From 58bfea2ad11a75615cfc47d217e3e650bc42a190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 19 Jun 2008 10:23:52 +0000 Subject: [PATCH 002/582] Replace the use of xml_stream by exmpp_xmlstream. exmpp_xml is configured to produce old #xmlelement records. exmpp_xmlstream is configured to send old xmlstreamstart tuple. Users are able to connect to ejabberd. Next step: ejabberd_c2s. SVN Revision: 1365 --- ChangeLog | 12 ++++++++++++ src/ejabberd_receiver.erl | 37 +++++++++++++++++++------------------ 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index e0bb52ad1..727c47ec3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2008-06-19 Jean-Sébastien Pédron + + * src/ejabberd_receiver.erl: Replace the use of xml_stream by + exmpp_xmlstream. exmpp_xml is configured to produce old #xmlelement + records. exmpp_xmlstream is configured to send old xmlstreamstart + tuple. Users are able to connect to ejabberd. Next step: + ejabberd_c2s. + +2008-06-19 Jean-Sébastien Pédron + + Start the transition to exmpp. + 2008-06-18 Badlop * src/ejabberd.app: The ejabberd version number is defined in the diff --git a/src/ejabberd_receiver.erl b/src/ejabberd_receiver.erl index 72b3608d6..208ec6a39 100644 --- a/src/ejabberd_receiver.erl +++ b/src/ejabberd_receiver.erl @@ -131,11 +131,8 @@ init([Socket, SockMod, Shaper, MaxStanzaSize]) -> %% Description: Handling call messages %%-------------------------------------------------------------------- handle_call({starttls, TLSSocket}, _From, - #state{xml_stream_state = XMLStreamState, - c2s_pid = C2SPid, - max_stanza_size = MaxStanzaSize} = State) -> - close_stream(XMLStreamState), - NewXMLStreamState = xml_stream:new(C2SPid, MaxStanzaSize), + #state{xml_stream_state = XMLStreamState} = State) -> + NewXMLStreamState = exmpp_xmlstream:reset(XMLStreamState), NewState = State#state{socket = TLSSocket, sock_mod = tls, xml_stream_state = NewXMLStreamState}, @@ -146,11 +143,8 @@ handle_call({starttls, TLSSocket}, _From, {stop, normal, ok, NewState} end; handle_call({compress, ZlibSocket}, _From, - #state{xml_stream_state = XMLStreamState, - c2s_pid = C2SPid, - max_stanza_size = MaxStanzaSize} = State) -> - close_stream(XMLStreamState), - NewXMLStreamState = xml_stream:new(C2SPid, MaxStanzaSize), + #state{xml_stream_state = XMLStreamState} = State) -> + NewXMLStreamState = exmpp_xmlstream:reset(XMLStreamState), NewState = State#state{socket = ZlibSocket, sock_mod = ejabberd_zlib, xml_stream_state = NewXMLStreamState}, @@ -161,15 +155,21 @@ handle_call({compress, ZlibSocket}, _From, {stop, normal, ok, NewState} end; handle_call(reset_stream, _From, - #state{xml_stream_state = XMLStreamState, - c2s_pid = C2SPid, - max_stanza_size = MaxStanzaSize} = State) -> - close_stream(XMLStreamState), - NewXMLStreamState = xml_stream:new(C2SPid, MaxStanzaSize), + #state{xml_stream_state = XMLStreamState} = State) -> + NewXMLStreamState = exmpp_xmlstream:reset(XMLStreamState), Reply = ok, {reply, Reply, State#state{xml_stream_state = NewXMLStreamState}}; handle_call({become_controller, C2SPid}, _From, State) -> - XMLStreamState = xml_stream:new(C2SPid, State#state.max_stanza_size), + % XXX OLD FORMAT + Parser = exmpp_xml:start_parser([ + {namespace, false}, + {name_as_atom, false}, + {maxsize, State#state.max_stanza_size} + ]), + XMLStreamState = exmpp_xmlstream:start( + {gen_fsm, C2SPid}, Parser, + [{xmlstreamstart, old}] + ), NewState = State#state{c2s_pid = C2SPid, xml_stream_state = XMLStreamState}, activate_socket(NewState), @@ -291,7 +291,7 @@ process_data(Data, shaper_state = ShaperState, c2s_pid = C2SPid} = State) -> ?DEBUG("Received XML on stream = ~p", [binary_to_list(Data)]), - XMLStreamState1 = xml_stream:parse(XMLStreamState, Data), + {ok, XMLStreamState1} = exmpp_xmlstream:parse(XMLStreamState, Data), {NewShaperState, Pause} = shaper:update(ShaperState, size(Data)), if C2SPid == undefined -> @@ -307,4 +307,5 @@ process_data(Data, close_stream(undefined) -> ok; close_stream(XMLStreamState) -> - xml_stream:close(XMLStreamState). + exmpp_xml:stop_parser(exmpp_xmlstream:get_parser(XMLStreamState)), + exmpp_xmlstream:stop(XMLStreamState). From e4646a6788951d3e5d5598668089c65ff6c5f466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 20 Jun 2008 12:49:39 +0000 Subject: [PATCH 003/582] Add exmpp detection. SVN Revision: 1366 --- ChangeLog | 4 ++++ src/Makefile.in | 2 +- src/aclocal.m4 | 11 ++++++++++- src/configure | 15 +++++++++++++-- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 727c47ec3..6386fdbf0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2008-06-20 Jean-Sébastien Pédron + + * src/configure, src/aclocal.m4, src/Makefile.in: Add exmpp detection. + 2008-06-19 Jean-Sébastien Pédron * src/ejabberd_receiver.erl: Replace the use of xml_stream by diff --git a/src/Makefile.in b/src/Makefile.in index 57bb56333..7391a8d9a 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -12,7 +12,7 @@ ERLANG_CFLAGS= @ERLANG_CFLAGS@ EXPAT_LIBS = @EXPAT_LIBS@ ERLANG_LIBS = @ERLANG_LIBS@ -ERLC_FLAGS += @ERLANG_SSL39@ +ERLC_FLAGS += @ERLANG_SSL39@ -I@ERLANG_EXMPP@/include ASN_FLAGS = -bber_bin +der +compact_bit_string +optimize +noobj # make debug=true to compile Erlang module with debug informations. diff --git a/src/aclocal.m4 b/src/aclocal.m4 index 46020d339..65509eefc 100644 --- a/src/aclocal.m4 +++ b/src/aclocal.m4 @@ -123,8 +123,14 @@ AC_DEFUN(AM_WITH_ERLANG, start() -> EIDirS = code:lib_dir("erl_interface") ++ "\n", EILibS = libpath("erl_interface") ++ "\n", + EXMPPDir = code:lib_dir("exmpp"), + case EXMPPDir of + {error, bad_name} -> exit("exmpp not found"); + _ -> ok + end, + EXMPPDirS = EXMPPDir ++ "\n", RootDirS = code:root_dir() ++ "\n", - file:write_file("conftest.out", list_to_binary(EIDirS ++ EILibS ++ ssldef() ++ RootDirS)), + file:write_file("conftest.out", list_to_binary(EIDirS ++ EILibS ++ ssldef() ++ EXMPPDirS ++ RootDirS)), halt(). -[ifdef]('id-pkix'). @@ -182,6 +188,8 @@ _EOF ERLANG_EI_LIB=`cat conftest.out | head -n 2 | tail -n 1` # Third line ERLANG_SSL39=`cat conftest.out | head -n 3 | tail -n 1` + # Fourth line + ERLANG_EXMPP=`cat conftest.out | head -n 4 | tail -n 1` # End line ERLANG_DIR=`cat conftest.out | tail -n 1` @@ -191,6 +199,7 @@ _EOF AC_SUBST(ERLANG_CFLAGS) AC_SUBST(ERLANG_LIBS) AC_SUBST(ERLANG_SSL39) + AC_SUBST(ERLANG_EXMPP) AC_SUBST(ERLC) AC_SUBST(ERL) ]) diff --git a/src/configure b/src/configure index b874f6cab..573a17ee7 100755 --- a/src/configure +++ b/src/configure @@ -664,6 +664,7 @@ ERL ERLANG_CFLAGS ERLANG_LIBS ERLANG_SSL39 +ERLANG_EXMPP LIBICONV CPP GREP @@ -2930,8 +2931,14 @@ echo "$as_me: error: erlang not found" >&2;} start() -> EIDirS = code:lib_dir("erl_interface") ++ "\n", EILibS = libpath("erl_interface") ++ "\n", + EXMPPDir = code:lib_dir("exmpp"), + case EXMPPDir of + {error, bad_name} -> exit("exmpp not found"); + _ -> ok + end, + EXMPPDirS = EXMPPDir ++ "\n", RootDirS = code:root_dir() ++ "\n", - file:write_file("conftest.out", list_to_binary(EIDirS ++ EILibS ++ ssldef() ++ RootDirS)), + file:write_file("conftest.out", list_to_binary(EIDirS ++ EILibS ++ ssldef() ++ EXMPPDirS ++ RootDirS)), halt(). -ifdef('id-pkix'). @@ -2995,6 +3002,8 @@ echo "$as_me: error: erlang program was not properly executed, (conftest.out was ERLANG_EI_LIB=`cat conftest.out | head -n 2 | tail -n 1` # Third line ERLANG_SSL39=`cat conftest.out | head -n 3 | tail -n 1` + # Fourth line + ERLANG_EXMPP=`cat conftest.out | head -n 4 | tail -n 1` # End line ERLANG_DIR=`cat conftest.out | tail -n 1` @@ -3007,6 +3016,7 @@ echo "$as_me: error: erlang program was not properly executed, (conftest.out was + #locating iconv @@ -6542,6 +6552,7 @@ ERL!$ERL$ac_delim ERLANG_CFLAGS!$ERLANG_CFLAGS$ac_delim ERLANG_LIBS!$ERLANG_LIBS$ac_delim ERLANG_SSL39!$ERLANG_SSL39$ac_delim +ERLANG_EXMPP!$ERLANG_EXMPP$ac_delim LIBICONV!$LIBICONV$ac_delim CPP!$CPP$ac_delim GREP!$GREP$ac_delim @@ -6583,7 +6594,7 @@ SSL_CFLAGS!$SSL_CFLAGS$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 89; then + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 90; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 From a19f280fcc8d7662b01af6cd2a973155e2f1ee45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 20 Jun 2008 12:50:20 +0000 Subject: [PATCH 004/582] Enable the new #xmlel record. SVN Revision: 1367 --- ChangeLog | 2 ++ src/ejabberd_receiver.erl | 7 +++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6386fdbf0..7af378f4c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,8 @@ * src/configure, src/aclocal.m4, src/Makefile.in: Add exmpp detection. + * src/ejabberd_receiver.erl: Enable the new #xmlel record. + 2008-06-19 Jean-Sébastien Pédron * src/ejabberd_receiver.erl: Replace the use of xml_stream by diff --git a/src/ejabberd_receiver.erl b/src/ejabberd_receiver.erl index 208ec6a39..5fdad76af 100644 --- a/src/ejabberd_receiver.erl +++ b/src/ejabberd_receiver.erl @@ -160,15 +160,14 @@ handle_call(reset_stream, _From, Reply = ok, {reply, Reply, State#state{xml_stream_state = NewXMLStreamState}}; handle_call({become_controller, C2SPid}, _From, State) -> - % XXX OLD FORMAT Parser = exmpp_xml:start_parser([ - {namespace, false}, - {name_as_atom, false}, + {namespace, true}, + {name_as_atom, true}, {maxsize, State#state.max_stanza_size} ]), XMLStreamState = exmpp_xmlstream:start( {gen_fsm, C2SPid}, Parser, - [{xmlstreamstart, old}] + [{xmlstreamstart, new}] ), NewState = State#state{c2s_pid = C2SPid, xml_stream_state = XMLStreamState}, From 389b5e64480eedbb7d6771a3c3045d1847fb0f33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 20 Jun 2008 12:52:29 +0000 Subject: [PATCH 005/582] 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 --- ChangeLog | 4 + src/ejabberd_c2s.erl | 865 ++++++++++++++++++++++--------------------- 2 files changed, 440 insertions(+), 429 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7af378f4c..3447a057b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,10 @@ * 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 * src/ejabberd_receiver.erl: Replace the use of xml_stream by diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 358b1fe32..400b725fe 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -54,8 +54,9 @@ handle_info/3, terminate/3]). +-include("exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("mod_privacy.hrl"). -define(SETS, gb_sets). @@ -93,11 +94,11 @@ %-define(DBGFSM, true). --ifdef(DBGFSM). +%-ifdef(DBGFSM). -define(FSMOPTS, [{debug, [trace]}]). --else. --define(FSMOPTS, []). --endif. +%-else. +%-define(FSMOPTS, []). +%-endif. %% Module start with or without supervisor: -ifdef(NO_TRANSIENT_SUPERVISORS). @@ -113,6 +114,11 @@ -define(C2S_OPEN_TIMEOUT, 60000). -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, "" " %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- -wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> +wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> DefaultLang = case ?MYLANG of undefined -> " xml:lang='en'"; DL -> " xml:lang='" ++ DL ++ "'" end, - case xml:get_attr_s("xmlns:stream", Attrs) of - ?NS_STREAM -> - Server = jlib:nameprep(xml:get_attr_s("to", Attrs)), + Header = exmpp_stream:opening_reply(Opening, + StateData#state.streamid), + 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 true -> - Lang = xml:get_attr_s("xml:lang", Attrs), - change_shaper(StateData, jlib:make_jid("", Server, "")), - case xml:get_attr_s("version", Attrs) of - "1.0" -> - Header = io_lib:format(?STREAM_HEADER, - [StateData#state.streamid, - Server, - " version='1.0'", - DefaultLang]), - send_text(StateData, Header), + Lang = exmpp_stream:get_lang(Opening), + change_shaper(StateData, + exmpp_jid:make_jid("", Server, "")), + case exmpp_stream:get_version(Opening) of + {1, 0} -> + send_element(StateData, Header1), case StateData#state.authenticated of false -> SASLState = @@ -255,11 +305,8 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> ejabberd_auth:check_password_with_authmodule( U, Server, P) end), - Mechs = lists:map( - fun(S) -> - {xmlelement, "mechanism", [], - [{xmlcdata, S}]} - end, cyrsasl:listmech(Server)), + SASL_Mechs = [exmpp_server_sasl:feature( + cyrsasl:listmech(Server))], SockMod = (StateData#state.sockmod):get_sockmod( StateData#state.socket), @@ -268,10 +315,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> case Zlib andalso (SockMod == gen_tcp) of true -> - [{xmlelement, "compression", - [{"xmlns", ?NS_FEATURE_COMPRESS}], - [{xmlelement, "method", - [], [{xmlcdata, "zlib"}]}]}]; + [exmpp_server_compression:feature(["zlib"])]; _ -> [] end, @@ -283,29 +327,19 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> (TLSEnabled == false) andalso (SockMod == gen_tcp) of true -> - case TLSRequired of - true -> - [{xmlelement, "starttls", - [{"xmlns", ?NS_TLS}], - [{xmlelement, "required", - [], []}]}]; - _ -> - [{xmlelement, "starttls", - [{"xmlns", ?NS_TLS}], []}] - end; + [exmpp_server_tls:feature(TLSRequired)]; false -> [] end, send_element(StateData, - {xmlelement, "stream:features", [], - TLSFeature ++ CompressFeature ++ - [{xmlelement, "mechanisms", - [{"xmlns", ?NS_SASL}], - Mechs}] ++ - ejabberd_hooks:run_fold( - c2s_stream_features, - Server, - [], [])}), + exmpp_stream:features( + TLSFeature ++ + CompressFeature ++ + SASL_Mechs ++ + ejabberd_hooks:run_fold( + c2s_stream_features, + Server, + [], []))), fsm_next_state(wait_for_feature_request, StateData#state{ server = Server, @@ -316,11 +350,10 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> "" -> send_element( StateData, - {xmlelement, "stream:features", [], - [{xmlelement, "bind", - [{"xmlns", ?NS_BIND}], []}, - {xmlelement, "session", - [{"xmlns", ?NS_SESSION}], []}]}), + exmpp_stream:features([ + exmpp_server_binding:feature(), + exmpp_server_session:feature() + ])), fsm_next_state(wait_for_bind, StateData#state{ server = Server, @@ -328,7 +361,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> _ -> send_element( StateData, - {xmlelement, "stream:features", [], []}), + exmpp_stream:features([])), fsm_next_state(wait_for_session, StateData#state{ server = Server, @@ -336,22 +369,16 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> end end; _ -> - Header = io_lib:format( - ?STREAM_HEADER, - [StateData#state.streamid, Server, "", - DefaultLang]), if (not StateData#state.tls_enabled) and StateData#state.tls_required -> - send_text(StateData, - Header ++ - ?POLICY_VIOLATION_ERR( - Lang, - "Use of STARTTLS required") ++ - ?STREAM_TRAILER), + send_element(StateData, + exmpp_xml:append_child(Header1, + exmpp_stream:error('policy-violation', + Lang, "Use of STARTTLS required"))), {stop, normal, StateData}; true -> - send_text(StateData, Header), + send_element(StateData, Header1), fsm_next_state(wait_for_auth, StateData#state{ server = Server, @@ -359,20 +386,16 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> end end; _ -> - Header = io_lib:format( - ?STREAM_HEADER, - [StateData#state.streamid, ?MYNAME, "", - DefaultLang]), - send_text(StateData, - Header ++ ?HOST_UNKNOWN_ERR ++ ?STREAM_TRAILER), + Header2 = exmpp_stream:set_initiating_entity(Header1, + ?MYNAME), + send_element(StateData, exmpp_xml:append_child(Header2, + exmpp_stream:error('host-unknown'))), {stop, normal, StateData} end; _ -> - Header = io_lib:format( - ?STREAM_HEADER, - [StateData#state.streamid, ?MYNAME, "", DefaultLang]), - send_text(StateData, - Header ++ ?INVALID_NS_ERR ++ ?STREAM_TRAILER), + Header2 = exmpp_stream:set_initiating_entity(Header1, ?MYNAME), + send_element(StateData, exmpp_xml:append_child(Header2, + exmpp_stream:error('invalid-namespace'))), {stop, normal, StateData} end; @@ -380,18 +403,21 @@ wait_for_stream(timeout, StateData) -> {stop, normal, 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}; 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}; wait_for_stream({xmlstreamerror, _}, StateData) -> - Header = io_lib:format(?STREAM_HEADER, - ["none", ?MYNAME, " version='1.0'", ""]), - send_text(StateData, - Header ++ ?INVALID_XML_ERR ++ ?STREAM_TRAILER), + Header = exmpp_stream:opening_reply(?MYNAME, 'jabber:client', "1.0", + "none"), + Header1 = exmpp_xml:append_child(Header, + exmpp_stream:error('xml-not-well-formed')), + send_element(StateData, Header1), {stop, normal, StateData}; wait_for_stream(closed, StateData) -> @@ -400,118 +426,96 @@ wait_for_stream(closed, StateData) -> wait_for_auth({xmlstreamelement, El}, StateData) -> case is_auth_packet(El) of - {auth, _ID, get, {U, _, _, _}} -> - {xmlelement, Name, Attrs, _Els} = jlib:make_result_iq_reply(El), - case U of - "" -> - UCdata = []; - _ -> - UCdata = [{xmlcdata, U}] + {auth, _ID, get, {_U, _, _, _}} -> + Fields = case ejabberd_auth:plain_password_required( + StateData#state.server) of + false -> both; + true -> plain end, - Res = case ejabberd_auth:plain_password_required( - StateData#state.server) of - false -> - {xmlelement, Name, Attrs, - [{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, - send_element(StateData, Res), + send_element(StateData, + exmpp_server_legacy_auth:fields(El, Fields)), 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), + Err = exmpp_stanza:error('not-acceptable', + {StateData#state.lang, "No resource provided"}), + send_element(StateData, exmpp_iq:error(El, 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 -> - case ejabberd_auth:check_password_with_authmodule( - U, StateData#state.server, P, - StateData#state.streamid, D) of - {true, AuthModule} -> - ?INFO_MSG( - "(~w) Accepted legacy authentication for ~s", - [StateData#state.socket, - jlib:jid_to_string(JID)]), - SID = {now(), self()}, - Conn = get_conn_type(StateData), - Info = [{ip, StateData#state.ip}, {conn, Conn}, - {auth_module, AuthModule}], - ejabberd_sm:open_session( - SID, U, StateData#state.server, R, Info), - Res1 = jlib:make_result_iq_reply(El), - Res = setelement(4, Res1, []), - send_element(StateData, Res), - change_shaper(StateData, JID), - {Fs, Ts} = ejabberd_hooks:run_fold( - roster_get_subscription_lists, - StateData#state.server, - {[], []}, - [U, StateData#state.server]), - LJID = jlib:jid_tolower( - jlib:jid_remove_resource(JID)), - Fs1 = [LJID | Fs], - Ts1 = [LJID | Ts], - PrivList = - ejabberd_hooks:run_fold( + try + JID = exmpp_jid:make_jid(U, StateData#state.server, R), + case acl:match_rule(StateData#state.server, + StateData#state.access, JID) of + allow -> + case ejabberd_auth:check_password_with_authmodule( + U, StateData#state.server, P, + StateData#state.streamid, D) of + {true, AuthModule} -> + ?INFO_MSG( + "(~w) Accepted legacy authentication for ~s", + [StateData#state.socket, + exmpp_jid:jid_to_string(JID)]), + SID = {now(), self()}, + Conn = get_conn_type(StateData), + Info = [{ip, StateData#state.ip}, {conn, Conn}, + {auth_module, AuthModule}], + ejabberd_sm:open_session( + SID, U, StateData#state.server, R, Info), + Res = exmpp_server_legacy_auth:success(El), + send_element(StateData, Res), + change_shaper(StateData, JID), + {Fs, Ts} = ejabberd_hooks:run_fold( + roster_get_subscription_lists, + StateData#state.server, + {[], []}, + [U, StateData#state.server]), + LJID = {JID#jid.lnode, JID#jid.ldomain, ""}, + Fs1 = [LJID | Fs], + Ts1 = [LJID | Ts], + PrivList = ejabberd_hooks:run_fold( privacy_get_user_list, StateData#state.server, #userlist{}, [U, StateData#state.server]), - fsm_next_state(session_established, - StateData#state{ - user = U, - resource = R, - jid = JID, - sid = SID, - conn = Conn, - auth_module = AuthModule, - pres_f = ?SETS:from_list(Fs1), - pres_t = ?SETS:from_list(Ts1), - privacy_list = PrivList}); - _ -> - ?INFO_MSG( - "(~w) Failed legacy authentication for ~s", - [StateData#state.socket, - jlib:jid_to_string(JID)]), - Err = jlib:make_error_reply( - El, ?ERR_NOT_AUTHORIZED), - send_element(StateData, Err), - fsm_next_state(wait_for_auth, StateData) - end; - _ -> - if - JID == error -> - ?INFO_MSG( - "(~w) Forbidden legacy authentication for " - "username '~s' with resource '~s'", - [StateData#state.socket, U, R]), - Err = jlib:make_error_reply(El, ?ERR_JID_MALFORMED), - send_element(StateData, Err), - fsm_next_state(wait_for_auth, StateData); - 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) - end + fsm_next_state(session_established, + StateData#state{ + user = U, + resource = R, + jid = JID, + sid = SID, + conn = Conn, + auth_module = AuthModule, + pres_f = ?SETS:from_list(Fs1), + pres_t = ?SETS:from_list(Ts1), + privacy_list = PrivList}); + _ -> + ?INFO_MSG( + "(~w) Failed legacy authentication for ~s", + [StateData#state.socket, + exmpp_jid:jid_to_string(JID)]), + Err = exmpp_stanza:error('not-authorized'), + Res = exmpp_iq:error_without_original(El, Err), + send_element(StateData, Res), + fsm_next_state(wait_for_auth, StateData) + end; + _ -> + ?INFO_MSG( + "(~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( + "(~w) Forbidden legacy authentication for " + "username '~s' with resource '~s'", + [StateData#state.socket, U, R]), + Err1 = exmpp_stanza:error('jid-malformed'), + Res1 = exmpp_iq:error_without_original(El, Err1), + send_element(StateData, Res1), + fsm_next_state(wait_for_auth, StateData) end; _ -> process_unauthenticated_stanza(StateData, El), @@ -522,38 +526,36 @@ wait_for_auth(timeout, StateData) -> {stop, normal, StateData}; wait_for_auth({xmlstreamend, _Name}, StateData) -> - send_text(StateData, ?STREAM_TRAILER), + send_element(StateData, exmpp_stream:closing()), {stop, normal, 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}; wait_for_auth(closed, StateData) -> {stop, normal, StateData}. -wait_for_feature_request({xmlstreamelement, El}, StateData) -> - {xmlelement, Name, Attrs, Els} = El, +wait_for_feature_request({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, + StateData) -> Zlib = StateData#state.zlib, TLS = StateData#state.tls, TLSEnabled = StateData#state.tls_enabled, TLSRequired = StateData#state.tls_required, SockMod = (StateData#state.sockmod):get_sockmod(StateData#state.socket), - case {xml:get_attr_s("xmlns", Attrs), Name} of - {?NS_SASL, "auth"} when not ((SockMod == gen_tcp) and TLSRequired) -> - Mech = xml:get_attr_s("mechanism", Attrs), - ClientIn = jlib:decode_base64(xml:get_cdata(Els)), + case {NS, Name} of + {?NS_SASL, 'auth'} when not ((SockMod == gen_tcp) and TLSRequired) -> + {auth, Mech, ClientIn} = exmpp_server_sasl:next_step(El), case cyrsasl:server_start(StateData#state.sasl_state, Mech, ClientIn) of {ok, Props} -> (StateData#state.sockmod):reset_stream( StateData#state.socket), - send_element(StateData, - {xmlelement, "success", - [{"xmlns", ?NS_SASL}], []}), - U = xml:get_attr_s(username, Props), + send_element(StateData, exmpp_server_sasl:success()), + U = proplists:get_value(username, Props), ?INFO_MSG("(~w) Accepted authentication for ~s", [StateData#state.socket, U]), fsm_next_state(wait_for_stream, @@ -563,10 +565,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> user = U }); {continue, ServerOut, NewSASLState} -> send_element(StateData, - {xmlelement, "challenge", - [{"xmlns", ?NS_SASL}], - [{xmlcdata, - jlib:encode_base64(ServerOut)}]}), + exmpp_server_sasl:challenge(ServerOut)), fsm_next_state(wait_for_sasl_response, StateData#state{ sasl_state = NewSASLState}); @@ -575,20 +574,18 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> "(~w) Failed authentication for ~s@~s", [StateData#state.socket, Username, StateData#state.server]), + % XXX OLD FORMAT: list_to_atom(Error). send_element(StateData, - {xmlelement, "failure", - [{"xmlns", ?NS_SASL}], - [{xmlelement, Error, [], []}]}), + exmpp_server_sasl:failure(list_to_atom(Error))), {next_state, wait_for_feature_request, StateData, ?C2S_OPEN_TIMEOUT}; {error, Error} -> + % XXX OLD FORMAT: list_to_atom(Error). send_element(StateData, - {xmlelement, "failure", - [{"xmlns", ?NS_SASL}], - [{xmlelement, Error, [], []}]}), + exmpp_server_sasl:failure(list_to_atom(Error))), fsm_next_state(wait_for_feature_request, StateData) end; - {?NS_TLS, "starttls"} when TLS == true, + {?NS_TLS, 'starttls'} when TLS == true, TLSEnabled == false, SockMod == gen_tcp -> TLSOpts = case ejabberd_config:get_local_option( @@ -601,55 +598,45 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> certfile, 1, StateData#state.tls_options)] end, Socket = StateData#state.socket, + Proceed = exmpp_xml:document_fragment_to_list( + exmpp_server_tls:proceed(), ?DEFAULT_NS, ?PREFIXED_NS), TLSSocket = (StateData#state.sockmod):starttls( Socket, TLSOpts, - xml:element_to_string( - {xmlelement, "proceed", [{"xmlns", ?NS_TLS}], []})), + Proceed), fsm_next_state(wait_for_stream, StateData#state{socket = TLSSocket, streamid = new_id(), tls_enabled = true }); - {?NS_COMPRESS, "compress"} when Zlib == true, + {?NS_COMPRESS, 'compress'} when Zlib == true, SockMod == gen_tcp -> - case xml:get_subtag(El, "method") of - false -> + case exmpp_server_compression:selected_method(El) of + undefined -> send_element(StateData, - {xmlelement, "failure", - [{"xmlns", ?NS_COMPRESS}], - [{xmlelement, "setup-failed", [], []}]}), + exmpp_server_compression:failure('steup-failed')), fsm_next_state(wait_for_feature_request, StateData); - Method -> - case xml:get_tag_cdata(Method) of - "zlib" -> - Socket = StateData#state.socket, - ZlibSocket = (StateData#state.sockmod):compress( - Socket, - xml:element_to_string( - {xmlelement, "compressed", - [{"xmlns", ?NS_COMPRESS}], []})), - fsm_next_state(wait_for_stream, - StateData#state{socket = ZlibSocket, - streamid = new_id() - }); - _ -> - send_element(StateData, - {xmlelement, "failure", - [{"xmlns", ?NS_COMPRESS}], - [{xmlelement, "unsupported-method", - [], []}]}), - fsm_next_state(wait_for_feature_request, - StateData) - end + "zlib" -> + Socket = StateData#state.socket, + ZlibSocket = (StateData#state.sockmod):compress( + Socket, + exmpp_server_compression:compressed()), + fsm_next_state(wait_for_stream, + StateData#state{socket = ZlibSocket, + streamid = new_id() + }); + _ -> + send_element(StateData, + exmpp_server_compression:failure('unsupported-method')), + fsm_next_state(wait_for_feature_request, + StateData) end; _ -> if (SockMod == gen_tcp) and TLSRequired -> Lang = StateData#state.lang, - send_text(StateData, ?POLICY_VIOLATION_ERR( - Lang, - "Use of STARTTLS required") ++ - ?STREAM_TRAILER), + send_element(StateData, exmpp_stream:error( + 'policy-violation', Lang, "Use of STARTTLS required")), + send_element(StateData, exmpp_stream:closing()), {stop, normal, StateData}; true -> process_unauthenticated_stanza(StateData, El), @@ -661,32 +648,31 @@ wait_for_feature_request(timeout, StateData) -> {stop, normal, StateData}; wait_for_feature_request({xmlstreamend, _Name}, StateData) -> - send_text(StateData, ?STREAM_TRAILER), + send_element(StateData, exmpp_stream:closing()), {stop, normal, 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}; wait_for_feature_request(closed, StateData) -> {stop, normal, StateData}. -wait_for_sasl_response({xmlstreamelement, El}, StateData) -> - {xmlelement, Name, Attrs, Els} = El, - case {xml:get_attr_s("xmlns", Attrs), Name} of - {?NS_SASL, "response"} -> - ClientIn = jlib:decode_base64(xml:get_cdata(Els)), +wait_for_sasl_response({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, + StateData) -> + case {NS, Name} of + {?NS_SASL, 'response'} -> + {response, ClientIn} = exmpp_server_sasl:next_step(El), case cyrsasl:server_step(StateData#state.sasl_state, ClientIn) of {ok, Props} -> (StateData#state.sockmod):reset_stream( StateData#state.socket), - send_element(StateData, - {xmlelement, "success", - [{"xmlns", ?NS_SASL}], []}), - U = xml:get_attr_s(username, Props), - AuthModule = xml:get_attr_s(auth_module, Props), + send_element(StateData, exmpp_server_sasl:success()), + U = proplists:get_value(username, Props), + AuthModule = proplists:get_value(auth_module, Props), ?INFO_MSG("(~w) Accepted authentication for ~s", [StateData#state.socket, U]), fsm_next_state(wait_for_stream, @@ -697,10 +683,7 @@ wait_for_sasl_response({xmlstreamelement, El}, StateData) -> user = U}); {continue, ServerOut, NewSASLState} -> send_element(StateData, - {xmlelement, "challenge", - [{"xmlns", ?NS_SASL}], - [{xmlcdata, - jlib:encode_base64(ServerOut)}]}), + exmpp_server_sasl:challenge(ServerOut)), fsm_next_state(wait_for_sasl_response, StateData#state{sasl_state = NewSASLState}); {error, Error, Username} -> @@ -708,16 +691,14 @@ wait_for_sasl_response({xmlstreamelement, El}, StateData) -> "(~w) Failed authentication for ~s@~s", [StateData#state.socket, Username, StateData#state.server]), + % XXX OLD FORMAT: list_to_atom(Error). send_element(StateData, - {xmlelement, "failure", - [{"xmlns", ?NS_SASL}], - [{xmlelement, Error, [], []}]}), + exmpp_server_sasl:failure(list_to_atom(Error))), fsm_next_state(wait_for_feature_request, StateData); {error, Error} -> + % XXX OLD FORMAT: list_to_atom(Error). send_element(StateData, - {xmlelement, "failure", - [{"xmlns", ?NS_SASL}], - [{xmlelement, Error, [], []}]}), + exmpp_server_sasl:failure(list_to_atom(Error))), fsm_next_state(wait_for_feature_request, StateData) end; _ -> @@ -729,11 +710,12 @@ wait_for_sasl_response(timeout, StateData) -> {stop, normal, StateData}; wait_for_sasl_response({xmlstreamend, _Name}, StateData) -> - send_text(StateData, ?STREAM_TRAILER), + send_element(StateData, exmpp_stream:closing()), {stop, normal, 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}; wait_for_sasl_response(closed, StateData) -> @@ -742,35 +724,25 @@ wait_for_sasl_response(closed, StateData) -> wait_for_bind({xmlstreamelement, El}, StateData) -> - case jlib:iq_query_info(El) of - #iq{type = set, xmlns = ?NS_BIND, sub_el = SubEl} = IQ -> - U = StateData#state.user, - R1 = xml:get_path_s(SubEl, [{elem, "resource"}, cdata]), - R = case jlib:resourceprep(R1) of - error -> error; - "" -> - lists:concat( - [randoms:get_string() | tuple_to_list(now())]); - Resource -> Resource - end, - case R of - error -> - Err = jlib:make_error_reply(El, ?ERR_BAD_REQUEST), - 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, - StateData#state{resource = R, jid = JID}) - end; - _ -> + try + U = StateData#state.user, + R = case exmpp_server_binding:wished_resource(El) of + undefined -> + lists:concat([randoms:get_string() | tuple_to_list(now())]); + Resource -> + Resource + end, + JID = exmpp_jid:make_jid(U, StateData#state.server, R), + Res = exmpp_server_binding:bind(El, JID), + send_element(StateData, Res), + fsm_next_state(wait_for_session, + StateData#state{resource = R, jid = JID}) + 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) end; @@ -778,11 +750,12 @@ wait_for_bind(timeout, StateData) -> {stop, normal, StateData}; wait_for_bind({xmlstreamend, _Name}, StateData) -> - send_text(StateData, ?STREAM_TRAILER), + send_element(StateData, exmpp_stream:closing()), {stop, normal, 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}; wait_for_bind(closed, StateData) -> @@ -791,57 +764,58 @@ wait_for_bind(closed, StateData) -> wait_for_session({xmlstreamelement, El}, StateData) -> - case jlib:iq_query_info(El) of - #iq{type = set, xmlns = ?NS_SESSION} -> - U = StateData#state.user, - R = StateData#state.resource, - JID = StateData#state.jid, - case acl:match_rule(StateData#state.server, - StateData#state.access, JID) of - allow -> - ?INFO_MSG("(~w) Opened session for ~s", - [StateData#state.socket, - jlib:jid_to_string(JID)]), - SID = {now(), self()}, - Conn = get_conn_type(StateData), - Info = [{ip, StateData#state.ip}, {conn, Conn}, - {auth_module, StateData#state.auth_module}], - ejabberd_sm:open_session( - SID, U, StateData#state.server, R, Info), - Res = jlib:make_result_iq_reply(El), - send_element(StateData, Res), - change_shaper(StateData, JID), - {Fs, Ts} = ejabberd_hooks:run_fold( - roster_get_subscription_lists, - StateData#state.server, - {[], []}, - [U, StateData#state.server]), - LJID = jlib:jid_tolower(jlib:jid_remove_resource(JID)), - Fs1 = [LJID | Fs], - Ts1 = [LJID | Ts], - PrivList = - ejabberd_hooks:run_fold( - privacy_get_user_list, StateData#state.server, - #userlist{}, - [U, StateData#state.server]), - fsm_next_state(session_established, - StateData#state{ - sid = SID, - conn = Conn, - pres_f = ?SETS:from_list(Fs1), - pres_t = ?SETS:from_list(Ts1), - privacy_list = PrivList}); - _ -> - ejabberd_hooks:run(forbidden_session_hook, - StateData#state.server, [JID]), - ?INFO_MSG("(~w) Forbidden session 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_session, StateData) - end; - _ -> + try + U = StateData#state.user, + R = StateData#state.resource, + JID = StateData#state.jid, + exmpp_server_session:want_establishment(El), + case acl:match_rule(StateData#state.server, + StateData#state.access, JID) of + allow -> + ?INFO_MSG("(~w) Opened session for ~s", + [StateData#state.socket, + exmpp_jid:jid_to_string(JID)]), + SID = {now(), self()}, + Conn = get_conn_type(StateData), + Info = [{ip, StateData#state.ip}, {conn, Conn}, + {auth_module, StateData#state.auth_module}], + ejabberd_sm:open_session( + SID, U, StateData#state.server, R, Info), + Res = exmpp_server_session:establish(El), + send_element(StateData, Res), + change_shaper(StateData, JID), + {Fs, Ts} = ejabberd_hooks:run_fold( + roster_get_subscription_lists, + StateData#state.server, + {[], []}, + [U, StateData#state.server]), + LJID = {JID#jid.lnode, JID#jid.ldomain, ""}, + Fs1 = [LJID | Fs], + Ts1 = [LJID | Ts], + PrivList = + ejabberd_hooks:run_fold( + privacy_get_user_list, StateData#state.server, + #userlist{}, + [U, StateData#state.server]), + fsm_next_state(session_established, + StateData#state{ + sid = SID, + conn = Conn, + pres_f = ?SETS:from_list(Fs1), + pres_t = ?SETS:from_list(Ts1), + privacy_list = PrivList}); + _ -> + ejabberd_hooks:run(forbidden_session_hook, + StateData#state.server, [JID]), + ?INFO_MSG("(~w) Forbidden session for ~s", + [StateData#state.socket, + exmpp_jid:jid_to_string(JID)]), + Err = exmpp_server_session:error(El, 'not-allowed'), + send_element(StateData, Err), + fsm_next_state(wait_for_session, StateData) + end + catch + throw:_Exception -> fsm_next_state(wait_for_session, StateData) end; @@ -849,11 +823,12 @@ wait_for_session(timeout, StateData) -> {stop, normal, StateData}; wait_for_session({xmlstreamend, _Name}, StateData) -> - send_text(StateData, ?STREAM_TRAILER), + send_element(StateData, exmpp_stream:closing()), {stop, normal, 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}; wait_for_session(closed, StateData) -> @@ -861,90 +836,121 @@ wait_for_session(closed, StateData) -> session_established({xmlstreamelement, El}, StateData) -> - {xmlelement, Name, Attrs, _Els} = El, - User = StateData#state.user, - Server = StateData#state.server, - % TODO: check 'from' attribute in stanza - FromJID = StateData#state.jid, - To = xml:get_attr_s("to", Attrs), - ToJID = case To of - "" -> - jlib:make_jid(User, Server, ""); - _ -> - jlib:string_to_jid(To) - end, - NewEl1 = jlib:remove_attr("xmlns", El), - NewEl = case xml:get_attr_s("xml:lang", Attrs) of - "" -> - case StateData#state.lang of - "" -> NewEl1; - Lang -> - xml:replace_tag_attr("xml:lang", Lang, NewEl1) - end; - _ -> - NewEl1 - end, - NewState = - case ToJID of - error -> - case xml:get_attr_s("type", Attrs) of - "error" -> StateData; - "result" -> StateData; + try + User = StateData#state.user, + Server = StateData#state.server, + % TODO: check 'from' attribute in stanza + FromJID = StateData#state.jid, + To = exmpp_stanza:get_recipient(El), + ToJID = case To of + "" -> + exmpp_jid:make_jid(User, Server, ""); _ -> - Err = jlib:make_error_reply(NewEl, ?ERR_JID_MALFORMED), - send_element(StateData, Err), - StateData + exmpp_jid:string_to_jid(To) + end, + NewEl = case exmpp_stanza:get_lang(El) of + "" -> + case StateData#state.lang of + "" -> El; + Lang -> + exmpp_stanza:set_lang(El, Lang) + end; + _ -> + El + end, + NewState = case El of + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence'} -> + % XXX OLD FORMAT: NewEl. + PresenceElOld = ejabberd_hooks:run_fold( + c2s_update_presence, + Server, + exmpp_xml:xmlel_to_xmlelement(NewEl, + ?DEFAULT_NS, ?PREFIXED_NS), + [User, Server]), + PresenceEl = exmpp_xml:xmlelement_to_xmlel(PresenceElOld, + ?DEFAULT_NS, ?PREFIXED_NS), + % XXX OLD FORMAT: PresenceElOld. + ejabberd_hooks:run( + user_send_packet, + Server, + [FromJID, ToJID, PresenceElOld]), + case ToJID of + #jid{node = User, + domain = Server, + resource = ""} -> + ?DEBUG("presence_update(~p,~n\t~p,~n\t~p)", + [FromJID, PresenceEl, StateData]), + % XXX OLD FORMAT: PresenceElOld. + presence_update(FromJID, PresenceElOld, + StateData); + _ -> + % XXX OLD FORMAT: PresenceElOld. + presence_track(FromJID, ToJID, PresenceElOld, + StateData) end; - _ -> - case Name of - "presence" -> - PresenceEl = ejabberd_hooks:run_fold( - c2s_update_presence, - Server, - NewEl, - [User, Server]), + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'iq'} -> + IQ_Content = case exmpp_iq:get_type(El) of + '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( + FromJID, ToJID, IQ, StateData); + _ -> + % XXX OLD FORMAT: NewElOld. + NewElOld = exmpp_xml:xmlel_to_xmlelement(NewEl, + ?DEFAULT_NS, ?PREFIXED_NS), ejabberd_hooks:run( user_send_packet, Server, - [FromJID, ToJID, PresenceEl]), - case ToJID of - #jid{user = User, - server = Server, - resource = ""} -> - ?DEBUG("presence_update(~p,~n\t~p,~n\t~p)", - [FromJID, PresenceEl, StateData]), - presence_update(FromJID, PresenceEl, - StateData); - _ -> - presence_track(FromJID, ToJID, PresenceEl, - StateData) - end; - "iq" -> - case jlib:iq_query_info(NewEl) of - #iq{xmlns = ?NS_PRIVACY} = IQ -> - process_privacy_iq( - FromJID, ToJID, IQ, StateData); - _ -> - ejabberd_hooks:run( - user_send_packet, - Server, - [FromJID, ToJID, NewEl]), - ejabberd_router:route( - FromJID, ToJID, NewEl), - StateData - end; - "message" -> - ejabberd_hooks:run(user_send_packet, - Server, - [FromJID, ToJID, NewEl]), - ejabberd_router:route(FromJID, ToJID, NewEl), - StateData; - _ -> + [FromJID, ToJID, NewElOld]), + % XXX OLD FORMAT: NewElOld. + ejabberd_router:route( + FromJID, ToJID, NewElOld), StateData - end + end; + #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, + Server, + [FromJID, ToJID, NewElOld]), + % XXX OLD FORMAT: NewElOld. + ejabberd_router:route(FromJID, ToJID, NewElOld), + StateData; + _ -> + StateData end, - ejabberd_hooks:run(c2s_loop_debug, [{xmlstreamelement, El}]), - fsm_next_state(session_established, NewState); + % XXX OLD FORMAT: El. + 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 %% configurable activity timeout @@ -956,11 +962,12 @@ session_established(timeout, StateData) -> fsm_next_state(session_established, StateData); session_established({xmlstreamend, _Name}, StateData) -> - send_text(StateData, ?STREAM_TRAILER), + send_element(StateData, exmpp_stream:closing()), {stop, normal, 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}; session_established(closed, StateData) -> From 2a439984446b63fc725e187cadc89579427066cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 20 Jun 2008 14:54:59 +0000 Subject: [PATCH 007/582] o Change the usage of #state.lang somewhat. o Fix value of DefaultLang: it doesn't contain the whole serialized attribute. o Use exmpp_jid:make_bare_jid/2 more. I started to work on the second half of the module and discovered several annoying things: o JID are represented in two forms: the #jid record and the {N, D, R} tuple. o Sometimes, #xmlelement may contain non-#xml* tuples in their children. This is the case for some stanzas. Their children are used to pass random data. I'm less and less convicted that ejabberd_c2s can be fully converted without starting to work on other modules. SVN Revision: 1370 --- ChangeLog | 4 ++++ src/ejabberd_c2s.erl | 54 ++++++++++++++++++++------------------------ 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3447a057b..ea528f668 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,10 @@ 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. + * src/ejabberd_c2s.erl: Change the usage of #state.lang somewhat. + Fix value of DefaultLang: it doesn't contain the whole serialized + attribute. Use exmpp_jid:make_bare_jid/2 more. + 2008-06-19 Jean-Sébastien Pédron * src/ejabberd_receiver.erl: Replace the use of xml_stream by diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 400b725fe..e50f9bdb5 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -142,7 +142,6 @@ -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), @@ -273,9 +272,9 @@ get_subscribed_and_online(FsmRef) -> wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> DefaultLang = case ?MYLANG of undefined -> - " xml:lang='en'"; + "en"; DL -> - " xml:lang='" ++ DL ++ "'" + DL end, Header = exmpp_stream:opening_reply(Opening, StateData#state.streamid), @@ -287,8 +286,9 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> case lists:member(Server, ?MYHOSTS) of true -> Lang = exmpp_stream:get_lang(Opening), + % OLD FORMAT: JID with empty strings. change_shaper(StateData, - exmpp_jid:make_jid("", Server, "")), + exmpp_jid:make_bare_jid(undefined, Server)), case exmpp_stream:get_version(Opening) of {1, 0} -> send_element(StateData, Header1), @@ -375,7 +375,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> send_element(StateData, exmpp_xml:append_child(Header1, exmpp_stream:error('policy-violation', - Lang, "Use of STARTTLS required"))), + "en", "Use of STARTTLS required"))), {stop, normal, StateData}; true -> send_element(StateData, Header1), @@ -437,7 +437,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> fsm_next_state(wait_for_auth, StateData); {auth, _ID, set, {_U, _P, _D, ""}} -> Err = exmpp_stanza:error('not-acceptable', - {StateData#state.lang, "No resource provided"}), + {"en", "No resource provided"}), send_element(StateData, exmpp_iq:error(El, Err)), fsm_next_state(wait_for_auth, StateData); {auth, _ID, set, {U, P, D, R}} -> @@ -468,7 +468,8 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> StateData#state.server, {[], []}, [U, StateData#state.server]), - LJID = {JID#jid.lnode, JID#jid.ldomain, ""}, + LJID = {JID#jid.lnode, JID#jid.ldomain, + undefined}, Fs1 = [LJID | Fs], Ts1 = [LJID | Ts], PrivList = ejabberd_hooks:run_fold( @@ -633,9 +634,8 @@ wait_for_feature_request({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, _ -> if (SockMod == gen_tcp) and TLSRequired -> - Lang = StateData#state.lang, send_element(StateData, exmpp_stream:error( - 'policy-violation', Lang, "Use of STARTTLS required")), + 'policy-violation', "en", "Use of STARTTLS required")), send_element(StateData, exmpp_stream:closing()), {stop, normal, StateData}; true -> @@ -742,7 +742,7 @@ wait_for_bind({xmlstreamelement, El}, StateData) -> Err = exmpp_server_binding:error(El, 'bad-request'), send_element(StateData, Err), fsm_next_state(wait_for_bind, StateData); - throw:Exception -> + throw:_Exception -> fsm_next_state(wait_for_bind, StateData) end; @@ -789,7 +789,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> StateData#state.server, {[], []}, [U, StateData#state.server]), - LJID = {JID#jid.lnode, JID#jid.ldomain, ""}, + LJID = {JID#jid.lnode, JID#jid.ldomain, undefined}, Fs1 = [LJID | Fs], Ts1 = [LJID | Ts], PrivList = @@ -805,6 +805,8 @@ wait_for_session({xmlstreamelement, El}, StateData) -> pres_t = ?SETS:from_list(Ts1), privacy_list = PrivList}); _ -> + % OLD FORMAT: Jid may use 'undefined' instead of empty + % strings. ejabberd_hooks:run(forbidden_session_hook, StateData#state.server, [JID]), ?INFO_MSG("(~w) Forbidden session for ~s", @@ -843,15 +845,15 @@ session_established({xmlstreamelement, El}, StateData) -> FromJID = StateData#state.jid, To = exmpp_stanza:get_recipient(El), ToJID = case To of - "" -> - exmpp_jid:make_jid(User, Server, ""); + undefined -> + exmpp_jid:make_bare_jid(User, Server); _ -> exmpp_jid:string_to_jid(To) end, NewEl = case exmpp_stanza:get_lang(El) of - "" -> + undefined -> case StateData#state.lang of - "" -> El; + undefined -> El; Lang -> exmpp_stanza:set_lang(El, Lang) end; @@ -889,17 +891,12 @@ session_established({xmlstreamelement, El}, StateData) -> StateData) end; #xmlel{ns = ?NS_JABBER_CLIENT, name = 'iq'} -> - IQ_Content = case exmpp_iq:get_type(El) of - '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 -> + case exmpp_iq:get_payload(El) of + #xmlel{ns = ?NS_PRIVACY} -> % XXX OLD FORMAT: IQ was #iq. + IQ_Record = exmpp_iq:make_iq_record(El), process_privacy_iq( - FromJID, ToJID, IQ, StateData); + FromJID, ToJID, IQ_Record, StateData); _ -> % XXX OLD FORMAT: NewElOld. NewElOld = exmpp_xml:xmlel_to_xmlelement(NewEl, @@ -1018,6 +1015,7 @@ handle_sync_event({get_presence}, _From, StateName, StateData) -> fsm_reply(Reply, StateName, StateData); handle_sync_event(get_subscribed_and_online, _From, StateName, StateData) -> + % XXX OLD FORMAT: This function needs update. User has the form {N, D, R}. Subscribed = StateData#state.pres_f, Online = StateData#state.pres_available, Pred = fun(User, _Caps) -> @@ -1042,15 +1040,13 @@ code_change(_OldVsn, StateName, StateData, _Extra) -> %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- handle_info({send_text, Text}, StateName, StateData) -> + % XXX OLD FORMAT: This clause should be removed. send_text(StateData, Text), ejabberd_hooks:run(c2s_loop_debug, [Text]), fsm_next_state(StateName, StateData); handle_info(replaced, _StateName, StateData) -> - Lang = StateData#state.lang, - send_text(StateData, - xml:element_to_string( - ?SERRT_CONFLICT(Lang, "Replaced by new connection")) - ++ ?STREAM_TRAILER), + send_element(StateData, exmpp_stream:error('conflict')), + send_element(StateData, exmpp_stream:closing()), {stop, normal, StateData#state{authenticated = replaced}}; handle_info({route, From, To, Packet}, StateName, StateData) -> {xmlelement, Name, Attrs, Els} = Packet, From e95df7999f57600b4819f069d4313d041ee6373d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 23 Jun 2008 11:47:10 +0000 Subject: [PATCH 008/582] Convert JID to the expected form outside of the C2S (empty fields must be set to the empty string). This fixes the broken routing. SVN Revision: 1375 --- ChangeLog | 6 ++++++ src/ejabberd_c2s.erl | 31 +++++++++++++++++++------------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index ea528f668..9be49fd1e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-06-23 Jean-Sébastien Pédron + + * src/ejabberd_c2s.erl (session_established): Convert JID to the + expected form outside of the C2S (empty fields must be set to the + empty string). This fixes the broken routing. + 2008-06-20 Jean-Sébastien Pédron * src/configure, src/aclocal.m4, src/Makefile.in: Add exmpp detection. diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index e50f9bdb5..1e3e38df6 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -871,32 +871,37 @@ session_established({xmlstreamelement, El}, StateData) -> [User, Server]), PresenceEl = exmpp_xml:xmlelement_to_xmlel(PresenceElOld, ?DEFAULT_NS, ?PREFIXED_NS), - % XXX OLD FORMAT: PresenceElOld. + % XXX OLD FORMAT: PresenceElOld, *JID. + FromJIDOld = exmpp_jid:to_ejabberd_jid(FromJID), + ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), ejabberd_hooks:run( user_send_packet, Server, - [FromJID, ToJID, PresenceElOld]), + [FromJIDOld, ToJIDOld, PresenceElOld]), case ToJID of #jid{node = User, domain = Server, - resource = ""} -> + resource = undefined} -> ?DEBUG("presence_update(~p,~n\t~p,~n\t~p)", [FromJID, PresenceEl, StateData]), % XXX OLD FORMAT: PresenceElOld. - presence_update(FromJID, PresenceElOld, + presence_update(FromJIDOld, PresenceElOld, StateData); _ -> % XXX OLD FORMAT: PresenceElOld. - presence_track(FromJID, ToJID, PresenceElOld, + presence_track(FromJIDOld, ToJIDOld, PresenceElOld, StateData) end; #xmlel{ns = ?NS_JABBER_CLIENT, name = 'iq'} -> + % XXX OLD FORMAT: JIDs. + FromJIDOld = exmpp_jid:to_ejabberd_jid(FromJID), + ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), case exmpp_iq:get_payload(El) of #xmlel{ns = ?NS_PRIVACY} -> % XXX OLD FORMAT: IQ was #iq. - IQ_Record = exmpp_iq:make_iq_record(El), + IQ_Record = exmpp_iq:to_ejabberd_iq(El), process_privacy_iq( - FromJID, ToJID, IQ_Record, StateData); + FromJIDOld, ToJIDOld, IQ_Record, StateData); _ -> % XXX OLD FORMAT: NewElOld. NewElOld = exmpp_xml:xmlel_to_xmlelement(NewEl, @@ -904,21 +909,23 @@ session_established({xmlstreamelement, El}, StateData) -> ejabberd_hooks:run( user_send_packet, Server, - [FromJID, ToJID, NewElOld]), + [FromJIDOld, ToJIDOld, NewElOld]), % XXX OLD FORMAT: NewElOld. ejabberd_router:route( - FromJID, ToJID, NewElOld), + FromJIDOld, ToJIDOld, NewElOld), StateData end; #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message'} -> - % XXX OLD FORMAT: NewElOld. + % XXX OLD FORMAT: NewElOld, JIDs. NewElOld = exmpp_xml:xmlel_to_xmlelement(NewEl, ?DEFAULT_NS, ?PREFIXED_NS), + FromJIDOld = exmpp_jid:to_ejabberd_jid(FromJID), + ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), ejabberd_hooks:run(user_send_packet, Server, - [FromJID, ToJID, NewElOld]), + [FromJIDOld, ToJIDOld, NewElOld]), % XXX OLD FORMAT: NewElOld. - ejabberd_router:route(FromJID, ToJID, NewElOld), + ejabberd_router:route(FromJIDOld, ToJIDOld, NewElOld), StateData; _ -> StateData From 4e2e68a3fb2122af3dd6839764daa57ae7171c8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 24 Jun 2008 08:55:24 +0000 Subject: [PATCH 009/582] The handle_info clause that treats routing order is now converted. In-memory sets and dict still use the short JID form with empty strings for unspecified fields. Users are able to connect to ejabberd but some features don't seem to work proprerly. SVN Revision: 1376 --- ChangeLog | 7 ++ src/ejabberd_c2s.erl | 223 +++++++++++++++++++++++++------------------ 2 files changed, 138 insertions(+), 92 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9be49fd1e..269717f7a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2008-06-24 Jean-Sébastien Pédron + + * src/ejabberd_c2s.erl: The handle_info clause that treats routing + order is now converted. In-memory sets and dict still use the short + JID form with empty strings for unspecified fields. Users are able to + connect to ejabberd but some features don't seem to work proprerly. + 2008-06-23 Jean-Sébastien Pédron * src/ejabberd_c2s.erl (session_established): Convert JID to the diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 1e3e38df6..7567a591e 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -872,8 +872,8 @@ session_established({xmlstreamelement, El}, StateData) -> PresenceEl = exmpp_xml:xmlelement_to_xmlel(PresenceElOld, ?DEFAULT_NS, ?PREFIXED_NS), % XXX OLD FORMAT: PresenceElOld, *JID. - FromJIDOld = exmpp_jid:to_ejabberd_jid(FromJID), - ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), + FromJIDOld = exmpp_jid:to_ejabberd_jid(FromJID), + ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), ejabberd_hooks:run( user_send_packet, Server, @@ -893,15 +893,17 @@ session_established({xmlstreamelement, El}, StateData) -> StateData) end; #xmlel{ns = ?NS_JABBER_CLIENT, name = 'iq'} -> - % XXX OLD FORMAT: JIDs. - FromJIDOld = exmpp_jid:to_ejabberd_jid(FromJID), - ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), + % XXX OLD FORMAT: JIDs. + FromJIDOld = exmpp_jid:to_ejabberd_jid(FromJID), + ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), case exmpp_iq:get_payload(El) of #xmlel{ns = ?NS_PRIVACY} -> % XXX OLD FORMAT: IQ was #iq. - IQ_Record = exmpp_iq:to_ejabberd_iq(El), + ElOld2 = exmpp_xml:xmlel_to_xmlelement(El, + ?DEFAULT_NS, ?PREFIXED_NS), + IQ = jlib:iq_query_info(ElOld2), process_privacy_iq( - FromJIDOld, ToJIDOld, IQ_Record, StateData); + FromJIDOld, ToJIDOld, IQ, StateData); _ -> % XXX OLD FORMAT: NewElOld. NewElOld = exmpp_xml:xmlel_to_xmlelement(NewEl, @@ -919,8 +921,8 @@ session_established({xmlstreamelement, El}, StateData) -> % XXX OLD FORMAT: NewElOld, JIDs. NewElOld = exmpp_xml:xmlel_to_xmlelement(NewEl, ?DEFAULT_NS, ?PREFIXED_NS), - FromJIDOld = exmpp_jid:to_ejabberd_jid(FromJID), - ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), + FromJIDOld = exmpp_jid:to_ejabberd_jid(FromJID), + ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), ejabberd_hooks:run(user_send_packet, Server, [FromJIDOld, ToJIDOld, NewElOld]), @@ -1055,15 +1057,20 @@ handle_info(replaced, _StateName, StateData) -> send_element(StateData, exmpp_stream:error('conflict')), send_element(StateData, exmpp_stream:closing()), {stop, normal, StateData#state{authenticated = replaced}}; -handle_info({route, From, To, Packet}, StateName, StateData) -> - {xmlelement, Name, Attrs, Els} = Packet, +handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> + %% XXX OLD FORMAT: From, To and Packet are in the old format. + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, + ?DEFAULT_NS, ?PREFIXED_NS), + From = exmpp_jid:from_ejabberd_jid(FromOld), + To = exmpp_jid:from_ejabberd_jid(ToOld), {Pass, NewAttrs, NewState} = - case Name of - "presence" -> - case xml:get_attr_s("type", Attrs) of - "probe" -> - LFrom = jlib:jid_tolower(From), - LBFrom = jlib:jid_remove_resource(LFrom), + case Packet of + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = Attrs} -> + case exmpp_presence:get_type(Packet) of + 'probe' -> + % XXX OLD FORMAT: LFrom and LBFrom. + LFrom = short_jid(From), + LBFrom = short_jid(exmpp_jid:jid_to_bare_jid(From)), NewStateData = case ?SETS:is_element( LFrom, StateData#state.pres_a) orelse @@ -1075,6 +1082,8 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> case ?SETS:is_element( LFrom, StateData#state.pres_f) of true -> + % XXX OLD FORMAT: Stores old short + % JIDs. A = ?SETS:add_element( LFrom, StateData#state.pres_a), @@ -1083,6 +1092,8 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> case ?SETS:is_element( LBFrom, StateData#state.pres_f) of true -> + % XXX OLD FORMAT: Stores + % old short JIDs. A = ?SETS:add_element( LBFrom, StateData#state.pres_a), @@ -1092,40 +1103,51 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> end end end, - process_presence_probe(From, To, NewStateData), + % XXX OLD FORMAT: FromOld and ToOld + process_presence_probe(FromOld, ToOld, NewStateData), {false, Attrs, NewStateData}; - "error" -> - NewA = remove_element(jlib:jid_tolower(From), + 'error' -> + % XXX OLD FORMAT: LFrom. + LFrom = short_jid(From), + NewA = remove_element(LFrom, StateData#state.pres_a), {true, Attrs, StateData#state{pres_a = NewA}}; - "invisible" -> - Attrs1 = lists:keydelete("type", 1, Attrs), - {true, [{"type", "unavailable"} | Attrs1], StateData}; - "subscribe" -> + 'invisible' -> + % XXX OLD FORMAT: Create a function to change 'type'. + Attrs1 = exmpp_stanza:set_type_in_attrs(Attrs, + "unavailable"), + {true, Attrs1, StateData}; + 'subscribe' -> {true, Attrs, StateData}; - "subscribed" -> + 'subscribed' -> {true, Attrs, StateData}; - "unsubscribe" -> + 'unsubscribe' -> {true, Attrs, StateData}; - "unsubscribed" -> + 'unsubscribed' -> {true, Attrs, StateData}; _ -> + % XXX OLD FORMAT: From, To, Packet. case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {From, To, Packet}, + {FromOld, ToOld, PacketOld}, in]) of allow -> - LFrom = jlib:jid_tolower(From), - LBFrom = jlib:jid_remove_resource(LFrom), + % XXX OLD FORMAT: LFrom and LBFrom. + LFrom = short_jid(From), + LBFrom = short_jid( + exmpp_jid:jid_to_bare_jid(From)), %% Note contact availability + % XXX OLD FORMAT: Els are #xmlelement. + Els = PacketOld#xmlelement.children, Caps = mod_caps:read_caps(Els), - mod_caps:note_caps(StateData#state.server, From, Caps), - NewAvailable = case xml:get_attr_s("type", Attrs) of - "unavailable" -> + % XXX OLD FORMAT: From. + mod_caps:note_caps(StateData#state.server, FromOld, Caps), + NewAvailable = case exmpp_presence:get_type(Packet) of + 'unavailable' -> ?DICT:erase(LFrom, StateData#state.pres_available); _ -> ?DICT:store(LFrom, Caps, StateData#state.pres_available) @@ -1164,10 +1186,14 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> {false, Attrs, StateData} end end; - "broadcast" -> + % XXX OLD FORMAT: broadcast? + #xmlel{ns = _NS, name = 'broadcast', attrs = Attrs} -> + % XXX OLD FORMAT: Els are #xmlelement. + Els = PacketOld#xmlelement.children, ?DEBUG("broadcast~n~p~n", [Els]), case Els of [{item, IJID, ISubscription}] -> + % XXX OLD FORMAT: IJID is an old #jid. {false, Attrs, roster_change(IJID, ISubscription, StateData)}; @@ -1182,76 +1208,82 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> false -> {false, Attrs, StateData}; NewPL -> - PrivPushIQ = - #iq{type = set, xmlns = ?NS_PRIVACY, - id = "push", - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_PRIVACY}], - [{xmlelement, "list", - [{"name", PrivListName}], - []}]}]}, - PrivPushEl = - jlib:replace_from_to( - jlib:jid_remove_resource( - StateData#state.jid), - StateData#state.jid, - jlib:iq_to_xml(PrivPushIQ)), + PrivPushEl = exmpp_server_privacy:list_push( + StateData#state.jid, PrivListName), send_element(StateData, PrivPushEl), {false, Attrs, StateData#state{privacy_list = NewPL}} end; _ -> {false, Attrs, StateData} end; - "iq" -> - IQ = jlib:iq_query_info(Packet), - case IQ of - #iq{xmlns = ?NS_VCARD} -> - Host = StateData#state.server, - case ets:lookup(sm_iqtable, {?NS_VCARD, Host}) of - [{_, Module, Function, Opts}] -> - gen_iq_handler:handle(Host, Module, Function, Opts, - From, To, IQ); - [] -> - Err = jlib:make_error_reply( - Packet, ?ERR_FEATURE_NOT_IMPLEMENTED), - ejabberd_router:route(To, From, Err) - end, - {false, Attrs, StateData}; - #iq{} -> - case ejabberd_hooks:run_fold( - privacy_check_packet, StateData#state.server, - allow, - [StateData#state.user, - StateData#state.server, - StateData#state.privacy_list, - {From, To, Packet}, - in]) of - allow -> - {true, Attrs, StateData}; - deny -> - Err = jlib:make_error_reply( - Packet, ?ERR_FEATURE_NOT_IMPLEMENTED), - ejabberd_router:route(To, From, Err), - {false, Attrs, StateData} + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'iq', attrs = Attrs} -> + case exmpp_iq:is_request(Packet) of + true -> + case exmpp_iq:get_request(Packet) of + #xmlel{ns = ?NS_VCARD} -> + Host = StateData#state.server, + % XXX OLD FORMAT: sm_iqtable contains strings + % for namespaces. + case ets:lookup(sm_iqtable, {atom_to_list(?NS_VCARD), Host}) of + [{_, Module, Function, Opts}] -> + % XXX OLD FORMAT: IQ is an old #iq, + % From, To. + IQ = jlib:iq_query_info(PacketOld), + io:format("IQ = ~p~n", [IQ]), + gen_iq_handler:handle(Host, Module, Function, Opts, + FromOld, ToOld, IQ); + [] -> + Err = exmpp_stanza:error('feature-not-implemented'), + Res = exmpp_iq:error(Packet, Err), + % XXX OLD FORMAT: To, From, Res. + ResOld = exmpp_xml:xmlel_to_xmlelement( + Res, ?DEFAULT_NS, ?PREFIXED_NS), + ejabberd_router:route(ToOld, FromOld, ResOld) + end, + {false, Attrs, StateData}; + _ -> + % XXX OLD FORMAT: From, To and Packet. + case ejabberd_hooks:run_fold( + privacy_check_packet, StateData#state.server, + allow, + [StateData#state.user, + StateData#state.server, + StateData#state.privacy_list, + {FromOld, ToOld, PacketOld}, + in]) of + allow -> + {true, Attrs, StateData}; + deny -> + Err = exmpp_stanza:error( + 'feature-not-implemented'), + Res = exmpp_iq:error(Packet, Err), + % XXX OLD FORMAT: To, From, Res. + ResOld = exmpp_xml:xmlel_to_xmlelement( + Res, + ?DEFAULT_NS, ?PREFIXED_NS), + ejabberd_router:route(ToOld, FromOld, ResOld), + {false, Attrs, StateData} + end end; - _ -> + false -> {true, Attrs, StateData} end; - "message" -> + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', attrs = Attrs} -> + % XXX OLD FORMAT: From, To and Packet. case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {From, To, Packet}, + {FromOld, ToOld, PacketOld}, in]) of allow -> {true, Attrs, StateData}; deny -> {false, Attrs, StateData} end; - _ -> + #xmlel{attrs = Attrs} -> {true, Attrs, StateData} end, if @@ -1259,19 +1291,22 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> catch send_text(StateData, ?STREAM_TRAILER), {stop, normal, StateData}; Pass -> - Attrs2 = jlib:replace_from_to_attrs(jlib:jid_to_string(From), - jlib:jid_to_string(To), - NewAttrs), - FixedPacket = {xmlelement, Name, Attrs2, Els}, - Text = xml:element_to_string(FixedPacket), - send_text(StateData, Text), + Attrs2 = exmpp_stanza:set_sender_in_attrs(NewAttrs, From), + Attrs3 = exmpp_stanza:set_recipient_in_attrs(Attrs2, To), + FixedPacket = Packet#xmlel{attrs = Attrs3}, + send_element(StateData, FixedPacket), + % XXX OLD FORMAT: From, To, FixedPacket. + FixedPacketOld = exmpp_xml:xmlel_to_xmlelement(FixedPacket, + ?DEFAULT_NS, ?PREFIXED_NS), ejabberd_hooks:run(user_receive_packet, StateData#state.server, - [StateData#state.jid, From, To, FixedPacket]), - ejabberd_hooks:run(c2s_loop_debug, [{route, From, To, Packet}]), + [StateData#state.jid, FromOld, ToOld, FixedPacketOld]), + % XXX OLD FORMAT: From, To, FixedPacket. + ejabberd_hooks:run(c2s_loop_debug, [{route, FromOld, ToOld, PacketOld}]), fsm_next_state(StateName, NewState); true -> - ejabberd_hooks:run(c2s_loop_debug, [{route, From, To, Packet}]), + % XXX OLD FORMAT: From, To, FixedPacket. + ejabberd_hooks:run(c2s_loop_debug, [{route, FromOld, ToOld, PacketOld}]), fsm_next_state(StateName, NewState) end; handle_info({'DOWN', Monitor, _Type, _Object, _Info}, _StateName, StateData) @@ -1981,3 +2016,7 @@ fsm_reply(Reply, StateName, StateData) -> %% Used by c2s blacklist plugins is_ip_blacklisted({IP,_Port}) -> ejabberd_hooks:run_fold(check_bl_c2s, false, [IP]). + +short_jid(JID) -> + JID1 = exmpp_jid:to_ejabberd_jid(JID), + {JID1#jid.lnode, JID1#jid.ldomain, JID1#jid.lresource}. From e93e846e160a3fa8c5bf11fe5424dfd262fa86bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 24 Jun 2008 09:44:56 +0000 Subject: [PATCH 010/582] o Use the new exmpp_stream:opening_reply/3 function in wait_for_stream/2. o The function terminate/3 is converted to exmpp. SVN Revision: 1377 --- ChangeLog | 4 ++++ src/ejabberd_c2s.erl | 46 ++++++++++++++++++++++++-------------------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index 269717f7a..5fa9f4736 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,10 @@ JID form with empty strings for unspecified fields. Users are able to connect to ejabberd but some features don't seem to work proprerly. + * src/ejabberd_c2s.erl: Use the new exmpp_stream:opening_reply/3 + function in wait_for_stream/2. The function terminate/3 is converted + to exmpp. + 2008-06-23 Jean-Sébastien Pédron * src/ejabberd_c2s.erl (session_established): Convert JID to the diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 7567a591e..04e45780d 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -277,8 +277,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> DL end, Header = exmpp_stream:opening_reply(Opening, - StateData#state.streamid), - Header1 = exmpp_stream:set_lang(Header, DefaultLang), + StateData#state.streamid, DefaultLang), case NS of ?NS_XMPP -> Server = exmpp_stringprep:nameprep( @@ -291,7 +290,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> exmpp_jid:make_bare_jid(undefined, Server)), case exmpp_stream:get_version(Opening) of {1, 0} -> - send_element(StateData, Header1), + send_element(StateData, Header), case StateData#state.authenticated of false -> SASLState = @@ -373,12 +372,12 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> (not StateData#state.tls_enabled) and StateData#state.tls_required -> send_element(StateData, - exmpp_xml:append_child(Header1, + exmpp_xml:append_child(Header, exmpp_stream:error('policy-violation', "en", "Use of STARTTLS required"))), {stop, normal, StateData}; true -> - send_element(StateData, Header1), + send_element(StateData, Header), fsm_next_state(wait_for_auth, StateData#state{ server = Server, @@ -386,14 +385,14 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> end end; _ -> - Header2 = exmpp_stream:set_initiating_entity(Header1, + Header2 = exmpp_stream:set_initiating_entity(Header, ?MYNAME), send_element(StateData, exmpp_xml:append_child(Header2, exmpp_stream:error('host-unknown'))), {stop, normal, StateData} end; _ -> - Header2 = exmpp_stream:set_initiating_entity(Header1, ?MYNAME), + Header2 = exmpp_stream:set_initiating_entity(Header, ?MYNAME), send_element(StateData, exmpp_xml:append_child(Header2, exmpp_stream:error('invalid-namespace'))), {stop, normal, StateData} @@ -1328,26 +1327,29 @@ terminate(_Reason, StateName, StateData) -> replaced -> ?INFO_MSG("(~w) Replaced session for ~s", [StateData#state.socket, - jlib:jid_to_string(StateData#state.jid)]), + exmpp_jid:jid_to_string(StateData#state.jid)]), From = StateData#state.jid, - Packet = {xmlelement, "presence", - [{"type", "unavailable"}], - [{xmlelement, "status", [], - [{xmlcdata, "Replaced by new connection"}]}]}, + Packet = exmpp_presence:unavailable(), + Packet1 = exmpp_presence:set_status(Packet, + "Replaced by new connection"), ejabberd_sm:close_session_unset_presence( StateData#state.sid, StateData#state.user, StateData#state.server, StateData#state.resource, "Replaced by new connection"), + % XXX OLD FORMAT: From, Packet1 + FromOld = exmpp_jid:to_ejabberd_jid(From), + Packet1Old = exmpp_xml:xmlel_to_xmlelement(Packet1, + ?DEFAULT_NS, ?PREFIXED_NS), presence_broadcast( - StateData, From, StateData#state.pres_a, Packet), + StateData, FromOld, StateData#state.pres_a, Packet1Old), presence_broadcast( - StateData, From, StateData#state.pres_i, Packet); + StateData, FromOld, StateData#state.pres_i, Packet1Old); _ -> ?INFO_MSG("(~w) Close session for ~s", [StateData#state.socket, - jlib:jid_to_string(StateData#state.jid)]), + exmpp_jid:jid_to_string(StateData#state.jid)]), EmptySet = ?SETS:new(), case StateData of @@ -1361,8 +1363,11 @@ terminate(_Reason, StateName, StateData) -> StateData#state.resource); _ -> From = StateData#state.jid, - Packet = {xmlelement, "presence", - [{"type", "unavailable"}], []}, + Packet = exmpp_presence:unavailable(), + % XXX OLD FORMAT: From, Packet. + FromOld = exmpp_jid:to_ejabberd_jid(From), + PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, + ?DEFAULT_NS, ?PREFIXED_NS), ejabberd_sm:close_session_unset_presence( StateData#state.sid, StateData#state.user, @@ -1370,9 +1375,9 @@ terminate(_Reason, StateName, StateData) -> StateData#state.resource, ""), presence_broadcast( - StateData, From, StateData#state.pres_a, Packet), + StateData, FromOld, StateData#state.pres_a, PacketOld), presence_broadcast( - StateData, From, StateData#state.pres_i, Packet) + StateData, FromOld, StateData#state.pres_i, PacketOld) end end; _ -> @@ -2018,5 +2023,4 @@ is_ip_blacklisted({IP,_Port}) -> ejabberd_hooks:run_fold(check_bl_c2s, false, [IP]). short_jid(JID) -> - JID1 = exmpp_jid:to_ejabberd_jid(JID), - {JID1#jid.lnode, JID1#jid.ldomain, JID1#jid.lresource}. + {JID#jid.lnode, JID#jid.ldomain, JID#jid.lresource}. From 6f931ce4fd13d74f1d630e099ddc532364403656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 24 Jun 2008 16:12:56 +0000 Subject: [PATCH 011/582] Convert all presence-related functions. SVN Revision: 1378 --- ChangeLog | 2 + src/ejabberd_c2s.erl | 412 ++++++++++++++++++++++--------------------- 2 files changed, 214 insertions(+), 200 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5fa9f4736..e314e31e5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,8 @@ function in wait_for_stream/2. The function terminate/3 is converted to exmpp. + * src/ejabberd_c2s.erl: Convert all presence-related functions. + 2008-06-23 Jean-Sébastien Pédron * src/ejabberd_c2s.erl (session_established): Convert JID to the diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 04e45780d..060fdadd1 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -119,61 +119,15 @@ -define(DEFAULT_NS, ['jabber:client']). -define(PREFIXED_NS, [{?NS_XMPP, "stream"}]). --define(STREAM_HEADER, - "" - "" - ). - --define(STREAM_TRAILER, ""). - --define(INVALID_NS_ERR, - xml:element_to_string(?SERR_INVALID_NAMESPACE)). --define(INVALID_XML_ERR, - xml:element_to_string(?SERR_XML_NOT_WELL_FORMED)). --define(HOST_UNKNOWN_ERR, - xml:element_to_string(?SERR_HOST_UNKNOWN)). --define(POLICY_VIOLATION_ERR(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(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 = "", @@ -285,7 +239,6 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> case lists:member(Server, ?MYHOSTS) of true -> Lang = exmpp_stream:get_lang(Opening), - % OLD FORMAT: JID with empty strings. change_shaper(StateData, exmpp_jid:make_bare_jid(undefined, Server)), case exmpp_stream:get_version(Opening) of @@ -442,8 +395,10 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> {auth, _ID, set, {U, P, D, R}} -> try JID = exmpp_jid:make_jid(U, StateData#state.server, R), + % XXX OLD FORMAT: JID. + JIDOld = exmpp_jid:to_ejabberd_jid(JID), case acl:match_rule(StateData#state.server, - StateData#state.access, JID) of + StateData#state.access, JIDOld) of allow -> case ejabberd_auth:check_password_with_authmodule( U, StateData#state.server, P, @@ -467,8 +422,8 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> StateData#state.server, {[], []}, [U, StateData#state.server]), - LJID = {JID#jid.lnode, JID#jid.ldomain, - undefined}, + LJID = short_jid( + exmpp_jid:jid_to_bare_jid(JID)), Fs1 = [LJID | Fs], Ts1 = [LJID | Ts], PrivList = ejabberd_hooks:run_fold( @@ -767,9 +722,11 @@ wait_for_session({xmlstreamelement, El}, StateData) -> U = StateData#state.user, R = StateData#state.resource, JID = StateData#state.jid, - exmpp_server_session:want_establishment(El), + % XXX OLD FORMAT: JID. + JIDOld = exmpp_jid:to_ejabberd_jid(JID), + true = exmpp_server_session:want_establishment(El), case acl:match_rule(StateData#state.server, - StateData#state.access, JID) of + StateData#state.access, JIDOld) of allow -> ?INFO_MSG("(~w) Opened session for ~s", [StateData#state.socket, @@ -788,7 +745,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> StateData#state.server, {[], []}, [U, StateData#state.server]), - LJID = {JID#jid.lnode, JID#jid.ldomain, undefined}, + LJID = short_jid(exmpp_jid:jid_to_bare_jid(JID)), Fs1 = [LJID | Fs], Ts1 = [LJID | Ts], PrivList = @@ -804,10 +761,9 @@ wait_for_session({xmlstreamelement, El}, StateData) -> pres_t = ?SETS:from_list(Ts1), privacy_list = PrivList}); _ -> - % OLD FORMAT: Jid may use 'undefined' instead of empty - % strings. + % XXX OLD FORMAT: Jid. ejabberd_hooks:run(forbidden_session_hook, - StateData#state.server, [JID]), + StateData#state.server, [JIDOld]), ?INFO_MSG("(~w) Forbidden session for ~s", [StateData#state.socket, exmpp_jid:jid_to_string(JID)]), @@ -816,7 +772,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> fsm_next_state(wait_for_session, StateData) end catch - throw:_Exception -> + _Exception -> fsm_next_state(wait_for_session, StateData) end; @@ -883,12 +839,10 @@ session_established({xmlstreamelement, El}, StateData) -> resource = undefined} -> ?DEBUG("presence_update(~p,~n\t~p,~n\t~p)", [FromJID, PresenceEl, StateData]), - % XXX OLD FORMAT: PresenceElOld. - presence_update(FromJIDOld, PresenceElOld, + presence_update(FromJID, PresenceEl, StateData); _ -> - % XXX OLD FORMAT: PresenceElOld. - presence_track(FromJIDOld, ToJIDOld, PresenceElOld, + presence_track(FromJID, ToJID, PresenceEl, StateData) end; #xmlel{ns = ?NS_JABBER_CLIENT, name = 'iq'} -> @@ -896,7 +850,7 @@ session_established({xmlstreamelement, El}, StateData) -> FromJIDOld = exmpp_jid:to_ejabberd_jid(FromJID), ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), case exmpp_iq:get_payload(El) of - #xmlel{ns = ?NS_PRIVACY} -> + #xmlel{ns = ?NS_JABBER_PRIVACY} -> % XXX OLD FORMAT: IQ was #iq. ElOld2 = exmpp_xml:xmlel_to_xmlelement(El, ?DEFAULT_NS, ?PREFIXED_NS), @@ -1015,23 +969,33 @@ handle_sync_event({get_presence}, _From, StateName, StateData) -> User = StateData#state.user, PresLast = StateData#state.pres_last, - Show = get_showtag(PresLast), - Status = get_statustag(PresLast), + Show = case PresLast of + undefined -> "unavailable"; + _ -> exmpp_presence:get_show(PresLast) + end, + Status = case PresLast of + undefined -> ""; + _ -> exmpp_presence:get_status(PresLast) + end, Resource = StateData#state.resource, - Reply = {User, Resource, Show, Status}, + Reply = {User, Resource, atom_to_list(Show), Status}, fsm_reply(Reply, StateName, StateData); handle_sync_event(get_subscribed_and_online, _From, StateName, StateData) -> - % XXX OLD FORMAT: This function needs update. User has the form {N, D, R}. Subscribed = StateData#state.pres_f, Online = StateData#state.pres_available, - Pred = fun(User, _Caps) -> - ?SETS:is_element(jlib:jid_remove_resource(User), + Pred = fun({U, S, _R} = User, _Caps) -> + ?SETS:is_element({U, S, undefined}, Subscribed) orelse ?SETS:is_element(User, Subscribed) end, - SubscribedAndOnline = ?DICT:filter(Pred, Online), + % XXX OLD FORMAT: Resource is "". + Old = fun({U, S, undefined}, _Caps) -> {U, S, ""}; + (User, _Caps) -> User + end, + SubscribedAndOnline = ?DICT:map(Old, ?DICT:filter(Pred, Online)), + io:format("===== SubscribedAndOnline = ~p~n", [SubscribedAndOnline]), {reply, ?DICT:to_list(SubscribedAndOnline), StateName, StateData}; handle_sync_event(_Event, _From, StateName, StateData) -> @@ -1081,7 +1045,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> case ?SETS:is_element( LFrom, StateData#state.pres_f) of true -> - % XXX OLD FORMAT: Stores old short + % XXX OLD FORMAT: Stores short % JIDs. A = ?SETS:add_element( LFrom, @@ -1092,7 +1056,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> LBFrom, StateData#state.pres_f) of true -> % XXX OLD FORMAT: Stores - % old short JIDs. + % short JIDs. A = ?SETS:add_element( LBFrom, StateData#state.pres_a), @@ -1102,8 +1066,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> end end end, - % XXX OLD FORMAT: FromOld and ToOld - process_presence_probe(FromOld, ToOld, NewStateData), + process_presence_probe(From, To, NewStateData), {false, Attrs, NewStateData}; 'error' -> % XXX OLD FORMAT: LFrom. @@ -1191,8 +1154,9 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> Els = PacketOld#xmlelement.children, ?DEBUG("broadcast~n~p~n", [Els]), case Els of - [{item, IJID, ISubscription}] -> - % XXX OLD FORMAT: IJID is an old #jid. + [{item, {U, S, R} = _IJIDShort, ISubscription}] -> + % XXX OLD FORMAT: IJID is of the form {U, S, R}. + IJID = exmpp_jid:make_jid(U, S, R), {false, Attrs, roster_change(IJID, ISubscription, StateData)}; @@ -1287,7 +1251,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> end, if Pass == exit -> - catch send_text(StateData, ?STREAM_TRAILER), + catch send_element(StateData, exmpp_stream:closing()), {stop, normal, StateData}; Pass -> Attrs2 = exmpp_stanza:set_sender_in_attrs(NewAttrs, From), @@ -1338,14 +1302,10 @@ terminate(_Reason, StateName, StateData) -> StateData#state.server, StateData#state.resource, "Replaced by new connection"), - % XXX OLD FORMAT: From, Packet1 - FromOld = exmpp_jid:to_ejabberd_jid(From), - Packet1Old = exmpp_xml:xmlel_to_xmlelement(Packet1, - ?DEFAULT_NS, ?PREFIXED_NS), presence_broadcast( - StateData, FromOld, StateData#state.pres_a, Packet1Old), + StateData, From, StateData#state.pres_a, Packet1), presence_broadcast( - StateData, FromOld, StateData#state.pres_i, Packet1Old); + StateData, From, StateData#state.pres_i, Packet1); _ -> ?INFO_MSG("(~w) Close session for ~s", [StateData#state.socket, @@ -1364,10 +1324,6 @@ terminate(_Reason, StateName, StateData) -> _ -> From = StateData#state.jid, Packet = exmpp_presence:unavailable(), - % XXX OLD FORMAT: From, Packet. - FromOld = exmpp_jid:to_ejabberd_jid(From), - PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - ?DEFAULT_NS, ?PREFIXED_NS), ejabberd_sm:close_session_unset_presence( StateData#state.sid, StateData#state.user, @@ -1375,9 +1331,9 @@ terminate(_Reason, StateName, StateData) -> StateData#state.resource, ""), presence_broadcast( - StateData, FromOld, StateData#state.pres_a, PacketOld), + StateData, From, StateData#state.pres_a, Packet), presence_broadcast( - StateData, FromOld, StateData#state.pres_i, PacketOld) + StateData, From, StateData#state.pres_i, Packet) end end; _ -> @@ -1391,8 +1347,10 @@ terminate(_Reason, StateName, StateData) -> %%%---------------------------------------------------------------------- change_shaper(StateData, JID) -> + % XXX OLD FORMAT: JIDOld is an old #jid. + JIDOld = exmpp_jid:to_ejabberd_jid(JID), Shaper = acl:match_rule(StateData#state.server, - StateData#state.shaper, JID), + StateData#state.shaper, JIDOld), (StateData#state.sockmod):change_shaper(StateData#state.socket, Shaper). send_text(StateData, Text) -> @@ -1408,7 +1366,10 @@ new_id() -> is_auth_packet(El) -> - case jlib:iq_query_info(El) of + % XXX OLD FORMAT: El. + ElOld = exmpp_xml:xmlel_to_xmlelement(El, + ?DEFAULT_NS, ?PREFIXED_NS), + case jlib:iq_query_info(ElOld) of #iq{id = ID, type = Type, xmlns = ?NS_AUTH, sub_el = SubEl} -> {xmlelement, _, _, Els} = SubEl, {auth, ID, Type, @@ -1448,8 +1409,8 @@ get_conn_type(StateData) -> end. process_presence_probe(From, To, StateData) -> - LFrom = jlib:jid_tolower(From), - LBFrom = setelement(3, LFrom, ""), + LFrom = short_jid(From), + LBFrom = short_jid(exmpp_jid:jid_to_bare_jid(From)), case StateData#state.pres_last of undefined -> ok; @@ -1470,47 +1431,54 @@ process_presence_probe(From, To, StateData) -> if Cond1 -> Packet = StateData#state.pres_last, + % XXX OLD FORMAT: From, To, Packet. + FromOld = exmpp_jid:to_ejabberd_jid(From), + ToOld = exmpp_jid:to_ejabberd_jid(To), + PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, + ?DEFAULT_NS, ?PREFIXED_NS), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {To, From, Packet}, + {ToOld, FromOld, PacketOld}, out]) of deny -> ok; allow -> Pid=element(2, StateData#state.sid), - ejabberd_hooks:run(presence_probe_hook, StateData#state.server, [From, To, Pid]), + % XXX OLD FORMAT: From, To. + ejabberd_hooks:run(presence_probe_hook, StateData#state.server, [FromOld, ToOld, Pid]), %% Don't route a presence probe to oneself case From == To of false -> - ejabberd_router:route(To, From, Packet); + % XXX OLD FORMAT: From, To, Packet. + ejabberd_router:route(ToOld, FromOld, PacketOld); true -> ok end end; Cond2 -> - ejabberd_router:route(To, From, - {xmlelement, "presence", - [], - []}); + Packet = exmpp_presence:available(), + % XXX OLD FORMAT: From, To, Packet. + FromOld = exmpp_jid:to_ejabberd_jid(From), + ToOld = exmpp_jid:to_ejabberd_jid(To), + PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, + ?DEFAULT_NS, ?PREFIXED_NS), + ejabberd_router:route(ToOld, FromOld, PacketOld); true -> ok end end. presence_update(From, Packet, StateData) -> - {xmlelement, _Name, Attrs, _Els} = Packet, - case xml:get_attr_s("type", Attrs) of - "unavailable" -> - Status = case xml:get_subtag(Packet, "status") of - false -> - ""; - StatusTag -> - xml:get_tag_cdata(StatusTag) - end, + case exmpp_presence:get_type(Packet) of + 'unavailable' -> + Status = case exmpp_presence:get_status(Packet) of + undefined -> ""; + S -> S + end, Info = [{ip, StateData#state.ip},{conn, StateData#state.conn}], ejabberd_sm:unset_presence(StateData#state.sid, StateData#state.user, @@ -1524,8 +1492,12 @@ presence_update(From, Packet, StateData) -> pres_a = ?SETS:new(), pres_i = ?SETS:new(), pres_invis = false}; - "invisible" -> - NewPriority = get_priority_from_presence(Packet), + 'invisible' -> + NewPriority = try + exmpp_presence:get_priority(Packet) + catch + _Exception -> 0 + end, update_priority(NewPriority, Packet, StateData), NewState = if @@ -1545,26 +1517,34 @@ presence_update(From, Packet, StateData) -> StateData end, NewState; - "error" -> + 'error' -> StateData; - "probe" -> + 'probe' -> StateData; - "subscribe" -> + 'subscribe' -> StateData; - "subscribed" -> + 'subscribed' -> StateData; - "unsubscribe" -> + 'unsubscribe' -> StateData; - "unsubscribed" -> + 'unsubscribed' -> StateData; _ -> OldPriority = case StateData#state.pres_last of undefined -> 0; OldPresence -> - get_priority_from_presence(OldPresence) + try + exmpp_presence:get_priority(OldPresence) + catch + _Exception -> 0 + end end, - NewPriority = get_priority_from_presence(Packet), + NewPriority = try + exmpp_presence:get_priority(Packet) + catch + _Exception1 -> 0 + end, update_priority(NewPriority, Packet, StateData), FromUnavail = (StateData#state.pres_last == undefined) or StateData#state.pres_invis, @@ -1572,9 +1552,11 @@ presence_update(From, Packet, StateData) -> NewState = if FromUnavail -> + % XXX OLD FORMAT: JID. + JIDOld = exmpp_jid:to_ejabberd_jid(StateData#state.jid), ejabberd_hooks:run(user_available_hook, StateData#state.server, - [StateData#state.jid]), + [JIDOld]), if NewPriority >= 0 -> resend_offline_messages(StateData), resend_subscription_requests(StateData); @@ -1604,66 +1586,85 @@ presence_update(From, Packet, StateData) -> end. presence_track(From, To, Packet, StateData) -> - {xmlelement, _Name, Attrs, _Els} = Packet, - LTo = jlib:jid_tolower(To), + LTo = short_jid(To), User = StateData#state.user, Server = StateData#state.server, - case xml:get_attr_s("type", Attrs) of - "unavailable" -> - ejabberd_router:route(From, To, Packet), + % XXX OLD FORMAT: From, To, Packet. + FromOld = exmpp_jid:to_ejabberd_jid(From), + BFromOld = exmpp_jid:to_ejabberd_jid(exmpp_jid:jid_to_bare_jid(From)), + ToOld = exmpp_jid:to_ejabberd_jid(To), + PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, + ?DEFAULT_NS, ?PREFIXED_NS), + case exmpp_presence:get_type(Packet) of + 'unavailable' -> + % XXX OLD FORMAT: From, To, Packet. + ejabberd_router:route(FromOld, ToOld, PacketOld), I = remove_element(LTo, StateData#state.pres_i), A = remove_element(LTo, StateData#state.pres_a), StateData#state{pres_i = I, pres_a = A}; - "invisible" -> - ejabberd_router:route(From, To, Packet), + 'invisible' -> + % XXX OLD FORMAT: From, To, Packet. + ejabberd_router:route(FromOld, ToOld, PacketOld), I = ?SETS:add_element(LTo, StateData#state.pres_i), A = remove_element(LTo, StateData#state.pres_a), StateData#state{pres_i = I, pres_a = A}; - "subscribe" -> + 'subscribe' -> + % XXX OLD FORMAT: To. ejabberd_hooks:run(roster_out_subscription, Server, - [User, Server, To, subscribe]), - ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet), + [User, Server, ToOld, subscribe]), + % XXX OLD FORMAT: From, To, Packet. + ejabberd_router:route(BFromOld, ToOld, PacketOld), StateData; - "subscribed" -> + 'subscribed' -> + % XXX OLD FORMAT: To. ejabberd_hooks:run(roster_out_subscription, Server, - [User, Server, To, subscribed]), - ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet), + [User, Server, ToOld, subscribed]), + % XXX OLD FORMAT: From, To, Packet. + ejabberd_router:route(BFromOld, ToOld, PacketOld), StateData; - "unsubscribe" -> + 'unsubscribe' -> + % XXX OLD FORMAT: To. ejabberd_hooks:run(roster_out_subscription, Server, - [User, Server, To, unsubscribe]), - ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet), + [User, Server, ToOld, unsubscribe]), + % XXX OLD FORMAT: From, To, Packet. + ejabberd_router:route(BFromOld, ToOld, PacketOld), StateData; - "unsubscribed" -> + 'unsubscribed' -> + % XXX OLD FORMAT: To. ejabberd_hooks:run(roster_out_subscription, Server, - [User, Server, To, unsubscribed]), - ejabberd_router:route(jlib:jid_remove_resource(From), To, Packet), + [User, Server, ToOld, unsubscribed]), + % XXX OLD FORMAT: From, To, Packet. + ejabberd_router:route(BFromOld, ToOld, PacketOld), StateData; - "error" -> - ejabberd_router:route(From, To, Packet), + 'error' -> + % XXX OLD FORMAT: From, To, Packet. + ejabberd_router:route(FromOld, ToOld, PacketOld), StateData; - "probe" -> - ejabberd_router:route(From, To, Packet), + 'probe' -> + % XXX OLD FORMAT: From, To, Packet. + ejabberd_router:route(FromOld, ToOld, PacketOld), StateData; _ -> + % XXX OLD FORMAT: From, To, Packet. case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {From, To, Packet}, + {FromOld, ToOld, PacketOld}, out]) of deny -> ok; allow -> - ejabberd_router:route(From, To, Packet) + % XXX OLD FORMAT: From, To, Packet. + ejabberd_router:route(FromOld, ToOld, PacketOld) end, I = remove_element(LTo, StateData#state.pres_i), A = ?SETS:add_element(LTo, StateData#state.pres_a), @@ -1672,41 +1673,54 @@ presence_track(From, To, Packet, StateData) -> end. presence_broadcast(StateData, From, JIDSet, Packet) -> - lists:foreach(fun(JID) -> - FJID = jlib:make_jid(JID), + lists:foreach(fun({U, S, R}) -> + FJID = exmpp_jid:make_jid(U, S, R), + % XXX OLD FORMAT: From, FJID, Packet. + FJIDOld = exmpp_jid:to_ejabberd_jid(FJID), + FromOld = exmpp_jid:to_ejabberd_jid(From), + PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, + ?DEFAULT_NS, ?PREFIXED_NS), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {From, FJID, Packet}, + {FromOld, FJIDOld, PacketOld}, out]) of deny -> ok; allow -> - ejabberd_router:route(From, FJID, Packet) + % XXX OLD FORMAT: From, FJID, Packet. + ejabberd_router:route(FromOld, FJIDOld, PacketOld) end end, ?SETS:to_list(JIDSet)). presence_broadcast_to_trusted(StateData, From, T, A, Packet) -> + % XXX OLD FORMAT: From, Packet. + FromOld = exmpp_jid:to_ejabberd_jid(From), + PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, + ?DEFAULT_NS, ?PREFIXED_NS), lists:foreach( - fun(JID) -> + fun({U, S, R} = JID) -> case ?SETS:is_element(JID, T) of true -> - FJID = jlib:make_jid(JID), + FJID = exmpp_jid:make_jid(U, S, R), + % XXX OLD FORMAT: FJID. + FJIDOld = exmpp_jid:to_ejabberd_jid(FJID), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {From, FJID, Packet}, + {FromOld, FJIDOld, PacketOld}, out]) of deny -> ok; allow -> - ejabberd_router:route(From, FJID, Packet) + % XXX OLD FORMAT: From, FJID, Packet. + ejabberd_router:route(FromOld, FJIDOld, PacketOld) end; _ -> ok @@ -1715,13 +1729,21 @@ presence_broadcast_to_trusted(StateData, From, T, A, Packet) -> presence_broadcast_first(From, StateData, Packet) -> - ?SETS:fold(fun(JID, X) -> + Probe = exmpp_presence:probe(), + % XXX OLD FORMAT: From, Packet, Probe. + FromOld = exmpp_jid:to_ejabberd_jid(From), + PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, + ?DEFAULT_NS, ?PREFIXED_NS), + ProbeOld = exmpp_xml:xmlel_to_xmlelement(Probe, + ?DEFAULT_NS, ?PREFIXED_NS), + ?SETS:fold(fun({U, S, R}, X) -> + FJID = exmpp_jid:make_jid(U, S, R), + % XXX OLD FORMAT: FJID. + FJIDOld = exmpp_jid:to_ejabberd_jid(FJID), ejabberd_router:route( - From, - jlib:make_jid(JID), - {xmlelement, "presence", - [{"type", "probe"}], - []}), + FromOld, + FJIDOld, + ProbeOld), X end, [], @@ -1731,20 +1753,22 @@ presence_broadcast_first(From, StateData, Packet) -> StateData; true -> As = ?SETS:fold( - fun(JID, A) -> - FJID = jlib:make_jid(JID), + fun({U, S, R} = JID, A) -> + FJID = exmpp_jid:make_jid(U, S, R), + % XXX OLD FORMAT: FJID. + FJIDOld = exmpp_jid:to_ejabberd_jid(FJID), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {From, FJID, Packet}, + {FromOld, FJIDOld, PacketOld}, out]) of deny -> ok; allow -> - ejabberd_router:route(From, FJID, Packet) + ejabberd_router:route(FromOld, FJIDOld, PacketOld) end, ?SETS:add_element(JID, A) end, @@ -1764,7 +1788,7 @@ remove_element(E, Set) -> roster_change(IJID, ISubscription, StateData) -> - LIJID = jlib:jid_tolower(IJID), + LIJID = short_jid(IJID), IsFrom = (ISubscription == both) or (ISubscription == from), IsTo = (ISubscription == both) or (ISubscription == to), OldIsFrom = ?SETS:is_element(LIJID, StateData#state.pres_f), @@ -1786,7 +1810,10 @@ roster_change(IJID, ISubscription, StateData) -> P -> ?DEBUG("roster changed for ~p~n", [StateData#state.user]), From = StateData#state.jid, - To = jlib:make_jid(IJID), + To = IJID, + % XXX OLD FORMAT: From, To. + FromOld = exmpp_jid:to_ejabberd_jid(From), + ToOld = exmpp_jid:to_ejabberd_jid(To), Cond1 = (not StateData#state.pres_invis) and IsFrom and (not OldIsFrom), Cond2 = (not IsFrom) and OldIsFrom @@ -1795,18 +1822,23 @@ roster_change(IJID, ISubscription, StateData) -> if Cond1 -> ?DEBUG("C1: ~p~n", [LIJID]), + % XXX OLD FORMAT: P. + POld = exmpp_xml:xmlelement_to_xmlel(P, + ?DEFAULT_NS, ?PREFIXED_NS), + % XXX OLD FORMAT: From, To, P. case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {From, To, P}, + {FromOld, ToOld, POld}, out]) of deny -> ok; allow -> - ejabberd_router:route(From, To, P) + % XXX OLD FORMAT: From, To, P. + ejabberd_router:route(FromOld, ToOld, POld) end, A = ?SETS:add_element(LIJID, StateData#state.pres_a), @@ -1815,20 +1847,24 @@ roster_change(IJID, ISubscription, StateData) -> pres_t = TSet}; Cond2 -> ?DEBUG("C2: ~p~n", [LIJID]), - PU = {xmlelement, "presence", - [{"type", "unavailable"}], []}, + PU = exmpp_presence:unavailable(), + % XXX OLD FORMAT: PU. + PUOld = exmpp_xml:xmlelement_to_xmlel(PU, + ?DEFAULT_NS, ?PREFIXED_NS), + % XXX OLD FORMAT: From, To, PU. case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {From, To, PU}, + {FromOld, ToOld, PUOld}, out]) of deny -> ok; allow -> - ejabberd_router:route(From, To, PU) + % XXX OLD FORMAT: From, To, PU. + ejabberd_router:route(FromOld, ToOld, PUOld) end, I = remove_element(LIJID, StateData#state.pres_i), @@ -1846,27 +1882,17 @@ roster_change(IJID, ISubscription, StateData) -> update_priority(Priority, Packet, StateData) -> Info = [{ip, StateData#state.ip},{conn, StateData#state.conn}], + % XXX OLD FORMAT: Packet. + PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, + ?DEFAULT_NS, ?PREFIXED_NS), ejabberd_sm:set_presence(StateData#state.sid, StateData#state.user, StateData#state.server, StateData#state.resource, Priority, - Packet, + PacketOld, Info). -get_priority_from_presence(PresencePacket) -> - case xml:get_subtag(PresencePacket, "priority") of - false -> - 0; - SubEl -> - case catch list_to_integer(xml:get_tag_cdata(SubEl)) of - P when is_integer(P) -> - P; - _ -> - 0 - end - end. - process_privacy_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ, StateData) -> @@ -1952,21 +1978,6 @@ resend_subscription_requests(#state{user = User, end, PendingSubscriptions). -get_showtag(undefined) -> - "unavailable"; -get_showtag(Presence) -> - case xml:get_path_s(Presence, [{elem, "show"}, cdata]) of - "" -> "available"; - ShowTag -> ShowTag - end. - -get_statustag(undefined) -> - ""; -get_statustag(Presence) -> - case xml:get_path_s(Presence, [{elem, "status"}, cdata]) of - ShowTag -> ShowTag - end. - process_unauthenticated_stanza(StateData, El) -> case jlib:iq_query_info(El) of #iq{} = IQ -> @@ -2022,5 +2033,6 @@ fsm_reply(Reply, StateName, StateData) -> is_ip_blacklisted({IP,_Port}) -> ejabberd_hooks:run_fold(check_bl_c2s, false, [IP]). -short_jid(JID) -> +short_jid(JID0) -> + JID = exmpp_jid:to_ejabberd_jid(JID0), {JID#jid.lnode, JID#jid.ldomain, JID#jid.lresource}. From 07651d712ffc95f6a40ec3fcaa2f9f15f85c68a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 25 Jun 2008 12:37:45 +0000 Subject: [PATCH 012/582] Finish ejabberd_c2s conversion with the functions related to offline stanzas. SVN Revision: 1380 --- ChangeLog | 5 +++ src/ejabberd_c2s.erl | 88 ++++++++++++++++++++++++++++---------------- 2 files changed, 61 insertions(+), 32 deletions(-) diff --git a/ChangeLog b/ChangeLog index e314e31e5..9790c3f08 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-06-25 Jean-Sébastien Pédron + + * src/ejabberd_c2s.erl: Finish ejabberd_c2s conversion with the + functions related to offline stanzas. + 2008-06-24 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: The handle_info clause that treats routing diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 060fdadd1..1f87d2a25 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -851,12 +851,8 @@ session_established({xmlstreamelement, El}, StateData) -> ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), case exmpp_iq:get_payload(El) of #xmlel{ns = ?NS_JABBER_PRIVACY} -> - % XXX OLD FORMAT: IQ was #iq. - ElOld2 = exmpp_xml:xmlel_to_xmlelement(El, - ?DEFAULT_NS, ?PREFIXED_NS), - IQ = jlib:iq_query_info(ElOld2), process_privacy_iq( - FromJIDOld, ToJIDOld, IQ, StateData); + FromJID, ToJID, El, StateData); _ -> % XXX OLD FORMAT: NewElOld. NewElOld = exmpp_xml:xmlel_to_xmlelement(NewEl, @@ -1894,21 +1890,28 @@ update_priority(Priority, Packet, StateData) -> Info). process_privacy_iq(From, To, - #iq{type = Type, sub_el = SubEl} = IQ, + El, StateData) -> + % XXX OLD FORMAT: IQ is #iq. + ElOld = exmpp_xml:xmlel_to_xmlelement(El, + ?DEFAULT_NS, ?PREFIXED_NS), + IQOld = jlib:iq_query_info(ElOld), + % XXX OLD FORMAT: JIDs. + FromOld = exmpp_jid:to_ejabberd_jid(From), + ToOld = exmpp_jid:to_ejabberd_jid(To), {Res, NewStateData} = - case Type of + case exmpp_iq:get_type(El) of get -> R = ejabberd_hooks:run_fold( privacy_iq_get, StateData#state.server, {error, ?ERR_FEATURE_NOT_IMPLEMENTED}, - [From, To, IQ, StateData#state.privacy_list]), + [FromOld, ToOld, IQOld, StateData#state.privacy_list]), {R, StateData}; set -> case ejabberd_hooks:run_fold( privacy_iq_set, StateData#state.server, {error, ?ERR_FEATURE_NOT_IMPLEMENTED}, - [From, To, IQ]) of + [FromOld, ToOld, IQOld]) of {result, R, NewPrivList} -> {{result, R}, StateData#state{privacy_list = NewPrivList}}; @@ -1917,13 +1920,20 @@ process_privacy_iq(From, To, end, IQRes = case Res of - {result, Result} -> - IQ#iq{type = result, sub_el = Result}; - {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]} + {result, ResultOld} -> + Result = exmpp_xml:xmlelement_to_xmlel(ResultOld, + ?DEFAULT_NS, ?PREFIXED_NS), + exmpp_iq:result(El, Result); + {error, ErrorOld} -> + Error = exmpp_xml:xmlelement_to_xmlel(ErrorOld, + ?DEFAULT_NS, ?PREFIXED_NS), + exmpp_iq:error(El, Error) end, + % XXX OLD FORMAT: To, From, IQRes. + IQResOld = exmpp_xml:xmlel_to_xmlelement(IQRes, + ?DEFAULT_NS, ?PREFIXED_NS), ejabberd_router:route( - To, From, jlib:iq_to_xml(IQRes)), + ToOld, FromOld, IQResOld), NewStateData. @@ -1935,16 +1945,18 @@ resend_offline_messages(#state{user = User, [], [User, Server]) of Rs when list(Rs) -> + % XXX OLD FORMAT: From, To, Packet. + % XXX OLD FORMAT ON DISK! lists:foreach( fun({route, - From, To, {xmlelement, Name, Attrs, Els} = Packet}) -> + FromOld, ToOld, PacketOld}) -> Pass = case ejabberd_hooks:run_fold( privacy_check_packet, Server, allow, [User, Server, PrivList, - {From, To, Packet}, + {FromOld, ToOld, PacketOld}, in]) of allow -> true; @@ -1953,12 +1965,17 @@ resend_offline_messages(#state{user = User, end, if Pass -> - Attrs2 = jlib:replace_from_to_attrs( - jlib:jid_to_string(From), - jlib:jid_to_string(To), - Attrs), + % XXX OLD FORMAT: From, To, Packet. + From = exmpp_jid:from_ejabberd_jid(FromOld), + To = exmpp_jid:from_ejabberd_jid(ToOld), + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, + ?DEFAULT_NS, ?PREFIXED_NS), + Attrs1 = exmpp_stanza:set_sender_in_attrs( + Packet#xmlel.attrs, From), + Attrs2 = exmpp_stanza:set_recipient_in_attrs( + Attrs1, To), send_element(StateData, - {xmlelement, Name, Attrs2, Els}); + Packet#xmlel{attrs = Attrs2}); true -> ok end @@ -1972,32 +1989,39 @@ resend_subscription_requests(#state{user = User, Server, [], [User, Server]), - lists:foreach(fun(XMLPacket) -> + % XXX OLD FORMAT: XMLPacket. + % XXX OLD FORMAT ON DISK! + lists:foreach(fun(XMLPacketOld) -> + XMLPacket = exmpp_xml:xmlelement_to_xmlel( + XMLPacketOld, ?DEFAULT_NS, ?PREFIXED_NS), send_element(StateData, XMLPacket) end, PendingSubscriptions). process_unauthenticated_stanza(StateData, El) -> - case jlib:iq_query_info(El) of + ElOld = exmpp_xml:xmlel_to_xmlelement(El, ?DEFAULT_NS, ?PREFIXED_NS), + case jlib:iq_query_info(ElOld) of #iq{} = IQ -> - Res = ejabberd_hooks:run_fold(c2s_unauthenticated_iq, + ResOld = ejabberd_hooks:run_fold(c2s_unauthenticated_iq, StateData#state.server, empty, [StateData#state.server, IQ, StateData#state.ip]), - case Res of + case ResOld of empty -> % The only reasonable IQ's here are auth and register IQ's % They contain secrets, so don't include subelements to response - ResIQ = IQ#iq{type = error, - sub_el = [?ERR_SERVICE_UNAVAILABLE]}, - Res1 = jlib:replace_from_to( - jlib:make_jid("", StateData#state.server, ""), - jlib:make_jid("", "", ""), - jlib:iq_to_xml(ResIQ)), - send_element(StateData, jlib:remove_attr("to", Res1)); + ResIQ = exmpp_iq:error_without_original(El, + exmpp_stanza:error(El#xmlel.ns, 'service-unavailable')), + Res1 = exmpp_stanza:set_sender(ResIQ, + exmpp_jid:make_bare_jid(undefined, + StateData#state.server)), + Res2 = exmpp_stanza:remove_recipient(Res1), + send_element(StateData, Res2); _ -> + Res = exmpp_xml:xmlelement_to_xmlel(ResOld, + ?DEFAULT_NS, ?PREFIXED_NS), send_element(StateData, Res) end; _ -> From 999f3233bbcaa5a82c3bfeec2f54f6a3b630c366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 25 Jun 2008 13:27:03 +0000 Subject: [PATCH 013/582] Fix short JID comparison in get_subscribed_and_online; it was using 'undefined' instead of empty strings. SVN Revision: 1381 --- ChangeLog | 3 +++ src/ejabberd_c2s.erl | 9 +++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9790c3f08..e49553877 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,9 @@ * src/ejabberd_c2s.erl: Finish ejabberd_c2s conversion with the functions related to offline stanzas. + * src/ejabberd_c2s.erl (get_subscribed_and_online): Fix short JID + comparison; it was using 'undefined' instead of empty strings. + 2008-06-24 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: The handle_info clause that treats routing diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 1f87d2a25..c847506be 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -981,16 +981,13 @@ handle_sync_event({get_presence}, _From, StateName, StateData) -> handle_sync_event(get_subscribed_and_online, _From, StateName, StateData) -> Subscribed = StateData#state.pres_f, Online = StateData#state.pres_available, + % XXX OLF FORMAT: short JID with empty string(s). Pred = fun({U, S, _R} = User, _Caps) -> - ?SETS:is_element({U, S, undefined}, + ?SETS:is_element({U, S, ""}, Subscribed) orelse ?SETS:is_element(User, Subscribed) end, - % XXX OLD FORMAT: Resource is "". - Old = fun({U, S, undefined}, _Caps) -> {U, S, ""}; - (User, _Caps) -> User - end, - SubscribedAndOnline = ?DICT:map(Old, ?DICT:filter(Pred, Online)), + SubscribedAndOnline = ?DICT:filter(Pred, Online), io:format("===== SubscribedAndOnline = ~p~n", [SubscribedAndOnline]), {reply, ?DICT:to_list(SubscribedAndOnline), StateName, StateData}; From 1a311a30b5ebd1153367d59f379f73bda8387db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 26 Jun 2008 15:47:21 +0000 Subject: [PATCH 014/582] o Use a macro in ?DEFAULT_NS instead of the namespace atom directly. o Comment DBGFSM our again. o Remove macro ERR_SERVICE_UNAVAILABLE. o In wait_for_auth and is_auth_packet, an empty resource is returned as 'undefined', not the empty string in the {auth, ...} tuple. o In handle_sync_event, remove a debugging printf. o In handle_info({route, ...}), use macro IS_PRESENCE & friends instead of direct matching with NS_JABBER_CLIENT and name. This way, the S2S doesn't have to change the namespace of all its incoming stanzas to NS_JABBER_CLIENT. o In send_element, for stanzas under the NS_JABBER_SERVER namespace, lie to exmpp_xml by telling it that this namespace is the default one. SVN Revision: 1382 --- ChangeLog | 15 +++++++++++++++ src/ejabberd_c2s.erl | 30 +++++++++++++++++------------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index e49553877..f42d06a56 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2008-06-26 Jean-Sébastien Pédron + + * src/ejabberd_c2s.erl: Use a macro in ?DEFAULT_NS instead of the + namespace atom directly. Comment DBGFSM our again. Remove macro + ERR_SERVICE_UNAVAILABLE. + (wait_for_auth, is_auth_packet): An empty resource is returned as + 'undefined', not the empty string in the {auth, ...} tuple. + (handle_sync_event): Remove a debugging printf. + (handle_info/{route, ...}): Use macro IS_PRESENCE & friends instead of + direct matching with NS_JABBER_CLIENT and name. This way, the S2S + doesn't have to change the namespace of all its incoming stanzas to + NS_JABBER_CLIENT. + (send_element): For stanzas under the NS_JABBER_SERVER namespace, lie + to exmpp_xml by telling it that this namespace is the default one. + 2008-06-25 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Finish ejabberd_c2s conversion with the diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index c847506be..38aae6e8b 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -94,11 +94,11 @@ %-define(DBGFSM, true). -%-ifdef(DBGFSM). +-ifdef(DBGFSM). -define(FSMOPTS, [{debug, [trace]}]). -%-else. -%-define(FSMOPTS, []). -%-endif. +-else. +-define(FSMOPTS, []). +-endif. %% Module start with or without supervisor: -ifdef(NO_TRANSIENT_SUPERVISORS). @@ -116,7 +116,7 @@ % These are the namespace already declared by the stream opening. This is % used at serialization time. --define(DEFAULT_NS, ['jabber:client']). +-define(DEFAULT_NS, [?NS_JABBER_CLIENT]). -define(PREFIXED_NS, [{?NS_XMPP, "stream"}]). % XXX OLD FORMAT @@ -126,7 +126,6 @@ exmpp_xml:xmlel_to_xmlelement(exmpp_stanza:error(Condition), [?NS_JABBER_CLIENT], [{?NS_XMPP, "stream"}])). -define(ERR_FEATURE_NOT_IMPLEMENTED, ?STANZA_ERROR('feature-not-implemented')). --define(ERR_SERVICE_UNAVAILABLE, ?STANZA_ERROR('service-unavialable')). -record(iq, {id = "", type, @@ -387,7 +386,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> send_element(StateData, exmpp_server_legacy_auth:fields(El, Fields)), fsm_next_state(wait_for_auth, StateData); - {auth, _ID, set, {_U, _P, _D, ""}} -> + {auth, _ID, set, {_U, _P, _D, undefined}} -> Err = exmpp_stanza:error('not-acceptable', {"en", "No resource provided"}), send_element(StateData, exmpp_iq:error(El, Err)), @@ -988,7 +987,6 @@ handle_sync_event(get_subscribed_and_online, _From, StateName, StateData) -> ?SETS:is_element(User, Subscribed) end, SubscribedAndOnline = ?DICT:filter(Pred, Online), - io:format("===== SubscribedAndOnline = ~p~n", [SubscribedAndOnline]), {reply, ?DICT:to_list(SubscribedAndOnline), StateName, StateData}; handle_sync_event(_Event, _From, StateName, StateData) -> @@ -1021,7 +1019,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> To = exmpp_jid:from_ejabberd_jid(ToOld), {Pass, NewAttrs, NewState} = case Packet of - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = Attrs} -> + #xmlel{attrs = Attrs} when ?IS_PRESENCE(Packet) -> case exmpp_presence:get_type(Packet) of 'probe' -> % XXX OLD FORMAT: LFrom and LBFrom. @@ -1172,7 +1170,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> _ -> {false, Attrs, StateData} end; - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'iq', attrs = Attrs} -> + #xmlel{attrs = Attrs} when ?IS_IQ(Packet) -> case exmpp_iq:is_request(Packet) of true -> case exmpp_iq:get_request(Packet) of @@ -1224,7 +1222,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> false -> {true, Attrs, StateData} end; - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', attrs = Attrs} -> + #xmlel{attrs = Attrs} when ?IS_MESSAGE(Packet) -> % XXX OLD FORMAT: From, To and Packet. case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, @@ -1350,8 +1348,14 @@ send_text(StateData, Text) -> ?DEBUG("Send XML on stream = ~p", [lists:flatten(Text)]), (StateData#state.sockmod):send(StateData#state.socket, Text). +send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> + send_text(StateData, exmpp_xml:document_to_list(El)); +send_element(StateData, #xmlel{ns = ?NS_JABBER_SERVER} = El) -> + send_text(StateData, exmpp_xml:document_fragment_to_list(El, + [?NS_JABBER_SERVER], ?PREFIXED_NS)); send_element(StateData, El) -> - send_text(StateData, xml:element_to_string(El)). + send_text(StateData, exmpp_xml:document_fragment_to_list(El, + ?DEFAULT_NS, ?PREFIXED_NS)). new_id() -> @@ -1366,7 +1370,7 @@ is_auth_packet(El) -> #iq{id = ID, type = Type, xmlns = ?NS_AUTH, sub_el = SubEl} -> {xmlelement, _, _, Els} = SubEl, {auth, ID, Type, - get_auth_tags(Els, "", "", "", "")}; + get_auth_tags(Els, "", "", "", undefined)}; _ -> false end. From 22e79490fffbc7d62d42774d5ba4c8a2e2ca2918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 26 Jun 2008 15:48:19 +0000 Subject: [PATCH 015/582] Convert to exmpp. SVN Revision: 1383 --- ChangeLog | 2 + src/ejabberd_s2s_in.erl | 298 +++++++++++++++---------------- src/ejabberd_s2s_out.erl | 370 ++++++++++++++++++--------------------- 3 files changed, 319 insertions(+), 351 deletions(-) diff --git a/ChangeLog b/ChangeLog index f42d06a56..0851fcd71 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,8 @@ (send_element): For stanzas under the NS_JABBER_SERVER namespace, lie to exmpp_xml by telling it that this namespace is the default one. + * src/ejabberd_s2s_in.erl, src/ejabberd_s2s_out.erl: Convert to exmpp. + 2008-06-25 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Finish ejabberd_c2s conversion with the diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 9827775d2..31ae9454e 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -46,8 +46,9 @@ handle_info/3, terminate/3]). + -include("exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -ifdef(SSL39). -include_lib("ssl/include/ssl_pkix.hrl"). -define(PKIXEXPLICIT, 'OTP-PKIX'). @@ -92,28 +93,10 @@ [SockData, Opts])). -endif. --define(STREAM_HEADER(Version), - ("" - "") - ). - --define(STREAM_TRAILER, ""). - --define(INVALID_NAMESPACE_ERR, - xml:element_to_string(?SERR_INVALID_NAMESPACE)). - --define(HOST_UNKNOWN_ERR, - xml:element_to_string(?SERR_HOST_UNKNOWN)). - --define(INVALID_FROM_ERR, - xml:element_to_string(?SERR_INVALID_FROM)). - --define(INVALID_XML_ERR, - xml:element_to_string(?SERR_XML_NOT_WELL_FORMED)). +% These are the namespace already declared by the stream opening. This is +% used at serialization time. +-define(DEFAULT_NS, [?NS_JABBER_SERVER]). +-define(PREFIXED_NS, [{?NS_XMPP, "stream"}, {?NS_JABBER_DIALBACK, "db"}]). %%%---------------------------------------------------------------------- %%% API @@ -174,13 +157,16 @@ init([{SockMod, Socket}, Opts]) -> %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- -wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> - case {xml:get_attr_s("xmlns", Attrs), - xml:get_attr_s("xmlns:db", Attrs), - xml:get_attr_s("version", Attrs) == "1.0"} of - {"jabber:server", _, true} when +wait_for_stream({xmlstreamstart, Opening}, StateData) -> + case {exmpp_stream:get_default_ns(Opening), + exmpp_xml:is_ns_declared_here(Opening, ?NS_JABBER_DIALBACK), + exmpp_stream:get_version(Opening) == {1, 0}} of + {?NS_JABBER_SERVER, _, true} when StateData#state.tls and (not StateData#state.authenticated) -> - send_text(StateData, ?STREAM_HEADER(" version='1.0'")), + Opening_Reply = exmpp_stream:opening_reply(Opening, + StateData#state.streamid), + send_element(StateData, + exmpp_stream:set_dialback_support(Opening_Reply)), SASL = if StateData#state.tls_enabled -> @@ -190,10 +176,8 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> case (StateData#state.sockmod):get_verify_result( StateData#state.socket) of 0 -> - [{xmlelement, "mechanisms", - [{"xmlns", ?NS_SASL}], - [{xmlelement, "mechanism", [], - [{xmlcdata, "EXTERNAL"}]}]}]; + [exmpp_server_sasl:feature( + ["EXTERNAL"])]; _ -> [] end; @@ -207,30 +191,35 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> StateData#state.tls_enabled -> []; true -> - [{xmlelement, "starttls", - [{"xmlns", ?NS_TLS}], []}] + [exmpp_server_tls:feature()] end, - send_element(StateData, - {xmlelement, "stream:features", [], - SASL ++ StartTLS}), + send_element(StateData, exmpp_stream:features(SASL ++ StartTLS)), {next_state, wait_for_feature_request, StateData}; - {"jabber:server", _, true} when + {?NS_JABBER_SERVER, _, true} when StateData#state.authenticated -> - send_text(StateData, ?STREAM_HEADER(" version='1.0'")), + Opening_Reply = exmpp_stream:opening_reply(Opening, + StateData#state.streamid), send_element(StateData, - {xmlelement, "stream:features", [], []}), + exmpp_stream:set_dialback_support(Opening_Reply)), + send_element(StateData, exmpp_stream:features([])), {next_state, stream_established, StateData}; - {"jabber:server", "jabber:server:dialback", _} -> - send_text(StateData, ?STREAM_HEADER("")), + {?NS_JABBER_SERVER, true, _} -> + Opening_Reply = exmpp_stream:opening_reply(Opening, + StateData#state.streamid), + send_element(StateData, + exmpp_stream:set_dialback_support(Opening_Reply)), {next_state, stream_established, StateData}; _ -> - send_text(StateData, ?INVALID_NAMESPACE_ERR), + send_element(StateData, exmpp_stream:error('invalid-namespace')), {stop, normal, StateData} end; wait_for_stream({xmlstreamerror, _}, StateData) -> - send_text(StateData, - ?STREAM_HEADER("") ++ ?INVALID_XML_ERR ++ ?STREAM_TRAILER), + Opening_Reply = exmpp_stream:opening_reply(undefined, ?NS_JABBER_SERVER, + "", StateData#state.streamid), + send_element(StateData, Opening_Reply), + send_element(StateData, exmpp_stream:error('xml-not-well-formed')), + send_element(StateData, exmpp_stream:closing()), {stop, normal, StateData}; wait_for_stream(timeout, StateData) -> @@ -241,31 +230,29 @@ wait_for_stream(closed, StateData) -> wait_for_feature_request({xmlstreamelement, El}, StateData) -> - {xmlelement, Name, Attrs, Els} = El, TLS = StateData#state.tls, TLSEnabled = StateData#state.tls_enabled, SockMod = (StateData#state.sockmod):get_sockmod(StateData#state.socket), - case {xml:get_attr_s("xmlns", Attrs), Name} of - {?NS_TLS, "starttls"} when TLS == true, + case El of + #xmlel{ns = ?NS_TLS, name = 'starttls'} when TLS == true, TLSEnabled == false, SockMod == gen_tcp -> ?DEBUG("starttls", []), Socket = StateData#state.socket, + Proceed = exmpp_xml:document_fragment_to_list( + exmpp_server_tls:proceed(), ?DEFAULT_NS, ?PREFIXED_NS), TLSOpts = StateData#state.tls_options, TLSSocket = (StateData#state.sockmod):starttls( Socket, TLSOpts, - xml:element_to_string( - {xmlelement, "proceed", [{"xmlns", ?NS_TLS}], []})), + Proceed), {next_state, wait_for_stream, StateData#state{socket = TLSSocket, streamid = new_id(), tls_enabled = true }}; - {?NS_SASL, "auth"} when TLSEnabled -> - Mech = xml:get_attr_s("mechanism", Attrs), - case Mech of - "EXTERNAL" -> - Auth = jlib:decode_base64(xml:get_cdata(Els)), + #xmlel{ns = ?NS_SASL, name = 'auth'} when TLSEnabled -> + case exmpp_server_sasl:next_step(El) of + {auth, "EXTERNAL", Auth} -> AuthDomain = jlib:nameprep(Auth), AuthRes = case (StateData#state.sockmod):get_peer_certificate( @@ -300,8 +287,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> (StateData#state.sockmod):reset_stream( StateData#state.socket), send_element(StateData, - {xmlelement, "success", - [{"xmlns", ?NS_SASL}], []}), + exmpp_server_sasl:success()), ?DEBUG("(~w) Accepted s2s authentication for ~s", [StateData#state.socket, AuthDomain]), {next_state, wait_for_stream, @@ -311,16 +297,14 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> }}; true -> send_element(StateData, - {xmlelement, "failure", - [{"xmlns", ?NS_SASL}], []}), - send_text(StateData, ?STREAM_TRAILER), + exmpp_server_sasl:failure()), + send_element(StateData, + exmpp_stream:closing()), {stop, normal, StateData} end; _ -> send_element(StateData, - {xmlelement, "failure", - [{"xmlns", ?NS_SASL}], - [{xmlelement, "invalid-mechanism", [], []}]}), + exmpp_server_sasl:failure('invalid-mechanism')), {stop, normal, StateData} end; _ -> @@ -328,11 +312,12 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> end; wait_for_feature_request({xmlstreamend, _Name}, StateData) -> - send_text(StateData, ?STREAM_TRAILER), + send_element(StateData, exmpp_stream:closing()), {stop, normal, 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}; wait_for_feature_request(closed, StateData) -> @@ -345,8 +330,8 @@ stream_established({xmlstreamelement, El}, StateData) -> case is_key_packet(El) of {key, To, From, Id, Key} -> ?DEBUG("GET KEY: ~p", [{To, From, Id, Key}]), - LTo = jlib:nameprep(To), - LFrom = jlib:nameprep(From), + LTo = exmpp_stringprep:nameprep(To), + LFrom = exmpp_stringprep:nameprep(From), %% Checks if the from domain is allowed and if the to %% domain is handled by this server: case {ejabberd_s2s:allow_host(To, From), @@ -358,49 +343,56 @@ stream_established({xmlstreamelement, El}, StateData) -> Key, StateData#state.streamid}), Conns = ?DICT:store({LFrom, LTo}, wait_for_verification, StateData#state.connections), - change_shaper(StateData, LTo, jlib:make_jid("", LFrom, "")), + change_shaper(StateData, LTo, + exmpp_jid:make_bare_jid(undefined, LFrom)), {next_state, stream_established, StateData#state{connections = Conns, timer = Timer}}; {_, false} -> - send_text(StateData, ?HOST_UNKNOWN_ERR), + send_element(StateData, exmpp_stream:error('host-unknown')), {stop, normal, StateData}; {false, _} -> - send_text(StateData, ?INVALID_FROM_ERR), + send_element(StateData, exmpp_stream:error('invalid-from')), {stop, normal, StateData} end; {verify, To, From, Id, Key} -> ?DEBUG("VERIFY KEY: ~p", [{To, From, Id, Key}]), - LTo = jlib:nameprep(To), - LFrom = jlib:nameprep(From), - Type = case ejabberd_s2s:has_key({LTo, LFrom}, Key) of - true -> "valid"; - _ -> "invalid" - end, - %Type = if Key == Key1 -> "valid"; - % true -> "invalid" - % end, - send_element(StateData, - {xmlelement, - "db:verify", - [{"from", To}, - {"to", From}, - {"id", Id}, - {"type", Type}], - []}), + LTo = exmpp_stringprep:nameprep(To), + LFrom = exmpp_stringprep:nameprep(From), + send_element(StateData, exmpp_dialback:verify_response( + El, ejabberd_s2s:has_key({LTo, LFrom}, Key))), {next_state, stream_established, StateData#state{timer = Timer}}; _ -> - NewEl = jlib:remove_attr("xmlns", El), - {xmlelement, Name, Attrs, _Els} = NewEl, - From_s = xml:get_attr_s("from", Attrs), - From = jlib:string_to_jid(From_s), - To_s = xml:get_attr_s("to", Attrs), - To = jlib:string_to_jid(To_s), + From = case exmpp_stanza:get_sender(El) of + undefined -> + error; + F -> + try + exmpp_jid:string_to_jid(F) + catch + _Exception1 -> error + end + end, + To = case exmpp_stanza:get_recipient(El) of + undefined -> + error; + T -> + try + exmpp_jid:string_to_jid(T) + catch + _Exception2 -> error + end + end, + % XXX OLD FORMAT: El. + % XXX No namespace conversion (:server <-> :client) is done. + % This is handled by C2S and S2S send_element functions. + ElOld = exmpp_xml:xmlel_to_xmlelement(El, + ?DEFAULT_NS, ?PREFIXED_NS), if (To /= error) and (From /= error) -> - LFrom = From#jid.lserver, - LTo = To#jid.lserver, + LFrom = From#jid.ldomain, + LTo = To#jid.ldomain, if StateData#state.authenticated -> case (LFrom == StateData#state.auth_domain) @@ -409,15 +401,19 @@ stream_established({xmlstreamelement, El}, StateData) -> LTo, ejabberd_router:dirty_get_all_domains()) of true -> - if ((Name == "iq") or - (Name == "message") or - (Name == "presence")) -> + Name = El#xmlel.name, + if ((Name == 'iq') or + (Name == 'message') or + (Name == 'presence')) -> + % XXX OLD FORMAT: From, To. + FromOld = exmpp_jid:to_ejabberd_jid(From), + ToOld = exmpp_jid:to_ejabberd_jid(To), ejabberd_hooks:run( s2s_receive_packet, LFrom, - [From, To, NewEl]), + [FromOld, ToOld, ElOld]), ejabberd_router:route( - From, To, NewEl); + FromOld, ToOld, ElOld); true -> error end; @@ -428,15 +424,19 @@ stream_established({xmlstreamelement, El}, StateData) -> case ?DICT:find({LFrom, LTo}, StateData#state.connections) of {ok, established} -> - if ((Name == "iq") or - (Name == "message") or - (Name == "presence")) -> + Name = El#xmlel.name, + if ((Name == 'iq') or + (Name == 'message') or + (Name == 'presence')) -> + % XXX OLD FORMAT: From, To. + FromOld = exmpp_jid:to_ejabberd_jid(From), + ToOld = exmpp_jid:to_ejabberd_jid(To), ejabberd_hooks:run( s2s_receive_packet, LFrom, - [From, To, NewEl]), + [FromOld, ToOld, ElOld]), ejabberd_router:route( - From, To, NewEl); + FromOld, ToOld, ElOld); true -> error end; @@ -447,35 +447,24 @@ stream_established({xmlstreamelement, El}, StateData) -> true -> error end, - ejabberd_hooks:run(s2s_loop_debug, [{xmlstreamelement, El}]), + ejabberd_hooks:run(s2s_loop_debug, [{xmlstreamelement, ElOld}]), {next_state, stream_established, StateData#state{timer = Timer}} end; stream_established({valid, From, To}, StateData) -> - send_element(StateData, - {xmlelement, - "db:result", - [{"from", To}, - {"to", From}, - {"type", "valid"}], - []}), - LFrom = jlib:nameprep(From), - LTo = jlib:nameprep(To), + send_element(StateData, exmpp_dialback:validate(From, To)), + LFrom = exmpp_stringprep:nameprep(From), + LTo = exmpp_stringprep:nameprep(To), NSD = StateData#state{ connections = ?DICT:store({LFrom, LTo}, established, StateData#state.connections)}, {next_state, stream_established, NSD}; stream_established({invalid, From, To}, StateData) -> - send_element(StateData, - {xmlelement, - "db:result", - [{"from", To}, - {"to", From}, - {"type", "invalid"}], - []}), - LFrom = jlib:nameprep(From), - LTo = jlib:nameprep(To), + Valid = exmpp_dialback:validate(From, To), + send_element(StateData, exmpp_stanza:set_type(Valid, "invalid")), + LFrom = exmpp_stringprep:nameprep(From), + LTo = exmpp_stringprep:nameprep(To), NSD = StateData#state{ connections = ?DICT:erase({LFrom, LTo}, StateData#state.connections)}, @@ -485,8 +474,8 @@ stream_established({xmlstreamend, _Name}, StateData) -> {stop, normal, StateData}; stream_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}; stream_established(timeout, StateData) -> @@ -570,12 +559,21 @@ terminate(Reason, _StateName, StateData) -> send_text(StateData, Text) -> (StateData#state.sockmod):send(StateData#state.socket, Text). + +send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> + send_text(StateData, exmpp_xml:document_to_list(El)); +send_element(StateData, #xmlel{ns = ?NS_JABBER_CLIENT} = El) -> + send_text(StateData, exmpp_xml:document_fragment_to_list(El, + [?NS_JABBER_CLIENT], ?PREFIXED_NS)); send_element(StateData, El) -> - send_text(StateData, xml:element_to_string(El)). + send_text(StateData, exmpp_xml:document_fragment_to_list(El, + ?DEFAULT_NS, ?PREFIXED_NS)). change_shaper(StateData, Host, JID) -> - Shaper = acl:match_rule(Host, StateData#state.shaper, JID), + % XXX OLD FORMAT: JIDOld is an old #jid. + JIDOld = exmpp_jid:to_ejabberd_jid(JID), + Shaper = acl:match_rule(Host, StateData#state.shaper, JIDOld), (StateData#state.sockmod):change_shaper(StateData#state.socket, Shaper). @@ -592,18 +590,20 @@ cancel_timer(Timer) -> end. -is_key_packet({xmlelement, Name, Attrs, Els}) when Name == "db:result" -> +is_key_packet(#xmlel{ns = ?NS_JABBER_DIALBACK, name = 'result', + attrs = Attrs} = El) -> {key, - xml:get_attr_s("to", Attrs), - xml:get_attr_s("from", Attrs), - xml:get_attr_s("id", Attrs), - xml:get_cdata(Els)}; -is_key_packet({xmlelement, Name, Attrs, Els}) when Name == "db:verify" -> + exmpp_stanza:get_recipient_from_attrs(Attrs), + exmpp_stanza:get_sender_from_attrs(Attrs), + exmpp_stanza:get_id_from_attrs(Attrs), + exmpp_xml:get_cdata_as_list(El)}; +is_key_packet(#xmlel{ns = ?NS_JABBER_DIALBACK, name = 'verify', + attrs = Attrs} = El) -> {verify, - xml:get_attr_s("to", Attrs), - xml:get_attr_s("from", Attrs), - xml:get_attr_s("id", Attrs), - xml:get_cdata(Els)}; + exmpp_stanza:get_recipient_from_attrs(Attrs), + exmpp_stanza:get_sender_from_attrs(Attrs), + exmpp_stanza:get_id_from_attrs(Attrs), + exmpp_xml:get_cdata_as_list(El)}; is_key_packet(_) -> false. @@ -625,10 +625,10 @@ get_cert_domains(Cert) -> end, if D /= error -> - case jlib:string_to_jid(D) of - #jid{luser = "", - lserver = LD, - lresource = ""} -> + case exmpp_jid:string_to_jid(D) of + #jid{lnode = undefined, + ldomain = LD, + lresource = undefined} -> [LD]; _ -> [] @@ -662,8 +662,8 @@ get_cert_domains(Cert) -> {ok, D} when is_binary(D) -> case jlib:string_to_jid( binary_to_list(D)) of - #jid{luser = "", - lserver = LD, + #jid{lnode = "", + ldomain = LD, lresource = ""} -> case idna:domain_utf8_to_ascii(LD) of false -> @@ -678,10 +678,10 @@ get_cert_domains(Cert) -> [] end; ({dNSName, D}) when is_list(D) -> - case jlib:string_to_jid(D) of - #jid{luser = "", - lserver = LD, - lresource = ""} -> + case exmpp_jid:string_to_jid(D) of + #jid{lnode = undefined, + ldomain = LD, + lresource = undefined} -> [LD]; _ -> [] diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index e465cfb39..d33439a6e 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -54,8 +54,9 @@ code_change/4, test_get_addr_port/1]). +-include("exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -record(state, {socket, streamid, @@ -72,7 +73,7 @@ new = false, verify = false, timer}). -%%-define(DBGFSM, true). +%-define(DBGFSM, true). -ifdef(DBGFSM). -define(FSMOPTS, [{debug, [trace]}]). @@ -98,25 +99,10 @@ %% Specified in miliseconds. Default value is 5 minutes. -define(MAX_RETRY_DELAY, 300000). --define(STREAM_HEADER, - "" - "" - ). - --define(STREAM_TRAILER, ""). - --define(INVALID_NAMESPACE_ERR, - xml:element_to_string(?SERR_INVALID_NAMESPACE)). - --define(HOST_UNKNOWN_ERR, - xml:element_to_string(?SERR_HOST_UNKNOWN)). - --define(INVALID_XML_ERR, - xml:element_to_string(?SERR_XML_NOT_WELL_FORMED)). +% These are the namespace already declared by the stream opening. This is +% used at serialization time. +-define(DEFAULT_NS, [?NS_JABBER_SERVER]). +-define(PREFIXED_NS, [{?NS_XMPP, "stream"}, {?NS_JABBER_DIALBACK, "db"}]). %%%---------------------------------------------------------------------- %%% API @@ -209,16 +195,19 @@ open_socket(init, StateData) -> {ok, Socket} -> Version = if StateData#state.use_v10 -> - " version='1.0'"; + "1.0"; true -> "" end, NewStateData = StateData#state{socket = Socket, tls_enabled = false, streamid = new_id()}, - send_text(NewStateData, io_lib:format(?STREAM_HEADER, - [StateData#state.server, - Version])), + Opening = exmpp_stream:opening( + StateData#state.server, + ?NS_JABBER_SERVER, + Version), + send_element(NewStateData, + exmpp_stream:set_dialback_support(Opening)), {next_state, wait_for_stream, NewStateData, ?FSMTIMEOUT}; {error, _Reason} -> ?INFO_MSG("s2s connection: ~s -> ~s (remote server not found)", @@ -272,27 +261,27 @@ open_socket1(Addr, Port) -> %%---------------------------------------------------------------------- -wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> - case {xml:get_attr_s("xmlns", Attrs), - xml:get_attr_s("xmlns:db", Attrs), - xml:get_attr_s("version", Attrs) == "1.0"} of - {"jabber:server", "jabber:server:dialback", false} -> +wait_for_stream({xmlstreamstart, Opening}, StateData) -> + case {exmpp_stream:get_default_ns(Opening), + exmpp_xml:is_ns_declared_here(Opening, ?NS_JABBER_DIALBACK), + exmpp_stream:get_version(Opening) == {1, 0}} of + {?NS_JABBER_SERVER, true, false} -> send_db_request(StateData); - {"jabber:server", "jabber:server:dialback", true} when + {?NS_JABBER_SERVER, true, true} when StateData#state.use_v10 -> {next_state, wait_for_features, StateData, ?FSMTIMEOUT}; - {"jabber:server", "", true} when StateData#state.use_v10 -> + {?NS_JABBER_SERVER, false, true} when StateData#state.use_v10 -> {next_state, wait_for_features, StateData#state{db_enabled = false}, ?FSMTIMEOUT}; _ -> - send_text(StateData, ?INVALID_NAMESPACE_ERR), + send_element(StateData, exmpp_stream:error('invalid-namespace')), ?INFO_MSG("Closing s2s connection: ~s -> ~s (invalid namespace)", [StateData#state.myname, StateData#state.server]), {stop, normal, StateData} end; wait_for_stream({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()), ?INFO_MSG("Closing s2s connection: ~s -> ~s (invalid xml)", [StateData#state.myname, StateData#state.server]), {stop, normal, StateData}; @@ -376,8 +365,8 @@ wait_for_validation({xmlstreamend, _Name}, StateData) -> wait_for_validation({xmlstreamerror, _}, StateData) -> ?INFO_MSG("wait for validation: ~s -> ~s (xmlstreamerror)", [StateData#state.myname, StateData#state.server]), - 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}; wait_for_validation(timeout, #state{verify = {VPid, VKey, SID}} = StateData) @@ -401,41 +390,37 @@ wait_for_validation(closed, StateData) -> wait_for_features({xmlstreamelement, El}, StateData) -> case El of - {xmlelement, "stream:features", _Attrs, Els} -> + #xmlel{ns = ?NS_XMPP, name = 'features'} = Features -> {SASLEXT, StartTLS, StartTLSRequired} = lists:foldl( - fun({xmlelement, "mechanisms", Attrs1, Els1} = _El1, + fun(#xmlel{ns = ?NS_SASL, name = 'mechanisms'}, {_SEXT, STLS, STLSReq} = Acc) -> - case xml:get_attr_s("xmlns", Attrs1) of - ?NS_SASL -> - NewSEXT = - lists:any( - fun({xmlelement, "mechanism", _, Els2}) -> - case xml:get_cdata(Els2) of - "EXTERNAL" -> true; - _ -> false - end; - (_) -> false - end, Els1), - {NewSEXT, STLS, STLSReq}; - _ -> + try + Mechs = exmpp_client_sasl:announced_mechanisms( + El), + NewSEXT = lists:member("EXTERNAL", Mechs), + {NewSEXT, STLS, STLSReq} + catch + _Exception -> Acc end; - ({xmlelement, "starttls", Attrs1, _Els1} = El1, + (#xmlel{ns = ?NS_TLS, name ='starttls'}, {SEXT, _STLS, _STLSReq} = Acc) -> - case xml:get_attr_s("xmlns", Attrs1) of - ?NS_TLS -> - Req = case xml:get_subtag(El1, "required") of - {xmlelement, _, _, _} -> true; - false -> false - end, - {SEXT, true, Req}; - _ -> + try + Support = exmpp_client_tls:announced_support( + El), + case Support of + none -> Acc; + optional -> {SEXT, true, false}; + required -> {SEXT, true, true} + end + catch + _Exception -> Acc end; (_, Acc) -> Acc - end, {false, false, false}, Els), + end, {false, false, false}, Features#xmlel.children), if (not SASLEXT) and (not StartTLS) and StateData#state.authenticated -> @@ -450,19 +435,14 @@ wait_for_features({xmlstreamelement, El}, StateData) -> SASLEXT and StateData#state.try_auth and (StateData#state.new /= false) -> send_element(StateData, - {xmlelement, "auth", - [{"xmlns", ?NS_SASL}, - {"mechanism", "EXTERNAL"}], - [{xmlcdata, - jlib:encode_base64( - StateData#state.myname)}]}), + exmpp_client_sasl:selected_mechanism("EXTERNAL", + StateData#state.myname)), {next_state, wait_for_auth_result, StateData#state{try_auth = false}, ?FSMTIMEOUT}; StartTLS and StateData#state.tls and (not StateData#state.tls_enabled) -> send_element(StateData, - {xmlelement, "starttls", - [{"xmlns", ?NS_TLS}], []}), + exmpp_client_tls:starttls()), {next_state, wait_for_starttls_proceed, StateData, ?FSMTIMEOUT}; StartTLSRequired and (not StateData#state.tls) -> @@ -483,9 +463,8 @@ wait_for_features({xmlstreamelement, El}, StateData) -> use_v10 = false}, ?FSMTIMEOUT} end; _ -> - send_text(StateData, - xml:element_to_string(?SERR_BAD_FORMAT) ++ - ?STREAM_TRAILER), + send_element(StateData, exmpp_stream:error('bad-format')), + send_element(StateData, exmpp_stream:closing()), ?INFO_MSG("Closing s2s connection: ~s -> ~s (bad format)", [StateData#state.myname, StateData#state.server]), {stop, normal, StateData} @@ -496,8 +475,8 @@ wait_for_features({xmlstreamend, _Name}, StateData) -> {stop, normal, StateData}; wait_for_features({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()), ?INFO_MSG("wait for features: xmlstreamerror", []), {stop, normal, StateData}; @@ -512,48 +491,29 @@ wait_for_features(closed, StateData) -> wait_for_auth_result({xmlstreamelement, El}, StateData) -> case El of - {xmlelement, "success", Attrs, _Els} -> - case xml:get_attr_s("xmlns", Attrs) of - ?NS_SASL -> - ?DEBUG("auth: ~p", [{StateData#state.myname, - StateData#state.server}]), - ejabberd_socket:reset_stream(StateData#state.socket), - send_text(StateData, - io_lib:format(?STREAM_HEADER, - [StateData#state.server, - " version='1.0'"])), - {next_state, wait_for_stream, - StateData#state{streamid = new_id(), - authenticated = true - }, ?FSMTIMEOUT}; - _ -> - send_text(StateData, - xml:element_to_string(?SERR_BAD_FORMAT) ++ - ?STREAM_TRAILER), - ?INFO_MSG("Closing s2s connection: ~s -> ~s (bad format)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData} - end; - {xmlelement, "failure", Attrs, _Els} -> - case xml:get_attr_s("xmlns", Attrs) of - ?NS_SASL -> - ?DEBUG("restarted: ~p", [{StateData#state.myname, - StateData#state.server}]), - ejabberd_socket:close(StateData#state.socket), - {next_state, reopen_socket, - StateData#state{socket = undefined}, ?FSMTIMEOUT}; - _ -> - send_text(StateData, - xml:element_to_string(?SERR_BAD_FORMAT) ++ - ?STREAM_TRAILER), - ?INFO_MSG("Closing s2s connection: ~s -> ~s (bad format)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData} - end; + #xmlel{ns = ?NS_SASL, name = 'success'} -> + ?DEBUG("auth: ~p", [{StateData#state.myname, + StateData#state.server}]), + ejabberd_socket:reset_stream(StateData#state.socket), + Opening = exmpp_stream:opening( + StateData#state.server, + ?NS_JABBER_SERVER, + "1.0"), + send_element(StateData, + exmpp_stream:set_dialback_support(Opening)), + {next_state, wait_for_stream, + StateData#state{streamid = new_id(), + authenticated = true + }, ?FSMTIMEOUT}; + #xmlel{ns = ?NS_SASL, name = 'failure'} -> + ?DEBUG("restarted: ~p", [{StateData#state.myname, + StateData#state.server}]), + ejabberd_socket:close(StateData#state.socket), + {next_state, reopen_socket, + StateData#state{socket = undefined}, ?FSMTIMEOUT}; _ -> - send_text(StateData, - xml:element_to_string(?SERR_BAD_FORMAT) ++ - ?STREAM_TRAILER), + send_element(StateData, exmpp_stream:error('bad-format')), + send_element(StateData, exmpp_stream:closing()), ?INFO_MSG("Closing s2s connection: ~s -> ~s (bad format)", [StateData#state.myname, StateData#state.server]), {stop, normal, StateData} @@ -564,8 +524,8 @@ wait_for_auth_result({xmlstreamend, _Name}, StateData) -> {stop, normal, StateData}; wait_for_auth_result({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()), ?INFO_MSG("wait for auth result: xmlstreamerror", []), {stop, normal, StateData}; @@ -580,42 +540,36 @@ wait_for_auth_result(closed, StateData) -> wait_for_starttls_proceed({xmlstreamelement, El}, StateData) -> case El of - {xmlelement, "proceed", Attrs, _Els} -> - case xml:get_attr_s("xmlns", Attrs) of - ?NS_TLS -> - ?DEBUG("starttls: ~p", [{StateData#state.myname, - StateData#state.server}]), - Socket = StateData#state.socket, - TLSOpts = case ejabberd_config:get_local_option( - {domain_certfile, - StateData#state.server}) of - undefined -> - StateData#state.tls_options; - CertFile -> - [{certfile, CertFile} | - lists:keydelete( - certfile, 1, - StateData#state.tls_options)] - end, - TLSSocket = ejabberd_socket:starttls(Socket, TLSOpts), - NewStateData = StateData#state{socket = TLSSocket, - streamid = new_id(), - tls_enabled = true - }, - send_text(NewStateData, - io_lib:format(?STREAM_HEADER, - [StateData#state.server, - " version='1.0'"])), - {next_state, wait_for_stream, NewStateData, ?FSMTIMEOUT}; - _ -> - send_text(StateData, - xml:element_to_string(?SERR_BAD_FORMAT) ++ - ?STREAM_TRAILER), - ?INFO_MSG("Closing s2s connection: ~s -> ~s (bad format)", - [StateData#state.myname, StateData#state.server]), - {stop, normal, StateData} - end; + #xmlel{ns = ?NS_TLS, name = 'proceed'} -> + ?DEBUG("starttls: ~p", [{StateData#state.myname, + StateData#state.server}]), + Socket = StateData#state.socket, + TLSOpts = case ejabberd_config:get_local_option( + {domain_certfile, + StateData#state.server}) of + undefined -> + StateData#state.tls_options; + CertFile -> + [{certfile, CertFile} | + lists:keydelete( + certfile, 1, + StateData#state.tls_options)] + end, + TLSSocket = ejabberd_socket:starttls(Socket, TLSOpts), + NewStateData = StateData#state{socket = TLSSocket, + streamid = new_id(), + tls_enabled = true + }, + Opening = exmpp_stream:opening( + StateData#state.server, + ?NS_JABBER_SERVER, + "1.0"), + send_element(NewStateData, + exmpp_stream:set_dialback_support(Opening)), + {next_state, wait_for_stream, NewStateData, ?FSMTIMEOUT}; _ -> + send_element(StateData, exmpp_stream:error('bad-format')), + send_element(StateData, exmpp_stream:closing()), ?INFO_MSG("Closing s2s connection: ~s -> ~s (bad format)", [StateData#state.myname, StateData#state.server]), {stop, normal, StateData} @@ -626,8 +580,8 @@ wait_for_starttls_proceed({xmlstreamend, _Name}, StateData) -> {stop, normal, StateData}; wait_for_starttls_proceed({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()), ?INFO_MSG("wait for starttls proceed: xmlstreamerror", []), {stop, normal, StateData}; @@ -690,8 +644,8 @@ stream_established({xmlstreamend, _Name}, StateData) -> {stop, normal, StateData}; stream_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()), ?INFO_MSG("stream established: ~s -> ~s (xmlstreamerror)", [StateData#state.myname, StateData#state.server]), {stop, normal, StateData}; @@ -759,7 +713,10 @@ handle_info({send_text, Text}, StateName, StateData) -> {next_state, StateName, StateData#state{timer = Timer}, get_timeout_interval(StateName)}; -handle_info({send_element, El}, StateName, StateData) -> +handle_info({send_element, ElOld}, StateName, StateData) -> + % XXX OLD FORMAT: El. + El = exmpp_xml:xmlelement_to_xmlel(ElOld, + [?NS_JABBER_CLIENT], ?PREFIXED_NS), case StateName of stream_established -> cancel_timer(StateData#state.timer), @@ -769,7 +726,7 @@ handle_info({send_element, El}, StateName, StateData) -> %% In this state we bounce all message: We are waiting before %% trying to reconnect wait_before_retry -> - bounce_element(El, ?ERR_REMOTE_SERVER_NOT_FOUND), + bounce_element(El, 'remote-server-not-found'), {next_state, StateName, StateData}; _ -> Q = queue:in(El, StateData#state.queue), @@ -811,8 +768,8 @@ terminate(Reason, StateName, StateData) -> {StateData#state.myname, StateData#state.server}, self(), Key) end, %% bounce queue manage by process and Erlang message queue - bounce_queue(StateData#state.queue, ?ERR_REMOTE_SERVER_NOT_FOUND), - bounce_messages(?ERR_REMOTE_SERVER_NOT_FOUND), + bounce_queue(StateData#state.queue, 'remote-server-not-found'), + bounce_messages('remote-server-not-found'), case StateData#state.socket of undefined -> ok; @@ -828,8 +785,14 @@ terminate(Reason, StateName, StateData) -> send_text(StateData, Text) -> ejabberd_socket:send(StateData#state.socket, Text). +send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> + send_text(StateData, exmpp_xml:document_to_list(El)); +send_element(StateData, #xmlel{ns = ?NS_JABBER_CLIENT} = El) -> + send_text(StateData, exmpp_xml:document_fragment_to_list(El, + [?NS_JABBER_CLIENT], ?PREFIXED_NS)); send_element(StateData, El) -> - send_text(StateData, xml:element_to_string(El)). + send_text(StateData, exmpp_xml:document_fragment_to_list(El, + ?DEFAULT_NS, ?PREFIXED_NS)). send_queue(StateData, Q) -> case queue:out(Q) of @@ -840,24 +803,31 @@ send_queue(StateData, Q) -> ok end. -%% Bounce a single message (xmlelement) -bounce_element(El, Error) -> - {xmlelement, _Name, Attrs, _SubTags} = El, - case xml:get_attr_s("type", Attrs) of +%% Bounce a single message (xmlel) +bounce_element(El, Condition) -> + case exmpp_stanza:get_type(El) of "error" -> ok; "result" -> ok; _ -> - 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) + Error = exmpp_stanza:error(El#xmlel.ns, Condition), + Err = exmpp_stanza:reply_with_error(El, Error), + From = exmpp_jid:string_to_jid(exmpp_stanza:get_sender(El)), + To = exmpp_jid:string_to_jid(exmpp_stanza:get_recipient(El)), + % XXX OLD FORMAT: From, To, Err. + % XXX No namespace conversion (:server <-> :client) is done. + % This is handled by C2S and S2S send_element functions. + ErrOld = exmpp_xml:xmlel_to_xmlelement(Err, + [?NS_JABBER_CLIENT], ?PREFIXED_NS), + FromOld = exmpp_jid:to_ejabberd_jid(From), + ToOld = exmpp_jid:to_ejabberd_jid(To), + ejabberd_router:route(ToOld, FromOld, ErrOld) end. -bounce_queue(Q, Error) -> +bounce_queue(Q, Condition) -> case queue:out(Q) of {{value, El}, Q1} -> - bounce_element(El, Error), - bounce_queue(Q1, Error); + bounce_element(El, Condition), + bounce_queue(Q1, Condition); {empty, _} -> ok end. @@ -874,11 +844,14 @@ cancel_timer(Timer) -> ok end. -bounce_messages(Error) -> +bounce_messages(Condition) -> receive - {send_element, El} -> - bounce_element(El, Error), - bounce_messages(Error) + {send_element, ElOld} -> + % XXX OLD FORMAT: El. + El = exmpp_xml:xmlelement_to_xmlel(ElOld, + [?NS_JABBER_CLIENT], ?PREFIXED_NS), + bounce_element(El, Condition), + bounce_messages(Condition) after 0 -> ok end. @@ -902,40 +875,33 @@ send_db_request(StateData) -> false -> ok; Key1 -> - send_element(StateData, - {xmlelement, - "db:result", - [{"from", StateData#state.myname}, - {"to", Server}], - [{xmlcdata, Key1}]}) + send_element(StateData, exmpp_dialback:key( + StateData#state.myname, Server, Key1)) end, case StateData#state.verify of false -> ok; {_Pid, Key2, SID} -> - send_element(StateData, - {xmlelement, - "db:verify", - [{"from", StateData#state.myname}, - {"to", StateData#state.server}, - {"id", SID}], - [{xmlcdata, Key2}]}) + send_element(StateData, exmpp_dialback:verify_request( + StateData#state.myname, StateData#state.server, SID, Key2)) end, {next_state, wait_for_validation, StateData#state{new = New}, ?FSMTIMEOUT*6}. -is_verify_res({xmlelement, Name, Attrs, _Els}) when Name == "db:result" -> +is_verify_res(#xmlel{ns = ?NS_JABBER_DIALBACK, name = 'result', + attrs = Attrs}) -> {result, - xml:get_attr_s("to", Attrs), - xml:get_attr_s("from", Attrs), - xml:get_attr_s("id", Attrs), - xml:get_attr_s("type", Attrs)}; -is_verify_res({xmlelement, Name, Attrs, _Els}) when Name == "db:verify" -> + exmpp_stanza:get_recipient_from_attrs(Attrs), + exmpp_stanza:get_sender_from_attrs(Attrs), + exmpp_stanza:get_id_from_attrs(Attrs), + exmpp_stanza:get_type_from_attrs(Attrs)}; +is_verify_res(#xmlel{ns = ?NS_JABBER_DIALBACK, name = 'verify', + attrs = Attrs}) -> {verify, - xml:get_attr_s("to", Attrs), - xml:get_attr_s("from", Attrs), - xml:get_attr_s("id", Attrs), - xml:get_attr_s("type", Attrs)}; + exmpp_stanza:get_recipient_from_attrs(Attrs), + exmpp_stanza:get_sender_from_attrs(Attrs), + exmpp_stanza:get_id_from_attrs(Attrs), + exmpp_stanza:get_type_from_attrs(Attrs)}; is_verify_res(_) -> false. @@ -1032,8 +998,8 @@ get_timeout_interval(StateName) -> %% function that want to wait for a reconnect delay before stopping. wait_before_reconnect(StateData) -> %% bounce queue manage by process and Erlang message queue - bounce_queue(StateData#state.queue, ?ERR_REMOTE_SERVER_NOT_FOUND), - bounce_messages(?ERR_REMOTE_SERVER_NOT_FOUND), + bounce_queue(StateData#state.queue, 'remote-server-not-found'), + bounce_messages('remote-server-not-found'), cancel_timer(StateData#state.timer), Delay = case StateData#state.delay_to_retry of undefined_delay -> From b32aba27c1b593d560b04973d404f570535791b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 27 Jun 2008 13:46:08 +0000 Subject: [PATCH 016/582] o Use the new exmpp namespace macro names. o Update send_element/2 to use exmpp new to_list functions. SVN Revision: 1384 --- ChangeLog | 6 +++ src/ejabberd_c2s.erl | 80 +++++++++++++++++++--------------------- src/ejabberd_s2s_in.erl | 26 +++++++------ src/ejabberd_s2s_out.erl | 23 +++++++----- 4 files changed, 71 insertions(+), 64 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0851fcd71..947a8e4ad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-06-27 Jean-Sébastien Pédron + + * src/ejabberd_c2s.erl, src/ejabberd_s2s_out.erl, + src/ejabberd_s2s_in.erl: Use the new exmpp namespace macro names. + Update send_element/2 to use exmpp new to_list functions. + 2008-06-26 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Use a macro in ?DEFAULT_NS instead of the diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 38aae6e8b..953e9beb2 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -116,11 +116,8 @@ % These are the namespace already declared by the stream opening. This is % used at serialization time. --define(DEFAULT_NS, [?NS_JABBER_CLIENT]). --define(PREFIXED_NS, [{?NS_XMPP, "stream"}]). - -% XXX OLD FORMAT --define(NS_AUTH, "jabber:iq:auth"). +-define(DEFAULT_NS, ?NS_JABBER_CLIENT). +-define(PREFIXED_NS, [{?NS_XMPP, ?NS_XMPP_pfx}]). -define(STANZA_ERROR(Condition), exmpp_xml:xmlel_to_xmlelement(exmpp_stanza:error(Condition), @@ -553,7 +550,7 @@ wait_for_feature_request({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, end, Socket = StateData#state.socket, Proceed = exmpp_xml:document_fragment_to_list( - exmpp_server_tls:proceed(), ?DEFAULT_NS, ?PREFIXED_NS), + exmpp_server_tls:proceed(), [?DEFAULT_NS], ?PREFIXED_NS), TLSSocket = (StateData#state.sockmod):starttls( Socket, TLSOpts, Proceed), @@ -821,10 +818,10 @@ session_established({xmlstreamelement, El}, StateData) -> c2s_update_presence, Server, exmpp_xml:xmlel_to_xmlelement(NewEl, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), [User, Server]), PresenceEl = exmpp_xml:xmlelement_to_xmlel(PresenceElOld, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), % XXX OLD FORMAT: PresenceElOld, *JID. FromJIDOld = exmpp_jid:to_ejabberd_jid(FromJID), ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), @@ -849,13 +846,13 @@ session_established({xmlstreamelement, El}, StateData) -> FromJIDOld = exmpp_jid:to_ejabberd_jid(FromJID), ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), case exmpp_iq:get_payload(El) of - #xmlel{ns = ?NS_JABBER_PRIVACY} -> + #xmlel{ns = ?NS_PRIVACY} -> process_privacy_iq( FromJID, ToJID, El, StateData); _ -> % XXX OLD FORMAT: NewElOld. NewElOld = exmpp_xml:xmlel_to_xmlelement(NewEl, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_hooks:run( user_send_packet, Server, @@ -868,7 +865,7 @@ session_established({xmlstreamelement, El}, StateData) -> #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message'} -> % XXX OLD FORMAT: NewElOld, JIDs. NewElOld = exmpp_xml:xmlel_to_xmlelement(NewEl, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), FromJIDOld = exmpp_jid:to_ejabberd_jid(FromJID), ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), ejabberd_hooks:run(user_send_packet, @@ -882,7 +879,7 @@ session_established({xmlstreamelement, El}, StateData) -> end, % XXX OLD FORMAT: El. ElOld = exmpp_xml:xmlel_to_xmlelement(El, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_hooks:run(c2s_loop_debug, [{xmlstreamelement, ElOld}]), fsm_next_state(session_established, NewState) catch @@ -898,7 +895,7 @@ session_established({xmlstreamelement, El}, StateData) -> end, % XXX OLD FORMAT: ElOld1. ElOld1 = exmpp_xml:xmlel_to_xmlelement(El, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_hooks:run(c2s_loop_debug, [{xmlstreamelement, ElOld1}]), fsm_next_state(session_established, StateData); throw:Exception -> @@ -1014,7 +1011,7 @@ handle_info(replaced, _StateName, StateData) -> handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> %% XXX OLD FORMAT: From, To and Packet are in the old format. Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), From = exmpp_jid:from_ejabberd_jid(FromOld), To = exmpp_jid:from_ejabberd_jid(ToOld), {Pass, NewAttrs, NewState} = @@ -1191,7 +1188,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> Res = exmpp_iq:error(Packet, Err), % XXX OLD FORMAT: To, From, Res. ResOld = exmpp_xml:xmlel_to_xmlelement( - Res, ?DEFAULT_NS, ?PREFIXED_NS), + Res, [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_router:route(ToOld, FromOld, ResOld) end, {false, Attrs, StateData}; @@ -1214,7 +1211,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> % XXX OLD FORMAT: To, From, Res. ResOld = exmpp_xml:xmlel_to_xmlelement( Res, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_router:route(ToOld, FromOld, ResOld), {false, Attrs, StateData} end @@ -1251,7 +1248,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> send_element(StateData, FixedPacket), % XXX OLD FORMAT: From, To, FixedPacket. FixedPacketOld = exmpp_xml:xmlel_to_xmlelement(FixedPacket, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_hooks:run(user_receive_packet, StateData#state.server, [StateData#state.jid, FromOld, ToOld, FixedPacketOld]), @@ -1349,13 +1346,11 @@ send_text(StateData, Text) -> (StateData#state.sockmod):send(StateData#state.socket, Text). send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> - send_text(StateData, exmpp_xml:document_to_list(El)); + send_text(StateData, exmpp_stream:to_list(El)); send_element(StateData, #xmlel{ns = ?NS_JABBER_SERVER} = El) -> - send_text(StateData, exmpp_xml:document_fragment_to_list(El, - [?NS_JABBER_SERVER], ?PREFIXED_NS)); + send_text(StateData, exmpp_stanza:to_list(El, ?NS_JABBER_SERVER)); send_element(StateData, El) -> - send_text(StateData, exmpp_xml:document_fragment_to_list(El, - ?DEFAULT_NS, ?PREFIXED_NS)). + send_text(StateData, exmpp_stanza:to_list(El, ?DEFAULT_NS)). new_id() -> @@ -1365,9 +1360,10 @@ new_id() -> is_auth_packet(El) -> % XXX OLD FORMAT: El. ElOld = exmpp_xml:xmlel_to_xmlelement(El, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), + NS_Auth = atom_to_list(?NS_LEGACY_AUTH), case jlib:iq_query_info(ElOld) of - #iq{id = ID, type = Type, xmlns = ?NS_AUTH, sub_el = SubEl} -> + #iq{id = ID, type = Type, xmlns = NS_Auth, sub_el = SubEl} -> {xmlelement, _, _, Els} = SubEl, {auth, ID, Type, get_auth_tags(Els, "", "", "", undefined)}; @@ -1432,7 +1428,7 @@ process_presence_probe(From, To, StateData) -> FromOld = exmpp_jid:to_ejabberd_jid(From), ToOld = exmpp_jid:to_ejabberd_jid(To), PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, @@ -1462,7 +1458,7 @@ process_presence_probe(From, To, StateData) -> FromOld = exmpp_jid:to_ejabberd_jid(From), ToOld = exmpp_jid:to_ejabberd_jid(To), PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_router:route(ToOld, FromOld, PacketOld); true -> ok @@ -1591,7 +1587,7 @@ presence_track(From, To, Packet, StateData) -> BFromOld = exmpp_jid:to_ejabberd_jid(exmpp_jid:jid_to_bare_jid(From)), ToOld = exmpp_jid:to_ejabberd_jid(To), PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), case exmpp_presence:get_type(Packet) of 'unavailable' -> % XXX OLD FORMAT: From, To, Packet. @@ -1676,7 +1672,7 @@ presence_broadcast(StateData, From, JIDSet, Packet) -> FJIDOld = exmpp_jid:to_ejabberd_jid(FJID), FromOld = exmpp_jid:to_ejabberd_jid(From), PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, @@ -1697,7 +1693,7 @@ presence_broadcast_to_trusted(StateData, From, T, A, Packet) -> % XXX OLD FORMAT: From, Packet. FromOld = exmpp_jid:to_ejabberd_jid(From), PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), lists:foreach( fun({U, S, R} = JID) -> case ?SETS:is_element(JID, T) of @@ -1730,9 +1726,9 @@ presence_broadcast_first(From, StateData, Packet) -> % XXX OLD FORMAT: From, Packet, Probe. FromOld = exmpp_jid:to_ejabberd_jid(From), PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), ProbeOld = exmpp_xml:xmlel_to_xmlelement(Probe, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), ?SETS:fold(fun({U, S, R}, X) -> FJID = exmpp_jid:make_jid(U, S, R), % XXX OLD FORMAT: FJID. @@ -1821,7 +1817,7 @@ roster_change(IJID, ISubscription, StateData) -> ?DEBUG("C1: ~p~n", [LIJID]), % XXX OLD FORMAT: P. POld = exmpp_xml:xmlelement_to_xmlel(P, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), % XXX OLD FORMAT: From, To, P. case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, @@ -1847,7 +1843,7 @@ roster_change(IJID, ISubscription, StateData) -> PU = exmpp_presence:unavailable(), % XXX OLD FORMAT: PU. PUOld = exmpp_xml:xmlelement_to_xmlel(PU, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), % XXX OLD FORMAT: From, To, PU. case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, @@ -1881,7 +1877,7 @@ update_priority(Priority, Packet, StateData) -> Info = [{ip, StateData#state.ip},{conn, StateData#state.conn}], % XXX OLD FORMAT: Packet. PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_sm:set_presence(StateData#state.sid, StateData#state.user, StateData#state.server, @@ -1895,7 +1891,7 @@ process_privacy_iq(From, To, StateData) -> % XXX OLD FORMAT: IQ is #iq. ElOld = exmpp_xml:xmlel_to_xmlelement(El, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), IQOld = jlib:iq_query_info(ElOld), % XXX OLD FORMAT: JIDs. FromOld = exmpp_jid:to_ejabberd_jid(From), @@ -1923,16 +1919,16 @@ process_privacy_iq(From, To, case Res of {result, ResultOld} -> Result = exmpp_xml:xmlelement_to_xmlel(ResultOld, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), exmpp_iq:result(El, Result); {error, ErrorOld} -> Error = exmpp_xml:xmlelement_to_xmlel(ErrorOld, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), exmpp_iq:error(El, Error) end, % XXX OLD FORMAT: To, From, IQRes. IQResOld = exmpp_xml:xmlel_to_xmlelement(IQRes, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_router:route( ToOld, FromOld, IQResOld), NewStateData. @@ -1970,7 +1966,7 @@ resend_offline_messages(#state{user = User, From = exmpp_jid:from_ejabberd_jid(FromOld), To = exmpp_jid:from_ejabberd_jid(ToOld), Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), Attrs1 = exmpp_stanza:set_sender_in_attrs( Packet#xmlel.attrs, From), Attrs2 = exmpp_stanza:set_recipient_in_attrs( @@ -1994,14 +1990,14 @@ resend_subscription_requests(#state{user = User, % XXX OLD FORMAT ON DISK! lists:foreach(fun(XMLPacketOld) -> XMLPacket = exmpp_xml:xmlelement_to_xmlel( - XMLPacketOld, ?DEFAULT_NS, ?PREFIXED_NS), + XMLPacketOld, [?DEFAULT_NS], ?PREFIXED_NS), send_element(StateData, XMLPacket) end, PendingSubscriptions). process_unauthenticated_stanza(StateData, El) -> - ElOld = exmpp_xml:xmlel_to_xmlelement(El, ?DEFAULT_NS, ?PREFIXED_NS), + ElOld = exmpp_xml:xmlel_to_xmlelement(El, [?DEFAULT_NS], ?PREFIXED_NS), case jlib:iq_query_info(ElOld) of #iq{} = IQ -> ResOld = ejabberd_hooks:run_fold(c2s_unauthenticated_iq, @@ -2022,7 +2018,7 @@ process_unauthenticated_stanza(StateData, El) -> send_element(StateData, Res2); _ -> Res = exmpp_xml:xmlelement_to_xmlel(ResOld, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), send_element(StateData, Res) end; _ -> diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 31ae9454e..ed8b922e0 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -95,8 +95,10 @@ % These are the namespace already declared by the stream opening. This is % used at serialization time. --define(DEFAULT_NS, [?NS_JABBER_SERVER]). --define(PREFIXED_NS, [{?NS_XMPP, "stream"}, {?NS_JABBER_DIALBACK, "db"}]). +-define(DEFAULT_NS, ?NS_JABBER_SERVER). +-define(PREFIXED_NS, [ + {?NS_XMPP, ?NS_XMPP_pfx}, {?NS_DIALBACK, ?NS_DIALBACK_pfx} +]). %%%---------------------------------------------------------------------- %%% API @@ -159,7 +161,7 @@ init([{SockMod, Socket}, Opts]) -> wait_for_stream({xmlstreamstart, Opening}, StateData) -> case {exmpp_stream:get_default_ns(Opening), - exmpp_xml:is_ns_declared_here(Opening, ?NS_JABBER_DIALBACK), + exmpp_xml:is_ns_declared_here(Opening, ?NS_DIALBACK), exmpp_stream:get_version(Opening) == {1, 0}} of {?NS_JABBER_SERVER, _, true} when StateData#state.tls and (not StateData#state.authenticated) -> @@ -240,7 +242,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> ?DEBUG("starttls", []), Socket = StateData#state.socket, Proceed = exmpp_xml:document_fragment_to_list( - exmpp_server_tls:proceed(), ?DEFAULT_NS, ?PREFIXED_NS), + exmpp_server_tls:proceed(), [?DEFAULT_NS], ?PREFIXED_NS), TLSOpts = StateData#state.tls_options, TLSSocket = (StateData#state.sockmod):starttls( Socket, TLSOpts, @@ -388,7 +390,7 @@ stream_established({xmlstreamelement, El}, StateData) -> % XXX No namespace conversion (:server <-> :client) is done. % This is handled by C2S and S2S send_element functions. ElOld = exmpp_xml:xmlel_to_xmlelement(El, - ?DEFAULT_NS, ?PREFIXED_NS), + [?DEFAULT_NS], ?PREFIXED_NS), if (To /= error) and (From /= error) -> LFrom = From#jid.ldomain, @@ -561,13 +563,13 @@ send_text(StateData, Text) -> send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> - send_text(StateData, exmpp_xml:document_to_list(El)); + send_text(StateData, exmpp_stream:to_list(El)); send_element(StateData, #xmlel{ns = ?NS_JABBER_CLIENT} = El) -> - send_text(StateData, exmpp_xml:document_fragment_to_list(El, - [?NS_JABBER_CLIENT], ?PREFIXED_NS)); + send_text(StateData, exmpp_stanza:to_list(El, + ?NS_JABBER_CLIENT, ?PREFIXED_NS)); send_element(StateData, El) -> - send_text(StateData, exmpp_xml:document_fragment_to_list(El, - ?DEFAULT_NS, ?PREFIXED_NS)). + send_text(StateData, exmpp_stanza:to_list(El, + ?DEFAULT_NS, ?PREFIXED_NS)). change_shaper(StateData, Host, JID) -> @@ -590,14 +592,14 @@ cancel_timer(Timer) -> end. -is_key_packet(#xmlel{ns = ?NS_JABBER_DIALBACK, name = 'result', +is_key_packet(#xmlel{ns = ?NS_DIALBACK, name = 'result', attrs = Attrs} = El) -> {key, exmpp_stanza:get_recipient_from_attrs(Attrs), exmpp_stanza:get_sender_from_attrs(Attrs), exmpp_stanza:get_id_from_attrs(Attrs), exmpp_xml:get_cdata_as_list(El)}; -is_key_packet(#xmlel{ns = ?NS_JABBER_DIALBACK, name = 'verify', +is_key_packet(#xmlel{ns = ?NS_DIALBACK, name = 'verify', attrs = Attrs} = El) -> {verify, exmpp_stanza:get_recipient_from_attrs(Attrs), diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index d33439a6e..ef099609b 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -101,8 +101,11 @@ % These are the namespace already declared by the stream opening. This is % used at serialization time. --define(DEFAULT_NS, [?NS_JABBER_SERVER]). --define(PREFIXED_NS, [{?NS_XMPP, "stream"}, {?NS_JABBER_DIALBACK, "db"}]). +-define(DEFAULT_NS, ?NS_JABBER_SERVER). +-define(PREFIXED_NS, [ + {?NS_XMPP, ?NS_XMPP_pfx}, {?NS_DIALBACK, ?NS_DIALBACK_pfx} +]). + %%%---------------------------------------------------------------------- %%% API @@ -263,7 +266,7 @@ open_socket1(Addr, Port) -> wait_for_stream({xmlstreamstart, Opening}, StateData) -> case {exmpp_stream:get_default_ns(Opening), - exmpp_xml:is_ns_declared_here(Opening, ?NS_JABBER_DIALBACK), + exmpp_xml:is_ns_declared_here(Opening, ?NS_DIALBACK), exmpp_stream:get_version(Opening) == {1, 0}} of {?NS_JABBER_SERVER, true, false} -> send_db_request(StateData); @@ -786,13 +789,13 @@ send_text(StateData, Text) -> ejabberd_socket:send(StateData#state.socket, Text). send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> - send_text(StateData, exmpp_xml:document_to_list(El)); + send_text(StateData, exmpp_stream:to_list(El)); send_element(StateData, #xmlel{ns = ?NS_JABBER_CLIENT} = El) -> - send_text(StateData, exmpp_xml:document_fragment_to_list(El, - [?NS_JABBER_CLIENT], ?PREFIXED_NS)); + send_text(StateData, exmpp_stanza:to_list(El, + ?NS_JABBER_CLIENT, ?PREFIXED_NS)); send_element(StateData, El) -> - send_text(StateData, exmpp_xml:document_fragment_to_list(El, - ?DEFAULT_NS, ?PREFIXED_NS)). + send_text(StateData, exmpp_stanza:to_list(El, + ?DEFAULT_NS, ?PREFIXED_NS)). send_queue(StateData, Q) -> case queue:out(Q) of @@ -888,14 +891,14 @@ send_db_request(StateData) -> {next_state, wait_for_validation, StateData#state{new = New}, ?FSMTIMEOUT*6}. -is_verify_res(#xmlel{ns = ?NS_JABBER_DIALBACK, name = 'result', +is_verify_res(#xmlel{ns = ?NS_DIALBACK, name = 'result', attrs = Attrs}) -> {result, exmpp_stanza:get_recipient_from_attrs(Attrs), exmpp_stanza:get_sender_from_attrs(Attrs), exmpp_stanza:get_id_from_attrs(Attrs), exmpp_stanza:get_type_from_attrs(Attrs)}; -is_verify_res(#xmlel{ns = ?NS_JABBER_DIALBACK, name = 'verify', +is_verify_res(#xmlel{ns = ?NS_DIALBACK, name = 'verify', attrs = Attrs}) -> {verify, exmpp_stanza:get_recipient_from_attrs(Attrs), From d05c2ee8a1d9d89b92c6d3464328159f766ae315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 30 Jun 2008 12:13:15 +0000 Subject: [PATCH 017/582] Use -include_lib instead of -include to include exmpp.hrl. This is a better solution than specifying the path (with -I) on erlc(1) command line. SVN Revision: 1388 --- ChangeLog | 9 +++++++++ src/Makefile.in | 2 +- src/ejabberd_c2s.erl | 2 +- src/ejabberd_s2s_in.erl | 2 +- src/ejabberd_s2s_out.erl | 2 +- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 947a8e4ad..9e9fc965a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2008-06-30 Jean-Sébastien Pédron + + * src/Makefile.in: Remove the -I flag for exmpp includes; the + -include_lib pragma is a better solution. + + * src/ejabberd_c2s.erl, src/ejabberd_s2s_in.erl, + src/ejabberd_s2s_out.erl: Use -include_lib instead of -include to + include exmpp.hrl. + 2008-06-27 Jean-Sébastien Pédron * src/ejabberd_c2s.erl, src/ejabberd_s2s_out.erl, diff --git a/src/Makefile.in b/src/Makefile.in index 7391a8d9a..57bb56333 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -12,7 +12,7 @@ ERLANG_CFLAGS= @ERLANG_CFLAGS@ EXPAT_LIBS = @EXPAT_LIBS@ ERLANG_LIBS = @ERLANG_LIBS@ -ERLC_FLAGS += @ERLANG_SSL39@ -I@ERLANG_EXMPP@/include +ERLC_FLAGS += @ERLANG_SSL39@ ASN_FLAGS = -bber_bin +der +compact_bit_string +optimize +noobj # make debug=true to compile Erlang module with debug informations. diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 953e9beb2..828df898c 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -54,7 +54,7 @@ handle_info/3, terminate/3]). --include("exmpp.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). -include("ejabberd.hrl"). -include("mod_privacy.hrl"). diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index ed8b922e0..70f5cecce 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -46,7 +46,7 @@ handle_info/3, terminate/3]). - -include("exmpp.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). -include("ejabberd.hrl"). -ifdef(SSL39). diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index ef099609b..19f68d25e 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -54,7 +54,7 @@ code_change/4, test_get_addr_port/1]). --include("exmpp.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). -include("ejabberd.hrl"). From 264e72830b213c81b9c7120b6e9704f9701444df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 30 Jun 2008 14:04:31 +0000 Subject: [PATCH 018/582] Convert to exmpp. SVN Revision: 1389 --- ChangeLog | 2 ++ src/ejabberd_s2s.erl | 67 ++++++++++++++++++++++++++++++-------------- 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9e9fc965a..0491d68f4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,8 @@ src/ejabberd_s2s_out.erl: Use -include_lib instead of -include to include exmpp.hrl. + * src/ejabberd_s2s.erl: Convert to exmpp. + 2008-06-27 Jean-Sébastien Pédron * src/ejabberd_c2s.erl, src/ejabberd_s2s_out.erl, diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index cd878c1b2..424b9fc99 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -46,13 +46,21 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("ejabberd_ctl.hrl"). -define(DEFAULT_MAX_S2S_CONNECTIONS_NUMBER, 1). -define(DEFAULT_MAX_S2S_CONNECTIONS_NUMBER_PER_NODE, 1). +% These are the namespace already declared by the stream opening. This is +% used at serialization time. +-define(DEFAULT_NS, ?NS_JABBER_CLIENT). +-define(PREFIXED_NS, [ + {?NS_XMPP, ?NS_XMPP_pfx}, {?NS_DIALBACK, ?NS_DIALBACK_pfx} +]). + -record(s2s, {fromto, pid, key}). -record(state, {}). @@ -66,7 +74,12 @@ start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). -route(From, To, Packet) -> +route(FromOld, ToOld, PacketOld) -> + % XXX OLD FORMAT: From, To, Packet. + From = exmpp_jid:from_ejabberd_jid(FromOld), + To = exmpp_jid:from_ejabberd_jid(ToOld), + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, + [?DEFAULT_NS], ?PREFIXED_NS), case catch do_route(From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", @@ -201,7 +214,12 @@ handle_cast(_Msg, State) -> handle_info({mnesia_system_event, {mnesia_down, Node}}, State) -> clean_table_from_bad_node(Node), {noreply, State}; -handle_info({route, From, To, Packet}, State) -> +handle_info({route, FromOld, ToOld, PacketOld}, State) -> + % XXX OLD FORMAT: From, To, Packet + From = exmpp_jid:from_ejabberd_jid(FromOld), + To = exmpp_jid:from_ejabberd_jid(ToOld), + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, + [?NS_JABBER_CLIENT], [{?NS_XMPP, ?NS_XMPP_pfx}]), case catch do_route(From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", @@ -249,35 +267,42 @@ clean_table_from_bad_node(Node) -> do_route(From, To, Packet) -> ?DEBUG("s2s manager~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n", [From, To, Packet, 8]), + % XXX OLD FORMAT: From, To. + FromOld = exmpp_jid:to_ejabberd_jid(From), + ToOld = exmpp_jid:to_ejabberd_jid(To), case find_connection(From, To) of {atomic, Pid} when pid(Pid) -> ?DEBUG("sending to process ~p~n", [Pid]), - {xmlelement, Name, Attrs, Els} = Packet, - NewAttrs = jlib:replace_from_to_attrs(jlib:jid_to_string(From), - jlib:jid_to_string(To), - Attrs), - #jid{lserver = MyServer} = From, + NewPacket1 = exmpp_stanza:set_sender(Packet, From), + NewPacket = exmpp_stanza:set_recipient(NewPacket1, To), + #jid{ldomain = MyServer} = From, + % XXX OLD FORMAT: NewPacket. + NewPacketOld = exmpp_xml:xmlel_to_xmlelement(NewPacket, + [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_hooks:run( s2s_send_packet, MyServer, - [From, To, Packet]), - send_element(Pid, {xmlelement, Name, NewAttrs, Els}), + [FromOld, ToOld, NewPacketOld]), + send_element(Pid, NewPacket), ok; {aborted, _Reason} -> - case xml:get_tag_attr_s("type", Packet) of + case exmpp_stanza:get_type(Packet) of "error" -> ok; "result" -> ok; _ -> - Err = jlib:make_error_reply( - Packet, ?ERR_SERVICE_UNAVAILABLE), - ejabberd_router:route(To, From, Err) + Err = exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error('service-unavailable')), + % XXX OLD FORMAT: Err. + ErrOld = exmpp_xml:xmlel_to_xmlelement(Err, + [?DEFAULT_NS], ?PREFIXED_NS), + ejabberd_router:route(ToOld, FromOld, ErrOld) end, false end. find_connection(From, To) -> - #jid{lserver = MyServer} = From, - #jid{lserver = Server} = To, + #jid{ldomain = MyServer} = From, + #jid{ldomain = Server} = To, FromTo = {MyServer, Server}, MaxS2SConnectionsNumber = max_s2s_connections_number(FromTo), MaxS2SConnectionsNumberPerNode = @@ -330,7 +355,7 @@ choose_pid(From, Pids) -> % Use sticky connections based on the JID of the sender (whithout % the resource to ensure that a muc room always uses the same % connection) - Pid = lists:nth(erlang:phash(jlib:jid_remove_resource(From), length(Pids1)), + Pid = lists:nth(erlang:phash(exmpp_jid:jid_to_bare_jid(From), length(Pids1)), Pids1), ?DEBUG("Using ejabberd_s2s_out ~p~n", [Pid]), Pid. @@ -381,14 +406,14 @@ new_connection(MyServer, Server, From, FromTo, max_s2s_connections_number({From, To}) -> case acl:match_rule( - From, max_s2s_connections, jlib:make_jid("", To, "")) of + From, max_s2s_connections, exmpp_jid:make_bare_jid(To)) of Max when is_integer(Max) -> Max; _ -> ?DEFAULT_MAX_S2S_CONNECTIONS_NUMBER end. max_s2s_connections_number_per_node({From, To}) -> case acl:match_rule( - From, max_s2s_connections_per_node, jlib:make_jid("", To, "")) of + From, max_s2s_connections_per_node, exmpp_jid:make_bare_jid(To)) of Max when is_integer(Max) -> Max; _ -> ?DEFAULT_MAX_S2S_CONNECTIONS_NUMBER_PER_NODE end. @@ -405,12 +430,12 @@ needed_connections_number(Ls, MaxS2SConnectionsNumber, %% service. %% -------------------------------------------------------------------- is_service(From, To) -> - LFromDomain = From#jid.lserver, + LFromDomain = From#jid.ldomain, case ejabberd_config:get_local_option({route_subdomains, LFromDomain}) of s2s -> % bypass RFC 3920 10.3 false; _ -> - LDstDomain = To#jid.lserver, + LDstDomain = To#jid.ldomain, P = fun(Domain) -> is_subdomain(LDstDomain, Domain) end, lists:any(P, ?MYHOSTS) end. From 290040ad9dd88a4d5608374efcafa73510e58e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 30 Jun 2008 15:49:58 +0000 Subject: [PATCH 019/582] o Add function to convert to and from old ejabberd #jid record. o Move function short_jid/1 from ejabberd_c2s. SVN Revision: 1390 --- ChangeLog | 3 +++ src/jlib.erl | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 0491d68f4..689eea395 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,9 @@ * src/ejabberd_s2s.erl: Convert to exmpp. + * src/jlib.erl: Add function to convert to and from old ejabberd #jid + record. Move function short_jid/1 from ejabberd_c2s. + 2008-06-27 Jean-Sébastien Pédron * src/ejabberd_c2s.erl, src/ejabberd_s2s_out.erl, diff --git a/src/jlib.erl b/src/jlib.erl index 4fd897599..d6938c799 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -60,7 +60,10 @@ datetime_string_to_timestamp/1, decode_base64/1, encode_base64/1, - ip_to_list/1]). + ip_to_list/1, + from_old_jid/1, + to_old_jid/1, + short_jid/1]). -include("jlib.hrl"). @@ -683,3 +686,51 @@ ip_to_list({IP, _Port}) -> ip_to_list(IP); ip_to_list({A,B,C,D}) -> lists:flatten(io_lib:format("~w.~w.~w.~w",[A,B,C,D])). + +% -------------------------------------------------------------------- +% Compat layer. +% -------------------------------------------------------------------- + +%% @spec (JID) -> New_JID +%% JID = jid() +%% New_JID = jid() +%% @doc Convert a JID from its ejabberd form to its exmpp form. +%% +%% Empty fields are set to `undefined', not the empty string. + +from_old_jid(#jid{user = Node, resource = Resource, + luser = LNode, lresource = LResource} = JID) -> + {Node1, LNode1} = case Node of + "" -> {undefined, undefined}; + _ -> {Node, LNode} + end, + {Resource1, LResource1} = case Resource of + "" -> {undefined, undefined}; + _ -> {Resource, LResource} + end, + JID#jid{user = Node1, resource = Resource1, + luser = LNode1, lresource = LResource1}. + +%% @spec (JID) -> New_JID +%% JID = jid() +%% New_JID = jid() +%% @doc Convert a JID from its exmpp form to its ejabberd form. +%% +%% Empty fields are set to the empty string, not `undefined'. + +to_old_jid(#jid{user = Node, resource = Resource, + luser = LNode, lresource = LResource} = JID) -> + {Node1, LNode1} = case Node of + undefined -> {"", ""}; + _ -> {Node, LNode} + end, + {Resource1, LResource1} = case Resource of + undefined -> {"", ""}; + _ -> {Resource, LResource} + end, + JID#jid{user = Node1, resource = Resource1, + luser = LNode1, lresource = LResource1}. + +short_jid(JID0) -> + JID = to_old_jid(JID0), + {JID#jid.luser, JID#jid.lserver, JID#jid.lresource}. From cc033b3b980ab6ae15ccb5a6cbdbc4d3a53b6bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 30 Jun 2008 15:51:23 +0000 Subject: [PATCH 020/582] o Use the new functions from jlib. o Use the new exmpp_xml:node_to_list/3. SVN Revision: 1391 --- ChangeLog | 4 ++ src/ejabberd_c2s.erl | 90 +++++++++++++++++++--------------------- src/ejabberd_s2s.erl | 12 +++--- src/ejabberd_s2s_in.erl | 12 +++--- src/ejabberd_s2s_out.erl | 4 +- 5 files changed, 61 insertions(+), 61 deletions(-) diff --git a/ChangeLog b/ChangeLog index 689eea395..dacc736dd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,10 @@ * src/jlib.erl: Add function to convert to and from old ejabberd #jid record. Move function short_jid/1 from ejabberd_c2s. + * src/ejabberd_c2s.erl, src/ejabberd_s2s.erl, src/ejabberd_s2s_in.erl, + src/ejabberd_s2s_out.erl: Use the new functions from jlib. Use the new + exmpp_xml:node_to_list/3. + 2008-06-27 Jean-Sébastien Pédron * src/ejabberd_c2s.erl, src/ejabberd_s2s_out.erl, diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 828df898c..26c696f72 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -392,7 +392,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> try JID = exmpp_jid:make_jid(U, StateData#state.server, R), % XXX OLD FORMAT: JID. - JIDOld = exmpp_jid:to_ejabberd_jid(JID), + JIDOld = jlib:to_old_jid(JID), case acl:match_rule(StateData#state.server, StateData#state.access, JIDOld) of allow -> @@ -418,7 +418,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> StateData#state.server, {[], []}, [U, StateData#state.server]), - LJID = short_jid( + LJID = jlib:short_jid( exmpp_jid:jid_to_bare_jid(JID)), Fs1 = [LJID | Fs], Ts1 = [LJID | Ts], @@ -719,7 +719,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> R = StateData#state.resource, JID = StateData#state.jid, % XXX OLD FORMAT: JID. - JIDOld = exmpp_jid:to_ejabberd_jid(JID), + JIDOld = jlib:to_old_jid(JID), true = exmpp_server_session:want_establishment(El), case acl:match_rule(StateData#state.server, StateData#state.access, JIDOld) of @@ -741,7 +741,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> StateData#state.server, {[], []}, [U, StateData#state.server]), - LJID = short_jid(exmpp_jid:jid_to_bare_jid(JID)), + LJID = jlib:short_jid(exmpp_jid:jid_to_bare_jid(JID)), Fs1 = [LJID | Fs], Ts1 = [LJID | Ts], PrivList = @@ -823,8 +823,8 @@ session_established({xmlstreamelement, El}, StateData) -> PresenceEl = exmpp_xml:xmlelement_to_xmlel(PresenceElOld, [?DEFAULT_NS], ?PREFIXED_NS), % XXX OLD FORMAT: PresenceElOld, *JID. - FromJIDOld = exmpp_jid:to_ejabberd_jid(FromJID), - ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), + FromJIDOld = jlib:to_old_jid(FromJID), + ToJIDOld = jlib:to_old_jid(ToJID), ejabberd_hooks:run( user_send_packet, Server, @@ -843,8 +843,8 @@ session_established({xmlstreamelement, El}, StateData) -> end; #xmlel{ns = ?NS_JABBER_CLIENT, name = 'iq'} -> % XXX OLD FORMAT: JIDs. - FromJIDOld = exmpp_jid:to_ejabberd_jid(FromJID), - ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), + FromJIDOld = jlib:to_old_jid(FromJID), + ToJIDOld = jlib:to_old_jid(ToJID), case exmpp_iq:get_payload(El) of #xmlel{ns = ?NS_PRIVACY} -> process_privacy_iq( @@ -866,8 +866,8 @@ session_established({xmlstreamelement, El}, StateData) -> % XXX OLD FORMAT: NewElOld, JIDs. NewElOld = exmpp_xml:xmlel_to_xmlelement(NewEl, [?DEFAULT_NS], ?PREFIXED_NS), - FromJIDOld = exmpp_jid:to_ejabberd_jid(FromJID), - ToJIDOld = exmpp_jid:to_ejabberd_jid(ToJID), + FromJIDOld = jlib:to_old_jid(FromJID), + ToJIDOld = jlib:to_old_jid(ToJID), ejabberd_hooks:run(user_send_packet, Server, [FromJIDOld, ToJIDOld, NewElOld]), @@ -1012,16 +1012,16 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> %% XXX OLD FORMAT: From, To and Packet are in the old format. Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, [?DEFAULT_NS], ?PREFIXED_NS), - From = exmpp_jid:from_ejabberd_jid(FromOld), - To = exmpp_jid:from_ejabberd_jid(ToOld), + From = jlib:from_old_jid(FromOld), + To = jlib:from_old_jid(ToOld), {Pass, NewAttrs, NewState} = case Packet of #xmlel{attrs = Attrs} when ?IS_PRESENCE(Packet) -> case exmpp_presence:get_type(Packet) of 'probe' -> % XXX OLD FORMAT: LFrom and LBFrom. - LFrom = short_jid(From), - LBFrom = short_jid(exmpp_jid:jid_to_bare_jid(From)), + LFrom = jlib:short_jid(From), + LBFrom = jlib:short_jid(exmpp_jid:jid_to_bare_jid(From)), NewStateData = case ?SETS:is_element( LFrom, StateData#state.pres_a) orelse @@ -1058,7 +1058,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> {false, Attrs, NewStateData}; 'error' -> % XXX OLD FORMAT: LFrom. - LFrom = short_jid(From), + LFrom = jlib:short_jid(From), NewA = remove_element(LFrom, StateData#state.pres_a), {true, Attrs, StateData#state{pres_a = NewA}}; @@ -1087,8 +1087,8 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> in]) of allow -> % XXX OLD FORMAT: LFrom and LBFrom. - LFrom = short_jid(From), - LBFrom = short_jid( + LFrom = jlib:short_jid(From), + LBFrom = jlib:short_jid( exmpp_jid:jid_to_bare_jid(From)), %% Note contact availability % XXX OLD FORMAT: Els are #xmlelement. @@ -1336,7 +1336,7 @@ terminate(_Reason, StateName, StateData) -> change_shaper(StateData, JID) -> % XXX OLD FORMAT: JIDOld is an old #jid. - JIDOld = exmpp_jid:to_ejabberd_jid(JID), + JIDOld = jlib:to_old_jid(JID), Shaper = acl:match_rule(StateData#state.server, StateData#state.shaper, JIDOld), (StateData#state.sockmod):change_shaper(StateData#state.socket, Shaper). @@ -1402,8 +1402,8 @@ get_conn_type(StateData) -> end. process_presence_probe(From, To, StateData) -> - LFrom = short_jid(From), - LBFrom = short_jid(exmpp_jid:jid_to_bare_jid(From)), + LFrom = jlib:short_jid(From), + LBFrom = jlib:short_jid(exmpp_jid:jid_to_bare_jid(From)), case StateData#state.pres_last of undefined -> ok; @@ -1425,8 +1425,8 @@ process_presence_probe(From, To, StateData) -> Cond1 -> Packet = StateData#state.pres_last, % XXX OLD FORMAT: From, To, Packet. - FromOld = exmpp_jid:to_ejabberd_jid(From), - ToOld = exmpp_jid:to_ejabberd_jid(To), + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, [?DEFAULT_NS], ?PREFIXED_NS), case ejabberd_hooks:run_fold( @@ -1455,8 +1455,8 @@ process_presence_probe(From, To, StateData) -> Cond2 -> Packet = exmpp_presence:available(), % XXX OLD FORMAT: From, To, Packet. - FromOld = exmpp_jid:to_ejabberd_jid(From), - ToOld = exmpp_jid:to_ejabberd_jid(To), + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_router:route(ToOld, FromOld, PacketOld); @@ -1546,7 +1546,7 @@ presence_update(From, Packet, StateData) -> if FromUnavail -> % XXX OLD FORMAT: JID. - JIDOld = exmpp_jid:to_ejabberd_jid(StateData#state.jid), + JIDOld = jlib:to_old_jid(StateData#state.jid), ejabberd_hooks:run(user_available_hook, StateData#state.server, [JIDOld]), @@ -1579,13 +1579,13 @@ presence_update(From, Packet, StateData) -> end. presence_track(From, To, Packet, StateData) -> - LTo = short_jid(To), + LTo = jlib:short_jid(To), User = StateData#state.user, Server = StateData#state.server, % XXX OLD FORMAT: From, To, Packet. - FromOld = exmpp_jid:to_ejabberd_jid(From), - BFromOld = exmpp_jid:to_ejabberd_jid(exmpp_jid:jid_to_bare_jid(From)), - ToOld = exmpp_jid:to_ejabberd_jid(To), + FromOld = jlib:to_old_jid(From), + BFromOld = jlib:to_old_jid(exmpp_jid:jid_to_bare_jid(From)), + ToOld = jlib:to_old_jid(To), PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, [?DEFAULT_NS], ?PREFIXED_NS), case exmpp_presence:get_type(Packet) of @@ -1669,8 +1669,8 @@ presence_broadcast(StateData, From, JIDSet, Packet) -> lists:foreach(fun({U, S, R}) -> FJID = exmpp_jid:make_jid(U, S, R), % XXX OLD FORMAT: From, FJID, Packet. - FJIDOld = exmpp_jid:to_ejabberd_jid(FJID), - FromOld = exmpp_jid:to_ejabberd_jid(From), + FJIDOld = jlib:to_old_jid(FJID), + FromOld = jlib:to_old_jid(From), PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, [?DEFAULT_NS], ?PREFIXED_NS), case ejabberd_hooks:run_fold( @@ -1691,7 +1691,7 @@ presence_broadcast(StateData, From, JIDSet, Packet) -> presence_broadcast_to_trusted(StateData, From, T, A, Packet) -> % XXX OLD FORMAT: From, Packet. - FromOld = exmpp_jid:to_ejabberd_jid(From), + FromOld = jlib:to_old_jid(From), PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, [?DEFAULT_NS], ?PREFIXED_NS), lists:foreach( @@ -1700,7 +1700,7 @@ presence_broadcast_to_trusted(StateData, From, T, A, Packet) -> true -> FJID = exmpp_jid:make_jid(U, S, R), % XXX OLD FORMAT: FJID. - FJIDOld = exmpp_jid:to_ejabberd_jid(FJID), + FJIDOld = jlib:to_old_jid(FJID), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, @@ -1724,7 +1724,7 @@ presence_broadcast_to_trusted(StateData, From, T, A, Packet) -> presence_broadcast_first(From, StateData, Packet) -> Probe = exmpp_presence:probe(), % XXX OLD FORMAT: From, Packet, Probe. - FromOld = exmpp_jid:to_ejabberd_jid(From), + FromOld = jlib:to_old_jid(From), PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, [?DEFAULT_NS], ?PREFIXED_NS), ProbeOld = exmpp_xml:xmlel_to_xmlelement(Probe, @@ -1732,7 +1732,7 @@ presence_broadcast_first(From, StateData, Packet) -> ?SETS:fold(fun({U, S, R}, X) -> FJID = exmpp_jid:make_jid(U, S, R), % XXX OLD FORMAT: FJID. - FJIDOld = exmpp_jid:to_ejabberd_jid(FJID), + FJIDOld = jlib:to_old_jid(FJID), ejabberd_router:route( FromOld, FJIDOld, @@ -1749,7 +1749,7 @@ presence_broadcast_first(From, StateData, Packet) -> fun({U, S, R} = JID, A) -> FJID = exmpp_jid:make_jid(U, S, R), % XXX OLD FORMAT: FJID. - FJIDOld = exmpp_jid:to_ejabberd_jid(FJID), + FJIDOld = jlib:to_old_jid(FJID), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, @@ -1781,7 +1781,7 @@ remove_element(E, Set) -> roster_change(IJID, ISubscription, StateData) -> - LIJID = short_jid(IJID), + LIJID = jlib:short_jid(IJID), IsFrom = (ISubscription == both) or (ISubscription == from), IsTo = (ISubscription == both) or (ISubscription == to), OldIsFrom = ?SETS:is_element(LIJID, StateData#state.pres_f), @@ -1805,8 +1805,8 @@ roster_change(IJID, ISubscription, StateData) -> From = StateData#state.jid, To = IJID, % XXX OLD FORMAT: From, To. - FromOld = exmpp_jid:to_ejabberd_jid(From), - ToOld = exmpp_jid:to_ejabberd_jid(To), + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), Cond1 = (not StateData#state.pres_invis) and IsFrom and (not OldIsFrom), Cond2 = (not IsFrom) and OldIsFrom @@ -1894,8 +1894,8 @@ process_privacy_iq(From, To, [?DEFAULT_NS], ?PREFIXED_NS), IQOld = jlib:iq_query_info(ElOld), % XXX OLD FORMAT: JIDs. - FromOld = exmpp_jid:to_ejabberd_jid(From), - ToOld = exmpp_jid:to_ejabberd_jid(To), + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), {Res, NewStateData} = case exmpp_iq:get_type(El) of get -> @@ -1963,8 +1963,8 @@ resend_offline_messages(#state{user = User, if Pass -> % XXX OLD FORMAT: From, To, Packet. - From = exmpp_jid:from_ejabberd_jid(FromOld), - To = exmpp_jid:from_ejabberd_jid(ToOld), + From = jlib:from_old_jid(FromOld), + To = jlib:from_old_jid(ToOld), Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, [?DEFAULT_NS], ?PREFIXED_NS), Attrs1 = exmpp_stanza:set_sender_in_attrs( @@ -2053,7 +2053,3 @@ fsm_reply(Reply, StateName, StateData) -> %% Used by c2s blacklist plugins is_ip_blacklisted({IP,_Port}) -> ejabberd_hooks:run_fold(check_bl_c2s, false, [IP]). - -short_jid(JID0) -> - JID = exmpp_jid:to_ejabberd_jid(JID0), - {JID#jid.lnode, JID#jid.ldomain, JID#jid.lresource}. diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index 424b9fc99..8ea563768 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -76,8 +76,8 @@ start_link() -> route(FromOld, ToOld, PacketOld) -> % XXX OLD FORMAT: From, To, Packet. - From = exmpp_jid:from_ejabberd_jid(FromOld), - To = exmpp_jid:from_ejabberd_jid(ToOld), + From = jlib:from_old_jid(FromOld), + To = jlib:from_old_jid(ToOld), Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, [?DEFAULT_NS], ?PREFIXED_NS), case catch do_route(From, To, Packet) of @@ -216,8 +216,8 @@ handle_info({mnesia_system_event, {mnesia_down, Node}}, State) -> {noreply, State}; handle_info({route, FromOld, ToOld, PacketOld}, State) -> % XXX OLD FORMAT: From, To, Packet - From = exmpp_jid:from_ejabberd_jid(FromOld), - To = exmpp_jid:from_ejabberd_jid(ToOld), + From = jlib:from_old_jid(FromOld), + To = jlib:from_old_jid(ToOld), Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, [?NS_JABBER_CLIENT], [{?NS_XMPP, ?NS_XMPP_pfx}]), case catch do_route(From, To, Packet) of @@ -268,8 +268,8 @@ do_route(From, To, Packet) -> ?DEBUG("s2s manager~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n", [From, To, Packet, 8]), % XXX OLD FORMAT: From, To. - FromOld = exmpp_jid:to_ejabberd_jid(From), - ToOld = exmpp_jid:to_ejabberd_jid(To), + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), case find_connection(From, To) of {atomic, Pid} when pid(Pid) -> ?DEBUG("sending to process ~p~n", [Pid]), diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 70f5cecce..5c6e2d503 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -241,7 +241,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> SockMod == gen_tcp -> ?DEBUG("starttls", []), Socket = StateData#state.socket, - Proceed = exmpp_xml:document_fragment_to_list( + Proceed = exmpp_xml:node_to_list( exmpp_server_tls:proceed(), [?DEFAULT_NS], ?PREFIXED_NS), TLSOpts = StateData#state.tls_options, TLSSocket = (StateData#state.sockmod):starttls( @@ -408,8 +408,8 @@ stream_established({xmlstreamelement, El}, StateData) -> (Name == 'message') or (Name == 'presence')) -> % XXX OLD FORMAT: From, To. - FromOld = exmpp_jid:to_ejabberd_jid(From), - ToOld = exmpp_jid:to_ejabberd_jid(To), + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), ejabberd_hooks:run( s2s_receive_packet, LFrom, @@ -431,8 +431,8 @@ stream_established({xmlstreamelement, El}, StateData) -> (Name == 'message') or (Name == 'presence')) -> % XXX OLD FORMAT: From, To. - FromOld = exmpp_jid:to_ejabberd_jid(From), - ToOld = exmpp_jid:to_ejabberd_jid(To), + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), ejabberd_hooks:run( s2s_receive_packet, LFrom, @@ -574,7 +574,7 @@ send_element(StateData, El) -> change_shaper(StateData, Host, JID) -> % XXX OLD FORMAT: JIDOld is an old #jid. - JIDOld = exmpp_jid:to_ejabberd_jid(JID), + JIDOld = jlib:to_old_jid(JID), Shaper = acl:match_rule(Host, StateData#state.shaper, JIDOld), (StateData#state.sockmod):change_shaper(StateData#state.socket, Shaper). diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 19f68d25e..45a92b8f6 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -821,8 +821,8 @@ bounce_element(El, Condition) -> % This is handled by C2S and S2S send_element functions. ErrOld = exmpp_xml:xmlel_to_xmlelement(Err, [?NS_JABBER_CLIENT], ?PREFIXED_NS), - FromOld = exmpp_jid:to_ejabberd_jid(From), - ToOld = exmpp_jid:to_ejabberd_jid(To), + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), ejabberd_router:route(ToOld, FromOld, ErrOld) end. From 06965000a5e7afa72d87b82b7a6baae1d2db6195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 30 Jun 2008 16:55:03 +0000 Subject: [PATCH 021/582] Before doing any routing, the router print a warning if old structures are used. Then it converts the structures to the old format and route them. The router doesn't care about the structures format but the conversion is necesary for code called from this module. In C2S and S2S, no conversion is done before calling ejabberd_router:route/3. SVN Revision: 1392 --- ChangeLog | 10 +++++ src/ejabberd_c2s.erl | 85 ++++++++++++---------------------------- src/ejabberd_router.erl | 61 +++++++++++++++++++++++----- src/ejabberd_s2s.erl | 5 +-- src/ejabberd_s2s_in.erl | 4 +- src/ejabberd_s2s_out.erl | 9 +---- 6 files changed, 91 insertions(+), 83 deletions(-) diff --git a/ChangeLog b/ChangeLog index dacc736dd..c773f335a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,16 @@ src/ejabberd_s2s_out.erl: Use the new functions from jlib. Use the new exmpp_xml:node_to_list/3. + * src/ejabberd_router.erl: Before doing any routing, the router print + a warning if old structures are used. Then it converts the structures + to the old format and route them. The router doesn't care about the + structures format but the conversion is necesary for code called from + this module. + + * src/ejabberd_c2s.erl, src/ejabberd_s2s.erl, src/ejabberd_s2s_in.erl, + src/ejabberd_s2s_out.erl: No conversion is done before calling + ejabberd_router:route/3. + 2008-06-27 Jean-Sébastien Pédron * src/ejabberd_c2s.erl, src/ejabberd_s2s_out.erl, diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 26c696f72..91a866d47 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -857,9 +857,8 @@ session_established({xmlstreamelement, El}, StateData) -> user_send_packet, Server, [FromJIDOld, ToJIDOld, NewElOld]), - % XXX OLD FORMAT: NewElOld. ejabberd_router:route( - FromJIDOld, ToJIDOld, NewElOld), + FromJID, ToJID, NewEl), StateData end; #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message'} -> @@ -871,8 +870,7 @@ session_established({xmlstreamelement, El}, StateData) -> ejabberd_hooks:run(user_send_packet, Server, [FromJIDOld, ToJIDOld, NewElOld]), - % XXX OLD FORMAT: NewElOld. - ejabberd_router:route(FromJIDOld, ToJIDOld, NewElOld), + ejabberd_router:route(FromJID, ToJID, NewEl), StateData; _ -> StateData @@ -1186,10 +1184,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> [] -> Err = exmpp_stanza:error('feature-not-implemented'), Res = exmpp_iq:error(Packet, Err), - % XXX OLD FORMAT: To, From, Res. - ResOld = exmpp_xml:xmlel_to_xmlelement( - Res, [?DEFAULT_NS], ?PREFIXED_NS), - ejabberd_router:route(ToOld, FromOld, ResOld) + ejabberd_router:route(To, From, Res) end, {false, Attrs, StateData}; _ -> @@ -1208,11 +1203,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> Err = exmpp_stanza:error( 'feature-not-implemented'), Res = exmpp_iq:error(Packet, Err), - % XXX OLD FORMAT: To, From, Res. - ResOld = exmpp_xml:xmlel_to_xmlelement( - Res, - [?DEFAULT_NS], ?PREFIXED_NS), - ejabberd_router:route(ToOld, FromOld, ResOld), + ejabberd_router:route(To, From, Res), {false, Attrs, StateData} end end; @@ -1446,20 +1437,14 @@ process_presence_probe(From, To, StateData) -> %% Don't route a presence probe to oneself case From == To of false -> - % XXX OLD FORMAT: From, To, Packet. - ejabberd_router:route(ToOld, FromOld, PacketOld); + ejabberd_router:route(To, From, Packet); true -> ok end end; Cond2 -> Packet = exmpp_presence:available(), - % XXX OLD FORMAT: From, To, Packet. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - [?DEFAULT_NS], ?PREFIXED_NS), - ejabberd_router:route(ToOld, FromOld, PacketOld); + ejabberd_router:route(To, From, Packet); true -> ok end @@ -1584,21 +1569,19 @@ presence_track(From, To, Packet, StateData) -> Server = StateData#state.server, % XXX OLD FORMAT: From, To, Packet. FromOld = jlib:to_old_jid(From), - BFromOld = jlib:to_old_jid(exmpp_jid:jid_to_bare_jid(From)), + BFrom = exmpp_jid:jid_to_bare_jid(From), ToOld = jlib:to_old_jid(To), PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, [?DEFAULT_NS], ?PREFIXED_NS), case exmpp_presence:get_type(Packet) of 'unavailable' -> - % XXX OLD FORMAT: From, To, Packet. - ejabberd_router:route(FromOld, ToOld, PacketOld), + ejabberd_router:route(From, To, Packet), I = remove_element(LTo, StateData#state.pres_i), A = remove_element(LTo, StateData#state.pres_a), StateData#state{pres_i = I, pres_a = A}; 'invisible' -> - % XXX OLD FORMAT: From, To, Packet. - ejabberd_router:route(FromOld, ToOld, PacketOld), + ejabberd_router:route(From, To, Packet), I = ?SETS:add_element(LTo, StateData#state.pres_i), A = remove_element(LTo, StateData#state.pres_a), StateData#state{pres_i = I, @@ -1608,40 +1591,34 @@ presence_track(From, To, Packet, StateData) -> ejabberd_hooks:run(roster_out_subscription, Server, [User, Server, ToOld, subscribe]), - % XXX OLD FORMAT: From, To, Packet. - ejabberd_router:route(BFromOld, ToOld, PacketOld), + ejabberd_router:route(BFrom, To, Packet), StateData; 'subscribed' -> % XXX OLD FORMAT: To. ejabberd_hooks:run(roster_out_subscription, Server, [User, Server, ToOld, subscribed]), - % XXX OLD FORMAT: From, To, Packet. - ejabberd_router:route(BFromOld, ToOld, PacketOld), + ejabberd_router:route(BFrom, To, Packet), StateData; 'unsubscribe' -> % XXX OLD FORMAT: To. ejabberd_hooks:run(roster_out_subscription, Server, [User, Server, ToOld, unsubscribe]), - % XXX OLD FORMAT: From, To, Packet. - ejabberd_router:route(BFromOld, ToOld, PacketOld), + ejabberd_router:route(BFrom, To, Packet), StateData; 'unsubscribed' -> % XXX OLD FORMAT: To. ejabberd_hooks:run(roster_out_subscription, Server, [User, Server, ToOld, unsubscribed]), - % XXX OLD FORMAT: From, To, Packet. - ejabberd_router:route(BFromOld, ToOld, PacketOld), + ejabberd_router:route(BFrom, To, Packet), StateData; 'error' -> - % XXX OLD FORMAT: From, To, Packet. - ejabberd_router:route(FromOld, ToOld, PacketOld), + ejabberd_router:route(From, To, Packet), StateData; 'probe' -> - % XXX OLD FORMAT: From, To, Packet. - ejabberd_router:route(FromOld, ToOld, PacketOld), + ejabberd_router:route(From, To, Packet), StateData; _ -> % XXX OLD FORMAT: From, To, Packet. @@ -1656,8 +1633,7 @@ presence_track(From, To, Packet, StateData) -> deny -> ok; allow -> - % XXX OLD FORMAT: From, To, Packet. - ejabberd_router:route(FromOld, ToOld, PacketOld) + ejabberd_router:route(From, To, Packet) end, I = remove_element(LTo, StateData#state.pres_i), A = ?SETS:add_element(LTo, StateData#state.pres_a), @@ -1684,8 +1660,7 @@ presence_broadcast(StateData, From, JIDSet, Packet) -> deny -> ok; allow -> - % XXX OLD FORMAT: From, FJID, Packet. - ejabberd_router:route(FromOld, FJIDOld, PacketOld) + ejabberd_router:route(From, FJID, Packet) end end, ?SETS:to_list(JIDSet)). @@ -1712,8 +1687,7 @@ presence_broadcast_to_trusted(StateData, From, T, A, Packet) -> deny -> ok; allow -> - % XXX OLD FORMAT: From, FJID, Packet. - ejabberd_router:route(FromOld, FJIDOld, PacketOld) + ejabberd_router:route(From, FJID, Packet) end; _ -> ok @@ -1727,16 +1701,12 @@ presence_broadcast_first(From, StateData, Packet) -> FromOld = jlib:to_old_jid(From), PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, [?DEFAULT_NS], ?PREFIXED_NS), - ProbeOld = exmpp_xml:xmlel_to_xmlelement(Probe, - [?DEFAULT_NS], ?PREFIXED_NS), ?SETS:fold(fun({U, S, R}, X) -> FJID = exmpp_jid:make_jid(U, S, R), - % XXX OLD FORMAT: FJID. - FJIDOld = jlib:to_old_jid(FJID), ejabberd_router:route( - FromOld, - FJIDOld, - ProbeOld), + From, + FJID, + Probe), X end, [], @@ -1761,7 +1731,7 @@ presence_broadcast_first(From, StateData, Packet) -> deny -> ok; allow -> - ejabberd_router:route(FromOld, FJIDOld, PacketOld) + ejabberd_router:route(From, FJID, Packet) end, ?SETS:add_element(JID, A) end, @@ -1830,8 +1800,7 @@ roster_change(IJID, ISubscription, StateData) -> deny -> ok; allow -> - % XXX OLD FORMAT: From, To, P. - ejabberd_router:route(FromOld, ToOld, POld) + ejabberd_router:route(From, To, P) end, A = ?SETS:add_element(LIJID, StateData#state.pres_a), @@ -1856,8 +1825,7 @@ roster_change(IJID, ISubscription, StateData) -> deny -> ok; allow -> - % XXX OLD FORMAT: From, To, PU. - ejabberd_router:route(FromOld, ToOld, PUOld) + ejabberd_router:route(From, To, PU) end, I = remove_element(LIJID, StateData#state.pres_i), @@ -1926,11 +1894,8 @@ process_privacy_iq(From, To, [?DEFAULT_NS], ?PREFIXED_NS), exmpp_iq:error(El, Error) end, - % XXX OLD FORMAT: To, From, IQRes. - IQResOld = exmpp_xml:xmlel_to_xmlelement(IQRes, - [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_router:route( - ToOld, FromOld, IQResOld), + To, From, IQRes), NewStateData. diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index 0085e8adf..d31c90132 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -46,8 +46,9 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -record(route, {domain, pid, local_hint}). -record(state, {}). @@ -64,7 +65,27 @@ start_link() -> route(From, To, Packet) -> - case catch do_route(From, To, Packet) of + % XXX OLD FORMAT: This code helps to detect old format routing. + {FromOld, ToOld, PacketOld} = case Packet of + #xmlelement{} -> + catch throw(for_stacktrace), % To have a stacktrace. + io:format("~nROUTE: old #xmlelement:~n~p~n~p~n~n", + [Packet, erlang:get_stacktrace()]), + {From, To, Packet}; + _ -> + F = jlib:to_old_jid(From), + T = jlib:to_old_jid(To), + Default_NS = case lists:member({Packet#xmlel.ns, none}, + Packet#xmlel.declared_ns) of + true -> []; + false -> [Packet#xmlel.ns] + end, + P = exmpp_xml:xmlel_to_xmlelement(Packet, + Default_NS, + [{?NS_XMPP, ?NS_XMPP_pfx}, {?NS_DIALBACK, ?NS_DIALBACK_pfx}]), + {F, T, P} + end, + case catch do_route(FromOld, ToOld, PacketOld) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", [Reason, {From, To, Packet}]); @@ -237,7 +258,27 @@ handle_cast(_Msg, State) -> %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- handle_info({route, From, To, Packet}, State) -> - case catch do_route(From, To, Packet) of + % XXX OLD FORMAT: This code helps to detect old format routing. + {FromOld, ToOld, PacketOld} = case Packet of + #xmlelement{} -> + catch throw(for_stacktrace), % To have a stacktrace. + io:format("~nROUTE: old #xmlelement:~n~p~n~p~n~n", + [Packet, erlang:get_stacktrace()]), + {From, To, Packet}; + _ -> + F = jlib:to_old_jid(From), + T = jlib:to_old_jid(To), + Default_NS = case lists:member({Packet#xmlel.ns, none}, + Packet#xmlel.declared_ns) of + true -> []; + false -> [Packet#xmlel.ns] + end, + P = exmpp_xml:xmlel_to_xmlelement(Packet, + Default_NS, + [{?NS_XMPP, ?NS_XMPP_pfx}, {?NS_DIALBACK, ?NS_DIALBACK_pfx}]), + {F, T, P} + end, + case catch do_route(FromOld, ToOld, PacketOld) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", [Reason, {From, To, Packet}]); @@ -303,7 +344,7 @@ do_route(OrigFrom, OrigTo, OrigPacket) -> case ejabberd_hooks:run_fold(filter_packet, {OrigFrom, OrigTo, OrigPacket}, []) of {From, To, Packet} -> - LDstDomain = To#jid.lserver, + LDstDomain = To#jid.ldomain, case mnesia:dirty_read(route, LDstDomain) of [] -> ejabberd_s2s:route(From, To, Packet); @@ -327,14 +368,14 @@ do_route(OrigFrom, OrigTo, OrigPacket) -> {domain_balancing, LDstDomain}) of undefined -> now(); random -> now(); - source -> jlib:jid_tolower(From); - destination -> jlib:jid_tolower(To); + source -> jlib:short_jid(From); + destination -> jlib:short_jid(To); bare_source -> - jlib:jid_remove_resource( - jlib:jid_tolower(From)); + jlib:short_jid( + exmpp_jid:jid_to_bare_jid(From)); bare_destination -> - jlib:jid_remove_resource( - jlib:jid_tolower(To)) + jlib:short_jid( + exmpp_jid:jid_tl_bare_jid(To)) end, case get_component_number(LDstDomain) of undefined -> diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index 8ea563768..a5f67fa9f 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -292,10 +292,7 @@ do_route(From, To, Packet) -> _ -> Err = exmpp_stanza:reply_with_error(Packet, exmpp_stanza:error('service-unavailable')), - % XXX OLD FORMAT: Err. - ErrOld = exmpp_xml:xmlel_to_xmlelement(Err, - [?DEFAULT_NS], ?PREFIXED_NS), - ejabberd_router:route(ToOld, FromOld, ErrOld) + ejabberd_router:route(To, From, Err) end, false end. diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 5c6e2d503..6504ec9f8 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -415,7 +415,7 @@ stream_established({xmlstreamelement, El}, StateData) -> LFrom, [FromOld, ToOld, ElOld]), ejabberd_router:route( - FromOld, ToOld, ElOld); + From, To, El); true -> error end; @@ -438,7 +438,7 @@ stream_established({xmlstreamelement, El}, StateData) -> LFrom, [FromOld, ToOld, ElOld]), ejabberd_router:route( - FromOld, ToOld, ElOld); + From, To, El); true -> error end; diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 45a92b8f6..bcf5b811b 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -816,14 +816,9 @@ bounce_element(El, Condition) -> Err = exmpp_stanza:reply_with_error(El, Error), From = exmpp_jid:string_to_jid(exmpp_stanza:get_sender(El)), To = exmpp_jid:string_to_jid(exmpp_stanza:get_recipient(El)), - % XXX OLD FORMAT: From, To, Err. - % XXX No namespace conversion (:server <-> :client) is done. + % No namespace conversion (:server <-> :client) is done. % This is handled by C2S and S2S send_element functions. - ErrOld = exmpp_xml:xmlel_to_xmlelement(Err, - [?NS_JABBER_CLIENT], ?PREFIXED_NS), - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - ejabberd_router:route(ToOld, FromOld, ErrOld) + ejabberd_router:route(To, From, Err) end. bounce_queue(Q, Condition) -> From 87218e1447a2d47166f35fb220ed94d34a90c4b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 1 Jul 2008 07:49:57 +0000 Subject: [PATCH 022/582] Convert to exmpp. SVN Revision: 1393 --- ChangeLog | 4 + src/ejabberd_sm.erl | 228 +++++++++++++++++++++++++++----------------- 2 files changed, 144 insertions(+), 88 deletions(-) diff --git a/ChangeLog b/ChangeLog index c773f335a..6cb3c2887 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2008-07-01 Jean-Sébastien Pédron + + * src/ejabberd_sm.erl: Convert to exmpp. + 2008-06-30 Jean-Sébastien Pédron * src/Makefile.in: Remove the -I flag for exmpp includes; the diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 2d4b7c5b9..acb18341f 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -56,8 +56,9 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("ejabberd_ctl.hrl"). -record(session, {sid, usr, us, priority, info}). @@ -66,6 +67,20 @@ %% default value for the maximum number of user connections -define(MAX_USER_SESSIONS, infinity). +% These are the namespace already declared by the stream opening. This is +% used at serialization time. +-define(DEFAULT_NS, ?NS_JABBER_CLIENT). +-define(PREFIXED_NS, [ + {?NS_XMPP, ?NS_XMPP_pfx}, {?NS_DIALBACK, ?NS_DIALBACK_pfx} +]). + +% XXX OLD FORMAT: Re-include jlib.hrl (after clean-up). +-record(iq, {id = "", + type, + xmlns = "", + lang = "", + sub_el}). + %%==================================================================== %% API %%==================================================================== @@ -76,7 +91,12 @@ start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). -route(From, To, Packet) -> +route(FromOld, ToOld, PacketOld) -> + % XXX OLD FORMAT: From, To, Packet. + From = jlib:from_old_jid(FromOld), + To = jlib:from_old_jid(ToOld), + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, + [?DEFAULT_NS], ?PREFIXED_NS), case catch do_route(From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", @@ -88,9 +108,11 @@ route(From, To, Packet) -> open_session(SID, User, Server, Resource, Info) -> set_session(SID, User, Server, Resource, undefined, Info), check_for_sessions_to_replace(User, Server, Resource), - JID = jlib:make_jid(User, Server, Resource), - ejabberd_hooks:run(sm_register_connection_hook, JID#jid.lserver, - [SID, JID, Info]). + JID = exmpp_jid:make_jid(User, Server, Resource), + % XXX OLD FORMAT: JID. + JIDOld = jlib:to_old_jid(JID), + ejabberd_hooks:run(sm_register_connection_hook, JID#jid.ldomain, + [SID, JIDOld, Info]). close_session(SID, User, Server, Resource) -> Info = case mnesia:dirty_read({session, SID}) of @@ -101,9 +123,11 @@ close_session(SID, User, Server, Resource) -> mnesia:delete({session, SID}) end, mnesia:sync_dirty(F), - JID = jlib:make_jid(User, Server, Resource), - ejabberd_hooks:run(sm_remove_connection_hook, JID#jid.lserver, - [SID, JID, Info]). + JID = exmpp_jid:make_jid(User, Server, Resource), + % XXX OLD FORMAT: JID. + JIDOld = jlib:to_old_jid(JID), + ejabberd_hooks:run(sm_remove_connection_hook, JID#jid.ldomain, + [SID, JIDOld, Info]). check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) -> case ejabberd_auth:is_user_exists(User, Server) of @@ -114,19 +138,19 @@ check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) -> end. bounce_offline_message(From, To, Packet) -> - Err = jlib:make_error_reply(Packet, ?ERR_SERVICE_UNAVAILABLE), + Err = exmpp_stanza:reply_with_error(Packet, 'service-unavailable'), ejabberd_router:route(To, From, Err), stop. disconnect_removed_user(User, Server) -> - ejabberd_sm:route(jlib:make_jid("", "", ""), - jlib:make_jid(User, Server, ""), - {xmlelement, "broadcast", [], - [{exit, "User removed"}]}). + ejabberd_sm:route(#jid{}, + exmpp_jid:make_bare_jid(User, Server), + #xmlel{name = 'broadcast', + children = [{exit, "User removed"}]}). get_user_resources(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, case catch mnesia:dirty_index_read(session, US, #session.us) of {'EXIT', _Reason} -> @@ -136,9 +160,9 @@ get_user_resources(User, Server) -> end. get_user_ip(User, Server, Resource) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - LResource = jlib:resourceprep(Resource), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + LResource = exmpp_stringprep:resourceprep(Resource), USR = {LUser, LServer, LResource}, case mnesia:dirty_index_read(session, USR, #session.usr) of [] -> @@ -149,9 +173,9 @@ get_user_ip(User, Server, Resource) -> end. get_user_info(User, Server, Resource) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - LResource = jlib:resourceprep(Resource), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + LResource = exmpp_stringprep:resourceprep(Resource), USR = {LUser, LServer, LResource}, case mnesia:dirty_index_read(session, USR, #session.usr) of [] -> @@ -166,23 +190,23 @@ get_user_info(User, Server, Resource) -> set_presence(SID, User, Server, Resource, Priority, Presence, Info) -> set_session(SID, User, Server, Resource, Priority, Info), - ejabberd_hooks:run(set_presence_hook, jlib:nameprep(Server), + ejabberd_hooks:run(set_presence_hook, exmpp_stringprep:nameprep(Server), [User, Server, Resource, Presence]). unset_presence(SID, User, Server, Resource, Status, Info) -> set_session(SID, User, Server, Resource, undefined, Info), - ejabberd_hooks:run(unset_presence_hook, jlib:nameprep(Server), + ejabberd_hooks:run(unset_presence_hook, exmpp_stringprep:nameprep(Server), [User, Server, Resource, Status]). close_session_unset_presence(SID, User, Server, Resource, Status) -> close_session(SID, User, Server, Resource), - ejabberd_hooks:run(unset_presence_hook, jlib:nameprep(Server), + ejabberd_hooks:run(unset_presence_hook, exmpp_stringprep:nameprep(Server), [User, Server, Resource, Status]). get_session_pid(User, Server, Resource) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - LResource = jlib:resourceprep(Resource), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + LResource = exmpp_stringprep:resourceprep(Resource), USR = {LUser, LServer, LResource}, case catch mnesia:dirty_index_read(session, USR, #session.usr) of [#session{sid = {_, Pid}}] -> Pid; @@ -204,7 +228,7 @@ dirty_get_my_sessions_list() -> ['$_']}]). get_vh_session_list(Server) -> - LServer = jlib:nameprep(Server), + LServer = exmpp_stringprep:nameprep(Server), mnesia:dirty_select( session, [{#session{usr = '$1', _ = '_'}, @@ -287,7 +311,12 @@ handle_cast(_Msg, State) -> %% {stop, Reason, State} %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- -handle_info({route, From, To, Packet}, State) -> +handle_info({route, FromOld, ToOld, PacketOld}, State) -> + % XXX OLD FORMAT: From, To, Packet. + From = jlib:from_old_jid(FromOld), + To = jlib:from_old_jid(ToOld), + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, + [?DEFAULT_NS], ?PREFIXED_NS), case catch do_route(From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", @@ -339,9 +368,9 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- set_session(SID, User, Server, Resource, Priority, Info) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - LResource = jlib:resourceprep(Resource), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + LResource = exmpp_stringprep:resourceprep(Resource), US = {LUser, LServer}, USR = {LUser, LServer, LResource}, F = fun() -> @@ -371,45 +400,49 @@ clean_table_from_bad_node(Node) -> do_route(From, To, Packet) -> ?DEBUG("session manager~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n", [From, To, Packet, 8]), - #jid{user = User, server = Server, - luser = LUser, lserver = LServer, lresource = LResource} = To, - {xmlelement, Name, Attrs, _Els} = Packet, + #jid{node = User, domain = Server, + lnode = LUser, ldomain = LServer, lresource = LResource} = To, + % XXX OLD FORMAT: From, To. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), case LResource of - "" -> - case Name of - "presence" -> + undefined -> + case Packet of + _ when ?IS_PRESENCE(Packet) -> {Pass, _Subsc} = - case xml:get_attr_s("type", Attrs) of - "subscribe" -> - Reason = xml:get_path_s( - Packet, - [{elem, "status"}, cdata]), + case exmpp_presence:get_type(Packet) of + 'subscribe' -> + Reason = exmpp_presence:get_status(Packet), + % XXX OLD FORMAT: From. {ejabberd_hooks:run_fold( roster_in_subscription, LServer, false, - [User, Server, From, subscribe, Reason]), + [User, Server, FromOld, subscribe, Reason]), true}; - "subscribed" -> + 'subscribed' -> + % XXX OLD FORMAT: From. {ejabberd_hooks:run_fold( roster_in_subscription, LServer, false, - [User, Server, From, subscribed, ""]), + [User, Server, FromOld, subscribed, ""]), true}; - "unsubscribe" -> + 'unsubscribe' -> + % XXX OLD FORMAT: From. {ejabberd_hooks:run_fold( roster_in_subscription, LServer, false, - [User, Server, From, unsubscribe, ""]), + [User, Server, FromOld, unsubscribe, ""]), true}; - "unsubscribed" -> + 'unsubscribed' -> + % XXX OLD FORMAT: From. {ejabberd_hooks:run_fold( roster_in_subscription, LServer, false, - [User, Server, From, unsubscribed, ""]), + [User, Server, FromOld, unsubscribed, ""]), true}; _ -> {true, false} @@ -421,21 +454,21 @@ do_route(From, To, Packet) -> fun({_, R}) -> do_route( From, - jlib:jid_replace_resource(To, R), + exmpp_jid:bare_jid_to_jid(To, R), Packet) end, PResources); true -> ok end; - "message" -> + _ when ?IS_MESSAGE(Packet) -> route_message(From, To, Packet); - "iq" -> + _ when ?IS_IQ(Packet) -> process_iq(From, To, Packet); - "broadcast" -> + #xmlel{name = 'broadcast'} -> lists:foreach( fun(R) -> do_route(From, - jlib:jid_replace_resource(To, R), + exmpp_jid:bare_jid_to_jid(To, R), Packet) end, get_user_resources(User, Server)); _ -> @@ -445,17 +478,17 @@ do_route(From, To, Packet) -> USR = {LUser, LServer, LResource}, case mnesia:dirty_index_read(session, USR, #session.usr) of [] -> - case Name of - "message" -> + case Packet of + _ when ?IS_MESSAGE(Packet) -> route_message(From, To, Packet); - "iq" -> - case xml:get_attr_s("type", Attrs) of - "error" -> ok; - "result" -> ok; + _ when ?IS_IQ(Packet) -> + case exmpp_iq:get_type(Packet) of + 'error' -> ok; + 'result' -> ok; _ -> Err = - jlib:make_error_reply( - Packet, ?ERR_RECIPIENT_UNAVAILABLE), + exmpp_iq:error(Packet, + 'service-unavailable'), ejabberd_router:route(To, From, Err) end; _ -> @@ -465,21 +498,29 @@ do_route(From, To, Packet) -> Session = lists:max(Ss), Pid = element(2, Session#session.sid), ?DEBUG("sending to process ~p~n", [Pid]), - Pid ! {route, From, To, Packet} + % XXX OLD FORMAT: From, To, Packet. + PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, + [?DEFAULT_NS], ?PREFIXED_NS), + Pid ! {route, FromOld, ToOld, PacketOld} end end. route_message(From, To, Packet) -> - LUser = To#jid.luser, - LServer = To#jid.lserver, + LUser = To#jid.lnode, + LServer = To#jid.ldomain, PrioRes = get_user_present_resources(LUser, LServer), + % XXX OLD FORMAT: From, To, Packet. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), + PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, + [?DEFAULT_NS], ?PREFIXED_NS), case catch lists:max(PrioRes) of {Priority, _R} when is_integer(Priority), Priority >= 0 -> lists:foreach( %% Route messages to all priority that equals the max, if %% positive fun({P, R}) when P == Priority -> - LResource = jlib:resourceprep(R), + LResource = exmpp_stringprep:resourceprep(R), USR = {LUser, LServer, LResource}, case mnesia:dirty_index_read(session, USR, #session.usr) of [] -> @@ -488,7 +529,8 @@ route_message(From, To, Packet) -> Session = lists:max(Ss), Pid = element(2, Session#session.sid), ?DEBUG("sending to process ~p~n", [Pid]), - Pid ! {route, From, To, Packet} + % XXX OLD FORMAT: From, To, Packet. + Pid ! {route, FromOld, ToOld, PacketOld} end; %% Ignore other priority: ({_Prio, _Res}) -> @@ -496,22 +538,23 @@ route_message(From, To, Packet) -> end, PrioRes); _ -> - case xml:get_tag_attr_s("type", Packet) of - "error" -> + case exmpp_message:get_type(Packet) of + 'error' -> ok; - "groupchat" -> + 'groupchat' -> bounce_offline_message(From, To, Packet); - "headline" -> + 'headline' -> bounce_offline_message(From, To, Packet); _ -> case ejabberd_auth:is_user_exists(LUser, LServer) of true -> + % XXX OLD FORMAT: From, To, Packet. ejabberd_hooks:run(offline_message_hook, LServer, - [From, To, Packet]); + [FromOld, ToOld, PacketOld]); _ -> - Err = jlib:make_error_reply( - Packet, ?ERR_SERVICE_UNAVAILABLE), + Err = exmpp_stanza:reply_with_error( + Packet, 'service-unaivailable'), ejabberd_router:route(To, From, Err) end end @@ -557,9 +600,9 @@ get_user_present_resources(LUser, LServer) -> %% On new session, check if some existing connections need to be replace check_for_sessions_to_replace(User, Server, Resource) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - LResource = jlib:resourceprep(Resource), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + LResource = exmpp_stringprep:resourceprep(Resource), %% TODO: Depending on how this is executed, there could be an unneeded %% replacement for max_sessions. We need to check this at some point. @@ -606,7 +649,7 @@ check_max_sessions(LUser, LServer) -> %% Defaults to infinity get_max_user_sessions(LUser, Host) -> case acl:match_rule( - Host, max_user_sessions, jlib:make_jid(LUser, Host, "")) of + Host, max_user_sessions, exmpp_jid:make_bare_jid(LUser, Host)) of Max when is_integer(Max) -> Max; infinity -> infinity; _ -> ?MAX_USER_SESSIONS @@ -616,32 +659,41 @@ get_max_user_sessions(LUser, Host) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% process_iq(From, To, Packet) -> - IQ = jlib:iq_query_info(Packet), + % XXX OLD FORMAT: From, To, Packet. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), + PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, + [?DEFAULT_NS], ?PREFIXED_NS), + IQ = jlib:iq_query_info(PacketOld), case IQ of #iq{xmlns = XMLNS} -> - Host = To#jid.lserver, + Host = To#jid.ldomain, case ets:lookup(sm_iqtable, {XMLNS, Host}) of [{_, Module, Function}] -> - ResIQ = Module:Function(From, To, IQ), + % XXX OLD FORMAT: From, To, IQ. + ResIQ = Module:Function(FromOld, ToOld, IQ), if ResIQ /= ignore -> - ejabberd_router:route(To, From, - jlib:iq_to_xml(ResIQ)); + % XXX OLD FORMAT: ResIQ. + ReplyOld = jlib:iq_to_xml(ResIQ), + Reply = exmpp_xml:xmlelement_to_xmlel(ReplyOld, + [?DEFAULT_NS], ?PREFIXED_NS), + ejabberd_router:route(To, From, Reply); true -> ok end; [{_, Module, Function, Opts}] -> + % XXX OLD FORMAT: From, To, IQ. gen_iq_handler:handle(Host, Module, Function, Opts, - From, To, IQ); + FromOld, ToOld, IQ); [] -> - Err = jlib:make_error_reply( - Packet, ?ERR_SERVICE_UNAVAILABLE), + Err = exmpp_iq:error(Packet, 'service-unavailable'), ejabberd_router:route(To, From, Err) end; reply -> ok; _ -> - Err = jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST), + Err = exmpp_iq:error(Packet, 'bad-request'), ejabberd_router:route(To, From, Err), ok end. From 8c33e12616109fd94d764e8b78158a16f2b29e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 1 Jul 2008 08:01:06 +0000 Subject: [PATCH 023/582] Use the new clause of exmpp_stanza:reply_with_error/2, exmpp_iq:error/2, exmpp_iq:error_without_original/2 and the new exmpp_jid:make_bare_jid/1. SVN Revision: 1394 --- ChangeLog | 6 ++++++ src/ejabberd_c2s.erl | 29 ++++++++++++----------------- src/ejabberd_s2s.erl | 2 +- src/ejabberd_s2s_in.erl | 2 +- src/ejabberd_s2s_out.erl | 3 +-- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6cb3c2887..e6197bc00 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,12 @@ * src/ejabberd_sm.erl: Convert to exmpp. + * src/ejabberd_c2s.erl, src/ejabberd_s2s.erl, src/ejabberd_s2s_in.erl, + src/ejabberd_s2s_out.erl: Use the new clause of + exmpp_stanza:reply_with_error/2, exmpp_iq:error/2, + exmpp_iq:error_without_original/2 and the new + exmpp_jid:make_bare_jid/1. + 2008-06-30 Jean-Sébastien Pédron * src/Makefile.in: Remove the -I flag for exmpp includes; the diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 91a866d47..86892b195 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -124,6 +124,7 @@ [?NS_JABBER_CLIENT], [{?NS_XMPP, "stream"}])). -define(ERR_FEATURE_NOT_IMPLEMENTED, ?STANZA_ERROR('feature-not-implemented')). +% XXX OLD FORMAT: Re-include jlib.hrl (after clean-up). -record(iq, {id = "", type, xmlns = "", @@ -236,7 +237,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> true -> Lang = exmpp_stream:get_lang(Opening), change_shaper(StateData, - exmpp_jid:make_bare_jid(undefined, Server)), + exmpp_jid:make_bare_jid(Server)), case exmpp_stream:get_version(Opening) of {1, 0} -> send_element(StateData, Header), @@ -442,8 +443,8 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> "(~w) Failed legacy authentication for ~s", [StateData#state.socket, exmpp_jid:jid_to_string(JID)]), - Err = exmpp_stanza:error('not-authorized'), - Res = exmpp_iq:error_without_original(El, Err), + Res = exmpp_iq:error_without_original(El, + 'not-authorized'), send_element(StateData, Res), fsm_next_state(wait_for_auth, StateData) end; @@ -452,8 +453,8 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> "(~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), + Res = exmpp_iq:error_without_original(El, + 'not-allowed'), send_element(StateData, Res), fsm_next_state(wait_for_auth, StateData) end @@ -463,8 +464,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> "(~w) Forbidden legacy authentication for " "username '~s' with resource '~s'", [StateData#state.socket, U, R]), - Err1 = exmpp_stanza:error('jid-malformed'), - Res1 = exmpp_iq:error_without_original(El, Err1), + Res1 = exmpp_iq:error_without_original(El, 'jid-malformed'), send_element(StateData, Res1), fsm_next_state(wait_for_auth, StateData) end; @@ -1134,8 +1134,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> {false, Attrs, StateData} end end; - % XXX OLD FORMAT: broadcast? - #xmlel{ns = _NS, name = 'broadcast', attrs = Attrs} -> + #xmlel{name = 'broadcast', attrs = Attrs} -> % XXX OLD FORMAT: Els are #xmlelement. Els = PacketOld#xmlelement.children, ?DEBUG("broadcast~n~p~n", [Els]), @@ -1182,8 +1181,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> gen_iq_handler:handle(Host, Module, Function, Opts, FromOld, ToOld, IQ); [] -> - Err = exmpp_stanza:error('feature-not-implemented'), - Res = exmpp_iq:error(Packet, Err), + Res = exmpp_iq:error(Packet, 'feature-not-implemented'), ejabberd_router:route(To, From, Res) end, {false, Attrs, StateData}; @@ -1200,9 +1198,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> allow -> {true, Attrs, StateData}; deny -> - Err = exmpp_stanza:error( - 'feature-not-implemented'), - Res = exmpp_iq:error(Packet, Err), + Res = exmpp_iq:error(Packet, 'feature-not-implemented'), ejabberd_router:route(To, From, Res), {false, Attrs, StateData} end @@ -1975,10 +1971,9 @@ process_unauthenticated_stanza(StateData, El) -> % The only reasonable IQ's here are auth and register IQ's % They contain secrets, so don't include subelements to response ResIQ = exmpp_iq:error_without_original(El, - exmpp_stanza:error(El#xmlel.ns, 'service-unavailable')), + 'service-unavailable'), Res1 = exmpp_stanza:set_sender(ResIQ, - exmpp_jid:make_bare_jid(undefined, - StateData#state.server)), + exmpp_jid:make_bare_jid(StateData#state.server)), Res2 = exmpp_stanza:remove_recipient(Res1), send_element(StateData, Res2); _ -> diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index a5f67fa9f..e023cd4a2 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -291,7 +291,7 @@ do_route(From, To, Packet) -> "result" -> ok; _ -> Err = exmpp_stanza:reply_with_error(Packet, - exmpp_stanza:error('service-unavailable')), + 'service-unavailable'), ejabberd_router:route(To, From, Err) end, false diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 6504ec9f8..b3229a69e 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -346,7 +346,7 @@ stream_established({xmlstreamelement, El}, StateData) -> Conns = ?DICT:store({LFrom, LTo}, wait_for_verification, StateData#state.connections), change_shaper(StateData, LTo, - exmpp_jid:make_bare_jid(undefined, LFrom)), + exmpp_jid:make_bare_jid(LFrom)), {next_state, stream_established, StateData#state{connections = Conns, diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index bcf5b811b..93171ced3 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -812,8 +812,7 @@ bounce_element(El, Condition) -> "error" -> ok; "result" -> ok; _ -> - Error = exmpp_stanza:error(El#xmlel.ns, Condition), - Err = exmpp_stanza:reply_with_error(El, Error), + Err = exmpp_stanza:reply_with_error(El, Condition), From = exmpp_jid:string_to_jid(exmpp_stanza:get_sender(El)), To = exmpp_jid:string_to_jid(exmpp_stanza:get_recipient(El)), % No namespace conversion (:server <-> :client) is done. From 83a33726ce33e700257f406a8bb0b28bb553b790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 1 Jul 2008 09:12:59 +0000 Subject: [PATCH 024/582] Add function short_bare_jid/1. SVN Revision: 1395 --- ChangeLog | 2 ++ src/jlib.erl | 33 +++++++++++++++++++-------------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index e6197bc00..54deda3d2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,8 @@ exmpp_iq:error_without_original/2 and the new exmpp_jid:make_bare_jid/1. + * src/jlib.erl: Add function short_bare_jid/1. + 2008-06-30 Jean-Sébastien Pédron * src/Makefile.in: Remove the -I flag for exmpp includes; the diff --git a/src/jlib.erl b/src/jlib.erl index d6938c799..4a0fbcbfa 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -63,7 +63,8 @@ ip_to_list/1, from_old_jid/1, to_old_jid/1, - short_jid/1]). + short_jid/1, + short_bare_jid/1]). -include("jlib.hrl"). @@ -699,14 +700,14 @@ ip_to_list({A,B,C,D}) -> %% Empty fields are set to `undefined', not the empty string. from_old_jid(#jid{user = Node, resource = Resource, - luser = LNode, lresource = LResource} = JID) -> + luser = LNode, lresource = LResource} = JID) -> {Node1, LNode1} = case Node of - "" -> {undefined, undefined}; - _ -> {Node, LNode} + "" -> {undefined, undefined}; + _ -> {Node, LNode} end, {Resource1, LResource1} = case Resource of - "" -> {undefined, undefined}; - _ -> {Resource, LResource} + "" -> {undefined, undefined}; + _ -> {Resource, LResource} end, JID#jid{user = Node1, resource = Resource1, luser = LNode1, lresource = LResource1}. @@ -719,18 +720,22 @@ from_old_jid(#jid{user = Node, resource = Resource, %% Empty fields are set to the empty string, not `undefined'. to_old_jid(#jid{user = Node, resource = Resource, - luser = LNode, lresource = LResource} = JID) -> + luser = LNode, lresource = LResource} = JID) -> {Node1, LNode1} = case Node of - undefined -> {"", ""}; - _ -> {Node, LNode} + undefined -> {"", ""}; + _ -> {Node, LNode} end, {Resource1, LResource1} = case Resource of - undefined -> {"", ""}; - _ -> {Resource, LResource} + undefined -> {"", ""}; + _ -> {Resource, LResource} end, JID#jid{user = Node1, resource = Resource1, luser = LNode1, lresource = LResource1}. -short_jid(JID0) -> - JID = to_old_jid(JID0), - {JID#jid.luser, JID#jid.lserver, JID#jid.lresource}. +short_jid(JID) -> + JID1 = to_old_jid(JID), + {JID1#jid.luser, JID1#jid.lserver, JID1#jid.lresource}. + +short_bare_jid(JID) -> + JID1 = to_old_jid(exmpp_jid:jid_to_bare_jid(JID)), + {JID1#jid.luser, JID1#jid.lserver, JID1#jid.lresource}. From b9074097da43cb4637aaa1fe82f7df21f8331d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 1 Jul 2008 09:13:49 +0000 Subject: [PATCH 025/582] Forgot to convert a from the new to the old record. SVN Revision: 1396 --- ChangeLog | 3 +++ src/ejabberd_sm.erl | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 54deda3d2..74200742b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,9 @@ * src/jlib.erl: Add function short_bare_jid/1. + * src/ejabberd_sm.erl: Forgot to convert a from the new to + the old record. + 2008-06-30 Jean-Sébastien Pédron * src/Makefile.in: Remove the -I flag for exmpp includes; the diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index acb18341f..8ca59bfbc 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -190,8 +190,11 @@ get_user_info(User, Server, Resource) -> set_presence(SID, User, Server, Resource, Priority, Presence, Info) -> set_session(SID, User, Server, Resource, Priority, Info), + % XXX OLD FORMAT: Presence. + PresenceOld = exmpp_xml:xmlel_to_xmlelement(Presence, + [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_hooks:run(set_presence_hook, exmpp_stringprep:nameprep(Server), - [User, Server, Resource, Presence]). + [User, Server, Resource, PresenceOld]). unset_presence(SID, User, Server, Resource, Status, Info) -> set_session(SID, User, Server, Resource, undefined, Info), From f55274c7fb8c4efe5fb96f9abe365795aaac9c02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 1 Jul 2008 09:17:48 +0000 Subject: [PATCH 026/582] o Use jlib:short_bare_jid/1. o Rewrite is_auth_packet/1 to use new formats. o Don't convert before calling ejabberd_sm:set_presence/7. o Don't convert broadcast children, because it's an internal special element. SVN Revision: 1397 --- ChangeLog | 5 ++++ src/ejabberd_c2s.erl | 71 ++++++++++++++++---------------------------- 2 files changed, 31 insertions(+), 45 deletions(-) diff --git a/ChangeLog b/ChangeLog index 74200742b..3b009fe1d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,11 @@ * src/ejabberd_sm.erl: Forgot to convert a from the new to the old record. + * src/ejabberd_c2s.erl: Use jlib:short_bare_jid/1. Rewrite + is_auth_packet/1 to use new formats. Don't convert before + calling ejabberd_sm:set_presence/7. Don't convert broadcast children, + because it's an internal special element. + 2008-06-30 Jean-Sébastien Pédron * src/Makefile.in: Remove the -I flag for exmpp includes; the diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 86892b195..f47433896 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -419,8 +419,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> StateData#state.server, {[], []}, [U, StateData#state.server]), - LJID = jlib:short_jid( - exmpp_jid:jid_to_bare_jid(JID)), + LJID = jlib:short_bare_jid(JID), Fs1 = [LJID | Fs], Ts1 = [LJID | Ts], PrivList = ejabberd_hooks:run_fold( @@ -741,7 +740,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> StateData#state.server, {[], []}, [U, StateData#state.server]), - LJID = jlib:short_jid(exmpp_jid:jid_to_bare_jid(JID)), + LJID = jlib:short_bare_jid(JID), Fs1 = [LJID | Fs], Ts1 = [LJID | Ts], PrivList = @@ -1017,9 +1016,8 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> #xmlel{attrs = Attrs} when ?IS_PRESENCE(Packet) -> case exmpp_presence:get_type(Packet) of 'probe' -> - % XXX OLD FORMAT: LFrom and LBFrom. LFrom = jlib:short_jid(From), - LBFrom = jlib:short_jid(exmpp_jid:jid_to_bare_jid(From)), + LBFrom = jlib:short_bare_jid(From), NewStateData = case ?SETS:is_element( LFrom, StateData#state.pres_a) orelse @@ -1031,8 +1029,6 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> case ?SETS:is_element( LFrom, StateData#state.pres_f) of true -> - % XXX OLD FORMAT: Stores short - % JIDs. A = ?SETS:add_element( LFrom, StateData#state.pres_a), @@ -1041,8 +1037,6 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> case ?SETS:is_element( LBFrom, StateData#state.pres_f) of true -> - % XXX OLD FORMAT: Stores - % short JIDs. A = ?SETS:add_element( LBFrom, StateData#state.pres_a), @@ -1055,15 +1049,13 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> process_presence_probe(From, To, NewStateData), {false, Attrs, NewStateData}; 'error' -> - % XXX OLD FORMAT: LFrom. LFrom = jlib:short_jid(From), NewA = remove_element(LFrom, StateData#state.pres_a), {true, Attrs, StateData#state{pres_a = NewA}}; 'invisible' -> - % XXX OLD FORMAT: Create a function to change 'type'. Attrs1 = exmpp_stanza:set_type_in_attrs(Attrs, - "unavailable"), + 'unavailable'), {true, Attrs1, StateData}; 'subscribe' -> {true, Attrs, StateData}; @@ -1084,10 +1076,8 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> {FromOld, ToOld, PacketOld}, in]) of allow -> - % XXX OLD FORMAT: LFrom and LBFrom. LFrom = jlib:short_jid(From), - LBFrom = jlib:short_jid( - exmpp_jid:jid_to_bare_jid(From)), + LBFrom = jlib:short_bare_jid(From), %% Note contact availability % XXX OLD FORMAT: Els are #xmlelement. Els = PacketOld#xmlelement.children, @@ -1135,12 +1125,9 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> end end; #xmlel{name = 'broadcast', attrs = Attrs} -> - % XXX OLD FORMAT: Els are #xmlelement. - Els = PacketOld#xmlelement.children, - ?DEBUG("broadcast~n~p~n", [Els]), - case Els of + ?DEBUG("broadcast~n~p~n", [Packet#xmlel.children]), + case Packet#xmlel.children of [{item, {U, S, R} = _IJIDShort, ISubscription}] -> - % XXX OLD FORMAT: IJID is of the form {U, S, R}. IJID = exmpp_jid:make_jid(U, S, R), {false, Attrs, roster_change(IJID, ISubscription, @@ -1177,7 +1164,6 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> % XXX OLD FORMAT: IQ is an old #iq, % From, To. IQ = jlib:iq_query_info(PacketOld), - io:format("IQ = ~p~n", [IQ]), gen_iq_handler:handle(Host, Module, Function, Opts, FromOld, ToOld, IQ); [] -> @@ -1233,12 +1219,13 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> Attrs3 = exmpp_stanza:set_recipient_in_attrs(Attrs2, To), FixedPacket = Packet#xmlel{attrs = Attrs3}, send_element(StateData, FixedPacket), - % XXX OLD FORMAT: From, To, FixedPacket. + % XXX OLD FORMAT: JID, From, To, FixedPacket. + JIDOld = jlib:to_old_jid(StateData#state.jid), FixedPacketOld = exmpp_xml:xmlel_to_xmlelement(FixedPacket, [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_hooks:run(user_receive_packet, StateData#state.server, - [StateData#state.jid, FromOld, ToOld, FixedPacketOld]), + [JIDOld, FromOld, ToOld, FixedPacketOld]), % XXX OLD FORMAT: From, To, FixedPacket. ejabberd_hooks:run(c2s_loop_debug, [{route, FromOld, ToOld, PacketOld}]), fsm_next_state(StateName, NewState); @@ -1345,30 +1332,27 @@ new_id() -> is_auth_packet(El) -> - % XXX OLD FORMAT: El. - ElOld = exmpp_xml:xmlel_to_xmlelement(El, - [?DEFAULT_NS], ?PREFIXED_NS), - NS_Auth = atom_to_list(?NS_LEGACY_AUTH), - case jlib:iq_query_info(ElOld) of - #iq{id = ID, type = Type, xmlns = NS_Auth, sub_el = SubEl} -> - {xmlelement, _, _, Els} = SubEl, - {auth, ID, Type, - get_auth_tags(Els, "", "", "", undefined)}; - _ -> + case exmpp_iq:is_request(El) of + true -> + {auth, exmpp_stanza:get_id(El), exmpp_iq:get_type(El), + get_auth_tags(El#xmlel.children, + undefined, undefined, undefined, undefined)}; + false -> false end. -get_auth_tags([{xmlelement, Name, _Attrs, Els}| L], U, P, D, R) -> - CData = xml:get_cdata(Els), +get_auth_tags([#xmlel{ns = ?NS_LEGACY_AUTH, name = Name, children = Els} | L], + U, P, D, R) -> + CData = exmpp_xml:get_cdata_from_list_as_list(Els), case Name of - "username" -> + 'username' -> get_auth_tags(L, CData, P, D, R); - "password" -> + 'password' -> get_auth_tags(L, U, CData, D, R); - "digest" -> + 'digest' -> get_auth_tags(L, U, P, CData, R); - "resource" -> + 'resource' -> get_auth_tags(L, U, P, D, CData); _ -> get_auth_tags(L, U, P, D, R) @@ -1390,7 +1374,7 @@ get_conn_type(StateData) -> process_presence_probe(From, To, StateData) -> LFrom = jlib:short_jid(From), - LBFrom = jlib:short_jid(exmpp_jid:jid_to_bare_jid(From)), + LBFrom = jlib:short_bare_jid(From), case StateData#state.pres_last of undefined -> ok; @@ -1563,9 +1547,9 @@ presence_track(From, To, Packet, StateData) -> LTo = jlib:short_jid(To), User = StateData#state.user, Server = StateData#state.server, + BFrom = exmpp_jid:jid_to_bare_jid(From), % XXX OLD FORMAT: From, To, Packet. FromOld = jlib:to_old_jid(From), - BFrom = exmpp_jid:jid_to_bare_jid(From), ToOld = jlib:to_old_jid(To), PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, [?DEFAULT_NS], ?PREFIXED_NS), @@ -1839,15 +1823,12 @@ roster_change(IJID, ISubscription, StateData) -> update_priority(Priority, Packet, StateData) -> Info = [{ip, StateData#state.ip},{conn, StateData#state.conn}], - % XXX OLD FORMAT: Packet. - PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_sm:set_presence(StateData#state.sid, StateData#state.user, StateData#state.server, StateData#state.resource, Priority, - PacketOld, + Packet, Info). process_privacy_iq(From, To, From ffbf8d5faa71552f52880d346e501ec5f889cedd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 1 Jul 2008 09:41:32 +0000 Subject: [PATCH 027/582] Convert acl to exmpp. SVN Revision: 1398 --- ChangeLog | 5 +++++ src/acl.erl | 4 ++-- src/ejabberd_c2s.erl | 9 +++------ src/ejabberd_s2s_in.erl | 4 +--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3b009fe1d..9c98b3e51 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,6 +18,11 @@ calling ejabberd_sm:set_presence/7. Don't convert broadcast children, because it's an internal special element. + * src/acl.erl: Convert to exmpp. + + * src/ejabberd_c2s.erl, src/ejabberd_s2s_in.erl: acl doesn't require + conversion anymore. + 2008-06-30 Jean-Sébastien Pédron * src/Makefile.in: Remove the -I flag for exmpp includes; the diff --git a/src/acl.erl b/src/acl.erl index eed295cb8..e65c34c4a 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -87,7 +87,7 @@ add_list(Host, ACLs, Clear) -> end. normalize(A) -> - jlib:nodeprep(A). + exmpp_stringprep:nodeprep(A). normalize_spec({A, B}) -> {A, normalize(B)}; normalize_spec({A, B, C}) -> @@ -158,7 +158,7 @@ match_acl(ACL, JID, Host) -> all -> true; none -> false; _ -> - {User, Server, Resource} = jlib:jid_tolower(JID), + {User, Server, Resource} = jlib:short_jid(JID), lists:any(fun(#acl{aclspec = Spec}) -> case Spec of all -> diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index f47433896..271ffabd7 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -392,10 +392,8 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> {auth, _ID, set, {U, P, D, R}} -> try JID = exmpp_jid:make_jid(U, StateData#state.server, R), - % XXX OLD FORMAT: JID. - JIDOld = jlib:to_old_jid(JID), case acl:match_rule(StateData#state.server, - StateData#state.access, JIDOld) of + StateData#state.access, JID) of allow -> case ejabberd_auth:check_password_with_authmodule( U, StateData#state.server, P, @@ -717,11 +715,9 @@ wait_for_session({xmlstreamelement, El}, StateData) -> U = StateData#state.user, R = StateData#state.resource, JID = StateData#state.jid, - % XXX OLD FORMAT: JID. - JIDOld = jlib:to_old_jid(JID), true = exmpp_server_session:want_establishment(El), case acl:match_rule(StateData#state.server, - StateData#state.access, JIDOld) of + StateData#state.access, JID) of allow -> ?INFO_MSG("(~w) Opened session for ~s", [StateData#state.socket, @@ -757,6 +753,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> privacy_list = PrivList}); _ -> % XXX OLD FORMAT: Jid. + JIDOld = jlib:to_old_jid(JID), ejabberd_hooks:run(forbidden_session_hook, StateData#state.server, [JIDOld]), ?INFO_MSG("(~w) Forbidden session for ~s", diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index b3229a69e..562033076 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -573,9 +573,7 @@ send_element(StateData, El) -> change_shaper(StateData, Host, JID) -> - % XXX OLD FORMAT: JIDOld is an old #jid. - JIDOld = jlib:to_old_jid(JID), - Shaper = acl:match_rule(Host, StateData#state.shaper, JIDOld), + Shaper = acl:match_rule(Host, StateData#state.shaper, JID), (StateData#state.sockmod):change_shaper(StateData#state.socket, Shaper). From b08ae0734747053a50260b0d3fc4726b021b9681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 1 Jul 2008 09:46:57 +0000 Subject: [PATCH 028/582] acl doesn't require conversion anymore. SVN Revision: 1399 --- src/ejabberd_c2s.erl | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 271ffabd7..8cc98e0f2 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1306,10 +1306,8 @@ terminate(_Reason, StateName, StateData) -> %%%---------------------------------------------------------------------- change_shaper(StateData, JID) -> - % XXX OLD FORMAT: JIDOld is an old #jid. - JIDOld = jlib:to_old_jid(JID), Shaper = acl:match_rule(StateData#state.server, - StateData#state.shaper, JIDOld), + StateData#state.shaper, JID), (StateData#state.sockmod):change_shaper(StateData#state.socket, Shaper). send_text(StateData, Text) -> @@ -1674,10 +1672,6 @@ presence_broadcast_to_trusted(StateData, From, T, A, Packet) -> presence_broadcast_first(From, StateData, Packet) -> Probe = exmpp_presence:probe(), - % XXX OLD FORMAT: From, Packet, Probe. - FromOld = jlib:to_old_jid(From), - PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - [?DEFAULT_NS], ?PREFIXED_NS), ?SETS:fold(fun({U, S, R}, X) -> FJID = exmpp_jid:make_jid(U, S, R), ejabberd_router:route( @@ -1695,8 +1689,11 @@ presence_broadcast_first(From, StateData, Packet) -> As = ?SETS:fold( fun({U, S, R} = JID, A) -> FJID = exmpp_jid:make_jid(U, S, R), - % XXX OLD FORMAT: FJID. + % XXX OLD FORMAT: From, FJID, Packet. + FromOld = jlib:to_old_jid(From), FJIDOld = jlib:to_old_jid(FJID), + PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, + [?DEFAULT_NS], ?PREFIXED_NS), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, From 6f7cf2e58b770af7eb109856e4eeedd4f5e8389c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 1 Jul 2008 10:20:01 +0000 Subject: [PATCH 029/582] Use a function to convert to old structures instead of duplicating code inside the module. SVN Revision: 1400 --- ChangeLog | 3 ++ src/ejabberd_router.erl | 62 +++++++++++++++-------------------------- 2 files changed, 26 insertions(+), 39 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9c98b3e51..a73436b6c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,6 +23,9 @@ * src/ejabberd_c2s.erl, src/ejabberd_s2s_in.erl: acl doesn't require conversion anymore. + * src/ejabberd_router.erl: Use a function to convert to old + structures instead of duplicating code inside the module. + 2008-06-30 Jean-Sébastien Pédron * src/Makefile.in: Remove the -I flag for exmpp includes; the diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index d31c90132..26c494ba0 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -66,25 +66,7 @@ start_link() -> route(From, To, Packet) -> % XXX OLD FORMAT: This code helps to detect old format routing. - {FromOld, ToOld, PacketOld} = case Packet of - #xmlelement{} -> - catch throw(for_stacktrace), % To have a stacktrace. - io:format("~nROUTE: old #xmlelement:~n~p~n~p~n~n", - [Packet, erlang:get_stacktrace()]), - {From, To, Packet}; - _ -> - F = jlib:to_old_jid(From), - T = jlib:to_old_jid(To), - Default_NS = case lists:member({Packet#xmlel.ns, none}, - Packet#xmlel.declared_ns) of - true -> []; - false -> [Packet#xmlel.ns] - end, - P = exmpp_xml:xmlel_to_xmlelement(Packet, - Default_NS, - [{?NS_XMPP, ?NS_XMPP_pfx}, {?NS_DIALBACK, ?NS_DIALBACK_pfx}]), - {F, T, P} - end, + {FromOld, ToOld, PacketOld} = convert_to_old_structs(From, To, Packet), case catch do_route(FromOld, ToOld, PacketOld) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", @@ -258,26 +240,7 @@ handle_cast(_Msg, State) -> %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- handle_info({route, From, To, Packet}, State) -> - % XXX OLD FORMAT: This code helps to detect old format routing. - {FromOld, ToOld, PacketOld} = case Packet of - #xmlelement{} -> - catch throw(for_stacktrace), % To have a stacktrace. - io:format("~nROUTE: old #xmlelement:~n~p~n~p~n~n", - [Packet, erlang:get_stacktrace()]), - {From, To, Packet}; - _ -> - F = jlib:to_old_jid(From), - T = jlib:to_old_jid(To), - Default_NS = case lists:member({Packet#xmlel.ns, none}, - Packet#xmlel.declared_ns) of - true -> []; - false -> [Packet#xmlel.ns] - end, - P = exmpp_xml:xmlel_to_xmlelement(Packet, - Default_NS, - [{?NS_XMPP, ?NS_XMPP_pfx}, {?NS_DIALBACK, ?NS_DIALBACK_pfx}]), - {F, T, P} - end, + {FromOld, ToOld, PacketOld} = convert_to_old_structs(From, To, Packet), case catch do_route(FromOld, ToOld, PacketOld) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", @@ -443,3 +406,24 @@ update_tables() -> ok end. +convert_to_old_structs(From, To, Packet) -> + % XXX OLD FORMAT: This code helps to detect old format routing. + if + is_record(Packet, xmlelement) -> + catch throw(for_stacktrace), % To have a stacktrace. + io:format("~nROUTE: old #xmlelement:~n~p~n~p~n~n", + [Packet, erlang:get_stacktrace()]), + {From, To, Packet}; + true -> + F = jlib:to_old_jid(From), + T = jlib:to_old_jid(To), + Default_NS = case lists:member({Packet#xmlel.ns, none}, + Packet#xmlel.declared_ns) of + true -> []; + false -> [Packet#xmlel.ns] + end, + P = exmpp_xml:xmlel_to_xmlelement(Packet, + Default_NS, + [{?NS_XMPP, ?NS_XMPP_pfx}, {?NS_DIALBACK, ?NS_DIALBACK_pfx}]), + {F, T, P} + end. From 094fa47f9f0e10d65d45a9e2101c7f7ae614de01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 1 Jul 2008 10:21:35 +0000 Subject: [PATCH 030/582] Convert gen_iq_handler to exmpp. SVN Revision: 1401 --- ChangeLog | 5 +++++ src/ejabberd_c2s.erl | 7 ++----- src/ejabberd_sm.erl | 2 +- src/gen_iq_handler.erl | 47 ++++++++++++++++++++++++++++++++++++++---- 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index a73436b6c..13c5f29f5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -26,6 +26,11 @@ * src/ejabberd_router.erl: Use a function to convert to old structures instead of duplicating code inside the module. + * src/gen_iq_handler.erl: Convert to exmpp. + + * src/ejabberd_sm.erl, src/ejabberd_c2s.erl: Don't convert + before calling gen_iq_handler:handle/7. + 2008-06-30 Jean-Sébastien Pédron * src/Makefile.in: Remove the -I flag for exmpp includes; the diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 8cc98e0f2..140e23378 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1158,11 +1158,8 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> % for namespaces. case ets:lookup(sm_iqtable, {atom_to_list(?NS_VCARD), Host}) of [{_, Module, Function, Opts}] -> - % XXX OLD FORMAT: IQ is an old #iq, - % From, To. - IQ = jlib:iq_query_info(PacketOld), gen_iq_handler:handle(Host, Module, Function, Opts, - FromOld, ToOld, IQ); + From, To, Packet); [] -> Res = exmpp_iq:error(Packet, 'feature-not-implemented'), ejabberd_router:route(To, From, Res) @@ -1935,7 +1932,7 @@ resend_subscription_requests(#state{user = User, process_unauthenticated_stanza(StateData, El) -> ElOld = exmpp_xml:xmlel_to_xmlelement(El, [?DEFAULT_NS], ?PREFIXED_NS), case jlib:iq_query_info(ElOld) of - #iq{} = IQ -> + IQ when is_record(IQ, iq) -> ResOld = ejabberd_hooks:run_fold(c2s_unauthenticated_iq, StateData#state.server, empty, diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 8ca59bfbc..bae6ce473 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -688,7 +688,7 @@ process_iq(From, To, Packet) -> [{_, Module, Function, Opts}] -> % XXX OLD FORMAT: From, To, IQ. gen_iq_handler:handle(Host, Module, Function, Opts, - FromOld, ToOld, IQ); + From, To, Packet); [] -> Err = exmpp_iq:error(Packet, 'service-unavailable'), ejabberd_router:route(To, From, Err) diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index 912f22c17..aeae283f7 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -41,12 +41,21 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). -record(state, {host, module, function}). +% XXX OLD FORMAT: Re-include jlib.hrl (after clean-up). +-record(iq, {id = "", + type, + xmlns = "", + lang = "", + sub_el}). + %%==================================================================== %% API %%==================================================================== @@ -101,10 +110,12 @@ handle(Host, Module, Function, Opts, From, To, IQ) -> no_queue -> process_iq(Host, Module, Function, From, To, IQ); {one_queue, Pid} -> - Pid ! {process_iq, From, To, IQ}; + {FromOld, ToOld, IQ_Rec} = convert_to_old_structs(From, To, IQ), + Pid ! {process_iq, FromOld, ToOld, IQ_Rec}; {queues, Pids} -> Pid = lists:nth(erlang:phash(now(), length(Pids)), Pids), - Pid ! {process_iq, From, To, IQ}; + {FromOld, ToOld, IQ_Rec} = convert_to_old_structs(From, To, IQ), + Pid ! {process_iq, FromOld, ToOld, IQ_Rec}; parallel -> spawn(?MODULE, process_iq, [Host, Module, Function, From, To, IQ]); _ -> @@ -113,14 +124,20 @@ handle(Host, Module, Function, Opts, From, To, IQ) -> process_iq(_Host, Module, Function, From, To, IQ) -> - case catch Module:Function(From, To, IQ) of + {FromOld, ToOld, IQ_Rec} = convert_to_old_structs(From, To, IQ), + case catch Module:Function(FromOld, ToOld, IQ_Rec) of {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); ResIQ -> if ResIQ /= ignore -> + ReplyOld = jlib:iq_to_xml(ResIQ), + Reply = exmpp_xml:xmlelement_to_xmlel(ReplyOld, + [?NS_JABBER_CLIENT], + [{?NS_XMPP, ?NS_XMPP_pfx}, + {?NS_DIALBACK, ?NS_DIALBACK_pfx}]), ejabberd_router:route(To, From, - jlib:iq_to_xml(ResIQ)); + Reply); true -> ok end @@ -199,3 +216,25 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- + +convert_to_old_structs(From, To, IQ) -> + if + is_record(IQ, iq) -> + catch throw(for_stacktrace), % To have a stacktrace. + io:format("~nIQ HANDLER: old #iq:~n~p~n~p~n~n", + [IQ, erlang:get_stacktrace()]), + {From, To, IQ}; + true -> + F = jlib:to_old_jid(From), + T = jlib:to_old_jid(To), + Default_NS = case lists:member({IQ#xmlel.ns, none}, + IQ#xmlel.declared_ns) of + true -> []; + false -> [IQ#xmlel.ns] + end, + IQOld = exmpp_xml:xmlel_to_xmlelement(IQ, + Default_NS, + [{?NS_XMPP, ?NS_XMPP_pfx}, {?NS_DIALBACK, ?NS_DIALBACK_pfx}]), + I = jlib:iq_query_info(IQOld), + {F, T, I} + end. From d6e6432a46c8a3c10aca643acf915c894b7e2930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 1 Jul 2008 13:34:51 +0000 Subject: [PATCH 031/582] Convert to exmpp. SVN Revision: 1402 --- ChangeLog | 2 + src/ejabberd_local.erl | 97 +++++++++++++++++++++++++++++------------- 2 files changed, 70 insertions(+), 29 deletions(-) diff --git a/ChangeLog b/ChangeLog index 13c5f29f5..b4f760626 100644 --- a/ChangeLog +++ b/ChangeLog @@ -31,6 +31,8 @@ * src/ejabberd_sm.erl, src/ejabberd_c2s.erl: Don't convert before calling gen_iq_handler:handle/7. + * src/ejabberd_local.erl: Convert to exmpp. + 2008-06-30 Jean-Sébastien Pédron * src/Makefile.in: Remove the -I flag for exmpp includes; the diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index b54173581..e86c030bc 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -45,8 +45,9 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -record(state, {}). @@ -54,6 +55,13 @@ -define(IQTABLE, local_iqtable). +% These are the namespace already declared by the stream opening. This is +% used at serialization time. +-define(DEFAULT_NS, ?NS_JABBER_CLIENT). +-define(PREFIXED_NS, [ + {?NS_XMPP, ?NS_XMPP_pfx}, {?NS_DIALBACK, ?NS_DIALBACK_pfx} +]). + %%==================================================================== %% API %%==================================================================== @@ -65,39 +73,51 @@ start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). process_iq(From, To, Packet) -> - IQ = jlib:iq_query_info(Packet), - case IQ of - #iq{xmlns = XMLNS} -> - Host = To#jid.lserver, + case exmpp_iq:get_kind(Packet) of + request -> + Host = To#jid.ldomain, + Request = exmpp_iq:get_request(Packet), + XMLNS = case Request#xmlel.ns of + NS when is_atom(NS) -> atom_to_list(NS); + NS -> NS + end, case ets:lookup(?IQTABLE, {XMLNS, Host}) of [{_, Module, Function}] -> - ResIQ = Module:Function(From, To, IQ), + % XXX OLD FORMAT: From, To, Packet. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), + PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, + [?DEFAULT_NS], ?PREFIXED_NS), + IQ_Rec = jlib:iq_query_info(PacketOld), + ResIQ = Module:Function(FromOld, ToOld, IQ_Rec), if ResIQ /= ignore -> + % XXX OLD FORMAT: ResIQ. + ReplyOld = jlib:iq_to_xml(ResIQ), + Reply = exmpp_xml:xmlelement_to_xmlel(ReplyOld, + [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_router:route( - To, From, jlib:iq_to_xml(ResIQ)); + To, From, Reply); true -> ok end; [{_, Module, Function, Opts}] -> gen_iq_handler:handle(Host, Module, Function, Opts, - From, To, IQ); + From, To, Packet); [] -> - Err = jlib:make_error_reply( - Packet, ?ERR_FEATURE_NOT_IMPLEMENTED), + Err = exmpp_iq:error(Packet, 'feature-not-implemented'), ejabberd_router:route(To, From, Err) end; - reply -> + response -> process_iq_reply(From, To, Packet); _ -> - Err = jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST), + Err = exmpp_iq:error(Packet, 'bad-request'), ejabberd_router:route(To, From, Err), ok end. process_iq_reply(From, To, Packet) -> - IQ = jlib:iq_query_or_response_info(Packet), - #iq{id = ID} = IQ, + ID = exmpp_stanza:get_id(Packet), case catch mnesia:dirty_read(iq_response, ID) of [] -> ok; @@ -114,13 +134,24 @@ process_iq_reply(From, To, Packet) -> end, case mnesia:transaction(F) of {atomic, {Module, Function}} -> - Module:Function(From, To, IQ); + % XXX OLD FORMAT: From, To, Packet. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), + PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, + [?DEFAULT_NS], ?PREFIXED_NS), + IQ_Rec = jlib:iq_query_or_response_info(PacketOld), + Module:Function(FromOld, ToOld, IQ_Rec); _ -> ok end end. -route(From, To, Packet) -> +route(FromOld, ToOld, PacketOld) -> + % XXX OLD FORMAT: From, To, Packet. + From = jlib:from_old_jid(FromOld), + To = jlib:from_old_jid(ToOld), + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, + [?DEFAULT_NS], ?PREFIXED_NS), case catch do_route(From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", @@ -145,7 +176,7 @@ refresh_iq_handlers() -> ejabberd_local ! refresh_iq_handlers. bounce_resource_packet(From, To, Packet) -> - Err = jlib:make_error_reply(Packet, ?ERR_ITEM_NOT_FOUND), + Err = exmpp_stanza:error(Packet, 'item-not-found'), ejabberd_router:route(To, From, Err), stop. @@ -202,7 +233,12 @@ handle_cast(_Msg, State) -> %% {stop, Reason, State} %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- -handle_info({route, From, To, Packet}, State) -> +handle_info({route, FromOld, ToOld, PacketOld}, State) -> + % XXX OLD FORMAT: From, To, Packet. + From = jlib:from_old_jid(FromOld), + To = jlib:from_old_jid(ToOld), + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, + [?DEFAULT_NS], ?PREFIXED_NS), case catch do_route(From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", @@ -272,29 +308,32 @@ do_route(From, To, Packet) -> ?DEBUG("local route~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n", [From, To, Packet, 8]), if - To#jid.luser /= "" -> + To#jid.lnode /= undefined -> ejabberd_sm:route(From, To, Packet); - To#jid.lresource == "" -> - {xmlelement, Name, _Attrs, _Els} = Packet, - case Name of - "iq" -> + To#jid.lresource == undefined -> + case Packet of + _ when ?IS_IQ(Packet) -> process_iq(From, To, Packet); - "message" -> + _ when ?IS_MESSAGE(Packet) -> ok; - "presence" -> + _ when ?IS_PRESENCE(Packet) -> ok; _ -> ok end; true -> - {xmlelement, _Name, Attrs, _Els} = Packet, - case xml:get_attr_s("type", Attrs) of + case exmpp_stanza:get_type(Packet) of "error" -> ok; "result" -> ok; _ -> + % XXX OLD FORMAT: From, To, Packet. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), + PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, + [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_hooks:run(local_send_to_resource_hook, - To#jid.lserver, - [From, To, Packet]) + To#jid.ldomain, + [FromOld, ToOld, PacketOld]) end end. From a25609f66bb8a0f2f5f4746b0ea7bb9a2e3d63bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 1 Jul 2008 14:19:36 +0000 Subject: [PATCH 032/582] Accept new #xmlel in functions that create #iq. A warning is printed when these functions are called with an old #xmlelement. SVN Revision: 1403 --- ChangeLog | 4 ++++ src/jlib.erl | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index b4f760626..92f2b00cb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -33,6 +33,10 @@ * src/ejabberd_local.erl: Convert to exmpp. + * src/jlib.erl: Accept new #xmlel in functions that create #iq. A + warning is printed when these functions are called with an old + #xmlelement. + 2008-06-30 Jean-Sébastien Pédron * src/Makefile.in: Remove the -I flag for exmpp includes; the diff --git a/src/jlib.erl b/src/jlib.erl index 4a0fbcbfa..b926c15fb 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -360,7 +360,17 @@ iq_query_info(El) -> iq_query_or_response_info(El) -> iq_info_internal(El, any). -iq_info_internal({xmlelement, Name, Attrs, Els}, Filter) when Name == "iq" -> +iq_info_internal({xmlel, NS, _, _, _, _} = El, Filter) -> + ElOld = exmpp_xml:xmlel_to_xmlelement(El, [NS], + [{'http://etherx.jabber.org/streams', "stream"}]), + iq_info_internal2(ElOld, Filter); +iq_info_internal(El, Filter) -> + catch throw(for_stacktrace), + io:format("~nJLIB: old #xmlelement:~n~p~n~p~n~n", + [El, erlang:get_stacktrace()]), + iq_info_internal2(El, Filter). + +iq_info_internal2({xmlelement, Name, Attrs, Els}, Filter) when Name == "iq" -> %% Filter is either request or any. If it is request, any replies %% are converted to the atom reply. ID = xml:get_attr_s("id", Attrs), @@ -413,7 +423,7 @@ iq_info_internal({xmlelement, Name, Attrs, Els}, Filter) when Name == "iq" -> Class == reply, Filter /= any -> reply end; -iq_info_internal(_, _) -> +iq_info_internal2(_, _) -> not_iq. is_iq_request_type(set) -> true; From 5317dd64d78766a061c5377ff23ddbd7ab6fe6a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 1 Jul 2008 14:20:20 +0000 Subject: [PATCH 033/582] Change warning message. SVN Revision: 1404 --- ChangeLog | 2 ++ src/ejabberd_router.erl | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 92f2b00cb..12d2b100b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -37,6 +37,8 @@ warning is printed when these functions are called with an old #xmlelement. + * src/ejabberd_router.erl: Change warning message. + 2008-06-30 Jean-Sébastien Pédron * src/Makefile.in: Remove the -I flag for exmpp includes; the diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index 26c494ba0..1774268b0 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -411,7 +411,7 @@ convert_to_old_structs(From, To, Packet) -> if is_record(Packet, xmlelement) -> catch throw(for_stacktrace), % To have a stacktrace. - io:format("~nROUTE: old #xmlelement:~n~p~n~p~n~n", + io:format("~nROUTER: old #xmlelement:~n~p~n~p~n~n", [Packet, erlang:get_stacktrace()]), {From, To, Packet}; true -> From 48cf5cb84aea6c0b33f34c0abf4a84a244f1e7f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 1 Jul 2008 14:25:02 +0000 Subject: [PATCH 034/582] Do not use the #iq record anymore internally. However it's still created and passed to other modules. SVN Revision: 1405 --- ChangeLog | 4 ++++ src/ejabberd_c2s.erl | 28 ++++++++++------------------ src/ejabberd_local.erl | 12 ++++-------- src/ejabberd_sm.erl | 30 +++++++++++------------------- src/gen_iq_handler.erl | 12 ++---------- 5 files changed, 31 insertions(+), 55 deletions(-) diff --git a/ChangeLog b/ChangeLog index 12d2b100b..4e03125f2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -39,6 +39,10 @@ * src/ejabberd_router.erl: Change warning message. + * src/ejabberd_sm.erl, src/ejabberd_c2s.erl, src/ejabberd_local.erl, + src/gen_iq_handler.erl: Do not use the #iq record anymore internally. + However it's still created and passed to other modules. + 2008-06-30 Jean-Sébastien Pédron * src/Makefile.in: Remove the -I flag for exmpp includes; the diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 140e23378..76e92de8d 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -124,13 +124,6 @@ [?NS_JABBER_CLIENT], [{?NS_XMPP, "stream"}])). -define(ERR_FEATURE_NOT_IMPLEMENTED, ?STANZA_ERROR('feature-not-implemented')). -% XXX OLD FORMAT: Re-include jlib.hrl (after clean-up). --record(iq, {id = "", - type, - xmlns = "", - lang = "", - sub_el}). - %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- @@ -546,7 +539,7 @@ wait_for_feature_request({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, certfile, 1, StateData#state.tls_options)] end, Socket = StateData#state.socket, - Proceed = exmpp_xml:document_fragment_to_list( + Proceed = exmpp_xml:node_to_list( exmpp_server_tls:proceed(), [?DEFAULT_NS], ?PREFIXED_NS), TLSSocket = (StateData#state.sockmod):starttls( Socket, TLSOpts, @@ -1825,10 +1818,8 @@ update_priority(Priority, Packet, StateData) -> process_privacy_iq(From, To, El, StateData) -> - % XXX OLD FORMAT: IQ is #iq. - ElOld = exmpp_xml:xmlel_to_xmlelement(El, - [?DEFAULT_NS], ?PREFIXED_NS), - IQOld = jlib:iq_query_info(ElOld), + % XXX OLD FORMAT: IQ_Rec is an #iq. + IQ_Rec = jlib:iq_query_info(El), % XXX OLD FORMAT: JIDs. FromOld = jlib:to_old_jid(From), ToOld = jlib:to_old_jid(To), @@ -1838,13 +1829,13 @@ process_privacy_iq(From, To, R = ejabberd_hooks:run_fold( privacy_iq_get, StateData#state.server, {error, ?ERR_FEATURE_NOT_IMPLEMENTED}, - [FromOld, ToOld, IQOld, StateData#state.privacy_list]), + [FromOld, ToOld, IQ_Rec, StateData#state.privacy_list]), {R, StateData}; set -> case ejabberd_hooks:run_fold( privacy_iq_set, StateData#state.server, {error, ?ERR_FEATURE_NOT_IMPLEMENTED}, - [FromOld, ToOld, IQOld]) of + [FromOld, ToOld, IQ_Rec]) of {result, R, NewPrivList} -> {{result, R}, StateData#state{privacy_list = NewPrivList}}; @@ -1930,13 +1921,14 @@ resend_subscription_requests(#state{user = User, PendingSubscriptions). process_unauthenticated_stanza(StateData, El) -> - ElOld = exmpp_xml:xmlel_to_xmlelement(El, [?DEFAULT_NS], ?PREFIXED_NS), - case jlib:iq_query_info(ElOld) of - IQ when is_record(IQ, iq) -> + case exmpp_iq:get_kind(El) of + request -> + % XXX OLD FORMAT: IQ_Rec is an #iq. + IQ_Rec = jlib:iq_query_info(El), ResOld = ejabberd_hooks:run_fold(c2s_unauthenticated_iq, StateData#state.server, empty, - [StateData#state.server, IQ, + [StateData#state.server, IQ_Rec, StateData#state.ip]), case ResOld of empty -> diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index e86c030bc..b0c355163 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -77,18 +77,14 @@ process_iq(From, To, Packet) -> request -> Host = To#jid.ldomain, Request = exmpp_iq:get_request(Packet), - XMLNS = case Request#xmlel.ns of - NS when is_atom(NS) -> atom_to_list(NS); - NS -> NS - end, + XMLNS = exmpp_xml:get_ns_as_list(Request), case ets:lookup(?IQTABLE, {XMLNS, Host}) of [{_, Module, Function}] -> - % XXX OLD FORMAT: From, To, Packet. + % XXX OLD FORMAT: From, To. FromOld = jlib:to_old_jid(From), ToOld = jlib:to_old_jid(To), - PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - [?DEFAULT_NS], ?PREFIXED_NS), - IQ_Rec = jlib:iq_query_info(PacketOld), + % XXX OLD FORMAT: IQ_Rec is an #iq. + IQ_Rec = jlib:iq_query_info(Packet), ResIQ = Module:Function(FromOld, ToOld, IQ_Rec), if ResIQ /= ignore -> diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index bae6ce473..31d40eaf0 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -74,13 +74,6 @@ {?NS_XMPP, ?NS_XMPP_pfx}, {?NS_DIALBACK, ?NS_DIALBACK_pfx} ]). -% XXX OLD FORMAT: Re-include jlib.hrl (after clean-up). --record(iq, {id = "", - type, - xmlns = "", - lang = "", - sub_el}). - %%==================================================================== %% API %%==================================================================== @@ -662,19 +655,19 @@ get_max_user_sessions(LUser, Host) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% process_iq(From, To, Packet) -> - % XXX OLD FORMAT: From, To, Packet. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - [?DEFAULT_NS], ?PREFIXED_NS), - IQ = jlib:iq_query_info(PacketOld), - case IQ of - #iq{xmlns = XMLNS} -> + case exmpp_iq:get_kind(Packet) of + request -> Host = To#jid.ldomain, + Request = exmpp_iq:get_request(Packet), + XMLNS = exmpp_xml:get_ns_as_list(Request), case ets:lookup(sm_iqtable, {XMLNS, Host}) of [{_, Module, Function}] -> - % XXX OLD FORMAT: From, To, IQ. - ResIQ = Module:Function(FromOld, ToOld, IQ), + % XXX OLD FORMAT: From, To. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), + % XXX OLD FORMAT: IQ_Rec is an #iq. + IQ_Rec = jlib:iq_query_info(Packet), + ResIQ = Module:Function(FromOld, ToOld, IQ_Rec), if ResIQ /= ignore -> % XXX OLD FORMAT: ResIQ. @@ -686,14 +679,13 @@ process_iq(From, To, Packet) -> ok end; [{_, Module, Function, Opts}] -> - % XXX OLD FORMAT: From, To, IQ. gen_iq_handler:handle(Host, Module, Function, Opts, From, To, Packet); [] -> Err = exmpp_iq:error(Packet, 'service-unavailable'), ejabberd_router:route(To, From, Err) end; - reply -> + response -> ok; _ -> Err = exmpp_iq:error(Packet, 'bad-request'), diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index aeae283f7..e3da47f0c 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -227,14 +227,6 @@ convert_to_old_structs(From, To, IQ) -> true -> F = jlib:to_old_jid(From), T = jlib:to_old_jid(To), - Default_NS = case lists:member({IQ#xmlel.ns, none}, - IQ#xmlel.declared_ns) of - true -> []; - false -> [IQ#xmlel.ns] - end, - IQOld = exmpp_xml:xmlel_to_xmlelement(IQ, - Default_NS, - [{?NS_XMPP, ?NS_XMPP_pfx}, {?NS_DIALBACK, ?NS_DIALBACK_pfx}]), - I = jlib:iq_query_info(IQOld), - {F, T, I} + I_Rec = jlib:iq_query_info(IQ), + {F, T, I_Rec} end. From 13b78b1ad2aac7a4fa518422f1834fe55d97d3ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 1 Jul 2008 15:51:34 +0000 Subject: [PATCH 035/582] Routing is now done with #xmlel. A warning is printed if those modules have to route an old #xmlelement. SVN Revision: 1406 --- ChangeLog | 5 +++ src/ejabberd_local.erl | 26 ++++++++++------ src/ejabberd_router.erl | 69 +++++++++++++++++++++-------------------- src/ejabberd_s2s.erl | 31 +++++++++++------- src/ejabberd_sm.erl | 22 +++++++++---- 5 files changed, 94 insertions(+), 59 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4e03125f2..0b324577c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -43,6 +43,11 @@ src/gen_iq_handler.erl: Do not use the #iq record anymore internally. However it's still created and passed to other modules. + * src/ejabberd_router.erl, src/ejabberd_sm.erl, + src/ejabberd_local.erl, src/ejabberd_s2s.erl: Routing is now done with + #xmlel. A warning is printed if those modules have to route an old + #xmlelement. + 2008-06-30 Jean-Sébastien Pédron * src/Makefile.in: Remove the -I flag for exmpp includes; the diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index b0c355163..76719bbb8 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -133,21 +133,24 @@ process_iq_reply(From, To, Packet) -> % XXX OLD FORMAT: From, To, Packet. FromOld = jlib:to_old_jid(From), ToOld = jlib:to_old_jid(To), - PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - [?DEFAULT_NS], ?PREFIXED_NS), - IQ_Rec = jlib:iq_query_or_response_info(PacketOld), + IQ_Rec = jlib:iq_query_or_response_info(Packet), Module:Function(FromOld, ToOld, IQ_Rec); _ -> ok end end. -route(FromOld, ToOld, PacketOld) -> +route(FromOld, ToOld, #xmlelement{} = PacketOld) -> + catch throw(for_stacktrace), % To have a stacktrace. + io:format("~nLOCAL: old #xmlelement:~n~p~n~p~n~n", + [PacketOld, erlang:get_stacktrace()]), % XXX OLD FORMAT: From, To, Packet. From = jlib:from_old_jid(FromOld), To = jlib:from_old_jid(ToOld), - Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, - [?DEFAULT_NS], ?PREFIXED_NS), + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, [?NS_JABBER_CLIENT], + [{?NS_XMPP, ?NS_XMPP_pfx}]), + route(From, To, Packet); +route(From, To, Packet) -> case catch do_route(From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", @@ -229,12 +232,17 @@ handle_cast(_Msg, State) -> %% {stop, Reason, State} %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- -handle_info({route, FromOld, ToOld, PacketOld}, State) -> +handle_info({route, FromOld, ToOld, #xmlelement{} = PacketOld}, State) -> + catch throw(for_stacktrace), % To have a stacktrace. + io:format("~nLOCAL: old #xmlelement:~n~p~n~p~n~n", + [PacketOld, erlang:get_stacktrace()]), % XXX OLD FORMAT: From, To, Packet. From = jlib:from_old_jid(FromOld), To = jlib:from_old_jid(ToOld), - Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, - [?DEFAULT_NS], ?PREFIXED_NS), + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, [?NS_JABBER_CLIENT], + [{?NS_XMPP, ?NS_XMPP_pfx}]), + handle_info({route, From, To, Packet}, State); +handle_info({route, From, To, Packet}, State) -> case catch do_route(From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index 1774268b0..cd7f02002 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -64,10 +64,18 @@ start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). +route(FromOld, ToOld, #xmlelement{} = PacketOld) -> + catch throw(for_stacktrace), % To have a stacktrace. + io:format("~nROUTER: old #xmlelement:~n~p~n~p~n~n", + [PacketOld, erlang:get_stacktrace()]), + % XXX OLD FORMAT: From, To, Packet. + From = jlib:from_old_jid(FromOld), + To = jlib:from_old_jid(ToOld), + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, [?NS_JABBER_CLIENT], + [{?NS_XMPP, ?NS_XMPP_pfx}]), + route(From, To, Packet); route(From, To, Packet) -> - % XXX OLD FORMAT: This code helps to detect old format routing. - {FromOld, ToOld, PacketOld} = convert_to_old_structs(From, To, Packet), - case catch do_route(FromOld, ToOld, PacketOld) of + case catch do_route(From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", [Reason, {From, To, Packet}]); @@ -239,9 +247,18 @@ handle_cast(_Msg, State) -> %% {stop, Reason, State} %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- +handle_info({route, FromOld, ToOld, #xmlelement{} = PacketOld}, State) -> + catch throw(for_stacktrace), % To have a stacktrace. + io:format("~nROUTER: old #xmlelement:~n~p~n~p~n~n", + [PacketOld, erlang:get_stacktrace()]), + % XXX OLD FORMAT: From, To, Packet. + From = jlib:from_old_jid(FromOld), + To = jlib:from_old_jid(ToOld), + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, [?NS_JABBER_CLIENT], + [{?NS_XMPP, ?NS_XMPP_pfx}]), + handle_info({route, From, To, Packet}, State); handle_info({route, From, To, Packet}, State) -> - {FromOld, ToOld, PacketOld} = convert_to_old_structs(From, To, Packet), - case catch do_route(FromOld, ToOld, PacketOld) of + case catch do_route(From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", [Reason, {From, To, Packet}]); @@ -304,9 +321,19 @@ code_change(_OldVsn, State, _Extra) -> do_route(OrigFrom, OrigTo, OrigPacket) -> ?DEBUG("route~n\tfrom ~p~n\tto ~p~n\tpacket ~p~n", [OrigFrom, OrigTo, OrigPacket]), + % XXX OLD FORMAT: OrigFrom, OrigTo, OrigPacket. + OrigFromOld = jlib:to_old_jid(OrigFrom), + OrigToOld = jlib:to_old_jid(OrigTo), + OrigPacketOld = exmpp_xml:xmlel_to_xmlelement(OrigPacket, + [?NS_JABBER_CLIENT], [{?NS_XMPP, ?NS_XMPP_pfx}]), case ejabberd_hooks:run_fold(filter_packet, - {OrigFrom, OrigTo, OrigPacket}, []) of - {From, To, Packet} -> + {OrigFromOld, OrigToOld, OrigPacketOld}, []) of + {FromOld, ToOld, PacketOld} -> + % XXX OLD FORMAT: From, To, Packet. + From = jlib:from_old_jid(FromOld), + To = jlib:from_old_jid(ToOld), + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, + [?NS_JABBER_CLIENT], [{?NS_XMPP, ?NS_XMPP_pfx}]), LDstDomain = To#jid.ldomain, case mnesia:dirty_read(route, LDstDomain) of [] -> @@ -334,11 +361,9 @@ do_route(OrigFrom, OrigTo, OrigPacket) -> source -> jlib:short_jid(From); destination -> jlib:short_jid(To); bare_source -> - jlib:short_jid( - exmpp_jid:jid_to_bare_jid(From)); + jlib:short_bare_jid(From); bare_destination -> - jlib:short_jid( - exmpp_jid:jid_tl_bare_jid(To)) + jlib:short_bare_jid(To) end, case get_component_number(LDstDomain) of undefined -> @@ -405,25 +430,3 @@ update_tables() -> false -> ok end. - -convert_to_old_structs(From, To, Packet) -> - % XXX OLD FORMAT: This code helps to detect old format routing. - if - is_record(Packet, xmlelement) -> - catch throw(for_stacktrace), % To have a stacktrace. - io:format("~nROUTER: old #xmlelement:~n~p~n~p~n~n", - [Packet, erlang:get_stacktrace()]), - {From, To, Packet}; - true -> - F = jlib:to_old_jid(From), - T = jlib:to_old_jid(To), - Default_NS = case lists:member({Packet#xmlel.ns, none}, - Packet#xmlel.declared_ns) of - true -> []; - false -> [Packet#xmlel.ns] - end, - P = exmpp_xml:xmlel_to_xmlelement(Packet, - Default_NS, - [{?NS_XMPP, ?NS_XMPP_pfx}, {?NS_DIALBACK, ?NS_DIALBACK_pfx}]), - {F, T, P} - end. diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index e023cd4a2..b8af4251f 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -74,12 +74,17 @@ start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). -route(FromOld, ToOld, PacketOld) -> +route(FromOld, ToOld, #xmlelement{} = PacketOld) -> + catch throw(for_stacktrace), % To have a stacktrace. + io:format("~nS2S: old #xmlelement:~n~p~n~p~n~n", + [PacketOld, erlang:get_stacktrace()]), % XXX OLD FORMAT: From, To, Packet. From = jlib:from_old_jid(FromOld), To = jlib:from_old_jid(ToOld), - Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, - [?DEFAULT_NS], ?PREFIXED_NS), + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, [?NS_JABBER_CLIENT], + [{?NS_XMPP, ?NS_XMPP_pfx}]), + route(From, To, Packet); +route(From, To, Packet) -> case catch do_route(From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", @@ -214,12 +219,17 @@ handle_cast(_Msg, State) -> handle_info({mnesia_system_event, {mnesia_down, Node}}, State) -> clean_table_from_bad_node(Node), {noreply, State}; -handle_info({route, FromOld, ToOld, PacketOld}, State) -> - % XXX OLD FORMAT: From, To, Packet +handle_info({route, FromOld, ToOld, #xmlelement{} = PacketOld}, State) -> + catch throw(for_stacktrace), % To have a stacktrace. + io:format("~nS2S: old #xmlelement:~n~p~n~p~n~n", + [PacketOld, erlang:get_stacktrace()]), + % XXX OLD FORMAT: From, To, Packet. From = jlib:from_old_jid(FromOld), To = jlib:from_old_jid(ToOld), - Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, - [?NS_JABBER_CLIENT], [{?NS_XMPP, ?NS_XMPP_pfx}]), + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, [?NS_JABBER_CLIENT], + [{?NS_XMPP, ?NS_XMPP_pfx}]), + handle_info({route, From, To, Packet}, State); +handle_info({route, From, To, Packet}, State) -> case catch do_route(From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", @@ -267,16 +277,15 @@ clean_table_from_bad_node(Node) -> do_route(From, To, Packet) -> ?DEBUG("s2s manager~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n", [From, To, Packet, 8]), - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), case find_connection(From, To) of {atomic, Pid} when pid(Pid) -> ?DEBUG("sending to process ~p~n", [Pid]), NewPacket1 = exmpp_stanza:set_sender(Packet, From), NewPacket = exmpp_stanza:set_recipient(NewPacket1, To), #jid{ldomain = MyServer} = From, - % XXX OLD FORMAT: NewPacket. + % XXX OLD FORMAT: From, To, NewPacket. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), NewPacketOld = exmpp_xml:xmlel_to_xmlelement(NewPacket, [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_hooks:run( diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 31d40eaf0..9300958d5 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -84,12 +84,17 @@ start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). -route(FromOld, ToOld, PacketOld) -> +route(FromOld, ToOld, #xmlelement{} = PacketOld) -> + catch throw(for_stacktrace), % To have a stacktrace. + io:format("~nSM: old #xmlelement:~n~p~n~p~n~n", + [PacketOld, erlang:get_stacktrace()]), % XXX OLD FORMAT: From, To, Packet. From = jlib:from_old_jid(FromOld), To = jlib:from_old_jid(ToOld), - Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, - [?DEFAULT_NS], ?PREFIXED_NS), + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, [?NS_JABBER_CLIENT], + [{?NS_XMPP, ?NS_XMPP_pfx}]), + route(From, To, Packet); +route(From, To, Packet) -> case catch do_route(From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", @@ -307,12 +312,17 @@ handle_cast(_Msg, State) -> %% {stop, Reason, State} %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- -handle_info({route, FromOld, ToOld, PacketOld}, State) -> +handle_info({route, FromOld, ToOld, #xmlelement{} = PacketOld}, State) -> + catch throw(for_stacktrace), % To have a stacktrace. + io:format("~nSM: old #xmlelement:~n~p~n~p~n~n", + [PacketOld, erlang:get_stacktrace()]), % XXX OLD FORMAT: From, To, Packet. From = jlib:from_old_jid(FromOld), To = jlib:from_old_jid(ToOld), - Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, - [?DEFAULT_NS], ?PREFIXED_NS), + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, [?NS_JABBER_CLIENT], + [{?NS_XMPP, ?NS_XMPP_pfx}]), + handle_info({route, From, To, Packet}, State); +handle_info({route, From, To, Packet}, State) -> case catch do_route(From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p~nwhen processing: ~p", From 1a687a4f1a1410f9a42e42327567ec8da80715c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 8 Jul 2008 15:43:52 +0000 Subject: [PATCH 036/582] SASL errors are now atoms, not strings anymore. SVN Revision: 1420 --- ChangeLog | 6 ++++++ src/cyrsasl.erl | 20 ++++++++++---------- src/cyrsasl_anonymous.erl | 2 +- src/cyrsasl_digest.erl | 8 ++++---- src/cyrsasl_plain.erl | 4 ++-- src/ejabberd_c2s.erl | 12 ++++-------- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0b324577c..5c7a7d30e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-07-08 Jean-Sébastien Pédron + + * src/cyrsasl.erl, src/cyrsasl_anonymous.erl, src/cyrsasl_digest.erl, + src/cyrsasl_plain.erl, src/ejabberd_c2s.erl: Errors are now atoms, not + strings anymore. + 2008-07-01 Jean-Sébastien Pédron * src/ejabberd_sm.erl: Convert to exmpp. diff --git a/src/cyrsasl.erl b/src/cyrsasl.erl index 17354e21f..e942aa3e8 100644 --- a/src/cyrsasl.erl +++ b/src/cyrsasl.erl @@ -86,14 +86,14 @@ register_mechanism(Mechanism, Module, RequirePlainPassword) -> %% end. check_credentials(_State, Props) -> - User = xml:get_attr_s(username, Props), - case jlib:nodeprep(User) of - error -> - {error, "not-authorized"}; - "" -> - {error, "not-authorized"}; - _LUser -> - ok + case proplists:get_value(username, Props) of + undefined -> + {error, 'not-authorized'}; + User -> + case exmpp_stringprep:is_node(User) of + false -> {error, 'not-authorized'}; + true -> ok + end end. listmech(Host) -> @@ -133,10 +133,10 @@ server_start(State, Mech, ClientIn) -> mech_state = MechState}, ClientIn); _ -> - {error, "no-mechanism"} + {error, 'no-mechanism'} end; false -> - {error, "no-mechanism"} + {error, 'no-mechanism'} end. server_step(State, ClientIn) -> diff --git a/src/cyrsasl_anonymous.erl b/src/cyrsasl_anonymous.erl index b9cf7449c..4f1219882 100644 --- a/src/cyrsasl_anonymous.erl +++ b/src/cyrsasl_anonymous.erl @@ -50,7 +50,7 @@ mech_step(State, _ClientIn) -> %% Checks that the username is available case ejabberd_auth:is_user_exists(User, Server) of - true -> {error, "not-authorized"}; + true -> {error, 'not-authorized'}; false -> {ok, [{username, User}, {auth_module, ejabberd_auth_anonymous}]} end. diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl index 5395205d7..c269a74bf 100644 --- a/src/cyrsasl_digest.erl +++ b/src/cyrsasl_digest.erl @@ -39,13 +39,13 @@ mech_step(#state{step = 1, nonce = Nonce} = State, _) -> mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) -> case parse(ClientIn) of bad -> - {error, "bad-protocol"}; + {error, 'bad-protocol'}; KeyVals -> UserName = xml:get_attr_s("username", KeyVals), AuthzId = xml:get_attr_s("authzid", KeyVals), case (State#state.get_password)(UserName) of {false, _} -> - {error, "not-authorized", UserName}; + {error, 'not-authorized', UserName}; {Passwd, AuthModule} -> Response = response(KeyVals, UserName, Passwd, Nonce, AuthzId, "AUTHENTICATE"), @@ -61,7 +61,7 @@ mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) -> username = UserName, authzid = AuthzId}}; _ -> - {error, "not-authorized", UserName} + {error, 'not-authorized', UserName} end end end; @@ -73,7 +73,7 @@ mech_step(#state{step = 5, {auth_module, AuthModule}]}; mech_step(A, B) -> ?DEBUG("SASL DIGEST: A ~p B ~p", [A,B]), - {error, "bad-protocol"}. + {error, 'bad-protocol'}. parse(S) -> diff --git a/src/cyrsasl_plain.erl b/src/cyrsasl_plain.erl index 1b9cddb49..c0ca708d8 100644 --- a/src/cyrsasl_plain.erl +++ b/src/cyrsasl_plain.erl @@ -51,10 +51,10 @@ mech_step(State, ClientIn) -> {ok, [{username, User}, {authzid, AuthzId}, {auth_module, AuthModule}]}; _ -> - {error, "not-authorized", User} + {error, 'not-authorized', User} end; _ -> - {error, "bad-protocol"} + {error, 'bad-protocol'} end. diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 76e92de8d..0b3360947 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -515,15 +515,13 @@ wait_for_feature_request({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, "(~w) Failed authentication for ~s@~s", [StateData#state.socket, Username, StateData#state.server]), - % XXX OLD FORMAT: list_to_atom(Error). send_element(StateData, - exmpp_server_sasl:failure(list_to_atom(Error))), + exmpp_server_sasl:failure(Error)), {next_state, wait_for_feature_request, StateData, ?C2S_OPEN_TIMEOUT}; {error, Error} -> - % XXX OLD FORMAT: list_to_atom(Error). send_element(StateData, - exmpp_server_sasl:failure(list_to_atom(Error))), + exmpp_server_sasl:failure(Error)), fsm_next_state(wait_for_feature_request, StateData) end; {?NS_TLS, 'starttls'} when TLS == true, @@ -631,14 +629,12 @@ wait_for_sasl_response({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, "(~w) Failed authentication for ~s@~s", [StateData#state.socket, Username, StateData#state.server]), - % XXX OLD FORMAT: list_to_atom(Error). send_element(StateData, - exmpp_server_sasl:failure(list_to_atom(Error))), + exmpp_server_sasl:failure(Error)), fsm_next_state(wait_for_feature_request, StateData); {error, Error} -> - % XXX OLD FORMAT: list_to_atom(Error). send_element(StateData, - exmpp_server_sasl:failure(list_to_atom(Error))), + exmpp_server_sasl:failure(Error)), fsm_next_state(wait_for_feature_request, StateData) end; _ -> From d5aa4be7e5dddce190d667f694b8872c11caab33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 9 Jul 2008 09:14:19 +0000 Subject: [PATCH 037/582] Convert #xmlelement returned by the 'c2s_stream_features' hook to #xmlel. SVN Revision: 1421 --- ChangeLog | 5 +++++ src/ejabberd_c2s.erl | 11 +++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5c7a7d30e..726641487 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-07-09 Jean-Sébastien Pédron + + * src/ejabberd_c2s.erl: Convert #xmlelement returned by the + 'c2s_stream_features' hook to #xmlel. + 2008-07-08 Jean-Sébastien Pédron * src/cyrsasl.erl, src/cyrsasl_anonymous.erl, src/cyrsasl_digest.erl, diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 0b3360947..9ecd3ebf5 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -273,15 +273,18 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> false -> [] end, + % XXX OLD FORMAT: Other_Feats. + Other_FeatsOld = ejabberd_hooks:run_fold( + c2s_stream_features, + Server, + [], []), + Other_Feats = [exmpp_xml:xmlelement_to_xmlel(F, [?DEFAULT_NS], ?PREFIXED_NS) || F <- Other_FeatsOld], send_element(StateData, exmpp_stream:features( TLSFeature ++ CompressFeature ++ SASL_Mechs ++ - ejabberd_hooks:run_fold( - c2s_stream_features, - Server, - [], []))), + Other_Feats)), fsm_next_state(wait_for_feature_request, StateData#state{ server = Server, From 7ca5bebab3e13832ee579150887ff94e96d1b53d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 9 Jul 2008 09:16:03 +0000 Subject: [PATCH 038/582] Convert to exmpp. SVN Revision: 1422 --- ChangeLog | 4 + src/ejabberd_auth.erl | 4 +- src/ejabberd_auth_anonymous.erl | 15 +- src/ejabberd_auth_internal.erl | 18 +-- src/ejabberd_auth_ldap.erl | 8 +- src/ejabberd_auth_odbc.erl | 263 +++++++++++++++++--------------- 6 files changed, 164 insertions(+), 148 deletions(-) diff --git a/ChangeLog b/ChangeLog index 726641487..15b69708f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,10 @@ * src/ejabberd_c2s.erl: Convert #xmlelement returned by the 'c2s_stream_features' hook to #xmlel. + * src/ejabberd_auth.erl, src/ejabberd_auth_internal.erl, + src/ejabberd_auth_odbc.erl, src/ejabberd_auth_ldap.erl, + src/ejabberd_auth_anonymous.erl: Convert to exmpp. + 2008-07-08 Jean-Sébastien Pédron * src/cyrsasl.erl, src/cyrsasl_anonymous.erl, src/cyrsasl_digest.erl, diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index d6a7e5228..358d44ae0 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -146,7 +146,7 @@ try_register(User, Server, Password) -> true -> {atomic, exists}; false -> - case lists:member(jlib:nameprep(Server), ?MYHOSTS) of + case lists:member(exmpp_stringprep:nameprep(Server), ?MYHOSTS) of true -> lists:foldl( fun(_M, {atomic, ok} = Res) -> @@ -286,7 +286,7 @@ auth_modules() -> %% Return the list of authenticated modules for a given host auth_modules(Server) -> - LServer = jlib:nameprep(Server), + LServer = exmpp_stringprep:nameprep(Server), Method = ejabberd_config:get_local_option({auth_method, LServer}), Methods = if Method == undefined -> []; diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index 3c5c58fed..8ba4d7336 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -122,8 +122,8 @@ allow_multiple_connections(Host) -> %% Check if user exist in the anonymus database anonymous_user_exist(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, case catch mnesia:dirty_read({anonymous, US}) of [] -> @@ -142,15 +142,16 @@ remove_connection(SID, LUser, LServer) -> %% Register connection register_connection(SID, #jid{luser = LUser, lserver = LServer}, Info) -> - AuthModule = xml:get_attr_s(auth_module, Info), - case AuthModule == ?MODULE of - true -> + case proplists:get_value(auth_module, Info) of + undefined -> + ok; + ?MODULE -> US = {LUser, LServer}, mnesia:sync_dirty( fun() -> mnesia:write(#anonymous{us = US, sid=SID}) end); - false -> - ok + _ -> + ok end. %% Remove an anonymous user from the anonymous users table diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index 315cc4620..71d9086d7 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -67,8 +67,8 @@ plain_password_required() -> false. check_password(User, Server, Password) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, case catch mnesia:dirty_read({passwd, US}) of [#passwd{password = Password}] -> @@ -78,8 +78,8 @@ check_password(User, Server, Password) -> end. check_password(User, Server, Password, StreamID, Digest) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, case catch mnesia:dirty_read({passwd, US}) of [#passwd{password = Passwd}] -> @@ -99,8 +99,8 @@ check_password(User, Server, Password, StreamID, Digest) -> end. set_password(User, Server, Password) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, if (LUser == error) or (LServer == error) -> @@ -114,8 +114,8 @@ set_password(User, Server, Password) -> end. try_register(User, Server, Password) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, if (LUser == error) or (LServer == error) -> @@ -139,7 +139,7 @@ dirty_get_registered_users() -> mnesia:dirty_all_keys(passwd). get_vh_registered_users(Server) -> - LServer = jlib:nameprep(Server), + LServer = exmpp_stringprep:nameprep(Server), mnesia:dirty_select( passwd, [{#passwd{us = '$1', _ = '_'}, diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl index e22be1bc9..d576a82fd 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -238,9 +238,11 @@ get_vh_registered_users_ldap(Server) -> {User, UIDFormat} -> case eldap_utils:get_user_part(User, UIDFormat) of {ok, U} -> - case jlib:nodeprep(U) of - error -> []; - LU -> [{LU, jlib:nameprep(Server)}] + try + [{exmpp_stringprep:nodeprep(U), exmpp_stringprep:nameprep(Server)}] + catch + _ -> + [] end; _ -> [] end diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index 14bd61b94..06ae695ea 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -62,71 +62,75 @@ plain_password_required() -> false. check_password(User, Server, Password) -> - case jlib:nodeprep(User) of - error -> - false; - LUser -> - Username = ejabberd_odbc:escape(LUser), - LServer = jlib:nameprep(Server), - case catch odbc_queries:get_password(LServer, Username) of - {selected, ["password"], [{Password}]} -> - Password /= ""; - _ -> - false - end + try + LUser = exmpp_stringprep:nodeprep(User), + Username = ejabberd_odbc:escape(LUser), + LServer = exmpp_stringprep:nameprep(Server), + case catch odbc_queries:get_password(LServer, Username) of + {selected, ["password"], [{Password}]} -> + Password /= ""; + _ -> + false + end + catch + _ -> + false end. check_password(User, Server, Password, StreamID, Digest) -> - case jlib:nodeprep(User) of - error -> - false; - LUser -> - Username = ejabberd_odbc:escape(LUser), - LServer = jlib:nameprep(Server), - case catch odbc_queries:get_password(LServer, Username) of - {selected, ["password"], [{Passwd}]} -> - DigRes = if - Digest /= "" -> - Digest == sha:sha(StreamID ++ Passwd); - true -> - false - end, - if DigRes -> - true; - true -> - (Passwd == Password) and (Password /= "") - end; - _ -> - false - end + try + LUser = exmpp_stringpre:nodeprep(User), + Username = ejabberd_odbc:escape(LUser), + LServer = exmpp_stringprep:nameprep(Server), + case catch odbc_queries:get_password(LServer, Username) of + {selected, ["password"], [{Passwd}]} -> + DigRes = if + Digest /= "" -> + Digest == sha:sha(StreamID ++ Passwd); + true -> + false + end, + if DigRes -> + true; + true -> + (Passwd == Password) and (Password /= "") + end; + _ -> + false + end + catch + _ -> + false end. set_password(User, Server, Password) -> - case jlib:nodeprep(User) of - error -> - {error, invalid_jid}; - LUser -> - Username = ejabberd_odbc:escape(LUser), - Pass = ejabberd_odbc:escape(Password), - LServer = jlib:nameprep(Server), - catch odbc_queries:set_password_t(LServer, Username, Pass) + try + LUser = exmpp_stringprep:nodeprep(User), + Username = ejabberd_odbc:escape(LUser), + Pass = ejabberd_odbc:escape(Password), + LServer = exmpp_stringprep:nameprep(Server), + catch odbc_queries:set_password_t(LServer, Username, Pass) + catch + _ -> + {error, invalid_jid} end. try_register(User, Server, Password) -> - case jlib:nodeprep(User) of - error -> - {error, invalid_jid}; - LUser -> - Username = ejabberd_odbc:escape(LUser), - Pass = ejabberd_odbc:escape(Password), - LServer = jlib:nameprep(Server), - case catch odbc_queries:add_user(LServer, Username, Pass) of - {updated, 1} -> - {atomic, ok}; - _ -> - {atomic, exists} - end + try + LUser = exmpp_stringprep:nodeprep(User), + Username = ejabberd_odbc:escape(LUser), + Pass = ejabberd_odbc:escape(Password), + LServer = exmpp_stringprep:nameprep(Server), + case catch odbc_queries:add_user(LServer, Username, Pass) of + {updated, 1} -> + {atomic, ok}; + _ -> + {atomic, exists} + end + catch + _ -> + {error, invalid_jid} end. dirty_get_registered_users() -> @@ -137,7 +141,7 @@ dirty_get_registered_users() -> end, Servers). get_vh_registered_users(Server) -> - LServer = jlib:nameprep(Server), + LServer = exmpp_stringprep:nameprep(Server), case catch odbc_queries:list_users(LServer) of {selected, ["username"], Res} -> [{U, LServer} || {U} <- Res]; @@ -146,7 +150,7 @@ get_vh_registered_users(Server) -> end. get_vh_registered_users(Server, Opts) -> - LServer = jlib:nameprep(Server), + LServer = exmpp_stringprep:nameprep(Server), case catch odbc_queries:list_users(LServer, Opts) of {selected, ["username"], Res} -> [{U, LServer} || {U} <- Res]; @@ -155,7 +159,7 @@ get_vh_registered_users(Server, Opts) -> end. get_vh_registered_users_number(Server) -> - LServer = jlib:nameprep(Server), + LServer = exmpp_stringprep:nameprep(Server), case catch odbc_queries:users_number(LServer) of {selected, [_], [{Res}]} -> list_to_integer(Res); @@ -164,7 +168,7 @@ get_vh_registered_users_number(Server) -> end. get_vh_registered_users_number(Server, Opts) -> - LServer = jlib:nameprep(Server), + LServer = exmpp_stringprep:nameprep(Server), case catch odbc_queries:users_number(LServer, Opts) of {selected, [_], [{Res}]} -> list_to_integer(Res); @@ -173,84 +177,89 @@ get_vh_registered_users_number(Server, Opts) -> end. get_password(User, Server) -> - case jlib:nodeprep(User) of - error -> - false; - LUser -> - Username = ejabberd_odbc:escape(LUser), - LServer = jlib:nameprep(Server), - case catch odbc_queries:get_password(LServer, Username) of - {selected, ["password"], [{Password}]} -> - Password; - _ -> - false - end + try + LUser = exmpp_stringprep:nodeprep(User), + Username = ejabberd_odbc:escape(LUser), + LServer = exmpp_stringprep:nameprep(Server), + case catch odbc_queries:get_password(LServer, Username) of + {selected, ["password"], [{Password}]} -> + Password; + _ -> + false + end + catch + _ -> + false end. get_password_s(User, Server) -> - case jlib:nodeprep(User) of - error -> - ""; - LUser -> - Username = ejabberd_odbc:escape(LUser), - LServer = jlib:nameprep(Server), - case catch odbc_queries:get_password(LServer, Username) of - {selected, ["password"], [{Password}]} -> - Password; - _ -> - "" - end + try + LUser = exmpp_stringprep:nodeprep(User), + Username = ejabberd_odbc:escape(LUser), + LServer = exmpp_stringprep:nameprep(Server), + case catch odbc_queries:get_password(LServer, Username) of + {selected, ["password"], [{Password}]} -> + Password; + _ -> + "" + end + catch + _ -> + "" end. is_user_exists(User, Server) -> - case jlib:nodeprep(User) of - error -> - false; - LUser -> - Username = ejabberd_odbc:escape(LUser), - LServer = jlib:nameprep(Server), - case catch odbc_queries:get_password(LServer, Username) of - {selected, ["password"], [{_Password}]} -> - true; - _ -> - false - end + try + LUser = exmpp_stringprep:nodeprep(User), + Username = ejabberd_odbc:escape(LUser), + LServer = exmpp_stringprep:nameprep(Server), + case catch odbc_queries:get_password(LServer, Username) of + {selected, ["password"], [{_Password}]} -> + true; + _ -> + false + end + catch + _ -> + false end. remove_user(User, Server) -> - case jlib:nodeprep(User) of - error -> - error; - LUser -> - Username = ejabberd_odbc:escape(LUser), - LServer = jlib:nameprep(Server), - catch odbc_queries:del_user(LServer, Username), - ejabberd_hooks:run(remove_user, jlib:nameprep(Server), - [User, Server]) + try + LUser = exmpp_stringprep:nodeprep(User), + Username = ejabberd_odbc:escape(LUser), + LServer = exmpp_stringprep:nameprep(Server), + catch odbc_queries:del_user(LServer, Username), + ejabberd_hooks:run(remove_user, exmpp_stringprep:nameprep(Server), + [User, Server]) + catch + _ -> + error end. remove_user(User, Server, Password) -> - case jlib:nodeprep(User) of - error -> - error; - LUser -> - Username = ejabberd_odbc:escape(LUser), - Pass = ejabberd_odbc:escape(Password), - LServer = jlib:nameprep(Server), - F = fun() -> - Result = odbc_queries:del_user_return_password( - LServer, Username, Pass), - case Result of - {selected, ["password"], [{Password}]} -> - ejabberd_hooks:run(remove_user, jlib:nameprep(Server), - [User, Server]), - ok; - {selected, ["password"], []} -> - not_exists; - _ -> - not_allowed - end - end, - {atomic, Result} = odbc_queries:sql_transaction(LServer, F), - Result + try + LUser = exmpp_stringprep:nodeprep(User), + Username = ejabberd_odbc:escape(LUser), + Pass = ejabberd_odbc:escape(Password), + LServer = exmpp_stringprep:nameprep(Server), + F = fun() -> + Result = odbc_queries:del_user_return_password( + LServer, Username, Pass), + case Result of + {selected, ["password"], [{Password}]} -> + ejabberd_hooks:run(remove_user, exmpp_stringprep:nameprep(Server), + [User, Server]), + ok; + {selected, ["password"], []} -> + not_exists; + _ -> + not_allowed + end + end, + {atomic, Result} = odbc_queries:sql_transaction(LServer, F), + Result + catch + _ -> + error end. From 8bfccb42a95ebfa1e46158855c787342096f13d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 11 Jul 2008 12:40:49 +0000 Subject: [PATCH 039/582] Exmpp now takes care of stanza serialization and compatible namespaces. SVN Revision: 1433 --- ChangeLog | 6 ++++++ src/ejabberd_c2s.erl | 4 +--- src/ejabberd_s2s_in.erl | 6 +----- src/ejabberd_s2s_out.erl | 6 +----- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index 15b69708f..8ed38c6f3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-07-11 Jean-Sébastien Pédron + + * src/ejabberd_s2s_in.erl, src/ejabberd_s2s_out.erl, + src/ejabberd_c2s.erl: Exmpp now takes care of stanza serialization and + compatible namespaces. + 2008-07-09 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Convert #xmlelement returned by the diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 9ecd3ebf5..dae88f07a 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1305,10 +1305,8 @@ send_text(StateData, Text) -> send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> send_text(StateData, exmpp_stream:to_list(El)); -send_element(StateData, #xmlel{ns = ?NS_JABBER_SERVER} = El) -> - send_text(StateData, exmpp_stanza:to_list(El, ?NS_JABBER_SERVER)); send_element(StateData, El) -> - send_text(StateData, exmpp_stanza:to_list(El, ?DEFAULT_NS)). + send_text(StateData, exmpp_stanza:to_list(El)). new_id() -> diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 562033076..c0c863c1e 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -564,12 +564,8 @@ send_text(StateData, Text) -> send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> send_text(StateData, exmpp_stream:to_list(El)); -send_element(StateData, #xmlel{ns = ?NS_JABBER_CLIENT} = El) -> - send_text(StateData, exmpp_stanza:to_list(El, - ?NS_JABBER_CLIENT, ?PREFIXED_NS)); send_element(StateData, El) -> - send_text(StateData, exmpp_stanza:to_list(El, - ?DEFAULT_NS, ?PREFIXED_NS)). + send_text(StateData, exmpp_stanza:to_list(El)). change_shaper(StateData, Host, JID) -> diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 93171ced3..baa5d23f5 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -790,12 +790,8 @@ send_text(StateData, Text) -> send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> send_text(StateData, exmpp_stream:to_list(El)); -send_element(StateData, #xmlel{ns = ?NS_JABBER_CLIENT} = El) -> - send_text(StateData, exmpp_stanza:to_list(El, - ?NS_JABBER_CLIENT, ?PREFIXED_NS)); send_element(StateData, El) -> - send_text(StateData, exmpp_stanza:to_list(El, - ?DEFAULT_NS, ?PREFIXED_NS)). + send_text(StateData, exmpp_stanza:to_list(El)). send_queue(StateData, Q) -> case queue:out(Q) of From 5610d00b4dcc0aa5b77e40c915dd3829f5074c32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 11 Jul 2008 12:41:48 +0000 Subject: [PATCH 040/582] Convert to exmpp. Note that this module hasn't been tested yet! SVN Revision: 1434 --- ChangeLog | 3 + src/ejabberd_service.erl | 130 +++++++++++++++++++-------------------- 2 files changed, 66 insertions(+), 67 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8ed38c6f3..cd04540e4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,9 @@ src/ejabberd_c2s.erl: Exmpp now takes care of stanza serialization and compatible namespaces. + * src/ejabberd_service.erl: Convert to exmpp. Note that this module + hasn't been tested yet! + 2008-07-09 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Convert #xmlelement returned by the diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 351743ae0..b6a977ce6 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -47,8 +47,9 @@ handle_info/3, terminate/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -record(state, {socket, sockmod, streamid, hosts, password, access, @@ -62,31 +63,10 @@ -define(FSMOPTS, []). -endif. --define(STREAM_HEADER, - "" - "" - ). - --define(STREAM_TRAILER, ""). - --define(INVALID_HEADER_ERR, - "" - "Invalid Stream Header" - "" - ). - --define(INVALID_HANDSHAKE_ERR, - "Invalid Handshake" - "" - ). - --define(INVALID_XML_ERR, - xml:element_to_string(?SERR_XML_NOT_WELL_FORMED)). --define(INVALID_NS_ERR, - xml:element_to_string(?SERR_INVALID_NAMESPACE)). +% These are the namespace already declared by the stream opening. This is +% used at serialization time. +-define(DEFAULT_NS, ?NS_COMPONENT_ACCEPT). +-define(PREFIXED_NS, [{?NS_XMPP, ?NS_XMPP_pfx}]). %%%---------------------------------------------------------------------- %%% API @@ -167,24 +147,32 @@ init([{SockMod, Socket}, Opts]) -> %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- -wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) -> +wait_for_stream({xmlstreamstart, #xmlel{ns = NS}}, StateData) -> % TODO - case xml:get_attr_s("xmlns", Attrs) of - "jabber:component:accept" -> - Header = io_lib:format(?STREAM_HEADER, - [StateData#state.streamid, ?MYNAME]), - send_text(StateData, Header), + case NS of + ?NS_COMPONENT_ACCEPT -> + Opening_Reply = exmpp_stream:opening_reply(?MYNAME, + ?NS_COMPONENT_ACCEPT, + {0, 0}, StateData#state.streamid), + send_element(StateData, Opening_Reply), {next_state, wait_for_handshake, StateData}; _ -> - send_text(StateData, ?INVALID_HEADER_ERR), + Error = #xmlel{ns = ?NS_XMPP, name = 'stream', children = [ + #xmlel{ns = ?NS_XMPP, name = 'error', children = [ + #xmlcdata{cdata = <<"Invalid Stream Header">>} + ]} + ]}, + send_element(StateData, Error), {stop, normal, StateData} end; wait_for_stream({xmlstreamerror, _}, StateData) -> - Header = io_lib:format(?STREAM_HEADER, - ["none", ?MYNAME]), - send_text(StateData, - Header ++ ?INVALID_XML_ERR ++ ?STREAM_TRAILER), + Opening_Reply = exmpp_stream:opening_reply(?MYNAME, + ?NS_COMPONENT_ACCEPT, + {0, 0}, "none"), + send_element(StateData, Opening_Reply), + send_element(StateData, exmpp_stream:error('xml-not-well-formed')), + send_element(StateData, exmpp_stream:closing()), {stop, normal, StateData}; wait_for_stream(closed, StateData) -> @@ -192,13 +180,13 @@ wait_for_stream(closed, StateData) -> wait_for_handshake({xmlstreamelement, El}, StateData) -> - {xmlelement, Name, _Attrs, Els} = El, - case {Name, xml:get_cdata(Els)} of - {"handshake", Digest} -> + case {El#xmlel.name, exmpp_xml:get_cdata(El)} of + {'handshake', Digest} -> case sha:sha(StateData#state.streamid ++ StateData#state.password) of Digest -> - send_text(StateData, ""), + send_element(StateData, + #xmlel{ns = ?NS_COMPONENT_ACCEPT, name = 'handshake'}), lists:foreach( fun(H) -> ejabberd_router:register_route(H), @@ -206,7 +194,10 @@ wait_for_handshake({xmlstreamelement, El}, StateData) -> end, StateData#state.hosts), {next_state, stream_established, StateData}; _ -> - send_text(StateData, ?INVALID_HANDSHAKE_ERR), + send_element(StateData, + #xmlel{ns = ?NS_XMPP, name = 'error', children = [ + #xmlcdata{cdata = <<"Invalid Handshake">>}]}), + send_element(StateData, exmpp_stream:closing()), {stop, normal, StateData} end; _ -> @@ -217,7 +208,8 @@ wait_for_handshake({xmlstreamend, _Name}, StateData) -> {stop, normal, StateData}; wait_for_handshake({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}; wait_for_handshake(closed, StateData) -> @@ -225,20 +217,18 @@ wait_for_handshake(closed, StateData) -> stream_established({xmlstreamelement, El}, StateData) -> - NewEl = jlib:remove_attr("xmlns", El), - {xmlelement, Name, Attrs, _Els} = NewEl, - From = xml:get_attr_s("from", Attrs), + From = exmpp_stanza:get_sender(El), FromJID = case StateData#state.check_from of %% If the admin does not want to check the from field %% when accept packets from any address. %% In this case, the component can send packet of %% behalf of the server users. - false -> jlib:string_to_jid(From); + false -> exmpp_jid:string_to_jid(From); %% The default is the standard behaviour in XEP-0114 _ -> - FromJID1 = jlib:string_to_jid(From), + FromJID1 = exmpp_jib:string_to_jid(From), case FromJID1 of - #jid{lserver = Server} -> + #jid{ldomain = Server} -> case lists:member(Server, StateData#state.hosts) of true -> FromJID1; false -> error @@ -246,18 +236,18 @@ stream_established({xmlstreamelement, El}, StateData) -> _ -> error end end, - To = xml:get_attr_s("to", Attrs), + To = exmpp_stanza:get_recipient(El), ToJID = case To of - "" -> error; - _ -> jlib:string_to_jid(To) + undefined -> error; + _ -> exmpp_jib:string_to_jid(To) end, - if ((Name == "iq") or - (Name == "message") or - (Name == "presence")) and + if ((El#xmlel.name == 'iq') or + (El#xmlel.name == 'message') or + (El#xmlel.name == 'presence')) and (ToJID /= error) and (FromJID /= error) -> - ejabberd_router:route(FromJID, ToJID, NewEl); + ejabberd_router:route(FromJID, ToJID, El); true -> - Err = jlib:make_error_reply(NewEl, ?ERR_BAD_REQUEST), + Err = exmpp_stanza:reply_with_error(El, 'bad-request'), send_element(StateData, Err), error end, @@ -268,7 +258,8 @@ stream_established({xmlstreamend, _Name}, StateData) -> {stop, normal, StateData}; stream_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}; stream_established(closed, StateData) -> @@ -322,22 +313,25 @@ code_change(_OldVsn, StateName, StateData, _Extra) -> %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- handle_info({send_text, Text}, StateName, StateData) -> + % XXX OLD FORMAT: This clause should be removed. send_text(StateData, Text), {next_state, StateName, StateData}; handle_info({send_element, El}, StateName, StateData) -> send_element(StateData, El), {next_state, StateName, StateData}; -handle_info({route, From, To, Packet}, StateName, StateData) -> +handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> + %% XXX OLD FORMAT: From, To and Packet are in the old format. + Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, + [?NS_JABBER_CLIENT], ?PREFIXED_NS), + From = jlib:from_old_jid(FromOld), + To = jlib:from_old_jid(ToOld), case acl:match_rule(global, StateData#state.access, From) of allow -> - {xmlelement, Name, Attrs, Els} = Packet, - Attrs2 = jlib:replace_from_to_attrs(jlib:jid_to_string(From), - jlib:jid_to_string(To), - Attrs), - Text = xml:element_to_string({xmlelement, Name, Attrs2, Els}), - send_text(StateData, Text); + El1 = exmpp_stanza:set_sender(Packet, From), + El2 = exmpp_stanza:set_recipient(El1, To), + send_element(StateData, El2); deny -> - Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED), + Err = exmpp_stanza:reply_with_error(Packet, 'not-allowed'), ejabberd_router:route(To, From, Err) end, {next_state, StateName, StateData}. @@ -369,8 +363,10 @@ terminate(Reason, StateName, StateData) -> send_text(StateData, Text) -> (StateData#state.sockmod):send(StateData#state.socket, Text). +send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> + send_text(StateData, exmpp_stream:to_list(El)); send_element(StateData, El) -> - send_text(StateData, xml:element_to_string(El)). + send_text(StateData, exmpp_stanza:to_list(El)). new_id() -> randoms:get_string(). From 332fb55e3abcce272d7ba2b0c32e363b57a0979b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 11 Jul 2008 12:48:27 +0000 Subject: [PATCH 041/582] MFC: Merge revisions from 1362 to revision 1434 from trunk. SVN Revision: 1435 --- ChangeLog | 138 ++++++++++- doc/guide.html | 360 ++++++++++++++++------------- doc/guide.tex | 74 +++++- src/Makefile.in | 6 +- src/configure | 3 + src/configure.ac | 3 + src/ejabberd.cfg.example | 2 +- src/ejabberd_c2s.erl | 3 + src/ejabberd_config.erl | 6 +- src/ejabberd_ctl.erl | 1 + src/ejabberd_local.erl | 7 + src/ejabberd_receiver.erl | 6 +- src/ejabberd_sm.erl | 15 +- src/mod_caps.erl | 12 + src/mod_configure.erl | 2 +- src/mod_muc/mod_muc_log.erl | 19 +- src/mod_muc/mod_muc_room.erl | 13 +- src/mod_privacy_odbc.erl | 25 +- src/mod_pubsub/gen_pubsub_node.erl | 2 + src/mod_pubsub/mod_pubsub.erl | 109 ++++++--- src/mod_pubsub/node.template | 9 +- src/mod_pubsub/node_buddy.erl | 8 + src/mod_pubsub/node_club.erl | 9 +- src/mod_pubsub/node_default.erl | 116 ++++++++-- src/mod_pubsub/node_dispatch.erl | 9 +- src/mod_pubsub/node_pep.erl | 35 ++- src/mod_pubsub/node_private.erl | 9 +- src/mod_pubsub/node_public.erl | 9 +- src/mod_pubsub/node_zoo.erl | 181 +++++++++++++++ src/mod_register.erl | 3 +- src/mod_roster.erl | 1 + src/mod_shared_roster.erl | 88 ++++++- src/web/ejabberd_http.erl | 27 ++- src/web/ejabberd_http_poll.erl | 38 ++- src/web/ejabberd_web_admin.erl | 2 +- tools/ejabberdctl | 3 +- 36 files changed, 1055 insertions(+), 298 deletions(-) create mode 100644 src/mod_pubsub/node_zoo.erl diff --git a/ChangeLog b/ChangeLog index cd04540e4..72fe05cb9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2008-07-11 Jean-Sébastien Pédron + + Merge revisions from 1362 to revision 1434 from trunk. + 2008-07-11 Jean-Sébastien Pédron * src/ejabberd_s2s_in.erl, src/ejabberd_s2s_out.erl, @@ -7,6 +11,11 @@ * src/ejabberd_service.erl: Convert to exmpp. Note that this module hasn't been tested yet! +2008-07-10 Badlop + + * src/configure.ac: Don't check for erlang header file (EJAB-232) + * src/configure: Likewise + 2008-07-09 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Convert #xmlelement returned by the @@ -16,12 +25,99 @@ src/ejabberd_auth_odbc.erl, src/ejabberd_auth_ldap.erl, src/ejabberd_auth_anonymous.erl: Convert to exmpp. +2008-07-09 Badlop + + * src/configure.ac: Check for erlang header files (EJAB-232) + * src/configure: Likewise + + * src/mod_pubsub/mod_pubsub.erl: Fix compilation warnings + * src/mod_pubsub/node_zoo.erl: Likewise + + * src/mod_shared_roster.erl: Allow to get subscribed to a contact + that is already in the roster by means of a shared roster group: + add it to another roster group and it gets subscribed + automatically (EJAB-407) + + * src/mod_roster.erl: Likewise + + * src/mod_muc/mod_muc_log.erl: Fix XHTML compliance: ensure some + language is set, include ID attribute in each message, add + microseconds to ensure unique value (EJAB-497) + + * src/mod_register.erl: Support for io_lib newline character in + the body of welcome_message (EJAB-501) + * doc/guide.tex: Document the newline character + * src/ejabberd.cfg.example: Example usage of newline character + + * src/ejabberd_config.erl (load_file): error message on sasl.log + is not flattened (EJAB-616) + + * doc/guide.tex: mod_muc_log XMPP URI supports the updated version + RFC 5122 (EJAB-631) + * doc/guide.html: Likewise + 2008-07-08 Jean-Sébastien Pédron * src/cyrsasl.erl, src/cyrsasl_anonymous.erl, src/cyrsasl_digest.erl, src/cyrsasl_plain.erl, src/ejabberd_c2s.erl: Errors are now atoms, not strings anymore. +2008-07-08 Badlop + + * tools/ejabberdctl: Work also when 'which' is unavailable + +2008-07-08 Christophe Romain + + * src/web/ejabberd_http_poll.erl: improve ip fetching patch + +2008-07-07 Badlop + + * src/Makefile.in: Spool, config and log dirs: writtable by owner, + readable by group, nothing by others (EJAB-686) + * doc/guide.tex: New section Securing sensible files + * doc/guide.html: Likewise + + * doc/guide.tex: Solaris Makefile install: use ginstall (thanks to + Jonathan Auer)(EJAB-649) + * doc/guide.html: Likewise + +2008-07-03 Jerome Sautret + + * src/mod_privacy_odbc.erl: Support for privacy lists in MySQL + (thanks to Igor Goryachev)(EJAB-538) + +2008-07-03 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: Fix permission control on item + retrieve (EJAB-453) + * src/mod_pubsub/node_dispatch.erl: Likewise + * src/mod_pubsub/node_buddy.erl: Likewise + * src/mod_pubsub/node_private.erl: Likewise + * src/mod_pubsub/node_public.erl: Likewise + * src/mod_pubsub/node_default.erl: Likewise + * src/mod_pubsub/node_pep.erl: Likewise + * src/mod_pubsub/node_club.erl: Likewise + * src/mod_pubsub/gen_pubsub_node.erl: Likewise + * src/mod_pubsub/node.template: Likewise + + * src/mod_pubsub/mod_pubsub.erl: Allow subscriber to request specific + items by ItemID; Allow to retrieve pubsub#title configuration (thanks + to Kevin Crosbie); Fix forbidden result on setting + affiliation/subscription + + * src/mod_pubsub/node_zoo.erl: Add node type without + home// constraint + + * src/ejabberd_local.erl: prevent iq_response table overload + (EJAB-608) + * src/mod_caps.erl: Likewise + + * src/web/ejabberd_http.erl: Retrieve correct IP from http connection + * src/web/ejabberd_http_poll.erl: Likewise + * src/ejabberd_receiver.erl: Likewise + * src/ejabberd_sm.erl: Likewise + * src/ejabberd_c2s.erl: Likewise + 2008-07-01 Jean-Sébastien Pédron * src/ejabberd_sm.erl: Convert to exmpp. @@ -100,6 +196,19 @@ src/ejabberd_s2s_out.erl: No conversion is done before calling ejabberd_router:route/3. +2008-06-29 Badlop + + * src/ejabberd_ctl.erl: Web Admin and Ad-hoc admin: dump only + persistent tables (EJAB-678) + + * src/mod_pubsub/node_pep.erl: Complain if mod_caps disabled and + mod_pubsub has PEP plugin enabled (EJAB-677) + +2008-06-28 Badlop + + * src/mod_muc/mod_muc_room.erl: Allow to store room + description (thanks to Christopher Dupont)(EJAB-670) + 2008-06-27 Jean-Sébastien Pédron * src/ejabberd_c2s.erl, src/ejabberd_s2s_out.erl, @@ -150,6 +259,15 @@ expected form outside of the C2S (empty fields must be set to the empty string). This fixes the broken routing. +2008-06-21 Badlop + + * src/web/ejabberd_http.erl: Support PUT and DELETE methods in + ejabberd_http (thanks to Eric Cestari)(EJAB-662) + + * doc/guide.tex: Explain that S2S outgoing first tries IPv4 and if + that fails then tries IPv6 + * doc/guide.html: Likewise + 2008-06-20 Jean-Sébastien Pédron * src/configure, src/aclocal.m4, src/Makefile.in: Add exmpp detection. @@ -271,7 +389,7 @@ 2008-05-19 Mickael Remond * src/ejabberd_s2s_out.erl: Avoid an harmless error (function clause in - logs) + logs) 2008-05-17 Badlop @@ -344,11 +462,11 @@ being immediately shown in an 'all' special shared roster group (thanks to Alexey Shchepin) (EJAB-71) * src/mod_register.erl: New vhost event user_registered - + * doc/guide.tex: Document option registration_timeout (EJAB-614) 2008-04-25 Badlop - + * src/ejabberd_c2s.erl: Added forbidden_session_hook * src/acl.erl: New access types: resource, resource_regexp and @@ -506,7 +624,7 @@ * doc/webadmmainru.png: Likewise * doc/disco.png: Removed because not used - + * doc/guide.tex: Fix Latex reference to webadmin section. Update explanation of screenshots. Update xmpp addresses of Mickael Remond and Sander Devrieze. @@ -619,7 +737,7 @@ * src/eldap.erl: Faster LDAP reconnection (Thanks to Christophe Romain) (EJAB-581) - + 2008-03-17 Mickael Remond * src/ejabberd_s2s.erl: Only trigger s2s_connect_hook on @@ -630,7 +748,7 @@ * src/ejabberd_ctl.erl: API improvement: Added reopen_log_hook (EJAB-565) - + * src/ejabberd_s2s.erl: API improvement: Added s2s_connect_hook (EJAB-566). @@ -722,7 +840,7 @@ configuration sanity checks (EJAB-533) * src/src/ejabberd_app.erl: Likewise * src/ejabberd_app.erl: Likewise - + 2008-02-26 Badlop * src/msgs/it.msg: Updated (thanks to Smart2128) @@ -858,7 +976,7 @@ * src/mod_pubsub/node_pep.erl: Likewise * src/mod_pubsub/node_private.erl: Likewise * src/mod_pubsub/node.template: Likewise - + * src/mod_pubsub/gen_pubsub_node.erl: API improvement: Added a way to generate custom item name * src/mod_pubsub/node_dispatch.erl: Likewise @@ -895,7 +1013,7 @@ * src/mod_pubsub/gen_pubsub_nodetree.erl: Likewise * src/mod_pubsub/nodetree_default.erl: Likewise * src/mod_pubsub/nodetree_virtual.erl: Likewise - + 2008-01-30 Badlop * doc/guide.tex: Removed the option served_hosts in mod_pubsub @@ -960,7 +1078,7 @@ * src/ejabberd.hrl: Likewise * doc/introduction.tex: Updated to 22 languages - + * doc/Makefile: Ensure that Bash is used * doc/guide.tex: Updated copyright dates to 2008. diff --git a/doc/guide.html b/doc/guide.html index b94c65959..b7f10839b 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -106,105 +106,107 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}
  • 2.4.4  Install
  • 2.4.5  Start
  • 2.4.6  Specific Notes for BSD -
  • 2.4.7  Specific Notes for Microsoft Windows +
  • 2.4.7  Specific Notes for Sun Solaris +
  • 2.4.8  Specific Notes for Microsoft Windows
  • -
  • 2.5  Create a Jabber Account for Administration -
  • 2.6  Upgrading ejabberd +
  • 2.5  Create a Jabber Account for Administration +
  • 2.6  Upgrading ejabberd
  • -
  • Chapter 3  Configuring ejabberd +
  • Chapter 3  Configuring ejabberd -
  • Chapter 4  Managing an ejabberd server +
  • Chapter 4  Managing an ejabberd server -
  • Chapter 5  Securing ejabberd +
  • Chapter 5  Securing ejabberd -
  • Chapter 6  Clustering +
  • Chapter 6  Clustering -
  • Chapter 7  Debugging +
  • Chapter 7  Debugging -
  • Appendix A  Internationalization and Localization -
  • Appendix B  Release Notes -
  • Appendix C  Acknowledgements -
  • Appendix D  Copyright Information +
  • Appendix A  Internationalization and Localization +
  • Appendix B  Release Notes +
  • Appendix C  Acknowledgements +
  • Appendix D  Copyright Information
  • Chapter 1  Introduction

    ejabberd is a free and open source instant messaging server written in Erlang.

    ejabberd is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.

    ejabberd is designed to be a rock-solid and feature rich XMPP server.

    ejabberd is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.

    @@ -360,7 +362,7 @@ To get the full list run the command:
    /sbin/ejabberdctl
    Administration script
    /var/lib/ejabberd/
    - .erlang.cookie
    Erlang cookie file + .erlang.cookie
    Erlang cookie file (see section 5.3)
    db
    Mnesia database spool files
    ebin
    Binary Erlang files (*.beam)
    priv
    @@ -389,8 +391,23 @@ and configurable options to fine tune the Erlang runtime system.

    2.4.6  Specific Notes for BSD

    The command to compile ejabberd in BSD systems is:

    gmake
    +

    +

    2.4.7  Specific Notes for Sun Solaris

    +

    You need to have GNU install, +but it isn’t included in Solaris. +It can be easily installed if your Solaris system +is set up for blastwave.org +package repository. +Make sure /opt/csw/bin is in your PATH and run: +

    pkg-get -i fileutils
    +

    If that program is called ginstall, +modify the ejabberd Makefile script to suit your system, +for example: +

    cat Makefile | sed s/install/ginstall/ > Makefile.gi
    +

    And finally install ejabberd with: +

    gmake -f Makefile.gi ginstall
     

    -

    2.4.7  Specific Notes for Microsoft Windows

    +

    2.4.8  Specific Notes for Microsoft Windows

    Requirements

    To compile ejabberd on a Microsoft Windows system, you need:

    • @@ -428,7 +445,7 @@ nmake -f Makefile.win32
    • Edit the file ejabberd\src\ejabberd.cfg and run
      werl -s ejabberd -name ejabberd
       
    • -

      2.5  Create a Jabber Account for Administration

      You need a Jabber account and grant him administrative privileges +

      2.5  Create a Jabber Account for Administration

      You need a Jabber account and grant him administrative privileges to enter the ejabberd Web Admin:

      1. Register a Jabber account on your ejabberd server, for example admin1@example.org. @@ -449,16 +466,16 @@ favourite browser. Make sure to enter the full JID as username (in this example: admin1@example.org. The reason that you also need to enter the suffix, is because ejabberd’s virtual hosting support.

      -

      2.6  Upgrading ejabberd

      To upgrade an ejabberd installation to a new version, +

      2.6  Upgrading ejabberd

      To upgrade an ejabberd installation to a new version, simply uninstall the old version, and then install the new one. Of course, it is important that the configuration file and Mnesia database spool directory are not removed.

      ejabberd automatically updates the Mnesia table definitions at startup when needed. If you also use an external database for storage of some modules, check if the release notes of the new ejabberd version indicates you need to also update those tables.

      -

      Chapter 3  Configuring ejabberd

      +

      Chapter 3  Configuring ejabberd

      -

      3.1  Basic Configuration

      The configuration file will be loaded the first time you start ejabberd. The +

      3.1  Basic Configuration

      The configuration file will be loaded the first time you start ejabberd. The content from this file will be parsed and stored in the internal ejabberd database. Subsequently the configuration will be loaded from the database and any commands in the configuration file are appended to the entries in the database.

      Note that ejabberd never edits the configuration file. @@ -477,7 +494,7 @@ override_acls.

      With these lines the old global options (shared between all ejabberd nodes in a cluster), local options (which are specific for this particular ejabberd node) and ACLs will be removed before new ones are added.

      -

      3.1.1  Host Names

      +

      3.1.1  Host Names

      The option hosts defines a list containing one or more domains that ejabberd will serve.

      Examples:

      • @@ -489,7 +506,7 @@ versions:
      • Serving two domains:
        {hosts, ["example.net", "example.com"]}.
         

      -

      3.1.2  Virtual Hosting

      +

      3.1.2  Virtual Hosting

      Options can be defined separately for every virtual host using the host_config option. It has the following syntax: @@ -561,7 +578,7 @@ other different modules for some specific virtual hosts: } ]}.

      -

      3.1.3  Listening Ports

      +

      3.1.3  Listening Ports

      The option listen defines for which addresses and ports ejabberd will listen and what services will be run on them. Each element of the list is a tuple with the following elements: @@ -623,7 +640,10 @@ do not allow outgoing sockets on port 5222.

      If HTTP Polling is enabled, it wil is also needed in the Jabber client. Remark also that HTTP Polling can be interesting to host a web-based Jabber client such as JWChat. -

    inet6
    Set up the socket for IPv6. +

    inet6
    Set up the socket for IPv6 instead of IPv4. +Note: this option is not required for S2S outgoing connections, +because when ejabberd attempts to establish a S2S outgoing connection +it first tries IPv4, and if that fails it attempts with IPv6.
    {ip, IPAddress}
    This option specifies which network interface to listen for. For example {ip, {192, 168, 1, 1}}.
    {max_stanza_size, Size}
    @@ -832,7 +852,7 @@ services you have to make the transports log and do XDB by themselves: </xdb_file> </xdb>

    -

    3.1.4  Authentication

    +

    3.1.4  Authentication

    The option auth_method defines the authentication method that is used for user authentication:

    {auth_method, [<method>]}.
    @@ -941,7 +961,7 @@ attacks.
     
  • You may want to allow login access only for certain users. pam_listfile.so module provides such functionality.
  • -

    3.1.5  Access Rules

    +

    3.1.5  Access Rules

    ACL Definition

    Access control in ejabberd is performed via Access Control Lists (ACLs). The @@ -1048,7 +1068,7 @@ There’s also available the access max_s2s_connections_per_node.< Allow up to 3 connections with each remote server:

    {access, max_s2s_connections, [{3, all}]}.
     

    -

    3.1.6  Shapers

    +

    3.1.6  Shapers

    Shapers enable you to limit connection traffic. The syntax of shapers is like this:

    {shaper, <shapername>, <kind>}.
    @@ -1067,7 +1087,7 @@ To define a shaper named ‘normal’ with traffic speed limi
     50,000 bytes/second:
     
    {shaper, fast, {maxrate, 50000}}.
     

    -

    3.1.7  Default Language

    +

    3.1.7  Default Language

    The option language defines the default language of server strings that can be seen by Jabber clients. If a Jabber client do not support xml:lang, the specified language is used. The default value is @@ -1079,7 +1099,7 @@ To set Russian as default language:

  • To set Spanish as default language:
    {language, "es"}.
     
  • -

    3.1.8  Include Additional Configuration Files

    +

    3.1.8  Include Additional Configuration Files

    The option include_config_file in a configuration file instructs ejabberd to include other configuration files immediately.

    The basic usage is:

    {include_config_file, <filename>}.
     

    It is also possible to specify suboptions: @@ -1110,7 +1130,7 @@ and later includes another file with additional rules:

    {acl, admin, {user, "bob", "localhost"}}.
     {acl, admin, {user, "jan", "localhost"}}.
     

    -

    3.1.9  Option Macros in Configuration File

    +

    3.1.9  Option Macros in Configuration File

    In the ejabberd configuration file, it is possible to define a macro for a value and later use this macro when defining an option.

    A macro is defined with this syntax: @@ -1159,7 +1179,7 @@ This usage behaves as if it were defined and used this way: ] }.

    -

    3.2  Database and LDAP Configuration

    +

    3.2  Database and LDAP Configuration

    ejabberd uses its internal Mnesia database by default. However, it is possible to use a relational database or an LDAP server to store persistent, @@ -1181,7 +1201,7 @@ different storage systems for modules, and so forth.

    The following databas

  • Normally any LDAP compatible server should work; inform us about your success with a not-listed server so that we can list it here.
  • -

    3.2.1  MySQL

    +

    3.2.1  MySQL

    Although this section will describe ejabberd’s configuration when you want to use the native MySQL driver, it does not describe MySQL’s installation and database creation. Check the MySQL documentation and the tutorial Using ejabberd with MySQL native driver for information regarding these topics. @@ -1237,7 +1257,7 @@ relational databases like MySQL. To enable storage to your database, just make sure that your database is running well (see previous sections), and replace the suffix-less or ldap module variant with the odbc module variant. Keep in mind that you cannot have several variants of the same module loaded!

    -

    3.2.2  Microsoft SQL Server

    +

    3.2.2  Microsoft SQL Server

    Although this section will describe ejabberd’s configuration when you want to use Microsoft SQL Server, it does not describe Microsoft SQL Server’s installation and database creation. Check the MySQL documentation and the @@ -1273,7 +1293,7 @@ database, just make sure that your database is running well (see previous sections), and replace the suffix-less or ldap module variant with the odbc module variant. Keep in mind that you cannot have several variants of the same module loaded!

    -

    3.2.3  PostgreSQL

    +

    3.2.3  PostgreSQL

    Although this section will describe ejabberd’s configuration when you want to use the native PostgreSQL driver, it does not describe PostgreSQL’s installation and database creation. Check the PostgreSQL documentation and the tutorial Using ejabberd with MySQL native driver for information regarding these topics. @@ -1332,7 +1352,7 @@ relational databases like PostgreSQL. To enable storage to your database, just make sure that your database is running well (see previous sections), and replace the suffix-less or ldap module variant with the odbc module variant. Keep in mind that you cannot have several variants of the same module loaded!

    -

    3.2.4  ODBC Compatible

    +

    3.2.4  ODBC Compatible

    Although this section will describe ejabberd’s configuration when you want to use the ODBC driver, it does not describe the installation and database creation of your database. Check the documentation of your database. The tutorial Using ejabberd with MySQL native driver also can help you. Note that the tutorial @@ -1375,7 +1395,7 @@ database, just make sure that your database is running well (see previous sections), and replace the suffix-less or ldap module variant with the odbc module variant. Keep in mind that you cannot have several variants of the same module loaded!

    -

    3.2.5  LDAP

    +

    3.2.5  LDAP

    ejabberd has built-in LDAP support. You can authenticate users against LDAP server and use LDAP directory as vCard storage. Shared rosters are not supported yet.

    @@ -1552,7 +1572,7 @@ configuration is shown below:

    {auth_method, ldap}.
       ...
      ]}.
     

    -

    3.3  Modules Configuration

    +

    3.3  Modules Configuration

    The option modules defines the list of modules that will be loaded after ejabberd’s startup. Each entry in the list is a tuple in which the first element is the name of a module and the second is a list of options for that @@ -1574,7 +1594,7 @@ all entries end with a comma: {mod_version, []} ]}.

    -

    3.3.1  Modules Overview

    +

    3.3.1  Modules Overview

    The following table lists all modules included in ejabberd.


    @@ -1636,7 +1656,7 @@ Last connection date and time: Use mod_last_odbc instead of ejabberd website. Please remember that these contributions might not work or that they can contain severe bugs and security leaks. Therefore, use them at your own risk!

    -

    3.3.2  Common Options

    The following options are used by many modules. Therefore, they are described in +

    3.3.2  Common Options

    The following options are used by many modules. Therefore, they are described in this separate section.

    iqdisc

    Many modules define handlers for processing IQ queries of different namespaces @@ -1688,7 +1708,7 @@ the "@HOST@" keyword must be used: ... ]}.

    -

    3.3.3  mod_announce

    +

    3.3.3  mod_announce

    This module enables configured users to broadcast announcements and to set the message of the day (MOTD). Configured users can perform these actions with a @@ -1752,7 +1772,7 @@ Only administrators can send announcements:

    Note that mod_announce can be resource intensive on large deployments as it can broadcast lot of messages. This module should be disabled for instances of ejabberd with hundreds of thousands users.

    -

    3.3.4  mod_disco

    +

    3.3.4  mod_disco

    @@ -1795,7 +1815,7 @@ To serve a link to the Jabber User Directory on jabber.org: ... ]}.

    -

    3.3.5  mod_echo

    +

    3.3.5  mod_echo

    This module simply echoes any Jabber packet back to the sender. This mirror can be of interest for ejabberd and Jabber client debugging.

    Options: @@ -1815,7 +1835,7 @@ of them all? ... ]}.

    -

    3.3.6  mod_irc

    +

    3.3.6  mod_irc

    This module is an IRC transport that can be used to join channels on IRC servers.

    End user information: @@ -1874,7 +1894,7 @@ our domains and on other servers. ... ]}.

    -

    3.3.7  mod_last

    +

    3.3.7  mod_last

    This module adds support for Last Activity (XEP-0012). It can be used to discover when a disconnected user last accessed the server, to know when a connected user was last active on the server, or to query the uptime of the @@ -1883,7 +1903,7 @@ connected user was last active on the server, or to query the uptime of the iqdisc

    This specifies the processing discipline for Last activity (jabber:iq:last) IQ queries (see section 3.3.2).

    -

    3.3.8  mod_muc

    +

    3.3.8  mod_muc

    With this module enabled, your server will support Multi-User Chat (XEP-0045). End users will be able to join text conferences.

    Some of the features of Multi-User Chat:

    • @@ -2083,7 +2103,7 @@ newly created chatrooms have by default those options. ... ]}.

    -

    3.3.9  mod_muc_log

    +

    3.3.9  mod_muc_log

    This module enables optional logging of Multi-User Chat (MUC) conversations to HTML. Once you enable this module, users can join a chatroom using a MUC capable Jabber client, and if they have enough privileges, they can request the @@ -2092,8 +2112,8 @@ configuration form in which they can set the option to enable chatroom logging.< Chatroom details are added on top of each page: room title, JID, author, subject and configuration.

  • -Room title and JID are links to join the chatroom (using -XMPP URIs). +The room JID in the generated HTML is a link to join the chatroom (using +XMPP URI).
  • Subject and chatroom configuration changes are tracked and displayed.
  • Joins, leaves, nick changes, kicks, bans and ‘/me’ are tracked and displayed, including the reason if available. @@ -2190,7 +2210,7 @@ top link will be the default <a href="/">Home</a>. ... ]}.
  • -

    3.3.10  mod_offline

    +

    3.3.10  mod_offline

    This module implements offline message storage. This means that all messages sent to an offline user will be stored on the server until that user comes online again. Thus it is very similar to how email works. Note that @@ -2201,7 +2221,7 @@ is use to set a max number of offline messages per user (quota). Its value can be either infinity or a strictly positive integer. The default value is infinity.

    -

    3.3.11  mod_privacy

    +

    3.3.11  mod_privacy

    This module implements Blocking Communication (also known as Privacy Rules) as defined in section 10 from XMPP IM. If end users have support for it in their Jabber client, they will be able to: @@ -2229,7 +2249,7 @@ subscription type (or globally). iqdisc

    This specifies the processing discipline for Blocking Communication (jabber:iq:privacy) IQ queries (see section 3.3.2).

    -

    3.3.12  mod_private

    +

    3.3.12  mod_private

    This module adds support for Private XML Storage (XEP-0049):

    Using this method, Jabber entities can store private data on the server and @@ -2241,7 +2261,7 @@ of client-specific preferences; another is Bookmark Storage ( This specifies the processing discipline for Private XML Storage (jabber:iq:private) IQ queries (see section 3.3.2).

    -

    3.3.13  mod_proxy65

    +

    3.3.13  mod_proxy65

    This module implements SOCKS5 Bytestreams (XEP-0065). It allows ejabberd to act as a file transfer proxy between two XMPP clients.

    Options: @@ -2296,7 +2316,7 @@ The simpliest configuration of the module: ... ]}.

    -

    3.3.14  mod_pubsub

    +

    3.3.14  mod_pubsub

    This module offers a Publish-Subscribe Service (XEP-0060). The functionality in mod_pubsub can be extended using plugins. The plugin that implements PEP (Personal Eventing via Pubsub) (XEP-0163) @@ -2327,7 +2347,7 @@ and is shared by all node plugins. ... ]}.

    -

    3.3.15  mod_register

    +

    3.3.15  mod_register

    This module adds support for In-Band Registration (XEP-0077). This protocol enables end users to use a Jabber client to:

    • @@ -2343,6 +2363,7 @@ restrictions by default).
      welcome_message
      Set a welcome message that is sent to each newly registered account. The first string is the subject, and the second string is the message body. +In the body you can set a newline with the characters: ~n.
      registration_watchers
      This option defines a list of JIDs which will be notified each time a new account is registered.
      iqdisc
      This specifies @@ -2393,19 +2414,19 @@ Also define a registration timeout of one hour: ... {mod_register, [ - {welcome_message, {"Welcome!", "Welcome to this Jabber server. Check http://www.jabber.org"}}, + {welcome_message, {"Welcome!", "Hi.~nWelcome to this Jabber server.~n Check http://www.jabber.org~n~nBye"}}, {registration_watchers, ["admin1@example.org", "boss@example.net"]} ]}, ... ]}.

    -

    3.3.16  mod_roster

    +

    3.3.16  mod_roster

    This module implements roster management as defined in RFC 3921: XMPP IM.

    Options:

    iqdisc
    This specifies the processing discipline for Roster Management (jabber:iq:roster) IQ queries (see section 3.3.2).

    -

    3.3.17  mod_service_log

    +

    3.3.17  mod_service_log

    This module adds support for logging end user packets via a Jabber message auditing service such as Bandersnatch. All user @@ -2435,7 +2456,7 @@ To log all end user packets to the Bandersnatch service running on ... ]}.

    -

    3.3.18  mod_shared_roster

    +

    3.3.18  mod_shared_roster

    This module enables you to create shared roster groups. This means that you can create groups of people that can see members from (other) groups in their rosters. The big advantages of this feature are that end users do not need to @@ -2510,7 +2531,7 @@ roster groups as shown in the following table:

    ModuleFeatureDependencies
    mod_adhocAd-Hoc Commands (XEP-0050) 

    -

    3.3.19  mod_stats

    +

    3.3.19  mod_stats

    This module adds support for Statistics Gathering (XEP-0039). This protocol allows you to retrieve next statistics from your ejabberd deployment:

    • @@ -2542,14 +2563,14 @@ by sending: </query> </iq>

    -

    3.3.20  mod_time

    +

    3.3.20  mod_time

    This module features support for Entity Time (XEP-0090). By using this XEP, you are able to discover the time at another entity’s location.

    Options:

    iqdisc
    This specifies the processing discipline for Entity Time (jabber:iq:time) IQ queries (see section 3.3.2).

    -

    3.3.21  mod_vcard

    +

    3.3.21  mod_vcard

    This module allows end users to store and retrieve their vCard, and to retrieve other users vCards, as defined in vcard-temp (XEP-0054). The module also implements an uncomplicated Jabber User Directory based on the vCards of @@ -2604,7 +2625,7 @@ and that all virtual hosts will be searched instead of only the current one: ... ]}.

    -

    3.3.22  mod_vcard_ldap

    +

    3.3.22  mod_vcard_ldap

    ejabberd can map LDAP attributes to vCard fields. This behaviour is implemented in the mod_vcard_ldap module. This module does not depend on the authentication method (see 3.2.5).

    The mod_vcard_ldap module has @@ -2778,7 +2799,7 @@ searching his info in LDAP.

  • ldap_vcard_map
  • -

    3.3.23  mod_version

    +

    3.3.23  mod_version

    This module implements Software Version (XEP-0092). Consequently, it answers ejabberd’s version when queried.

    Options:

    @@ -2787,9 +2808,9 @@ The default value is true.
    iqdisc
    This specifies the processing discipline for Software Version (jabber:iq:version) IQ queries (see section 3.3.2).

    -

    Chapter 4  Managing an ejabberd server

    -

    4.1  ejabberdctl

    -

    4.1.1  Commands

    The ejabberdctl command line administration script allows to start, stop and perform +

    Chapter 4  Managing an ejabberd server

    +

    4.1  ejabberdctl

    +

    4.1.1  Commands

    The ejabberdctl command line administration script allows to start, stop and perform many other administrative tasks in a local or remote ejabberd server.

    When ejabberdctl is executed without any parameter, it displays the available options. If there isn’t an ejabberd server running, the available parameters are: @@ -2822,7 +2843,7 @@ and other codes may be used for specifical results. This can be used by other scripts to determine automatically if a command succedded or failed, for example using: echo $?

    -

    4.1.2  Erlang runtime system

    ejabberd is an Erlang/OTP application that runs inside an Erlang runtime system. +

    4.1.2  Erlang runtime system

    ejabberd is an Erlang/OTP application that runs inside an Erlang runtime system. This system is configured using environment variables and command line parameters. The ejabberdctl administration script uses many of those possibilities. You can configure some of them with the file ejabberdctl.cfg, @@ -2889,7 +2910,7 @@ Starts the Erlang system detached from the system console.

    Note that some characters need to be escaped when used in shell scripts, for instance " and {}. You can find other options in the Erlang manual page (erl -man erl).

    -

    4.2  Web Admin

    +

    4.2  Web Admin

    The ejabberd Web Admin allows to administer most of ejabberd using a web browser.

    This feature is enabled by default: a ejabberd_http listener with the option web_admin (see section 3.1.3) is included in the listening ports. Then you can open @@ -2949,15 +2970,15 @@ web browser to https://192.168.1.1:5280/admin/: ... ]}.

    -

    4.3  Ad-hoc Commands

    If you enable mod_configure and mod_adhoc, +

    4.3  Ad-hoc Commands

    If you enable mod_configure and mod_adhoc, you can perform several administrative tasks in ejabberd with a Jabber client. The client must support Ad-Hoc Commands (XEP-0050), and you must login in the Jabber server with an account with proper privileges.

    -

    4.4  Change Computer Hostname

    ejabberd uses the distributed Mnesia database. +

    4.4  Change Computer Hostname

    ejabberd uses the distributed Mnesia database. Being distributed, Mnesia enforces consistency of its file, -so it stores the name of the Erlang node in it. +so it stores the name of the Erlang node in it (see section 5.4). The name of an Erlang node includes the hostname of the computer. So, the name of the Erlang node changes if you change the name of the machine in which ejabberd runs, @@ -2971,8 +2992,8 @@ you must follow these instructions: For example:

    ejabberdctl restore /tmp/ejabberd-oldhost.backup
     

    -

    Chapter 5  Securing ejabberd

    -

    5.1  Firewall Settings

    +

    Chapter 5  Securing ejabberd

    +

    5.1  Firewall Settings

    You need to take the following TCP ports in mind when configuring your firewall:


    @@ -2983,7 +3004,7 @@ you must follow these instructions:
    PortDescription
    port rangeUsed for connections between Erlang nodes. This range is configurable (see section 5.2).

    -

    5.2  epmd

    epmd (Erlang Port Mapper Daemon) +

    5.2  epmd

    epmd (Erlang Port Mapper Daemon) is a small name server included in Erlang/OTP and used by Erlang programs when establishing distributed Erlang communications. ejabberd needs epmd to use ejabberdctl and also when clustering ejabberd nodes. @@ -3008,9 +3029,10 @@ but can be configured in the file ejabberdctl.cfg. The Erlang command-line parameter used internally is, for example:

    erl ... -kernel inet_dist_listen_min 4370 inet_dist_listen_max 4375
     

    -

    5.3  Erlang Cookie

    The Erlang cookie is a string with numbers and letters. -An Erlang node reads the cookie at startup from the command-line parameter -setcookie -or from a cookie file. +

    5.3  Erlang Cookie

    The Erlang cookie is a string with numbers and letters. +An Erlang node reads the cookie at startup from the command-line parameter -setcookie. +If not indicated, the cookie is read from the cookie file $HOME/.erlang.cookie. +If this file does not exist, it is created immediately with a random cookie. Two Erlang nodes communicate only if they have the same cookie. Setting a cookie on the Erlang node allows you to structure your Erlang network and define which nodes are allowed to connect to which.

    Thanks to Erlang cookies, you can prevent access to the Erlang node by mistake, @@ -3021,7 +3043,7 @@ to prevent unauthorized access or intrusion to an Erlang node. The communication between Erlang nodes are not encrypted, so the cookie could be read sniffing the traffic on the network. The recommended way to secure the Erlang node is to block the port 4369.

    -

    5.4  Erlang node name

    An Erlang node may have a node name. +

    5.4  Erlang node name

    An Erlang node may have a node name. The name can be short (if indicated with the command-line parameter -sname) or long (if indicated with the parameter -name). Starting an Erlang node with -sname limits the communication between Erlang nodes to the LAN.

    Using the option -sname instead of -name is a simple method @@ -3029,10 +3051,30 @@ to difficult unauthorized access to your Erlang node. However, it is not ultimately effective to prevent access to the Erlang node, because it may be possible to fake the fact that you are on another network using a modified version of Erlang epmd. -The recommended way to secure the Erlang node is to block the port 4369.

    -

    Chapter 6  Clustering

    +The recommended way to secure the Erlang node is to block the port 4369.

    +

    5.5  Securing sensible files

    ejabberd stores sensible data in the file system either in plain text or binary files. +The file system permissions should be set to only allow the proper user to read, +write and execute those files and directories.

    +ejabberd configuration file: /etc/ejabberd/ejabberd.cfg
    +Contains the JID of administrators +and passwords of external components. +The backup files probably contain also this information, +so it is preferable to secure the whole /etc/ejabberd/ directory. +
    ejabberd service log: /var/log/ejabberd/ejabberd.log
    +Contains IP addresses of clients. +If the loglevel is set to 5, it contains whole conversations and passwords. +If a logrotate system is used, there may be several log files with similar information, +so it is preferable to secure the whole /var/log/ejabberd/ directory. +
    Mnesia database spool files: /var/lib/ejabberd/db/*
    +The files store binary data, but some parts are still readable. +The files are generated by Mnesia and their permissions cannot be set directly, +so it is preferable to secure the whole /var/lib/ejabberd/db/ directory. +
    Erlang cookie file: /var/lib/ejabberd/.erlang.cookie
    +See section 5.3. +

    +

    Chapter 6  Clustering

    -

    6.1  How it Works

    +

    6.1  How it Works

    A Jabber domain is served by one or more ejabberd nodes. These nodes can be run on different machines that are connected via a network. They all must have the ability to connect to port 4369 of all another nodes, and must @@ -3046,29 +3088,29 @@ router,

  • session manager,
  • s2s manager.
  • -

    6.1.1  Router

    +

    6.1.1  Router

    This module is the main router of Jabber packets on each node. It routes them based on their destination’s domains. It uses a global routing table. The domain of the packet’s destination is searched in the routing table, and if it is found, the packet is routed to the appropriate process. If not, it is sent to the s2s manager.

    -

    6.1.2  Local Router

    +

    6.1.2  Local Router

    This module routes packets which have a destination domain equal to one of this server’s host names. If the destination JID has a non-empty user part, it is routed to the session manager, otherwise it is processed depending on its content.

    -

    6.1.3  Session Manager

    +

    6.1.3  Session Manager

    This module routes packets to local users. It looks up to which user resource a packet must be sent via a presence table. Then the packet is either routed to the appropriate c2s process, or stored in offline storage, or bounced back.

    -

    6.1.4  s2s Manager

    +

    6.1.4  s2s Manager

    This module routes packets to other Jabber servers. First, it checks if an opened s2s connection from the domain of the packet’s source to the domain of the packet’s destination exists. If that is the case, the s2s manager routes the packet to the process serving this connection, otherwise a new connection is opened.

    -

    6.2  Clustering Setup

    +

    6.2  Clustering Setup

    Suppose you already configured ejabberd on one machine named (first), and you need to setup another one to make an ejabberd cluster. Then do following steps:

    1. @@ -3102,10 +3144,10 @@ and ‘access’ options — they will be taken from enabled only on one machine in the cluster).

    You can repeat these steps for other machines supposed to serve this domain.

    -

    6.3  Service Load-Balancing

    +

    6.3  Service Load-Balancing

    -

    6.3.1  Components Load-Balancing

    -

    6.3.2  Domain Load-Balancing Algorithm

    +

    6.3.1  Components Load-Balancing

    +

    6.3.2  Domain Load-Balancing Algorithm

    ejabberd includes an algorithm to load balance the components that are plugged on an ejabberd cluster. It means that you can plug one or several instances of the same component on each ejabberd cluster and that the traffic will be automatically distributed.

    The default distribution algorithm try to deliver to a local instance of a component. If several local instances are available, one instance is chosen randomly. If no instance is available locally, one instance is chosen randomly among the remote component instances.

    If you need a different behaviour, you can change the load balancing behaviour with the option domain_balancing. The syntax of the option is the following:

    {domain_balancing, "component.example.com", <balancing_criterium>}.                                   
     

    Several balancing criteria are available:

    • @@ -3114,13 +3156,13 @@ domain.

      -

      6.3.3  Load-Balancing Buckets

      +

      6.3.3  Load-Balancing Buckets

      When there is a risk of failure for a given component, domain balancing can cause service trouble. If one component is failing the service will not work correctly unless the sessions are rebalanced.

      In this case, it is best to limit the problem to the sessions handled by the failing component. This is what the domain_balancing_component_number option does, making the load balancing algorithm not dynamic, but sticky on a fix number of component instances.

      The syntax is the following:

      {domain_balancing_component_number, "component.example.com", N}
       

      -

      Chapter 7  Debugging

      +

      Chapter 7  Debugging

      -

      7.1  Watchdog Alerts

      +

      7.1  Watchdog Alerts

      ejabberd includes a watchdog mechanism. If a process in the ejabberd server consumes too much memory, a message is sent to the Jabber accounts defined with the option @@ -3132,7 +3174,7 @@ Example configuration: To remove all watchdog admins, set the option with an empty list:

      {watchdog_admins, []}.
       

      -

      7.2  Log Files

      An ejabberd node writes two log files: +

      7.2  Log Files

      An ejabberd node writes two log files:

      ejabberd.log
      is the ejabberd service log, with the messages reported by ejabberd code
      sasl.log
      is the Erlang/OTP system log, with the messages reported by Erlang/OTP using SASL (System Architecture Support Libraries) @@ -3149,12 +3191,12 @@ The possible levels are: For example, the default configuration is:

      {loglevel, 4}.
       

      -

      7.3  Debug Console

      The Debug Console is an Erlang shell attached to an already running ejabberd server. +

      7.3  Debug Console

      The Debug Console is an Erlang shell attached to an already running ejabberd server. With this Erlang shell, an experienced administrator can perform complex tasks.

      This shell gives complete control over the ejabberd server, so it is important to use it with extremely care. There are some simple and safe examples in the article Interconnecting Erlang Nodes

      To exit the shell, close the window or press the keys: control+c control+c.

      -

      Appendix A  Internationalization and Localization

      +

      Appendix A  Internationalization and Localization

      All built-in modules support the xml:lang attribute inside IQ queries. Figure A.1, for example, shows the reply to the following query:

      <iq id='5'
      @@ -3181,9 +3223,9 @@ HTTP header ‘Accept-Language: ru’
       
       
       

      -

      Appendix B  Release Notes

      +

      Appendix B  Release Notes

      Release notes are available from ejabberd Home Page

      -

      Appendix C  Acknowledgements

      Thanks to all people who contributed to this guide: +

      Appendix C  Acknowledgements

      Thanks to all people who contributed to this guide:

      -

      Appendix D  Copyright Information

      Ejabberd Installation and Operation Guide.
      +

      Appendix D  Copyright Information

      Ejabberd Installation and Operation Guide.
      Copyright © 2003 — 2008 Process-one

      This document 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 diff --git a/doc/guide.tex b/doc/guide.tex index 73d889fc5..5a23a359a 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -361,7 +361,7 @@ The files and directories created are, by default: \titem{/sbin/ejabberdctl} Administration script \titem{/var/lib/ejabberd/} \begin{description} - \titem{.erlang.cookie} Erlang cookie file + \titem{.erlang.cookie} Erlang cookie file (see section \ref{cookie}) \titem{db} Mnesia database spool files \titem{ebin} Binary Erlang files (*.beam) \titem{priv} @@ -405,6 +405,31 @@ gmake \end{verbatim} +\makesubsection{solaris}{Specific Notes for Sun Solaris} +\ind{install!solaris} + +You need to have \term{GNU install}, +but it isn't included in Solaris. +It can be easily installed if your Solaris system +is set up for \footahref{http://www.blastwave.org/}{blastwave.org} +package repository. +Make sure \term{/opt/csw/bin} is in your \term{PATH} and run: +\begin{verbatim} +pkg-get -i fileutils +\end{verbatim} + +If that program is called \term{ginstall}, +modify the \ejabberd{} \term{Makefile} script to suit your system, +for example: +\begin{verbatim} +cat Makefile | sed s/install/ginstall/ > Makefile.gi +\end{verbatim} +And finally install \ejabberd{} with: +\begin{verbatim} +gmake -f Makefile.gi ginstall +\end{verbatim} + + \makesubsection{windows}{Specific Notes for Microsoft Windows} \ind{install!windows} @@ -729,7 +754,10 @@ This is a detailed description of each option allowed by the listening modules: is also needed in the \Jabber{} client. Remark also that HTTP Polling can be interesting to host a web-based \Jabber{} client such as \footahref{http://jwchat.sourceforge.net/}{JWChat}. - \titem{inet6} \ind{options!inet6}\ind{IPv6}Set up the socket for IPv6. + \titem{inet6} \ind{options!inet6}\ind{IPv6}Set up the socket for IPv6 instead of IPv4. + Note: this option is not required for S2S outgoing connections, + because when ejabberd attempts to establish a S2S outgoing connection + it first tries IPv4, and if that fails it attempts with IPv6. \titem{\{ip, IPAddress\}} \ind{options!ip}This option specifies which network interface to listen for. For example \verb|{ip, {192, 168, 1, 1}}|. \titem{\{max\_stanza\_size, Size\}} @@ -2710,9 +2738,9 @@ Features: \begin{itemize} \item Chatroom details are added on top of each page: room title, JID, author, subject and configuration. -\item \ind{protocols!RFC 4622: Internationalized Resource Identifiers (IRIs) and Uniform Resource Identifiers (URIs) for the Extensible Messaging and Presence Protocol (XMPP)} - Room title and JID are links to join the chatroom (using - \footahref{http://www.ietf.org/rfc/rfc4622.txt}{XMPP URIs}). +\item \ind{protocols!RFC 5122: Internationalized Resource Identifiers (IRIs) and Uniform Resource Identifiers (URIs) for the Extensible Messaging and Presence Protocol (XMPP)} + The room JID in the generated HTML is a link to join the chatroom (using + \footahref{http://www.xmpp.org/rfcs/rfc5122.html}{XMPP URI}). \item Subject and chatroom configuration changes are tracked and displayed. \item Joins, leaves, nick changes, kicks, bans and `/me' are tracked and displayed, including the reason if available. @@ -3008,6 +3036,7 @@ Options: \titem{welcome\_message} \ind{options!welcomem}Set a welcome message that is sent to each newly registered account. The first string is the subject, and the second string is the message body. + In the body you can set a newline with the characters: \term{\~\ n}. \titem{registration\_watchers} \ind{options!rwatchers}This option defines a list of JIDs which will be notified each time a new account is registered. \iqdiscitem{In-Band Registration (\ns{jabber:iq:register})} @@ -3066,7 +3095,7 @@ Also define a registration timeout of one hour: ... {mod_register, [ - {welcome_message, {"Welcome!", "Welcome to this Jabber server. Check http://www.jabber.org"}}, + {welcome_message, {"Welcome!", "Hi.~nWelcome to this Jabber server.~n Check http://www.jabber.org~n~nBye"}}, {registration_watchers, ["admin1@example.org", "boss@example.net"]} ]}, ... @@ -3781,7 +3810,7 @@ an account with proper privileges. \ejabberd{} uses the distributed Mnesia database. Being distributed, Mnesia enforces consistency of its file, -so it stores the name of the Erlang node in it. +so it stores the name of the Erlang node in it (see section \ref{nodename}). The name of an Erlang node includes the hostname of the computer. So, the name of the Erlang node changes if you change the name of the machine in which \ejabberd{} runs, @@ -3861,8 +3890,9 @@ erl ... -kernel inet_dist_listen_min 4370 inet_dist_listen_max 4375 \makesection{cookie}{Erlang Cookie} The Erlang cookie is a string with numbers and letters. -An Erlang node reads the cookie at startup from the command-line parameter \term{-setcookie} -or from a cookie file. +An Erlang node reads the cookie at startup from the command-line parameter \term{-setcookie}. +If not indicated, the cookie is read from the cookie file \term{\$HOME/.erlang.cookie}. +If this file does not exist, it is created immediately with a random cookie. Two Erlang nodes communicate only if they have the same cookie. Setting a cookie on the Erlang node allows you to structure your Erlang network and define which nodes are allowed to connect to which. @@ -3894,6 +3924,32 @@ using a modified version of Erlang \term{epmd}. The recommended way to secure the Erlang node is to block the port 4369. +\makesection{secure-files}{Securing sensible files} + +\ejabberd{} stores sensible data in the file system either in plain text or binary files. +The file system permissions should be set to only allow the proper user to read, +write and execute those files and directories. + +\begin{description} + \titem{ejabberd configuration file: /etc/ejabberd/ejabberd.cfg} + Contains the JID of administrators + and passwords of external components. + The backup files probably contain also this information, + so it is preferable to secure the whole \term{/etc/ejabberd/} directory. + \titem{ejabberd service log: /var/log/ejabberd/ejabberd.log} + Contains IP addresses of clients. + If the loglevel is set to 5, it contains whole conversations and passwords. + If a logrotate system is used, there may be several log files with similar information, + so it is preferable to secure the whole \term{/var/log/ejabberd/} directory. + \titem{Mnesia database spool files: /var/lib/ejabberd/db/*} + The files store binary data, but some parts are still readable. + The files are generated by Mnesia and their permissions cannot be set directly, + so it is preferable to secure the whole \term{/var/lib/ejabberd/db/} directory. + \titem{Erlang cookie file: /var/lib/ejabberd/.erlang.cookie} + See section \ref{cookie}. +\end{description} + + \makechapter{clustering}{Clustering} \ind{clustering} diff --git a/src/Makefile.in b/src/Makefile.in index 57bb56333..607af353e 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -60,6 +60,7 @@ DESTDIR = EJABBERDDIR = $(DESTDIR)@localstatedir@/lib/ejabberd BEAMDIR = $(EJABBERDDIR)/ebin +SPOOLDIR = $(EJABBERDDIR)/db PRIVDIR = $(EJABBERDDIR)/priv SODIR = $(PRIVDIR)/lib PBINDIR = $(PRIVDIR)/bin @@ -116,20 +117,21 @@ install: all install -m 644 *.beam $(BEAMDIR) rm -f $(BEAMDIR)/configure.beam install -m 644 *.app $(BEAMDIR) + install -d -m 750 $(SPOOLDIR) install -d $(SODIR) install -d $(PBINDIR) install -m 644 *.so $(SODIR) $(INSTALL_EPAM) install -d $(MSGSDIR) install -m 644 msgs/*.msg $(MSGSDIR) - install -d $(ETCDIR) + install -d -m 750 $(ETCDIR) [ -f $(ETCDIR)/ejabberd.cfg ] && install -b -m 644 ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg-new || install -b -m 644 ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg sed -e "s*@rootdir@*@prefix@*" ejabberdctl.template > ejabberdctl.example [ -f $(ETCDIR)/ejabberdctl.cfg ] && install -b -m 644 ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg-new || install -b -m 644 ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg install -b -m 644 inetrc $(ETCDIR)/inetrc install -d $(SBINDIR) install -m 755 ejabberdctl.example $(SBINDIR)/ejabberdctl - install -d $(LOGDIR) + install -d -m 750 $(LOGDIR) uninstall: uninstall-binary diff --git a/src/configure b/src/configure index 573a17ee7..034868416 100755 --- a/src/configure +++ b/src/configure @@ -4765,6 +4765,9 @@ _ACEOF fi +# Check Erlang headers are installed +#AC_CHECK_HEADER(erl_driver.h,,[AC_MSG_ERROR([cannot find Erlang header files])]) + # Change default prefix diff --git a/src/configure.ac b/src/configure.ac index a3e8894e9..254b16b06 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -26,6 +26,9 @@ AM_WITH_PAM # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST +# Check Erlang headers are installed +#AC_CHECK_HEADER(erl_driver.h,,[AC_MSG_ERROR([cannot find Erlang header files])]) + # Change default prefix AC_PREFIX_DEFAULT(/) diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index e1d63ed9e..eb43bb3ca 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -459,7 +459,7 @@ %% a message with this subject and body. %% {welcome_message, {"Welcome!", - "Welcome to this Jabber server."}}, + "Hi.~nWelcome to this Jabber server."}}, %% %% When a user registers, send a notification to diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index dae88f07a..82fd029ce 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1223,6 +1223,9 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> handle_info({'DOWN', Monitor, _Type, _Object, _Info}, _StateName, StateData) when Monitor == StateData#state.socket_monitor -> {stop, normal, StateData}; +handle_info({peername, IP}, StateName, StateData) -> + ejabberd_sm:set_session_ip(StateData#state.sid, IP), + fsm_next_state(StateName, StateData#state{ip = IP}); handle_info(Info, StateName, StateData) -> ?ERROR_MSG("Unexpected info: ~p", [Info]), fsm_next_state(StateName, StateData). diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 7a9cade1f..c18cfe6de 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -96,8 +96,10 @@ get_plain_terms_file(File1) -> {ok, Terms} -> include_config_files(Terms); {error, Reason} -> - ?ERROR_MSG("Can't load config file ~p: ~p", [File, Reason]), - exit(File ++ ": " ++ file:format_error(Reason)) + ExitText = lists:flatten(File ++ ": around line " + ++ file:format_error(Reason)), + ?ERROR_MSG("Problem loading ejabberd config file:~n~s", [ExitText]), + exit(ExitText) end. %% @doc Convert configuration filename to absolute path. diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl index 7cb36141d..9a84b592e 100644 --- a/src/ejabberd_ctl.erl +++ b/src/ejabberd_ctl.erl @@ -30,6 +30,7 @@ -export([start/0, init/0, process/1, + dump_to_textfile/1, register_commands/3, register_commands/4, unregister_commands/3, diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 76719bbb8..c3786ca53 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -37,6 +37,7 @@ register_iq_handler/5, register_iq_response_handler/4, unregister_iq_handler/2, + unregister_iq_response_handler/2, refresh_iq_handlers/0, bounce_resource_packet/3 ]). @@ -168,6 +169,9 @@ register_iq_handler(Host, XMLNS, Module, Fun) -> register_iq_handler(Host, XMLNS, Module, Fun, Opts) -> ejabberd_local ! {register_iq_handler, Host, XMLNS, Module, Fun, Opts}. +unregister_iq_response_handler(Host, ID) -> + ejabberd_local ! {unregister_iq_response_handler, Host, ID}. + unregister_iq_handler(Host, XMLNS) -> ejabberd_local ! {unregister_iq_handler, Host, XMLNS}. @@ -254,6 +258,9 @@ handle_info({route, From, To, Packet}, State) -> handle_info({register_iq_response_handler, _Host, ID, Module, Function}, State) -> mnesia:dirty_write(#iq_response{id = ID, module = Module, function = Function}), {noreply, State}; +handle_info({unregister_iq_response_handler, _Host, ID}, State) -> + mnesia:dirty_delete({iq_response, ID}), + {noreply, State}; handle_info({register_iq_handler, Host, XMLNS, Module, Function}, State) -> ets:insert(?IQTABLE, {{XMLNS, Host}, Module, Function}), catch mod_disco:register_feature(Host, XMLNS), diff --git a/src/ejabberd_receiver.erl b/src/ejabberd_receiver.erl index 5fdad76af..3b6c80439 100644 --- a/src/ejabberd_receiver.erl +++ b/src/ejabberd_receiver.erl @@ -268,7 +268,8 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- activate_socket(#state{socket = Socket, - sock_mod = SockMod}) -> + sock_mod = SockMod, + c2s_pid = C2SPid}) -> PeerName = case SockMod of gen_tcp -> @@ -281,7 +282,8 @@ activate_socket(#state{socket = Socket, case PeerName of {error, _Reason} -> self() ! {tcp_closed, Socket}; - {ok, _} -> + {ok, IP} -> + C2SPid ! {peername, IP}, ok end. diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 9300958d5..ccf679386 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -49,7 +49,8 @@ ctl_process/2, get_session_pid/3, get_user_info/3, - get_user_ip/3 + get_user_ip/3, + set_session_ip/2 ]). %% gen_server callbacks @@ -186,6 +187,18 @@ get_user_info(User, Server, Resource) -> [{node, Node}, {conn, Conn}, {ip, IP}] end. +set_session_ip(SID, IP) -> + case mnesia:dirty_read(session, SID) of + [#session{info = Info} = Session] -> + NewInfo = case lists:keymember(ip, 1, Info) of + true -> lists:keyreplace(ip, 1, Info, {ip, IP}); + false -> [{ip, IP}|Info] + end, + mnesia:dirty_write(Session#session{info = NewInfo}); + _ -> + ok + end. + set_presence(SID, User, Server, Resource, Priority, Presence, Info) -> set_session(SID, User, Server, Resource, Priority, Info), % XXX OLD FORMAT: Presence. diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 2be0fac66..3240aa6e2 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -53,6 +53,7 @@ -define(PROCNAME, ejabberd_mod_caps). -define(DICT, dict). +-define(CAPS_QUERY_TIMEOUT, 60000). % 1mn without answer, consider client never answer -record(caps, {node, version, exts}). -record(caps_features, {node_pair, features}). @@ -220,6 +221,7 @@ handle_cast({note_caps, From, ejabberd_local:register_iq_response_handler (Host, ID, ?MODULE, handle_disco_response), ejabberd_router:route(jlib:make_jid("", Host, ""), From, Stanza), + timer:send_after(?CAPS_QUERY_TIMEOUT, self(), {disco_timeout, ID}), ?DICT:store(ID, {Node, SubNode}, Dict) end, Requests, Missing), {noreply, State#state{disco_requests = NewRequests}}; @@ -274,6 +276,16 @@ handle_cast({disco_response, From, _To, end, NewRequests = ?DICT:erase(ID, Requests), {noreply, State#state{disco_requests = NewRequests}}; +handle_cast({disco_timeout, ID}, #state{host = Host, disco_requests = Requests} = State) -> + %% do not wait a response anymore for this IQ, client certainly will never answer + NewRequests = case ?DICT:is_key(ID, Requests) of + true -> + ejabberd_local:unregister_iq_response_handler(Host, ID), + ?DICT:erase(ID, Requests); + false -> + Requests + end, + {noreply, State#state{disco_requests = NewRequests}}; handle_cast(visit_feature_queries, #state{feature_queries = FeatureQueries} = State) -> Timestamp = timestamp(), NewFeatureQueries = diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 625e380cd..e012794dd 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -1416,7 +1416,7 @@ set_form(_From, _Host, ["running nodes", ENode, "backup", "textfile"], _Lang, XD false -> {error, ?ERR_BAD_REQUEST}; {value, {_, [String]}} -> - case rpc:call(Node, mnesia, dump_to_textfile, [String]) of + case rpc:call(Node, ejabberd_ctl, dump_to_textfile, [String]) of {badrpc, _Reason} -> {error, ?ERR_INTERNAL_SERVER_ERROR}; {error, _Reason} -> diff --git a/src/mod_muc/mod_muc_log.erl b/src/mod_muc/mod_muc_log.erl index fce9c15b2..9ab8d4ce2 100644 --- a/src/mod_muc/mod_muc_log.erl +++ b/src/mod_muc/mod_muc_log.erl @@ -120,9 +120,11 @@ init([Host, Opts]) -> NoFollow = gen_mod:get_opt(spam_prevention, Opts, true), Lang = case ejabberd_config:get_local_option({language, Host}) of undefined -> - ""; - L -> - L + case ejabberd_config:get_global_option(language) of + undefined -> "en"; + L -> L + end; + L -> L end, {ok, #state{host = Host, out_dir = OutDir, @@ -286,9 +288,10 @@ add_message_to_log(Nick1, Message, RoomJID, Opts, State) -> top_link = TopLink} = State, Room = get_room_info(RoomJID, Opts), + Now = now(), TimeStamp = case Timezone of - local -> calendar:now_to_local_time(now()); - universal -> calendar:now_to_universal_time(now()) + local -> calendar:now_to_local_time(Now); + universal -> calendar:now_to_universal_time(Now) end, {Fd, Fn, _Dir} = build_filename_string(TimeStamp, OutDir, Room#room.jid, DirType), {Date, Time} = TimeStamp, @@ -382,10 +385,12 @@ add_message_to_log(Nick1, Message, RoomJID, Opts, State) -> {Hour, Minute, Second} = Time, STime = lists:flatten( io_lib:format("~2..0w:~2..0w:~2..0w", [Hour, Minute, Second])), + {_, _, Microsecs} = Now, + STimeUnique = io_lib:format("~s.~w", [STime, Microsecs]), % Write message - file:write(F, io_lib:format("[~s] ~s~n", - [STime, STime, STime, Text])), + file:write(F, io_lib:format("[~s] ~s~n", + [STimeUnique, STimeUnique, STimeUnique, STime, Text])), % Close file file:close(F), diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index e858d680f..64957a70a 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -59,6 +59,7 @@ -record(lqueue, {queue, len, max}). -record(config, {title = "", + description = "", allow_change_subj = true, allow_query_users = true, allow_private_messages = true, @@ -2614,7 +2615,10 @@ get_config(Lang, StateData, From) -> [{xmlcdata, "http://jabber.org/protocol/muc#roomconfig"}]}]}, ?STRINGXFIELD("Room title", "muc#roomconfig_roomname", - Config#config.title) + Config#config.title), + ?STRINGXFIELD("Room description", + "muc#roomconfig_roomdesc", + Config#config.description) ] ++ case acl:match_rule(StateData#state.server_host, AccessPersistent, From) of allow -> @@ -2761,6 +2765,8 @@ set_xoption([], Config) -> Config; set_xoption([{"muc#roomconfig_roomname", [Val]} | Opts], Config) -> ?SET_STRING_XOPT(title, Val); +set_xoption([{"muc#roomconfig_roomdesc", [Val]} | Opts], Config) -> + ?SET_STRING_XOPT(description, Val); set_xoption([{"muc#roomconfig_changesubject", [Val]} | Opts], Config) -> ?SET_BOOL_XOPT(allow_change_subj, Val); set_xoption([{"allow_query_users", [Val]} | Opts], Config) -> @@ -2856,6 +2862,7 @@ set_opts([], StateData) -> set_opts([{Opt, Val} | Opts], StateData) -> NSD = case Opt of title -> StateData#state{config = (StateData#state.config)#config{title = Val}}; + description -> StateData#state{config = (StateData#state.config)#config{description = Val}}; allow_change_subj -> StateData#state{config = (StateData#state.config)#config{allow_change_subj = Val}}; allow_query_users -> StateData#state{config = (StateData#state.config)#config{allow_query_users = Val}}; allow_private_messages -> StateData#state{config = (StateData#state.config)#config{allow_private_messages = Val}}; @@ -2895,6 +2902,7 @@ make_opts(StateData) -> Config = StateData#state.config, [ ?MAKE_CONFIG_OPT(title), + ?MAKE_CONFIG_OPT(description), ?MAKE_CONFIG_OPT(allow_change_subj), ?MAKE_CONFIG_OPT(allow_query_users), ?MAKE_CONFIG_OPT(allow_private_messages), @@ -2991,9 +2999,12 @@ process_iq_disco_info(_From, get, Lang, StateData) -> iq_disco_info_extras(Lang, StateData) -> Len = length(?DICT:to_list(StateData#state.users)), + RoomDescription = (StateData#state.config)#config.description, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "result"}], [?RFIELDT("hidden", "FORM_TYPE", "http://jabber.org/protocol/muc#roominfo"), + ?RFIELD("Room description", "muc#roominfo_description", + RoomDescription), ?RFIELD("Number of occupants", "muc#roominfo_occupants", integer_to_list(Len)) ]}]. diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 8db812d0b..b4e267d28 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -698,11 +698,11 @@ raw_to_item({SType, SValue, SAction, SOrder, SMatchAll, SMatchIQ, "d" -> deny end, Order = list_to_integer(SOrder), - MatchAll = SMatchAll == "t", - MatchIQ = SMatchIQ == "t", - MatchMessage = SMatchMessage == "t", - MatchPresenceIn = SMatchPresenceIn == "t", - MatchPresenceOut = SMatchPresenceOut == "t", + MatchAll = SMatchAll == "1" orelse SMatchAll == "t", + MatchIQ = SMatchIQ == "1" orelse SMatchIQ == "t" , + MatchMessage = SMatchMessage == "1" orelse SMatchMessage == "t", + MatchPresenceIn = SMatchPresenceIn == "1" orelse SMatchPresenceIn == "t", + MatchPresenceOut = SMatchPresenceOut == "1" orelse SMatchPresenceOut == "t", #listitem{type = Type, value = Value, action = Action, @@ -750,11 +750,11 @@ item_to_raw(#listitem{type = Type, deny -> "d" end, SOrder = integer_to_list(Order), - SMatchAll = if MatchAll -> "t"; true -> "f" end, - SMatchIQ = if MatchIQ -> "t"; true -> "f" end, - SMatchMessage = if MatchMessage -> "t"; true -> "f" end, - SMatchPresenceIn = if MatchPresenceIn -> "t"; true -> "f" end, - SMatchPresenceOut = if MatchPresenceOut -> "t"; true -> "f" end, + SMatchAll = if MatchAll -> "1"; true -> "0" end, + SMatchIQ = if MatchIQ -> "1"; true -> "0" end, + SMatchMessage = if MatchMessage -> "1"; true -> "0" end, + SMatchPresenceIn = if MatchPresenceIn -> "1"; true -> "0" end, + SMatchPresenceOut = if MatchPresenceOut -> "1"; true -> "0" end, ["'", SType, "', " "'", SValue, "', " "'", SAction, "', " @@ -871,6 +871,3 @@ sql_set_privacy_list(ID, RItems) -> ") " "values ('", ID, "', ", Items, ");"]) end, RItems). - - - diff --git a/src/mod_pubsub/gen_pubsub_node.erl b/src/mod_pubsub/gen_pubsub_node.erl index 195ed3934..bbbb5c409 100644 --- a/src/mod_pubsub/gen_pubsub_node.erl +++ b/src/mod_pubsub/gen_pubsub_node.erl @@ -62,7 +62,9 @@ behaviour_info(callbacks) -> {get_states, 2}, {get_state, 3}, {set_state, 1}, + {get_items, 7}, {get_items, 2}, + {get_item, 8}, {get_item, 3}, {set_item, 1}, {get_item_name, 3} diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index cb8ce997d..e83e0170f 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -30,16 +30,17 @@ %%% %%% @reference See XEP-0060: Pubsub for %%% the latest version of the PubSub specification. -%%% This module uses version 1.10 of the specification as a base. +%%% This module uses version 1.11 of the specification as a base. %%% Most of the specification is implemented. -%%% Code is derivated from the original pubsub v1.7, functions concerning config may be rewritten. -%%% Code also inspired from the original PEP patch by Magnus Henoch (mangeATfreemail.hu) +%%% Functions concerning configuration should be rewritten. +%%% Code is derivated from the original pubsub v1.7, by Alexey Shchepin %%% TODO %%% plugin: generate Reply (do not use broadcast atom anymore) -module(mod_pubsub). --version('1.10-01'). +-author('christophe.romain@process-one.net'). +-version('1.11-01'). -behaviour(gen_server). -behaviour(gen_mod). @@ -912,7 +913,17 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) -> unsubscribe_node(Host, Node, From, JID, SubId); {get, "items"} -> MaxItems = xml:get_attr_s("max_items", Attrs), - get_items(Host, Node, From, MaxItems); + SubId = xml:get_attr_s("subid", Attrs), + ItemIDs = lists:foldl(fun + ({xmlelement, "item", ItemAttrs, _}, Acc) -> + case xml:get_attr_s("id", ItemAttrs) of + "" -> Acc; + ItemID -> ItemID + end; + (_, Acc) -> + Acc + end, [], xml:remove_cdata(Els)), + get_items(Host, Node, From, SubId, MaxItems, ItemIDs); {get, "subscriptions"} -> get_subscriptions(Host, From, Plugins); {get, "affiliations"} -> @@ -1436,7 +1447,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> Action = fun(#pubsub_node{options = Options, type = Type}) -> Features = features(Type), PublishFeature = lists:member("publish", Features), - Model = get_option(Options, publish_model), + PublishModel = get_option(Options, publish_model), MaxItems = max_items(Options), PayloadSize = size(term_to_binary(Payload)), PayloadMaxSize = get_option(Options, max_payload_size), @@ -1459,7 +1470,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> %% % Publisher attempts to publish to transient notification node with item %% {error, extended_error(?ERR_BAD_REQUEST, "item-forbidden")}; true -> - node_call(Type, publish_item, [Host, Node, Publisher, Model, MaxItems, ItemId, Payload]) + node_call(Type, publish_item, [Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload]) end end, %%ejabberd_hooks:run(pubsub_publish_item, Host, [Host, Node, JID, service_jid(Host), ItemId, Payload]), @@ -1622,7 +1633,7 @@ purge_node(Host, Node, Owner) -> %%

      The permission are not checked in this function.

      %% @todo We probably need to check that the user doing the query has the right %% to read the items. -get_items(Host, Node, _JID, SMaxItems) -> +get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> MaxItems = if SMaxItems == "" -> ?MAXITEMS; @@ -1636,24 +1647,60 @@ get_items(Host, Node, _JID, SMaxItems) -> {error, Error} -> {error, Error}; _ -> - case get_items(Host, Node) of - [] -> - {error, ?ERR_ITEM_NOT_FOUND}; - Items -> + Action = fun(#pubsub_node{options = Options, type = Type}) -> + Features = features(Type), + RetreiveFeature = lists:member("retrieve-items", Features), + PersistentFeature = lists:member("persistent-items", Features), + AccessModel = get_option(Options, access_model), + AllowedGroups = get_option(Options, roster_groups_allowed), + {PresenceSubscription, RosterGroup} = + case Host of + {OUser, OServer, _} -> + get_roster_info(OUser, OServer, + jlib:jid_tolower(From), AllowedGroups); + _ -> + {true, true} + end, + if + not RetreiveFeature -> + %% Item Retrieval Not Supported + {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "retrieve-items")}; + not PersistentFeature -> + %% Persistent Items Not Supported + {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "persistent-items")}; + true -> + node_call(Type, get_items, + [Host, Node, From, + AccessModel, PresenceSubscription, RosterGroup, + SubId]) + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {error, Reason} -> + {error, Reason}; + {result, Items} -> + SendItems = case ItemIDs of + [] -> + Items; + _ -> + lists:filter(fun(Item) -> + lists:member(Item, ItemIDs) + end, Items) + end, %% Generate the XML response (Item list), limiting the %% number of items sent to MaxItems: ItemsEls = lists:map( - fun(#pubsub_item{itemid = {ItemId, _}, - payload = Payload}) -> - ItemAttrs = case ItemId of - "" -> []; - _ -> [{"id", ItemId}] - end, - {xmlelement, "item", ItemAttrs, Payload} - end, lists:sublist(Items, MaxItems)), + fun(#pubsub_item{itemid = {ItemId, _}, + payload = Payload}) -> + ItemAttrs = case ItemId of + "" -> []; + _ -> [{"id", ItemId}] + end, + {xmlelement, "item", ItemAttrs, Payload} + end, lists:sublist(SendItems, MaxItems)), {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], - [{xmlelement, "items", [{"node", node_to_string(Node)}], - ItemsEls}]}]} + [{xmlelement, "items", [{"node", node_to_string(Node)}], + ItemsEls}]}]} end end. @@ -1809,7 +1856,7 @@ set_affiliations(Host, Node, From, EntitiesEls) -> end, Entities), {result, []}; _ -> - {error, ?ERR_NOT_ALLOWED} + {error, ?ERR_FORBIDDEN} end end, transaction(Host, Node, Action, sync_dirty) @@ -1870,7 +1917,7 @@ get_subscriptions(Host, Node, JID) -> %% Service does not support manage subscriptions {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "manage-affiliations")}; Affiliation /= {result, owner} -> - % Entity is not an owner + %% Entity is not an owner {error, ?ERR_FORBIDDEN}; true -> node_call(Type, get_node_subscriptions, [Host, Node]) @@ -1938,7 +1985,7 @@ set_subscriptions(Host, Node, From, EntitiesEls) -> end, Entities), {result, []}; _ -> - {error, ?ERR_NOT_ALLOWED} + {error, ?ERR_FORBIDDEN} end end, transaction(Host, Node, Action, sync_dirty) @@ -2352,7 +2399,10 @@ get_configure(Host, Node, From, Lang) -> transaction(Host, Node, Action, sync_dirty). get_default(Host, _Node, _From, Lang) -> - Type = hd(plugins(Host)), % first configured plugin is default + Type = case Host of + {_, _, _} -> ?PEPNODE; + _ -> hd(plugins(Host)) + end, Options = node_options(Type), {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB_OWNER}], [{xmlelement, "default", [], @@ -2435,6 +2485,7 @@ get_configure_xfields(_Type, Options, Lang, _Owners) -> ?BOOL_CONFIG_FIELD("Notify subscribers when the node is deleted", notify_delete), ?BOOL_CONFIG_FIELD("Notify subscribers when items are removed from the node", notify_retract), ?BOOL_CONFIG_FIELD("Persist items to storage", persist_items), + ?STRING_CONFIG_FIELD("A friendly name for the node", title), ?INTEGER_CONFIG_FIELD("Max # of items to persist", max_items), ?BOOL_CONFIG_FIELD("Whether to allow subscriptions", subscribe), ?ALIST_CONFIG_FIELD("Specify the access model", access_model, @@ -2551,7 +2602,7 @@ set_xoption([], NewOpts) -> NewOpts; set_xoption([{"FORM_TYPE", _} | Opts], NewOpts) -> set_xoption(Opts, NewOpts); -set_xoption([{"pubsub#roster_groups_allowed", Value} | Opts], NewOpts) -> +set_xoption([{"pubsub#roster_groups_allowed", _Value} | Opts], NewOpts) -> ?SET_LIST_XOPT(roster_groups_allowed, []); % XXX: waiting for EJAB-659 to be solved set_xoption([{"pubsub#deliver_payloads", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(deliver_payloads, Val); @@ -2602,7 +2653,7 @@ features() -> [ %"access-authorize", % OPTIONAL "access-open", % OPTIONAL this relates to access_model option in node_default - %"access-presence", % OPTIONAL + "access-presence", % OPTIONAL this relates to access_model option in node_pep %"access-roster", % OPTIONAL %"access-whitelist", % OPTIONAL % see plugin "auto-create", % OPTIONAL @@ -2616,7 +2667,7 @@ features() -> % see plugin "filtered-notifications", % RECOMMENDED %TODO "get-pending", % OPTIONAL % see plugin "instant-nodes", % RECOMMENDED - %TODO "item-ids", % RECOMMENDED + "item-ids", % RECOMMENDED "last-published", % RECOMMENDED %TODO "cache-last-item", %TODO "leased-subscription", % OPTIONAL diff --git a/src/mod_pubsub/node.template b/src/mod_pubsub/node.template index 850a38ec9..973aa38a4 100644 --- a/src/mod_pubsub/node.template +++ b/src/mod_pubsub/node.template @@ -61,7 +61,9 @@ get_states/2, get_state/3, set_state/1, + get_items/7, get_items/2, + get_item/8, get_item/3, set_item/1 ]). @@ -94,7 +96,6 @@ features() -> ["create-nodes", "delete-nodes", "instant-nodes", - "item-ids", "outcast-affiliation", "persistent-items", "publish", @@ -170,8 +171,14 @@ set_state(State) -> get_items(Host, Node) -> node_default:get_items(Host, Node). +get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) + node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + get_item(Host, Node, ItemId) -> node_default:get_item(Host, Node, ItemId). +get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + set_item(Item) -> node_default:set_item(Item). diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl index cdf3a696f..cd051b66f 100644 --- a/src/mod_pubsub/node_buddy.erl +++ b/src/mod_pubsub/node_buddy.erl @@ -62,7 +62,9 @@ get_states/2, get_state/3, set_state/1, + get_items/7, get_items/2, + get_item/8, get_item/3, set_item/1, get_item_name/3 @@ -172,9 +174,15 @@ set_state(State) -> get_items(Host, Node) -> node_default:get_items(Host, Node). +get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + get_item(Host, Node, ItemId) -> node_default:get_item(Host, Node, ItemId). +get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + set_item(Item) -> node_default:set_item(Item). diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl index d927053fb..155edc10a 100644 --- a/src/mod_pubsub/node_club.erl +++ b/src/mod_pubsub/node_club.erl @@ -62,7 +62,9 @@ get_states/2, get_state/3, set_state/1, + get_items/7, get_items/2, + get_item/8, get_item/3, set_item/1, get_item_name/3 @@ -96,7 +98,6 @@ features() -> ["create-nodes", "delete-nodes", "instant-nodes", - "item-ids", "outcast-affiliation", "persistent-items", "publish", @@ -172,9 +173,15 @@ set_state(State) -> get_items(Host, Node) -> node_default:get_items(Host, Node). +get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + get_item(Host, Node, ItemId) -> node_default:get_item(Host, Node, ItemId). +get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + set_item(Item) -> node_default:set_item(Item). diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index fc4194c32..491676269 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -69,7 +69,9 @@ get_states/2, get_state/3, set_state/1, + get_items/7, get_items/2, + get_item/8, get_item/3, set_item/1, get_item_name/3 @@ -158,7 +160,6 @@ features() -> "auto-create", "delete-nodes", "instant-nodes", - "item-ids", "manage-subscriptions", "modify-affiliations", "outcast-affiliation", @@ -192,18 +193,14 @@ features() -> %% module by implementing this function like this: %% ```check_create_user_permission(Host, Node, Owner, Access) -> %% node_default:check_create_user_permission(Host, Node, Owner, Access).'''

      -create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) -> +create_node_permission(_Host, ServerHost, Node, _ParentNode, Owner, Access) -> LOwner = jlib:jid_tolower(Owner), {User, Server, _Resource} = LOwner, Allowed = case acl:match_rule(ServerHost, Access, LOwner) of allow -> - if Server == Host -> %% Server == ServerHost ?? - true; - true -> - case Node of - ["home", Server, User | _] -> true; - _ -> false - end + case Node of + ["home", Server, User | _] -> true; + _ -> false end; _ -> case Owner of @@ -211,8 +208,7 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) -> _ -> false end end, - ChildOK = true, %% TODO test with ParentNode - {result, Allowed and ChildOK}. + {result, Allowed}. %% @spec (Host, Node, Owner) -> %% {result, Result} | exit @@ -297,12 +293,12 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel, not Authorized -> %% JIDs do not match {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "invalid-jid")}; - Subscription == pending -> - %% Requesting entity has pending subscription - {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "pending-subscription")}; Affiliation == outcast -> %% Requesting entity is blocked {error, ?ERR_FORBIDDEN}; + Subscription == pending -> + %% Requesting entity has pending subscription + {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "pending-subscription")}; (AccessModel == presence) and (not PresenceSubscription) -> %% Entity is not authorized to create a subscription (presence subscription required) {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "presence-subscription-required")}; @@ -446,6 +442,7 @@ publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) -> {error, ?ERR_FORBIDDEN}; true -> PubId = {PublisherKey, now()}, + %% TODO: check creation, presence, roster (EJAB-663) Item = case get_item(Host, Node, ItemId) of {error, ?ERR_ITEM_NOT_FOUND} -> #pubsub_item{itemid = {ItemId, {Host, Node}}, @@ -501,7 +498,7 @@ remove_extra_items(Host, Node, MaxItems, ItemIds) -> %% ItemId = string() %% @doc

      Triggers item deletion.

      %%

      Default plugin: The user performing the deletion must be the node owner -%% or a node publisher e item publisher.

      +%% or a publisher.

      delete_item(Host, Node, Publisher, ItemId) -> PublisherKey = jlib:jid_tolower(jlib:jid_remove_resource(Publisher)), State = case get_state(Host, Node, PublisherKey) of @@ -542,17 +539,16 @@ delete_item(Host, Node, Publisher, ItemId) -> purge_node(Host, Node, Owner) -> OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), case get_state(Host, Node, OwnerKey) of - {error, ?ERR_ITEM_NOT_FOUND} -> - %% This should not append (case node does not exists) - {error, ?ERR_ITEM_NOT_FOUND}; {result, #pubsub_state{items = Items, affiliation = owner}} -> lists:foreach(fun(ItemId) -> mnesia:delete({pubsub_item, {ItemId, {Host, Node}}}) end, Items), {result, {default, broadcast}}; + {result, _} -> + %% Entity is not owner + {error, ?ERR_FORBIDDEN}; _ -> - %% Entity is not an owner - {error, ?ERR_FORBIDDEN} + {error, ?ERR_ITEM_NOT_FOUND} end. %% @spec (Host, JID) -> [{Node,Affiliation}] @@ -588,7 +584,7 @@ get_affiliation(Host, Node, Owner) -> OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), Affiliation = case get_state(Host, Node, OwnerKey) of {result, #pubsub_state{affiliation = A}} -> A; - _ -> unknown + _ -> none end, {result, Affiliation}. @@ -638,7 +634,7 @@ get_subscription(Host, Node, Owner) -> OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), Subscription = case get_state(Host, Node, OwnerKey) of {result, #pubsub_state{subscription = S}} -> S; - _ -> unknown + _ -> none end, {result, Subscription}. @@ -713,6 +709,44 @@ get_items(Host, Node) -> Items = mnesia:match_object( #pubsub_item{itemid = {'_', {Host, Node}}, _ = '_'}), {result, Items}. +get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> + {Affiliation, Subscription} = + case get_state(Host, Node, jlib:jid_tolower(jlib:jid_remove_resource(JID))) of + {result, #pubsub_state{affiliation = A, subscription = S}} -> {A, S}; + _ -> {none, none} + end, + Subscribed = not ((Subscription == none) or (Subscription == pending)), + if + %%SubID == "", ?? -> + %% Entity has multiple subscriptions to the node but does not specify a subscription ID + %{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}; + %%InvalidSubID -> + %% Entity is subscribed but specifies an invalid subscription ID + %{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; + Affiliation == outcast -> + %% Requesting entity is blocked + {error, ?ERR_FORBIDDEN}; + (AccessModel == open) and (not Subscribed) -> + %% Entity is not subscribed + {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "not-subscribed")}; + (AccessModel == presence) and (not PresenceSubscription) -> + %% Entity is not authorized to create a subscription (presence subscription required) + {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "presence-subscription-required")}; + (AccessModel == roster) and (not RosterGroup) -> + %% Entity is not authorized to create a subscription (not in roster group) + {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "not-in-roster-group")}; + (AccessModel == whitelist) -> % TODO: to be done + %% Node has whitelist access model + {error, ?ERR_EXTENDED(?ERR_NOT_ALLOWED, "closed-node")}; + (AccessModel == authorize) -> % TODO: to be done + %% Node has authorize access model + {error, ?ERR_FORBIDDEN}; + %%MustPay -> + %% % Payment is required for a subscription + %% {error, ?ERR_PAYMENT_REQUIRED}; + true -> + get_items(Host, Node) + end. %% @spec (Host, Node, ItemId) -> [Item] | [] %% Host = mod_pubsub:host() @@ -727,6 +761,44 @@ get_item(Host, Node, ItemId) -> _ -> {error, ?ERR_ITEM_NOT_FOUND} end. +get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> + {Affiliation, Subscription} = + case get_state(Host, Node, jlib:jid_tolower(jlib:jid_remove_resource(JID))) of + {result, #pubsub_state{affiliation = A, subscription = S}} -> {A, S}; + _ -> {none, none} + end, + Subscribed = not ((Subscription == none) or (Subscription == pending)), + if + %%SubID == "", ?? -> + %% Entity has multiple subscriptions to the node but does not specify a subscription ID + %{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}; + %%InvalidSubID -> + %% Entity is subscribed but specifies an invalid subscription ID + %{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; + Affiliation == outcast -> + %% Requesting entity is blocked + {error, ?ERR_FORBIDDEN}; + (AccessModel == open) and (not Subscribed) -> + %% Entity is not subscribed + {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "not-subscribed")}; + (AccessModel == presence) and (not PresenceSubscription) -> + %% Entity is not authorized to create a subscription (presence subscription required) + {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "presence-subscription-required")}; + (AccessModel == roster) and (not RosterGroup) -> + %% Entity is not authorized to create a subscription (not in roster group) + {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "not-in-roster-group")}; + (AccessModel == whitelist) -> % TODO: to be done + %% Node has whitelist access model + {error, ?ERR_EXTENDED(?ERR_NOT_ALLOWED, "closed-node")}; + (AccessModel == authorize) -> % TODO: to be done + %% Node has authorize access model + {error, ?ERR_FORBIDDEN}; + %%MustPay -> + %% % Payment is required for a subscription + %% {error, ?ERR_PAYMENT_REQUIRED}; + true -> + get_item(Host, Node, ItemId) + end. %% @spec (Item) -> ok | {error, Reason::stanzaError()} %% Item = mod_pubsub:pubsubItems() diff --git a/src/mod_pubsub/node_dispatch.erl b/src/mod_pubsub/node_dispatch.erl index 3b4418c3e..0532826d2 100644 --- a/src/mod_pubsub/node_dispatch.erl +++ b/src/mod_pubsub/node_dispatch.erl @@ -60,7 +60,9 @@ get_states/2, get_state/3, set_state/1, + get_items/7, get_items/2, + get_item/8, get_item/3, set_item/1, get_item_name/3 @@ -94,7 +96,6 @@ features() -> ["create-nodes", "delete-nodes", "instant-nodes", - "item-ids", "outcast-affiliation", "persistent-items", "publish", @@ -175,9 +176,15 @@ set_state(State) -> get_items(Host, Node) -> node_default:get_items(Host, Node). +get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + get_item(Host, Node, ItemId) -> node_default:get_item(Host, Node, ItemId). +get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + set_item(Item) -> node_default:set_item(Item). diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index 97bf1b2fa..2c648148d 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -29,6 +29,7 @@ -module(node_pep). -author('christophe.romain@process-one.net'). +-include("ejabberd.hrl"). -include("pubsub.hrl"). -include("jlib.hrl"). @@ -57,7 +58,9 @@ get_states/2, get_state/3, set_state/1, + get_items/7, get_items/2, + get_item/8, get_item/3, set_item/1, get_item_name/3 @@ -65,6 +68,7 @@ init(Host, ServerHost, Opts) -> node_default:init(Host, ServerHost, Opts), + complain_if_modcaps_disabled(ServerHost), ok. terminate(Host, ServerHost) -> @@ -94,7 +98,6 @@ features() -> "auto-subscribe", %* "delete-nodes", %* "filtered-notifications", %* - "item-ids", "modify-affiliations", "outcast-affiliation", "persistent-items", @@ -183,7 +186,7 @@ get_node_subscriptions(_Host, _Node) -> {result, []}. get_subscription(_Host, _Node, _Owner) -> - {result, unknown}. + {result, none}. set_subscription(_Host, _Node, _Owner, _Subscription) -> ok. @@ -200,11 +203,39 @@ set_state(State) -> get_items(Host, Node) -> node_default:get_items(Host, Node). +get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + get_item(Host, Node, ItemId) -> node_default:get_item(Host, Node, ItemId). +get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + set_item(Item) -> node_default:set_item(Item). get_item_name(Host, Node, Id) -> node_default:get_item_name(Host, Node, Id). + + +%%% +%%% Internal +%%% + +%% @doc Check mod_caps is enabled, otherwise show warning. +%% The PEP plugin for mod_pubsub requires mod_caps to be enabled in the host. +%% Check that the mod_caps module is enabled in that Jabber Host +%% If not, show a warning message in the ejabberd log file. +complain_if_modcaps_disabled(ServerHost) -> + Modules = ejabberd_config:get_local_option({modules, ServerHost}), + ModCaps = [mod_caps_enabled || {mod_caps, _Opts} <- Modules], + case ModCaps of + [] -> + ?WARNING_MSG("The PEP plugin is enabled in mod_pubsub of host ~p. " + "This plugin requires mod_caps to be enabled, " + "but it isn't.", [ServerHost]); + _ -> + ok + end. + diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl index 35f63c925..00e952392 100644 --- a/src/mod_pubsub/node_private.erl +++ b/src/mod_pubsub/node_private.erl @@ -62,7 +62,9 @@ get_states/2, get_state/3, set_state/1, + get_items/7, get_items/2, + get_item/8, get_item/3, set_item/1, get_item_name/3 @@ -96,7 +98,6 @@ features() -> ["create-nodes", "delete-nodes", "instant-nodes", - "item-ids", "outcast-affiliation", "persistent-items", "publish", @@ -175,9 +176,15 @@ set_state(State) -> get_items(Host, Node) -> node_default:get_items(Host, Node). +get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + get_item(Host, Node, ItemId) -> node_default:get_item(Host, Node, ItemId). +get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + set_item(Item) -> node_default:set_item(Item). diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl index 1586abe86..ab4107a76 100644 --- a/src/mod_pubsub/node_public.erl +++ b/src/mod_pubsub/node_public.erl @@ -62,7 +62,9 @@ get_states/2, get_state/3, set_state/1, + get_items/7, get_items/2, + get_item/8, get_item/3, set_item/1, get_item_name/3 @@ -96,7 +98,6 @@ features() -> ["create-nodes", "delete-nodes", "instant-nodes", - "item-ids", "outcast-affiliation", "persistent-items", "publish", @@ -172,9 +173,15 @@ set_state(State) -> get_items(Host, Node) -> node_default:get_items(Host, Node). +get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + get_item(Host, Node, ItemId) -> node_default:get_item(Host, Node, ItemId). +get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + set_item(Item) -> node_default:set_item(Item). diff --git a/src/mod_pubsub/node_zoo.erl b/src/mod_pubsub/node_zoo.erl new file mode 100644 index 000000000..45e601ed7 --- /dev/null +++ b/src/mod_pubsub/node_zoo.erl @@ -0,0 +1,181 @@ +%%% ==================================================================== +%%% ``The contents of this file are subject to the Erlang Public License, +%%% Version 1.1, (the "License"); you may not use this file except in +%%% compliance with the License. You should have received a copy of the +%%% Erlang Public License along with this software. If not, it can be +%%% retrieved via the world wide web at http://www.erlang.org/. +%%% +%%% Software distributed under the License is distributed on an "AS IS" +%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%%% the License for the specific language governing rights and limitations +%%% under the License. +%%% +%%% The Initial Developer of the Original Code is Process-one. +%%% Portions created by Process-one are Copyright 2006-2008, Process-one +%%% All Rights Reserved.'' +%%% This software is copyright 2006-2008, Process-one. +%%% +%%% @copyright 2006-2008 Process-one +%%% @author Christophe romain +%%% [http://www.process-one.net/] +%%% @version {@vsn}, {@date} {@time} +%%% @end +%%% ==================================================================== + +-module(node_zoo). +-author('christophe.romain@process-one.net'). + +-include("pubsub.hrl"). +-include("jlib.hrl"). + +-behaviour(gen_pubsub_node). + +%% API definition +-export([init/3, terminate/2, + options/0, features/0, + create_node_permission/6, + create_node/3, + delete_node/2, + purge_node/3, + subscribe_node/8, + unsubscribe_node/5, + publish_item/7, + delete_item/4, + remove_extra_items/4, + get_entity_affiliations/2, + get_node_affiliations/2, + get_affiliation/3, + set_affiliation/4, + get_entity_subscriptions/2, + get_node_subscriptions/2, + get_subscription/3, + set_subscription/4, + get_states/2, + get_state/3, + set_state/1, + get_items/7, + get_items/2, + get_item/8, + get_item/3, + set_item/1, + get_item_name/3 + ]). + + +init(Host, ServerHost, Opts) -> + node_default:init(Host, ServerHost, Opts). + +terminate(Host, ServerHost) -> + node_default:terminate(Host, ServerHost). + +options() -> + [{node_type, zoo}, + {deliver_payloads, true}, + {notify_config, false}, + {notify_delete, false}, + {notify_retract, true}, + {persist_items, true}, + {max_items, ?MAXITEMS div 2}, + {subscribe, true}, + {access_model, open}, + {roster_groups_allowed, []}, + {publish_model, publishers}, + {max_payload_size, ?MAX_PAYLOAD_SIZE}, + {send_last_published_item, never}, + {deliver_notifications, true}, + {presence_based_delivery, false}]. + +features() -> + node_default:features(). + +%% use same code as node_default, but do not limite node to +%% the home/localhost/user/... hierarchy +%% any node is allowed +create_node_permission(_Host, ServerHost, _Node, _ParentNode, Owner, Access) -> + LOwner = jlib:jid_tolower(Owner), + %%{_User, _Server, _Resource} = LOwner, + Allowed = case acl:match_rule(ServerHost, Access, LOwner) of + allow -> + true; + _ -> + case Owner of + {jid, "", _, "", "", _, ""} -> true; + _ -> false + end + end, + {result, Allowed}. + +create_node(Host, Node, Owner) -> + node_default:create_node(Host, Node, Owner). + +delete_node(Host, Removed) -> + node_default:delete_node(Host, Removed). + +subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> + node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). + +unsubscribe_node(Host, Node, Sender, Subscriber, SubID) -> + node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID). + +publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) -> + node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload). + +remove_extra_items(Host, Node, MaxItems, ItemIds) -> + node_default:remove_extra_items(Host, Node, MaxItems, ItemIds). + +delete_item(Host, Node, JID, ItemId) -> + node_default:delete_item(Host, Node, JID, ItemId). + +purge_node(Host, Node, Owner) -> + node_default:purge_node(Host, Node, Owner). + +get_entity_affiliations(Host, Owner) -> + node_default:get_entity_affiliations(Host, Owner). + +get_node_affiliations(Host, Node) -> + node_default:get_node_affiliations(Host, Node). + +get_affiliation(Host, Node, Owner) -> + node_default:get_affiliation(Host, Node, Owner). + +set_affiliation(Host, Node, Owner, Affiliation) -> + node_default:set_affiliation(Host, Node, Owner, Affiliation). + +get_entity_subscriptions(Host, Owner) -> + node_default:get_entity_subscriptions(Host, Owner). + +get_node_subscriptions(Host, Node) -> + node_default:get_node_subscriptions(Host, Node). + +get_subscription(Host, Node, Owner) -> + node_default:get_subscription(Host, Node, Owner). + +set_subscription(Host, Node, Owner, Subscription) -> + node_default:set_subscription(Host, Node, Owner, Subscription). + +get_states(Host, Node) -> + node_default:get_states(Host, Node). + +get_state(Host, Node, JID) -> + node_default:get_state(Host, Node, JID). + +set_state(State) -> + node_default:set_state(State). + +get_items(Host, Node) -> + node_default:get_items(Host, Node). + +get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + +get_item(Host, Node, ItemId) -> + node_default:get_item(Host, Node, ItemId). + +get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + +set_item(Item) -> + node_default:set_item(Item). + +get_item_name(Host, Node, Id) -> + node_default:get_item_name(Host, Node, Id). diff --git a/src/mod_register.erl b/src/mod_register.erl index a936ea5e1..21080c8a2 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -241,12 +241,13 @@ send_welcome_message(JID) -> {"", ""} -> ok; {Subj, Body} -> + BodyFormatted = io_lib:format(Body, []), ejabberd_router:route( jlib:make_jid("", Host, ""), JID, {xmlelement, "message", [{"type", "normal"}], [{xmlelement, "subject", [], [{xmlcdata, Subj}]}, - {xmlelement, "body", [], [{xmlcdata, Body}]}]}); + {xmlelement, "body", [], [{xmlcdata, BodyFormatted}]}]}); _ -> ok end. diff --git a/src/mod_roster.erl b/src/mod_roster.erl index f1f59665a..038de586a 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -40,6 +40,7 @@ set_items/3, remove_user/2, get_jid_info/4, + item_to_xml/1, webadmin_page/3, webadmin_user/4]). diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 7b8558cf5..ff378010d 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -155,12 +155,12 @@ get_user_roster(Items, US) -> {{U1, S1}, GroupNames} <- dict:to_list(SRUsersRest)], SRItems ++ NewItems1. -%% This function in use to rewrite the roster entries when moving or renaming +%% This function rewrites the roster entries when moving or renaming %% them in the user contact list. process_item(RosterItem, Host) -> - USFrom = RosterItem#roster.us, - {User,Server,_Resource} = RosterItem#roster.jid, - USTo = {User,Server}, + USFrom = {UserFrom, ServerFrom} = RosterItem#roster.us, + {UserTo, ServerTo, ResourceTo} = RosterItem#roster.jid, + USTo = {UserTo, ServerTo}, DisplayedGroups = get_user_displayed_groups(USFrom), CommonGroups = lists:filter(fun(Group) -> is_user_in_group(USTo, Group, Host) @@ -174,9 +174,83 @@ process_item(RosterItem, Host) -> end, CommonGroups), RosterItem#roster{subscription = both, ask = none, groups=[GroupNames]}; - _ -> RosterItem#roster{subscription = both, ask = none} + %% Both users have at least a common shared group, + %% So each user can see the other + _ -> + %% Check if the list of groups of the new roster item + %% include at least a new one + case lists:subtract(RosterItem#roster.groups, CommonGroups) of + [] -> + RosterItem#roster{subscription = both, ask = none}; + %% If so, it means the user wants to add that contact + %% to his personal roster + PersonalGroups -> + %% Store roster items in From and To rosters + set_new_rosteritems(UserFrom, ServerFrom, + UserTo, ServerTo, ResourceTo, + PersonalGroups) + end end. +build_roster_record(User1, Server1, User2, Server2, Groups) -> + USR2 = {User2, Server2, ""}, + #roster{usj = {User1, Server1, USR2}, + us = {User1, Server1}, + jid = USR2, + name = User2, + subscription = both, + ask = none, + groups = Groups + }. + +set_new_rosteritems(UserFrom, ServerFrom, + UserTo, ServerTo, ResourceTo, GroupsFrom) -> + Mod = case lists:member(mod_roster_odbc, + gen_mod:loaded_modules(ServerFrom)) of + true -> mod_roster_odbc; + false -> mod_roster + end, + + RIFrom = build_roster_record(UserFrom, ServerFrom, + UserTo, ServerTo, GroupsFrom), + set_item(UserFrom, ServerFrom, ResourceTo, RIFrom), + JIDTo = jlib:make_jid(UserTo, ServerTo, ""), + + JIDFrom = jlib:make_jid(UserFrom, ServerFrom, ""), + RITo = build_roster_record(UserTo, ServerTo, + UserFrom, ServerFrom, []), + set_item(UserTo, ServerTo, "", RITo), + + %% From requests + Mod:out_subscription(UserFrom, ServerFrom, JIDTo, subscribe), + Mod:in_subscription(aaa, UserTo, ServerTo, JIDFrom, subscribe, ""), + + %% To accepts + Mod:out_subscription(UserTo, ServerTo, JIDFrom, subscribed), + Mod:in_subscription(aaa, UserFrom, ServerFrom, JIDTo, subscribed, ""), + + %% To requests + Mod:out_subscription(UserTo, ServerTo, JIDFrom, subscribe), + Mod:in_subscription(aaa, UserFrom, ServerFrom, JIDTo, subscribe, ""), + + %% From accepts + Mod:out_subscription(UserFrom, ServerFrom, JIDTo, subscribed), + Mod:in_subscription(aaa, UserTo, ServerTo, JIDFrom, subscribed, ""), + + RIFrom. + +set_item(User, Server, Resource, Item) -> + ResIQ = #iq{type = set, xmlns = ?NS_ROSTER, + id = "push", + sub_el = [{xmlelement, "query", + [{"xmlns", ?NS_ROSTER}], + [mod_roster:item_to_xml(Item)]}]}, + ejabberd_router:route( + jlib:make_jid(User, Server, Resource), + jlib:make_jid("", Server, ""), + jlib:iq_to_xml(ResIQ)). + + get_subscription_lists({F, T}, User, Server) -> LUser = jlib:nodeprep(User), LServer = jlib:nameprep(Server), @@ -414,10 +488,10 @@ get_user_displayed_groups(US) -> end, get_user_groups(US))), [Group || Group <- DisplayedGroups1, is_group_enabled(Host, Group)]. -is_user_in_group(US, Group, Host) -> +is_user_in_group({_U, S} = US, Group, Host) -> case catch mnesia:dirty_match_object( #sr_user{us=US, group_host={Group, Host}}) of - [] -> false; + [] -> lists:member(US, get_group_users(S, Group)); _ -> true end. diff --git a/src/web/ejabberd_http.erl b/src/web/ejabberd_http.erl index a53910803..34eeef739 100644 --- a/src/web/ejabberd_http.erl +++ b/src/web/ejabberd_http.erl @@ -271,13 +271,14 @@ process(Handlers, Request) -> process(HandlersLeft, Request) end. -process_request(#state{request_method = 'GET', +process_request(#state{request_method = Method, request_path = {abs_path, Path}, request_auth = Auth, request_lang = Lang, request_handlers = RequestHandlers, sockmod = SockMod, - socket = Socket} = State) -> + socket = Socket} = State) + when Method=:='GET' orelse Method=:='HEAD' orelse Method=:='DELETE' -> case (catch url_decode_q_split(Path)) of {'EXIT', _} -> process_request(false); @@ -289,19 +290,19 @@ process_request(#state{request_method = 'GET', LQ end, LPath = string:tokens(NPath, "/"), - {ok, {IP, _Port}} = + {ok, IP} = case SockMod of gen_tcp -> inet:peername(Socket); _ -> SockMod:peername(Socket) end, - Request = #request{method = 'GET', + Request = #request{method = Method, path = LPath, q = LQuery, auth = Auth, lang = Lang, - ip=IP}, + ip = IP}, %% XXX bard: This previously passed control to %% ejabberd_web:process_get, now passes it to a local %% procedure (process) that handles dispatching based on @@ -319,7 +320,7 @@ process_request(#state{request_method = 'GET', end end; -process_request(#state{request_method = 'POST', +process_request(#state{request_method = Method, request_path = {abs_path, Path}, request_auth = Auth, request_content_length = Len, @@ -327,7 +328,7 @@ process_request(#state{request_method = 'POST', sockmod = SockMod, socket = Socket, request_handlers = RequestHandlers} = State) - when is_integer(Len) -> + when (Method=:='POST' orelse Method=:='PUT') andalso is_integer(Len) -> case SockMod of gen_tcp -> inet:setopts(Socket, [{packet, 0}]); @@ -347,12 +348,20 @@ process_request(#state{request_method = 'POST', LQ -> LQ end, - Request = #request{method = 'POST', + {ok, IP} = + case SockMod of + gen_tcp -> + inet:peername(Socket); + _ -> + SockMod:peername(Socket) + end, + Request = #request{method = Method, path = LPath, q = LQuery, auth = Auth, data = Data, - lang = Lang}, + lang = Lang, + ip = IP}, case process(RequestHandlers, Request) of El when element(1, El) == xmlelement -> make_xhtml_output(State, 200, [], El); diff --git a/src/web/ejabberd_http_poll.erl b/src/web/ejabberd_http_poll.erl index f5b419275..ad6c46b77 100644 --- a/src/web/ejabberd_http_poll.erl +++ b/src/web/ejabberd_http_poll.erl @@ -50,13 +50,16 @@ -record(http_poll, {id, pid}). +-define(NULL_PEER, {{0, 0, 0, 0}, 0}). + -record(state, {id, key, output = "", input = "", waiting_input = false, %% {ReceiverPid, Tag} last_receiver, - timer}). + timer, + ip = ?NULL_PEER }). %-define(DBGFSM, true). @@ -94,11 +97,16 @@ setopts({http_poll, FsmRef}, Opts) -> ok end. -sockname(_Socket) -> - {ok, {{0, 0, 0, 0}, 0}}. +sockname(_) -> + {ok, ?NULL_PEER}. -peername(_Socket) -> - {ok, {{0, 0, 0, 0}, 0}}. +peername({http_poll, FsmRef}) -> + case catch gen_fsm:sync_send_all_state_event(FsmRef, peername, 1000) of + {ok, IP} -> {ok, IP}; + _ -> {ok, ?NULL_PEER} + end; +peername(_) -> + {ok, ?NULL_PEER}. controlling_process(_Socket, _Pid) -> ok. @@ -107,7 +115,7 @@ close({http_poll, FsmRef}) -> catch gen_fsm:sync_send_all_state_event(FsmRef, close). -process([], #request{data = Data} = _Request) -> +process([], #request{data = Data, ip = IP} = _Request) -> case catch parse_request(Data) of {ok, ID1, Key, NewKey, Packet} -> ID = if @@ -123,7 +131,7 @@ process([], #request{data = Data} = _Request) -> true -> ID1 end, - case http_put(ID, Key, NewKey, Packet) of + case http_put(ID, Key, NewKey, Packet, IP) of {error, not_exists} -> {200, ?BAD_REQUEST, ""}; {error, bad_key} -> @@ -249,7 +257,7 @@ handle_sync_event(stop, _From, _StateName, StateData) -> Reply = ok, {stop, normal, Reply, StateData}; -handle_sync_event({http_put, Key, NewKey, Packet}, +handle_sync_event({http_put, Key, NewKey, Packet, IP}, _From, StateName, StateData) -> Allow = case StateData#state.key of "" -> @@ -271,7 +279,8 @@ handle_sync_event({http_put, Key, NewKey, Packet}, Input = [StateData#state.input|Packet], Reply = ok, {reply, Reply, StateName, StateData#state{input = Input, - key = NewKey}}; + key = NewKey, + ip = IP}}; {Receiver, _Tag} -> Receiver ! {tcp, {http_poll, self()}, list_to_binary(Packet)}, @@ -282,7 +291,8 @@ handle_sync_event({http_put, Key, NewKey, Packet}, StateData#state{waiting_input = false, last_receiver = Receiver, key = NewKey, - timer = Timer}} + timer = Timer, + ip = IP}} end; true -> Reply = {error, bad_key}, @@ -293,6 +303,10 @@ handle_sync_event(http_get, _From, StateName, StateData) -> Reply = {ok, StateData#state.output}, {reply, Reply, StateName, StateData#state{output = ""}}; +handle_sync_event(peername, _From, StateName, StateData) -> + Reply = {ok, StateData#state.ip}, + {reply, Reply, StateName, StateData}; + handle_sync_event(_Event, _From, StateName, StateData) -> Reply = ok, {reply, Reply, StateName, StateData}. @@ -343,13 +357,13 @@ terminate(_Reason, _StateName, StateData) -> %%% Internal functions %%%---------------------------------------------------------------------- -http_put(ID, Key, NewKey, Packet) -> +http_put(ID, Key, NewKey, Packet, IP) -> case mnesia:dirty_read({http_poll, ID}) of [] -> {error, not_exists}; [#http_poll{pid = FsmRef}] -> gen_fsm:sync_send_all_state_event( - FsmRef, {http_put, Key, NewKey, Packet}) + FsmRef, {http_put, Key, NewKey, Packet, IP}) end. http_get(ID) -> diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index abc1ac871..d133fa14d 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -2022,7 +2022,7 @@ node_backup_parse_query(Node, Query) -> rpc:call(Node, mnesia, install_fallback, [Path]); "dump" -> - rpc:call(Node, mnesia, + rpc:call(Node, ejabberd_ctl, dump_to_textfile, [Path]); "load" -> rpc:call(Node, mnesia, diff --git a/tools/ejabberdctl b/tools/ejabberdctl index 9d3f7bd5a..c821e8081 100755 --- a/tools/ejabberdctl +++ b/tools/ejabberdctl @@ -4,7 +4,8 @@ NODE=ejabberd HOST=localhost # Define ejabberd environment -base="`dirname $(which "$0")`/.." +here=`which "$0" 2>/dev/null || echo .` +base="`dirname $here`/.." ROOTDIR=`(cd "$base"; echo $PWD)` SASL_LOG_PATH=$ROOTDIR/sasl.log EJABBERD_DB=$ROOTDIR/database/$NODE From 574dbbfd08378de06e47763956e8b3dff5dce47f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 15 Jul 2008 08:45:05 +0000 Subject: [PATCH 042/582] Merge revisions from 1434 to revision 1444 from trunk. SVN Revision: 1445 --- ChangeLog | 63 +++++++ doc/Makefile | 2 +- doc/guide.html | 63 ++++--- doc/guide.tex | 64 ++++--- {src => include}/adhoc.hrl | 0 {src => include}/ejabberd.hrl | 0 {src => include}/ejabberd_config.hrl | 0 {src => include}/ejabberd_ctl.hrl | 0 {src/web => include}/ejabberd_http.hrl | 0 {src/web => include}/ejabberd_web_admin.hrl | 0 {src/eldap => include}/eldap.hrl | 0 {src => include}/jlib.hrl | 0 {src => include}/mod_privacy.hrl | 0 {src/mod_proxy65 => include}/mod_proxy65.hrl | 0 {src => include}/mod_roster.hrl | 0 {src/mod_pubsub => include}/pubsub.hrl | 0 src/Makefile.in | 171 +++++++++++++++---- src/aclocal.m4 | 15 +- src/configure | 150 +++++++++++----- src/configure.ac | 26 ++- src/ejabberd.cfg.example | 2 +- src/ejabberd_auth_ldap.erl | 2 +- src/ejabberd_zlib/Makefile.in | 3 +- src/ejabberdctl.template | 98 ++++++----- src/eldap/Makefile.in | 3 +- src/mod_irc/Makefile.in | 4 +- src/mod_muc/Makefile.in | 4 +- src/mod_offline.erl | 4 +- src/mod_offline_odbc.erl | 4 +- src/mod_proxy65/Makefile.in | 4 +- src/mod_proxy65/mod_proxy65_service.erl | 4 +- src/mod_proxy65/mod_proxy65_stream.erl | 2 +- src/mod_pubsub/Makefile.in | 4 +- src/mod_register.erl | 3 +- src/mod_roster.erl | 4 +- src/mod_roster_odbc.erl | 4 +- src/mod_shared_roster.erl | 4 +- src/mod_vcard_ldap.erl | 2 +- src/odbc/Makefile.in | 4 +- src/pam/Makefile.in | 4 +- src/tls/Makefile.in | 4 +- src/web/Makefile.in | 6 +- 42 files changed, 525 insertions(+), 202 deletions(-) rename {src => include}/adhoc.hrl (100%) rename {src => include}/ejabberd.hrl (100%) rename {src => include}/ejabberd_config.hrl (100%) rename {src => include}/ejabberd_ctl.hrl (100%) rename {src/web => include}/ejabberd_http.hrl (100%) rename {src/web => include}/ejabberd_web_admin.hrl (100%) rename {src/eldap => include}/eldap.hrl (100%) rename {src => include}/jlib.hrl (100%) rename {src => include}/mod_privacy.hrl (100%) rename {src/mod_proxy65 => include}/mod_proxy65.hrl (100%) rename {src => include}/mod_roster.hrl (100%) rename {src/mod_pubsub => include}/pubsub.hrl (100%) diff --git a/ChangeLog b/ChangeLog index 72fe05cb9..ae52d1fa1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,66 @@ +2008-07-15 Jean-Sébastien Pédron + + Merge revisions from 1434 to revision 1444 from trunk. + + * configure: Recreated with autoconf(1) after merge. + +2008-07-14 Badlop + + * doc/guide.tex: Update what permissions does enable-user grant + * doc/guide.html: Likewise + + * src/configure.ac: Don't explicitely put root privileges when a + user is not explicitely enabled + * src/configure: Likewise + * src/Makefile.in: Likewise + + * src/Makefile.in: Fix docdir so it recognizes prefix. If sbin dir + does not exist, create it. Fix cookiefile permission + check. (EJAB-696) + +2008-07-13 Badlop + + * src/configure.ac: Update installation permissions (EJAB-402) + * src/configure: Likewise + + * src/Makefile.in: The mnesia, ebin and priv dirs are now + installed in different locations. Install header files and + documentation (EJAB-696) + * doc/guide.tex: Likewise + * doc/guide.html: Likewise + + * include/*.hrl: Place for all ejabberd header files (EJAB-696) + * src/*/*.erl: Update references to header files + * src/*/Makefile.in: Include the include/ dir + + * src/configure.ac: Allow to execute ejabberd with a normal + system user (thanks to Viq)(EJAB-402) + * src/configure: Likewise + * src/ejabberdctl.template: Likewise + * src/Makefile.in: Likewise + * doc/guide.tex: Likewise + * doc/guide.html: Likewise + +2008-07-12 Badlop + + * src/configure.ac: Improve legibility + * src/aclocal.m4: Likewise + * src/configure: Likewise + + * src/ejabberdctl.template: Remove garbage variable. Document node + option + + * doc/guide.tex: Add references to sections. + * doc/guide.html: Likewise + +2008-07-11 Badlop + + * src/mod_register.erl: Revert support for io_lib newline, since + there is a standard character that representes newline (EJAB-501) + * doc/guide.tex: Update documentation to explain newline character + * doc/guide.html: Likewise + * src/ejabberd.cfg.example: Likewise + 2008-07-11 Jean-Sébastien Pédron Merge revisions from 1362 to revision 1434 from trunk. diff --git a/doc/Makefile b/doc/Makefile index c1f35fdff..2fda395a0 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -16,7 +16,7 @@ all: release pdf html release: @echo "Notes for the releaser:" @echo "* Do not forget to add a link to the release notes in guide.tex" - @echo "* Do not forget to update the version number in src/ejabberd.hrl!" + @echo "* Do not forget to update the version number in src/ejabberd.app!" @echo "* Do not forget to update the features in introduction.tex (including \new{} and \improved{} tags)." @echo "Press any key to continue" @read foo diff --git a/doc/guide.html b/doc/guide.html index b7f10839b..735fc1f8c 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -333,14 +333,24 @@ Alternatively, the latest development version can be retrieved from the Subversi

      To compile ejabberd execute the commands:

      ./configure
       make
      -

      The build configuration script provides several parameters. +

      The build configuration script allows several options. To get the full list run the command:

      ./configure --help
       

      Some options that you may be interested in modifying:

      --prefix=/
      - Specify the path prefix where the files will be copied when running the make install command.

      --enable-pam
      - Enable the PAM authentication method.

      --enable-odbc or --enable-mssql
      + Specify the path prefix where the files will be copied when running + the make install command.

      --enable-user[=USER]
      + Allow this normal system user to execute the ejabberdctl script + (see section 4.1), + read the configuration files, + read and write in the spool directory, + read and write in the log directory. + The account user and group must exist in the machine + before running make install. + This account doesn’t need an explicit HOME directory, because + /var/lib/ejabberd/ will be used by default.

      --enable-pam
      + Enable the PAM authentication method (see section 3.1.4).

      --enable-odbc or --enable-mssql
      Required if you want to use an external database. See section 3.2 for more information.

      --enable-full-xml
      Enable the use of XML based optimisations. @@ -351,34 +361,43 @@ To get the full list run the command:

      2.4.4  Install

      To install ejabberd in the destination directories, run the command:

      make install
      -

      Note that you may need to have administrative privileges in the system.

      The files and directories created are, by default: +

      Note that you probably need administrative privileges in the system +to install ejabberd.

      The files and directories created are, by default:

      - /etc/ejabberd/
      Configuration files: + /etc/ejabberd/
      Configuration directory:
      ejabberd.cfg
      ejabberd configuration file
      ejabberdctl.cfg
      Configuration file of the administration script -
      inetrc
      Network DNS configuration +
      inetrc
      Network DNS configuration file
      -
      /sbin/ejabberdctl
      Administration script -
      /var/lib/ejabberd/
      +
      /lib/ejabberd/
      - .erlang.cookie
      Erlang cookie file (see section 5.3) -
      db
      Mnesia database spool files -
      ebin
      Binary Erlang files (*.beam) -
      priv
      + ebin/
      Erlang binary files (*.beam) +
      include/
      Erlang header files (*.hrl) +
      priv/
      Additional files required at runtime
      - lib
      Binary system libraries (*.so) -
      msgs
      Translated strings (*.msgs) + bin/
      Binary C programs +
      lib/
      Binary system libraries (*.so) +
      msgs/
      Translation files (*.msgs)
      -
      /var/log/ejabberd/
      Log files (see section 7.2): +
      /sbin/ejabberdctl
      Administration script (see section 4.1) +
      /share/doc/ejabberd/
      Documentation of ejabberd +
      /var/lib/ejabberd/
      Spool directory: +
      + .erlang.cookie
      Erlang cookie file (see section 5.3) +
      acl.DCD, ...
      Mnesia database spool files (*.DCD, *.DCL, *.DAT) +
      +
      /var/log/ejabberd/
      Log directory (see section 7.2):
      ejabberd.log
      ejabberd service log
      sasl.log
      Erlang/OTP system log

      2.4.5  Start

      -

      You can use the ejabberdctl command line administration script to start and stop ejabberd.

      Usage example: +

      You can use the ejabberdctl command line administration script to start and stop ejabberd. +If you provided the configure option --enable-user=USER (see 2.4.3), +you can execute ejabberdctl with either that system account or root.

      Usage example:

      ejabberdctl start
       
       ejabberdctl status
      @@ -939,7 +958,7 @@ for more information.
       

      Though it is quite easy to set up PAM support in ejabberd, PAM itself introduces some security issues:

      • To perform PAM authentication ejabberd uses external C-program called -epam. By default, it is located in /var/lib/ejabberd/priv/lib/ +epam. By default, it is located in /var/lib/ejabberd/priv/bin/ directory. You have to set it root on execution in the case when your PAM module requires root privileges (pam_unix.so for example). Also you have to grant access for ejabberd to this file and remove all other permissions from it. @@ -2363,7 +2382,7 @@ restrictions by default).
      welcome_message
      Set a welcome message that is sent to each newly registered account. The first string is the subject, and the second string is the message body. -In the body you can set a newline with the characters: ~n. +In the body you can set a newline with the characters: \n
      registration_watchers
      This option defines a list of JIDs which will be notified each time a new account is registered.
      iqdisc
      This specifies @@ -2414,7 +2433,7 @@ Also define a registration timeout of one hour: ... {mod_register, [ - {welcome_message, {"Welcome!", "Hi.~nWelcome to this Jabber server.~n Check http://www.jabber.org~n~nBye"}}, + {welcome_message, {"Welcome!", "Hi.\nWelcome to this Jabber server.\n Check http://www.jabber.org\n\nBye"}}, {registration_watchers, ["admin1@example.org", "boss@example.net"]} ]}, ... @@ -2895,7 +2914,7 @@ Starts the Erlang system detached from the system console. Specify the directory where Erlang binary files (*.beam) are located.
      -s ejabberd
      Tell Erlang runtime system to start the ejabberd application. -
      -mnesia dir "/var/lib/ejabberd/db/nodename"
      +
      -mnesia dir "/var/lib/ejabberd/"
      Specify the Mnesia database directory.
      -sasl sasl_error_logger {file, "/var/log/ejabberd/sasl.log"}
      Path to the Erlang/OTP system log file. @@ -3065,10 +3084,10 @@ Contains IP addresses of clients. If the loglevel is set to 5, it contains whole conversations and passwords. If a logrotate system is used, there may be several log files with similar information, so it is preferable to secure the whole /var/log/ejabberd/ directory. -
      Mnesia database spool files: /var/lib/ejabberd/db/*
      +
      Mnesia database spool files in /var/lib/ejabberd/
      The files store binary data, but some parts are still readable. The files are generated by Mnesia and their permissions cannot be set directly, -so it is preferable to secure the whole /var/lib/ejabberd/db/ directory. +so it is preferable to secure the whole /var/lib/ejabberd/ directory.
      Erlang cookie file: /var/lib/ejabberd/.erlang.cookie
      See section 5.3.

      diff --git a/doc/guide.tex b/doc/guide.tex index 5a23a359a..3831ac024 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -313,7 +313,7 @@ To compile \ejabberd{} execute the commands: make \end{verbatim} -The build configuration script provides several parameters. +The build configuration script allows several options. To get the full list run the command: \begin{verbatim} ./configure --help @@ -322,10 +322,22 @@ To get the full list run the command: Some options that you may be interested in modifying: \begin{description} \titem{--prefix=/} - Specify the path prefix where the files will be copied when running the make install command. + Specify the path prefix where the files will be copied when running + the \term{make install} command. + + \titem{--enable-user[=USER]} + Allow this normal system user to execute the ejabberdctl script + (see section~\ref{ejabberdctl}), + read the configuration files, + read and write in the spool directory, + read and write in the log directory. + The account user and group must exist in the machine + before running \term{make install}. + This account doesn't need an explicit HOME directory, because + \term{/var/lib/ejabberd/} will be used by default. \titem{--enable-pam} - Enable the PAM authentication method. + Enable the PAM authentication method (see section \ref{pam}). \titem{--enable-odbc or --enable-mssql} Required if you want to use an external database. @@ -348,29 +360,36 @@ To install \ejabberd{} in the destination directories, run the command: \begin{verbatim} make install \end{verbatim} -Note that you may need to have administrative privileges in the system. +Note that you probably need administrative privileges in the system +to install \term{ejabberd}. The files and directories created are, by default: \begin{description} - \titem{/etc/ejabberd/} Configuration files: + \titem{/etc/ejabberd/} Configuration directory: \begin{description} \titem{ejabberd.cfg} ejabberd configuration file \titem{ejabberdctl.cfg} Configuration file of the administration script - \titem{inetrc} Network DNS configuration + \titem{inetrc} Network DNS configuration file \end{description} - \titem{/sbin/ejabberdctl} Administration script - \titem{/var/lib/ejabberd/} + \titem{/lib/ejabberd/} \begin{description} - \titem{.erlang.cookie} Erlang cookie file (see section \ref{cookie}) - \titem{db} Mnesia database spool files - \titem{ebin} Binary Erlang files (*.beam) - \titem{priv} + \titem{ebin/} Erlang binary files (*.beam) + \titem{include/} Erlang header files (*.hrl) + \titem{priv/} Additional files required at runtime \begin{description} - \titem{lib} Binary system libraries (*.so) - \titem{msgs} Translated strings (*.msgs) + \titem{bin/} Binary C programs + \titem{lib/} Binary system libraries (*.so) + \titem{msgs/} Translation files (*.msgs) \end{description} \end{description} - \titem{/var/log/ejabberd/} Log files (see section~\ref{logfiles}): + \titem{/sbin/ejabberdctl} Administration script (see section~\ref{ejabberdctl}) + \titem{/share/doc/ejabberd/} Documentation of ejabberd + \titem{/var/lib/ejabberd/} Spool directory: + \begin{description} + \titem{.erlang.cookie} Erlang cookie file (see section \ref{cookie}) + \titem{acl.DCD, ...} Mnesia database spool files (*.DCD, *.DCL, *.DAT) + \end{description} + \titem{/var/log/ejabberd/} Log directory (see section~\ref{logfiles}): \begin{description} \titem{ejabberd.log} ejabberd service log \titem{sasl.log} Erlang/OTP system log @@ -382,6 +401,8 @@ The files and directories created are, by default: \ind{install!start} You can use the \term{ejabberdctl} command line administration script to start and stop \ejabberd{}. +If you provided the configure option \term{--enable-user=USER} (see \ref{compile}), +you can execute \term{ejabberdctl} with either that system account or root. Usage example: \begin{verbatim} @@ -393,6 +414,7 @@ ejabberd is running ejabberdctl stop \end{verbatim} + Please refer to the section~\ref{ejabberdctl} for details about \term{ejabberdctl}, and configurable options to fine tune the Erlang runtime system. @@ -1117,7 +1139,7 @@ security issues: \begin{itemize} \item To perform PAM authentication \ejabberd{} uses external C-program called -\term{epam}. By default, it is located in \verb|/var/lib/ejabberd/priv/lib/| +\term{epam}. By default, it is located in \verb|/var/lib/ejabberd/priv/bin/| directory. You have to set it root on execution in the case when your PAM module requires root privileges (\term{pam\_unix.so} for example). Also you have to grant access for \ejabberd{} to this file and remove all other permissions from it. @@ -3036,7 +3058,7 @@ Options: \titem{welcome\_message} \ind{options!welcomem}Set a welcome message that is sent to each newly registered account. The first string is the subject, and the second string is the message body. - In the body you can set a newline with the characters: \term{\~\ n}. + In the body you can set a newline with the characters: \verb|\n| \titem{registration\_watchers} \ind{options!rwatchers}This option defines a list of JIDs which will be notified each time a new account is registered. \iqdiscitem{In-Band Registration (\ns{jabber:iq:register})} @@ -3095,7 +3117,7 @@ Also define a registration timeout of one hour: ... {mod_register, [ - {welcome_message, {"Welcome!", "Hi.~nWelcome to this Jabber server.~n Check http://www.jabber.org~n~nBye"}}, + {welcome_message, {"Welcome!", "Hi.\nWelcome to this Jabber server.\n Check http://www.jabber.org\n\nBye"}}, {registration_watchers, ["admin1@example.org", "boss@example.net"]} ]}, ... @@ -3708,7 +3730,7 @@ The command line parameters: Specify the directory where Erlang binary files (*.beam) are located. \titem{-s ejabberd} Tell Erlang runtime system to start the \ejabberd{} application. - \titem{-mnesia dir "/var/lib/ejabberd/db/nodename"} + \titem{-mnesia dir "/var/lib/ejabberd/"} Specify the Mnesia database directory. \titem{-sasl sasl\_error\_logger \{file, "/var/log/ejabberd/sasl.log"\}} Path to the Erlang/OTP system log file. @@ -3941,10 +3963,10 @@ write and execute those files and directories. If the loglevel is set to 5, it contains whole conversations and passwords. If a logrotate system is used, there may be several log files with similar information, so it is preferable to secure the whole \term{/var/log/ejabberd/} directory. - \titem{Mnesia database spool files: /var/lib/ejabberd/db/*} + \titem{Mnesia database spool files in /var/lib/ejabberd/} The files store binary data, but some parts are still readable. The files are generated by Mnesia and their permissions cannot be set directly, - so it is preferable to secure the whole \term{/var/lib/ejabberd/db/} directory. + so it is preferable to secure the whole \term{/var/lib/ejabberd/} directory. \titem{Erlang cookie file: /var/lib/ejabberd/.erlang.cookie} See section \ref{cookie}. \end{description} diff --git a/src/adhoc.hrl b/include/adhoc.hrl similarity index 100% rename from src/adhoc.hrl rename to include/adhoc.hrl diff --git a/src/ejabberd.hrl b/include/ejabberd.hrl similarity index 100% rename from src/ejabberd.hrl rename to include/ejabberd.hrl diff --git a/src/ejabberd_config.hrl b/include/ejabberd_config.hrl similarity index 100% rename from src/ejabberd_config.hrl rename to include/ejabberd_config.hrl diff --git a/src/ejabberd_ctl.hrl b/include/ejabberd_ctl.hrl similarity index 100% rename from src/ejabberd_ctl.hrl rename to include/ejabberd_ctl.hrl diff --git a/src/web/ejabberd_http.hrl b/include/ejabberd_http.hrl similarity index 100% rename from src/web/ejabberd_http.hrl rename to include/ejabberd_http.hrl diff --git a/src/web/ejabberd_web_admin.hrl b/include/ejabberd_web_admin.hrl similarity index 100% rename from src/web/ejabberd_web_admin.hrl rename to include/ejabberd_web_admin.hrl diff --git a/src/eldap/eldap.hrl b/include/eldap.hrl similarity index 100% rename from src/eldap/eldap.hrl rename to include/eldap.hrl diff --git a/src/jlib.hrl b/include/jlib.hrl similarity index 100% rename from src/jlib.hrl rename to include/jlib.hrl diff --git a/src/mod_privacy.hrl b/include/mod_privacy.hrl similarity index 100% rename from src/mod_privacy.hrl rename to include/mod_privacy.hrl diff --git a/src/mod_proxy65/mod_proxy65.hrl b/include/mod_proxy65.hrl similarity index 100% rename from src/mod_proxy65/mod_proxy65.hrl rename to include/mod_proxy65.hrl diff --git a/src/mod_roster.hrl b/include/mod_roster.hrl similarity index 100% rename from src/mod_roster.hrl rename to include/mod_roster.hrl diff --git a/src/mod_pubsub/pubsub.hrl b/include/pubsub.hrl similarity index 100% rename from src/mod_pubsub/pubsub.hrl rename to include/pubsub.hrl diff --git a/src/Makefile.in b/src/Makefile.in index 607af353e..3d398f569 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -12,37 +12,53 @@ ERLANG_CFLAGS= @ERLANG_CFLAGS@ EXPAT_LIBS = @EXPAT_LIBS@ ERLANG_LIBS = @ERLANG_LIBS@ -ERLC_FLAGS += @ERLANG_SSL39@ - ASN_FLAGS = -bber_bin +der +compact_bit_string +optimize +noobj + +INSTALLUSER=@INSTALLUSER@ +# if no user was enabled, don't set privileges or ownership +ifeq ($(INSTALLUSER),) + O_USER= + G_USER= + CHOWN_COMMAND=echo + CHOWN_OUTPUT=/dev/null +else + O_USER=-o $(INSTALLUSER) + G_USER=-g $(INSTALLUSER) + CHOWN_COMMAND=chown + CHOWN_OUTPUT=&1 +endif + +EFLAGS += @ERLANG_SSL39@ +EFLAGS += -I ../include + # make debug=true to compile Erlang module with debug informations. ifdef debug - ERLC_FLAGS+=+debug_info + EFLAGS+=+debug_info endif ifdef ejabberd_debug - ERLC_FLAGS+=-Dejabberd_debug + EFLAGS+=-Dejabberd_debug endif ifeq (@hipe@, true) - ERLC_FLAGS+=+native + EFLAGS+=+native endif ifeq (@roster_gateway_workaround@, true) - ERLC_FLAGS+=-DROSTER_GATEWAY_WORKAROUND + EFLAGS+=-DROSTER_GATEWAY_WORKAROUND endif ifeq (@full_xml@, true) - ERLC_FLAGS+=-DFULL_XML_SUPPORT + EFLAGS+=-DFULL_XML_SUPPORT endif ifeq (@transient_supervisors@, false) - ERLC_FLAGS+=-DNO_TRANSIENT_SUPERVISORS + EFLAGS+=-DNO_TRANSIENT_SUPERVISORS endif INSTALL_EPAM= ifeq (@pam@, pam) - INSTALL_EPAM=install -m 750 epam $(PBINDIR) + INSTALL_EPAM=install -m 750 $(O_USER) epam $(PBINDIR) endif prefix = @prefix@ @@ -58,17 +74,47 @@ BEAMS = $(SOURCES:.erl=.beam) DESTDIR = -EJABBERDDIR = $(DESTDIR)@localstatedir@/lib/ejabberd -BEAMDIR = $(EJABBERDDIR)/ebin -SPOOLDIR = $(EJABBERDDIR)/db -PRIVDIR = $(EJABBERDDIR)/priv -SODIR = $(PRIVDIR)/lib -PBINDIR = $(PRIVDIR)/bin -MSGSDIR = $(PRIVDIR)/msgs -LOGDIR = $(DESTDIR)@localstatedir@/log/ejabberd +# /etc/ejabberd/ ETCDIR = $(DESTDIR)@sysconfdir@/ejabberd + +# /sbin/ SBINDIR = $(DESTDIR)@sbindir@ +# /lib/ejabberd/ +EJABBERDDIR = $(DESTDIR)@libdir@/ejabberd + +# /share/doc/ejabberd +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +datarootdir = @datarootdir@ +DOCDIR = @docdir@ + +# /usr/lib/ejabberd/ebin/ +BEAMDIR = $(EJABBERDDIR)/ebin + +# /usr/lib/ejabberd/include/ +INCLUDEDIR = $(EJABBERDDIR)/include + +# /usr/lib/ejabberd/priv/ +PRIVDIR = $(EJABBERDDIR)/priv + +# /usr/lib/ejabberd/priv/bin +PBINDIR = $(PRIVDIR)/bin + +# /usr/lib/ejabberd/priv/lib +SODIR = $(PRIVDIR)/lib + +# /usr/lib/ejabberd/priv/msgs +MSGSDIR = $(PRIVDIR)/msgs + +# /var/lib/ejabberd/ +SPOOLDIR = $(DESTDIR)@localstatedir@/lib/ejabberd + +# /var/lib/ejabberd/.erlang.cookie +COOKIEFILE = $(SPOOLDIR)/.erlang.cookie + +# /var/log/ejabberd/ +LOGDIR = $(DESTDIR)@localstatedir@/log/ejabberd + ifeq ($(shell uname),Darwin) DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress else @@ -85,7 +131,7 @@ $(BEAMS): $(ERLBEHAVBEAMS) all-recursive: $(ERLBEHAVBEAMS) %.beam: %.erl - @ERLC@ -W $(ERLC_FLAGS) $< + @ERLC@ -W $(EFLAGS) $< all-recursive install-recursive uninstall-recursive \ @@ -100,7 +146,7 @@ mostlyclean-recursive maintainer-clean-recursive: %.hrl: %.asn1 @ERLC@ $(ASN_FLAGS) $< - @ERLC@ -W $(ERLC_FLAGS) $*.erl + @ERLC@ -W $(EFLAGS) $*.erl $(ERLSHLIBS): %.so: %.c $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) \ @@ -113,39 +159,90 @@ $(ERLSHLIBS): %.so: %.c $(DYNAMIC_LIB_CFLAGS) install: all + # + # Configuration files + install -d -m 750 $(G_USER) $(ETCDIR) + [ -f $(ETCDIR)/ejabberd.cfg ] \ + && install -b -m 640 $(G_USER) ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg-new \ + || install -b -m 640 $(G_USER) ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg + sed -e "s*@rootdir@*@prefix@*" \ + -e "s*@installuser@*@INSTALLUSER@*" \ + -e "s*@LIBDIR@*@libdir@*" \ + -e "s*@SYSCONFDIR@*@sysconfdir@*" \ + -e "s*@LOCALSTATEDIR@*@localstatedir@*" \ + -e "s*@erl@*@ERL@*" ejabberdctl.template \ + > ejabberdctl.example + [ -f $(ETCDIR)/ejabberdctl.cfg ] \ + && install -b -m 640 $(G_USER) ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg-new \ + || install -b -m 640 $(G_USER) ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg + install -b -m 644 $(G_USER) inetrc $(ETCDIR)/inetrc + # + # Administration script + [ -d $(SBINDIR) ] || install -d 750 $(SBINDIR) + install -m 550 $(G_USER) ejabberdctl.example $(SBINDIR)/ejabberdctl + # + # Binary Erlang files install -d $(BEAMDIR) + install -m 644 *.app $(BEAMDIR) install -m 644 *.beam $(BEAMDIR) rm -f $(BEAMDIR)/configure.beam - install -m 644 *.app $(BEAMDIR) - install -d -m 750 $(SPOOLDIR) - install -d $(SODIR) + # + # ejabberd header files + install -d $(INCLUDEDIR) + install -m 644 ../include/*.hrl $(INCLUDEDIR) + # + # Binary C programs install -d $(PBINDIR) - install -m 644 *.so $(SODIR) $(INSTALL_EPAM) + # + # Binary system libraries + install -d $(SODIR) + install -m 644 *.so $(SODIR) + # + # Translated strings install -d $(MSGSDIR) install -m 644 msgs/*.msg $(MSGSDIR) - install -d -m 750 $(ETCDIR) - [ -f $(ETCDIR)/ejabberd.cfg ] && install -b -m 644 ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg-new || install -b -m 644 ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg - sed -e "s*@rootdir@*@prefix@*" ejabberdctl.template > ejabberdctl.example - [ -f $(ETCDIR)/ejabberdctl.cfg ] && install -b -m 644 ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg-new || install -b -m 644 ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg - install -b -m 644 inetrc $(ETCDIR)/inetrc - install -d $(SBINDIR) - install -m 755 ejabberdctl.example $(SBINDIR)/ejabberdctl - install -d -m 750 $(LOGDIR) + # + # Spool directory + install -d -m 750 $(O_USER) $(SPOOLDIR) + $(CHOWN_COMMAND) -R @INSTALLUSER@ $(SPOOLDIR) >$(CHOWN_OUTPUT) + chmod -R 750 $(SPOOLDIR) + [ ! -f $(COOKIEFILE) ] || { $(CHOWN_COMMAND) @INSTALLUSER@ $(COOKIEFILE) >$(CHOWN_OUTPUT) ; chmod 400 $(COOKIEFILE) ; } + # + # Log directory + install -d -m 750 $(O_USER) $(LOGDIR) + $(CHOWN_COMMAND) -R @INSTALLUSER@ $(LOGDIR) >$(CHOWN_OUTPUT) + chmod -R 750 $(LOGDIR) + # + # Documentation + install -d $(DOCDIR) + install ../doc/guide.html $(DOCDIR) + install ../doc/*.png $(DOCDIR) + install ../doc/*.txt $(DOCDIR) uninstall: uninstall-binary uninstall-binary: - rm -rf $(BEAMDIR) - rm -rf $(SODIR) - rm -rf $(MSGSDIR) - rm -rf $(PRIVDIR) - rm -rf $(SBINDIR)/ejabberdctl + rm -f $(SBINDIR)/ejabberdctl + rm -fr $(DOCDIR) + rm -f $(BEAMDIR)/*.beam + rm -f $(BEAMDIR)/*.app + rm -fr $(BEAMDIR) + rm -f $(INCLUDEDIR)/*.hrl + rm -fr $(INCLUDEDIR) + rm -fr $(PBINDIR) + rm -f $(SODIR)/*.so + rm -fr $(SODIR) + rm -f $(MSGSDIR)/*.msgs + rm -fr $(MSGSDIR) + rm -fr $(PRIVDIR) + rm -fr $(EJABBERDDIR) uninstall-all: uninstall-binary rm -rf $(ETCDIR) - rm -rf $(LOGDIR) rm -rf $(EJABBERDDIR) + rm -rf $(SPOOLDIR) + rm -rf $(LOGDIR) clean: clean-recursive clean-local diff --git a/src/aclocal.m4 b/src/aclocal.m4 index 65509eefc..10a9e4bd1 100644 --- a/src/aclocal.m4 +++ b/src/aclocal.m4 @@ -1,6 +1,6 @@ AC_DEFUN(AM_WITH_EXPAT, [ AC_ARG_WITH(expat, - [ --with-expat=PREFIX prefix where EXPAT is installed]) + [AC_HELP_STRING([--with-expat=PREFIX], [prefix where EXPAT is installed])]) EXPAT_CFLAGS= EXPAT_LIBS= @@ -34,7 +34,7 @@ AC_DEFUN(AM_WITH_EXPAT, AC_DEFUN(AM_WITH_ZLIB, [ AC_ARG_WITH(zlib, - [ --with-zlib=PREFIX prefix where zlib is installed]) + [AC_HELP_STRING([--with-zlib=PREFIX], [prefix where zlib is installed])]) ZLIB_CFLAGS= ZLIB_LIBS= @@ -68,7 +68,7 @@ AC_DEFUN(AM_WITH_ZLIB, AC_DEFUN(AM_WITH_PAM, [ AC_ARG_WITH(pam, - [ --with-pam=PREFIX prefix where PAM is installed]) + [AC_HELP_STRING([--with-pam=PREFIX], [prefix where PAM is installed])]) PAM_CFLAGS= PAM_LIBS= @@ -102,7 +102,7 @@ AC_DEFUN(AM_WITH_PAM, AC_DEFUN(AM_WITH_ERLANG, [ AC_ARG_WITH(erlang, - [ --with-erlang=PREFIX path to erlc and erl ]) + [AC_HELP_STRING([--with-erlang=PREFIX], [path to erlc and erl])]) AC_PATH_TOOL(ERLC, erlc, , $with_erlang:$with_erlang/bin:$PATH) AC_PATH_TOOL(ERL, erl, , $with_erlang:$with_erlang/bin:$PATH) @@ -204,14 +204,13 @@ _EOF AC_SUBST(ERL) ]) - AC_DEFUN(AC_MOD_ENABLE, [ $1= make_$1= AC_MSG_CHECKING([whether build $1]) AC_ARG_ENABLE($1, - [ --enable-$1 enable $1 (default: $2)], + [AC_HELP_STRING([--enable-$1], [enable $1 (default: $2)])], [mr_enable_$1="$enableval"], [mr_enable_$1=$2]) if test "$mr_enable_$1" = "yes"; then @@ -232,7 +231,7 @@ AC_DEFUN([AM_ICONV], dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and dnl those with the standalone portable GNU libiconv installed). AC_ARG_WITH([libiconv-prefix], -[ --with-libiconv-prefix=PREFIX prefix where libiconv is installed], [ + [AC_HELP_STRING([--with-libiconv-prefix=PREFIX], [prefix where libiconv is installed])], [ for dir in `echo "$withval" | tr : ' '`; do if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi if test -d $dir/include; then CFLAGS="$CFLAGS -I$dir/include"; fi @@ -317,7 +316,7 @@ size_t iconv(); dnl AC_DEFUN(AM_WITH_OPENSSL, [ AC_ARG_WITH(openssl, - [ --with-openssl=PREFIX prefix where OPENSSL is installed ]) + [AC_HELP_STRING([--with-openssl=PREFIX], [prefix where OPENSSL is installed])]) unset SSL_LIBS; unset SSL_CFLAGS; have_openssl=no diff --git a/src/configure b/src/configure index 034868416..a6cc19b6c 100755 --- a/src/configure +++ b/src/configure @@ -1,6 +1,8 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.61. +# Generated by GNU Autoconf 2.61 for ejabberd.erl version. +# +# Report bugs to . # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. @@ -570,13 +572,12 @@ MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. -PACKAGE_NAME= -PACKAGE_TARNAME= -PACKAGE_VERSION= -PACKAGE_STRING= -PACKAGE_BUGREPORT= +PACKAGE_NAME='ejabberd.erl' +PACKAGE_TARNAME='ejabberd' +PACKAGE_VERSION='version' +PACKAGE_STRING='ejabberd.erl version' +PACKAGE_BUGREPORT='ejabberd@process-one.net' -ac_unique_file="ejabberd.erl" # Factoring default headers for most tests. ac_includes_default="\ #include @@ -703,6 +704,7 @@ transient_supervisors full_xml SSL_LIBS SSL_CFLAGS +INSTALLUSER LTLIBOBJS' ac_subst_files='' ac_precious_vars='build_alias @@ -752,7 +754,7 @@ sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE}' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' @@ -1216,7 +1218,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures this package to adapt to many kinds of systems. +\`configure' configures ejabberd.erl version to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1264,7 +1266,7 @@ Fine tuning of the installation directories: --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --docdir=DIR documentation root [DATAROOTDIR/doc/ejabberd] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] @@ -1276,37 +1278,49 @@ _ACEOF fi if test -n "$ac_init_help"; then - + case $ac_init_help in + short | recursive ) echo "Configuration of ejabberd.erl version:";; + esac cat <<\_ACEOF Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-mod_pubsub enable mod_pubsub (default: yes) + --enable-mod_pubsub enable mod_pubsub (default: yes) --enable-mod_irc enable mod_irc (default: yes) --enable-mod_muc enable mod_muc (default: yes) - --enable-mod_proxy65 enable mod_proxy65 (default: yes) - --enable-eldap enable eldap (default: yes) - --enable-pam enable pam (default: no) - --enable-web enable web (default: yes) - --enable-tls enable tls (default: yes) - --enable-odbc enable odbc (default: no) - --enable-ejabberd_zlib enable ejabberd_zlib (default: yes) - --enable-hipe Compile natively with HiPE, not recommended (default: no) - --enable-roster-gateway-workaround Turn on workaround for processing gateway subscriptions (default: no) - --enable-mssql Use Microsoft SQL Server database (default: no, requires --enable-odbc) - --enable-transient_supervisors Use Erlang supervision for transient process (default: yes) - --enable-full-xml Use XML features in XMPP stream (ex: CDATA) (default: no, requires XML compliant clients) + --enable-mod_proxy65 enable mod_proxy65 (default: yes) + --enable-eldap enable eldap (default: yes) + --enable-pam enable pam (default: no) + --enable-web enable web (default: yes) + --enable-tls enable tls (default: yes) + --enable-odbc enable odbc (default: no) + --enable-ejabberd_zlib enable ejabberd_zlib (default: yes) + --enable-hipe compile natively with HiPE, not recommended + (default: no) + --enable-roster-gateway-workaround + turn on workaround for processing gateway + subscriptions (default: no) + --enable-mssql use Microsoft SQL Server database (default: no, + requires --enable-odbc) + --enable-transient_supervisors + use Erlang supervision for transient process + (default: yes) + --enable-full-xml use XML features in XMPP stream (ex: CDATA) + (default: no, requires XML compliant clients) + --enable-user[=USER] allow this system user to start ejabberd (default: + no) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-erlang=PREFIX path to erlc and erl - --with-libiconv-prefix=PREFIX prefix where libiconv is installed - --with-expat=PREFIX prefix where EXPAT is installed - --with-zlib=PREFIX prefix where zlib is installed - --with-pam=PREFIX prefix where PAM is installed - --with-openssl=PREFIX prefix where OPENSSL is installed + --with-libiconv-prefix=PREFIX + prefix where libiconv is installed + --with-expat=PREFIX prefix where EXPAT is installed + --with-zlib=PREFIX prefix where zlib is installed + --with-pam=PREFIX prefix where PAM is installed + --with-openssl=PREFIX prefix where OPENSSL is installed Some influential environment variables: CC C compiler command @@ -1321,6 +1335,7 @@ Some influential environment variables: Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. +Report bugs to . _ACEOF ac_status=$? fi @@ -1381,7 +1396,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -configure +ejabberd.erl configure version generated by GNU Autoconf 2.61 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1395,7 +1410,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by $as_me, which was +It was created by ejabberd.erl $as_me version, which was generated by GNU Autoconf 2.61. Invocation command line was $ $0 $@ @@ -1728,6 +1743,14 @@ fi + + + + + + + + @@ -4131,7 +4154,12 @@ echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\ echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - + ( cat <<\_ASBOX +## --------------------------------------- ## +## Report this to ejabberd@process-one.net ## +## --------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { echo "$as_me:$LINENO: checking for $ac_header" >&5 @@ -4376,7 +4404,12 @@ echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\ echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - + ( cat <<\_ASBOX +## --------------------------------------- ## +## Report this to ejabberd@process-one.net ## +## --------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { echo "$as_me:$LINENO: checking for $ac_header" >&5 @@ -4620,7 +4653,12 @@ echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\ echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - + ( cat <<\_ASBOX +## --------------------------------------- ## +## Report this to ejabberd@process-one.net ## +## --------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { echo "$as_me:$LINENO: checking for $ac_header" >&5 @@ -4888,7 +4926,12 @@ echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\ echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - + ( cat <<\_ASBOX +## --------------------------------------- ## +## Report this to ejabberd@process-one.net ## +## --------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { echo "$as_me:$LINENO: checking for $ac_header" >&5 @@ -5676,7 +5719,12 @@ echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\ echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - + ( cat <<\_ASBOX +## --------------------------------------- ## +## Report this to ejabberd@process-one.net ## +## --------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { echo "$as_me:$LINENO: checking for $ac_header" >&5 @@ -5849,7 +5897,12 @@ echo "$as_me: WARNING: krb5.h: section \"Present But Cannot Be Compiled\"" > echo "$as_me: WARNING: krb5.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: krb5.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: krb5.h: in the future, the compiler will take precedence" >&2;} - + ( cat <<\_ASBOX +## --------------------------------------- ## +## Report this to ejabberd@process-one.net ## +## --------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { echo "$as_me:$LINENO: checking for krb5.h" >&5 @@ -5866,6 +5919,22 @@ fi +ENABLEUSER="" +# Check whether --enable-user was given. +if test "${enable_user+set}" = set; then + enableval=$enable_user; case "${enableval}" in + yes) ENABLEUSER=`whoami` ;; + no) ENABLEUSER="" ;; + *) ENABLEUSER=$enableval + esac +fi + +if test "$ENABLEUSER" != ""; then + echo "allow this system user to start ejabberd: $ENABLEUSER" + INSTALLUSER=$ENABLEUSER + +fi + cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure @@ -6292,7 +6361,7 @@ exec 6>&1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by $as_me, which was +This file was extended by ejabberd.erl $as_me version, which was generated by GNU Autoconf 2.61. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -6335,7 +6404,7 @@ Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -config.status +ejabberd.erl config.status version configured by $0, generated by GNU Autoconf 2.61, with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" @@ -6594,10 +6663,11 @@ transient_supervisors!$transient_supervisors$ac_delim full_xml!$full_xml$ac_delim SSL_LIBS!$SSL_LIBS$ac_delim SSL_CFLAGS!$SSL_CFLAGS$ac_delim +INSTALLUSER!$INSTALLUSER$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 90; then + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 91; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 diff --git a/src/configure.ac b/src/configure.ac index 254b16b06..ba6384633 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.53) -AC_INIT(ejabberd.erl,, ejabberd@process-one.net) +AC_INIT(ejabberd.erl, version, [ejabberd@process-one.net], [ejabberd]) # Checks for programs. AC_PROG_CC @@ -48,7 +48,7 @@ AC_MOD_ENABLE(odbc, no) AC_MOD_ENABLE(ejabberd_zlib, yes) AC_ARG_ENABLE(hipe, -[ --enable-hipe Compile natively with HiPE, not recommended (default: no)], +[AC_HELP_STRING([--enable-hipe], [compile natively with HiPE, not recommended (default: no)])], [case "${enableval}" in yes) hipe=true ;; no) hipe=false ;; @@ -57,7 +57,7 @@ esac],[hipe=false]) AC_SUBST(hipe) AC_ARG_ENABLE(roster_gateway_workaround, -[ --enable-roster-gateway-workaround Turn on workaround for processing gateway subscriptions (default: no)], +[AC_HELP_STRING([--enable-roster-gateway-workaround], [turn on workaround for processing gateway subscriptions (default: no)])], [case "${enableval}" in yes) roster_gateway_workaround=true ;; no) roster_gateway_workaround=false ;; @@ -66,7 +66,7 @@ esac],[roster_gateway_workaround=false]) AC_SUBST(roster_gateway_workaround) AC_ARG_ENABLE(mssql, -[ --enable-mssql Use Microsoft SQL Server database (default: no, requires --enable-odbc)], +[AC_HELP_STRING([--enable-mssql], [use Microsoft SQL Server database (default: no, requires --enable-odbc)])], [case "${enableval}" in yes) db_type=mssql ;; no) db_type=generic ;; @@ -75,7 +75,7 @@ esac],[db_type=generic]) AC_SUBST(db_type) AC_ARG_ENABLE(transient_supervisors, -[ --enable-transient_supervisors Use Erlang supervision for transient process (default: yes)], +[AC_HELP_STRING([--enable-transient_supervisors], [use Erlang supervision for transient process (default: yes)])], [case "${enableval}" in yes) transient_supervisors=true ;; no) transient_supervisors=false ;; @@ -84,7 +84,7 @@ esac],[transient_supervisors=true]) AC_SUBST(transient_supervisors) AC_ARG_ENABLE(full_xml, -[ --enable-full-xml Use XML features in XMPP stream (ex: CDATA) (default: no, requires XML compliant clients)], +[AC_HELP_STRING([--enable-full-xml], [use XML features in XMPP stream (ex: CDATA) (default: no, requires XML compliant clients)])], [case "${enableval}" in yes) full_xml=true ;; no) full_xml=false ;; @@ -122,4 +122,18 @@ else fi AC_CHECK_HEADER(krb5.h,,) +ENABLEUSER="" +AC_ARG_ENABLE(user, + [AS_HELP_STRING([--enable-user[[[[=USER]]]]], [allow this system user to start ejabberd (default: no)])], + [case "${enableval}" in + yes) ENABLEUSER=`whoami` ;; + no) ENABLEUSER="" ;; + *) ENABLEUSER=$enableval + esac], + []) +if test "$ENABLEUSER" != ""; then + echo "allow this system user to start ejabberd: $ENABLEUSER" + AC_SUBST([INSTALLUSER], [$ENABLEUSER]) +fi + AC_OUTPUT diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index eb43bb3ca..022a9ebc2 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -459,7 +459,7 @@ %% a message with this subject and body. %% {welcome_message, {"Welcome!", - "Hi.~nWelcome to this Jabber server."}}, + "Hi.\nWelcome to this Jabber server."}}, %% %% When a user registers, send a notification to diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl index d576a82fd..b9bf3b477 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -58,7 +58,7 @@ ]). -include("ejabberd.hrl"). --include("eldap/eldap.hrl"). +-include("eldap.hrl"). -record(state, {host, eldap_id, diff --git a/src/ejabberd_zlib/Makefile.in b/src/ejabberd_zlib/Makefile.in index f24addbc3..3a70186bd 100644 --- a/src/ejabberd_zlib/Makefile.in +++ b/src/ejabberd_zlib/Makefile.in @@ -19,7 +19,8 @@ else DYNAMIC_LIB_CFLAGS = -fpic -shared endif -EFLAGS = -I .. -pz .. +EFLAGS += -I ../../include +EFLAGS += -pz .. # make debug=true to compile Erlang module with debug informations. ifdef debug EFLAGS+=+debug_info diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template index e086d1ef4..fcf0a80cc 100644 --- a/src/ejabberdctl.template +++ b/src/ejabberdctl.template @@ -11,13 +11,15 @@ ERL_MAX_ETS_TABLES=1400 NODE=ejabberd HOST=localhost ERLANG_NODE=$NODE@$HOST -ROOTDIR=@rootdir@ -EJABBERD_CONFIG_PATH=$ROOTDIR/etc/ejabberd/ejabberd.cfg -LOGS_DIR=$ROOTDIR/var/log/ejabberd/ -EJABBERD_DB=$ROOTDIR/var/lib/ejabberd/db/$NODE +ERL=@erl@ +INSTALLUSER=@installuser@ +ETCDIR=@SYSCONFDIR@/ejabberd +EJABBERD_CONFIG_PATH=$ETCDIR/ejabberd.cfg +LOGDIR=@LOCALSTATEDIR@/log/ejabberd +SPOOLDIR=@LOCALSTATEDIR@/lib/ejabberd # read custom configuration -CONFIG=$ROOTDIR/etc/ejabberd/ejabberdctl.cfg +CONFIG=$ETCDIR/ejabberdctl.cfg [ -f "$CONFIG" ] && . "$CONFIG" # parse command line parameters @@ -30,12 +32,27 @@ while [ $# -ne 0 ] ; do --node) ERLANG_NODE=$1; shift ;; --config) EJABBERD_CONFIG_PATH=$1 ; shift ;; --ctl-config) CONFIG=$1 ; shift ;; - --logs) LOGS_DIR=$1 ; shift ;; - --spool) EJABBERD_DB=$1 ; shift ;; + --logs) LOGDIR=$1 ; shift ;; + --spool) SPOOLDIR=$1 ; shift ;; *) ARGS="$ARGS $PARAM" ;; esac done +# check the proper system user is used +ID=`id -g` +EJID=`id -g $INSTALLUSER` +EXEC_CMD="false" +if [ $ID -eq 0 ] ; then + EXEC_CMD="su ${INSTALLUSER} -c" +fi +if [ "$ID" -eq "$EJID" ] ; then + EXEC_CMD="sh -c" +fi +if [ "$EXEC_CMD" = "false" ] ; then + echo "This command can only be run by root or the user $INSTALLUSER" >&2 + exit 1 +fi + NAME=-name [ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] && NAME=-sname @@ -48,31 +65,36 @@ fi ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $KERNEL_OPTS" # define additional environment variables -EJABBERD_EBIN=$ROOTDIR/var/lib/ejabberd/ebin -EJABBERD_MSGS_PATH=$ROOTDIR/var/lib/ejabberd/priv/msgs -EJABBERD_SO_PATH=$ROOTDIR/var/lib/ejabberd/priv/lib -EJABBERD_BIN_PATH=$ROOTDIR/var/lib/ejabberd/priv/bin -EJABBERD_LOG_PATH=$LOGS_DIR/ejabberd.log -SASL_LOG_PATH=$LOGS_DIR/sasl.log +EJABBERDDIR=@LIBDIR@/ejabberd +BEAMDIR=$EJABBERDDIR/ebin +PRIVDIR=$EJABBERDDIR/priv +PBINDIR=$PRIVDIR/bin +SODIR=$PRIVDIR/lib +MSGSDIR=$PRIVDIR/msgs + +EJABBERD_LOG_PATH=$LOGDIR/ejabberd.log +SASL_LOG_PATH=$LOGDIR/sasl.log DATETIME=`date "+%Y%m%d-%H%M%S"` -ERL_CRASH_DUMP=$LOGS_DIR/erl_crash_$DATETIME.dump -ERL_INETRC=$ROOTDIR/etc/ejabberd/inetrc -HOME=$ROOTDIR/var/lib/ejabberd +ERL_CRASH_DUMP=$LOGDIR/erl_crash_$DATETIME.dump +ERL_INETRC=$ETCDIR/inetrc +HOME=$SPOOLDIR + +# create the home dir with the proper user if doesn't exist, because it stores cookie file +[ -d $HOME ] || $EXEC_CMD "mkdir -p $HOME" # export global variables export EJABBERD_CONFIG_PATH -export EJABBERD_MSGS_PATH +export MSGSDIR export EJABBERD_LOG_PATH -export EJABBERD_SO_PATH -export EJABBERD_BIN_PATH +export SODIR +export PBINDIR export ERL_CRASH_DUMP export ERL_INETRC export ERL_MAX_PORTS export ERL_MAX_ETS_TABLES export HOME +export EXEC_CMD -[ -d $EJABBERD_DB ] || mkdir -p $EJABBERD_DB -[ -d $LOGS_DIR ] || mkdir -p $LOGS_DIR # Compatibility in ZSH #setopt shwordsplit 2>/dev/null @@ -80,14 +102,14 @@ export HOME # start server start () { - erl \ + $EXEC_CMD "$ERL \ $NAME $ERLANG_NODE \ -noinput -detached \ - -pa $EJABBERD_EBIN \ - -mnesia dir "\"$EJABBERD_DB\"" \ + -pa $BEAMDIR \ + -mnesia dir \"\\\"$SPOOLDIR\\\"\" \ -s ejabberd \ - -sasl sasl_error_logger \{file,\"$SASL_LOG_PATH\"\} \ - $ERLANG_OPTS $ARGS "$@" + -sasl sasl_error_logger \\{file,\\\"$SASL_LOG_PATH\\\"\\} \ + $ERLANG_OPTS $ARGS \"$@\"" } # attach to server @@ -109,10 +131,10 @@ debug () echo "Press any key to continue" read foo echo "" - erl \ + $EXEC_CMD "$ERL \ $NAME ${NODE}debug \ -remsh $ERLANG_NODE \ - $ERLANG_OPTS $ARGS "$@" + $ERLANG_OPTS $ARGS \"$@\"" } # start interactive server @@ -133,23 +155,22 @@ live () echo "Press any key to continue" read foo echo "" - erl \ + $EXEC_CMD "$ERL \ $NAME $ERLANG_NODE \ - $ERLANG_OPTS \ - -pa $EJABBERD_EBIN \ - -mnesia dir "\"$EJABBERD_DB\"" \ + -pa $BEAMDIR \ + -mnesia dir \"\\\"$SPOOLDIR\\\"\" \ -s ejabberd \ - $ERLANG_OPTS $ARGS "$@" + $ERLANG_OPTS $ARGS \"$@\"" } # common control function ctl () { - erl \ + $EXEC_CMD "$ERL \ $NAME ejabberdctl \ -noinput \ - -pa $EJABBERD_EBIN \ - -s ejabberd_ctl -extra $ERLANG_NODE $@ + -pa $BEAMDIR \ + -s ejabberd_ctl -extra $ERLANG_NODE $@" result=$? case $result in 0) :;; @@ -163,8 +184,9 @@ ctl () echo "Optional parameters when starting an ejabberd node:" echo " --config file Config file of ejabberd: $EJABBERD_CONFIG_PATH" echo " --ctl-config file Config file of ejabberdctl: $CONFIG" - echo " --logs dir Directory for logs: $LOGS_DIR" - echo " --spool dir Database spool dir: $EJABBERD_DB" + echo " --logs dir Directory for logs: $LOGDIR" + echo " --spool dir Database spool dir: $SPOOLDIR" + echo " --node nodename ejabberd node name: $ERLANG_NODE" echo "";; esac return $result diff --git a/src/eldap/Makefile.in b/src/eldap/Makefile.in index 1c9b7ca22..4c9c33c22 100644 --- a/src/eldap/Makefile.in +++ b/src/eldap/Makefile.in @@ -9,7 +9,8 @@ LIBS = @LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ -EFLAGS = -I .. -pz .. +EFLAGS += -I ../../include +EFLAGS += -pz .. # make debug=true to compile Erlang module with debug informations. ifdef debug EFLAGS+=+debug_info diff --git a/src/mod_irc/Makefile.in b/src/mod_irc/Makefile.in index 5000721a6..86212e45c 100644 --- a/src/mod_irc/Makefile.in +++ b/src/mod_irc/Makefile.in @@ -16,7 +16,9 @@ else DYNAMIC_LIB_CFLAGS = -fpic -shared endif -EFLAGS = -I .. -pz .. +EFLAGS += -I ../../include +EFLAGS += -pz .. + # make debug=true to compile Erlang module with debug informations. ifdef debug EFLAGS+=+debug_info diff --git a/src/mod_muc/Makefile.in b/src/mod_muc/Makefile.in index 8aa3bf5e1..80725d33d 100644 --- a/src/mod_muc/Makefile.in +++ b/src/mod_muc/Makefile.in @@ -9,7 +9,9 @@ LIBS = @LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ -EFLAGS = -I .. -pz .. +EFLAGS += -I ../../include +EFLAGS += -pz .. + # make debug=true to compile Erlang module with debug informations. ifdef debug EFLAGS+=+debug_info diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 3a751c328..3db29844b 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -43,8 +43,8 @@ -include("ejabberd.hrl"). -include("jlib.hrl"). --include("web/ejabberd_http.hrl"). --include("web/ejabberd_web_admin.hrl"). +-include("ejabberd_http.hrl"). +-include("ejabberd_web_admin.hrl"). -record(offline_msg, {us, timestamp, expire, from, to, packet}). diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index c3d0513d0..79d7c51ae 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -42,8 +42,8 @@ -include("ejabberd.hrl"). -include("jlib.hrl"). --include("web/ejabberd_http.hrl"). --include("web/ejabberd_web_admin.hrl"). +-include("ejabberd_http.hrl"). +-include("ejabberd_web_admin.hrl"). -record(offline_msg, {user, timestamp, expire, from, to, packet}). diff --git a/src/mod_proxy65/Makefile.in b/src/mod_proxy65/Makefile.in index b9eba4267..62ae77c9f 100644 --- a/src/mod_proxy65/Makefile.in +++ b/src/mod_proxy65/Makefile.in @@ -9,7 +9,9 @@ LIBS = @LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ -EFLAGS = -I .. -pz .. +EFLAGS += -I ../../include +EFLAGS += -pz .. + # make debug=true to compile Erlang module with debug informations. ifdef debug EFLAGS+=+debug_info diff --git a/src/mod_proxy65/mod_proxy65_service.erl b/src/mod_proxy65/mod_proxy65_service.erl index 41c3af7d5..4ee3ec61a 100644 --- a/src/mod_proxy65/mod_proxy65_service.erl +++ b/src/mod_proxy65/mod_proxy65_service.erl @@ -41,8 +41,8 @@ %% API. -export([start_link/2]). --include("../ejabberd.hrl"). --include("../jlib.hrl"). +-include("ejabberd.hrl"). +-include("jlib.hrl"). -define(PROCNAME, ejabberd_mod_proxy65_service). diff --git a/src/mod_proxy65/mod_proxy65_stream.erl b/src/mod_proxy65/mod_proxy65_stream.erl index ccc060afe..046ac8e71 100644 --- a/src/mod_proxy65/mod_proxy65_stream.erl +++ b/src/mod_proxy65/mod_proxy65_stream.erl @@ -58,7 +58,7 @@ ]). -include("mod_proxy65.hrl"). --include("../ejabberd.hrl"). +-include("ejabberd.hrl"). -define(WAIT_TIMEOUT, 60000). %% 1 minute (is it enough?) diff --git a/src/mod_pubsub/Makefile.in b/src/mod_pubsub/Makefile.in index 39f6a16e8..25dbf57a5 100644 --- a/src/mod_pubsub/Makefile.in +++ b/src/mod_pubsub/Makefile.in @@ -9,7 +9,9 @@ LIBS = @LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ -EFLAGS = -I .. -pz .. +EFLAGS += -I ../../include +EFLAGS += -pz .. + # make debug=true to compile Erlang module with debug informations. ifdef debug EFLAGS+=+debug_info diff --git a/src/mod_register.erl b/src/mod_register.erl index 21080c8a2..a936ea5e1 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -241,13 +241,12 @@ send_welcome_message(JID) -> {"", ""} -> ok; {Subj, Body} -> - BodyFormatted = io_lib:format(Body, []), ejabberd_router:route( jlib:make_jid("", Host, ""), JID, {xmlelement, "message", [{"type", "normal"}], [{xmlelement, "subject", [], [{xmlcdata, Subj}]}, - {xmlelement, "body", [], [{xmlcdata, BodyFormatted}]}]}); + {xmlelement, "body", [], [{xmlcdata, Body}]}]}); _ -> ok end. diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 038de586a..c1569bb61 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -47,8 +47,8 @@ -include("ejabberd.hrl"). -include("jlib.hrl"). -include("mod_roster.hrl"). --include("web/ejabberd_http.hrl"). --include("web/ejabberd_web_admin.hrl"). +-include("ejabberd_http.hrl"). +-include("ejabberd_web_admin.hrl"). start(Host, Opts) -> diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index d38121560..dfb76dcbe 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -46,8 +46,8 @@ -include("ejabberd.hrl"). -include("jlib.hrl"). -include("mod_roster.hrl"). --include("web/ejabberd_http.hrl"). --include("web/ejabberd_web_admin.hrl"). +-include("ejabberd_http.hrl"). +-include("ejabberd_web_admin.hrl"). start(Host, Opts) -> diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index ff378010d..f363bd22e 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -52,8 +52,8 @@ -include("ejabberd.hrl"). -include("jlib.hrl"). -include("mod_roster.hrl"). --include("web/ejabberd_http.hrl"). --include("web/ejabberd_web_admin.hrl"). +-include("ejabberd_http.hrl"). +-include("ejabberd_web_admin.hrl"). -record(sr_group, {group_host, opts}). -record(sr_user, {us, group_host}). diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index 2b5e7faac..2225f7c86 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -50,7 +50,7 @@ ]). -include("ejabberd.hrl"). --include("eldap/eldap.hrl"). +-include("eldap.hrl"). -include("jlib.hrl"). -define(PROCNAME, ejabberd_mod_vcard_ldap). diff --git a/src/odbc/Makefile.in b/src/odbc/Makefile.in index 974517c5b..5bd130b6e 100644 --- a/src/odbc/Makefile.in +++ b/src/odbc/Makefile.in @@ -9,7 +9,9 @@ LIBS = @LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ -EFLAGS = -I .. -pz .. +EFLAGS += -I ../../include +EFLAGS += -pz .. + # make debug=true to compile Erlang module with debug informations. ifdef debug EFLAGS+=+debug_info diff --git a/src/pam/Makefile.in b/src/pam/Makefile.in index d86b119b9..57c1ab78a 100644 --- a/src/pam/Makefile.in +++ b/src/pam/Makefile.in @@ -9,7 +9,9 @@ LIBS = @LIBS@ @PAM_LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ -EFLAGS = -I .. -pz .. +EFLAGS += -I ../../include +EFLAGS += -pz .. + # make debug=true to compile Erlang module with debug informations. ifdef debug EFLAGS+=+debug_info diff --git a/src/tls/Makefile.in b/src/tls/Makefile.in index dfb8c87d0..db4a874e1 100644 --- a/src/tls/Makefile.in +++ b/src/tls/Makefile.in @@ -19,7 +19,9 @@ else DYNAMIC_LIB_CFLAGS = -fpic -shared endif -EFLAGS = -I .. -pz .. +EFLAGS += -I ../../include +EFLAGS += -pz .. + # make debug=true to compile Erlang module with debug informations. ifdef debug EFLAGS+=+debug_info diff --git a/src/web/Makefile.in b/src/web/Makefile.in index 7c4732da8..3a75f7e17 100644 --- a/src/web/Makefile.in +++ b/src/web/Makefile.in @@ -9,7 +9,9 @@ LIBS = @LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ -EFLAGS = -I .. -pz .. +EFLAGS += -I ../../include +EFLAGS += -pz .. + # make debug=true to compile Erlang module with debug informations. ifdef debug EFLAGS+=+debug_info @@ -21,7 +23,7 @@ BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam)) all: $(BEAMS) -$(OUTDIR)/%.beam: %.erl ejabberd_http.hrl +$(OUTDIR)/%.beam: %.erl @ERLC@ -W $(EFLAGS) -o $(OUTDIR) $< clean: From 532e8ee228bab2ecf750cc7a15ea7a97cf766ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 17 Jul 2008 15:26:48 +0000 Subject: [PATCH 043/582] Start conversion to exmpp. For now, only direct calls from ejabberd_c2s are done. Calls through gen_iq_handler aren't. SVN Revision: 1457 --- ChangeLog | 6 ++++++ src/ejabberd_c2s.erl | 6 ++---- src/mod_caps.erl | 51 ++++++++++++++++++++------------------------ 3 files changed, 31 insertions(+), 32 deletions(-) diff --git a/ChangeLog b/ChangeLog index ae52d1fa1..8fe09d32c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-07-17 Jean-Sébastien Pédron + + * src/mod_caps.erl, src/ejabberd_c2s.erl: Start conversion to exmpp. + For now, only direct calls from ejabberd_c2s are done. Calls through + gen_iq_handler aren't. + 2008-07-15 Jean-Sébastien Pédron Merge revisions from 1434 to revision 1444 from trunk. diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 82fd029ce..8c35273a7 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1068,11 +1068,9 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> LFrom = jlib:short_jid(From), LBFrom = jlib:short_bare_jid(From), %% Note contact availability - % XXX OLD FORMAT: Els are #xmlelement. - Els = PacketOld#xmlelement.children, + Els = Packet#xmlel.children, Caps = mod_caps:read_caps(Els), - % XXX OLD FORMAT: From. - mod_caps:note_caps(StateData#state.server, FromOld, Caps), + mod_caps:note_caps(StateData#state.server, From, Caps), NewAvailable = case exmpp_presence:get_type(Packet) of 'unavailable' -> ?DICT:erase(LFrom, StateData#state.pres_available); diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 3240aa6e2..9d7846a48 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -48,8 +48,9 @@ code_change/3 ]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -define(PROCNAME, ejabberd_mod_caps). -define(DICT, dict). @@ -61,29 +62,26 @@ disco_requests = ?DICT:new(), feature_queries = []}). +% XXX OLD FORMAT: Re-include jlib.hrl (after clean-up). +-record(iq, {id = "", + type, + xmlns = "", + lang = "", + sub_el}). + %% read_caps takes a list of XML elements (the child elements of a %% stanza) and returns an opaque value representing the %% Entity Capabilities contained therein, or the atom nothing if no %% capabilities are advertised. read_caps(Els) -> read_caps(Els, nothing). -read_caps([{xmlelement, "c", Attrs, _Els} | Tail], Result) -> - case xml:get_attr_s("xmlns", Attrs) of - ?NS_CAPS -> - Node = xml:get_attr_s("node", Attrs), - Version = xml:get_attr_s("ver", Attrs), - Exts = string:tokens(xml:get_attr_s("ext", Attrs), " "), - read_caps(Tail, #caps{node = Node, version = Version, exts = Exts}); - _ -> - read_caps(Tail, Result) - end; -read_caps([{xmlelement, "x", Attrs, _Els} | Tail], Result) -> - case xml:get_attr_s("xmlns", Attrs) of - ?NS_MUC_USER -> - nothing; - _ -> - read_caps(Tail, Result) - end; +read_caps([#xmlel{ns = ?NS_CAPS, name = 'c'} = El | Tail], _Result) -> + Node = exmpp_xml:get_attribute(El, 'node'), + Version = exmpp_xml:get_attribute(El, 'ver'), + Exts = string:tokens(exmpp_xml:get_attribute(El, 'ext'), " "), + read_caps(Tail, #caps{node = Node, version = Version, exts = Exts}); +read_caps([#xmlel{ns = ?NS_MUC_USER, name = 'x'} | _Tail], _Result) -> + nothing; read_caps([_ | Tail], Result) -> read_caps(Tail, Result); read_caps([], Result) -> @@ -210,17 +208,14 @@ handle_cast({note_caps, From, lists:foldl( fun(SubNode, Dict) -> ID = randoms:get_string(), - Stanza = - {xmlelement, "iq", - [{"type", "get"}, - {"id", ID}], - [{xmlelement, "query", - [{"xmlns", ?NS_DISCO_INFO}, - {"node", lists:concat([Node, "#", SubNode])}], - []}]}, + Query = exmpp_xml:set_attribute( + #xmlel{ns = ?NS_DISCO_INFO, name = 'query'}, + 'node', lists:concat([Node, "#", SubNode])), + Stanza = exmpp_iq:get(?NS_JABBER_CLIENT, Query, ID), ejabberd_local:register_iq_response_handler (Host, ID, ?MODULE, handle_disco_response), - ejabberd_router:route(jlib:make_jid("", Host, ""), From, Stanza), + ejabberd_router:route(exmpp_jid:make_bare_jid(Host), + From, Stanza), timer:send_after(?CAPS_QUERY_TIMEOUT, self(), {disco_timeout, ID}), ?DICT:store(ID, {Node, SubNode}, Dict) end, Requests, Missing), @@ -301,7 +296,7 @@ handle_cast(visit_feature_queries, #state{feature_queries = FeatureQueries} = St {noreply, State#state{feature_queries = NewFeatureQueries}}. handle_disco_response(From, To, IQ) -> - #jid{lserver = Host} = To, + #jid{ldomain = Host} = To, Proc = gen_mod:get_module_proc(Host, ?PROCNAME), gen_server:cast(Proc, {disco_response, From, To, IQ}). From 07b1210b50771e10fec1500a5cc1830d26de052f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 17 Jul 2008 15:33:50 +0000 Subject: [PATCH 044/582] Merge revisions from 1444 to revision 1457 from trunk. SVN Revision: 1458 --- ChangeLog | 39 ++++++++++ doc/guide.html | 23 +++--- doc/guide.tex | 23 +++--- src/Makefile.in | 11 ++- {include => src}/adhoc.hrl | 0 {include => src}/ejabberd.hrl | 0 src/ejabberd_auth_ldap.erl | 2 +- src/ejabberd_c2s.erl | 9 ++- {include => src}/ejabberd_config.hrl | 0 {include => src}/ejabberd_ctl.hrl | 0 src/ejabberd_receiver.erl | 6 +- src/ejabberd_sm.erl | 15 +--- src/ejabberd_zlib/Makefile.in | 3 +- src/ejabberdctl.template | 45 ++++++------ src/eldap/Makefile.in | 3 +- {include => src/eldap}/eldap.hrl | 0 {include => src}/jlib.hrl | 0 src/mod_irc/Makefile.in | 2 +- src/mod_muc/Makefile.in | 2 +- src/mod_offline.erl | 4 +- src/mod_offline_odbc.erl | 4 +- {include => src}/mod_privacy.hrl | 0 src/mod_proxy65/Makefile.in | 2 +- {include => src/mod_proxy65}/mod_proxy65.hrl | 0 src/mod_pubsub/Makefile.in | 2 +- {include => src/mod_pubsub}/pubsub.hrl | 0 src/mod_roster.erl | 4 +- {include => src}/mod_roster.hrl | 0 src/mod_roster_odbc.erl | 4 +- src/mod_shared_roster.erl | 4 +- src/mod_vcard_ldap.erl | 2 +- src/odbc/Makefile.in | 2 +- src/pam/Makefile.in | 2 +- src/stringprep/Makefile.in | 4 +- src/tls/Makefile.in | 2 +- src/web/Makefile.in | 3 +- {include => src/web}/ejabberd_http.hrl | 0 src/web/ejabberd_http_poll.erl | 76 +++++++++----------- {include => src/web}/ejabberd_web_admin.hrl | 0 39 files changed, 166 insertions(+), 132 deletions(-) rename {include => src}/adhoc.hrl (100%) rename {include => src}/ejabberd.hrl (100%) rename {include => src}/ejabberd_config.hrl (100%) rename {include => src}/ejabberd_ctl.hrl (100%) rename {include => src/eldap}/eldap.hrl (100%) rename {include => src}/jlib.hrl (100%) rename {include => src}/mod_privacy.hrl (100%) rename {include => src/mod_proxy65}/mod_proxy65.hrl (100%) rename {include => src/mod_pubsub}/pubsub.hrl (100%) rename {include => src}/mod_roster.hrl (100%) rename {include => src/web}/ejabberd_http.hrl (100%) rename {include => src/web}/ejabberd_web_admin.hrl (100%) diff --git a/ChangeLog b/ChangeLog index 8fe09d32c..07524ef9b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,48 @@ +2008-07-17 Jean-Sébastien Pédron + + Merge revisions from 1444 to revision 1457 from trunk. + 2008-07-17 Jean-Sébastien Pédron * src/mod_caps.erl, src/ejabberd_c2s.erl: Start conversion to exmpp. For now, only direct calls from ejabberd_c2s are done. Calls through gen_iq_handler aren't. +2008-07-17 Christophe Romain + + * src/web/Makefile.in: use -DSSL39 if compiling with R12 + +2008-07-16 Badlop + + * src/ejabberd_c2s.erl: Put auth_module in Info always (EJAB-549) + + * src/*.hrl: Get back all ejabberd header files to their original + placement in src/ subdirectories (EJAB-696) + * src/*/*.erl: Likewise + * src/*/Makefile.in: Likewise + * src/Makefile.in: Install header files in system include/ dir, + reproducing the subdirectory structure of src/ + + * src/ejabberdctl.template: Update environment variable names + +2008-07-15 Badlop + + * src/ejabberdctl.template: Small fix so arguments of the command + are also passed to erl + + * doc/guide.tex: Improve explanation of option 'hosts' in + ejabberd_service + * doc/guide.html: Likewise + +2008-07-15 Alexey Shchepin + + * src/web/ejabberd_http_poll.erl: Report connection's IP address + + * src/ejabberd_c2s.erl: Rolled back the previous IP getting patch + * src/ejabberd_sm.erl: Likewise + * src/ejabberd_receiver.erl: Likewise + * src/web/ejabberd_http_poll.erl: Likewise + 2008-07-15 Jean-Sébastien Pédron Merge revisions from 1434 to revision 1444 from trunk. diff --git a/doc/guide.html b/doc/guide.html index 735fc1f8c..02ea12132 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -637,9 +637,14 @@ This option can be used with ejabberd_service only. It is used to disable control on the from field on packets send by an external components. The option can be either true or false. The default value is true which conforms to XEP-0114. -
      {hosts, [Hostnames], [HostOptions]}
      This option -defines one or more hostnames of connected services and enables you to -specify additional options including {password, Secret}. +
      {hosts, [Hostnames], [HostOptions]}
      +This option of ejabberd_service allows to define one or more hostnames +of external Jabber components that provide a service. +In HostOptions it is possible to define the password required to those components +when attempt to connect to ejabberd: {password, Secret}. +Note that you cannot define in a single ejabberd_service components of +different services: add an ejabberd_service for each service, +as seen in an example below.
      http_bind
      This option enables HTTP Binding (XEP-0124 and XEP-0206) support. HTTP Bind enables access via HTTP requests to ejabberd from behind firewalls which @@ -818,19 +823,19 @@ connected to port 5237 with password ‘ggsecret’. ssl, {certfile, "/path/to/ssl.pem"}]}, {5269, ejabberd_s2s_in, []}, {5280, ejabberd_http, [http_poll, web_admin]}, - {5233, ejabberd_service, [{host, "aim.example.org", + {5233, ejabberd_service, [{hosts, ["aim.example.org"], [{password, "aimsecret"}]}]}, {5234, ejabberd_service, [{hosts, ["icq.example.org", "sms.example.org"], [{password, "jitsecret"}]}]}, - {5235, ejabberd_service, [{host, "msn.example.org", + {5235, ejabberd_service, [{hosts, ["msn.example.org"], [{password, "msnsecret"}]}]}, - {5236, ejabberd_service, [{host, "yahoo.example.org", + {5236, ejabberd_service, [{hosts, ["yahoo.example.org"], [{password, "yahoosecret"}]}]}, - {5237, ejabberd_service, [{host, "gg.example.org", + {5237, ejabberd_service, [{hosts, ["gg.example.org"], [{password, "ggsecret"}]}]}, - {5238, ejabberd_service, [{host, "jmc.example.org", + {5238, ejabberd_service, [{hosts, ["jmc.example.org"], [{password, "jmcsecret"}]}]}, - {5239, ejabberd_service, [{host, "custom.example.org", + {5239, ejabberd_service, [{hosts, ["custom.example.org"], [{password, "customsecret"}]}, {service_check_from, false}]} ] diff --git a/doc/guide.tex b/doc/guide.tex index 3831ac024..17cfbeb80 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -748,9 +748,14 @@ This is a detailed description of each option allowed by the listening modules: used to disable control on the from field on packets send by an external components. The option can be either \term{true} or \term{false}. The default value is \term{true} which conforms to \xepref{0114}. - \titem{\{hosts, [Hostnames], [HostOptions]\}} \ind{options!hosts}This option - defines one or more hostnames of connected services and enables you to - specify additional options including \poption{\{password, Secret\}}. + \titem{\{hosts, [Hostnames], [HostOptions]\}} \ind{options!hosts} + This option of \term{ejabberd\_service} allows to define one or more hostnames + of external Jabber components that provide a service. + In \term{HostOptions} it is possible to define the password required to those components + when attempt to connect to ejabberd: \poption{\{password, Secret\}}. + Note that you cannot define in a single \term{ejabberd\_service} components of + different services: add an \term{ejabberd\_service} for each service, + as seen in an example below. \titem{http\_bind} \ind{options!http\_bind}\ind{protocols!XEP-0206: HTTP Binding}\ind{JWChat}\ind{web-based Jabber client} This option enables HTTP Binding (\xepref{0124} and \xepref{0206}) support. HTTP Bind enables access via HTTP requests to \ejabberd{} from behind firewalls which @@ -945,19 +950,19 @@ In this example, the following configuration defines that: ssl, {certfile, "/path/to/ssl.pem"}]}, {5269, ejabberd_s2s_in, []}, {5280, ejabberd_http, [http_poll, web_admin]}, - {5233, ejabberd_service, [{host, "aim.example.org", + {5233, ejabberd_service, [{hosts, ["aim.example.org"], [{password, "aimsecret"}]}]}, {5234, ejabberd_service, [{hosts, ["icq.example.org", "sms.example.org"], [{password, "jitsecret"}]}]}, - {5235, ejabberd_service, [{host, "msn.example.org", + {5235, ejabberd_service, [{hosts, ["msn.example.org"], [{password, "msnsecret"}]}]}, - {5236, ejabberd_service, [{host, "yahoo.example.org", + {5236, ejabberd_service, [{hosts, ["yahoo.example.org"], [{password, "yahoosecret"}]}]}, - {5237, ejabberd_service, [{host, "gg.example.org", + {5237, ejabberd_service, [{hosts, ["gg.example.org"], [{password, "ggsecret"}]}]}, - {5238, ejabberd_service, [{host, "jmc.example.org", + {5238, ejabberd_service, [{hosts, ["jmc.example.org"], [{password, "jmcsecret"}]}]}, - {5239, ejabberd_service, [{host, "custom.example.org", + {5239, ejabberd_service, [{hosts, ["custom.example.org"], [{password, "customsecret"}]}, {service_check_from, false}]} ] diff --git a/src/Makefile.in b/src/Makefile.in index 3d398f569..5dabf5431 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -29,7 +29,6 @@ else endif EFLAGS += @ERLANG_SSL39@ -EFLAGS += -I ../include # make debug=true to compile Erlang module with debug informations. ifdef debug @@ -189,7 +188,15 @@ install: all # # ejabberd header files install -d $(INCLUDEDIR) - install -m 644 ../include/*.hrl $(INCLUDEDIR) + install -m 644 *.hrl $(INCLUDEDIR) + install -d $(INCLUDEDIR)/eldap/ + install -m 644 eldap/*.hrl $(INCLUDEDIR)/eldap/ + install -d $(INCLUDEDIR)/mod_proxy65/ + install -m 644 mod_proxy65/*.hrl $(INCLUDEDIR)/mod_proxy65/ + install -d $(INCLUDEDIR)/mod_pubsub/ + install -m 644 mod_pubsub/*.hrl $(INCLUDEDIR)/mod_pubsub/ + install -d $(INCLUDEDIR)/web/ + install -m 644 web/*.hrl $(INCLUDEDIR)/web/ # # Binary C programs install -d $(PBINDIR) diff --git a/include/adhoc.hrl b/src/adhoc.hrl similarity index 100% rename from include/adhoc.hrl rename to src/adhoc.hrl diff --git a/include/ejabberd.hrl b/src/ejabberd.hrl similarity index 100% rename from include/ejabberd.hrl rename to src/ejabberd.hrl diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl index b9bf3b477..d576a82fd 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -58,7 +58,7 @@ ]). -include("ejabberd.hrl"). --include("eldap.hrl"). +-include("eldap/eldap.hrl"). -record(state, {host, eldap_id, diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 8c35273a7..da1239064 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1221,9 +1221,6 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> handle_info({'DOWN', Monitor, _Type, _Object, _Info}, _StateName, StateData) when Monitor == StateData#state.socket_monitor -> {stop, normal, StateData}; -handle_info({peername, IP}, StateName, StateData) -> - ejabberd_sm:set_session_ip(StateData#state.sid, IP), - fsm_next_state(StateName, StateData#state{ip = IP}); handle_info(Info, StateName, StateData) -> ?ERROR_MSG("Unexpected info: ~p", [Info]), fsm_next_state(StateName, StateData). @@ -1420,7 +1417,8 @@ presence_update(From, Packet, StateData) -> undefined -> ""; S -> S end, - Info = [{ip, StateData#state.ip},{conn, StateData#state.conn}], + Info = [{ip, StateData#state.ip}, {conn, StateData#state.conn}, + {auth_module, StateData#state.auth_module}], ejabberd_sm:unset_presence(StateData#state.sid, StateData#state.user, StateData#state.server, @@ -1804,7 +1802,8 @@ roster_change(IJID, ISubscription, StateData) -> update_priority(Priority, Packet, StateData) -> - Info = [{ip, StateData#state.ip},{conn, StateData#state.conn}], + Info = [{ip, StateData#state.ip}, {conn, StateData#state.conn}, + {auth_module, StateData#state.auth_module}], ejabberd_sm:set_presence(StateData#state.sid, StateData#state.user, StateData#state.server, diff --git a/include/ejabberd_config.hrl b/src/ejabberd_config.hrl similarity index 100% rename from include/ejabberd_config.hrl rename to src/ejabberd_config.hrl diff --git a/include/ejabberd_ctl.hrl b/src/ejabberd_ctl.hrl similarity index 100% rename from include/ejabberd_ctl.hrl rename to src/ejabberd_ctl.hrl diff --git a/src/ejabberd_receiver.erl b/src/ejabberd_receiver.erl index 3b6c80439..5fdad76af 100644 --- a/src/ejabberd_receiver.erl +++ b/src/ejabberd_receiver.erl @@ -268,8 +268,7 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- activate_socket(#state{socket = Socket, - sock_mod = SockMod, - c2s_pid = C2SPid}) -> + sock_mod = SockMod}) -> PeerName = case SockMod of gen_tcp -> @@ -282,8 +281,7 @@ activate_socket(#state{socket = Socket, case PeerName of {error, _Reason} -> self() ! {tcp_closed, Socket}; - {ok, IP} -> - C2SPid ! {peername, IP}, + {ok, _} -> ok end. diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index ccf679386..9300958d5 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -49,8 +49,7 @@ ctl_process/2, get_session_pid/3, get_user_info/3, - get_user_ip/3, - set_session_ip/2 + get_user_ip/3 ]). %% gen_server callbacks @@ -187,18 +186,6 @@ get_user_info(User, Server, Resource) -> [{node, Node}, {conn, Conn}, {ip, IP}] end. -set_session_ip(SID, IP) -> - case mnesia:dirty_read(session, SID) of - [#session{info = Info} = Session] -> - NewInfo = case lists:keymember(ip, 1, Info) of - true -> lists:keyreplace(ip, 1, Info, {ip, IP}); - false -> [{ip, IP}|Info] - end, - mnesia:dirty_write(Session#session{info = NewInfo}); - _ -> - ok - end. - set_presence(SID, User, Server, Resource, Priority, Presence, Info) -> set_session(SID, User, Server, Resource, Priority, Info), % XXX OLD FORMAT: Presence. diff --git a/src/ejabberd_zlib/Makefile.in b/src/ejabberd_zlib/Makefile.in index 3a70186bd..dd781d0ae 100644 --- a/src/ejabberd_zlib/Makefile.in +++ b/src/ejabberd_zlib/Makefile.in @@ -19,8 +19,9 @@ else DYNAMIC_LIB_CFLAGS = -fpic -shared endif -EFLAGS += -I ../../include +EFLAGS += -I .. EFLAGS += -pz .. + # make debug=true to compile Erlang module with debug informations. ifdef debug EFLAGS+=+debug_info diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template index fcf0a80cc..02ebd56b5 100644 --- a/src/ejabberdctl.template +++ b/src/ejabberdctl.template @@ -15,12 +15,12 @@ ERL=@erl@ INSTALLUSER=@installuser@ ETCDIR=@SYSCONFDIR@/ejabberd EJABBERD_CONFIG_PATH=$ETCDIR/ejabberd.cfg -LOGDIR=@LOCALSTATEDIR@/log/ejabberd +LOGS_DIR=@LOCALSTATEDIR@/log/ejabberd SPOOLDIR=@LOCALSTATEDIR@/lib/ejabberd # read custom configuration -CONFIG=$ETCDIR/ejabberdctl.cfg -[ -f "$CONFIG" ] && . "$CONFIG" +EJABBERDCTL_CONFIG_PATH=$ETCDIR/ejabberdctl.cfg +[ -f "$EJABBERDCTL_CONFIG_PATH" ] && . "$EJABBERDCTL_CONFIG_PATH" # parse command line parameters ARGS= @@ -31,8 +31,8 @@ while [ $# -ne 0 ] ; do --) break ;; --node) ERLANG_NODE=$1; shift ;; --config) EJABBERD_CONFIG_PATH=$1 ; shift ;; - --ctl-config) CONFIG=$1 ; shift ;; - --logs) LOGDIR=$1 ; shift ;; + --ctl-config) EJABBERDCTL_CONFIG_PATH=$1 ; shift ;; + --logs) LOGS_DIR=$1 ; shift ;; --spool) SPOOLDIR=$1 ; shift ;; *) ARGS="$ARGS $PARAM" ;; esac @@ -66,16 +66,16 @@ ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $KERNEL_OPTS" # define additional environment variables EJABBERDDIR=@LIBDIR@/ejabberd -BEAMDIR=$EJABBERDDIR/ebin -PRIVDIR=$EJABBERDDIR/priv -PBINDIR=$PRIVDIR/bin -SODIR=$PRIVDIR/lib -MSGSDIR=$PRIVDIR/msgs +EJABBERD_EBIN_PATH=$EJABBERDDIR/ebin +EJABBERD_PRIV_PATH=$EJABBERDDIR/priv +EJABBERD_BIN_PATH=$EJABBERD_PRIV_PATH/bin +EJABBERD_SO_PATH=$EJABBERD_PRIV_PATH/lib +EJABBERD_MSGS_PATH=$EJABBERD_PRIV_PATH/msgs -EJABBERD_LOG_PATH=$LOGDIR/ejabberd.log -SASL_LOG_PATH=$LOGDIR/sasl.log +EJABBERD_LOG_PATH=$LOGS_DIR/ejabberd.log +SASL_LOG_PATH=$LOGS_DIR/sasl.log DATETIME=`date "+%Y%m%d-%H%M%S"` -ERL_CRASH_DUMP=$LOGDIR/erl_crash_$DATETIME.dump +ERL_CRASH_DUMP=$LOGS_DIR/erl_crash_$DATETIME.dump ERL_INETRC=$ETCDIR/inetrc HOME=$SPOOLDIR @@ -84,10 +84,10 @@ HOME=$SPOOLDIR # export global variables export EJABBERD_CONFIG_PATH -export MSGSDIR +export EJABBERD_MSGS_PATH export EJABBERD_LOG_PATH -export SODIR -export PBINDIR +export EJABBERD_SO_PATH +export EJABBERD_BIN_PATH export ERL_CRASH_DUMP export ERL_INETRC export ERL_MAX_PORTS @@ -105,7 +105,7 @@ start () $EXEC_CMD "$ERL \ $NAME $ERLANG_NODE \ -noinput -detached \ - -pa $BEAMDIR \ + -pa $EJABBERD_EBIN_PATH \ -mnesia dir \"\\\"$SPOOLDIR\\\"\" \ -s ejabberd \ -sasl sasl_error_logger \\{file,\\\"$SASL_LOG_PATH\\\"\\} \ @@ -157,7 +157,7 @@ live () echo "" $EXEC_CMD "$ERL \ $NAME $ERLANG_NODE \ - -pa $BEAMDIR \ + -pa $EJABBERD_EBIN_PATH \ -mnesia dir \"\\\"$SPOOLDIR\\\"\" \ -s ejabberd \ $ERLANG_OPTS $ARGS \"$@\"" @@ -166,11 +166,12 @@ live () # common control function ctl () { + COMMAND=$@ $EXEC_CMD "$ERL \ $NAME ejabberdctl \ -noinput \ - -pa $BEAMDIR \ - -s ejabberd_ctl -extra $ERLANG_NODE $@" + -pa $EJABBERD_EBIN_PATH \ + -s ejabberd_ctl -extra $ERLANG_NODE $COMMAND" result=$? case $result in 0) :;; @@ -183,8 +184,8 @@ ctl () echo "" echo "Optional parameters when starting an ejabberd node:" echo " --config file Config file of ejabberd: $EJABBERD_CONFIG_PATH" - echo " --ctl-config file Config file of ejabberdctl: $CONFIG" - echo " --logs dir Directory for logs: $LOGDIR" + echo " --ctl-config file Config file of ejabberdctl: $EJABBERDCTL_CONFIG_PATH" + echo " --logs dir Directory for logs: $LOGS_DIR" echo " --spool dir Database spool dir: $SPOOLDIR" echo " --node nodename ejabberd node name: $ERLANG_NODE" echo "";; diff --git a/src/eldap/Makefile.in b/src/eldap/Makefile.in index 4c9c33c22..22cdad48b 100644 --- a/src/eldap/Makefile.in +++ b/src/eldap/Makefile.in @@ -9,8 +9,9 @@ LIBS = @LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ -EFLAGS += -I ../../include +EFLAGS += -I .. EFLAGS += -pz .. + # make debug=true to compile Erlang module with debug informations. ifdef debug EFLAGS+=+debug_info diff --git a/include/eldap.hrl b/src/eldap/eldap.hrl similarity index 100% rename from include/eldap.hrl rename to src/eldap/eldap.hrl diff --git a/include/jlib.hrl b/src/jlib.hrl similarity index 100% rename from include/jlib.hrl rename to src/jlib.hrl diff --git a/src/mod_irc/Makefile.in b/src/mod_irc/Makefile.in index 86212e45c..76a2d57f6 100644 --- a/src/mod_irc/Makefile.in +++ b/src/mod_irc/Makefile.in @@ -16,7 +16,7 @@ else DYNAMIC_LIB_CFLAGS = -fpic -shared endif -EFLAGS += -I ../../include +EFLAGS += -I .. EFLAGS += -pz .. # make debug=true to compile Erlang module with debug informations. diff --git a/src/mod_muc/Makefile.in b/src/mod_muc/Makefile.in index 80725d33d..5ede5e521 100644 --- a/src/mod_muc/Makefile.in +++ b/src/mod_muc/Makefile.in @@ -9,7 +9,7 @@ LIBS = @LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ -EFLAGS += -I ../../include +EFLAGS += -I .. EFLAGS += -pz .. # make debug=true to compile Erlang module with debug informations. diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 3db29844b..3a751c328 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -43,8 +43,8 @@ -include("ejabberd.hrl"). -include("jlib.hrl"). --include("ejabberd_http.hrl"). --include("ejabberd_web_admin.hrl"). +-include("web/ejabberd_http.hrl"). +-include("web/ejabberd_web_admin.hrl"). -record(offline_msg, {us, timestamp, expire, from, to, packet}). diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index 79d7c51ae..c3d0513d0 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -42,8 +42,8 @@ -include("ejabberd.hrl"). -include("jlib.hrl"). --include("ejabberd_http.hrl"). --include("ejabberd_web_admin.hrl"). +-include("web/ejabberd_http.hrl"). +-include("web/ejabberd_web_admin.hrl"). -record(offline_msg, {user, timestamp, expire, from, to, packet}). diff --git a/include/mod_privacy.hrl b/src/mod_privacy.hrl similarity index 100% rename from include/mod_privacy.hrl rename to src/mod_privacy.hrl diff --git a/src/mod_proxy65/Makefile.in b/src/mod_proxy65/Makefile.in index 62ae77c9f..3fc94c662 100644 --- a/src/mod_proxy65/Makefile.in +++ b/src/mod_proxy65/Makefile.in @@ -9,7 +9,7 @@ LIBS = @LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ -EFLAGS += -I ../../include +EFLAGS += -I .. EFLAGS += -pz .. # make debug=true to compile Erlang module with debug informations. diff --git a/include/mod_proxy65.hrl b/src/mod_proxy65/mod_proxy65.hrl similarity index 100% rename from include/mod_proxy65.hrl rename to src/mod_proxy65/mod_proxy65.hrl diff --git a/src/mod_pubsub/Makefile.in b/src/mod_pubsub/Makefile.in index 25dbf57a5..4088303cb 100644 --- a/src/mod_pubsub/Makefile.in +++ b/src/mod_pubsub/Makefile.in @@ -9,7 +9,7 @@ LIBS = @LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ -EFLAGS += -I ../../include +EFLAGS += -I .. EFLAGS += -pz .. # make debug=true to compile Erlang module with debug informations. diff --git a/include/pubsub.hrl b/src/mod_pubsub/pubsub.hrl similarity index 100% rename from include/pubsub.hrl rename to src/mod_pubsub/pubsub.hrl diff --git a/src/mod_roster.erl b/src/mod_roster.erl index c1569bb61..038de586a 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -47,8 +47,8 @@ -include("ejabberd.hrl"). -include("jlib.hrl"). -include("mod_roster.hrl"). --include("ejabberd_http.hrl"). --include("ejabberd_web_admin.hrl"). +-include("web/ejabberd_http.hrl"). +-include("web/ejabberd_web_admin.hrl"). start(Host, Opts) -> diff --git a/include/mod_roster.hrl b/src/mod_roster.hrl similarity index 100% rename from include/mod_roster.hrl rename to src/mod_roster.hrl diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index dfb76dcbe..d38121560 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -46,8 +46,8 @@ -include("ejabberd.hrl"). -include("jlib.hrl"). -include("mod_roster.hrl"). --include("ejabberd_http.hrl"). --include("ejabberd_web_admin.hrl"). +-include("web/ejabberd_http.hrl"). +-include("web/ejabberd_web_admin.hrl"). start(Host, Opts) -> diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index f363bd22e..ff378010d 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -52,8 +52,8 @@ -include("ejabberd.hrl"). -include("jlib.hrl"). -include("mod_roster.hrl"). --include("ejabberd_http.hrl"). --include("ejabberd_web_admin.hrl"). +-include("web/ejabberd_http.hrl"). +-include("web/ejabberd_web_admin.hrl"). -record(sr_group, {group_host, opts}). -record(sr_user, {us, group_host}). diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index 2225f7c86..2b5e7faac 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -50,7 +50,7 @@ ]). -include("ejabberd.hrl"). --include("eldap.hrl"). +-include("eldap/eldap.hrl"). -include("jlib.hrl"). -define(PROCNAME, ejabberd_mod_vcard_ldap). diff --git a/src/odbc/Makefile.in b/src/odbc/Makefile.in index 5bd130b6e..3f4898d3a 100644 --- a/src/odbc/Makefile.in +++ b/src/odbc/Makefile.in @@ -9,7 +9,7 @@ LIBS = @LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ -EFLAGS += -I ../../include +EFLAGS += -I .. EFLAGS += -pz .. # make debug=true to compile Erlang module with debug informations. diff --git a/src/pam/Makefile.in b/src/pam/Makefile.in index 57c1ab78a..bde289402 100644 --- a/src/pam/Makefile.in +++ b/src/pam/Makefile.in @@ -9,7 +9,7 @@ LIBS = @LIBS@ @PAM_LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ -EFLAGS += -I ../../include +EFLAGS += -I .. EFLAGS += -pz .. # make debug=true to compile Erlang module with debug informations. diff --git a/src/stringprep/Makefile.in b/src/stringprep/Makefile.in index 248aee693..3ac6c24db 100644 --- a/src/stringprep/Makefile.in +++ b/src/stringprep/Makefile.in @@ -16,7 +16,9 @@ else DYNAMIC_LIB_CFLAGS = -fpic -shared endif -EFLAGS = -I .. -pz .. +EFLAGS += -I .. +EFLAGS += -pz .. + # make debug=true to compile Erlang module with debug informations. ifdef debug EFLAGS+=+debug_info diff --git a/src/tls/Makefile.in b/src/tls/Makefile.in index db4a874e1..b6f10efc2 100644 --- a/src/tls/Makefile.in +++ b/src/tls/Makefile.in @@ -19,7 +19,7 @@ else DYNAMIC_LIB_CFLAGS = -fpic -shared endif -EFLAGS += -I ../../include +EFLAGS += -I .. EFLAGS += -pz .. # make debug=true to compile Erlang module with debug informations. diff --git a/src/web/Makefile.in b/src/web/Makefile.in index 3a75f7e17..21f7c9348 100644 --- a/src/web/Makefile.in +++ b/src/web/Makefile.in @@ -9,7 +9,8 @@ LIBS = @LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ -EFLAGS += -I ../../include +EFLAGS += @ERLANG_SSL39@ +EFLAGS += -I .. EFLAGS += -pz .. # make debug=true to compile Erlang module with debug informations. diff --git a/include/ejabberd_http.hrl b/src/web/ejabberd_http.hrl similarity index 100% rename from include/ejabberd_http.hrl rename to src/web/ejabberd_http.hrl diff --git a/src/web/ejabberd_http_poll.erl b/src/web/ejabberd_http_poll.erl index ad6c46b77..2b36136cd 100644 --- a/src/web/ejabberd_http_poll.erl +++ b/src/web/ejabberd_http_poll.erl @@ -30,7 +30,7 @@ -behaviour(gen_fsm). %% External exports --export([start_link/2, +-export([start_link/3, init/1, handle_event/3, handle_sync_event/4, @@ -50,16 +50,14 @@ -record(http_poll, {id, pid}). --define(NULL_PEER, {{0, 0, 0, 0}, 0}). - -record(state, {id, key, + socket, output = "", input = "", waiting_input = false, %% {ReceiverPid, Tag} last_receiver, - timer, - ip = ?NULL_PEER }). + timer}). %-define(DBGFSM, true). @@ -77,19 +75,19 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- -start(ID, Key) -> +start(ID, Key, IP) -> mnesia:create_table(http_poll, [{ram_copies, [node()]}, {attributes, record_info(fields, http_poll)}]), - supervisor:start_child(ejabberd_http_poll_sup, [ID, Key]). + supervisor:start_child(ejabberd_http_poll_sup, [ID, Key, IP]). -start_link(ID, Key) -> - gen_fsm:start_link(?MODULE, [ID, Key], ?FSMOPTS). +start_link(ID, Key, IP) -> + gen_fsm:start_link(?MODULE, [ID, Key, IP], ?FSMOPTS). -send({http_poll, FsmRef}, Packet) -> +send({http_poll, FsmRef, _IP}, Packet) -> gen_fsm:sync_send_all_state_event(FsmRef, {send, Packet}). -setopts({http_poll, FsmRef}, Opts) -> +setopts({http_poll, FsmRef, _IP}, Opts) -> case lists:member({active, once}, Opts) of true -> gen_fsm:send_all_state_event(FsmRef, {activate, self()}); @@ -97,31 +95,27 @@ setopts({http_poll, FsmRef}, Opts) -> ok end. -sockname(_) -> - {ok, ?NULL_PEER}. +sockname(_Socket) -> + {ok, {{0, 0, 0, 0}, 0}}. -peername({http_poll, FsmRef}) -> - case catch gen_fsm:sync_send_all_state_event(FsmRef, peername, 1000) of - {ok, IP} -> {ok, IP}; - _ -> {ok, ?NULL_PEER} - end; -peername(_) -> - {ok, ?NULL_PEER}. +peername({http_poll, _FsmRef, IP}) -> + {ok, IP}. controlling_process(_Socket, _Pid) -> ok. -close({http_poll, FsmRef}) -> +close({http_poll, FsmRef, _IP}) -> catch gen_fsm:sync_send_all_state_event(FsmRef, close). -process([], #request{data = Data, ip = IP} = _Request) -> +process([], #request{data = Data, + ip = IP} = _Request) -> case catch parse_request(Data) of {ok, ID1, Key, NewKey, Packet} -> ID = if (ID1 == "0") or (ID1 == "mobile") -> NewID = sha:sha(term_to_binary({now(), make_ref()})), - {ok, Pid} = start(NewID, ""), + {ok, Pid} = start(NewID, "", IP), mnesia:transaction( fun() -> mnesia:write(#http_poll{id = NewID, @@ -131,7 +125,7 @@ process([], #request{data = Data, ip = IP} = _Request) -> true -> ID1 end, - case http_put(ID, Key, NewKey, Packet, IP) of + case http_put(ID, Key, NewKey, Packet) of {error, not_exists} -> {200, ?BAD_REQUEST, ""}; {error, bad_key} -> @@ -176,8 +170,8 @@ process(_, _Request) -> %% ignore | %% {stop, StopReason} %%---------------------------------------------------------------------- -init([ID, Key]) -> - ?INFO_MSG("started: ~p", [{ID, Key}]), +init([ID, Key, IP]) -> + ?INFO_MSG("started: ~p", [{ID, Key, IP}]), %% Read c2s options from the first ejabberd_c2s configuration in %% the config file listen section @@ -187,12 +181,12 @@ init([ID, Key]) -> %% connector. Opts = ejabberd_c2s_config:get_c2s_limits(), - ejabberd_socket:start(ejabberd_c2s, ?MODULE, {http_poll, self()}, Opts), - %{ok, C2SPid} = ejabberd_c2s:start({?MODULE, {http_poll, self()}}, Opts), - %ejabberd_c2s:become_controller(C2SPid), + Socket = {http_poll, self(), IP}, + ejabberd_socket:start(ejabberd_c2s, ?MODULE, Socket, Opts), Timer = erlang:start_timer(?HTTP_POLL_TIMEOUT, self(), []), {ok, loop, #state{id = ID, key = Key, + socket = Socket, timer = Timer}}. %%---------------------------------------------------------------------- @@ -229,7 +223,7 @@ handle_event({activate, From}, StateName, StateData) -> StateData#state{waiting_input = {From, ok}}}; Input -> Receiver = From, - Receiver ! {tcp, {http_poll, self()}, list_to_binary(Input)}, + Receiver ! {tcp, StateData#state.socket, list_to_binary(Input)}, {next_state, StateName, StateData#state{input = "", waiting_input = false, last_receiver = Receiver @@ -257,7 +251,7 @@ handle_sync_event(stop, _From, _StateName, StateData) -> Reply = ok, {stop, normal, Reply, StateData}; -handle_sync_event({http_put, Key, NewKey, Packet, IP}, +handle_sync_event({http_put, Key, NewKey, Packet}, _From, StateName, StateData) -> Allow = case StateData#state.key of "" -> @@ -279,10 +273,9 @@ handle_sync_event({http_put, Key, NewKey, Packet, IP}, Input = [StateData#state.input|Packet], Reply = ok, {reply, Reply, StateName, StateData#state{input = Input, - key = NewKey, - ip = IP}}; + key = NewKey}}; {Receiver, _Tag} -> - Receiver ! {tcp, {http_poll, self()}, + Receiver ! {tcp, StateData#state.socket, list_to_binary(Packet)}, cancel_timer(StateData#state.timer), Timer = erlang:start_timer(?HTTP_POLL_TIMEOUT, self(), []), @@ -291,8 +284,7 @@ handle_sync_event({http_put, Key, NewKey, Packet, IP}, StateData#state{waiting_input = false, last_receiver = Receiver, key = NewKey, - timer = Timer, - ip = IP}} + timer = Timer}} end; true -> Reply = {error, bad_key}, @@ -303,10 +295,6 @@ handle_sync_event(http_get, _From, StateName, StateData) -> Reply = {ok, StateData#state.output}, {reply, Reply, StateName, StateData#state{output = ""}}; -handle_sync_event(peername, _From, StateName, StateData) -> - Reply = {ok, StateData#state.ip}, - {reply, Reply, StateName, StateData}; - handle_sync_event(_Event, _From, StateName, StateData) -> Reply = ok, {reply, Reply, StateName, StateData}. @@ -345,10 +333,10 @@ terminate(_Reason, _StateName, StateData) -> case StateData#state.last_receiver of undefined -> ok; Receiver -> - Receiver ! {tcp_closed, {http_poll, self()}} + Receiver ! {tcp_closed, StateData#state.socket} end; {Receiver, _Tag} -> - Receiver ! {tcp_closed, {http_poll, self()}} + Receiver ! {tcp_closed, StateData#state.socket} end, catch resend_messages(StateData#state.output), ok. @@ -357,13 +345,13 @@ terminate(_Reason, _StateName, StateData) -> %%% Internal functions %%%---------------------------------------------------------------------- -http_put(ID, Key, NewKey, Packet, IP) -> +http_put(ID, Key, NewKey, Packet) -> case mnesia:dirty_read({http_poll, ID}) of [] -> {error, not_exists}; [#http_poll{pid = FsmRef}] -> gen_fsm:sync_send_all_state_event( - FsmRef, {http_put, Key, NewKey, Packet, IP}) + FsmRef, {http_put, Key, NewKey, Packet}) end. http_get(ID) -> diff --git a/include/ejabberd_web_admin.hrl b/src/web/ejabberd_web_admin.hrl similarity index 100% rename from include/ejabberd_web_admin.hrl rename to src/web/ejabberd_web_admin.hrl From 75a8be230ba09219f4bd87b2e3bc1bf0ede0a919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 21 Jul 2008 15:28:44 +0000 Subject: [PATCH 045/582] Prepare gen_iq_handler to pass arguments in the new format to a built-in list of modules known to support them. Other modules will still receive arguments in the old format. SVN Revision: 1462 --- ChangeLog | 6 +++ src/gen_iq_handler.erl | 85 +++++++++++++++++++++++++++--------------- 2 files changed, 60 insertions(+), 31 deletions(-) diff --git a/ChangeLog b/ChangeLog index 07524ef9b..20b91bbfc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-07-21 Jean-Sébastien Pédron + + * src/gen_iq_handler.erl: Prepare gen_iq_handler to pass arguments in + the new format to a built-in list of modules known to support them. + Other modules will still receive arguments in the old format. + 2008-07-17 Jean-Sébastien Pédron Merge revisions from 1444 to revision 1457 from trunk. diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index e3da47f0c..11fba0929 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -56,6 +56,11 @@ lang = "", sub_el}). +% XXX OLD FORMAT: modules not in the following list will receive +% old format strudctures. +-define(CONVERTED_MODULES, [ +]). + %%==================================================================== %% API %%==================================================================== @@ -110,37 +115,55 @@ handle(Host, Module, Function, Opts, From, To, IQ) -> no_queue -> process_iq(Host, Module, Function, From, To, IQ); {one_queue, Pid} -> - {FromOld, ToOld, IQ_Rec} = convert_to_old_structs(From, To, IQ), - Pid ! {process_iq, FromOld, ToOld, IQ_Rec}; + Pid ! {process_iq, From, To, IQ}; {queues, Pids} -> Pid = lists:nth(erlang:phash(now(), length(Pids)), Pids), - {FromOld, ToOld, IQ_Rec} = convert_to_old_structs(From, To, IQ), - Pid ! {process_iq, FromOld, ToOld, IQ_Rec}; + Pid ! {process_iq, From, To, IQ}; parallel -> - spawn(?MODULE, process_iq, [Host, Module, Function, From, To, IQ]); + spawn(?MODULE, process_iq, + [Host, Module, Function, From, To, IQ]); _ -> todo end. +process_iq(Host, Module, Function, FromOld, ToOld, IQ_Rec) + when is_record(IQ_Rec, iq) -> + catch throw(for_stacktrace), % To have a stacktrace. + io:format("~nIQ HANDLER: old #iq for ~s:~s:~n~p~n~p~n~n", + [Module, Function, IQ_Rec, erlang:get_stacktrace()]), + From = jlib:from_old_jid(FromOld), + To = jlib:from_old_jid(ToOld), + IQOld = jlib:iq_to_xml(IQ_Rec), + IQOld1 = IQOld#xmlelement{children = [IQOld#xmlelement.children]}, + IQ = exmpp_xml:xmlelement_to_xmlel(IQOld1, + [?NS_JABBER_CLIENT], + [{?NS_XMPP, ?NS_XMPP_pfx}, + {?NS_DIALBACK, ?NS_DIALBACK_pfx}]), + process_iq(Host, Module, Function, From, To, IQ); process_iq(_Host, Module, Function, From, To, IQ) -> - {FromOld, ToOld, IQ_Rec} = convert_to_old_structs(From, To, IQ), - case catch Module:Function(FromOld, ToOld, IQ_Rec) of + Ret = case lists:member(Module, ?CONVERTED_MODULES) of + true -> + catch Module:Function(From, To, IQ); + false -> + {FromOld, ToOld, IQ_Rec} = convert_to_old_structs( + Module, Function, From, To, IQ), + catch Module:Function(FromOld, ToOld, IQ_Rec) + end, + case Ret of {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); - ResIQ -> - if - ResIQ /= ignore -> - ReplyOld = jlib:iq_to_xml(ResIQ), - Reply = exmpp_xml:xmlelement_to_xmlel(ReplyOld, - [?NS_JABBER_CLIENT], - [{?NS_XMPP, ?NS_XMPP_pfx}, - {?NS_DIALBACK, ?NS_DIALBACK_pfx}]), - ejabberd_router:route(To, From, - Reply); - true -> - ok - end + ignore -> + ok; + ResIQ when is_record(ResIQ, iq) -> + ReplyOld = jlib:iq_to_xml(ResIQ), + Reply = exmpp_xml:xmlelement_to_xmlel(ReplyOld, + [?NS_JABBER_CLIENT], + [{?NS_XMPP, ?NS_XMPP_pfx}, + {?NS_DIALBACK, ?NS_DIALBACK_pfx}]), + ejabberd_router:route(To, From, Reply); + Reply -> + ejabberd_router:route(To, From, Reply) end. %%==================================================================== @@ -217,16 +240,16 @@ code_change(_OldVsn, State, _Extra) -> %%% Internal functions %%-------------------------------------------------------------------- -convert_to_old_structs(From, To, IQ) -> +convert_to_old_structs(Mod, Fun, From, To, IQ) -> + catch throw(for_stacktrace), % To have a stacktrace. + io:format("~nIQ HANDLER: ~s:~s expects old #iq:~n~p~n~p~n~n", + [Mod, Fun, IQ, erlang:get_stacktrace()]), if - is_record(IQ, iq) -> - catch throw(for_stacktrace), % To have a stacktrace. - io:format("~nIQ HANDLER: old #iq:~n~p~n~p~n~n", - [IQ, erlang:get_stacktrace()]), - {From, To, IQ}; - true -> - F = jlib:to_old_jid(From), - T = jlib:to_old_jid(To), - I_Rec = jlib:iq_query_info(IQ), - {F, T, I_Rec} + is_record(IQ, iq) -> + {From, To, IQ}; + true -> + F = jlib:to_old_jid(From), + T = jlib:to_old_jid(To), + I_Rec = jlib:iq_query_info(IQ), + {F, T, I_Rec} end. From 6e91399922a988218f13384e9146e5124e34c86d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 21 Jul 2008 15:29:52 +0000 Subject: [PATCH 046/582] Convert to exmpp. SVN Revision: 1463 --- ChangeLog | 2 + src/gen_iq_handler.erl | 1 + src/mod_roster.erl | 451 +++++++++++++++++++++-------------------- 3 files changed, 230 insertions(+), 224 deletions(-) diff --git a/ChangeLog b/ChangeLog index 20b91bbfc..73c49c0ab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,8 @@ the new format to a built-in list of modules known to support them. Other modules will still receive arguments in the old format. + * src/mod_roster.erl, src/gen_iq_handler.erl: Convert to exmpp. + 2008-07-17 Jean-Sébastien Pédron Merge revisions from 1444 to revision 1457 from trunk. diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index 11fba0929..09318e058 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -59,6 +59,7 @@ % XXX OLD FORMAT: modules not in the following list will receive % old format strudctures. -define(CONVERTED_MODULES, [ + mod_roster ]). %%==================================================================== diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 038de586a..4e7e5ecab 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -44,8 +44,9 @@ webadmin_page/3, webadmin_user/4]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("mod_roster.hrl"). -include("web/ejabberd_http.hrl"). -include("web/ejabberd_web_admin.hrl"). @@ -77,7 +78,8 @@ start(Host, Opts) -> ?MODULE, webadmin_page, 50), ejabberd_hooks:add(webadmin_user, Host, ?MODULE, webadmin_user, 50), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ROSTER, + % XXX OLD FORMAT: NS as string. + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, atom_to_list(?NS_ROSTER), ?MODULE, process_iq, IQDisc). stop(Host) -> @@ -101,21 +103,22 @@ stop(Host) -> ?MODULE, webadmin_page, 50), ejabberd_hooks:delete(webadmin_user, Host, ?MODULE, webadmin_user, 50), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ROSTER). + % XXX OLD FORMAT: NS as string. + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, + atom_to_list(?NS_ROSTER)). process_iq(From, To, IQ) -> - #iq{sub_el = SubEl} = IQ, - #jid{lserver = LServer} = From, + #jid{ldomain = LServer} = From, case lists:member(LServer, ?MYHOSTS) of true -> process_local_iq(From, To, IQ); _ -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]} + exmpp_iq:error(IQ, 'item-not-found') end. -process_local_iq(From, To, #iq{type = Type} = IQ) -> - case Type of +process_local_iq(From, To, IQ) -> + case exmpp_iq:get_type(IQ) of set -> process_iq_set(From, To, IQ); get -> @@ -124,19 +127,17 @@ process_local_iq(From, To, #iq{type = Type} = IQ) -> -process_iq_get(From, To, #iq{sub_el = SubEl} = IQ) -> - LUser = From#jid.luser, - LServer = From#jid.lserver, +process_iq_get(From, To, IQ) -> + LUser = From#jid.lnode, + LServer = From#jid.ldomain, US = {LUser, LServer}, - case catch ejabberd_hooks:run_fold(roster_get, To#jid.lserver, [], [US]) of + case catch ejabberd_hooks:run_fold(roster_get, To#jid.ldomain, [], [US]) of Items when is_list(Items) -> XItems = lists:map(fun item_to_xml/1, Items), - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_ROSTER}], - XItems}]}; + exmpp_iq:result(IQ, #xmlel{ns = ?NS_ROSTER, name = 'query', + children = XItems}); _ -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]} + exmpp_iq:error(IQ, 'internal-server-error') end. get_user_roster(Acc, US) -> @@ -153,139 +154,138 @@ get_user_roster(Acc, US) -> item_to_xml(Item) -> - Attrs1 = [{"jid", jlib:jid_to_string(Item#roster.jid)}], + {U, S, R} = Item#roster.jid, + Attrs1 = exmpp_xml:set_attribute_in_list([], + 'jid', exmpp_jid:jid_to_string(U, S, R)), Attrs2 = case Item#roster.name of "" -> Attrs1; Name -> - [{"name", Name} | Attrs1] - end, - Attrs3 = case Item#roster.subscription of - none -> - [{"subscription", "none"} | Attrs2]; - from -> - [{"subscription", "from"} | Attrs2]; - to -> - [{"subscription", "to"} | Attrs2]; - both -> - [{"subscription", "both"} | Attrs2]; - remove -> - [{"subscription", "remove"} | Attrs2] + exmpp_xml:set_attribute_in_list(Attrs1, 'name', Name) end, + Attrs3 = exmpp_xml:set_attribute_in_list(Attrs2, + 'subscription', Item#roster.subscription), Attrs4 = case ask_to_pending(Item#roster.ask) of out -> - [{"ask", "subscribe"} | Attrs3]; + exmpp_xml:set_attribute_in_list(Attrs3, + 'ask', "subscribe"); both -> - [{"ask", "subscribe"} | Attrs3]; + exmpp_xml:set_attribute_in_list(Attrs3, + 'ask', "subscribe"); _ -> Attrs3 end, SubEls1 = lists:map(fun(G) -> - {xmlelement, "group", [], [{xmlcdata, G}]} + exmpp_xml:set_cdata( + #xmlel{ns = ?NS_ROSTER, name = 'group'}, G) end, Item#roster.groups), SubEls = SubEls1 ++ Item#roster.xs, - {xmlelement, "item", Attrs4, SubEls}. + #xmlel{ns = ?NS_ROSTER, name = 'item', attrs = Attrs4, children = SubEls}. -process_iq_set(From, To, #iq{sub_el = SubEl} = IQ) -> - {xmlelement, _Name, _Attrs, Els} = SubEl, - lists:foreach(fun(El) -> process_item_set(From, To, El) end, Els), - IQ#iq{type = result, sub_el = []}. - -process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) -> - JID1 = jlib:string_to_jid(xml:get_attr_s("jid", Attrs)), - #jid{user = User, luser = LUser, lserver = LServer} = From, - case JID1 of - error -> - ok; +process_iq_set(From, To, IQ) -> + case exmpp_iq:get_request(IQ) of + #xmlel{children = Els} -> + lists:foreach(fun(El) -> process_item_set(From, To, El) end, Els); _ -> - JID = {JID1#jid.user, JID1#jid.server, JID1#jid.resource}, - LJID = jlib:jid_tolower(JID1), - F = fun() -> - Res = mnesia:read({roster, {LUser, LServer, LJID}}), - Item = case Res of - [] -> - #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, - jid = JID}; - [I] -> - I#roster{jid = JID, - name = "", - groups = [], - xs = []} - end, - Item1 = process_item_attrs(Item, Attrs), - Item2 = process_item_els(Item1, Els), - case Item2#roster.subscription of - remove -> - mnesia:delete({roster, {LUser, LServer, LJID}}); - _ -> - mnesia:write(Item2) - end, - %% If the item exist in shared roster, take the - %% subscription information from there: - Item3 = ejabberd_hooks:run_fold(roster_process_item, - LServer, Item2, [LServer]), - {Item, Item3} - end, - case mnesia:transaction(F) of - {atomic, {OldItem, Item}} -> - push_item(User, LServer, To, Item), - case Item#roster.subscription of + ok + end, + exmpp_iq:result(IQ). + +process_item_set(From, To, #xmlel{} = Item) -> + try + JID1 = exmpp_jid:string_to_jid(exmpp_xml:get_attribute(Item, 'jid')), + % XXX OLD FORMAT: old JID (with empty strings). + #jid{node = User, lnode = LUser, ldomain = LServer} = + jlib:to_old_jid(From), + JID = {JID1#jid.node, JID1#jid.domain, JID1#jid.resource}, + LJID = jlib:short_jid(JID1), + F = fun() -> + Res = mnesia:read({roster, {LUser, LServer, LJID}}), + Item = case Res of + [] -> + #roster{usj = {LUser, LServer, LJID}, + us = {LUser, LServer}, + jid = JID}; + [I] -> + I#roster{jid = JID, + name = "", + groups = [], + xs = []} + end, + Item1 = process_item_attrs(Item, Item#xmlel.attrs), + Item2 = process_item_els(Item1, Item#xmlel.children), + case Item2#roster.subscription of remove -> - IsTo = case OldItem#roster.subscription of - both -> true; - to -> true; - _ -> false - end, - IsFrom = case OldItem#roster.subscription of - both -> true; - from -> true; - _ -> false - end, - if IsTo -> - ejabberd_router:route( - jlib:jid_remove_resource(From), - jlib:make_jid(OldItem#roster.jid), - {xmlelement, "presence", - [{"type", "unsubscribe"}], - []}); - true -> ok - end, - if IsFrom -> - ejabberd_router:route( - jlib:jid_remove_resource(From), - jlib:make_jid(OldItem#roster.jid), - {xmlelement, "presence", - [{"type", "unsubscribed"}], - []}); - true -> ok - end, - ok; + mnesia:delete({roster, {LUser, LServer, LJID}}); _ -> - ok - end; - E -> - ?DEBUG("ROSTER: roster item set error: ~p~n", [E]), - ok - end + mnesia:write(Item2) + end, + %% If the item exist in shared roster, take the + %% subscription information from there: + Item3 = ejabberd_hooks:run_fold(roster_process_item, + LServer, Item2, [LServer]), + {Item, Item3} + end, + case mnesia:transaction(F) of + {atomic, {OldItem, Item}} -> + push_item(User, LServer, To, Item), + case Item#roster.subscription of + remove -> + IsTo = case OldItem#roster.subscription of + both -> true; + to -> true; + _ -> false + end, + IsFrom = case OldItem#roster.subscription of + both -> true; + from -> true; + _ -> false + end, + {U, S, R} = OldItem#roster.jid, + if IsTo -> + ejabberd_router:route( + exmpp_jid:jid_to_bare_jid(From), + exmpp_jid:make_jid(U, S, R), + exmpp_presence:unsubscribe()); + true -> ok + end, + if IsFrom -> + ejabberd_router:route( + exmpp_jid:jid_to_bare_jid(From), + exmpp_jid:make_jid(U, S, R), + exmpp_presence:unsubscribed()); + true -> ok + end, + ok; + _ -> + ok + end; + E -> + ?DEBUG("ROSTER: roster item set error: ~p~n", [E]), + ok + end + catch + _ -> + ok end; process_item_set(_From, _To, _) -> ok. -process_item_attrs(Item, [{Attr, Val} | Attrs]) -> +process_item_attrs(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> case Attr of - "jid" -> - case jlib:string_to_jid(Val) of - error -> - process_item_attrs(Item, Attrs); - JID1 -> - JID = {JID1#jid.user, JID1#jid.server, JID1#jid.resource}, - process_item_attrs(Item#roster{jid = JID}, Attrs) + 'jid' -> + try + JID1 = exmpp_jid:string_to_jid(Val), + JID = {JID1#jid.node, JID1#jid.domain, JID1#jid.resource}, + process_item_attrs(Item#roster{jid = JID}, Attrs) + catch + _ -> + process_item_attrs(Item, Attrs) end; - "name" -> + 'name' -> process_item_attrs(Item#roster{name = Val}, Attrs); - "subscription" -> + 'subscription' -> case Val of "remove" -> process_item_attrs(Item#roster{subscription = remove}, @@ -293,7 +293,7 @@ process_item_attrs(Item, [{Attr, Val} | Attrs]) -> _ -> process_item_attrs(Item, Attrs) end; - "ask" -> + 'ask' -> process_item_attrs(Item, Attrs); _ -> process_item_attrs(Item, Attrs) @@ -302,30 +302,30 @@ process_item_attrs(Item, []) -> Item. -process_item_els(Item, [{xmlelement, Name, Attrs, SEls} | Els]) -> +process_item_els(Item, [#xmlel{ns = NS, name = Name} = El | Els]) -> case Name of - "group" -> - Groups = [xml:get_cdata(SEls) | Item#roster.groups], + 'group' -> + Groups = [exmpp_xml:get_cdata(El) | Item#roster.groups], process_item_els(Item#roster{groups = Groups}, Els); _ -> - case xml:get_attr_s("xmlns", Attrs) of - "" -> + if + NS == ?NS_JABBER_CLIENT; NS == ?NS_JABBER_SERVER -> process_item_els(Item, Els); - _ -> - XEls = [{xmlelement, Name, Attrs, SEls} | Item#roster.xs], + true -> + XEls = [El | Item#roster.xs], process_item_els(Item#roster{xs = XEls}, Els) end end; -process_item_els(Item, [{xmlcdata, _} | Els]) -> +process_item_els(Item, [_ | Els]) -> process_item_els(Item, Els); process_item_els(Item, []) -> Item. push_item(User, Server, From, Item) -> - ejabberd_sm:route(jlib:make_jid("", "", ""), - jlib:make_jid(User, Server, ""), - {xmlelement, "broadcast", [], + ejabberd_sm:route(exmpp_jid:make_bare_jid(""), + exmpp_jid:make_bare_jid(User, Server), + #xmlel{name = 'broadcast', children = [{item, Item#roster.jid, Item#roster.subscription}]}), @@ -335,19 +335,17 @@ push_item(User, Server, From, Item) -> % TODO: don't push to those who didn't load roster push_item(User, Server, Resource, From, Item) -> - ResIQ = #iq{type = set, xmlns = ?NS_ROSTER, - id = "push", - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_ROSTER}], - [item_to_xml(Item)]}]}, + Request = #xmlel{ns = ?NS_ROSTER, name = 'query', + children = item_to_xml(Item)}, + ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request, "push"), ejabberd_router:route( From, - jlib:make_jid(User, Server, Resource), - jlib:iq_to_xml(ResIQ)). + exmpp_jid:make_jid(User, Server, Resource), + ResIQ). get_subscription_lists(_, User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, case mnesia:dirty_index_read(roster, US, #roster.us) of Items when is_list(Items) -> @@ -384,15 +382,15 @@ out_subscription(User, Server, JID, Type) -> process_subscription(out, User, Server, JID, Type, []). process_subscription(Direction, User, Server, JID1, Type, Reason) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, - LJID = jlib:jid_tolower(JID1), + LJID = jlib:short_jid(JID1), F = fun() -> Item = case mnesia:read({roster, {LUser, LServer, LJID}}) of [] -> - JID = {JID1#jid.user, - JID1#jid.server, + JID = {JID1#jid.node, + JID1#jid.domain, JID1#jid.resource}, #roster{usj = {LUser, LServer, LJID}, us = US, @@ -444,13 +442,9 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) -> none -> ok; _ -> - T = case AutoReply of - subscribed -> "subscribed"; - unsubscribed -> "unsubscribed" - end, ejabberd_router:route( - jlib:make_jid(User, Server, ""), JID1, - {xmlelement, "presence", [{"type", T}], []}) + exmpp_jid:make_bare_jid(User, Server), JID1, + exmpp_presence:AutoReply()) end, case Push of {push, Item} -> @@ -460,7 +454,7 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) -> ok; true -> push_item(User, Server, - jlib:make_jid(User, Server, ""), Item) + exmpp_jid:make_bare_jid(User, Server), Item) end, true; none -> @@ -567,8 +561,8 @@ in_auto_reply(_, _, _) -> none. remove_user(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringpre:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, F = fun() -> lists:foreach(fun(R) -> @@ -582,8 +576,8 @@ remove_user(User, Server) -> set_items(User, Server, SubEl) -> {xmlelement, _Name, _Attrs, Els} = SubEl, - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), F = fun() -> lists:foreach(fun(El) -> process_item_set_t(LUser, LServer, El) @@ -591,42 +585,43 @@ set_items(User, Server, SubEl) -> end, mnesia:transaction(F). -process_item_set_t(LUser, LServer, {xmlelement, _Name, Attrs, Els}) -> - JID1 = jlib:string_to_jid(xml:get_attr_s("jid", Attrs)), - case JID1 of - error -> - ok; +process_item_set_t(LUser, LServer, #xmlel{} = El) -> + try + JID1 = exmpp_jid:string_to_jid(exmpp_xml:get_attribute(El, 'jid')), + JID = {JID1#jid.node, JID1#jid.domain, JID1#jid.resource}, + LJID = {JID1#jid.lnode, JID1#jid.ldomain, JID1#jid.lresource}, + Item = #roster{usj = {LUser, LServer, LJID}, + us = {LUser, LServer}, + jid = JID}, + Item1 = process_item_attrs_ws(Item, El#xmlel.attrs), + Item2 = process_item_els(Item1, El#xmlel.children), + case Item2#roster.subscription of + remove -> + mnesia:delete({roster, {LUser, LServer, LJID}}); + _ -> + mnesia:write(Item2) + end + catch _ -> - JID = {JID1#jid.user, JID1#jid.server, JID1#jid.resource}, - LJID = {JID1#jid.luser, JID1#jid.lserver, JID1#jid.lresource}, - Item = #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, - jid = JID}, - Item1 = process_item_attrs_ws(Item, Attrs), - Item2 = process_item_els(Item1, Els), - case Item2#roster.subscription of - remove -> - mnesia:delete({roster, {LUser, LServer, LJID}}); - _ -> - mnesia:write(Item2) - end + ok end; process_item_set_t(_LUser, _LServer, _) -> ok. -process_item_attrs_ws(Item, [{Attr, Val} | Attrs]) -> +process_item_attrs_ws(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> case Attr of - "jid" -> - case jlib:string_to_jid(Val) of - error -> - process_item_attrs_ws(Item, Attrs); - JID1 -> - JID = {JID1#jid.user, JID1#jid.server, JID1#jid.resource}, - process_item_attrs_ws(Item#roster{jid = JID}, Attrs) + 'jid' -> + try + JID1 = exmpp_jid:string_to_jid(Val), + JID = {JID1#jid.node, JID1#jid.domain, JID1#jid.resource}, + process_item_attrs_ws(Item#roster{jid = JID}, Attrs) + catch + _ -> + process_item_attrs_ws(Item, Attrs) end; - "name" -> + 'name' -> process_item_attrs_ws(Item#roster{name = Val}, Attrs); - "subscription" -> + 'subscription' -> case Val of "remove" -> process_item_attrs_ws(Item#roster{subscription = remove}, @@ -646,7 +641,7 @@ process_item_attrs_ws(Item, [{Attr, Val} | Attrs]) -> _ -> process_item_attrs_ws(Item, Attrs) end; - "ask" -> + 'ask' -> process_item_attrs_ws(Item, Attrs); _ -> process_item_attrs_ws(Item, Attrs) @@ -655,8 +650,8 @@ process_item_attrs_ws(Item, []) -> Item. get_in_pending_subscriptions(Ls, User, Server) -> - JID = jlib:make_jid(User, Server, ""), - US = {JID#jid.luser, JID#jid.lserver}, + JID = exmpp_jid:make_bare_jid(User, Server), + US = {JID#jid.lnode, JID#jid.ldomain}, case mnesia:dirty_index_read(roster, US, #roster.us) of Result when list(Result) -> Ls ++ lists:map( @@ -667,12 +662,14 @@ get_in_pending_subscriptions(Ls, User, Server) -> true -> "" end, - {xmlelement, "presence", - [{"from", jlib:jid_to_string(R#roster.jid)}, - {"to", jlib:jid_to_string(JID)}, - {"type", "subscribe"}], - [{xmlelement, "status", [], - [{xmlcdata, Status}]}]} + {U, S, R} = R#roster.jid, + Attrs1 = exmpp_stanza:set_sender_in_list([], + exmpp_jid:jid_to_string(U, S, R)), + Attrs2 = exmpp_stanza:set_recipient_in_list(Attrs1, + exmpp_jid:jid_to_string(JID)), + Pres1 = exmpp_presence:subscribe(), + Pres2 = Pres1#xmlel{attrs = Attrs2}, + exmpp_presence:set_status(Pres2, Status) end, lists:filter( fun(R) -> @@ -691,14 +688,14 @@ get_in_pending_subscriptions(Ls, User, Server) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% get_jid_info(_, User, Server, JID) -> - LUser = jlib:nodeprep(User), - LJID = jlib:jid_tolower(JID), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LJID = jlib:short_jid(JID), + LServer = exmpp_stringprep:nameprep(Server), case catch mnesia:dirty_read(roster, {LUser, LServer, LJID}) of [#roster{subscription = Subscription, groups = Groups}] -> {Subscription, Groups}; _ -> - LRJID = jlib:jid_tolower(jlib:jid_remove_resource(JID)), + LRJID = jlib:short_jid(exmpp_jid:jid_to_bare_jid(JID)), if LRJID == LJID -> {none, []}; @@ -787,7 +784,7 @@ webadmin_page(_, Host, webadmin_page(Acc, _, _) -> Acc. user_roster(User, Server, Query, Lang) -> - US = {jlib:nodeprep(User), jlib:nameprep(Server)}, + US = {exmpp_stringprep:nodeprep(User), exmpp_stringprep:nameprep(Server)}, Items1 = mnesia:dirty_index_read(roster, US, #roster.us), Res = user_roster_parse_query(User, Server, Items1, Query), Items = mnesia:dirty_index_read(roster, US, #roster.us), @@ -815,9 +812,10 @@ user_roster(User, Server, Query, Lang) -> [?C(Group), ?BR] end, R#roster.groups), Pending = ask_to_pending(R#roster.ask), + {U, S, R} = R#roster.jid, ?XE("tr", [?XAC("td", [{"class", "valign"}], - jlib:jid_to_string(R#roster.jid)), + catch exmpp_jid:jid_to_string(U, S, R)), ?XAC("td", [{"class", "valign"}], R#roster.name), ?XAC("td", [{"class", "valign"}], @@ -862,11 +860,12 @@ user_roster_parse_query(User, Server, Items, Query) -> {value, {_, undefined}} -> error; {value, {_, SJID}} -> - case jlib:string_to_jid(SJID) of - JID when is_record(JID, jid) -> - user_roster_subscribe_jid(User, Server, JID), - ok; - error -> + try + JID = exmpp_jid:string_to_jid(SJID), + user_roster_subscribe_jid(User, Server, JID), + ok + catch + _ -> error end; false -> @@ -887,9 +886,9 @@ user_roster_parse_query(User, Server, Items, Query) -> user_roster_subscribe_jid(User, Server, JID) -> out_subscription(User, Server, JID, subscribe), - UJID = jlib:make_jid(User, Server, ""), + UJID = exmpp_jid:make_bare_jid(User, Server), ejabberd_router:route( - UJID, JID, {xmlelement, "presence", [{"type", "subscribe"}], []}). + UJID, JID, exmpp_presence:subscribe()). user_roster_item_parse_query(User, Server, Items, Query) -> lists:foreach( @@ -898,28 +897,32 @@ user_roster_item_parse_query(User, Server, Items, Query) -> case lists:keysearch( "validate" ++ ejabberd_web_admin:term_to_id(JID), 1, Query) of {value, _} -> - JID1 = jlib:make_jid(JID), + {U, S, R} = JID, + JID1 = exmpp_jid:make_jid(U, S, R), out_subscription( User, Server, JID1, subscribed), - UJID = jlib:make_jid(User, Server, ""), + UJID = exmpp_jid:make_bare_jid(User, Server), ejabberd_router:route( - UJID, JID1, {xmlelement, "presence", - [{"type", "subscribed"}], []}), + UJID, JID1, exmpp_presence:subscribed()), throw(submitted); false -> case lists:keysearch( "remove" ++ ejabberd_web_admin:term_to_id(JID), 1, Query) of {value, _} -> - UJID = jlib:make_jid(User, Server, ""), + UJID = exmpp_jid:make_bare_jid(User, Server), + Attrs1 = exmpp_xml:set_attribute_in_list([], + 'jid', exmpp_jid:jid_to_string(JID)), + Attrs2 = exmpp_xml:set_attribute_in_list(Attrs1, + 'subscription', "remove"), + Item = #xmlel{ns = ?NS_ROSTER, name = 'item', + attrs = Attrs2}, + Request = #xmlel{ + ns = ?NS_ROSTER, + name = 'query', + children = [Item]}, process_iq( UJID, UJID, - #iq{type = set, - sub_el = {xmlelement, "query", - [{"xmlns", ?NS_ROSTER}], - [{xmlelement, "item", - [{"jid", jlib:jid_to_string(JID)}, - {"subscription", "remove"}], - []}]}}), + exmpp_iq:set(?NS_JABBER_CLIENT, Request)), throw(submitted); false -> ok @@ -930,7 +933,7 @@ user_roster_item_parse_query(User, Server, Items, Query) -> nothing. us_to_list({User, Server}) -> - jlib:jid_to_string({User, Server, ""}). + exmpp_jid:bare_jid_to_string(User, Server). webadmin_user(Acc, _User, _Server, Lang) -> Acc ++ [?XE("h3", [?ACT("roster/", "Roster")])]. From b33ac4722844c335072e0b27bd7c90c48ad3964a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 21 Jul 2008 15:30:32 +0000 Subject: [PATCH 047/582] Convert to exmpp. SVN Revision: 1464 --- ChangeLog | 3 +- src/gen_iq_handler.erl | 3 +- src/mod_vcard.erl | 610 +++++++++++++++++++++-------------------- 3 files changed, 311 insertions(+), 305 deletions(-) diff --git a/ChangeLog b/ChangeLog index 73c49c0ab..ad48991b0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,7 +4,8 @@ the new format to a built-in list of modules known to support them. Other modules will still receive arguments in the old format. - * src/mod_roster.erl, src/gen_iq_handler.erl: Convert to exmpp. + * src/mod_roster.erl, src/mod_vcard.erl, src/gen_iq_handler.erl: + Convert to exmpp. 2008-07-17 Jean-Sébastien Pédron diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index 09318e058..0a949566f 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -59,7 +59,8 @@ % XXX OLD FORMAT: modules not in the following list will receive % old format strudctures. -define(CONVERTED_MODULES, [ - mod_roster + mod_roster, + mod_vcard ]). %%==================================================================== diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index 2a6474eba..fd78c3fb8 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -36,8 +36,9 @@ reindex_vcards/0, remove_user/2]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -define(JUD_MATCHES, 30). @@ -83,9 +84,11 @@ start(Host, Opts) -> ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD, + % XXX OLD FORMAT: NS as string. + gen_iq_handler:add_iq_handler(ejabberd_local, Host, atom_to_list(?NS_VCARD), ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD, + % XXX OLD FORMAT: NS as string. + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, atom_to_list(?NS_VCARD), ?MODULE, process_sm_iq, IQDisc), ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50), MyHost = gen_mod:get_opt_host(Host, Opts, "vjud.@HOST@"), @@ -123,8 +126,12 @@ loop(Host, ServerHost) -> stop(Host) -> ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD), + % XXX OLD FORMAT: NS as string. + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, + atom_to_list(?NS_VCARD)), + % XXX OLD FORMAT: NS as string. + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, + atom_to_list(?NS_VCARD)), ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), Proc ! stop, @@ -138,51 +145,53 @@ get_sm_features(Acc, _From, _To, Node, _Lang) -> [] -> case Acc of {result, Features} -> - {result, [?NS_VCARD | Features]}; + % XXX OLD FORMAT: NS as string. + {result, [atom_to_list(?NS_VCARD) | Features]}; empty -> - {result, [?NS_VCARD]} + % XXX OLD FORMAT: NS as string. + {result, [atom_to_list(?NS_VCARD)]} end; _ -> Acc end. -process_local_iq(_From, _To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> - case Type of +process_local_iq(_From, _To, IQ) -> + case exmpp_iq:get_type(IQ) of set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + exmpp_iq:error(IQ, 'not-allowed'); get -> - IQ#iq{type = result, - sub_el = [{xmlelement, "vCard", - [{"xmlns", ?NS_VCARD}], - [{xmlelement, "FN", [], - [{xmlcdata, "ejabberd"}]}, - {xmlelement, "URL", [], - [{xmlcdata, ?EJABBERD_URI}]}, - {xmlelement, "DESC", [], - [{xmlcdata, - translate:translate( - Lang, - "Erlang Jabber Server") ++ - "\nCopyright (c) 2002-2008 ProcessOne"}]}, - {xmlelement, "BDAY", [], - [{xmlcdata, "2002-11-16"}]} - ]}]} + Lang = case exmpp_stanza:get_lang(IQ) of + undefined -> ""; + L -> L + end, + Result = #xmlel{ns = ?NS_VCARD, name = 'vCard', children = [ + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'FN'}, + "ejabberd"), + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'URL'}, + ?EJABBERD_URI), + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'DESC'}, + translate:translate(Lang, "Erlang Jabber Server") ++ + "\nCopyright (c) 2002-2008 ProcessOne"), + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'BDAY'}, + "2002-11-16") + ]}, + exmpp_iq:result(IQ, Result) end. -process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> - case Type of +process_sm_iq(From, To, IQ) -> + case exmpp_iq:get_type(IQ) of set -> - #jid{user = User, lserver = LServer} = From, + #jid{node = User, ldomain = LServer} = From, case lists:member(LServer, ?MYHOSTS) of true -> - set_vcard(User, LServer, SubEl), - IQ#iq{type = result, sub_el = []}; + set_vcard(User, LServer, exmpp_iq:get_request(IQ)), + exmpp_iq:result(IQ); false -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]} + exmpp_iq:error(IQ, 'not-allowed') end; get -> - #jid{luser = LUser, lserver = LServer} = To, + #jid{lnode = LUser, ldomain = LServer} = To, US = {LUser, LServer}, F = fun() -> mnesia:read({vcard, US}) @@ -190,27 +199,46 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> Els = case mnesia:transaction(F) of {atomic, Rs} -> lists:map(fun(R) -> - R#vcard.vcard + case R#vcard.vcard of + #xmlel{} = E -> + E; + #xmlelement{} = E -> + % XXX OLD FORMAT: Base contains old elements. + io:format("VCARD: Old element in base: ~p~n", [E]), + exmpp_xml:xmlelement_to_xmlel(E, [?NS_VCARD], []) + end end, Rs); {aborted, _Reason} -> [] end, - IQ#iq{type = result, sub_el = Els} + exmpp_iq:result(IQ, Els) end. set_vcard(User, LServer, VCARD) -> - FN = xml:get_path_s(VCARD, [{elem, "FN"}, cdata]), - Family = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "FAMILY"}, cdata]), - Given = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "GIVEN"}, cdata]), - Middle = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "MIDDLE"}, cdata]), - Nickname = xml:get_path_s(VCARD, [{elem, "NICKNAME"}, cdata]), - BDay = xml:get_path_s(VCARD, [{elem, "BDAY"}, cdata]), - CTRY = xml:get_path_s(VCARD, [{elem, "ADR"}, {elem, "CTRY"}, cdata]), - Locality = xml:get_path_s(VCARD, [{elem, "ADR"}, {elem, "LOCALITY"},cdata]), - EMail1 = xml:get_path_s(VCARD, [{elem, "EMAIL"}, {elem, "USERID"},cdata]), - EMail2 = xml:get_path_s(VCARD, [{elem, "EMAIL"}, cdata]), - OrgName = xml:get_path_s(VCARD, [{elem, "ORG"}, {elem, "ORGNAME"}, cdata]), - OrgUnit = xml:get_path_s(VCARD, [{elem, "ORG"}, {elem, "ORGUNIT"}, cdata]), + FN = exmpp_xml:get_path(VCARD, + [{element, 'FN'}, cdata_as_list]), + Family = exmpp_xml:get_path(VCARD, + [{element, 'N'}, {element, 'FAMILY'}, cdata_as_list]), + Given = exmpp_xml:get_path(VCARD, + [{element, 'N'}, {element, 'GIVEN'}, cdata_as_list]), + Middle = exmpp_xml:get_path(VCARD, + [{element, 'N'}, {element, 'MIDDLE'}, cdata_as_list]), + Nickname = exmpp_xml:get_path(VCARD, + [{element, 'NICKNAME'}, cdata_as_list]), + BDay = exmpp_xml:get_path(VCARD, + [{element, 'BDAY'}, cdata_as_list]), + CTRY = exmpp_xml:get_path(VCARD, + [{element, 'ADR'}, {element, 'CTRY'}, cdata_as_list]), + Locality = exmpp_xml:get_path(VCARD, + [{element, 'ADR'}, {element, 'LOCALITY'}, cdata_as_list]), + EMail1 = exmpp_xml:get_path(VCARD, + [{element, 'EMAIL'}, {element, 'USERID'}, cdata_as_list]), + EMail2 = exmpp_xml:get_path(VCARD, + [{element, 'EMAIL'}, cdata_as_list]), + OrgName = exmpp_xml:get_path(VCARD, + [{element, 'ORG'}, {element, 'ORGNAME'}, cdata_as_list]), + OrgUnit = exmpp_xml:get_path(VCARD, + [{element, 'ORG'}, {element, 'ORGUNIT'}, cdata_as_list]), EMail = case EMail1 of "" -> EMail2; @@ -218,76 +246,70 @@ set_vcard(User, LServer, VCARD) -> EMail1 end, - LUser = jlib:nodeprep(User), - LFN = stringprep:tolower(FN), - LFamily = stringprep:tolower(Family), - LGiven = stringprep:tolower(Given), - LMiddle = stringprep:tolower(Middle), - LNickname = stringprep:tolower(Nickname), - LBDay = stringprep:tolower(BDay), - LCTRY = stringprep:tolower(CTRY), - LLocality = stringprep:tolower(Locality), - LEMail = stringprep:tolower(EMail), - LOrgName = stringprep:tolower(OrgName), - LOrgUnit = stringprep:tolower(OrgUnit), + try + LUser = exmpp_stringprep:nodeprep(User), + LFN = exmpp_stringprep:to_lower(FN), + LFamily = exmpp_stringprep:to_lower(Family), + LGiven = exmpp_stringprep:to_lower(Given), + LMiddle = exmpp_stringprep:to_lower(Middle), + LNickname = exmpp_stringprep:to_lower(Nickname), + LBDay = exmpp_stringprep:to_lower(BDay), + LCTRY = exmpp_stringprep:to_lower(CTRY), + LLocality = exmpp_stringprep:to_lower(Locality), + LEMail = exmpp_stringprep:to_lower(EMail), + LOrgName = exmpp_stringprep:to_lower(OrgName), + LOrgUnit = exmpp_stringprep:to_lower(OrgUnit), - US = {LUser, LServer}, + US = {LUser, LServer}, - if - (LUser == error) or - (LFN == error) or - (LFamily == error) or - (LGiven == error) or - (LMiddle == error) or - (LNickname == error) or - (LBDay == error) or - (LCTRY == error) or - (LLocality == error) or - (LEMail == error) or - (LOrgName == error) or - (LOrgUnit == error) -> - {error, badarg}; - true -> - F = fun() -> - mnesia:write(#vcard{us = US, vcard = VCARD}), - mnesia:write( - #vcard_search{us = US, - user = {User, LServer}, - luser = LUser, - fn = FN, lfn = LFN, - family = Family, lfamily = LFamily, - given = Given, lgiven = LGiven, - middle = Middle, lmiddle = LMiddle, - nickname = Nickname, lnickname = LNickname, - bday = BDay, lbday = LBDay, - ctry = CTRY, lctry = LCTRY, - locality = Locality, llocality = LLocality, - email = EMail, lemail = LEMail, - orgname = OrgName, lorgname = LOrgName, - orgunit = OrgUnit, lorgunit = LOrgUnit - }) - end, - mnesia:transaction(F) + F = fun() -> + % XXX OLD FORMAT: We keep persistent data in the old format + % for now. + VCARDOld = exmpp_xml:xmlel_to_xmlelement(VCARD, [?NS_VCARD], []), + mnesia:write(#vcard{us = US, vcard = VCARDOld}), + mnesia:write( + #vcard_search{us = US, + user = {User, LServer}, + luser = LUser, + fn = FN, lfn = LFN, + family = Family, lfamily = LFamily, + given = Given, lgiven = LGiven, + middle = Middle, lmiddle = LMiddle, + nickname = Nickname, lnickname = LNickname, + bday = BDay, lbday = LBDay, + ctry = CTRY, lctry = LCTRY, + locality = Locality, llocality = LLocality, + email = EMail, lemail = LEMail, + orgname = OrgName, lorgname = LOrgName, + orgunit = OrgUnit, lorgunit = LOrgUnit + }) + end, + mnesia:transaction(F) + catch + _ -> + {error, badarg} end. -define(TLFIELD(Type, Label, Var), - {xmlelement, "field", [{"type", Type}, - {"label", translate:translate(Lang, Label)}, - {"var", Var}], []}). + #xmlel{ns = ?NS_VCARD, name = 'field', attrs = [ + #xmlattr{name = 'type', value = Type}, + #xmlattr{name = 'label', value = translate:translate(Lang, Label)}, + #xmlattr{name = 'var', value = Var}]}). -define(FORM(JID), - [{xmlelement, "instructions", [], - [{xmlcdata, translate:translate(Lang, "You need an x:data capable client to search")}]}, - {xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}], - [{xmlelement, "title", [], - [{xmlcdata, translate:translate(Lang, "Search users in ") ++ - jlib:jid_to_string(JID)}]}, - {xmlelement, "instructions", [], - [{xmlcdata, translate:translate(Lang, "Fill in the form to search " - "for any matching Jabber User " - "(Add * to the end of field to " - "match substring)")}]}, + [#xmlel{ns = ?NS_SEARCH, name = 'instructions', children = + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "You need an x:data capable client to search"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = + [#xmlattr{name = 'type', value = "form"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ jlib:jid_to_string(JID))}]}, + #xmlel{ns = ?NS_SEARCH, name = 'instructions', children = + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, + "Fill in the form to search " + "for any matching Jabber User " + "(Add * to the end of field to " + "match substring)"))}]}, ?TLFIELD("text-single", "User", "user"), ?TLFIELD("text-single", "Full Name", "fn"), ?TLFIELD("text-single", "Name", "first"), @@ -306,157 +328,139 @@ set_vcard(User, LServer, VCARD) -> do_route(ServerHost, From, To, Packet) -> - #jid{user = User, resource = Resource} = To, + #jid{node = User, resource = Resource} = To, if - (User /= "") or (Resource /= "") -> - Err = jlib:make_error_reply(Packet, ?ERR_SERVICE_UNAVAILABLE), + (User /= undefined) or (Resource /= undefined) -> + Err = exmpp_stanza:reply_with_error(Packet, 'service-unavailable'), ejabberd_router ! {route, To, From, Err}; true -> - IQ = jlib:iq_query_info(Packet), - case IQ of - #iq{type = Type, xmlns = ?NS_SEARCH, lang = Lang, sub_el = SubEl} -> - case Type of - set -> - XDataEl = find_xdata_el(SubEl), - case XDataEl of - false -> - Err = jlib:make_error_reply( - Packet, ?ERR_BAD_REQUEST), - ejabberd_router:route(To, From, Err); - _ -> - XData = jlib:parse_xdata_submit(XDataEl), - case XData of - invalid -> - Err = jlib:make_error_reply( - Packet, - ?ERR_BAD_REQUEST), - ejabberd_router:route(To, From, - Err); - _ -> - ResIQ = - IQ#iq{ - type = result, - sub_el = - [{xmlelement, - "query", - [{"xmlns", ?NS_SEARCH}], - [{xmlelement, "x", - [{"xmlns", ?NS_XDATA}, - {"type", "result"}], - search_result(Lang, To, ServerHost, XData) - }]}]}, - ejabberd_router:route( - To, From, jlib:iq_to_xml(ResIQ)) - end - end; - get -> - ResIQ = IQ#iq{type = result, - sub_el = [{xmlelement, - "query", - [{"xmlns", ?NS_SEARCH}], - ?FORM(To) - }]}, - ejabberd_router:route(To, - From, - jlib:iq_to_xml(ResIQ)) - end; - #iq{type = Type, xmlns = ?NS_DISCO_INFO, lang = Lang} -> - case Type of - set -> - Err = jlib:make_error_reply( - Packet, ?ERR_NOT_ALLOWED), - ejabberd_router:route(To, From, Err); - get -> - ResIQ = - IQ#iq{type = result, - sub_el = [{xmlelement, - "query", - [{"xmlns", ?NS_DISCO_INFO}], - [{xmlelement, "identity", - [{"category", "directory"}, - {"type", "user"}, - {"name", - translate:translate(Lang, "vCard User Search")}], - []}, - {xmlelement, "feature", - [{"var", ?NS_SEARCH}], []}, - {xmlelement, "feature", - [{"var", ?NS_VCARD}], []} - ] - }]}, - ejabberd_router:route(To, - From, - jlib:iq_to_xml(ResIQ)) - end; - #iq{type = Type, xmlns = ?NS_DISCO_ITEMS} -> - case Type of - set -> - Err = jlib:make_error_reply( - Packet, ?ERR_NOT_ALLOWED), - ejabberd_router:route(To, From, Err); - get -> - ResIQ = - IQ#iq{type = result, - sub_el = [{xmlelement, - "query", - [{"xmlns", ?NS_DISCO_ITEMS}], - []}]}, - ejabberd_router:route(To, - From, - jlib:iq_to_xml(ResIQ)) - end; - #iq{type = get, xmlns = ?NS_VCARD, lang = Lang} -> - ResIQ = - IQ#iq{type = result, - sub_el = [{xmlelement, - "vCard", - [{"xmlns", ?NS_VCARD}], - iq_get_vcard(Lang)}]}, - ejabberd_router:route(To, - From, - jlib:iq_to_xml(ResIQ)); + try + Request = exmpp_iq:get_request(Packet), + Type = exmpp_iq:get_type(Packet), + Lang = exmpp_stanza:get_lang(Packet), + case {Type, Request#xmlel.ns} of + {set, ?NS_SEARCH} -> + XDataEl = find_xdata_el(Request), + case XDataEl of + false -> + Err = exmpp_iq:error(Packet, 'bad-request'), + ejabberd_router:route(To, From, Err); + _ -> + XData = jlib:parse_xdata_submit(XDataEl), + case XData of + invalid -> + Err = exmpp_iq:error(Packet, + 'bad-request'), + ejabberd_router:route(To, From, + Err); + _ -> + Result = #xmlel{ + ns = ?NS_SEARCH, + name = 'query', + children = [ + #xmlel{ + ns = ?NS_DATA_FORMS, + name = 'x', + attrs = [#xmlattr{name = 'type', + value = "result"}], + children = search_result(Lang, + To, ServerHost, XData)}]}, + ResIQ = exmpp_iq:result(Packet, + Result), + ejabberd_router:route( + To, From, ResIQ) + end + end; + {get, ?NS_SEARCH} -> + Result = #xmlel{ns = ?NS_SEARCH, name = 'query', + children = ?FORM(To)}, + ResIQ = exmpp_iq:result(Packet, Result), + ejabberd_router:route(To, + From, + ResIQ); + {set, ?NS_DISCO_INFO} -> + Err = exmpp_iq:error(Packet, 'not-allowed'), + ejabberd_router:route(To, From, Err); + {get, ?NS_DISCO_INFO} -> + Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', + children = [ + #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', + attrs = [ + #xmlattr{name = 'category', + value = "directory"}, + #xmlattr{name = 'type', + value = "user"}, + #xmlattr{name = 'name', + value = translate:translate(Lang, + "vCard User Search")}]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', + attrs = [ + #xmlattr{name = 'var', + value = atom_to_list(?NS_SEARCH)}]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', + attrs = [ + #xmlattr{name = 'var', + value = atom_to_list(?NS_VCARD)}]} + ]}, + ResIQ = exmpp_iq:result(Packet, Result), + ejabberd_router:route(To, + From, + ResIQ); + {set, ?NS_DISCO_ITEMS} -> + Err = exmpp_iq:error(Packet, 'not-allowed'), + ejabberd_router:route(To, From, Err); + {get, ?NS_DISCO_ITEMS} -> + Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query'}, + ResIQ = exmpp_iq:result(Packet, Result), + ejabberd_router:route(To, + From, + ResIQ); + {get, ?NS_VCARD} -> + Result = #xmlel{ns = ?NS_VCARD, name = 'vCard', + children = iq_get_vcard(Lang)}, + ResIQ = exmpp_iq:result(Packet, Result), + ejabberd_router:route(To, + From, + ResIQ); + _ -> + Err = exmpp_iq:error(Packet, 'service-unavailable'), + ejabberd_router:route(To, From, Err) + end + catch _ -> - Err = jlib:make_error_reply(Packet, - ?ERR_SERVICE_UNAVAILABLE), - ejabberd_router:route(To, From, Err) + Err1 = exmpp_iq:error(Packet, 'service-unavailable'), + ejabberd_router:route(To, From, Err1) end end. iq_get_vcard(Lang) -> - [{xmlelement, "FN", [], - [{xmlcdata, "ejabberd/mod_vcard"}]}, - {xmlelement, "URL", [], - [{xmlcdata, ?EJABBERD_URI}]}, - {xmlelement, "DESC", [], - [{xmlcdata, translate:translate( - Lang, - "ejabberd vCard module") ++ - "\nCopyright (c) 2003-2008 ProcessOne"}]}]. + [ + #xmlel{ns = ?NS_SEARCH, name = 'FN', children = [ + #xmlcdata{cdata = <<"ejabberd/mod_vcard">>}]}, + #xmlel{ns = ?NS_SEARCH, name = 'URL', children = [ + #xmlcdata{cdata = list_to_binary(?EJABBERD_URI)}]}, + #xmlel{ns = ?NS_SEARCH, name ='DESC', children = [ + #xmlcdata{cdata = list_to_binary( + translate:translate(Lang, "ejabberd vCard module") ++ + "\nCopyright (c) 2003-2008 ProcessOne")}]} + ]. -find_xdata_el({xmlelement, _Name, _Attrs, SubEls}) -> +find_xdata_el(#xmlel{children = SubEls}) -> find_xdata_el1(SubEls). find_xdata_el1([]) -> false; -find_xdata_el1([{xmlelement, Name, Attrs, SubEls} | Els]) -> - case xml:get_attr_s("xmlns", Attrs) of - ?NS_XDATA -> - {xmlelement, Name, Attrs, SubEls}; - _ -> - find_xdata_el1(Els) - end; +find_xdata_el1([#xmlel{ns = ?NS_DATA_FORMS} = El | _Els]) -> + El; find_xdata_el1([_ | Els]) -> find_xdata_el1(Els). --define(LFIELD(Label, Var), - {xmlelement, "field", [{"label", translate:translate(Lang, Label)}, - {"var", Var}], []}). - search_result(Lang, JID, ServerHost, Data) -> - [{xmlelement, "title", [], - [{xmlcdata, translate:translate(Lang, "Search Results for ") ++ - jlib:jid_to_string(JID)}]}, - {xmlelement, "reported", [], + [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary( + translate:translate(Lang, "Search Results for ") ++ + exmpp_jid:jid_to_string(JID))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'reported', children = [?TLFIELD("text-single", "Jabber ID", "jid"), ?TLFIELD("text-single", "Full Name", "fn"), ?TLFIELD("text-single", "Name", "first"), @@ -472,13 +476,14 @@ search_result(Lang, JID, ServerHost, Data) -> ]}] ++ lists:map(fun record_to_item/1, search(ServerHost, Data)). -define(FIELD(Var, Val), - {xmlelement, "field", [{"var", Var}], - [{xmlelement, "value", [], - [{xmlcdata, Val}]}]}). + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'var', value = Var}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = + [#xmlcdata{cdata = list_to_binary(Val)}]}]}). record_to_item(R) -> {User, Server} = R#vcard_search.user, - {xmlelement, "item", [], + #xmlel{ns = ?NS_DATA_FORMS, name = 'item', children = [ ?FIELD("jid", User ++ "@" ++ Server), ?FIELD("fn", R#vcard_search.fn), @@ -599,61 +604,60 @@ set_vcard_t(R, _) -> User = US, VCARD = R#vcard.vcard, - FN = xml:get_path_s(VCARD, [{elem, "FN"}, cdata]), - Family = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "FAMILY"}, cdata]), - Given = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "GIVEN"}, cdata]), - Middle = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "MIDDLE"}, cdata]), - Nickname = xml:get_path_s(VCARD, [{elem, "NICKNAME"}, cdata]), - BDay = xml:get_path_s(VCARD, [{elem, "BDAY"}, cdata]), - CTRY = xml:get_path_s(VCARD, [{elem, "ADR"}, {elem, "CTRY"}, cdata]), - Locality = xml:get_path_s(VCARD, [{elem, "ADR"}, {elem, "LOCALITY"},cdata]), - EMail = xml:get_path_s(VCARD, [{elem, "EMAIL"}, cdata]), - OrgName = xml:get_path_s(VCARD, [{elem, "ORG"}, {elem, "ORGNAME"}, cdata]), - OrgUnit = xml:get_path_s(VCARD, [{elem, "ORG"}, {elem, "ORGUNIT"}, cdata]), + FN = exmpp_xml:get_path(VCARD, + [{element, 'FN'}, cdata_as_list]), + Family = exmpp_xml:get_path(VCARD, + [{element, 'N'}, {element, 'FAMILY'}, cdata_as_list]), + Given = exmpp_xml:get_path(VCARD, + [{element, 'N'}, {element, 'GIVEN'}, cdata_as_list]), + Middle = exmpp_xml:get_path(VCARD, + [{element, 'N'}, {element, 'MIDDLE'}, cdata_as_list]), + Nickname = exmpp_xml:get_path(VCARD, + [{element, 'NICKNAME'}, cdata_as_list]), + BDay = exmpp_xml:get_path(VCARD, + [{element, 'BDAY'}, cdata_as_list]), + CTRY = exmpp_xml:get_path(VCARD, + [{element, 'ADR'}, {element, 'CTRY'}, cdata_as_list]), + Locality = exmpp_xml:get_path(VCARD, + [{element, 'ADR'}, {element, 'LOCALITY'},cdata_as_list]), + EMail = exmpp_xml:get_path(VCARD, + [{element, 'EMAIL'}, cdata_as_list]), + OrgName = exmpp_xml:get_path(VCARD, + [{element, 'ORG'}, {element, 'ORGNAME'}, cdata_as_list]), + OrgUnit = exmpp_xml:get_path(VCARD, + [{element, 'ORG'}, {element, 'ORGUNIT'}, cdata_as_list]), - {LUser, _LServer} = US, - LFN = stringprep:tolower(FN), - LFamily = stringprep:tolower(Family), - LGiven = stringprep:tolower(Given), - LMiddle = stringprep:tolower(Middle), - LNickname = stringprep:tolower(Nickname), - LBDay = stringprep:tolower(BDay), - LCTRY = stringprep:tolower(CTRY), - LLocality = stringprep:tolower(Locality), - LEMail = stringprep:tolower(EMail), - LOrgName = stringprep:tolower(OrgName), - LOrgUnit = stringprep:tolower(OrgUnit), - - if - (LUser == error) or - (LFN == error) or - (LFamily == error) or - (LGiven == error) or - (LMiddle == error) or - (LNickname == error) or - (LBDay == error) or - (LCTRY == error) or - (LLocality == error) or - (LEMail == error) or - (LOrgName == error) or - (LOrgUnit == error) -> - {error, badarg}; - true -> - mnesia:write( - #vcard_search{us = US, - user = User, luser = LUser, - fn = FN, lfn = LFN, - family = Family, lfamily = LFamily, - given = Given, lgiven = LGiven, - middle = Middle, lmiddle = LMiddle, - nickname = Nickname, lnickname = LNickname, - bday = BDay, lbday = LBDay, - ctry = CTRY, lctry = LCTRY, - locality = Locality, llocality = LLocality, - email = EMail, lemail = LEMail, - orgname = OrgName, lorgname = LOrgName, - orgunit = OrgUnit, lorgunit = LOrgUnit - }) + try + {LUser, _LServer} = US, + LFN = exmpp_stringprep:to_lower(FN), + LFamily = exmpp_stringprep:to_lower(Family), + LGiven = exmpp_stringprep:to_lower(Given), + LMiddle = exmpp_stringprep:to_lower(Middle), + LNickname = exmpp_stringprep:to_lower(Nickname), + LBDay = exmpp_stringprep:to_lower(BDay), + LCTRY = exmpp_stringprep:to_lower(CTRY), + LLocality = exmpp_stringprep:to_lower(Locality), + LEMail = exmpp_stringprep:to_lower(EMail), + LOrgName = exmpp_stringprep:to_lower(OrgName), + LOrgUnit = exmpp_stringprep:to_lower(OrgUnit), + mnesia:write( + #vcard_search{us = US, + user = User, luser = LUser, + fn = FN, lfn = LFN, + family = Family, lfamily = LFamily, + given = Given, lgiven = LGiven, + middle = Middle, lmiddle = LMiddle, + nickname = Nickname, lnickname = LNickname, + bday = BDay, lbday = LBDay, + ctry = CTRY, lctry = LCTRY, + locality = Locality, llocality = LLocality, + email = EMail, lemail = LEMail, + orgname = OrgName, lorgname = LOrgName, + orgunit = OrgUnit, lorgunit = LOrgUnit + }) + catch + _ -> + {error, badarg} end. @@ -665,8 +669,8 @@ reindex_vcards() -> remove_user(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_jid:nodeprep(User), + LServer = exmpp_jid:nameprep(Server), US = {LUser, LServer}, F = fun() -> mnesia:delete({vcard, US}), From 4a1e45070ec1f5e8c13f09e7feba7bf3d21cc89b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 21 Jul 2008 15:53:58 +0000 Subject: [PATCH 048/582] One call to jlib:jid_to_string/1 was remaining. SVN Revision: 1465 --- ChangeLog | 2 ++ src/mod_vcard.erl | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index ad48991b0..cc53893a8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,8 @@ * src/mod_roster.erl, src/mod_vcard.erl, src/gen_iq_handler.erl: Convert to exmpp. + * src/mod_vcard.erl: One call to jlib:jid_to_string/1 was remaining. + 2008-07-17 Jean-Sébastien Pédron Merge revisions from 1444 to revision 1457 from trunk. diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index fd78c3fb8..9f980dd70 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -303,7 +303,7 @@ set_vcard(User, LServer, VCARD) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', value = "form"}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = - [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ jlib:jid_to_string(JID))}]}, + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ exmpp_jid:jid_to_string(JID))}]}, #xmlel{ns = ?NS_SEARCH, name = 'instructions', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Fill in the form to search " From a8ab6c1568abe882dd529fa60ce6afb146a12e19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 21 Jul 2008 15:54:47 +0000 Subject: [PATCH 049/582] Add support for #xmlel to parse_xdata_submit/1 and friends. This fixes the user search in mod_vcard. SVN Revision: 1466 --- ChangeLog | 3 +++ src/jlib.erl | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/ChangeLog b/ChangeLog index cc53893a8..e18a404d8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,9 @@ * src/mod_vcard.erl: One call to jlib:jid_to_string/1 was remaining. + * src/jlib.erl: Add support for #xmlel to parse_xdata_submit/1 and + friends. This fixes the user search in mod_vcard. + 2008-07-17 Jean-Sébastien Pédron Merge revisions from 1444 to revision 1457 from trunk. diff --git a/src/jlib.erl b/src/jlib.erl index b926c15fb..698e704e4 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -448,6 +448,13 @@ iq_to_xml(#iq{id = ID, type = Type, sub_el = SubEl}) -> end. +parse_xdata_submit({xmlel, _, _, _, Attrs, Els}) -> + case exmpp_xml:get_attribute_from_list(Attrs, 'type') of + "submit" -> + lists:reverse(parse_xdata_fields(Els, [])); + _ -> + invalid + end; parse_xdata_submit(El) -> {xmlelement, _Name, Attrs, Els} = El, case xml:get_attr_s("type", Attrs) of @@ -459,6 +466,15 @@ parse_xdata_submit(El) -> parse_xdata_fields([], Res) -> Res; +parse_xdata_fields([{xmlel, _, _, 'field', Attrs, SubEls} | Els], + Res) -> + case exmpp_xml:get_attribute_from_list(Attrs, 'var') of + "" -> + parse_xdata_fields(Els, Res); + Var -> + Field = {Var, lists:reverse(parse_xdata_values(SubEls, []))}, + parse_xdata_fields(Els, [Field | Res]) + end; parse_xdata_fields([{xmlelement, Name, Attrs, SubEls} | Els], Res) -> case Name of "field" -> @@ -478,6 +494,9 @@ parse_xdata_fields([_ | Els], Res) -> parse_xdata_values([], Res) -> Res; +parse_xdata_values([{xmlel, _, _, 'value', _, SubEls} | Els], Res) -> + Val = exmpp_xml:get_cdata_from_list_as_list(SubEls), + parse_xdata_values(Els, [Val | Res]); parse_xdata_values([{xmlelement, Name, _Attrs, SubEls} | Els], Res) -> case Name of "value" -> From 37b99639d43b17b18e090eeace19d5ef6c107f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 22 Jul 2008 14:03:11 +0000 Subject: [PATCH 050/582] Convert to exmpp. SVN Revision: 1468 --- ChangeLog | 4 + src/gen_iq_handler.erl | 1 + src/mod_disco.erl | 255 +++++++++++++++++++++++------------------ 3 files changed, 147 insertions(+), 113 deletions(-) diff --git a/ChangeLog b/ChangeLog index e18a404d8..e19d2da6b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2008-07-22 Jean-Sébastien Pédron + + * src/mod_disco.erl, src/gen_iq_handler.erl: Convert to exmpp. + 2008-07-21 Jean-Sébastien Pédron * src/gen_iq_handler.erl: Prepare gen_iq_handler to pass arguments in diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index 0a949566f..19a0da6c4 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -59,6 +59,7 @@ % XXX OLD FORMAT: modules not in the following list will receive % old format strudctures. -define(CONVERTED_MODULES, [ + mod_disco, mod_roster, mod_vcard ]). diff --git a/src/mod_disco.erl b/src/mod_disco.erl index cf8751e07..9700a6546 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -47,8 +47,9 @@ register_extra_domain/2, unregister_extra_domain/2]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -record(disco_publish, {owner_node, jid, name, node}). @@ -62,13 +63,13 @@ start(Host, Opts) -> ejabberd_local:refresh_iq_handlers(), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, atom_to_list(?NS_DISCO_ITEMS), ?MODULE, process_local_iq_items, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, atom_to_list(?NS_DISCO_INFO), ?MODULE, process_local_iq_info, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_DISCO_ITEMS, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, atom_to_list(?NS_DISCO_ITEMS), ?MODULE, process_sm_iq_items, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_DISCO_INFO, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, atom_to_list(?NS_DISCO_INFO), ?MODULE, process_sm_iq_info, IQDisc), catch ets:new(disco_features, [named_table, ordered_set, public]), @@ -100,10 +101,10 @@ stop(Host) -> ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, get_local_identity, 100), ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, get_local_features, 100), ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, get_local_services, 100), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_DISCO_ITEMS), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_DISCO_INFO), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, atom_to_list(?NS_DISCO_ITEMS)), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, atom_to_list(?NS_DISCO_INFO)), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, atom_to_list(?NS_DISCO_ITEMS)), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, atom_to_list(?NS_DISCO_INFO)), catch ets:match_delete(disco_features, {{'_', Host}}), catch ets:match_delete(disco_extra_domains, {{'_', Host}}), ok. @@ -125,71 +126,82 @@ unregister_extra_domain(Host, Domain) -> catch ets:new(disco_extra_domains, [named_table, ordered_set, public]), ets:delete(disco_extra_domains, {Domain, Host}). -process_local_iq_items(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> - case Type of +process_local_iq_items(From, To, IQ) -> + case exmpp_iq:get_type(IQ) of set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + exmpp_iq:error(IQ, 'not-allowed'); get -> - Node = xml:get_tag_attr_s("node", SubEl), - Host = To#jid.lserver, + SubEl = exmpp_iq:get_request(IQ), + Node = exmpp_xml:get_attribute(SubEl, 'node'), + Host = To#jid.ldomain, + Lang = exmpp_stanza:get_lang(IQ), + % XXX OLD FORMAT: From, To. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), case ejabberd_hooks:run_fold(disco_local_items, Host, empty, - [From, To, Node, Lang]) of + [FromOld, ToOld, Node, Lang]) of {result, Items} -> + % XXX OLD FORMAT: Items might be an #xmlelement. ANode = case Node of "" -> []; - _ -> [{"node", Node}] + _ -> [#xmlattr{name = 'node', value = Node}] end, - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_DISCO_ITEMS} | ANode], - Items - }]}; + Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', + attrs = ANode, children = Items}, + exmpp_iq:result(IQ, Result); {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]} + % XXX OLD FORMAT: Error. + exmpp_iq:error(IQ, Error) end end. -process_local_iq_info(From, To, #iq{type = Type, lang = Lang, - sub_el = SubEl} = IQ) -> - case Type of +process_local_iq_info(From, To, IQ) -> + case exmpp_iq:get_type(IQ) of set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + exmpp_iq:error(IQ, 'not-allowed'); get -> - Host = To#jid.lserver, - Node = xml:get_tag_attr_s("node", SubEl), + Host = To#jid.ldomain, + SubEl = exmpp_iq:get_request(IQ), + Node = exmpp_xml:get_attribute(SubEl, 'node'), + Lang = exmpp_stanza:get_lang(IQ), + % XXX OLD FORMAT: From, To. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), + % XXX OLD FORMAT: Identity might be an #xmlelement. Identity = ejabberd_hooks:run_fold(disco_local_identity, Host, [], - [From, To, Node, Lang]), + [FromOld, ToOld, Node, Lang]), + % XXX OLD FORMAT: From, To. case ejabberd_hooks:run_fold(disco_local_features, Host, empty, - [From, To, Node, Lang]) of + [FromOld, ToOld, Node, Lang]) of {result, Features} -> ANode = case Node of "" -> []; - _ -> [{"node", Node}] + _ -> [#xmlattr{name = 'node', value = Node}] end, - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_DISCO_INFO} | ANode], - Identity ++ - lists:map(fun feature_to_xml/1, Features) - }]}; + Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', + attrs = ANode, + children = Identity ++ lists:map(fun feature_to_xml/1, + Features)}, + exmpp_iq:result(IQ, Result); {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]} + exmpp_iq:error(IQ, Error) end end. get_local_identity(Acc, _From, _To, [], _Lang) -> - Acc ++ [{xmlelement, "identity", - [{"category", "server"}, - {"type", "im"}, - {"name", "ejabberd"}], []}]; + Acc ++ [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [ + #xmlattr{name = 'category', value = "server"}, + #xmlattr{name = 'type', value = "im"}, + #xmlattr{name = 'name', value = "ejabberd"} + ]}]; get_local_identity(Acc, _From, _To, _Node, _Lang) -> Acc. @@ -202,7 +214,7 @@ get_local_features(Acc, _From, To, [], _Lang) -> {result, Features} -> Features; empty -> [] end, - Host = To#jid.lserver, + Host = To#jid.ldomain, {result, ets:select(disco_features, [{{{'_', Host}}, [], ['$_']}]) ++ Feats}; @@ -211,29 +223,36 @@ get_local_features(Acc, _From, _To, _Node, _Lang) -> {result, _Features} -> Acc; empty -> - {error, ?ERR_ITEM_NOT_FOUND} + {error, 'item-not-found'} end. feature_to_xml({{Feature, _Host}}) -> feature_to_xml(Feature); feature_to_xml(Feature) when is_list(Feature) -> - {xmlelement, "feature", [{"var", Feature}], []}. + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ + #xmlattr{name = 'var', value = Feature} + ]}. domain_to_xml({Domain}) -> - {xmlelement, "item", [{"jid", Domain}], []}; + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [ + #xmlattr{name = 'jid', value = Domain} + ]}; domain_to_xml(Domain) -> - {xmlelement, "item", [{"jid", Domain}], []}. + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [ + #xmlattr{name = 'jid', value = Domain} + ]}. get_local_services({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; get_local_services(Acc, _From, To, [], _Lang) -> + % XXX OLD FORMAT: Items might be an #xmlelement. Items = case Acc of {result, Its} -> Its; empty -> [] end, - Host = To#jid.lserver, + Host = To#jid.ldomain, {result, lists:usort( lists:map(fun domain_to_xml/1, @@ -246,7 +265,7 @@ get_local_services({result, _} = Acc, _From, _To, _Node, _Lang) -> Acc; get_local_services(empty, _From, _To, _Node, _Lang) -> - {error, ?ERR_ITEM_NOT_FOUND}. + {error, 'item-not-found'}. get_vh_services(Host) -> Hosts = lists:sort(fun(H1, H2) -> length(H1) >= length(H2) end, ?MYHOSTS), @@ -264,46 +283,49 @@ get_vh_services(Host) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -process_sm_iq_items(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> - case Type of +process_sm_iq_items(From, To, IQ) -> + SubEl = exmpp_iq:get_request(IQ), + case exmpp_iq:get_type(IQ) of set -> - #jid{luser = LTo, lserver = ToServer} = To, - #jid{luser = LFrom, lserver = LServer} = From, + #jid{lnode = LTo, ldomain = ToServer} = To, + #jid{lnode = LFrom, ldomain = LServer} = From, Self = (LTo == LFrom) andalso (ToServer == LServer), - Node = xml:get_tag_attr_s("node", SubEl), + Node = exmpp_xml:get_attribute(SubEl, 'node'), if Self, Node /= [] -> %% Here, we treat disco publish attempts to your own JID. - {xmlelement, _, _, Items} = SubEl, + Items = SubEl#xmlel.children, case process_disco_publish({LFrom, LServer}, Node, Items) of ok -> - IQ#iq{type = result, sub_el = []}; + exmpp_iq:result(IQ); {error, Err} -> - IQ#iq{type = error, sub_el = [SubEl, Err]} + exmpp_iq:error(IQ, Err) end; true -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]} + exmpp_iq:error(IQ, 'not-allowed') end; get -> - Host = To#jid.lserver, - Node = xml:get_tag_attr_s("node", SubEl), + Host = To#jid.ldomain, + Node = exmpp_xml:get_attribute(SubEl, 'node'), + Lang = exmpp_stanza:get_lang(IQ), + % XXX OLD FORMAT: From, To. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), case ejabberd_hooks:run_fold(disco_sm_items, Host, empty, - [From, To, Node, Lang]) of + [FromOld, ToOld, Node, Lang]) of {result, Items} -> ANode = case Node of "" -> []; - _ -> [{"node", Node}] + _ -> [#xmlattr{name = 'node', value = Node}] end, - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_DISCO_ITEMS} | ANode], - Items - }]}; + Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', + attrs = ANode, children = Items}, + exmpp_iq:result(IQ, Result); {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]} + exmpp_iq:error(IQ, Error) end end. @@ -311,8 +333,8 @@ get_sm_items({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; get_sm_items(Acc, - #jid{luser = LFrom, lserver = LSFrom}, - #jid{user = User, server = Server, luser = LTo, lserver = LSTo} = _To, + #jid{lnode = LFrom, ldomain = LSFrom}, + #jid{node = User, domain = Server, lnode = LTo, ldomain = LSTo} = _To, [], _Lang) -> Items = case Acc of {result, Its} -> Its; @@ -328,43 +350,48 @@ get_sm_items({result, _} = Acc, _From, _To, _Node, _Lang) -> Acc; get_sm_items(empty, From, To, _Node, _Lang) -> - #jid{luser = LFrom, lserver = LSFrom} = From, - #jid{luser = LTo, lserver = LSTo} = To, + #jid{lnode = LFrom, ldomain = LSFrom} = From, + #jid{lnode = LTo, ldomain = LSTo} = To, case {LFrom, LSFrom} of {LTo, LSTo} -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; _ -> - {error, ?ERR_NOT_ALLOWED} + {error, 'not-allowed'} end. -process_sm_iq_info(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> - case Type of +process_sm_iq_info(From, To, IQ) -> + case exmpp_iq:get_type(IQ) of set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + exmpp_iq:error(IQ, 'not-allowed'); get -> - Host = To#jid.lserver, - Node = xml:get_tag_attr_s("node", SubEl), + Host = To#jid.ldomain, + SubEl = exmpp_iq:get_request(IQ), + Node = exmpp_xml:get_attribute(SubEl, 'node'), + Lang = exmpp_stanza:get_lang(IQ), + % XXX OLD FORMAT: From, To. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), + % XXX OLD FORMAT: Identity might be an #xmlelement. Identity = ejabberd_hooks:run_fold(disco_sm_identity, Host, [], - [From, To, Node, Lang]), + [FromOld, ToOld, Node, Lang]), case ejabberd_hooks:run_fold(disco_sm_features, Host, empty, - [From, To, Node, Lang]) of + [FromOld, ToOld, Node, Lang]) of {result, Features} -> ANode = case Node of "" -> []; - _ -> [{"node", Node}] + _ -> [#xmlattr{name = 'node', value = Node}] end, - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_DISCO_INFO} | ANode], - Identity ++ - lists:map(fun feature_to_xml/1, Features) - }]}; + Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', + attrs = ANode, + children = Identity ++ lists:map(fun feature_to_xml/1, + Features)}, + exmpp_iq:result(IQ, Result); {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]} + exmpp_iq:error(IQ, Error) end end. @@ -372,13 +399,13 @@ get_sm_identity(Acc, _From, _To, _Node, _Lang) -> Acc. get_sm_features(empty, From, To, _Node, _Lang) -> - #jid{luser = LFrom, lserver = LSFrom} = From, - #jid{luser = LTo, lserver = LSTo} = To, + #jid{lnode = LFrom, ldomain = LSFrom} = From, + #jid{lnode = LTo, ldomain = LSTo} = To, case {LFrom, LSFrom} of {LTo, LSTo} -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; _ -> - {error, ?ERR_NOT_ALLOWED} + {error, 'not-allowed'} end; get_sm_features(Acc, _From, _To, _Node, _Lang) -> @@ -389,15 +416,17 @@ get_sm_features(Acc, _From, _To, _Node, _Lang) -> get_user_resources(User, Server) -> Rs = ejabberd_sm:get_user_resources(User, Server), lists:map(fun(R) -> - {xmlelement, "item", - [{"jid", User ++ "@" ++ Server ++ "/" ++ R}, - {"name", User}], []} + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [ + #xmlattr{name = 'jid', value = + exmpp_jid:jid_to_string(User, Server, R)}, + #xmlattr{name = 'name', value = User} + ]} end, lists:sort(Rs)). get_publish_items(empty, - #jid{luser = LFrom, lserver = LSFrom}, - #jid{luser = LTo, lserver = LSTo} = _To, + #jid{lnode = LFrom, ldomain = LSFrom}, + #jid{lnode = LTo, ldomain = LSTo} = _To, Node, _Lang) -> if (LFrom == LTo) and (LSFrom == LSTo) -> @@ -411,11 +440,11 @@ get_publish_items(Acc, _From, _To, _Node, _Lang) -> process_disco_publish(User, Node, Items) -> F = fun() -> lists:foreach( - fun({xmlelement, _Name, _Attrs, _SubEls} = Item) -> - Action = xml:get_tag_attr_s("action", Item), - Jid = xml:get_tag_attr_s("jid", Item), - PNode = xml:get_tag_attr_s("node", Item), - Name = xml:get_tag_attr_s("name", Item), + fun(#xmlel{} = Item) -> + Action = exmpp_xml:get_attribute(Item, 'action'), + Jid = exmpp_xml:get_attribute(Item, 'jid'), + PNode = exmpp_xml:get_attribute(Item, 'node'), + Name = exmpp_xml:get_attribute(Item, 'name'), ?INFO_MSG("Disco publish: ~p ~p ~p ~p ~p ~p~n", [User, Action, Node, Jid, PNode, Name]), @@ -442,7 +471,7 @@ process_disco_publish(User, Node, Items) -> "remove" -> case SupersededItems of [] -> - mnesia:abort({error, ?ERR_ITEM_NOT_FOUND}); + mnesia:abort({error, 'item-not-found'}); _ -> lists:map( fun(O) -> @@ -451,9 +480,9 @@ process_disco_publish(User, Node, Items) -> end; _ -> %% invalid "action" attribute - return an error - mnesia:abort({error, ?ERR_BAD_REQUEST}) + mnesia:abort({error, 'bad-request'}) end; - ({xmlcdata, _CDATA}) -> + (#xmlcdata{}) -> ok end, Items) end, @@ -463,13 +492,13 @@ process_disco_publish(User, Node, Items) -> {atomic, _} -> ok; _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} + {error, 'internal-server-error'} end. retrieve_disco_publish(User, Node) -> case catch mnesia:dirty_read({disco_publish, {User, Node}}) of {'EXIT', _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, 'internal-server-error'}; [] -> empty; Items -> @@ -478,20 +507,20 @@ retrieve_disco_publish(User, Node) -> fun(#disco_publish{jid = Jid, name = Name, node = PNode}) -> - {xmlelement, "item", - lists:append([[{"jid", Jid}], + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = + lists:append([[#xmlattr{name = 'jid', value = Jid}], case Name of "" -> []; _ -> - [{"name", Name}] + [#xmlattr{name = 'name', value = Name}] end, case PNode of "" -> []; _ -> - [{"node", PNode}] - end]), []} + [#xmlattr{name = 'node', value = PNode}] + end])} end, Items)} end. From adaf3921560a8a60bb7bdd6206f3488e3fff367d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 22 Jul 2008 14:51:19 +0000 Subject: [PATCH 051/582] o Finish conversion to exmpp for mod_caps. o In ejabberd_loca, IQ response handler are now always called with arguments in the new format. SVN Revision: 1469 --- ChangeLog | 6 ++++++ src/ejabberd_local.erl | 6 +----- src/gen_iq_handler.erl | 1 + src/mod_caps.erl | 24 ++++++++---------------- 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index e19d2da6b..514c75211 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,12 @@ * src/mod_disco.erl, src/gen_iq_handler.erl: Convert to exmpp. + * src/mod_caps.erl, src/gen_iq_handler.erl: Finish conversion to + exmpp. + + * src/ejabberd_local.erl (process_iq_reply): IQ handler are now always + called with arguments in the new format. + 2008-07-21 Jean-Sébastien Pédron * src/gen_iq_handler.erl: Prepare gen_iq_handler to pass arguments in diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index c3786ca53..f047569f9 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -131,11 +131,7 @@ process_iq_reply(From, To, Packet) -> end, case mnesia:transaction(F) of {atomic, {Module, Function}} -> - % XXX OLD FORMAT: From, To, Packet. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - IQ_Rec = jlib:iq_query_or_response_info(Packet), - Module:Function(FromOld, ToOld, IQ_Rec); + Module:Function(From, To, Packet); _ -> ok end diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index 19a0da6c4..8cc1c4c65 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -59,6 +59,7 @@ % XXX OLD FORMAT: modules not in the following list will receive % old format strudctures. -define(CONVERTED_MODULES, [ + mod_caps, mod_disco, mod_roster, mod_vcard diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 9d7846a48..9b3bef70b 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -62,13 +62,6 @@ disco_requests = ?DICT:new(), feature_queries = []}). -% XXX OLD FORMAT: Re-include jlib.hrl (after clean-up). --record(iq, {id = "", - type, - xmlns = "", - lang = "", - sub_el}). - %% read_caps takes a list of XML elements (the child elements of a %% stanza) and returns an opaque value representing the %% Entity Capabilities contained therein, or the atom nothing if no @@ -224,17 +217,16 @@ handle_cast({note_caps, From, ?ERROR_MSG("Transaction failed: ~p", [Error]), {noreply, State} end; -handle_cast({disco_response, From, _To, - #iq{type = Type, id = ID, - sub_el = SubEls}}, +handle_cast({disco_response, From, _To, IQ}, #state{disco_requests = Requests} = State) -> - case {Type, SubEls} of - {result, [{xmlelement, "query", _Attrs, Els}]} -> + ID = exmpp_stanza:get_id(IQ), + case {exmpp_iq:get_type(IQ), exmpp_iq:get_payload(IQ)} of + {result, #xmlel{name = 'query', children = Els}} -> case ?DICT:find(ID, Requests) of {ok, {Node, SubNode}} -> Features = - lists:flatmap(fun({xmlelement, "feature", FAttrs, _}) -> - [xml:get_attr_s("var", FAttrs)]; + lists:flatmap(fun(#xmlel{name = 'feature'} = F) -> + [exmpp_xml:get_attribute(F, 'var')]; (_) -> [] end, Els), @@ -262,9 +254,9 @@ handle_cast({disco_response, From, _To, ?ERROR_MSG("ID '~s' matches no query", [ID]) end; %gen_server:cast(self(), visit_feature_queries), - %?DEBUG("Error IQ reponse from ~s:~n~p", [jlib:jid_to_string(From), SubEls]); + %?DEBUG("Error IQ reponse from ~s:~n~p", [exmpp_jid:jid_to_string(From), SubEls]); {result, _} -> - ?DEBUG("Invalid IQ contents from ~s:~n~p", [jlib:jid_to_string(From), SubEls]); + ?DEBUG("Invalid IQ contents from ~s:~n~p", [exmpp_jid:jid_to_string(From), IQ#xmlel.children]); _ -> %% Can't do anything about errors ok From 70956ece120fbe155b56f8c6d7f432965025d883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 25 Jul 2008 14:26:59 +0000 Subject: [PATCH 052/582] Convert to exmpp. SVN Revision: 1492 --- ChangeLog | 5 + src/adhoc.erl | 87 ++-- src/gen_iq_handler.erl | 3 + src/mod_adhoc.erl | 121 +++--- src/mod_announce.erl | 313 +++++++------- src/mod_configure.erl | 938 ++++++++++++++++++++--------------------- 6 files changed, 739 insertions(+), 728 deletions(-) diff --git a/ChangeLog b/ChangeLog index 514c75211..8e9dce87a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-07-25 Jean-Sébastien Pédron + + * src/adhoc.erl, src/mod_configure.erl, src/mod_announce.erl, + src/mod_adhoc.erl, src/gen_iq_handler.erl: Convert to exmpp. + 2008-07-22 Jean-Sébastien Pédron * src/mod_disco.erl, src/gen_iq_handler.erl: Convert to exmpp. diff --git a/src/adhoc.erl b/src/adhoc.erl index b4641253f..a35dc763f 100644 --- a/src/adhoc.erl +++ b/src/adhoc.erl @@ -31,47 +31,53 @@ produce_response/2, produce_response/1]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("adhoc.hrl"). %% Parse an ad-hoc request. Return either an adhoc_request record or %% an {error, ErrorType} tuple. -parse_request(#iq{type = set, lang = Lang, sub_el = SubEl, xmlns = ?NS_COMMANDS}) -> - ?DEBUG("entering parse_request...", []), - Node = xml:get_tag_attr_s("node", SubEl), - SessionID = xml:get_tag_attr_s("sessionid", SubEl), - Action = xml:get_tag_attr_s("action", SubEl), - XData = find_xdata_el(SubEl), - {xmlelement, _, _, AllEls} = SubEl, - if XData -> - Others = lists:delete(XData, AllEls); - true -> - Others = AllEls - end, +parse_request(IQ) -> + try + SubEl = exmpp_iq:get_request(IQ), + case {exmpp_iq:get_type(IQ), SubEl#xmlel.ns} of + {set, ?NS_ADHOC} -> + ?DEBUG("entering parse_request...", []), + Lang = exmpp_stanza:get_lang(IQ), + Node = exmpp_xml:get_attribute(SubEl, 'node'), + SessionID = exmpp_xml:get_attribute(SubEl, 'sessionid'), + Action = exmpp_xml:get_attribute(SubEl, 'action'), + XData = find_xdata_el(SubEl), + AllEls = SubEl#xmlel.ns, + if XData -> + Others = lists:delete(XData, AllEls); + true -> + Others = AllEls + end, - #adhoc_request{lang = Lang, - node = Node, - sessionid = SessionID, - action = Action, - xdata = XData, - others = Others}; -parse_request(_) -> - {error, ?ERR_BAD_REQUEST}. + #adhoc_request{lang = Lang, + node = Node, + sessionid = SessionID, + action = Action, + xdata = XData, + others = Others}; + _ -> + {error, 'bad-request'} + end + catch + _ -> + {error, 'bad-request'} + end. %% Borrowed from mod_vcard.erl -find_xdata_el({xmlelement, _Name, _Attrs, SubEls}) -> +find_xdata_el(#xmlel{children = SubEls}) -> find_xdata_el1(SubEls). find_xdata_el1([]) -> false; -find_xdata_el1([{xmlelement, Name, Attrs, SubEls} | Els]) -> - case xml:get_attr_s("xmlns", Attrs) of - ?NS_XDATA -> - {xmlelement, Name, Attrs, SubEls}; - _ -> - find_xdata_el1(Els) - end; +find_xdata_el1([#xmlel{ns = ?NS_DATA_FORMS} = El | _Els]) -> + El; find_xdata_el1([_ | Els]) -> find_xdata_el1(Els). @@ -109,20 +115,19 @@ produce_response(#adhoc_response{lang = _Lang, "" -> ActionsElAttrs = []; _ -> - ActionsElAttrs = [{"execute", DefaultAction}] + ActionsElAttrs = [#xmlattr{name = 'execute', value = DefaultAction}] end, - ActionsEls = [{xmlelement, "actions", - ActionsElAttrs, - [{xmlelement, Action, [], []} || Action <- Actions]}] + ActionsEls = [#xmlel{ns = ?NS_ADHOC, name = 'actions', attrs = + ActionsElAttrs, children = + [#xmlel{ns = ?NS_ADHOC, name = Action} || Action <- Actions]}] end, NotesEls = lists:map(fun({Type, Text}) -> - {xmlelement, "note", - [{"type", Type}], - [{xmlcdata, Text}]} + #xmlel{ns = ?NS_ADHOC, name = 'note', attrs = + [#xmlattr{name = 'type', value = Type}], + children = [#xmlcdata{cdata = list_to_binary(Text)}]} end, Notes), - {xmlelement, "command", - [{"xmlns", ?NS_COMMANDS}, - {"sessionid", SessionID}, - {"node", Node}, - {"status", atom_to_list(Status)}], + #xmlel{ns = ?NS_ADHOC, name = 'command', attrs = + [#xmlattr{name = 'sessionid', value = SessionID}, + #xmlattr{name = 'node', value = Node}, + #xmlattr{name = 'status', value = atom_to_list(Status)}], children = ActionsEls ++ NotesEls ++ Elements}. diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index 8cc1c4c65..33d445942 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -59,7 +59,10 @@ % XXX OLD FORMAT: modules not in the following list will receive % old format strudctures. -define(CONVERTED_MODULES, [ + mod_adhoc, + mod_annouce, mod_caps, + mod_configure, mod_disco, mod_roster, mod_vcard diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl index be1bc1cb8..87f66899b 100644 --- a/src/mod_adhoc.erl +++ b/src/mod_adhoc.erl @@ -42,16 +42,17 @@ ping_item/4, ping_command/4]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("adhoc.hrl"). start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_COMMANDS, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_ADHOC_s, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_COMMANDS, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ADHOC_s, ?MODULE, process_sm_iq, IQDisc), ejabberd_hooks:add(disco_local_identity, Host, ?MODULE, get_local_identity, 99), @@ -73,12 +74,12 @@ stop(Host) -> ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, get_local_features, 99), ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, get_local_identity, 99), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_COMMANDS), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_COMMANDS). + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ADHOC_s), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ADHOC_s). %------------------------------------------------------------------------- -get_local_commands(Acc, _From, #jid{server = Server, lserver = LServer} = _To, "", Lang) -> +get_local_commands(Acc, _From, #jid{domain = Server, ldomain = LServer} = _To, "", Lang) -> Display = gen_mod:get_module_opt(LServer, ?MODULE, report_commands_node, false), case Display of false -> @@ -88,17 +89,20 @@ get_local_commands(Acc, _From, #jid{server = Server, lserver = LServer} = _To, " {result, I} -> I; _ -> [] end, - Nodes = [{xmlelement, - "item", - [{"jid", Server}, - {"node", ?NS_COMMANDS}, - {"name", translate:translate(Lang, "Commands")}], - []}], + Nodes = [#xmlel{ns = ?NS_DISCO_ITEMS, + name = 'item', attrs = + [#xmlattr{name = 'jid', value = Server}, + #xmlattr{name = 'node', value = ?NS_ADHOC_s}, + #xmlattr{name = 'name', value = translate:translate(Lang, "Commands")}] + }], {result, Items ++ Nodes} end; -get_local_commands(_Acc, From, #jid{lserver = LServer} = To, ?NS_COMMANDS, Lang) -> - ejabberd_hooks:run_fold(adhoc_local_items, LServer, {result, []}, [From, To, Lang]); +get_local_commands(_Acc, From, #jid{ldomain = LServer} = To, ?NS_ADHOC_s, Lang) -> + % XXX OLD FORMAT: From, To. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), + ejabberd_hooks:run_fold(adhoc_local_items, LServer, {result, []}, [FromOld, ToOld, Lang]); get_local_commands(_Acc, _From, _To, "ping", _Lang) -> {result, []}; @@ -108,7 +112,7 @@ get_local_commands(Acc, _From, _To, _Node, _Lang) -> %------------------------------------------------------------------------- -get_sm_commands(Acc, _From, #jid{lserver = LServer} = To, "", Lang) -> +get_sm_commands(Acc, _From, #jid{ldomain = LServer} = To, "", Lang) -> Display = gen_mod:get_module_opt(LServer, ?MODULE, report_commands_node, false), case Display of false -> @@ -118,17 +122,20 @@ get_sm_commands(Acc, _From, #jid{lserver = LServer} = To, "", Lang) -> {result, I} -> I; _ -> [] end, - Nodes = [{xmlelement, - "item", - [{"jid", jlib:jid_to_string(To)}, - {"node", ?NS_COMMANDS}, - {"name", translate:translate(Lang, "Commands")}], - []}], + Nodes = [#xmlel{ns = ?NS_DISCO_ITEMS, + name = 'item', attrs = + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_string(To)}, + #xmlattr{name = 'node', value = ?NS_ADHOC_s}, + #xmlattr{name = 'name', value = translate:translate(Lang, "Commands")}] + }], {result, Items ++ Nodes} end; -get_sm_commands(_Acc, From, #jid{lserver = LServer} = To, ?NS_COMMANDS, Lang) -> - ejabberd_hooks:run_fold(adhoc_sm_items, LServer, {result, []}, [From, To, Lang]); +get_sm_commands(_Acc, From, #jid{ldomain = LServer} = To, ?NS_ADHOC_s, Lang) -> + % XXX OLD FORMAT: From, To. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), + ejabberd_hooks:run_fold(adhoc_sm_items, LServer, {result, []}, [FromOld, ToOld, Lang]); get_sm_commands(Acc, _From, _To, _Node, _Lang) -> Acc. @@ -136,17 +143,17 @@ get_sm_commands(Acc, _From, _To, _Node, _Lang) -> %------------------------------------------------------------------------- %% On disco info request to the ad-hoc node, return automation/command-list. -get_local_identity(Acc, _From, _To, ?NS_COMMANDS, Lang) -> - [{xmlelement, "identity", - [{"category", "automation"}, - {"type", "command-list"}, - {"name", translate:translate(Lang, "Commands")}], []} | Acc]; +get_local_identity(Acc, _From, _To, ?NS_ADHOC_s, Lang) -> + [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = + [#xmlattr{name = 'category', value = "automation"}, + #xmlattr{name = 'type', value = "command-list"}, + #xmlattr{name = 'name', value = translate:translate(Lang, "Commands")}]} | Acc]; get_local_identity(Acc, _From, _To, "ping", Lang) -> - [{xmlelement, "identity", - [{"category", "automation"}, - {"type", "command-node"}, - {"name", translate:translate(Lang, "Ping")}], []} | Acc]; + [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = + [#xmlattr{name = 'category', value = "automation"}, + #xmlattr{name = 'type', value = "command-node"}, + #xmlattr{name = 'name', value = translate:translate(Lang, "Ping")}]} | Acc]; get_local_identity(Acc, _From, _To, _Node, _Lang) -> Acc. @@ -154,11 +161,11 @@ get_local_identity(Acc, _From, _To, _Node, _Lang) -> %------------------------------------------------------------------------- %% On disco info request to the ad-hoc node, return automation/command-list. -get_sm_identity(Acc, _From, _To, ?NS_COMMANDS, Lang) -> - [{xmlelement, "identity", - [{"category", "automation"}, - {"type", "command-list"}, - {"name", translate:translate(Lang, "Commands")}], []} | Acc]; +get_sm_identity(Acc, _From, _To, ?NS_ADHOC_s, Lang) -> + [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = + [#xmlattr{name = 'category', value = "automation"}, + #xmlattr{name = 'type', value = "command-list"}, + #xmlattr{name = 'name', value = translate:translate(Lang, "Commands")}]} | Acc]; get_sm_identity(Acc, _From, _To, _Node, _Lang) -> Acc. @@ -170,15 +177,15 @@ get_local_features(Acc, _From, _To, "", _Lang) -> {result, I} -> I; _ -> [] end, - {result, Feats ++ [?NS_COMMANDS]}; + {result, Feats ++ [?NS_ADHOC_s]}; -get_local_features(_Acc, _From, _To, ?NS_COMMANDS, _Lang) -> +get_local_features(_Acc, _From, _To, ?NS_ADHOC_s, _Lang) -> %% override all lesser features... {result, []}; get_local_features(_Acc, _From, _To, "ping", _Lang) -> %% override all lesser features... - {result, [?NS_COMMANDS]}; + {result, [?NS_ADHOC_s]}; get_local_features(Acc, _From, _To, _Node, _Lang) -> Acc. @@ -190,9 +197,9 @@ get_sm_features(Acc, _From, _To, "", _Lang) -> {result, I} -> I; _ -> [] end, - {result, Feats ++ [?NS_COMMANDS]}; + {result, Feats ++ [?NS_ADHOC_s]}; -get_sm_features(_Acc, _From, _To, ?NS_COMMANDS, _Lang) -> +get_sm_features(_Acc, _From, _To, ?NS_ADHOC_s, _Lang) -> %% override all lesser features... {result, []}; @@ -209,39 +216,41 @@ process_sm_iq(From, To, IQ) -> process_adhoc_request(From, To, IQ, adhoc_sm_commands). -process_adhoc_request(From, To, #iq{sub_el = SubEl} = IQ, Hook) -> +process_adhoc_request(From, To, IQ, Hook) -> ?DEBUG("About to parse ~p...", [IQ]), case adhoc:parse_request(IQ) of {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]}; + exmpp_iq:error(IQ, Error); #adhoc_request{} = AdhocRequest -> - Host = To#jid.lserver, + Host = To#jid.ldomain, + % XXX OLD FORMAT: From, To. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), case ejabberd_hooks:run_fold(Hook, Host, empty, - [From, To, AdhocRequest]) of + [FromOld, ToOld, AdhocRequest]) of ignore -> ignore; empty -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]}; + exmpp_iq:error(IQ, 'item-not-found'); {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]}; + exmpp_iq:error(IQ, Error); Command -> - IQ#iq{type = result, sub_el = [Command]} + exmpp_iq:result(IQ, Command) end end. -ping_item(Acc, _From, #jid{server = Server} = _To, Lang) -> +ping_item(Acc, _From, #jid{domain = Server} = _To, Lang) -> Items = case Acc of {result, I} -> I; _ -> [] end, - Nodes = [{xmlelement, "item", - [{"jid", Server}, - {"node", "ping"}, - {"name", translate:translate(Lang, "Ping")}], - []}], + Nodes = [#xmlel{ns = ?NS_DISCO_INFO, name = 'item', attrs = + [#xmlattr{name = 'jid', value = Server}, + #xmlattr{name = 'node', value = "ping"}, + #xmlattr{name = 'name', value = translate:translate(Lang, "Ping")}]}], {result, Items ++ Nodes}. @@ -259,7 +268,7 @@ ping_command(_Acc, _From, _To, Lang, "Pong")}]}); true -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; ping_command(Acc, _From, _To, _Request) -> diff --git a/src/mod_announce.erl b/src/mod_announce.erl index 438f834a2..5a744e6e0 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -43,8 +43,9 @@ announce_commands/4, announce_items/4]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("adhoc.hrl"). -record(motd, {server, packet}). @@ -52,6 +53,8 @@ -define(PROCNAME, ejabberd_announce). +-define(NS_ADMIN_s, "http://jabber.org/protocol/admin"). + -define(NS_ADMINL(Sub), ["http:","jabber.org","protocol","admin", Sub]). tokenize(Node) -> string:tokens(Node, "/#"). @@ -129,38 +132,38 @@ stop(Host) -> %% Announcing via messages to a custom resource announce(From, To, Packet) -> case To of - #jid{luser = "", lresource = Res} -> - {xmlelement, Name, _Attrs, _Els} = Packet, - Proc = gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME), + #jid{lnode = undefined, lresource = Res} -> + Name = Packet#xmlel.name, + Proc = gen_mod:get_module_proc(To#jid.ldomain, ?PROCNAME), case {Res, Name} of - {"announce/all", "message"} -> + {"announce/all", 'message'} -> Proc ! {announce_all, From, To, Packet}, stop; - {"announce/all-hosts/all", "message"} -> + {"announce/all-hosts/all", 'message'} -> Proc ! {announce_all_hosts_all, From, To, Packet}, stop; - {"announce/online", "message"} -> + {"announce/online", 'message'} -> Proc ! {announce_online, From, To, Packet}, stop; - {"announce/all-hosts/online", "message"} -> + {"announce/all-hosts/online", 'message'} -> Proc ! {announce_all_hosts_online, From, To, Packet}, stop; - {"announce/motd", "message"} -> + {"announce/motd", 'message'} -> Proc ! {announce_motd, From, To, Packet}, stop; - {"announce/all-hosts/motd", "message"} -> + {"announce/all-hosts/motd", 'message'} -> Proc ! {announce_all_hosts_motd, From, To, Packet}, stop; - {"announce/motd/update", "message"} -> + {"announce/motd/update", 'message'} -> Proc ! {announce_motd_update, From, To, Packet}, stop; - {"announce/all-hosts/motd/update", "message"} -> + {"announce/all-hosts/motd/update", 'message'} -> Proc ! {announce_all_hosts_motd_update, From, To, Packet}, stop; - {"announce/motd/delete", "message"} -> + {"announce/motd/delete", 'message'} -> Proc ! {announce_motd_delete, From, To, Packet}, stop; - {"announce/all-hosts/motd/delete", "message"} -> + {"announce/all-hosts/motd/delete", 'message'} -> Proc ! {announce_all_hosts_motd_delete, From, To, Packet}, stop; _ -> @@ -173,10 +176,10 @@ announce(From, To, Packet) -> %%------------------------------------------------------------------------- %% Announcing via ad-hoc commands -define(INFO_COMMAND(Lang, Node), - [{xmlelement, "identity", - [{"category", "automation"}, - {"type", "command-node"}, - {"name", get_title(Lang, Node)}], []}]). + [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = + [#xmlattr{name = 'category', value = "automation"}, + #xmlattr{name = 'type', value = "command-node"}, + #xmlattr{name = 'name', value = get_title(Lang, Node)}]}]). disco_identity(Acc, _From, _To, Node, Lang) -> LNode = tokenize(Node), @@ -210,12 +213,12 @@ disco_identity(Acc, _From, _To, Node, Lang) -> -define(INFO_RESULT(Allow, Feats), case Allow of deny -> - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; allow -> {result, Feats} end). -disco_features(Acc, From, #jid{lserver = LServer} = _To, +disco_features(Acc, From, #jid{ldomain = LServer} = _To, "announce", _Lang) -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> @@ -226,13 +229,13 @@ disco_features(Acc, From, #jid{lserver = LServer} = _To, case {acl:match_rule(LServer, Access1, From), acl:match_rule(global, Access2, From)} of {deny, deny} -> - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; _ -> {result, []} end end; -disco_features(Acc, From, #jid{lserver = LServer} = _To, +disco_features(Acc, From, #jid{ldomain = LServer} = _To, Node, _Lang) -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> @@ -243,26 +246,26 @@ disco_features(Acc, From, #jid{lserver = LServer} = _To, AccessGlobal = gen_mod:get_module_opt(global, ?MODULE, access, none), AllowGlobal = acl:match_rule(global, AccessGlobal, From), case Node of - ?NS_ADMIN ++ "#announce" -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); - ?NS_ADMIN ++ "#announce-all" -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); - ?NS_ADMIN ++ "#set-motd" -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); - ?NS_ADMIN ++ "#edit-motd" -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); - ?NS_ADMIN ++ "#delete-motd" -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); - ?NS_ADMIN ++ "#announce-allhosts" -> - ?INFO_RESULT(AllowGlobal, [?NS_COMMANDS]); - ?NS_ADMIN ++ "#announce-all-allhosts" -> - ?INFO_RESULT(AllowGlobal, [?NS_COMMANDS]); - ?NS_ADMIN ++ "#set-motd-allhosts" -> - ?INFO_RESULT(AllowGlobal, [?NS_COMMANDS]); - ?NS_ADMIN ++ "#edit-motd-allhosts" -> - ?INFO_RESULT(AllowGlobal, [?NS_COMMANDS]); - ?NS_ADMIN ++ "#delete-motd-allhosts" -> - ?INFO_RESULT(AllowGlobal, [?NS_COMMANDS]); + ?NS_ADMIN_s ++ "#announce" -> + ?INFO_RESULT(Allow, [?NS_ADHOC_s]); + ?NS_ADMIN_s ++ "#announce-all" -> + ?INFO_RESULT(Allow, [?NS_ADHOC_s]); + ?NS_ADMIN_s ++ "#set-motd" -> + ?INFO_RESULT(Allow, [?NS_ADHOC_s]); + ?NS_ADMIN_s ++ "#edit-motd" -> + ?INFO_RESULT(Allow, [?NS_ADHOC_s]); + ?NS_ADMIN_s ++ "#delete-motd" -> + ?INFO_RESULT(Allow, [?NS_ADHOC_s]); + ?NS_ADMIN_s ++ "#announce-allhosts" -> + ?INFO_RESULT(AllowGlobal, [?NS_ADHOC_s]); + ?NS_ADMIN_s ++ "#announce-all-allhosts" -> + ?INFO_RESULT(AllowGlobal, [?NS_ADHOC_s]); + ?NS_ADMIN_s ++ "#set-motd-allhosts" -> + ?INFO_RESULT(AllowGlobal, [?NS_ADHOC_s]); + ?NS_ADMIN_s ++ "#edit-motd-allhosts" -> + ?INFO_RESULT(AllowGlobal, [?NS_ADHOC_s]); + ?NS_ADMIN_s ++ "#delete-motd-allhosts" -> + ?INFO_RESULT(AllowGlobal, [?NS_ADHOC_s]); _ -> Acc end @@ -271,21 +274,20 @@ disco_features(Acc, From, #jid{lserver = LServer} = _To, %%------------------------------------------------------------------------- -define(NODE_TO_ITEM(Lang, Server, Node), - {xmlelement, "item", - [{"jid", Server}, - {"node", Node}, - {"name", get_title(Lang, Node)}], - []}). + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = + [#xmlattr{name = 'jid', value = Server}, + #xmlattr{name = 'node', value = Node}, + #xmlattr{name = 'name', value = get_title(Lang, Node)}]}). -define(ITEMS_RESULT(Allow, Items), case Allow of deny -> - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; allow -> {result, Items} end). -disco_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, +disco_items(Acc, From, #jid{ldomain = LServer, domain = Server} = _To, "", Lang) -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> @@ -307,7 +309,7 @@ disco_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, end end; -disco_items(Acc, From, #jid{lserver = LServer} = To, "announce", Lang) -> +disco_items(Acc, From, #jid{ldomain = LServer} = To, "announce", Lang) -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -315,7 +317,7 @@ disco_items(Acc, From, #jid{lserver = LServer} = To, "announce", Lang) -> announce_items(Acc, From, To, Lang) end; -disco_items(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) -> +disco_items(Acc, From, #jid{ldomain = LServer} = _To, Node, _Lang) -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -325,25 +327,25 @@ disco_items(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) -> AccessGlobal = gen_mod:get_module_opt(global, ?MODULE, access, none), AllowGlobal = acl:match_rule(global, AccessGlobal, From), case Node of - ?NS_ADMIN ++ "#announce" -> + ?NS_ADMIN_s ++ "#announce" -> ?ITEMS_RESULT(Allow, []); - ?NS_ADMIN ++ "#announce-all" -> + ?NS_ADMIN_s ++ "#announce-all" -> ?ITEMS_RESULT(Allow, []); - ?NS_ADMIN ++ "#set-motd" -> + ?NS_ADMIN_s ++ "#set-motd" -> ?ITEMS_RESULT(Allow, []); - ?NS_ADMIN ++ "#edit-motd" -> + ?NS_ADMIN_s ++ "#edit-motd" -> ?ITEMS_RESULT(Allow, []); - ?NS_ADMIN ++ "#delete-motd" -> + ?NS_ADMIN_s ++ "#delete-motd" -> ?ITEMS_RESULT(Allow, []); - ?NS_ADMIN ++ "#announce-allhosts" -> + ?NS_ADMIN_s ++ "#announce-allhosts" -> ?ITEMS_RESULT(AllowGlobal, []); - ?NS_ADMIN ++ "#announce-all-allhosts" -> + ?NS_ADMIN_s ++ "#announce-all-allhosts" -> ?ITEMS_RESULT(AllowGlobal, []); - ?NS_ADMIN ++ "#set-motd-allhosts" -> + ?NS_ADMIN_s ++ "#set-motd-allhosts" -> ?ITEMS_RESULT(AllowGlobal, []); - ?NS_ADMIN ++ "#edit-motd-allhosts" -> + ?NS_ADMIN_s ++ "#edit-motd-allhosts" -> ?ITEMS_RESULT(AllowGlobal, []); - ?NS_ADMIN ++ "#delete-motd-allhosts" -> + ?NS_ADMIN_s ++ "#delete-motd-allhosts" -> ?ITEMS_RESULT(AllowGlobal, []); _ -> Acc @@ -352,26 +354,26 @@ disco_items(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) -> %%------------------------------------------------------------------------- -announce_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, Lang) -> +announce_items(Acc, From, #jid{ldomain = LServer, domain = Server} = _To, Lang) -> Access1 = gen_mod:get_module_opt(LServer, ?MODULE, access, none), Nodes1 = case acl:match_rule(LServer, Access1, From) of allow -> - [?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN ++ "#announce"), - ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN ++ "#announce-all"), - ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN ++ "#set-motd"), - ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN ++ "#edit-motd"), - ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN ++ "#delete-motd")]; + [?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#announce"), + ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#announce-all"), + ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#set-motd"), + ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#edit-motd"), + ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#delete-motd")]; deny -> [] end, Access2 = gen_mod:get_module_opt(global, ?MODULE, access, none), Nodes2 = case acl:match_rule(global, Access2, From) of allow -> - [?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN ++ "#announce-allhosts"), - ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN ++ "#announce-all-allhosts"), - ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN ++ "#set-motd-allhosts"), - ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN ++ "#edit-motd-allhosts"), - ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN ++ "#delete-motd-allhosts")]; + [?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#announce-allhosts"), + ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#announce-all-allhosts"), + ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#set-motd-allhosts"), + ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#edit-motd-allhosts"), + ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#delete-motd-allhosts")]; deny -> [] end, @@ -391,13 +393,13 @@ announce_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, Lang) commands_result(Allow, From, To, Request) -> case Allow of deny -> - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; allow -> announce_commands(From, To, Request) end. -announce_commands(Acc, From, #jid{lserver = LServer} = To, +announce_commands(Acc, From, #jid{ldomain = LServer} = To, #adhoc_request{ node = Node} = Request) -> LNode = tokenize(Node), F = fun() -> @@ -453,7 +455,7 @@ announce_commands(From, To, #adhoc_response{status = canceled}); XData == false, ActionIsExecute -> %% User requests form - Elements = generate_adhoc_form(Lang, Node, To#jid.lserver), + Elements = generate_adhoc_form(Lang, Node, To#jid.ldomain), adhoc:produce_response( Request, #adhoc_response{status = executing, @@ -462,26 +464,26 @@ announce_commands(From, To, %% User returns form. case jlib:parse_xdata_submit(XData) of invalid -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; Fields -> handle_adhoc_form(From, To, Request, Fields) end; true -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end. -define(VVALUE(Val), - {xmlelement, "value", [], [{xmlcdata, Val}]}). + #xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Val)}]}). -define(VVALUEL(Val), case Val of "" -> []; _ -> [?VVALUE(Val)] end). -define(TVFIELD(Type, Var, Val), - {xmlelement, "field", [{"type", Type}, - {"var", Var}], + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, + #xmlattr{name = 'var', value = Var}], children = ?VVALUEL(Val)}). --define(HFIELD(), ?TVFIELD("hidden", "FORM_TYPE", ?NS_ADMIN)). +-define(HFIELD(), ?TVFIELD("hidden", "FORM_TYPE", ?NS_ADMIN_s)). generate_adhoc_form(Lang, Node, ServerHost) -> LNode = tokenize(Node), @@ -491,31 +493,29 @@ generate_adhoc_form(Lang, Node, ServerHost) -> true -> {[], []} end, - {xmlelement, "x", - [{"xmlns", ?NS_XDATA}, - {"type", "form"}], + #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = + [#xmlattr{name = 'type', value = "form"}], children = [?HFIELD(), - {xmlelement, "title", [], [{xmlcdata, get_title(Lang, Node)}]}] + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(get_title(Lang, Node))}]}] ++ if (LNode == ?NS_ADMINL("delete-motd")) or (LNode == ?NS_ADMINL("delete-motd-allhosts")) -> - [{xmlelement, "field", - [{"var", "confirm"}, - {"type", "boolean"}, - {"label", translate:translate(Lang, "Really delete message of the day?")}], - [{xmlelement, "value", - [], - [{xmlcdata, "true"}]}]}]; + [#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'var', value = "confirm"}, + #xmlattr{name = 'type', value = "boolean"}, + #xmlattr{name = 'label', value = translate:translate(Lang, "Really delete message of the day?")}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = + [#xmlcdata{cdata = <<"true">>}]}]}]; true -> - [{xmlelement, "field", - [{"var", "subject"}, - {"type", "text-single"}, - {"label", translate:translate(Lang, "Subject")}], + [#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'var', value = "subject"}, + #xmlattr{name = 'type', value = "text-single"}, + #xmlattr{name = 'label', value = translate:translate(Lang, "Subject")}], children = ?VVALUEL(OldSubject)}, - {xmlelement, "field", - [{"var", "body"}, - {"type", "text-multi"}, - {"label", translate:translate(Lang, "Message body")}], + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'var', value = "body"}, + #xmlattr{name = 'type', value = "text-multi"}, + #xmlattr{name = 'label', value = translate:translate(Lang, "Message body")}], children = ?VVALUEL(OldBody)}] end}. @@ -529,7 +529,7 @@ join_lines([], Acc) -> %% Remove last newline lists:flatten(lists:reverse(tl(Acc))). -handle_adhoc_form(From, #jid{lserver = LServer} = To, +handle_adhoc_form(From, #jid{ldomain = LServer} = To, #adhoc_request{lang = Lang, node = Node, sessionid = SessionID}, @@ -560,30 +560,30 @@ handle_adhoc_form(From, #jid{lserver = LServer} = To, node = Node, sessionid = SessionID, status = completed}, - Packet = {xmlelement, "message", [{"type", "normal"}], + Packet = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', attrs = [#xmlattr{name = 'type', value = "normal"}], children = if Subject /= [] -> - [{xmlelement, "subject", [], - [{xmlcdata, Subject}]}]; + [#xmlel{ns = ?NS_JABBER_CLIENT, name = 'subject', children = + [#xmlcdata{cdata = list_to_binary(Subject)}]}]; true -> [] end ++ if Body /= [] -> - [{xmlelement, "body", [], - [{xmlcdata, Body}]}]; + [#xmlel{ns = ?NS_JABBER_CLIENT, name = 'body', children = + [#xmlcdata{cdata = list_to_binary(Body)}]}]; true -> [] end}, Proc = gen_mod:get_module_proc(LServer, ?PROCNAME), case {Node, Body} of - {?NS_ADMIN ++ "#delete-motd", _} -> + {?NS_ADMIN_s ++ "#delete-motd", _} -> if Confirm -> Proc ! {announce_motd_delete, From, To, Packet}, adhoc:produce_response(Response); true -> adhoc:produce_response(Response) end; - {?NS_ADMIN ++ "#delete-motd-allhosts", _} -> + {?NS_ADMIN_s ++ "#delete-motd-allhosts", _} -> if Confirm -> Proc ! {announce_all_hosts_motd_delete, From, To, Packet}, adhoc:produce_response(Response); @@ -593,79 +593,78 @@ handle_adhoc_form(From, #jid{lserver = LServer} = To, {_, []} -> %% An announce message with no body is definitely an operator error. %% Throw an error and give him/her a chance to send message again. - {error, ?ERRT_NOT_ACCEPTABLE( - Lang, - "No body provided for announce message")}; + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'not-acceptable', + {"en", "No body provided for announce message"})}; %% Now send the packet to ?PROCNAME. %% We don't use direct announce_* functions because it %% leads to large delay in response and queries processing - {?NS_ADMIN ++ "#announce", _} -> + {?NS_ADMIN_s ++ "#announce", _} -> Proc ! {announce_online, From, To, Packet}, adhoc:produce_response(Response); - {?NS_ADMIN ++ "#announce-allhosts", _} -> + {?NS_ADMIN_s ++ "#announce-allhosts", _} -> Proc ! {announce_all_hosts_online, From, To, Packet}, adhoc:produce_response(Response); - {?NS_ADMIN ++ "#announce-all", _} -> + {?NS_ADMIN_s ++ "#announce-all", _} -> Proc ! {announce_all, From, To, Packet}, adhoc:produce_response(Response); - {?NS_ADMIN ++ "#announce-all-allhosts", _} -> + {?NS_ADMIN_s ++ "#announce-all-allhosts", _} -> Proc ! {announce_all_hosts_all, From, To, Packet}, adhoc:produce_response(Response); - {?NS_ADMIN ++ "#set-motd", _} -> + {?NS_ADMIN_s ++ "#set-motd", _} -> Proc ! {announce_motd, From, To, Packet}, adhoc:produce_response(Response); - {?NS_ADMIN ++ "#set-motd-allhosts", _} -> + {?NS_ADMIN_s ++ "#set-motd-allhosts", _} -> Proc ! {announce_all_hosts_motd, From, To, Packet}, adhoc:produce_response(Response); - {?NS_ADMIN ++ "#edit-motd", _} -> + {?NS_ADMIN_s ++ "#edit-motd", _} -> Proc ! {announce_motd_update, From, To, Packet}, adhoc:produce_response(Response); - {?NS_ADMIN ++ "#edit-motd-allhosts", _} -> + {?NS_ADMIN_s ++ "#edit-motd-allhosts", _} -> Proc ! {announce_all_hosts_motd_update, From, To, Packet}, adhoc:produce_response(Response); _ -> %% This can't happen, as we haven't registered any other %% command nodes. - {error, ?ERR_INTERNAL_SERVER_ERROR} + {error, 'internal-server-error'} end. get_title(Lang, "announce") -> translate:translate(Lang, "Announcements"); -get_title(Lang, ?NS_ADMIN ++ "#announce-all") -> +get_title(Lang, ?NS_ADMIN_s ++ "#announce-all") -> translate:translate(Lang, "Send announcement to all users"); -get_title(Lang, ?NS_ADMIN ++ "#announce-all-allhosts") -> +get_title(Lang, ?NS_ADMIN_s ++ "#announce-all-allhosts") -> translate:translate(Lang, "Send announcement to all users on all hosts"); -get_title(Lang, ?NS_ADMIN ++ "#announce") -> +get_title(Lang, ?NS_ADMIN_s ++ "#announce") -> translate:translate(Lang, "Send announcement to all online users"); -get_title(Lang, ?NS_ADMIN ++ "#announce-allhosts") -> +get_title(Lang, ?NS_ADMIN_s ++ "#announce-allhosts") -> translate:translate(Lang, "Send announcement to all online users on all hosts"); -get_title(Lang, ?NS_ADMIN ++ "#set-motd") -> +get_title(Lang, ?NS_ADMIN_s ++ "#set-motd") -> translate:translate(Lang, "Set message of the day and send to online users"); -get_title(Lang, ?NS_ADMIN ++ "#set-motd-allhosts") -> +get_title(Lang, ?NS_ADMIN_s ++ "#set-motd-allhosts") -> translate:translate(Lang, "Set message of the day on all hosts and send to online users"); -get_title(Lang, ?NS_ADMIN ++ "#edit-motd") -> +get_title(Lang, ?NS_ADMIN_s ++ "#edit-motd") -> translate:translate(Lang, "Update message of the day (don't send)"); -get_title(Lang, ?NS_ADMIN ++ "#edit-motd-allhosts") -> +get_title(Lang, ?NS_ADMIN_s ++ "#edit-motd-allhosts") -> translate:translate(Lang, "Update message of the day on all hosts (don't send)"); -get_title(Lang, ?NS_ADMIN ++ "#delete-motd") -> +get_title(Lang, ?NS_ADMIN_s ++ "#delete-motd") -> translate:translate(Lang, "Delete message of the day"); -get_title(Lang, ?NS_ADMIN ++ "#delete-motd-allhosts") -> +get_title(Lang, ?NS_ADMIN_s ++ "#delete-motd-allhosts") -> translate:translate(Lang, "Delete message of the day on all hosts"). %%------------------------------------------------------------------------- announce_all(From, To, Packet) -> - Host = To#jid.lserver, + Host = To#jid.ldomain, Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), case acl:match_rule(Host, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Err = exmpp_stanza:reply_with_error(Packet, 'forbidden'), ejabberd_router:route(To, From, Err); allow -> - Local = jlib:make_jid("", To#jid.server, ""), + Local = exmpp_jid:make_jid(To#jid.domain), lists:foreach( fun({User, Server}) -> - Dest = jlib:make_jid(User, Server, ""), + Dest = exmpp_jid:make_jid(User, Server), ejabberd_router:route(Local, Dest, Packet) end, ejabberd_auth:get_vh_registered_users(Host)) end. @@ -674,27 +673,27 @@ announce_all_hosts_all(From, To, Packet) -> Access = gen_mod:get_module_opt(global, ?MODULE, access, none), case acl:match_rule(global, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Err = exmpp_stanza:reply_with_error(Packet, 'forbidden'), ejabberd_router:route(To, From, Err); allow -> - Local = jlib:make_jid("", To#jid.server, ""), + Local = exmpp_jid:make_jid(To#jid.domain), lists:foreach( fun({User, Server}) -> - Dest = jlib:make_jid(User, Server, ""), + Dest = exmpp_jid:make_jid(User, Server), ejabberd_router:route(Local, Dest, Packet) end, ejabberd_auth:dirty_get_registered_users()) end. announce_online(From, To, Packet) -> - Host = To#jid.lserver, + Host = To#jid.ldomain, Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), case acl:match_rule(Host, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Err = exmpp_stanza:reply_with_error(Packet, 'forbidden'), ejabberd_router:route(To, From, Err); allow -> announce_online1(ejabberd_sm:get_vh_session_list(Host), - To#jid.server, + To#jid.domain, Packet) end. @@ -702,28 +701,28 @@ announce_all_hosts_online(From, To, Packet) -> Access = gen_mod:get_module_opt(global, ?MODULE, access, none), case acl:match_rule(global, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Err = exmpp_stanza:reply_with_error(Packet, 'forbidden'), ejabberd_router:route(To, From, Err); allow -> announce_online1(ejabberd_sm:dirty_get_sessions_list(), - To#jid.server, + To#jid.domain, Packet) end. announce_online1(Sessions, Server, Packet) -> - Local = jlib:make_jid("", Server, ""), + Local = exmpp_jid:make_jid(Server), lists:foreach( fun({U, S, R}) -> - Dest = jlib:make_jid(U, S, R), + Dest = exmpp_jid:make_jid(U, S, R), ejabberd_router:route(Local, Dest, Packet) end, Sessions). announce_motd(From, To, Packet) -> - Host = To#jid.lserver, + Host = To#jid.ldomain, Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), case acl:match_rule(Host, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Err = exmpp_stanza:reply_with_error(Packet, 'forbidden'), ejabberd_router:route(To, From, Err); allow -> announce_motd(Host, Packet) @@ -733,7 +732,7 @@ announce_all_hosts_motd(From, To, Packet) -> Access = gen_mod:get_module_opt(global, ?MODULE, access, none), case acl:match_rule(global, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Err = exmpp_stanza:reply_with_error(Packet, 'forbidden'), ejabberd_router:route(To, From, Err); allow -> Hosts = ?MYHOSTS, @@ -753,11 +752,11 @@ announce_motd(Host, Packet) -> mnesia:transaction(F). announce_motd_update(From, To, Packet) -> - Host = To#jid.lserver, + Host = To#jid.ldomain, Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), case acl:match_rule(Host, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Err = exmpp_stanza:reply_with_error(Packet, 'forbidden'), ejabberd_router:route(To, From, Err); allow -> announce_motd_update(Host, Packet) @@ -767,7 +766,7 @@ announce_all_hosts_motd_update(From, To, Packet) -> Access = gen_mod:get_module_opt(global, ?MODULE, access, none), case acl:match_rule(global, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Err = exmpp_stanza:reply_with_error(Packet, 'forbidden'), ejabberd_router:route(To, From, Err); allow -> Hosts = ?MYHOSTS, @@ -782,11 +781,11 @@ announce_motd_update(LServer, Packet) -> mnesia:transaction(F). announce_motd_delete(From, To, Packet) -> - Host = To#jid.lserver, + Host = To#jid.ldomain, Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), case acl:match_rule(Host, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Err = exmpp_stanza:reply_with_error(Packet, 'forbidden'), ejabberd_router:route(To, From, Err); allow -> announce_motd_delete(Host) @@ -796,7 +795,7 @@ announce_all_hosts_motd_delete(From, To, Packet) -> Access = gen_mod:get_module_opt(global, ?MODULE, access, none), case acl:match_rule(global, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Err = exmpp_stanza:reply_with_error(Packet, 'forbidden'), ejabberd_router:route(To, From, Err); allow -> Hosts = ?MYHOSTS, @@ -818,7 +817,7 @@ announce_motd_delete(LServer) -> end, mnesia:transaction(F). -send_motd(#jid{luser = LUser, lserver = LServer} = JID) -> +send_motd(#jid{lnode = LUser, ldomain = LServer} = JID) -> case catch mnesia:dirty_read({motd, LServer}) of [#motd{packet = Packet}] -> US = {LUser, LServer}, @@ -826,7 +825,7 @@ send_motd(#jid{luser = LUser, lserver = LServer} = JID) -> [#motd_users{}] -> ok; _ -> - Local = jlib:make_jid("", LServer, ""), + Local = exmpp_jid:make_jid(LServer), ejabberd_router:route(Local, JID, Packet), F = fun() -> mnesia:write(#motd_users{us = US}) @@ -840,8 +839,8 @@ send_motd(#jid{luser = LUser, lserver = LServer} = JID) -> get_stored_motd(LServer) -> case catch mnesia:dirty_read({motd, LServer}) of [#motd{packet = Packet}] -> - {xml:get_subtag_cdata(Packet, "subject"), - xml:get_subtag_cdata(Packet, "body")}; + {exmpp_xml:get_cdata_as_list(exmpp_xml:get_element_by_name(Packet, 'subject')), + exmpp_xml:get_cdata_as_list(exmpp_xml:get_element_by_name(Packet, 'body'))}; _ -> {"", ""} end. diff --git a/src/mod_configure.erl b/src/mod_configure.erl index e012794dd..c8925277e 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -45,8 +45,10 @@ adhoc_sm_items/4, adhoc_sm_commands/4]). + +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("adhoc.hrl"). -define(T(Lang, Text), translate:translate(Lang, Text)). @@ -54,6 +56,8 @@ %% Copied from ejabberd_sm.erl -record(session, {sid, usr, us, priority, info}). +-define(NS_ADMIN_s, "http://jabber.org/protocol/admin"). + start(Host, _Opts) -> ejabberd_hooks:add(disco_local_items, Host, ?MODULE, get_local_items, 50), ejabberd_hooks:add(disco_local_features, Host, ?MODULE, get_local_features, 50), @@ -78,33 +82,33 @@ stop(Host) -> ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, get_local_identity, 50), ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, get_local_features, 50), ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, get_local_items, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_COMMANDS), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_COMMANDS). + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ADHOC_s), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ADHOC_s). %%%----------------------------------------------------------------------- -define(INFO_IDENTITY(Category, Type, Name, Lang), - [{xmlelement, "identity", - [{"category", Category}, - {"type", Type}, - {"name", ?T(Lang, Name)}], []}]). + [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = + [#xmlattr{name = 'category', value = Category}, + #xmlattr{name = 'type', value = Type}, + #xmlattr{name = 'name', value = ?T(Lang, Name)}]}]). -define(INFO_COMMAND(Name, Lang), ?INFO_IDENTITY("automation", "command-node", Name, Lang)). -define(NODEJID(To, Name, Node), - {xmlelement, "item", - [{"jid", jlib:jid_to_string(To)}, - {"name", ?T(Lang, Name)}, - {"node", Node}], []}). + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_string(To)}, + #xmlattr{name = 'name', value = ?T(Lang, Name)}, + #xmlattr{name = 'node', value = Node}]}). -define(NODE(Name, Node), - {xmlelement, "item", - [{"jid", Server}, - {"name", ?T(Lang, Name)}, - {"node", Node}], []}). + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = + [#xmlattr{name = 'jid', value = Server}, + #xmlattr{name = 'name', value = ?T(Lang, Name)}, + #xmlattr{name = 'node', value = Node}]}). --define(NS_ADMINX(Sub), ?NS_ADMIN++"#"++Sub). +-define(NS_ADMINX(Sub), ?NS_ADMIN_s++"#"++Sub). -define(NS_ADMINL(Sub), ["http:","jabber.org","protocol","admin", Sub]). tokenize(Node) -> string:tokens(Node, "/#"). @@ -172,12 +176,12 @@ get_local_identity(Acc, _From, _To, Node, Lang) -> -define(INFO_RESULT(Allow, Feats), case Allow of deny -> - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; allow -> {result, Feats} end). -get_sm_features(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) -> +get_sm_features(Acc, From, #jid{ldomain = LServer} = _To, Node, _Lang) -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -185,13 +189,13 @@ get_sm_features(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) -> Allow = acl:match_rule(LServer, configure, From), case Node of "config" -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_ADHOC_s]); _ -> Acc end end. -get_local_features(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) -> +get_local_features(Acc, From, #jid{ldomain = LServer} = _To, Node, _Lang) -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -216,29 +220,29 @@ get_local_features(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) -> ["stopped nodes"] -> ?INFO_RESULT(Allow, []); ["running nodes", _ENode] -> - ?INFO_RESULT(Allow, [?NS_STATS]); + ?INFO_RESULT(Allow, [?NS_STATS_s]); ["running nodes", _ENode, "DB"] -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_ADHOC_s]); ["running nodes", _ENode, "modules"] -> ?INFO_RESULT(Allow, []); ["running nodes", _ENode, "modules", _] -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_ADHOC_s]); ["running nodes", _ENode, "backup"] -> ?INFO_RESULT(Allow, []); ["running nodes", _ENode, "backup", _] -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_ADHOC_s]); ["running nodes", _ENode, "import"] -> ?INFO_RESULT(Allow, []); ["running nodes", _ENode, "import", _] -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_ADHOC_s]); ["running nodes", _ENode, "restart"] -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_ADHOC_s]); ["running nodes", _ENode, "shutdown"] -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_ADHOC_s]); ["config", _] -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_ADHOC_s]); ["http:" | _] -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_ADHOC_s]); _ -> Acc end @@ -246,17 +250,17 @@ get_local_features(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) -> %%%----------------------------------------------------------------------- -adhoc_sm_items(Acc, From, #jid{lserver = LServer} = To, Lang) -> +adhoc_sm_items(Acc, From, #jid{ldomain = LServer} = To, Lang) -> case acl:match_rule(LServer, configure, From) of allow -> Items = case Acc of {result, Its} -> Its; empty -> [] end, - Nodes = [{xmlelement, "item", - [{"jid", jlib:jid_to_string(To)}, - {"name", ?T(Lang, "Configuration")}, - {"node", "config"}], []}], + Nodes = [#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_string(To)}, + #xmlattr{name = 'name', value = ?T(Lang, "Configuration")}, + #xmlattr{name = 'node', value = "config"}]}], {result, Items ++ Nodes}; _ -> Acc @@ -265,7 +269,7 @@ adhoc_sm_items(Acc, From, #jid{lserver = LServer} = To, Lang) -> %%%----------------------------------------------------------------------- get_sm_items(Acc, From, - #jid{user = User, server = Server, lserver = LServer} = To, + #jid{node = User, domain = Server, ldomain = LServer} = To, Node, Lang) -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> @@ -283,7 +287,7 @@ get_sm_items(Acc, From, {allow, "config"} -> {result, []}; {_, "config"} -> - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; _ -> Acc end @@ -292,14 +296,14 @@ get_sm_items(Acc, From, get_user_resources(User, Server) -> Rs = ejabberd_sm:get_user_resources(User, Server), lists:map(fun(R) -> - {xmlelement, "item", - [{"jid", User ++ "@" ++ Server ++ "/" ++ R}, - {"name", User}], []} + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_string(User, Server, R)}, + #xmlattr{name = 'name', value = User}]} end, lists:sort(Rs)). %%%----------------------------------------------------------------------- -adhoc_local_items(Acc, From, #jid{lserver = LServer, server = Server} = To, +adhoc_local_items(Acc, From, #jid{ldomain = LServer, domain = Server} = To, Lang) -> case acl:match_rule(LServer, configure, From) of allow -> @@ -311,10 +315,10 @@ adhoc_local_items(Acc, From, #jid{lserver = LServer, server = Server} = To, Nodes = recursively_get_local_items(LServer, "", Server, Lang), Nodes1 = lists:filter( fun(N) -> - Nd = xml:get_tag_attr_s("node", N), + Nd = exmpp_xml:get_attribute(N, 'node'), F = get_local_features([], From, To, Nd, Lang), case F of - {result, [?NS_COMMANDS]} -> + {result, [?NS_ADHOC_s]} -> true; _ -> false @@ -342,8 +346,8 @@ recursively_get_local_items(LServer, Node, Server, Lang) -> Nodes = lists:flatten( lists:map( fun(N) -> - S = xml:get_tag_attr_s("jid", N), - Nd = xml:get_tag_attr_s("node", N), + S = exmpp_xml:get_attribute(N, 'jid'), + Nd = exmpp_xml:get_attribute(N, 'node'), if (S /= Server) or (Nd == "") -> []; true -> @@ -361,7 +365,7 @@ recursively_get_local_items(LServer, Node, Server, Lang) -> Fallback; allow -> case get_local_items(LServer, LNode, - jlib:jid_to_string(To), Lang) of + exmpp_jid:jid_to_string(To), Lang) of {result, Res} -> {result, Res}; {error, Error} -> @@ -369,7 +373,7 @@ recursively_get_local_items(LServer, Node, Server, Lang) -> end end). -get_local_items(Acc, From, #jid{lserver = LServer} = To, "", Lang) -> +get_local_items(Acc, From, #jid{ldomain = LServer} = To, "", Lang) -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -384,7 +388,7 @@ get_local_items(Acc, From, #jid{lserver = LServer} = To, "", Lang) -> {result, Items}; allow -> case get_local_items(LServer, [], - jlib:jid_to_string(To), Lang) of + exmpp_jid:jid_to_string(To), Lang) of {result, Res} -> {result, Items ++ Res}; {error, _Error} -> @@ -393,7 +397,7 @@ get_local_items(Acc, From, #jid{lserver = LServer} = To, "", Lang) -> end end; -get_local_items(Acc, From, #jid{lserver = LServer} = To, Node, Lang) -> +get_local_items(Acc, From, #jid{ldomain = LServer} = To, Node, Lang) -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -402,45 +406,45 @@ get_local_items(Acc, From, #jid{lserver = LServer} = To, Node, Lang) -> Allow = acl:match_rule(LServer, configure, From), case LNode of ["config"] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["user"] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["online users"] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["all users"] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["all users", [$@ | _]] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["outgoing s2s" | _] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["running nodes"] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["stopped nodes"] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["running nodes", _ENode] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["running nodes", _ENode, "DB"] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["running nodes", _ENode, "modules"] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["running nodes", _ENode, "modules", _] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["running nodes", _ENode, "backup"] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["running nodes", _ENode, "backup", _] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["running nodes", _ENode, "import"] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["running nodes", _ENode, "import", _] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["running nodes", _ENode, "restart"] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["running nodes", _ENode, "shutdown"] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ["config", _] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); ?NS_ADMINL(_) -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, 'forbidden'}); _ -> Acc end @@ -493,7 +497,7 @@ get_local_items(Host, ["all users"], _Server, _Lang) -> get_local_items(Host, ["all users", [$@ | Diap]], _Server, _Lang) -> case catch ejabberd_auth:get_vh_registered_users(Host) of {'EXIT', _Reason} -> - ?ERR_INTERNAL_SERVER_ERROR; + {error, 'internal-server-error'}; Users -> SUsers = lists:sort([{S, U} || {U, S} <- Users]), case catch begin @@ -502,13 +506,13 @@ get_local_items(Host, ["all users", [$@ | Diap]], _Server, _Lang) -> N2 = list_to_integer(S2), Sub = lists:sublist(SUsers, N1, N2 - N1 + 1), lists:map(fun({S, U}) -> - {xmlelement, "item", - [{"jid", U ++ "@" ++ S}, - {"name", U ++ "@" ++ S}], []} + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_string(U, S)}, + #xmlattr{name = 'name', value = exmpp_jid:jid_to_string(U, S)}]} end, Sub) end of {'EXIT', _Reason} -> - ?ERR_NOT_ACCEPTABLE; + {error, 'not-acceptable'}; Res -> {result, Res} end @@ -576,7 +580,7 @@ get_local_items(_Host, ["running nodes", _ENode, "shutdown"], _Server, _Lang) -> {result, []}; get_local_items(_Host, _, _Server, _Lang) -> - {error, ?ERR_ITEM_NOT_FOUND}. + {error, 'item-not-found'}. get_online_vh_users(Host) -> @@ -586,9 +590,9 @@ get_online_vh_users(Host) -> USRs -> SURs = lists:sort([{S, U, R} || {U, S, R} <- USRs]), lists:map(fun({S, U, R}) -> - {xmlelement, "item", - [{"jid", U ++ "@" ++ S ++ "/" ++ R}, - {"name", U ++ "@" ++ S}], []} + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_string(U, S, R)}, + #xmlattr{name = 'name', value = exmpp_jid:jid_to_string(U, S)}]} end, SURs) end. @@ -601,9 +605,9 @@ get_all_vh_users(Host) -> case length(SUsers) of N when N =< 100 -> lists:map(fun({S, U}) -> - {xmlelement, "item", - [{"jid", U ++ "@" ++ S}, - {"name", U ++ "@" ++ S}], []} + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_string(U, S)}, + #xmlattr{name = 'name', value = exmpp_jid:jid_to_string(U, S)}]} end, SUsers); N -> NParts = trunc(math:sqrt(N * 0.618)) + 1, @@ -622,10 +626,10 @@ get_all_vh_users(Host) -> FU ++ "@" ++ FS ++ " -- " ++ LU ++ "@" ++ LS, - {xmlelement, "item", - [{"jid", Host}, - {"node", "all users/" ++ Node}, - {"name", Name}], []} + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = + [#xmlattr{name = 'jid', value = Host}, + #xmlattr{name = 'node', value = "all users/" ++ Node}, + #xmlattr{name = 'name', value = Name}]} end, lists:seq(1, N, M)) end end. @@ -640,14 +644,13 @@ get_outgoing_s2s(Host, Lang) -> Host == FH orelse lists:suffix(DotHost, FH)], lists:map( fun(T) -> - {xmlelement, "item", - [{"jid", Host}, - {"node", "outgoing s2s/" ++ T}, - {"name", + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = + [#xmlattr{name = 'jid', value = Host}, + #xmlattr{name = 'node', value = "outgoing s2s/" ++ T}, + #xmlattr{name = 'name', value = lists:flatten( io_lib:format( - ?T(Lang, "To ~s"), [T]))}], - []} + ?T(Lang, "To ~s"), [T]))}]} end, lists:usort(TConns)) end. @@ -658,14 +661,13 @@ get_outgoing_s2s(Host, Lang, To) -> Connections -> lists:map( fun({F, _T}) -> - {xmlelement, "item", - [{"jid", Host}, - {"node", "outgoing s2s/" ++ To ++ "/" ++ F}, - {"name", + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = + [#xmlattr{name = 'jid', value = Host}, + #xmlattr{name = 'node', value = "outgoing s2s/" ++ To ++ "/" ++ F}, + #xmlattr{name = 'name', value = lists:flatten( io_lib:format( - ?T(Lang, "From ~s"), [F]))}], - []} + ?T(Lang, "From ~s"), [F]))}]} end, lists:keysort(1, lists:filter(fun(E) -> element(2, E) == To end, Connections))) @@ -680,11 +682,10 @@ get_running_nodes(Server, _Lang) -> lists:map( fun(N) -> S = atom_to_list(N), - {xmlelement, "item", - [{"jid", Server}, - {"node", "running nodes/" ++ S}, - {"name", S}], - []} + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = + [#xmlattr{name = 'jid', value = Server}, + #xmlattr{name = 'node', value = "running nodes/" ++ S}, + #xmlattr{name = 'name', value = S}]} end, lists:sort(DBNodes)) end. @@ -698,11 +699,10 @@ get_stopped_nodes(_Lang) -> lists:map( fun(N) -> S = atom_to_list(N), - {xmlelement, "item", - [{"jid", ?MYNAME}, - {"node", "stopped nodes/" ++ S}, - {"name", S}], - []} + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = + [#xmlattr{name = 'jid', value = ?MYNAME}, + #xmlattr{name = 'node', value = "stopped nodes/" ++ S}, + #xmlattr{name = 'name', value = S}]} end, lists:sort(DBNodes)) end. @@ -711,12 +711,12 @@ get_stopped_nodes(_Lang) -> -define(COMMANDS_RESULT(Allow, From, To, Request), case Allow of deny -> - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; allow -> adhoc_local_commands(From, To, Request) end). -adhoc_local_commands(Acc, From, #jid{lserver = LServer} = To, +adhoc_local_commands(Acc, From, #jid{ldomain = LServer} = To, #adhoc_request{node = Node} = Request) -> LNode = tokenize(Node), Allow = acl:match_rule(LServer, configure, From), @@ -741,7 +741,7 @@ adhoc_local_commands(Acc, From, #jid{lserver = LServer} = To, Acc end. -adhoc_local_commands(From, #jid{lserver = LServer} = _To, +adhoc_local_commands(From, #jid{ldomain = LServer} = _To, #adhoc_request{lang = Lang, node = Node, sessionid = SessionID, @@ -779,7 +779,7 @@ adhoc_local_commands(From, #jid{lserver = LServer} = _To, %% User returns form. case jlib:parse_xdata_submit(XData) of invalid -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; Fields -> case catch set_form(From, LServer, LNode, Lang, Fields) of {result, Res} -> @@ -790,58 +790,58 @@ adhoc_local_commands(From, #jid{lserver = LServer} = _To, elements = Res, status = completed}); {'EXIT', _} -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; {error, Error} -> {error, Error} end end; true -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end. -define(TVFIELD(Type, Var, Val), - {xmlelement, "field", [{"type", Type}, - {"var", Var}], - [{xmlelement, "value", [], [{xmlcdata, Val}]}]}). --define(HFIELD(), ?TVFIELD("hidden", "FORM_TYPE", ?NS_ADMIN)). + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, + #xmlattr{name = 'var', value = Var}], + children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Val)}]}]}). +-define(HFIELD(), ?TVFIELD("hidden", "FORM_TYPE", ?NS_ADMIN_s)). -define(TLFIELD(Type, Label, Var), - {xmlelement, "field", [{"type", Type}, - {"label", ?T(Lang, Label)}, - {"var", Var}], []}). + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, + #xmlattr{name = 'label', value = ?T(Lang, Label)}, + #xmlattr{name = 'var', value = Var}]}). -define(XFIELD(Type, Label, Var, Val), - {xmlelement, "field", [{"type", Type}, - {"label", ?T(Lang, Label)}, - {"var", Var}], - [{xmlelement, "value", [], [{xmlcdata, Val}]}]}). + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, + #xmlattr{name = 'label', value = ?T(Lang, Label)}, + #xmlattr{name = 'var', value = Var}], + children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Val)}]}]}). -define(XMFIELD(Type, Label, Var, Vals), - {xmlelement, "field", [{"type", Type}, - {"label", ?T(Lang, Label)}, - {"var", Var}], - [{xmlelement, "value", [], [{xmlcdata,Val}]} || Val <- Vals]}). + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, + #xmlattr{name = 'label', value = ?T(Lang, Label)}, + #xmlattr{name = 'var', value = Var}], + children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Val)}]} || Val <- Vals]}). -define(TABLEFIELD(Table, Val), - {xmlelement, "field", [{"type", "list-single"}, - {"label", atom_to_list(Table)}, - {"var", atom_to_list(Table)}], - [{xmlelement, "value", [], [{xmlcdata, atom_to_list(Val)}]}, - {xmlelement, "option", [{"label", + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = "list-single"}, + #xmlattr{name = 'label', value = atom_to_list(Table)}, + #xmlattr{name = 'var', value = atom_to_list(Table)}], + children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(atom_to_list(Val))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = [#xmlattr{name = 'label', value = ?T(Lang, "RAM copy")}], - [{xmlelement, "value", [], [{xmlcdata, "ram_copies"}]}]}, - {xmlelement, "option", [{"label", + children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"ram_copies">>}]}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = [#xmlattr{name = 'label', value = ?T(Lang, "RAM and disc copy")}], - [{xmlelement, "value", [], [{xmlcdata, "disc_copies"}]}]}, - {xmlelement, "option", [{"label", + children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"disc_copies">>}]}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = [#xmlattr{name = 'label', value = ?T(Lang, "Disc only copy")}], - [{xmlelement, "value", [], [{xmlcdata, "disc_only_copies"}]}]}, - {xmlelement, "option", [{"label", + children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"disc_only_copies">>}]}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = [#xmlattr{name = 'label', value = ?T(Lang, "Remote copy")}], - [{xmlelement, "value", [], [{xmlcdata, "unknown"}]}]} + children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"unknown">>}]}]} ]}). @@ -849,24 +849,24 @@ adhoc_local_commands(From, #jid{lserver = LServer} = _To, get_form(_Host, ["running nodes", ENode, "DB"], Lang) -> case search_running_node(ENode) of false -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; Node -> case rpc:call(Node, mnesia, system_info, [tables]) of {badrpc, _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, 'internal-server-error'}; Tables -> STables = lists:sort(Tables), - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, - ?T( + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = + list_to_binary(?T( Lang, "Database Tables Configuration at ") ++ - ENode}]}, - {xmlelement, "instructions", [], - [{xmlcdata, - ?T( - Lang, "Choose storage type of tables")}]} | + ENode)}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Choose storage type of tables"))}]} | lists:map( fun(Table) -> case rpc:call(Node, @@ -886,23 +886,23 @@ get_form(_Host, ["running nodes", ENode, "DB"], Lang) -> get_form(Host, ["running nodes", ENode, "modules", "stop"], Lang) -> case search_running_node(ENode) of false -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; Node -> case rpc:call(Node, gen_mod, loaded_modules, [Host]) of {badrpc, _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, 'internal-server-error'}; Modules -> SModules = lists:sort(Modules), - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, - ?T( - Lang, "Stop Modules at ") ++ ENode}]}, - {xmlelement, "instructions", [], - [{xmlcdata, - ?T( - Lang, "Choose modules to stop")}]} | + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Stop Modules at ") ++ ENode)}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Choose modules to stop"))}]} | lists:map(fun(M) -> S = atom_to_list(M), ?XFIELD("boolean", S, S, "0") @@ -912,104 +912,104 @@ get_form(Host, ["running nodes", ENode, "modules", "stop"], Lang) -> end; get_form(_Host, ["running nodes", ENode, "modules", "start"], Lang) -> - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, - ?T( - Lang, "Start Modules at ") ++ ENode}]}, - {xmlelement, "instructions", [], - [{xmlcdata, - ?T( - Lang, "Enter list of {Module, [Options]}")}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Start Modules at ") ++ ENode)}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Enter list of {Module, [Options]}"))}]}, ?XFIELD("text-multi", "List of modules to start", "modules", "[].") ]}]}; get_form(_Host, ["running nodes", ENode, "backup", "backup"], Lang) -> - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, - ?T( - Lang, "Backup to File at ") ++ ENode}]}, - {xmlelement, "instructions", [], - [{xmlcdata, - ?T( - Lang, "Enter path to backup file")}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Backup to File at ") ++ ENode)}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Enter path to backup file"))}]}, ?XFIELD("text-single", "Path to File", "path", "") ]}]}; get_form(_Host, ["running nodes", ENode, "backup", "restore"], Lang) -> - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, - ?T( - Lang, "Restore Backup from File at ") ++ ENode}]}, - {xmlelement, "instructions", [], - [{xmlcdata, - ?T( - Lang, "Enter path to backup file")}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Restore Backup from File at ") ++ ENode)}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Enter path to backup file"))}]}, ?XFIELD("text-single", "Path to File", "path", "") ]}]}; get_form(_Host, ["running nodes", ENode, "backup", "textfile"], Lang) -> - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, - ?T( - Lang, "Dump Backup to Text File at ") ++ ENode}]}, - {xmlelement, "instructions", [], - [{xmlcdata, - ?T( - Lang, "Enter path to text file")}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Dump Backup to Text File at ") ++ ENode)}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Enter path to text file"))}]}, ?XFIELD("text-single", "Path to File", "path", "") ]}]}; get_form(_Host, ["running nodes", ENode, "import", "file"], Lang) -> - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, - ?T( - Lang, "Import User from File at ") ++ ENode}]}, - {xmlelement, "instructions", [], - [{xmlcdata, - ?T( - Lang, "Enter path to jabberd1.4 spool file")}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Import User from File at ") ++ ENode)}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Enter path to jabberd1.4 spool file"))}]}, ?XFIELD("text-single", "Path to File", "path", "") ]}]}; get_form(_Host, ["running nodes", ENode, "import", "dir"], Lang) -> - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, - ?T( - Lang, "Import Users from Dir at ") ++ ENode}]}, - {xmlelement, "instructions", [], - [{xmlcdata, - ?T( - Lang, "Enter path to jabberd1.4 spool dir")}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Import Users from Dir at ") ++ ENode)}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Enter path to jabberd1.4 spool dir"))}]}, ?XFIELD("text-single", "Path to Dir", "path", "") ]}]}; get_form(_Host, ["running nodes", _ENode, "restart"], Lang) -> Make_option = fun(LabelNum, LabelUnit, Value)-> - {xmlelement, "option", - [{"label", LabelNum ++ ?T(Lang, LabelUnit)}], - [{xmlelement, "value", [], [{xmlcdata, Value}]}]} + #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = + [#xmlattr{name = 'label', value = LabelNum ++ ?T(Lang, LabelUnit)}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Value)}]}]} end, - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, ?T(Lang, "Restart Service")}]}, - {xmlelement, "field", - [{"type", "list-single"}, - {"label", ?T(Lang, "Time delay")}, - {"var", "delay"}], + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary(?T(Lang, "Restart Service"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "list-single"}, + #xmlattr{name = 'label', value = ?T(Lang, "Time delay")}, + #xmlattr{name = 'var', value = "delay"}], children = [Make_option("", "immediately", "1"), Make_option("15 ", "seconds", "15"), Make_option("30 ", "seconds", "30"), @@ -1022,39 +1022,36 @@ get_form(_Host, ["running nodes", _ENode, "restart"], Lang) -> Make_option("10 ", "minutes", "600"), Make_option("15 ", "minutes", "900"), Make_option("30 ", "minutes", "1800"), - {xmlelement, "required", [], []} + #xmlel{ns = ?NS_DATA_FORMS, name = 'required'} ]}, - {xmlelement, "field", - [{"type", "fixed"}, - {"label", ?T(Lang, "Send announcement to all online users on all hosts")}], - []}, - {xmlelement, "field", - [{"var", "subject"}, - {"type", "text-single"}, - {"label", ?T(Lang, "Subject")}], - []}, - {xmlelement, "field", - [{"var", "announcement"}, - {"type", "text-multi"}, - {"label", ?T(Lang, "Message body")}], - []} + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "fixed"}, + #xmlattr{name = 'label', value = ?T(Lang, "Send announcement to all online users on all hosts")}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'var', value = "subject"}, + #xmlattr{name = 'type', value = "text-single"}, + #xmlattr{name = 'label', value = ?T(Lang, "Subject")}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'var', value = "announcement"}, + #xmlattr{name = 'type', value = "text-multi"}, + #xmlattr{name = 'label', value = ?T(Lang, "Message body")}]} ]}]}; get_form(_Host, ["running nodes", _ENode, "shutdown"], Lang) -> Make_option = fun(LabelNum, LabelUnit, Value)-> - {xmlelement, "option", - [{"label", LabelNum ++ ?T(Lang, LabelUnit)}], - [{xmlelement, "value", [], [{xmlcdata, Value}]}]} + #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = + [#xmlattr{name = 'label', value = LabelNum ++ ?T(Lang, LabelUnit)}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Value)}]}]} end, - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, ?T(Lang, "Shut Down Service")}]}, - {xmlelement, "field", - [{"type", "list-single"}, - {"label", ?T(Lang, "Time delay")}, - {"var", "delay"}], + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary(?T(Lang, "Shut Down Service"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "list-single"}, + #xmlattr{name = 'label', value = ?T(Lang, "Time delay")}, + #xmlattr{name = 'var', value = "delay"}], children = [Make_option("", "immediately", "1"), Make_option("15 ", "seconds", "15"), Make_option("30 ", "seconds", "30"), @@ -1067,38 +1064,35 @@ get_form(_Host, ["running nodes", _ENode, "shutdown"], Lang) -> Make_option("10 ", "minutes", "600"), Make_option("15 ", "minutes", "900"), Make_option("30 ", "minutes", "1800"), - {xmlelement, "required", [], []} + #xmlel{ns = ?NS_DATA_FORMS, name = 'required'} ]}, - {xmlelement, "field", - [{"type", "fixed"}, - {"label", ?T(Lang, "Send announcement to all online users on all hosts")}], - []}, - {xmlelement, "field", - [{"var", "subject"}, - {"type", "text-single"}, - {"label", ?T(Lang, "Subject")}], - []}, - {xmlelement, "field", - [{"var", "announcement"}, - {"type", "text-multi"}, - {"label", ?T(Lang, "Message body")}], - []} + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "fixed"}, + #xmlattr{name = 'label', value = ?T(Lang, "Send announcement to all online users on all hosts")}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'var', value = "subject"}, + #xmlattr{name = 'type', value = "text-single"}, + #xmlattr{name = 'label', value = ?T(Lang, "Subject")}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'var', value = "announcement"}, + #xmlattr{name = 'type', value = "text-multi"}, + #xmlattr{name = 'label', value = ?T(Lang, "Message body")}]} ]}]}; get_form(Host, ["config", "acls"], Lang) -> - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, - ?T( - Lang, "Access Control List Configuration")}]}, - {xmlelement, "field", [{"type", "text-multi"}, - {"label", + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Access Control List Configuration"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = "text-multi"}, + #xmlattr{name = 'label', value = ?T( Lang, "Access control lists")}, - {"var", "acls"}], - lists:map(fun(S) -> - {xmlelement, "value", [], [{xmlcdata, S}]} + #xmlattr{name = 'var', value = "acls"}], + children = lists:map(fun(S) -> + #xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(S)}]} end, string:tokens( lists:flatten( @@ -1114,19 +1108,19 @@ get_form(Host, ["config", "acls"], Lang) -> ]}]}; get_form(Host, ["config", "access"], Lang) -> - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, - ?T( - Lang, "Access Configuration")}]}, - {xmlelement, "field", [{"type", "text-multi"}, - {"label", + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Access Configuration"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs =[#xmlattr{name = 'type', value = "text-multi"}, + #xmlattr{name = 'label', value = ?T( Lang, "Access rules")}, - {"var", "access"}], - lists:map(fun(S) -> - {xmlelement, "value", [], [{xmlcdata, S}]} + #xmlattr{name = 'var', value = "access"}], + children = lists:map(fun(S) -> + #xmlel{ns = ?NS_DATA_FORMS, name = 'value', children =[#xmlcdata{cdata = list_to_binary(S)}]} end, string:tokens( lists:flatten( @@ -1142,141 +1136,137 @@ get_form(Host, ["config", "access"], Lang) -> ]}]}; get_form(_Host, ?NS_ADMINL("add-user"), Lang) -> - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, ?T(Lang, "Add User")}]}, - {xmlelement, "field", - [{"type", "jid-single"}, - {"label", ?T(Lang, "Jabber ID")}, - {"var", "accountjid"}], - [{xmlelement, "required", [], []}]}, - {xmlelement, "field", - [{"type", "text-private"}, - {"label", ?T(Lang, "Password")}, - {"var", "password"}], - [{xmlelement, "required", [], []}]}, - {xmlelement, "field", - [{"type", "text-private"}, - {"label", ?T(Lang, "Password Verification")}, - {"var", "password-verify"}], - [{xmlelement, "required", [], []}]} + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary(?T(Lang, "Add User"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "jid-single"}, + #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, + #xmlattr{name = 'var', value = "accountjid"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "text-private"}, + #xmlattr{name = 'label', value = ?T(Lang, "Password")}, + #xmlattr{name = 'var', value = "password"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "text-private"}, + #xmlattr{name = 'label', value = ?T(Lang, "Password Verification")}, + #xmlattr{name = 'var', value = "password-verify"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; get_form(_Host, ?NS_ADMINL("delete-user"), Lang) -> - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, ?T(Lang, "Delete User")}]}, - {xmlelement, "field", - [{"type", "jid-multi"}, - {"label", ?T(Lang, "Jabber ID")}, - {"var", "accountjids"}], - [{xmlelement, "required", [], []}]} + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary(?T(Lang, "Delete User"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "jid-multi"}, + #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, + #xmlattr{name = 'var', value = "accountjids"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; get_form(_Host, ?NS_ADMINL("end-user-session"), Lang) -> - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, ?T(Lang, "End User Session")}]}, - {xmlelement, "field", - [{"type", "jid-single"}, - {"label", ?T(Lang, "Jabber ID")}, - {"var", "accountjid"}], - [{xmlelement, "required", [], []}]} + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary(?T(Lang, "End User Session"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "jid-single"}, + #xmlattr{name = 'label', value = list_to_binary(?T(Lang, "Jabber ID"))}, + #xmlattr{name = 'var', value = "accountjid"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; get_form(_Host, ?NS_ADMINL("get-user-password"), Lang) -> - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, ?T(Lang, "Get User Password")}]}, - {xmlelement, "field", - [{"type", "jid-single"}, - {"label", ?T(Lang, "Jabber ID")}, - {"var", "accountjid"}], - [{xmlelement, "required", [], []}]} + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary(?T(Lang, "Get User Password"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "jid-single"}, + #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, + #xmlattr{name = 'var', value = "accountjid"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; get_form(_Host, ?NS_ADMINL("change-user-password"), Lang) -> - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, ?T(Lang, "Get User Password")}]}, - {xmlelement, "field", - [{"type", "jid-single"}, - {"label", ?T(Lang, "Jabber ID")}, - {"var", "accountjid"}], - [{xmlelement, "required", [], []}]}, - {xmlelement, "field", - [{"type", "text-private"}, - {"label", ?T(Lang, "Password")}, - {"var", "password"}], - [{xmlelement, "required", [], []}]} + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary(?T(Lang, "Get User Password"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "jid-single"}, + #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, + #xmlattr{name = 'var', value = "accountjid"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "text-private"}, + #xmlattr{name = 'label', value = ?T(Lang, "Password")}, + #xmlattr{name = 'var', value = "password"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; get_form(_Host, ?NS_ADMINL("get-user-lastlogin"), Lang) -> - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, ?T(Lang, "Get User Last Login Time")}]}, - {xmlelement, "field", - [{"type", "jid-single"}, - {"label", ?T(Lang, "Jabber ID")}, - {"var", "accountjid"}], - [{xmlelement, "required", [], []}]} + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary(?T(Lang, "Get User Last Login Time"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "jid-single"}, + #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, + #xmlattr{name = 'var', value = "accountjid"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; get_form(_Host, ?NS_ADMINL("user-stats"), Lang) -> - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, ?T(Lang, "Get User Statistics")}]}, - {xmlelement, "field", - [{"type", "jid-single"}, - {"label", ?T(Lang, "Jabber ID")}, - {"var", "accountjid"}], - [{xmlelement, "required", [], []}]} + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary(?T(Lang, "Get User Statistics"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "jid-single"}, + #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, + #xmlattr{name = 'var', value = "accountjid"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; get_form(Host, ?NS_ADMINL("get-registered-users-num"), Lang) -> [Num] = io_lib:format("~p", [ejabberd_auth:get_vh_registered_users_number(Host)]), {result, completed, - [{xmlelement, "x", - [{"xmlns", ?NS_XDATA}], + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, - "field", - [{"type", "jid-single"}, - {"label", ?T(Lang, "Number of registered users")}, - {"var", "registeredusersnum"}], - [{xmlelement, "value", [], [{xmlcdata, Num}]}] + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "jid-single"}, + #xmlattr{name = 'label', value = ?T(Lang, "Number of registered users")}, + #xmlattr{name = 'var', value = "registeredusersnum"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Num)}]}] }]}]}; get_form(Host, ?NS_ADMINL("get-online-users-num"), Lang) -> Num = io_lib:format("~p", [length(ejabberd_sm:get_vh_session_list(Host))]), {result, completed, - [{xmlelement, "x", - [{"xmlns", ?NS_XDATA}], + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, - "field", - [{"type", "jid-single"}, - {"label", ?T(Lang, "Number of online users")}, - {"var", "onlineusersnum"}], - [{xmlelement, "value", [], [{xmlcdata, Num}]}] + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "jid-single"}, + #xmlattr{name = 'label', value = ?T(Lang, "Number of online users")}, + #xmlattr{name = 'var', value = "onlineusersnum"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Num)}]}] }]}]}; get_form(_Host, _, _Lang) -> - {error, ?ERR_SERVICE_UNAVAILABLE}. + {error, 'service-unavailable'}. set_form(_From, _Host, ["running nodes", ENode, "DB"], _Lang, XData) -> case search_running_node(ENode) of false -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; Node -> lists:foreach( fun({SVar, SVals}) -> @@ -1310,7 +1300,7 @@ set_form(_From, _Host, ["running nodes", ENode, "DB"], _Lang, XData) -> set_form(_From, Host, ["running nodes", ENode, "modules", "stop"], _Lang, XData) -> case search_running_node(ENode) of false -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; Node -> lists:foreach( fun({Var, Vals}) -> @@ -1328,11 +1318,11 @@ set_form(_From, Host, ["running nodes", ENode, "modules", "stop"], _Lang, XData) set_form(_From, Host, ["running nodes", ENode, "modules", "start"], _Lang, XData) -> case search_running_node(ENode) of false -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; Node -> case lists:keysearch("modules", 1, XData) of false -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; {value, {_, Strings}} -> String = lists:foldl(fun(S, Res) -> Res ++ S ++ "\n" @@ -1350,13 +1340,13 @@ set_form(_From, Host, ["running nodes", ENode, "modules", "start"], _Lang, XData end, Modules), {result, []}; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end end; @@ -1364,22 +1354,22 @@ set_form(_From, Host, ["running nodes", ENode, "modules", "start"], _Lang, XData set_form(_From, _Host, ["running nodes", ENode, "backup", "backup"], _Lang, XData) -> case search_running_node(ENode) of false -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; Node -> case lists:keysearch("path", 1, XData) of false -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; {value, {_, [String]}} -> case rpc:call(Node, mnesia, backup, [String]) of {badrpc, _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, 'internal-server-error'}; {error, _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, 'internal-server-error'}; _ -> {result, []} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end end; @@ -1387,22 +1377,22 @@ set_form(_From, _Host, ["running nodes", ENode, "backup", "backup"], _Lang, XDat set_form(_From, _Host, ["running nodes", ENode, "backup", "restore"], _Lang, XData) -> case search_running_node(ENode) of false -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; Node -> case lists:keysearch("path", 1, XData) of false -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; {value, {_, [String]}} -> case rpc:call(Node, ejabberd_admin, restore, [String]) of {badrpc, _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, 'internal-server-error'}; {error, _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, 'internal-server-error'}; _ -> {result, []} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end end; @@ -1410,22 +1400,22 @@ set_form(_From, _Host, ["running nodes", ENode, "backup", "restore"], _Lang, XDa set_form(_From, _Host, ["running nodes", ENode, "backup", "textfile"], _Lang, XData) -> case search_running_node(ENode) of false -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; Node -> case lists:keysearch("path", 1, XData) of false -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; {value, {_, [String]}} -> case rpc:call(Node, ejabberd_ctl, dump_to_textfile, [String]) of {badrpc, _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, 'internal-server-error'}; {error, _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, 'internal-server-error'}; _ -> {result, []} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end end; @@ -1433,16 +1423,16 @@ set_form(_From, _Host, ["running nodes", ENode, "backup", "textfile"], _Lang, XD set_form(_From, _Host, ["running nodes", ENode, "import", "file"], _Lang, XData) -> case search_running_node(ENode) of false -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; Node -> case lists:keysearch("path", 1, XData) of false -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; {value, {_, [String]}} -> rpc:call(Node, jd2ejd, import_file, [String]), {result, []}; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end end; @@ -1450,16 +1440,16 @@ set_form(_From, _Host, ["running nodes", ENode, "import", "file"], _Lang, XData) set_form(_From, _Host, ["running nodes", ENode, "import", "dir"], _Lang, XData) -> case search_running_node(ENode) of false -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; Node -> case lists:keysearch("path", 1, XData) of false -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; {value, {_, [String]}} -> rpc:call(Node, jd2ejd, import_dir, [String]), {result, []}; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end end; @@ -1483,16 +1473,16 @@ set_form(_From, Host, ["config", "acls"], _Lang, XData) -> ok -> {result, []}; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; set_form(_From, Host, ["config", "access"], _Lang, XData) -> @@ -1528,25 +1518,25 @@ set_form(_From, Host, ["config", "access"], _Lang, XData) -> {atomic, _} -> {result, []}; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; set_form(_From, _Host, ?NS_ADMINL("add-user"), _Lang, XData) -> AccountString = get_value("accountjid", XData), Password = get_value("password", XData), Password = get_value("password-verify", XData), - AccountJID = jlib:string_to_jid(AccountString), - User = AccountJID#jid.luser, - Server = AccountJID#jid.lserver, + AccountJID = exmpp_jid:string_to_jid(AccountString), + User = AccountJID#jid.lnode, + Server = AccountJID#jid.ldomain, true = lists:member(Server, ?MYHOSTS), ejabberd_auth:try_register(User, Server, Password), {result, []}; @@ -1556,10 +1546,10 @@ set_form(_From, _Host, ?NS_ADMINL("delete-user"), _Lang, XData) -> [_|_] = AccountStringList, ASL2 = lists:map( fun(AccountString) -> - JID = jlib:string_to_jid(AccountString), - [_|_] = JID#jid.luser, - User = JID#jid.luser, - Server = JID#jid.lserver, + JID = exmpp_jid:string_to_jid(AccountString), + [_|_] = JID#jid.lnode, + User = JID#jid.lnode, + Server = JID#jid.ldomain, true = ejabberd_auth:is_user_exists(User, Server), {User, Server} end, @@ -1569,13 +1559,13 @@ set_form(_From, _Host, ?NS_ADMINL("delete-user"), _Lang, XData) -> set_form(_From, _Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> AccountString = get_value("accountjid", XData), - JID = jlib:string_to_jid(AccountString), - [_|_] = JID#jid.luser, - LUser = JID#jid.luser, - LServer = JID#jid.lserver, + JID = exmpp_jid:string_to_jid(AccountString), + [_|_] = JID#jid.lnode, + LUser = JID#jid.lnode, + LServer = JID#jid.ldomain, %% Code copied from ejabberd_sm.erl case JID#jid.lresource of - [] -> + undefined -> SIDs = mnesia:dirty_select(session, [{#session{sid = '$1', usr = {LUser, LServer, '_'}, _ = '_'}, [], ['$1']}]), [Pid ! replaced || {_, Pid} <- SIDs]; @@ -1588,13 +1578,13 @@ set_form(_From, _Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> set_form(_From, _Host, ?NS_ADMINL("get-user-password"), Lang, XData) -> AccountString = get_value("accountjid", XData), - JID = jlib:string_to_jid(AccountString), - [_|_] = JID#jid.luser, - User = JID#jid.luser, - Server = JID#jid.lserver, + JID = exmpp_jid:string_to_jid(AccountString), + [_|_] = JID#jid.lnode, + User = JID#jid.lnode, + Server = JID#jid.ldomain, Password = ejabberd_auth:get_password(User, Server), true = is_list(Password), - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), ?XFIELD("jid-single", "Jabber ID", "accountjid", AccountString), ?XFIELD("text-single", "Password", "password", Password) @@ -1603,20 +1593,20 @@ set_form(_From, _Host, ?NS_ADMINL("get-user-password"), Lang, XData) -> set_form(_From, _Host, ?NS_ADMINL("change-user-password"), _Lang, XData) -> AccountString = get_value("accountjid", XData), Password = get_value("password", XData), - JID = jlib:string_to_jid(AccountString), - [_|_] = JID#jid.luser, - User = JID#jid.luser, - Server = JID#jid.lserver, + JID = exmpp_jid:string_to_jid(AccountString), + [_|_] = JID#jid.lnode, + User = JID#jid.lnode, + Server = JID#jid.ldomain, true = ejabberd_auth:is_user_exists(User, Server), ejabberd_auth:set_password(User, Server, Password), {result, []}; set_form(_From, _Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> AccountString = get_value("accountjid", XData), - JID = jlib:string_to_jid(AccountString), - [_|_] = JID#jid.luser, - User = JID#jid.luser, - Server = JID#jid.lserver, + JID = exmpp_jid:string_to_jid(AccountString), + [_|_] = JID#jid.lnode, + User = JID#jid.lnode, + Server = JID#jid.ldomain, %% Code copied from web/ejabberd_web_admin.erl %% TODO: Update time format to XEP-0202: Entity Time @@ -1642,7 +1632,7 @@ set_form(_From, _Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> _ -> ?T(Lang, "Online") end, - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "result"}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', value = "result"}], children = [?HFIELD(), ?XFIELD("jid-single", "Jabber ID", "accountjid", AccountString), ?XFIELD("text-single", "Last login", "lastlogin", FLast) @@ -1650,10 +1640,10 @@ set_form(_From, _Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> set_form(_From, _Host, ?NS_ADMINL("user-stats"), Lang, XData) -> AccountString = get_value("accountjid", XData), - JID = jlib:string_to_jid(AccountString), - [_|_] = JID#jid.luser, - User = JID#jid.luser, - Server = JID#jid.lserver, + JID = exmpp_jid:string_to_jid(AccountString), + [_|_] = JID#jid.lnode, + User = JID#jid.lnode, + Server = JID#jid.ldomain, Resources = ejabberd_sm:get_user_resources(User, Server), IPs1 = [ejabberd_sm:get_user_ip(User, Server, Resource) || Resource <- Resources], @@ -1662,7 +1652,7 @@ set_form(_From, _Host, ?NS_ADMINL("user-stats"), Lang, XData) -> Items = ejabberd_hooks:run_fold(roster_get, Server, [], [{User, Server}]), Rostersize = integer_to_list(erlang:length(Items)), - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), ?XFIELD("jid-single", "Jabber ID", "accountjid", AccountString), ?XFIELD("text-single", "Roster size", "rostersize", Rostersize), @@ -1671,7 +1661,7 @@ set_form(_From, _Host, ?NS_ADMINL("user-stats"), Lang, XData) -> ]}]}; set_form(_From, _Host, _, _Lang, _XData) -> - {error, ?ERR_SERVICE_UNAVAILABLE}. + {error, 'service-unavailable'}. get_value(Field, XData) -> hd(get_values(Field, XData)). @@ -1697,13 +1687,13 @@ stop_node(From, Host, ENode, Action, XData) -> Delay = list_to_integer(get_value("delay", XData)), Subject = case get_value("subject", XData) of [] -> []; - S -> [{xmlelement, "field", [{"var","subject"}], - [{xmlelement,"value",[],[{xmlcdata,S}]}]}] + S -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'var', value = "subject"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(S)}]}]}] end, Announcement = case get_values("announcement", XData) of [] -> []; - As -> [{xmlelement, "field", [{"var","body"}], - [{xmlelement,"value",[],[{xmlcdata,Line}]} || Line <- As] }] + As -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'var', value = "body"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Line)}]} || Line <- As] }] end, case Subject ++ Announcement of [] -> ok; @@ -1711,14 +1701,14 @@ stop_node(From, Host, ENode, Action, XData) -> Request = #adhoc_request{ node = ?NS_ADMINX("announce-allhosts"), action = "complete", - xdata = {xmlelement, "x", - [{"xmlns","jabber:x:data"},{"type","submit"}], + xdata = #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = + [#xmlattr{name = 'type', value = "submit"}], children = SubEls}, - others= [{xmlelement, "x", - [{"xmlns","jabber:x:data"},{"type","submit"}], + others= [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = + [#xmlattr{name = 'type', value = "submit"}], children = SubEls}] }, - To = jlib:make_jid("", Host, ""), + To = exmpp_jid:make_jid(Host), mod_announce:announce_commands(empty, From, To, Request) end, Time = timer:seconds(Delay), @@ -1740,14 +1730,14 @@ get_last_info(User, Server) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% adhoc_sm_commands(_Acc, From, - #jid{user = User, server = Server, lserver = LServer} = _To, + #jid{node = User, domain = Server, ldomain = LServer} = _To, #adhoc_request{lang = Lang, node = "config", action = Action, xdata = XData} = Request) -> case acl:match_rule(LServer, configure, From) of deny -> - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; allow -> %% If the "action" attribute is not present, it is %% understood as "execute". If there was no @@ -1775,12 +1765,12 @@ adhoc_sm_commands(_Acc, From, %% User returns form. case jlib:parse_xdata_submit(XData) of invalid -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; Fields -> set_sm_form(User, Server, "config", Request, Fields) end; true -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end end; @@ -1788,30 +1778,30 @@ adhoc_sm_commands(Acc, _From, _To, _Request) -> Acc. get_sm_form(User, Server, "config", Lang) -> - {result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - {xmlelement, "title", [], - [{xmlcdata, - ?T( - Lang, "Administration of ") ++ User}]}, - {xmlelement, "field", - [{"type", "list-single"}, - {"label", ?T(Lang, "Action on user")}, - {"var", "action"}], - [{xmlelement, "value", [], [{xmlcdata, "edit"}]}, - {xmlelement, "option", - [{"label", ?T(Lang, "Edit Properties")}], - [{xmlelement, "value", [], [{xmlcdata, "edit"}]}]}, - {xmlelement, "option", - [{"label", ?T(Lang, "Remove User")}], - [{xmlelement, "value", [], [{xmlcdata, "remove"}]}]} + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = + list_to_binary(?T( + Lang, "Administration of ") ++ User)}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'type', value = "list-single"}, + #xmlattr{name = 'label', value = ?T(Lang, "Action on user")}, + #xmlattr{name = 'var', value = "action"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"edit">>}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = + [#xmlattr{name = 'label', value = ?T(Lang, "Edit Properties")}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"edit">>}]}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = + [#xmlattr{name = 'label', value = ?T(Lang, "Remove User")}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"remove">>}]}]} ]}, ?XFIELD("text-private", "Password", "password", ejabberd_auth:get_password_s(User, Server)) ]}]}; get_sm_form(_User, _Server, _Node, _Lang) -> - {error, ?ERR_SERVICE_UNAVAILABLE}. + {error, 'service-unavailable'}. set_sm_form(User, Server, "config", @@ -1829,17 +1819,17 @@ set_sm_form(User, Server, "config", ejabberd_auth:set_password(User, Server, Password), adhoc:produce_response(Response); _ -> - {error, ?ERR_NOT_ACCEPTABLE} + {error, 'not-acceptable'} end; {value, {_, ["remove"]}} -> catch ejabberd_auth:remove_user(User, Server), adhoc:produce_response(Response); _ -> - {error, ?ERR_NOT_ACCEPTABLE} + {error, 'not-acceptable'} end; set_sm_form(_User, _Server, _Node, _Request, _Fields) -> - {error, ?ERR_SERVICE_UNAVAILABLE}. + {error, 'service-unavailable'}. From d9a493561b8cf0f186ab7502e97c3e1ad1fee81c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 6 Aug 2008 13:44:58 +0000 Subject: [PATCH 053/582] Convert to exmpp. SVN Revision: 1513 --- ChangeLog | 6 ++ src/gen_iq_handler.erl | 4 + src/mod_configure2.erl | 81 +++++++++------- src/mod_echo.erl | 21 ++-- src/mod_last.erl | 68 ++++++------- src/mod_last_odbc.erl | 71 +++++++------- src/mod_offline.erl | 205 +++++++++++++++++++++------------------ src/mod_offline_odbc.erl | 188 +++++++++++++++++------------------ 8 files changed, 330 insertions(+), 314 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8e9dce87a..0ef9fe049 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-08-06 Jean-Sébastien Pédron + + * src/mod_offline.erl, src/mod_offline_odbc.erl, src/mod_echo.erl, + src/mod_last.erl, src/mod_configure2.erl, src/mod_last_odbc.erl, + src/gen_iq_handler.erl: Convert to exmpp. + 2008-07-25 Jean-Sébastien Pédron * src/adhoc.erl, src/mod_configure.erl, src/mod_announce.erl, diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index 33d445942..97a24efbb 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -63,7 +63,11 @@ mod_annouce, mod_caps, mod_configure, + mod_configure2, mod_disco, + mod_echo, + mod_offline, + mod_offline_odbc, mod_roster, mod_vcard ]). diff --git a/src/mod_configure2.erl b/src/mod_configure2.erl index db84c43b7..2b6874112 100644 --- a/src/mod_configure2.erl +++ b/src/mod_configure2.erl @@ -33,30 +33,36 @@ stop/1, process_local_iq/3]). --include("ejabberd.hrl"). --include("jlib.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). --define(NS_ECONFIGURE, "http://ejabberd.jabberstudio.org/protocol/configure"). +-include("ejabberd.hrl"). + +% XXX The namespace used in this module isn't known by Exmpp: if the +% known list isn't updated by Ejabberd, some element names will be +% represented with strings. +% XXX This module currently supposed that they'll be atoms. + +-define(NS_ECONFIGURE, 'http://ejabberd.jabberstudio.org/protocol/configure'). +-define(NS_ECONFIGURE_s, "http://ejabberd.jabberstudio.org/protocol/configure"). start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE_s, ?MODULE, process_local_iq, IQDisc), ok. stop(Host) -> - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE). + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE_s). -process_local_iq(From, To, #iq{type = Type, lang = _Lang, sub_el = SubEl} = IQ) -> - case acl:match_rule(To#jid.lserver, configure, From) of +process_local_iq(From, To, IQ) -> + case acl:match_rule(To#jid.ldomain, configure, From) of deny -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + exmpp_iq:error(IQ, 'not-allowed'); allow -> - case Type of + case exmpp_iq:get_type(IQ) of set -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_FEATURE_NOT_IMPLEMENTED]}; + exmpp_iq:error(IQ, 'feature-not-implemented'); %%case xml:get_tag_attr_s("type", SubEl) of %% "cancel" -> %% IQ#iq{type = result, @@ -90,56 +96,57 @@ process_local_iq(From, To, #iq{type = Type, lang = _Lang, sub_el = SubEl} = IQ) %% sub_el = [SubEl, ?ERR_NOT_ALLOWED]} %%end; get -> - case process_get(SubEl) of + case process_get(IQ#xmlel.children) of {result, Res} -> - IQ#iq{type = result, sub_el = [Res]}; + exmpp_iq:result(IQ, Res); {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]} + exmpp_iq:error(IQ, Error) end end end. -process_get({xmlelement, "info", _Attrs, _SubEls}) -> +process_get(#xmlel{ns = ?NS_ECONFIGURE, name = 'info'}) -> S2SConns = ejabberd_s2s:dirty_get_connections(), TConns = lists:usort([element(2, C) || C <- S2SConns]), - Attrs = [{"registered-users", + Attrs = [#xmlattr{name = 'registered-users', value = integer_to_list(mnesia:table_info(passwd, size))}, - {"online-users", + #xmlattr{name = 'online-users', value = integer_to_list(mnesia:table_info(presence, size))}, - {"running-nodes", + #xmlattr{name = 'running-nodes', value = integer_to_list(length(mnesia:system_info(running_db_nodes)))}, - {"stopped-nodes", + #xmlattr{name = 'stopped-nodes', value = integer_to_list( length(lists:usort(mnesia:system_info(db_nodes) ++ mnesia:system_info(extra_db_nodes)) -- mnesia:system_info(running_db_nodes)))}, - {"outgoing-s2s-servers", integer_to_list(length(TConns))}], - {result, {xmlelement, "info", - [{"xmlns", ?NS_ECONFIGURE} | Attrs], []}}; -process_get({xmlelement, "welcome-message", Attrs, _SubEls}) -> + #xmlattr{name = 'outgoing-s2s-servers', value = + integer_to_list(length(TConns))}], + {result, #xmlel{ns = ?NS_ECONFIGURE, name = 'info', attrs = Attrs}}; +process_get(#xmlel{ns = ?NS_ECONFIGURE, name = 'welcome-message', attrs = Attrs}) -> {Subj, Body} = case ejabberd_config:get_local_option(welcome_message) of {_Subj, _Body} = SB -> SB; _ -> {"", ""} end, - {result, {xmlelement, "welcome-message", Attrs, - [{xmlelement, "subject", [], [{xmlcdata, Subj}]}, - {xmlelement, "body", [], [{xmlcdata, Body}]}]}}; -process_get({xmlelement, "registration-watchers", Attrs, _SubEls}) -> + {result, #xmlel{ns = ?NS_ECONFIGURE, name = 'welcome-message', + attrs = Attrs, children = + [#xmlel{ns = ?NS_ECONFIGURE, name = 'subject', children = [#xmlcdata{cdata = list_to_binary(Subj)}]}, + #xmlel{ns = ?NS_ECONFIGURE, name = 'body', children = [#xmlcdata{cdata = list_to_binary(Body)}]}]}}; +process_get(#xmlel{ns = ?NS_ECONFIGURE, name = 'registration-watchers', attrs = Attrs}) -> SubEls = case ejabberd_config:get_local_option(registration_watchers) of JIDs when is_list(JIDs) -> lists:map(fun(JID) -> - {xmlelement, "jid", [], [{xmlcdata, JID}]} + #xmlel{ns = ?NS_ECONFIGURE, name = 'jid', children = [#xmlcdata{cdata = list_to_binary(JID)}]} end, JIDs); _ -> [] end, - {result, {xmlelement, "registration_watchers", Attrs, SubEls}}; -process_get({xmlelement, "acls", Attrs, _SubEls}) -> + {result, #xmlel{ns = ?NS_ECONFIGURE, name = 'registration_watchers', attrs = Attrs, children = SubEls}}; +process_get(#xmlel{ns = ?NS_ECONFIGURE, name = 'acls', attrs = Attrs}) -> Str = lists:flatten(io_lib:format("~p.", [ets:tab2list(acl)])), - {result, {xmlelement, "acls", Attrs, [{xmlcdata, Str}]}}; -process_get({xmlelement, "access", Attrs, _SubEls}) -> + {result, #xmlel{ns = ?NS_ECONFIGURE, name = 'acls', attrs = Attrs, children = [#xmlcdata{cdata = list_to_binary(Str)}]}}; +process_get(#xmlel{ns = ?NS_ECONFIGURE, name = 'access', attrs = Attrs}) -> Str = lists:flatten( io_lib:format( @@ -149,22 +156,22 @@ process_get({xmlelement, "access", Attrs, _SubEls}) -> [], [{{access, '$1', '$2'}}]}]) ])), - {result, {xmlelement, "access", Attrs, [{xmlcdata, Str}]}}; -process_get({xmlelement, "last", Attrs, _SubEls}) -> + {result, #xmlel{ns = ?NS_ECONFIGURE, name = 'access', attrs = Attrs, children = [#xmlcdata{cdata = list_to_binary(Str)}]}}; +process_get(#xmlel{ns = ?NS_ECONFIGURE, name = 'last', attrs = Attrs}) -> case catch mnesia:dirty_select( last_activity, [{{last_activity, '_', '$1', '_'}, [], ['$1']}]) of {'EXIT', _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, 'internal-server-error'}; Vals -> {MegaSecs, Secs, _MicroSecs} = now(), TimeStamp = MegaSecs * 1000000 + Secs, Str = lists:flatten( lists:append( [[integer_to_list(TimeStamp - V), " "] || V <- Vals])), - {result, {xmlelement, "last", Attrs, [{xmlcdata, Str}]}} + {result, #xmlel{ns = ?NS_ECONFIGURE, name = 'last', attrs = Attrs, children = [#xmlcdata{cdata = list_to_binary(Str)}]}} end; %%process_get({xmlelement, Name, Attrs, SubEls}) -> %% {result, }; process_get(_) -> - {error, ?ERR_BAD_REQUEST}. + {error, 'bad-request'}. diff --git a/src/mod_echo.erl b/src/mod_echo.erl index 22875adcd..f2540081c 100644 --- a/src/mod_echo.erl +++ b/src/mod_echo.erl @@ -37,8 +37,9 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -record(state, {host}). @@ -117,8 +118,8 @@ handle_cast(_Msg, State) -> %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- handle_info({route, From, To, Packet}, State) -> - Packet2 = case From#jid.user of - "" -> jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST); + Packet2 = case From#jid.node of + <<>> -> exmpp_stanza:reply_with_error(Packet, 'bad-request'); _ -> Packet end, do_client_version(disabled, To, From), % Put 'enabled' to enable it @@ -171,16 +172,16 @@ code_change(_OldVsn, State, _Extra) -> do_client_version(disabled, _From, _To) -> ok; do_client_version(enabled, From, To) -> - ToS = jlib:jid_to_string(To), %% It is important to identify this process and packet Random_resource = integer_to_list(random:uniform(100000)), From2 = From#jid{resource = Random_resource, lresource = Random_resource}, %% Build an iq:query request - Packet = {xmlelement, "iq", - [{"to", ToS}, {"type", "get"}], - [{xmlelement, "query", [{"xmlns", ?NS_VERSION}], []}]}, + Request = #xmlel{ns = ?NS_SOFT_VERSION, name = 'query'}, + Packet = exmpp_stanza:set_recipient( + exmpp_iq:get(?NS_JABBER_CLIENT, Request), + To), %% Send the request ejabberd_router:route(From2, To, Packet), @@ -189,15 +190,15 @@ do_client_version(enabled, From, To) -> %% It is very important to only accept a packet which is the %% response to the request that he sent Els = receive {route, To, From2, IQ} -> - {xmlelement, "query", _, List} = xml:get_subtag(IQ, "query"), + #xmlel{ns = ?NS_SOFT_VERSION, name = 'query', children = List} = exmpp_iq:get_payload(IQ), List after 5000 -> % Timeout in miliseconds: 5 seconds [] end, - Values = [{Name, Value} || {xmlelement,Name,[],[{xmlcdata,Value}]} <- Els], + Values = [{Name, binary_to_list(Value)} || #xmlel{name = Name, children = [#xmlcdata{cdata = Value}]} <- Els], %% Print in log Values_string1 = [io_lib:format("~n~s: ~p", [N, V]) || {N, V} <- Values], Values_string2 = lists:concat(Values_string1), - ?INFO_MSG("Information of the client: ~s~s", [ToS, Values_string2]). + ?INFO_MSG("Information of the client: ~s~s", [exmpp_jid:jid_to_string(To), Values_string2]). diff --git a/src/mod_last.erl b/src/mod_last.erl index 3ed5964c7..dee915f86 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -38,8 +38,9 @@ get_last_info/2, remove_user/2]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("mod_privacy.hrl"). -record(last_activity, {us, timestamp, status}). @@ -51,9 +52,9 @@ start(Host, Opts) -> [{disc_copies, [node()]}, {attributes, record_info(fields, last_activity)}]), update_table(), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY_s, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY_s, ?MODULE, process_sm_iq, IQDisc), ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), @@ -65,30 +66,28 @@ stop(Host) -> ?MODULE, remove_user, 50), ejabberd_hooks:delete(unset_presence_hook, Host, ?MODULE, on_presence_update, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST). + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY_s), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY_s). -process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) -> - case Type of +process_local_iq(_From, _To, IQ) -> + case exmpp_iq:get_type(IQ) of set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + exmpp_iq:error(IQ, 'not-allowed'); get -> Sec = trunc(element(1, erlang:statistics(wall_clock))/1000), - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_LAST}, - {"seconds", integer_to_list(Sec)}], - []}]} + Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = + [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}]}, + exmpp_iq:result(IQ, Response) end. -process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> - case Type of +process_sm_iq(From, To, IQ) -> + case exmpp_iq:get_type(IQ) of set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + exmpp_iq:error(IQ, 'not-allowed'); get -> - User = To#jid.luser, - Server = To#jid.lserver, + User = To#jid.lnode, + Server = To#jid.ldomain, {Subscription, _Groups} = ejabberd_hooks:run_fold( roster_get_jid_info, Server, @@ -104,36 +103,33 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> allow, [User, Server, UserListRecord, {From, To, - {xmlelement, "presence", [], []}}, + exmpp_presence:available()}, out]) of allow -> - get_last(IQ, SubEl, User, Server); + get_last(IQ, User, Server); deny -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_NOT_ALLOWED]} + exmpp_iq:error(IQ, 'not-allowed') end; true -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_NOT_ALLOWED]} + exmpp_iq:error(IQ, 'not-allowed') end end. %% TODO: This function could use get_last_info/2 -get_last(IQ, SubEl, LUser, LServer) -> +get_last(IQ, LUser, LServer) -> case catch mnesia:dirty_read(last_activity, {LUser, LServer}) of {'EXIT', _Reason} -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}; + exmpp_iq:error(IQ, 'internal-server-error'); [] -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]}; + exmpp_iq:error(IQ, 'service-unavailable'); [#last_activity{timestamp = TimeStamp, status = Status}] -> {MegaSecs, Secs, _MicroSecs} = now(), TimeStamp2 = MegaSecs * 1000000 + Secs, Sec = TimeStamp2 - TimeStamp, - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_LAST}, - {"seconds", integer_to_list(Sec)}], - [{xmlcdata, Status}]}]} + Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', + attrs = [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}], + children = [#xmlcdata{cdata = list_to_binary(Status)}]}, + exmpp_iq:result(IQ, Response) end. @@ -144,8 +140,8 @@ on_presence_update(User, Server, _Resource, Status) -> store_last_info(User, Server, TimeStamp, Status). store_last_info(User, Server, TimeStamp, Status) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, F = fun() -> mnesia:write(#last_activity{us = US, @@ -166,8 +162,8 @@ get_last_info(LUser, LServer) -> end. remove_user(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, F = fun() -> mnesia:delete({last_activity, US}) diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 053876766..76489b4c0 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -38,15 +38,16 @@ get_last_info/2, remove_user/2]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("mod_privacy.hrl"). start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY_s, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY_s, ?MODULE, process_sm_iq, IQDisc), ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), @@ -58,29 +59,27 @@ stop(Host) -> ?MODULE, remove_user, 50), ejabberd_hooks:delete(unset_presence_hook, Host, ?MODULE, on_presence_update, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST). + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY_s), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY_s). -process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) -> - case Type of +process_local_iq(_From, _To, IQ) -> + case exmpp_iq:get_type(IQ) of set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + exmpp_iq:error(IQ, 'not-allowed'); get -> Sec = trunc(element(1, erlang:statistics(wall_clock))/1000), - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_LAST}, - {"seconds", integer_to_list(Sec)}], - []}]} + Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = + [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}]}, + exmpp_iq:result(IQ, Response) end. -process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> - case Type of +process_sm_iq(From, To, IQ) -> + case exmpp_iq:get_type(IQ) of set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + exmpp_iq:error(IQ, 'not-allowed'); get -> - User = To#jid.luser, - Server = To#jid.lserver, + User = To#jid.lnode, + Server = To#jid.ldomain, {Subscription, _Groups} = ejabberd_hooks:run_fold( roster_get_jid_info, Server, @@ -96,42 +95,38 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> allow, [User, Server, UserListRecord, {From, To, - {xmlelement, "presence", [], []}}, + exmpp_presence:available()}, out]) of allow -> - get_last(IQ, SubEl, User, Server); + get_last(IQ, User, Server); deny -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_NOT_ALLOWED]} + exmpp_iq:error(IQ, 'not-allowed') end; true -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_NOT_ALLOWED]} + exmpp_iq:error(IQ, 'not-allowed') end end. %% TODO: This function could use get_last_info/2 -get_last(IQ, SubEl, LUser, LServer) -> +get_last(IQ, LUser, LServer) -> Username = ejabberd_odbc:escape(LUser), case catch odbc_queries:get_last(LServer, Username) of {'EXIT', _Reason} -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}; + exmpp_iq:error(IQ, 'internal-server-error'); {selected, ["seconds","state"], []} -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]}; + exmpp_iq:error(IQ, 'service-unavailable'); {selected, ["seconds","state"], [{STimeStamp, Status}]} -> case catch list_to_integer(STimeStamp) of TimeStamp when is_integer(TimeStamp) -> {MegaSecs, Secs, _MicroSecs} = now(), TimeStamp2 = MegaSecs * 1000000 + Secs, Sec = TimeStamp2 - TimeStamp, - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_LAST}, - {"seconds", integer_to_list(Sec)}], - [{xmlcdata, Status}]}]}; + Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', + attrs = [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}], + children = [#xmlcdata{cdata = list_to_binary(Status)}]}, + exmpp_iq:result(IQ, Response); _ -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]} + exmpp_iq:error(IQ, 'internal-server-error') end end. @@ -141,8 +136,8 @@ on_presence_update(User, Server, _Resource, Status) -> store_last_info(User, Server, TimeStamp, Status). store_last_info(User, Server, TimeStamp, Status) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), Username = ejabberd_odbc:escape(LUser), Seconds = ejabberd_odbc:escape(integer_to_list(TimeStamp)), State = ejabberd_odbc:escape(Status), @@ -166,7 +161,7 @@ get_last_info(LUser, LServer) -> end. remove_user(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), Username = ejabberd_odbc:escape(LUser), odbc_queries:del_last(LServer, Username). diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 3a751c328..283d68607 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -41,8 +41,9 @@ webadmin_page/3, webadmin_user/4]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("web/ejabberd_http.hrl"). -include("web/ejabberd_web_admin.hrl"). @@ -51,6 +52,11 @@ -define(PROCNAME, ejabberd_offline). -define(OFFLINE_TABLE_LOCK_THRESHOLD, 1000). +% These are the namespace already declared by the stream opening. This is +% used at serialization time. +-define(DEFAULT_NS, ?NS_JABBER_CLIENT). +-define(PREFIXED_NS, [{?NS_XMPP, ?NS_XMPP_pfx}]). + start(Host, Opts) -> mnesia:create_table(offline_msg, [{disc_only_copies, [node()]}, @@ -142,23 +148,25 @@ stop(Host) -> {wait, Proc}. store_packet(From, To, Packet) -> - Type = xml:get_tag_attr_s("type", Packet), + Type = exmpp_stanza:get_type(Packet), if (Type /= "error") and (Type /= "groupchat") and (Type /= "headline") -> case check_event(From, To, Packet) of true -> - #jid{luser = LUser, lserver = LServer} = To, + #jid{lnode = LUser, ldomain = LServer} = To, TimeStamp = now(), - {xmlelement, _Name, _Attrs, Els} = Packet, - Expire = find_x_expire(TimeStamp, Els), - gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME) ! + Expire = find_x_expire(TimeStamp, Packet#xmlel.children), + % XXX OLD FORMAT: Packet is stored in the old format. + PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, + [?DEFAULT_NS], ?PREFIXED_NS), + gen_mod:get_module_proc(To#jid.ldomain, ?PROCNAME) ! #offline_msg{us = {LUser, LServer}, timestamp = TimeStamp, expire = Expire, from = From, to = To, - packet = Packet}, + packet = PacketOld}, stop; _ -> ok @@ -168,31 +176,28 @@ store_packet(From, To, Packet) -> end. check_event(From, To, Packet) -> - {xmlelement, Name, Attrs, Els} = Packet, - case find_x_event(Els) of + case find_x_event(Packet#xmlel.children) of false -> true; El -> - case xml:get_subtag(El, "id") of - false -> - case xml:get_subtag(El, "offline") of - false -> + case exmpp_xml:get_element(El, 'id') of + undefined -> + case exmpp_xml:get_element(El, 'offline') of + undefined -> true; _ -> - ID = case xml:get_tag_attr_s("id", Packet) of - "" -> - {xmlelement, "id", [], []}; + ID = case exmpp_stanza:get_id(Packet) of + undefined -> + #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'id'}; S -> - {xmlelement, "id", [], - [{xmlcdata, S}]} + #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'id', + children = [#xmlcdata{cdata = + list_to_binary(S)}]} end, + X = #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'x', children = + [ID, #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'offline'}]}, ejabberd_router:route( - To, From, {xmlelement, Name, Attrs, - [{xmlelement, "x", - [{"xmlns", ?NS_EVENT}], - [ID, - {xmlelement, "offline", [], []}]}] - }), + To, From, exmpp_xml:set_children(Packet, [X])), true end; _ -> @@ -202,44 +207,34 @@ check_event(From, To, Packet) -> find_x_event([]) -> false; -find_x_event([{xmlcdata, _} | Els]) -> - find_x_event(Els); -find_x_event([El | Els]) -> - case xml:get_tag_attr_s("xmlns", El) of - ?NS_EVENT -> - El; - _ -> - find_x_event(Els) - end. +find_x_event([#xmlel{ns = ?NS_MESSAGE_EVENT} = El | _Els]) -> + El; +find_x_event([_ | Els]) -> + find_x_event(Els). find_x_expire(_, []) -> never; -find_x_expire(TimeStamp, [{xmlcdata, _} | Els]) -> - find_x_expire(TimeStamp, Els); -find_x_expire(TimeStamp, [El | Els]) -> - case xml:get_tag_attr_s("xmlns", El) of - ?NS_EXPIRE -> - Val = xml:get_tag_attr_s("seconds", El), - case catch list_to_integer(Val) of - {'EXIT', _} -> - never; - Int when Int > 0 -> - {MegaSecs, Secs, MicroSecs} = TimeStamp, - S = MegaSecs * 1000000 + Secs + Int, - MegaSecs1 = S div 1000000, - Secs1 = S rem 1000000, - {MegaSecs1, Secs1, MicroSecs}; - _ -> - never - end; +find_x_expire(TimeStamp, [#xmlel{ns = ?NS_MESSAGE_EXPIRE} = El | _Els]) -> + Val = exmpp_xml:get_attribute(El, 'seconds', ""), + case catch list_to_integer(Val) of + {'EXIT', _} -> + never; + Int when Int > 0 -> + {MegaSecs, Secs, MicroSecs} = TimeStamp, + S = MegaSecs * 1000000 + Secs + Int, + MegaSecs1 = S div 1000000, + Secs1 = S rem 1000000, + {MegaSecs1, Secs1, MicroSecs}; _ -> - find_x_expire(TimeStamp, Els) - end. + never + end; +find_x_expire(TimeStamp, [_ | Els]) -> + find_x_expire(TimeStamp, Els). resend_offline_messages(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, F = fun() -> Rs = mnesia:wread({offline_msg, US}), @@ -250,16 +245,22 @@ resend_offline_messages(User, Server) -> {atomic, Rs} -> lists:foreach( fun(R) -> - {xmlelement, Name, Attrs, Els} = R#offline_msg.packet, + Packet = case R#offline_msg.packet of + #xmlelement{} = P -> + exmpp_xml:xmlelement_to_xmlel(P, + [?DEFAULT_NS], ?PREFIXED_NS); + #xmlel{} = P -> + P + end, + % XXX OLD FORMAT: Convert From & To. ejabberd_sm ! {route, - R#offline_msg.from, - R#offline_msg.to, - {xmlelement, Name, Attrs, - Els ++ - [jlib:timestamp_to_xml( + jlib:from_old_jid(R#offline_msg.from), + jlib:from_old_jid(R#offline_msg.to), + exmpp_xml:append_child(Packet, + jlib:timestamp_to_xml( calendar:now_to_universal_time( - R#offline_msg.timestamp))]}} + R#offline_msg.timestamp)))} end, lists:keysort(#offline_msg.timestamp, Rs)); _ -> @@ -267,8 +268,8 @@ resend_offline_messages(User, Server) -> end. pop_offline_messages(Ls, User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, F = fun() -> Rs = mnesia:wread({offline_msg, US}), @@ -280,15 +281,21 @@ pop_offline_messages(Ls, User, Server) -> TS = now(), Ls ++ lists:map( fun(R) -> - {xmlelement, Name, Attrs, Els} = R#offline_msg.packet, + Packet = case R#offline_msg.packet of + #xmlelement{} = P -> + exmpp_xml:xmlelement_to_xmlel(P, + [?DEFAULT_NS], ?PREFIXED_NS); + #xmlel{} = P -> + P + end, + % XXX OLD FORMAT: Convert From & To. {route, - R#offline_msg.from, - R#offline_msg.to, - {xmlelement, Name, Attrs, - Els ++ - [jlib:timestamp_to_xml( + jlib:from_old_jid(R#offline_msg.from), + jlib:from_old_jid(R#offline_msg.to), + exmpp_xml:append_child(Packet, + jlib:timestamp_to_xml( calendar:now_to_universal_time( - R#offline_msg.timestamp))]}} + R#offline_msg.timestamp)))} end, lists:filter( fun(R) -> @@ -343,8 +350,8 @@ remove_old_messages(Days) -> mnesia:transaction(F). remove_user(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, F = fun() -> mnesia:delete({offline_msg, US}) @@ -371,10 +378,15 @@ update_table() -> F1 = fun() -> mnesia:write_lock_table(mod_offline_tmp_table), mnesia:foldl( - fun(#offline_msg{us = U} = R, _) -> + fun(#offline_msg{us = U, packet = P} = R, _) -> + New_R = R#offline_msg{ + us = {U, Host}, + packet = exmpp_xml:xmlelement_to_xmlel(P, + [?DEFAULT_NS], ?PREFIXED_NS) + }, mnesia:dirty_write( mod_offline_tmp_table, - R#offline_msg{us = {U, Host}}) + New_R) end, ok, offline_msg) end, mnesia:transaction(F1), @@ -402,8 +414,7 @@ update_table() -> mnesia:transform_table( offline_msg, fun({_, U, TS, F, T, P}) -> - {xmlelement, _Name, _Attrs, Els} = P, - Expire = find_x_expire(TS, Els), + Expire = find_x_expire(TS, P#xmlelement.children), #offline_msg{us = U, timestamp = TS, expire = Expire, @@ -442,14 +453,21 @@ update_table() -> %% Warn senders that their messages have been discarded: discard_warn_sender(Msgs) -> lists:foreach( - fun(#offline_msg{from=From, to=To, packet=Packet}) -> + fun(#offline_msg{from=From, to=To, packet=Packet0}) -> + Packet = case Packet0 of + #xmlelement{} = P -> + exmpp_xml:xmlelement_to_xmlel(P, + [?DEFAULT_NS], ?PREFIXED_NS); + #xmlel{} = P -> + P + end, ErrText = "Your contact offline message queue is full. The message has been discarded.", - Lang = xml:get_tag_attr_s("xml:lang", Packet), - Err = jlib:make_error_reply( - Packet, ?ERRT_RESOURCE_CONSTRAINT(Lang, ErrText)), + Error = exmpp_stanza:error('resource-constraint', + {"en", ErrText}), + Err = exmpp_stanza:reply_with_error(Packet, Error), ejabberd_router:route( - To, - From, Err) + jlib:from_old_jid(To), + jlib:from_old_jid(From), Err) end, Msgs). @@ -464,14 +482,14 @@ webadmin_page(_, Host, webadmin_page(Acc, _, _) -> Acc. user_queue(User, Server, Query, Lang) -> - US = {jlib:nodeprep(User), jlib:nameprep(Server)}, + US = {exmpp_stringprep:nodeprep(User), exmpp_stringprep:nameprep(Server)}, Res = user_queue_parse_query(US, Query), Msgs = lists:keysort(#offline_msg.timestamp, mnesia:dirty_read({offline_msg, US})), FMsgs = lists:map( fun(#offline_msg{timestamp = TimeStamp, from = From, to = To, - packet = {xmlelement, Name, Attrs, Els}} = Msg) -> + packet = Packet} = Msg) -> ID = jlib:encode_base64(binary_to_list(term_to_binary(Msg))), {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:now_to_local_time(TimeStamp), @@ -479,11 +497,14 @@ user_queue(User, Server, Query, Lang) -> io_lib:format( "~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", [Year, Month, Day, Hour, Minute, Second])), - SFrom = jlib:jid_to_string(From), - STo = jlib:jid_to_string(To), - Attrs2 = jlib:replace_from_to_attrs(SFrom, STo, Attrs), - Packet = {xmlelement, Name, Attrs2, Els}, - FPacket = ejabberd_web_admin:pretty_print_xml(Packet), + SFrom = exmpp_jid:jid_to_string(jlib:from_old_jid(From)), + STo = exmpp_jid:jid_to_string(jlib:from_old_jid(To)), + Packet0 = exmpp_xml:xmlelement_to_xmlel(Packet, + [?DEFAULT_NS], ?PREFIXED_NS), + Packet1 = exmpp_stanza:set_jids(Packet0, SFrom, STo), + FPacket = exmpp_xml:node_to_list( + exmpp_xml:indent_document(Packet1, <<" ">>), + [?DEFAULT_NS], ?PREFIXED_NS), ?XE("tr", [?XAE("td", [{"class", "valign"}], [?INPUT("checkbox", "selected", ID)]), ?XAC("td", [{"class", "valign"}], Time), @@ -547,10 +568,10 @@ user_queue_parse_query(US, Query) -> end. us_to_list({User, Server}) -> - jlib:jid_to_string({User, Server, ""}). + exmpp_jid:jid_to_string(User, Server). webadmin_user(Acc, User, Server, Lang) -> - US = {jlib:nodeprep(User), jlib:nameprep(Server)}, + US = {exmpp_stringprep:nodeprep(User), exmpp_stringprep:nameprep(Server)}, QueueLen = length(mnesia:dirty_read({offline_msg, US})), FQueueLen = [?AC("queue/", integer_to_list(QueueLen))], diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index c3d0513d0..a8831aa0d 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -40,8 +40,9 @@ webadmin_page/3, webadmin_user/4]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("web/ejabberd_http.hrl"). -include("web/ejabberd_web_admin.hrl"). @@ -50,6 +51,11 @@ -define(PROCNAME, ejabberd_offline). -define(OFFLINE_TABLE_LOCK_THRESHOLD, 1000). +% These are the namespace already declared by the stream opening. This is +% used at serialization time. +-define(DEFAULT_NS, ?NS_JABBER_CLIENT). +-define(PREFIXED_NS, [{?NS_XMPP, ?NS_XMPP_pfx}]). + start(Host, Opts) -> ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, store_packet, 50), @@ -93,24 +99,20 @@ loop(Host, MaxOfflineMsgs) -> fun(M) -> Username = ejabberd_odbc:escape( - (M#offline_msg.to)#jid.luser), + (M#offline_msg.to)#jid.lnode), From = M#offline_msg.from, To = M#offline_msg.to, - {xmlelement, Name, Attrs, Els} = - M#offline_msg.packet, - Attrs2 = jlib:replace_from_to_attrs( - jlib:jid_to_string(From), - jlib:jid_to_string(To), - Attrs), - Packet = {xmlelement, Name, Attrs2, - Els ++ - [jlib:timestamp_to_xml( + Packet0 = exmpp_stanza:set_jids( + From, + To, + M#offline_msg.packet), + Packet1 = exmpp_xml:append_child(Packet0, + jlib:timestamp_to_xml( calendar:now_to_universal_time( - M#offline_msg.timestamp))]}, + M#offline_msg.timestamp))), XML = ejabberd_odbc:escape( - lists:flatten( - xml:element_to_string(Packet))), + exmpp_xml:document_to_string(Packet1)), odbc_queries:add_spool_sql(Username, XML) end, Msgs), case catch odbc_queries:add_spool(Host, Query) of @@ -152,17 +154,16 @@ stop(Host) -> ok. store_packet(From, To, Packet) -> - Type = xml:get_tag_attr_s("type", Packet), + Type = exmpp_stanza_:get_type(Packet, 'type'), if (Type /= "error") and (Type /= "groupchat") and (Type /= "headline") -> case check_event(From, To, Packet) of true -> - #jid{luser = LUser} = To, + #jid{lnode = LUser} = To, TimeStamp = now(), - {xmlelement, _Name, _Attrs, Els} = Packet, - Expire = find_x_expire(TimeStamp, Els), - gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME) ! + Expire = find_x_expire(TimeStamp, Packet#xmlel.children), + gen_mod:get_module_proc(To#jid.ldomain, ?PROCNAME) ! #offline_msg{user = LUser, timestamp = TimeStamp, expire = Expire, @@ -178,31 +179,27 @@ store_packet(From, To, Packet) -> end. check_event(From, To, Packet) -> - {xmlelement, Name, Attrs, Els} = Packet, - case find_x_event(Els) of + case find_x_event(Packet#xmlel.children) of false -> true; El -> - case xml:get_subtag(El, "id") of - false -> - case xml:get_subtag(El, "offline") of - false -> + case exmpp_xml:get_element(El, 'id') of + undefined -> + case exmpp_xml:get_element(El, 'offline') of + undefined -> true; _ -> - ID = case xml:get_tag_attr_s("id", Packet) of + ID = case exmpp_xml:get_attribute(Packet, 'id', "") of "" -> - {xmlelement, "id", [], []}; + #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'id'}; S -> - {xmlelement, "id", [], - [{xmlcdata, S}]} + #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'id', + children = [#xmlcdata{cdata = list_to_binary(S)}]} end, + X = #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'x', children = + [ID, #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'offline'}]}, ejabberd_router:route( - To, From, {xmlelement, Name, Attrs, - [{xmlelement, "x", - [{"xmlns", ?NS_EVENT}], - [ID, - {xmlelement, "offline", [], []}]}] - }), + To, From, exmpp_xml:set_children(Packet, [X])), true end; _ -> @@ -212,64 +209,49 @@ check_event(From, To, Packet) -> find_x_event([]) -> false; -find_x_event([{xmlcdata, _} | Els]) -> - find_x_event(Els); -find_x_event([El | Els]) -> - case xml:get_tag_attr_s("xmlns", El) of - ?NS_EVENT -> - El; - _ -> - find_x_event(Els) - end. +find_x_event([#xmlel{ns = ?NS_MESSAGE_EVENT} = El | _Els]) -> + El; +find_x_event([_ | Els]) -> + find_x_event(Els). find_x_expire(_, []) -> never; -find_x_expire(TimeStamp, [{xmlcdata, _} | Els]) -> - find_x_expire(TimeStamp, Els); -find_x_expire(TimeStamp, [El | Els]) -> - case xml:get_tag_attr_s("xmlns", El) of - ?NS_EXPIRE -> - Val = xml:get_tag_attr_s("seconds", El), - case catch list_to_integer(Val) of - {'EXIT', _} -> - never; - Int when Int > 0 -> - {MegaSecs, Secs, MicroSecs} = TimeStamp, - S = MegaSecs * 1000000 + Secs + Int, - MegaSecs1 = S div 1000000, - Secs1 = S rem 1000000, - {MegaSecs1, Secs1, MicroSecs}; - _ -> - never - end; +find_x_expire(TimeStamp, [#xmlel{ns = ?NS_MESSAGE_EXPIRE} = El | _Els]) -> + Val = exmpp_xml:get_attribute(El, 'seconds', ""), + case catch list_to_integer(Val) of + {'EXIT', _} -> + never; + Int when Int > 0 -> + {MegaSecs, Secs, MicroSecs} = TimeStamp, + S = MegaSecs * 1000000 + Secs + Int, + MegaSecs1 = S div 1000000, + Secs1 = S rem 1000000, + {MegaSecs1, Secs1, MicroSecs}; _ -> - find_x_expire(TimeStamp, Els) - end. + never + end; +find_x_expire(TimeStamp, [_ | Els]) -> + find_x_expire(TimeStamp, Els). pop_offline_messages(Ls, User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), EUser = ejabberd_odbc:escape(LUser), case odbc_queries:get_and_del_spool_msg_t(LServer, EUser) of {atomic, {selected, ["username","xml"], Rs}} -> Ls ++ lists:flatmap( fun({_, XML}) -> - case xml_stream:parse_element(XML) of - {error, _Reason} -> - []; - El -> - To = jlib:string_to_jid( - xml:get_tag_attr_s("to", El)), - From = jlib:string_to_jid( - xml:get_tag_attr_s("from", El)), - if - (To /= error) and - (From /= error) -> - [{route, From, To, El}]; - true -> - [] - end + try + [El] = exmpp_xml:parse_document(XML, [namespace, name_as_atom]), + To = exmpp_jid:list_to_jid( + exmpp_stanza:get_recipient(El)), + From = exmpp_jid:list_to_jid( + exmpp_stanza:get_sender(El)), + [{route, From, To, El}] + catch + _ -> + [] end end, Rs); _ -> @@ -278,8 +260,8 @@ pop_offline_messages(Ls, User, Server) -> remove_user(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), Username = ejabberd_odbc:escape(LUser), odbc_queries:del_spool_msg(LServer, Username). @@ -294,9 +276,9 @@ discard_warn_sender(Msgs) -> lists:foreach( fun(#offline_msg{from=From, to=To, packet=Packet}) -> ErrText = "Your contact offline message queue is full. The message has been discarded.", - Lang = xml:get_tag_attr_s("xml:lang", Packet), - Err = jlib:make_error_reply( - Packet, ?ERRT_RESOURCE_CONSTRAINT(Lang, ErrText)), + Error = exmpp_stanza:error('resource-constraint', + {"en", ErrText}), + Err = exmpp_stanza:reply_with_error(Packet, Error), ejabberd_router:route( To, From, Err) @@ -314,8 +296,8 @@ webadmin_page(_, Host, webadmin_page(Acc, _, _) -> Acc. user_queue(User, Server, Query, Lang) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), Username = ejabberd_odbc:escape(LUser), US = {LUser, LServer}, Res = user_queue_parse_query(Username, LServer, Query), @@ -327,11 +309,12 @@ user_queue(User, Server, Query, Lang) -> {selected, ["username", "xml"], Rs} -> lists:flatmap( fun({_, XML}) -> - case xml_stream:parse_element(XML) of - {error, _Reason} -> - []; - El -> + try exmpp_xml:parse_document(XML, [namespace, name_as_atom]) of + [El] -> [El] + catch + _ -> + [] end end, Rs); _ -> @@ -339,10 +322,12 @@ user_queue(User, Server, Query, Lang) -> end, FMsgs = lists:map( - fun({xmlelement, _Name, _Attrs, _Els} = Msg) -> + fun(#xmlel{} = Msg) -> ID = jlib:encode_base64(binary_to_list(term_to_binary(Msg))), Packet = Msg, - FPacket = ejabberd_web_admin:pretty_print_xml(Packet), + FPacket = exmpp_xml:node_to_list( + exmpp_xml:indent_document(Packet, <<" ">>), + [?DEFAULT_NS], ?PREFIXED_NS), ?XE("tr", [?XAE("td", [{"class", "valign"}], [?INPUT("checkbox", "selected", ID)]), ?XAE("td", [{"class", "valign"}], [?XC("pre", FPacket)])] @@ -386,11 +371,12 @@ user_queue_parse_query(Username, LServer, Query) -> {selected, ["xml", "seq"], Rs} -> lists:flatmap( fun({XML, Seq}) -> - case xml_stream:parse_element(XML) of - {error, _Reason} -> - []; - El -> + try exmpp_xml:parse_document(XML, [namespace, name_as_atom]) of + [El] -> [{El, Seq}] + catch + _ -> + [] end end, Rs); _ -> @@ -421,11 +407,11 @@ user_queue_parse_query(Username, LServer, Query) -> end. us_to_list({User, Server}) -> - jlib:jid_to_string({User, Server, ""}). + exmpp_jid:jid_to_list(User, Server). webadmin_user(Acc, User, Server, Lang) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), Username = ejabberd_odbc:escape(LUser), QueueLen = case catch ejabberd_odbc:sql_query( LServer, From cb20c9b0d7049c94f08f5ddbaf5570624a0f69e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 6 Aug 2008 13:46:23 +0000 Subject: [PATCH 054/582] Update to use the new exmpp_xml:get_attribute/{3,4} API. SVN Revision: 1514 --- ChangeLog | 4 ++++ src/adhoc.erl | 6 +++--- src/mod_caps.erl | 8 ++++---- src/mod_configure.erl | 6 +++--- src/mod_disco.erl | 18 +++++++++--------- src/mod_roster.erl | 4 ++-- 6 files changed, 25 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0ef9fe049..792cc377f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,10 @@ src/mod_last.erl, src/mod_configure2.erl, src/mod_last_odbc.erl, src/gen_iq_handler.erl: Convert to exmpp. + * src/adhoc.erl, src/mod_configure.erl, src/mod_roster.erl, + src/mod_disco.erl, src/mod_caps.erl: Update to use the new + exmpp_xml:get_attribute/{3,4} API. + 2008-07-25 Jean-Sébastien Pédron * src/adhoc.erl, src/mod_configure.erl, src/mod_announce.erl, diff --git a/src/adhoc.erl b/src/adhoc.erl index a35dc763f..b338df068 100644 --- a/src/adhoc.erl +++ b/src/adhoc.erl @@ -45,9 +45,9 @@ parse_request(IQ) -> {set, ?NS_ADHOC} -> ?DEBUG("entering parse_request...", []), Lang = exmpp_stanza:get_lang(IQ), - Node = exmpp_xml:get_attribute(SubEl, 'node'), - SessionID = exmpp_xml:get_attribute(SubEl, 'sessionid'), - Action = exmpp_xml:get_attribute(SubEl, 'action'), + Node = exmpp_xml:get_attribute(SubEl, 'node', ""), + SessionID = exmpp_xml:get_attribute(SubEl, 'sessionid', ""), + Action = exmpp_xml:get_attribute(SubEl, 'action', ""), XData = find_xdata_el(SubEl), AllEls = SubEl#xmlel.ns, if XData -> diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 9b3bef70b..3cb1b8530 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -69,9 +69,9 @@ read_caps(Els) -> read_caps(Els, nothing). read_caps([#xmlel{ns = ?NS_CAPS, name = 'c'} = El | Tail], _Result) -> - Node = exmpp_xml:get_attribute(El, 'node'), - Version = exmpp_xml:get_attribute(El, 'ver'), - Exts = string:tokens(exmpp_xml:get_attribute(El, 'ext'), " "), + Node = exmpp_xml:get_attribute(El, 'node', ""), + Version = exmpp_xml:get_attribute(El, 'ver', ""), + Exts = string:tokens(exmpp_xml:get_attribute(El, 'ext', ""), " "), read_caps(Tail, #caps{node = Node, version = Version, exts = Exts}); read_caps([#xmlel{ns = ?NS_MUC_USER, name = 'x'} | _Tail], _Result) -> nothing; @@ -226,7 +226,7 @@ handle_cast({disco_response, From, _To, IQ}, {ok, {Node, SubNode}} -> Features = lists:flatmap(fun(#xmlel{name = 'feature'} = F) -> - [exmpp_xml:get_attribute(F, 'var')]; + [exmpp_xml:get_attribute(F, 'var', "")]; (_) -> [] end, Els), diff --git a/src/mod_configure.erl b/src/mod_configure.erl index c8925277e..f62d1926a 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -315,7 +315,7 @@ adhoc_local_items(Acc, From, #jid{ldomain = LServer, domain = Server} = To, Nodes = recursively_get_local_items(LServer, "", Server, Lang), Nodes1 = lists:filter( fun(N) -> - Nd = exmpp_xml:get_attribute(N, 'node'), + Nd = exmpp_xml:get_attribute(N, 'node', ""), F = get_local_features([], From, To, Nd, Lang), case F of {result, [?NS_ADHOC_s]} -> @@ -346,8 +346,8 @@ recursively_get_local_items(LServer, Node, Server, Lang) -> Nodes = lists:flatten( lists:map( fun(N) -> - S = exmpp_xml:get_attribute(N, 'jid'), - Nd = exmpp_xml:get_attribute(N, 'node'), + S = exmpp_xml:get_attribute(N, 'jid', ""), + Nd = exmpp_xml:get_attribute(N, 'node', ""), if (S /= Server) or (Nd == "") -> []; true -> diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 9700a6546..a2e9e4feb 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -132,7 +132,7 @@ process_local_iq_items(From, To, IQ) -> exmpp_iq:error(IQ, 'not-allowed'); get -> SubEl = exmpp_iq:get_request(IQ), - Node = exmpp_xml:get_attribute(SubEl, 'node'), + Node = exmpp_xml:get_attribute(SubEl, 'node', ""), Host = To#jid.ldomain, Lang = exmpp_stanza:get_lang(IQ), @@ -166,7 +166,7 @@ process_local_iq_info(From, To, IQ) -> get -> Host = To#jid.ldomain, SubEl = exmpp_iq:get_request(IQ), - Node = exmpp_xml:get_attribute(SubEl, 'node'), + Node = exmpp_xml:get_attribute(SubEl, 'node', ""), Lang = exmpp_stanza:get_lang(IQ), % XXX OLD FORMAT: From, To. FromOld = jlib:to_old_jid(From), @@ -290,7 +290,7 @@ process_sm_iq_items(From, To, IQ) -> #jid{lnode = LTo, ldomain = ToServer} = To, #jid{lnode = LFrom, ldomain = LServer} = From, Self = (LTo == LFrom) andalso (ToServer == LServer), - Node = exmpp_xml:get_attribute(SubEl, 'node'), + Node = exmpp_xml:get_attribute(SubEl, 'node', ""), if Self, Node /= [] -> %% Here, we treat disco publish attempts to your own JID. @@ -307,7 +307,7 @@ process_sm_iq_items(From, To, IQ) -> end; get -> Host = To#jid.ldomain, - Node = exmpp_xml:get_attribute(SubEl, 'node'), + Node = exmpp_xml:get_attribute(SubEl, 'node', ""), Lang = exmpp_stanza:get_lang(IQ), % XXX OLD FORMAT: From, To. FromOld = jlib:to_old_jid(From), @@ -366,7 +366,7 @@ process_sm_iq_info(From, To, IQ) -> get -> Host = To#jid.ldomain, SubEl = exmpp_iq:get_request(IQ), - Node = exmpp_xml:get_attribute(SubEl, 'node'), + Node = exmpp_xml:get_attribute(SubEl, 'node', ""), Lang = exmpp_stanza:get_lang(IQ), % XXX OLD FORMAT: From, To. FromOld = jlib:to_old_jid(From), @@ -441,10 +441,10 @@ process_disco_publish(User, Node, Items) -> F = fun() -> lists:foreach( fun(#xmlel{} = Item) -> - Action = exmpp_xml:get_attribute(Item, 'action'), - Jid = exmpp_xml:get_attribute(Item, 'jid'), - PNode = exmpp_xml:get_attribute(Item, 'node'), - Name = exmpp_xml:get_attribute(Item, 'name'), + Action = exmpp_xml:get_attribute(Item, 'action', ""), + Jid = exmpp_xml:get_attribute(Item, 'jid', ""), + PNode = exmpp_xml:get_attribute(Item, 'node', ""), + Name = exmpp_xml:get_attribute(Item, 'name', ""), ?INFO_MSG("Disco publish: ~p ~p ~p ~p ~p ~p~n", [User, Action, Node, Jid, PNode, Name]), diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 4e7e5ecab..9d7211cc9 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -194,7 +194,7 @@ process_iq_set(From, To, IQ) -> process_item_set(From, To, #xmlel{} = Item) -> try - JID1 = exmpp_jid:string_to_jid(exmpp_xml:get_attribute(Item, 'jid')), + JID1 = exmpp_jid:string_to_jid(exmpp_xml:get_attribute(Item, 'jid', "")), % XXX OLD FORMAT: old JID (with empty strings). #jid{node = User, lnode = LUser, ldomain = LServer} = jlib:to_old_jid(From), @@ -587,7 +587,7 @@ set_items(User, Server, SubEl) -> process_item_set_t(LUser, LServer, #xmlel{} = El) -> try - JID1 = exmpp_jid:string_to_jid(exmpp_xml:get_attribute(El, 'jid')), + JID1 = exmpp_jid:string_to_jid(exmpp_xml:get_attribute(El, 'jid', "")), JID = {JID1#jid.node, JID1#jid.domain, JID1#jid.resource}, LJID = {JID1#jid.lnode, JID1#jid.ldomain, JID1#jid.lresource}, Item = #roster{usj = {LUser, LServer, LJID}, From 85c2097ece8016e6abb7bad3ccd89c82de3852b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 6 Aug 2008 13:51:42 +0000 Subject: [PATCH 055/582] Update to use the new names used in exmpp_jid. SVN Revision: 1515 --- ChangeLog | 6 ++++++ src/ejabberd_c2s.erl | 16 ++++++++-------- src/ejabberd_s2s_in.erl | 8 ++++---- src/ejabberd_s2s_out.erl | 4 ++-- src/ejabberd_service.erl | 2 +- src/mod_adhoc.erl | 2 +- src/mod_caps.erl | 4 ++-- src/mod_configure.erl | 36 ++++++++++++++++++------------------ src/mod_disco.erl | 2 +- src/mod_echo.erl | 2 +- src/mod_offline.erl | 6 +++--- src/mod_roster.erl | 22 +++++++++++----------- src/mod_vcard.erl | 4 ++-- 13 files changed, 60 insertions(+), 54 deletions(-) diff --git a/ChangeLog b/ChangeLog index 792cc377f..8e2e1f4bf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,12 @@ src/mod_disco.erl, src/mod_caps.erl: Update to use the new exmpp_xml:get_attribute/{3,4} API. + * src/ejabberd_c2s.erl, src/ejabberd_s2s_in.erl, + src/ejabberd_s2s_out.erl, src/ejabberd_service.erl, src/mod_adhoc.erl, + src/mod_caps.erl, src/mod_configure.erl, src/mod_disco.erl, + src/mod_echo.erl, src/mod_offline.erl, src/mod_roster.erl, + src/mod_vcard.erl: Update to use the new names used in exmpp_jid. + 2008-07-25 Jean-Sébastien Pédron * src/adhoc.erl, src/mod_configure.erl, src/mod_announce.erl, diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index da1239064..d006e2a5a 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -398,7 +398,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> ?INFO_MSG( "(~w) Accepted legacy authentication for ~s", [StateData#state.socket, - exmpp_jid:jid_to_string(JID)]), + exmpp_jid:jid_to_list(JID)]), SID = {now(), self()}, Conn = get_conn_type(StateData), Info = [{ip, StateData#state.ip}, {conn, Conn}, @@ -435,7 +435,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> ?INFO_MSG( "(~w) Failed legacy authentication for ~s", [StateData#state.socket, - exmpp_jid:jid_to_string(JID)]), + exmpp_jid:jid_to_list(JID)]), Res = exmpp_iq:error_without_original(El, 'not-authorized'), send_element(StateData, Res), @@ -445,7 +445,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> ?INFO_MSG( "(~w) Forbidden legacy authentication for ~s", [StateData#state.socket, - exmpp_jid:jid_to_string(JID)]), + exmpp_jid:jid_to_list(JID)]), Res = exmpp_iq:error_without_original(El, 'not-allowed'), send_element(StateData, Res), @@ -713,7 +713,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> allow -> ?INFO_MSG("(~w) Opened session for ~s", [StateData#state.socket, - exmpp_jid:jid_to_string(JID)]), + exmpp_jid:jid_to_list(JID)]), SID = {now(), self()}, Conn = get_conn_type(StateData), Info = [{ip, StateData#state.ip}, {conn, Conn}, @@ -750,7 +750,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> StateData#state.server, [JIDOld]), ?INFO_MSG("(~w) Forbidden session for ~s", [StateData#state.socket, - exmpp_jid:jid_to_string(JID)]), + exmpp_jid:jid_to_list(JID)]), Err = exmpp_server_session:error(El, 'not-allowed'), send_element(StateData, Err), fsm_next_state(wait_for_session, StateData) @@ -787,7 +787,7 @@ session_established({xmlstreamelement, El}, StateData) -> undefined -> exmpp_jid:make_bare_jid(User, Server); _ -> - exmpp_jid:string_to_jid(To) + exmpp_jid:list_to_jid(To) end, NewEl = case exmpp_stanza:get_lang(El) of undefined -> @@ -1237,7 +1237,7 @@ terminate(_Reason, StateName, StateData) -> replaced -> ?INFO_MSG("(~w) Replaced session for ~s", [StateData#state.socket, - exmpp_jid:jid_to_string(StateData#state.jid)]), + exmpp_jid:jid_to_list(StateData#state.jid)]), From = StateData#state.jid, Packet = exmpp_presence:unavailable(), Packet1 = exmpp_presence:set_status(Packet, @@ -1255,7 +1255,7 @@ terminate(_Reason, StateName, StateData) -> _ -> ?INFO_MSG("(~w) Close session for ~s", [StateData#state.socket, - exmpp_jid:jid_to_string(StateData#state.jid)]), + exmpp_jid:jid_to_list(StateData#state.jid)]), EmptySet = ?SETS:new(), case StateData of diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index c0c863c1e..4804ff551 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -371,7 +371,7 @@ stream_established({xmlstreamelement, El}, StateData) -> error; F -> try - exmpp_jid:string_to_jid(F) + exmpp_jid:list_to_jid(F) catch _Exception1 -> error end @@ -381,7 +381,7 @@ stream_established({xmlstreamelement, El}, StateData) -> error; T -> try - exmpp_jid:string_to_jid(T) + exmpp_jid:list_to_jid(T) catch _Exception2 -> error end @@ -621,7 +621,7 @@ get_cert_domains(Cert) -> end, if D /= error -> - case exmpp_jid:string_to_jid(D) of + case exmpp_jid:list_to_jid(D) of #jid{lnode = undefined, ldomain = LD, lresource = undefined} -> @@ -674,7 +674,7 @@ get_cert_domains(Cert) -> [] end; ({dNSName, D}) when is_list(D) -> - case exmpp_jid:string_to_jid(D) of + case exmpp_jid:list_to_jid(D) of #jid{lnode = undefined, ldomain = LD, lresource = undefined} -> diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index baa5d23f5..5859b89cf 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -809,8 +809,8 @@ bounce_element(El, Condition) -> "result" -> ok; _ -> Err = exmpp_stanza:reply_with_error(El, Condition), - From = exmpp_jid:string_to_jid(exmpp_stanza:get_sender(El)), - To = exmpp_jid:string_to_jid(exmpp_stanza:get_recipient(El)), + From = exmpp_jid:list_to_jid(exmpp_stanza:get_sender(El)), + To = exmpp_jid:list_to_jid(exmpp_stanza:get_recipient(El)), % No namespace conversion (:server <-> :client) is done. % This is handled by C2S and S2S send_element functions. ejabberd_router:route(To, From, Err) diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index b6a977ce6..302211f07 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -223,7 +223,7 @@ stream_established({xmlstreamelement, El}, StateData) -> %% when accept packets from any address. %% In this case, the component can send packet of %% behalf of the server users. - false -> exmpp_jid:string_to_jid(From); + false -> exmpp_jid:list_to_jid(From); %% The default is the standard behaviour in XEP-0114 _ -> FromJID1 = exmpp_jib:string_to_jid(From), diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl index 87f66899b..c96c3e580 100644 --- a/src/mod_adhoc.erl +++ b/src/mod_adhoc.erl @@ -124,7 +124,7 @@ get_sm_commands(Acc, _From, #jid{ldomain = LServer} = To, "", Lang) -> end, Nodes = [#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_string(To)}, + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(To)}, #xmlattr{name = 'node', value = ?NS_ADHOC_s}, #xmlattr{name = 'name', value = translate:translate(Lang, "Commands")}] }], diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 3cb1b8530..a04a27f0a 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -254,9 +254,9 @@ handle_cast({disco_response, From, _To, IQ}, ?ERROR_MSG("ID '~s' matches no query", [ID]) end; %gen_server:cast(self(), visit_feature_queries), - %?DEBUG("Error IQ reponse from ~s:~n~p", [exmpp_jid:jid_to_string(From), SubEls]); + %?DEBUG("Error IQ reponse from ~s:~n~p", [exmpp_jid:jid_to_list(From), SubEls]); {result, _} -> - ?DEBUG("Invalid IQ contents from ~s:~n~p", [exmpp_jid:jid_to_string(From), IQ#xmlel.children]); + ?DEBUG("Invalid IQ contents from ~s:~n~p", [exmpp_jid:jid_to_list(From), IQ#xmlel.children]); _ -> %% Can't do anything about errors ok diff --git a/src/mod_configure.erl b/src/mod_configure.erl index f62d1926a..c362963a6 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -98,7 +98,7 @@ stop(Host) -> -define(NODEJID(To, Name, Node), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_string(To)}, + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(To)}, #xmlattr{name = 'name', value = ?T(Lang, Name)}, #xmlattr{name = 'node', value = Node}]}). @@ -258,7 +258,7 @@ adhoc_sm_items(Acc, From, #jid{ldomain = LServer} = To, Lang) -> empty -> [] end, Nodes = [#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_string(To)}, + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(To)}, #xmlattr{name = 'name', value = ?T(Lang, "Configuration")}, #xmlattr{name = 'node', value = "config"}]}], {result, Items ++ Nodes}; @@ -297,7 +297,7 @@ get_user_resources(User, Server) -> Rs = ejabberd_sm:get_user_resources(User, Server), lists:map(fun(R) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_string(User, Server, R)}, + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(User, Server, R)}, #xmlattr{name = 'name', value = User}]} end, lists:sort(Rs)). @@ -365,7 +365,7 @@ recursively_get_local_items(LServer, Node, Server, Lang) -> Fallback; allow -> case get_local_items(LServer, LNode, - exmpp_jid:jid_to_string(To), Lang) of + exmpp_jid:jid_to_list(To), Lang) of {result, Res} -> {result, Res}; {error, Error} -> @@ -388,7 +388,7 @@ get_local_items(Acc, From, #jid{ldomain = LServer} = To, "", Lang) -> {result, Items}; allow -> case get_local_items(LServer, [], - exmpp_jid:jid_to_string(To), Lang) of + exmpp_jid:jid_to_list(To), Lang) of {result, Res} -> {result, Items ++ Res}; {error, _Error} -> @@ -507,8 +507,8 @@ get_local_items(Host, ["all users", [$@ | Diap]], _Server, _Lang) -> Sub = lists:sublist(SUsers, N1, N2 - N1 + 1), lists:map(fun({S, U}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_string(U, S)}, - #xmlattr{name = 'name', value = exmpp_jid:jid_to_string(U, S)}]} + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(U, S)}, + #xmlattr{name = 'name', value = exmpp_jid:jid_to_list(U, S)}]} end, Sub) end of {'EXIT', _Reason} -> @@ -591,8 +591,8 @@ get_online_vh_users(Host) -> SURs = lists:sort([{S, U, R} || {U, S, R} <- USRs]), lists:map(fun({S, U, R}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_string(U, S, R)}, - #xmlattr{name = 'name', value = exmpp_jid:jid_to_string(U, S)}]} + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(U, S, R)}, + #xmlattr{name = 'name', value = exmpp_jid:jid_to_list(U, S)}]} end, SURs) end. @@ -606,8 +606,8 @@ get_all_vh_users(Host) -> N when N =< 100 -> lists:map(fun({S, U}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_string(U, S)}, - #xmlattr{name = 'name', value = exmpp_jid:jid_to_string(U, S)}]} + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(U, S)}, + #xmlattr{name = 'name', value = exmpp_jid:jid_to_list(U, S)}]} end, SUsers); N -> NParts = trunc(math:sqrt(N * 0.618)) + 1, @@ -1534,7 +1534,7 @@ set_form(_From, _Host, ?NS_ADMINL("add-user"), _Lang, XData) -> AccountString = get_value("accountjid", XData), Password = get_value("password", XData), Password = get_value("password-verify", XData), - AccountJID = exmpp_jid:string_to_jid(AccountString), + AccountJID = exmpp_jid:list_to_jid(AccountString), User = AccountJID#jid.lnode, Server = AccountJID#jid.ldomain, true = lists:member(Server, ?MYHOSTS), @@ -1546,7 +1546,7 @@ set_form(_From, _Host, ?NS_ADMINL("delete-user"), _Lang, XData) -> [_|_] = AccountStringList, ASL2 = lists:map( fun(AccountString) -> - JID = exmpp_jid:string_to_jid(AccountString), + JID = exmpp_jid:list_to_jid(AccountString), [_|_] = JID#jid.lnode, User = JID#jid.lnode, Server = JID#jid.ldomain, @@ -1559,7 +1559,7 @@ set_form(_From, _Host, ?NS_ADMINL("delete-user"), _Lang, XData) -> set_form(_From, _Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> AccountString = get_value("accountjid", XData), - JID = exmpp_jid:string_to_jid(AccountString), + JID = exmpp_jid:list_to_jid(AccountString), [_|_] = JID#jid.lnode, LUser = JID#jid.lnode, LServer = JID#jid.ldomain, @@ -1578,7 +1578,7 @@ set_form(_From, _Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> set_form(_From, _Host, ?NS_ADMINL("get-user-password"), Lang, XData) -> AccountString = get_value("accountjid", XData), - JID = exmpp_jid:string_to_jid(AccountString), + JID = exmpp_jid:list_to_jid(AccountString), [_|_] = JID#jid.lnode, User = JID#jid.lnode, Server = JID#jid.ldomain, @@ -1593,7 +1593,7 @@ set_form(_From, _Host, ?NS_ADMINL("get-user-password"), Lang, XData) -> set_form(_From, _Host, ?NS_ADMINL("change-user-password"), _Lang, XData) -> AccountString = get_value("accountjid", XData), Password = get_value("password", XData), - JID = exmpp_jid:string_to_jid(AccountString), + JID = exmpp_jid:list_to_jid(AccountString), [_|_] = JID#jid.lnode, User = JID#jid.lnode, Server = JID#jid.ldomain, @@ -1603,7 +1603,7 @@ set_form(_From, _Host, ?NS_ADMINL("change-user-password"), _Lang, XData) -> set_form(_From, _Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> AccountString = get_value("accountjid", XData), - JID = exmpp_jid:string_to_jid(AccountString), + JID = exmpp_jid:list_to_jid(AccountString), [_|_] = JID#jid.lnode, User = JID#jid.lnode, Server = JID#jid.ldomain, @@ -1640,7 +1640,7 @@ set_form(_From, _Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> set_form(_From, _Host, ?NS_ADMINL("user-stats"), Lang, XData) -> AccountString = get_value("accountjid", XData), - JID = exmpp_jid:string_to_jid(AccountString), + JID = exmpp_jid:list_to_jid(AccountString), [_|_] = JID#jid.lnode, User = JID#jid.lnode, Server = JID#jid.ldomain, diff --git a/src/mod_disco.erl b/src/mod_disco.erl index a2e9e4feb..517ef7a90 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -418,7 +418,7 @@ get_user_resources(User, Server) -> lists:map(fun(R) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [ #xmlattr{name = 'jid', value = - exmpp_jid:jid_to_string(User, Server, R)}, + exmpp_jid:jid_to_list(User, Server, R)}, #xmlattr{name = 'name', value = User} ]} end, lists:sort(Rs)). diff --git a/src/mod_echo.erl b/src/mod_echo.erl index f2540081c..fc043370c 100644 --- a/src/mod_echo.erl +++ b/src/mod_echo.erl @@ -200,5 +200,5 @@ do_client_version(enabled, From, To) -> %% Print in log Values_string1 = [io_lib:format("~n~s: ~p", [N, V]) || {N, V} <- Values], Values_string2 = lists:concat(Values_string1), - ?INFO_MSG("Information of the client: ~s~s", [exmpp_jid:jid_to_string(To), Values_string2]). + ?INFO_MSG("Information of the client: ~s~s", [exmpp_jid:jid_to_list(To), Values_string2]). diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 283d68607..3712dadbf 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -497,8 +497,8 @@ user_queue(User, Server, Query, Lang) -> io_lib:format( "~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", [Year, Month, Day, Hour, Minute, Second])), - SFrom = exmpp_jid:jid_to_string(jlib:from_old_jid(From)), - STo = exmpp_jid:jid_to_string(jlib:from_old_jid(To)), + SFrom = exmpp_jid:jid_to_list(jlib:from_old_jid(From)), + STo = exmpp_jid:jid_to_list(jlib:from_old_jid(To)), Packet0 = exmpp_xml:xmlelement_to_xmlel(Packet, [?DEFAULT_NS], ?PREFIXED_NS), Packet1 = exmpp_stanza:set_jids(Packet0, SFrom, STo), @@ -568,7 +568,7 @@ user_queue_parse_query(US, Query) -> end. us_to_list({User, Server}) -> - exmpp_jid:jid_to_string(User, Server). + exmpp_jid:jid_to_list(User, Server). webadmin_user(Acc, User, Server, Lang) -> US = {exmpp_stringprep:nodeprep(User), exmpp_stringprep:nameprep(Server)}, diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 9d7211cc9..57cc60f14 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -156,7 +156,7 @@ get_user_roster(Acc, US) -> item_to_xml(Item) -> {U, S, R} = Item#roster.jid, Attrs1 = exmpp_xml:set_attribute_in_list([], - 'jid', exmpp_jid:jid_to_string(U, S, R)), + 'jid', exmpp_jid:jid_to_list(U, S, R)), Attrs2 = case Item#roster.name of "" -> Attrs1; @@ -194,7 +194,7 @@ process_iq_set(From, To, IQ) -> process_item_set(From, To, #xmlel{} = Item) -> try - JID1 = exmpp_jid:string_to_jid(exmpp_xml:get_attribute(Item, 'jid', "")), + JID1 = exmpp_jid:list_to_jid(exmpp_xml:get_attribute(Item, 'jid', "")), % XXX OLD FORMAT: old JID (with empty strings). #jid{node = User, lnode = LUser, ldomain = LServer} = jlib:to_old_jid(From), @@ -276,7 +276,7 @@ process_item_attrs(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> case Attr of 'jid' -> try - JID1 = exmpp_jid:string_to_jid(Val), + JID1 = exmpp_jid:list_to_jid(Val), JID = {JID1#jid.node, JID1#jid.domain, JID1#jid.resource}, process_item_attrs(Item#roster{jid = JID}, Attrs) catch @@ -587,7 +587,7 @@ set_items(User, Server, SubEl) -> process_item_set_t(LUser, LServer, #xmlel{} = El) -> try - JID1 = exmpp_jid:string_to_jid(exmpp_xml:get_attribute(El, 'jid', "")), + JID1 = exmpp_jid:list_to_jid(exmpp_xml:get_attribute(El, 'jid', "")), JID = {JID1#jid.node, JID1#jid.domain, JID1#jid.resource}, LJID = {JID1#jid.lnode, JID1#jid.ldomain, JID1#jid.lresource}, Item = #roster{usj = {LUser, LServer, LJID}, @@ -612,7 +612,7 @@ process_item_attrs_ws(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> case Attr of 'jid' -> try - JID1 = exmpp_jid:string_to_jid(Val), + JID1 = exmpp_jid:list_to_jid(Val), JID = {JID1#jid.node, JID1#jid.domain, JID1#jid.resource}, process_item_attrs_ws(Item#roster{jid = JID}, Attrs) catch @@ -664,9 +664,9 @@ get_in_pending_subscriptions(Ls, User, Server) -> end, {U, S, R} = R#roster.jid, Attrs1 = exmpp_stanza:set_sender_in_list([], - exmpp_jid:jid_to_string(U, S, R)), + exmpp_jid:jid_to_list(U, S, R)), Attrs2 = exmpp_stanza:set_recipient_in_list(Attrs1, - exmpp_jid:jid_to_string(JID)), + exmpp_jid:jid_to_list(JID)), Pres1 = exmpp_presence:subscribe(), Pres2 = Pres1#xmlel{attrs = Attrs2}, exmpp_presence:set_status(Pres2, Status) @@ -815,7 +815,7 @@ user_roster(User, Server, Query, Lang) -> {U, S, R} = R#roster.jid, ?XE("tr", [?XAC("td", [{"class", "valign"}], - catch exmpp_jid:jid_to_string(U, S, R)), + catch exmpp_jid:jid_to_list(U, S, R)), ?XAC("td", [{"class", "valign"}], R#roster.name), ?XAC("td", [{"class", "valign"}], @@ -861,7 +861,7 @@ user_roster_parse_query(User, Server, Items, Query) -> error; {value, {_, SJID}} -> try - JID = exmpp_jid:string_to_jid(SJID), + JID = exmpp_jid:list_to_jid(SJID), user_roster_subscribe_jid(User, Server, JID), ok catch @@ -911,7 +911,7 @@ user_roster_item_parse_query(User, Server, Items, Query) -> {value, _} -> UJID = exmpp_jid:make_bare_jid(User, Server), Attrs1 = exmpp_xml:set_attribute_in_list([], - 'jid', exmpp_jid:jid_to_string(JID)), + 'jid', exmpp_jid:jid_to_list(JID)), Attrs2 = exmpp_xml:set_attribute_in_list(Attrs1, 'subscription', "remove"), Item = #xmlel{ns = ?NS_ROSTER, name = 'item', @@ -933,7 +933,7 @@ user_roster_item_parse_query(User, Server, Items, Query) -> nothing. us_to_list({User, Server}) -> - exmpp_jid:bare_jid_to_string(User, Server). + exmpp_jid:bare_jid_to_list(User, Server). webadmin_user(Acc, _User, _Server, Lang) -> Acc ++ [?XE("h3", [?ACT("roster/", "Roster")])]. diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index 9f980dd70..cf0690637 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -303,7 +303,7 @@ set_vcard(User, LServer, VCARD) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', value = "form"}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = - [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ exmpp_jid:jid_to_string(JID))}]}, + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ exmpp_jid:jid_to_list(JID))}]}, #xmlel{ns = ?NS_SEARCH, name = 'instructions', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Fill in the form to search " @@ -459,7 +459,7 @@ search_result(Lang, JID, ServerHost, Data) -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary( translate:translate(Lang, "Search Results for ") ++ - exmpp_jid:jid_to_string(JID))}]}, + exmpp_jid:jid_to_list(JID))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'reported', children = [?TLFIELD("text-single", "Jabber ID", "jid"), ?TLFIELD("text-single", "Full Name", "fn"), From 44d3e844a343555d415471de53116f555c97cd4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 14 Aug 2008 13:32:31 +0000 Subject: [PATCH 056/582] Accept 'undefined' as a language and treat it as the empty string. SVN Revision: 1522 --- ChangeLog | 5 +++++ src/translate.erl | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 8e2e1f4bf..900d7ce0b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-08-14 Jean-Sébastien Pédron + + * translate.erl (ascii_tolower): Accept 'undefined' as a language and + treat it as the empty string. + 2008-08-06 Jean-Sébastien Pédron * src/mod_offline.erl, src/mod_offline_odbc.erl, src/mod_echo.erl, diff --git a/src/translate.erl b/src/translate.erl index bc0af1399..bc1d9e0c9 100644 --- a/src/translate.erl +++ b/src/translate.erl @@ -159,5 +159,6 @@ ascii_tolower([C | Cs]) when C >= $A, C =< $Z -> ascii_tolower([C | Cs]) -> [C | ascii_tolower(Cs)]; ascii_tolower([]) -> + []; +ascii_tolower(undefined) -> []. - From 5e78c535726295d655bce8fe4a78a61b9abc0900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 14 Aug 2008 13:34:30 +0000 Subject: [PATCH 057/582] Remove the compatibility layer and always call modules with the new #iq record from Exmpp. SVN Revision: 1523 --- ChangeLog | 4 +++ src/ejabberd_local.erl | 36 +++++++------------- src/ejabberd_sm.erl | 22 ++++-------- src/gen_iq_handler.erl | 76 ++++++++---------------------------------- 4 files changed, 36 insertions(+), 102 deletions(-) diff --git a/ChangeLog b/ChangeLog index 900d7ce0b..18826707f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,10 @@ * translate.erl (ascii_tolower): Accept 'undefined' as a language and treat it as the empty string. + * src/gen_iq_handler.erl, src/ejabberd_local.erl, src/ejabberd_sm.erl: + Remove the compatibility layer and always call modules with the new + #iq record from Exmpp. + 2008-08-06 Jean-Sébastien Pédron * src/mod_offline.erl, src/mod_offline_odbc.erl, src/mod_echo.erl, diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index f047569f9..f06b821e6 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -74,47 +74,35 @@ start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). process_iq(From, To, Packet) -> - case exmpp_iq:get_kind(Packet) of - request -> + case exmpp_iq:xmlel_to_iq(Packet) of + #iq{kind = request, ns = XMLNS} = IQ_Rec -> Host = To#jid.ldomain, - Request = exmpp_iq:get_request(Packet), - XMLNS = exmpp_xml:get_ns_as_list(Request), case ets:lookup(?IQTABLE, {XMLNS, Host}) of [{_, Module, Function}] -> - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - % XXX OLD FORMAT: IQ_Rec is an #iq. - IQ_Rec = jlib:iq_query_info(Packet), - ResIQ = Module:Function(FromOld, ToOld, IQ_Rec), + ResIQ = Module:Function(From, To, IQ_Rec), if ResIQ /= ignore -> - % XXX OLD FORMAT: ResIQ. - ReplyOld = jlib:iq_to_xml(ResIQ), - Reply = exmpp_xml:xmlelement_to_xmlel(ReplyOld, - [?DEFAULT_NS], ?PREFIXED_NS), - ejabberd_router:route( - To, From, Reply); + Reply = exmpp_iq:iq_to_xmlel(ResIQ, To, From), + ejabberd_router:route(To, From, Reply); true -> ok end; [{_, Module, Function, Opts}] -> gen_iq_handler:handle(Host, Module, Function, Opts, - From, To, Packet); + From, To, IQ_Rec); [] -> - Err = exmpp_iq:error(Packet, 'feature-not-implemented'), + Err = exmpp_iq:error(Packet, 'feature-not-implemented'), ejabberd_router:route(To, From, Err) end; - response -> - process_iq_reply(From, To, Packet); + #iq{kind = response} = IQ_Rec -> + process_iq_reply(From, To, IQ_Rec); _ -> - Err = exmpp_iq:error(Packet, 'bad-request'), + Err = exmpp_iq:error(Packet, 'bad-request'), ejabberd_router:route(To, From, Err), ok end. -process_iq_reply(From, To, Packet) -> - ID = exmpp_stanza:get_id(Packet), +process_iq_reply(From, To, #iq{id = ID} = IQ_Rec) -> case catch mnesia:dirty_read(iq_response, ID) of [] -> ok; @@ -131,7 +119,7 @@ process_iq_reply(From, To, Packet) -> end, case mnesia:transaction(F) of {atomic, {Module, Function}} -> - Module:Function(From, To, Packet); + Module:Function(From, To, IQ_Rec); _ -> ok end diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 9300958d5..d9bc3c185 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -665,37 +665,27 @@ get_max_user_sessions(LUser, Host) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% process_iq(From, To, Packet) -> - case exmpp_iq:get_kind(Packet) of - request -> + case exmpp_iq:xmlel_to_iq(Packet) of + #iq{kind = request, ns = XMLNS} = IQ_Rec -> Host = To#jid.ldomain, - Request = exmpp_iq:get_request(Packet), - XMLNS = exmpp_xml:get_ns_as_list(Request), case ets:lookup(sm_iqtable, {XMLNS, Host}) of [{_, Module, Function}] -> - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - % XXX OLD FORMAT: IQ_Rec is an #iq. - IQ_Rec = jlib:iq_query_info(Packet), - ResIQ = Module:Function(FromOld, ToOld, IQ_Rec), + ResIQ = Module:Function(From, To, IQ_Rec), if ResIQ /= ignore -> - % XXX OLD FORMAT: ResIQ. - ReplyOld = jlib:iq_to_xml(ResIQ), - Reply = exmpp_xml:xmlelement_to_xmlel(ReplyOld, - [?DEFAULT_NS], ?PREFIXED_NS), + Reply = exmpp_iq:iq_to_xmlel(ResIQ, To, From), ejabberd_router:route(To, From, Reply); true -> ok end; [{_, Module, Function, Opts}] -> gen_iq_handler:handle(Host, Module, Function, Opts, - From, To, Packet); + From, To, IQ_Rec); [] -> Err = exmpp_iq:error(Packet, 'service-unavailable'), ejabberd_router:route(To, From, Err) end; - response -> + #iq{type = response} -> ok; _ -> Err = exmpp_iq:error(Packet, 'bad-request'), diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index 97a24efbb..b3e3beca5 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -49,13 +49,6 @@ module, function}). -% XXX OLD FORMAT: Re-include jlib.hrl (after clean-up). --record(iq, {id = "", - type, - xmlns = "", - lang = "", - sub_el}). - % XXX OLD FORMAT: modules not in the following list will receive % old format strudctures. -define(CONVERTED_MODULES, [ @@ -121,60 +114,33 @@ stop_iq_handler(_Module, _Function, Opts) -> ok end. -handle(Host, Module, Function, Opts, From, To, IQ) -> +handle(Host, Module, Function, Opts, From, To, IQ_Rec) -> case Opts of no_queue -> - process_iq(Host, Module, Function, From, To, IQ); + process_iq(Host, Module, Function, From, To, IQ_Rec); {one_queue, Pid} -> - Pid ! {process_iq, From, To, IQ}; + Pid ! {process_iq, From, To, IQ_Rec}; {queues, Pids} -> Pid = lists:nth(erlang:phash(now(), length(Pids)), Pids), - Pid ! {process_iq, From, To, IQ}; + Pid ! {process_iq, From, To, IQ_Rec}; parallel -> spawn(?MODULE, process_iq, - [Host, Module, Function, From, To, IQ]); + [Host, Module, Function, From, To, IQ_Rec]); _ -> todo end. -process_iq(Host, Module, Function, FromOld, ToOld, IQ_Rec) - when is_record(IQ_Rec, iq) -> - catch throw(for_stacktrace), % To have a stacktrace. - io:format("~nIQ HANDLER: old #iq for ~s:~s:~n~p~n~p~n~n", - [Module, Function, IQ_Rec, erlang:get_stacktrace()]), - From = jlib:from_old_jid(FromOld), - To = jlib:from_old_jid(ToOld), - IQOld = jlib:iq_to_xml(IQ_Rec), - IQOld1 = IQOld#xmlelement{children = [IQOld#xmlelement.children]}, - IQ = exmpp_xml:xmlelement_to_xmlel(IQOld1, - [?NS_JABBER_CLIENT], - [{?NS_XMPP, ?NS_XMPP_pfx}, - {?NS_DIALBACK, ?NS_DIALBACK_pfx}]), - process_iq(Host, Module, Function, From, To, IQ); -process_iq(_Host, Module, Function, From, To, IQ) -> - Ret = case lists:member(Module, ?CONVERTED_MODULES) of - true -> - catch Module:Function(From, To, IQ); - false -> - {FromOld, ToOld, IQ_Rec} = convert_to_old_structs( - Module, Function, From, To, IQ), - catch Module:Function(FromOld, ToOld, IQ_Rec) - end, - case Ret of - {'EXIT', Reason} -> - ?ERROR_MSG("~p", [Reason]); +process_iq(_Host, Module, Function, From, To, IQ_Rec) -> + try Module:Function(From, To, IQ_Rec) of ignore -> ok; - ResIQ when is_record(ResIQ, iq) -> - ReplyOld = jlib:iq_to_xml(ResIQ), - Reply = exmpp_xml:xmlelement_to_xmlel(ReplyOld, - [?NS_JABBER_CLIENT], - [{?NS_XMPP, ?NS_XMPP_pfx}, - {?NS_DIALBACK, ?NS_DIALBACK_pfx}]), - ejabberd_router:route(To, From, Reply); - Reply -> + ResIQ -> + Reply = exmpp_iq:iq_to_xmlel(ResIQ, To, From), ejabberd_router:route(To, From, Reply) + catch + _Class:Reason -> + ?ERROR_MSG("~p~n~p~n", [Reason, erlang:get_stacktrace()]) end. %%==================================================================== @@ -221,11 +187,11 @@ handle_cast(_Msg, State) -> %% {stop, Reason, State} %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- -handle_info({process_iq, From, To, IQ}, +handle_info({process_iq, From, To, IQ_Rec}, #state{host = Host, module = Module, function = Function} = State) -> - process_iq(Host, Module, Function, From, To, IQ), + process_iq(Host, Module, Function, From, To, IQ_Rec), {noreply, State}; handle_info(_Info, State) -> {noreply, State}. @@ -250,17 +216,3 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- - -convert_to_old_structs(Mod, Fun, From, To, IQ) -> - catch throw(for_stacktrace), % To have a stacktrace. - io:format("~nIQ HANDLER: ~s:~s expects old #iq:~n~p~n~p~n~n", - [Mod, Fun, IQ, erlang:get_stacktrace()]), - if - is_record(IQ, iq) -> - {From, To, IQ}; - true -> - F = jlib:to_old_jid(From), - T = jlib:to_old_jid(To), - I_Rec = jlib:iq_query_info(IQ), - {F, T, I_Rec} - end. From d8c3aae412d3dd99c8895a0aeae215d888702def Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 14 Aug 2008 13:36:11 +0000 Subject: [PATCH 058/582] Convert to the new #iq record from Exmpp. SVN Revision: 1524 --- ChangeLog | 5 + src/adhoc.erl | 8 +- src/mod_adhoc.erl | 30 ++--- src/mod_configure.erl | 4 +- src/mod_configure2.erl | 18 +-- src/mod_disco.erl | 294 ++++++++++++++++++++--------------------- src/mod_last.erl | 96 +++++++------- src/mod_roster.erl | 38 +++--- src/mod_vcard.erl | 112 +++++++--------- 9 files changed, 286 insertions(+), 319 deletions(-) diff --git a/ChangeLog b/ChangeLog index 18826707f..d45411378 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,11 @@ Remove the compatibility layer and always call modules with the new #iq record from Exmpp. + * src/mod_roster.erl, src/mod_vcard.erl, src/adhoc.erl, + src/mod_adhoc.erl, src/mod_configure.erl, src/mod_configure2.erl, + src/mod_disco.erl, src/mod_last.erl: Convert to the new #iq record + from Exmpp. + 2008-08-06 Jean-Sébastien Pédron * src/mod_offline.erl, src/mod_offline_odbc.erl, src/mod_echo.erl, diff --git a/src/adhoc.erl b/src/adhoc.erl index b338df068..0382062b0 100644 --- a/src/adhoc.erl +++ b/src/adhoc.erl @@ -38,18 +38,16 @@ %% Parse an ad-hoc request. Return either an adhoc_request record or %% an {error, ErrorType} tuple. -parse_request(IQ) -> +parse_request(#iq{type = Type, ns = NS, payload = SubEl, lang = Lang}) -> try - SubEl = exmpp_iq:get_request(IQ), - case {exmpp_iq:get_type(IQ), SubEl#xmlel.ns} of + case {Type, NS} of {set, ?NS_ADHOC} -> ?DEBUG("entering parse_request...", []), - Lang = exmpp_stanza:get_lang(IQ), Node = exmpp_xml:get_attribute(SubEl, 'node', ""), SessionID = exmpp_xml:get_attribute(SubEl, 'sessionid', ""), Action = exmpp_xml:get_attribute(SubEl, 'action', ""), XData = find_xdata_el(SubEl), - AllEls = SubEl#xmlel.ns, + AllEls = exmpp_xml:get_child_elements(SubEl), if XData -> Others = lists:delete(XData, AllEls); true -> diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl index c96c3e580..ad255f827 100644 --- a/src/mod_adhoc.erl +++ b/src/mod_adhoc.erl @@ -50,9 +50,9 @@ start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_ADHOC_s, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_ADHOC, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ADHOC_s, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ADHOC, ?MODULE, process_sm_iq, IQDisc), ejabberd_hooks:add(disco_local_identity, Host, ?MODULE, get_local_identity, 99), @@ -74,8 +74,8 @@ stop(Host) -> ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, get_local_features, 99), ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, get_local_identity, 99), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ADHOC_s), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ADHOC_s). + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ADHOC), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ADHOC). %------------------------------------------------------------------------- @@ -208,19 +208,19 @@ get_sm_features(Acc, _From, _To, _Node, _Lang) -> %------------------------------------------------------------------------- -process_local_iq(From, To, IQ) -> - process_adhoc_request(From, To, IQ, adhoc_local_commands). +process_local_iq(From, To, IQ_Rec) -> + process_adhoc_request(From, To, IQ_Rec, adhoc_local_commands). -process_sm_iq(From, To, IQ) -> - process_adhoc_request(From, To, IQ, adhoc_sm_commands). +process_sm_iq(From, To, IQ_Rec) -> + process_adhoc_request(From, To, IQ_Rec, adhoc_sm_commands). -process_adhoc_request(From, To, IQ, Hook) -> - ?DEBUG("About to parse ~p...", [IQ]), - case adhoc:parse_request(IQ) of +process_adhoc_request(From, To, IQ_Rec, Hook) -> + ?DEBUG("About to parse ~p...", [IQ_Rec]), + case adhoc:parse_request(IQ_Rec) of {error, Error} -> - exmpp_iq:error(IQ, Error); + exmpp_iq:error(IQ_Rec, Error); #adhoc_request{} = AdhocRequest -> Host = To#jid.ldomain, % XXX OLD FORMAT: From, To. @@ -231,11 +231,11 @@ process_adhoc_request(From, To, IQ, Hook) -> ignore -> ignore; empty -> - exmpp_iq:error(IQ, 'item-not-found'); + exmpp_iq:error(IQ_Rec, 'item-not-found'); {error, Error} -> - exmpp_iq:error(IQ, Error); + exmpp_iq:error(IQ_Rec, Error); Command -> - exmpp_iq:result(IQ, Command) + exmpp_iq:result(IQ_Rec, Command) end end. diff --git a/src/mod_configure.erl b/src/mod_configure.erl index c362963a6..f960eb08e 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -82,8 +82,8 @@ stop(Host) -> ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, get_local_identity, 50), ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, get_local_features, 50), ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, get_local_items, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ADHOC_s), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ADHOC_s). + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ADHOC), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ADHOC). %%%----------------------------------------------------------------------- diff --git a/src/mod_configure2.erl b/src/mod_configure2.erl index 2b6874112..9acec3fc1 100644 --- a/src/mod_configure2.erl +++ b/src/mod_configure2.erl @@ -47,22 +47,22 @@ start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE_s, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE, ?MODULE, process_local_iq, IQDisc), ok. stop(Host) -> - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE_s). + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE). -process_local_iq(From, To, IQ) -> +process_local_iq(From, To, #iq{type = Type, payload = Request} = IQ_Rec) -> case acl:match_rule(To#jid.ldomain, configure, From) of deny -> - exmpp_iq:error(IQ, 'not-allowed'); + exmpp_iq:error(IQ_Rec, 'not-allowed'); allow -> - case exmpp_iq:get_type(IQ) of + case Type of set -> - exmpp_iq:error(IQ, 'feature-not-implemented'); + exmpp_iq:error(IQ_Rec, 'feature-not-implemented'); %%case xml:get_tag_attr_s("type", SubEl) of %% "cancel" -> %% IQ#iq{type = result, @@ -96,11 +96,11 @@ process_local_iq(From, To, IQ) -> %% sub_el = [SubEl, ?ERR_NOT_ALLOWED]} %%end; get -> - case process_get(IQ#xmlel.children) of + case process_get(Request) of {result, Res} -> - exmpp_iq:result(IQ, Res); + exmpp_iq:result(IQ_Rec, Res); {error, Error} -> - exmpp_iq:error(IQ, Error) + exmpp_iq:error(IQ_Rec, Error) end end end. diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 517ef7a90..6907a4176 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -63,13 +63,13 @@ start(Host, Opts) -> ejabberd_local:refresh_iq_handlers(), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, atom_to_list(?NS_DISCO_ITEMS), + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS, ?MODULE, process_local_iq_items, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, atom_to_list(?NS_DISCO_INFO), + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO, ?MODULE, process_local_iq_info, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, atom_to_list(?NS_DISCO_ITEMS), + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_DISCO_ITEMS, ?MODULE, process_sm_iq_items, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, atom_to_list(?NS_DISCO_INFO), + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_DISCO_INFO, ?MODULE, process_sm_iq_info, IQDisc), catch ets:new(disco_features, [named_table, ordered_set, public]), @@ -101,10 +101,10 @@ stop(Host) -> ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, get_local_identity, 100), ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, get_local_features, 100), ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, get_local_services, 100), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, atom_to_list(?NS_DISCO_ITEMS)), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, atom_to_list(?NS_DISCO_INFO)), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, atom_to_list(?NS_DISCO_ITEMS)), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, atom_to_list(?NS_DISCO_INFO)), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_DISCO_ITEMS), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_DISCO_INFO), catch ets:match_delete(disco_features, {{'_', Host}}), catch ets:match_delete(disco_extra_domains, {{'_', Host}}), ok. @@ -126,75 +126,67 @@ unregister_extra_domain(Host, Domain) -> catch ets:new(disco_extra_domains, [named_table, ordered_set, public]), ets:delete(disco_extra_domains, {Domain, Host}). -process_local_iq_items(From, To, IQ) -> - case exmpp_iq:get_type(IQ) of - set -> - exmpp_iq:error(IQ, 'not-allowed'); - get -> - SubEl = exmpp_iq:get_request(IQ), - Node = exmpp_xml:get_attribute(SubEl, 'node', ""), - Host = To#jid.ldomain, - Lang = exmpp_stanza:get_lang(IQ), +process_local_iq_items(From, To, #iq{type = get, payload = SubEl, + lang = Lang} = IQ_Rec) -> + Host = To#jid.ldomain, + Node = exmpp_xml:get_attribute(SubEl, 'node', ""), - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - case ejabberd_hooks:run_fold(disco_local_items, - Host, - empty, - [FromOld, ToOld, Node, Lang]) of - {result, Items} -> - % XXX OLD FORMAT: Items might be an #xmlelement. - ANode = case Node of - "" -> []; - _ -> [#xmlattr{name = 'node', value = Node}] + % XXX OLD FORMAT: From, To. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), + case ejabberd_hooks:run_fold(disco_local_items, + Host, + empty, + [FromOld, ToOld, Node, Lang]) of + {result, Items} -> + % XXX OLD FORMAT: Items might be an #xmlelement. + ANode = case Node of + "" -> []; + _ -> [#xmlattr{name = 'node', value = Node}] + end, + Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', + attrs = ANode, children = Items}, + exmpp_iq:result(IQ_Rec, Result); + {error, Error} -> + % XXX OLD FORMAT: Error. + exmpp_iq:error(IQ_Rec, Error) + end; +process_local_iq_items(_From, _To, #iq{type = set} = IQ_Rec) -> + exmpp_iq:error(IQ_Rec, 'not-allowed'). + + +process_local_iq_info(From, To, #iq{type = get, payload = SubEl, + lang = Lang} = IQ_Rec) -> + Host = To#jid.ldomain, + Node = exmpp_xml:get_attribute(SubEl, 'node', ""), + % XXX OLD FORMAT: From, To. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), + % XXX OLD FORMAT: Identity might be an #xmlelement. + Identity = ejabberd_hooks:run_fold(disco_local_identity, + Host, + [], + [FromOld, ToOld, Node, Lang]), + % XXX OLD FORMAT: From, To. + case ejabberd_hooks:run_fold(disco_local_features, + Host, + empty, + [FromOld, ToOld, Node, Lang]) of + {result, Features} -> + ANode = case Node of + "" -> []; + _ -> [#xmlattr{name = 'node', value = Node}] end, - Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', - attrs = ANode, children = Items}, - exmpp_iq:result(IQ, Result); - {error, Error} -> - % XXX OLD FORMAT: Error. - exmpp_iq:error(IQ, Error) - end - end. - - -process_local_iq_info(From, To, IQ) -> - case exmpp_iq:get_type(IQ) of - set -> - exmpp_iq:error(IQ, 'not-allowed'); - get -> - Host = To#jid.ldomain, - SubEl = exmpp_iq:get_request(IQ), - Node = exmpp_xml:get_attribute(SubEl, 'node', ""), - Lang = exmpp_stanza:get_lang(IQ), - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - % XXX OLD FORMAT: Identity might be an #xmlelement. - Identity = ejabberd_hooks:run_fold(disco_local_identity, - Host, - [], - [FromOld, ToOld, Node, Lang]), - % XXX OLD FORMAT: From, To. - case ejabberd_hooks:run_fold(disco_local_features, - Host, - empty, - [FromOld, ToOld, Node, Lang]) of - {result, Features} -> - ANode = case Node of - "" -> []; - _ -> [#xmlattr{name = 'node', value = Node}] - end, - Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', - attrs = ANode, - children = Identity ++ lists:map(fun feature_to_xml/1, - Features)}, - exmpp_iq:result(IQ, Result); - {error, Error} -> - exmpp_iq:error(IQ, Error) - end - end. + Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', + attrs = ANode, + children = Identity ++ lists:map(fun feature_to_xml/1, + Features)}, + exmpp_iq:result(IQ_Rec, Result); + {error, Error} -> + exmpp_iq:error(IQ_Rec, Error) + end; +process_local_iq_info(_From, _To, #iq{type = set} = IQ_Rec) -> + exmpp_iq:error(IQ_Rec, 'not-allowed'). get_local_identity(Acc, _From, _To, [], _Lang) -> Acc ++ [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [ @@ -232,6 +224,10 @@ feature_to_xml({{Feature, _Host}}) -> feature_to_xml(Feature) when is_list(Feature) -> #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ #xmlattr{name = 'var', value = Feature} + ]}; +feature_to_xml(Feature) when is_atom(Feature) -> + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ + #xmlattr{name = 'var', value = atom_to_list(Feature)} ]}. domain_to_xml({Domain}) -> @@ -283,50 +279,46 @@ get_vh_services(Host) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -process_sm_iq_items(From, To, IQ) -> - SubEl = exmpp_iq:get_request(IQ), - case exmpp_iq:get_type(IQ) of - set -> - #jid{lnode = LTo, ldomain = ToServer} = To, - #jid{lnode = LFrom, ldomain = LServer} = From, - Self = (LTo == LFrom) andalso (ToServer == LServer), - Node = exmpp_xml:get_attribute(SubEl, 'node', ""), - if - Self, Node /= [] -> - %% Here, we treat disco publish attempts to your own JID. - Items = SubEl#xmlel.children, - case process_disco_publish({LFrom, LServer}, Node, Items) of - ok -> - exmpp_iq:result(IQ); - {error, Err} -> - exmpp_iq:error(IQ, Err) - end; - - true -> - exmpp_iq:error(IQ, 'not-allowed') +process_sm_iq_items(From, To, #iq{type = get, payload = SubEl, + lang = Lang} = IQ_Rec) -> + Host = To#jid.ldomain, + Node = exmpp_xml:get_attribute(SubEl, 'node', ""), + % XXX OLD FORMAT: From, To. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), + case ejabberd_hooks:run_fold(disco_sm_items, + Host, + empty, + [FromOld, ToOld, Node, Lang]) of + {result, Items} -> + ANode = case Node of + "" -> []; + _ -> [#xmlattr{name = 'node', value = Node}] + end, + Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', + attrs = ANode, children = Items}, + exmpp_iq:result(IQ_Rec, Result); + {error, Error} -> + exmpp_iq:error(IQ_Rec, Error) + end; +process_sm_iq_items(From, To, #iq{type = set, payload = SubEl} = IQ_Rec) -> + #jid{lnode = LTo, ldomain = ToServer} = To, + #jid{lnode = LFrom, ldomain = LServer} = From, + Self = (LTo == LFrom) andalso (ToServer == LServer), + Node = exmpp_xml:get_attribute(SubEl, 'node', ""), + if + Self, Node /= [] -> + %% Here, we treat disco publish attempts to your own JID. + Items = SubEl#xmlel.children, + case process_disco_publish({LFrom, LServer}, Node, Items) of + ok -> + exmpp_iq:result(IQ_Rec); + {error, Err} -> + exmpp_iq:error(IQ_Rec, Err) end; - get -> - Host = To#jid.ldomain, - Node = exmpp_xml:get_attribute(SubEl, 'node', ""), - Lang = exmpp_stanza:get_lang(IQ), - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - case ejabberd_hooks:run_fold(disco_sm_items, - Host, - empty, - [FromOld, ToOld, Node, Lang]) of - {result, Items} -> - ANode = case Node of - "" -> []; - _ -> [#xmlattr{name = 'node', value = Node}] - end, - Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', - attrs = ANode, children = Items}, - exmpp_iq:result(IQ, Result); - {error, Error} -> - exmpp_iq:error(IQ, Error) - end + + true -> + exmpp_iq:error(IQ_Rec, 'not-allowed') end. get_sm_items({error, _Error} = Acc, _From, _To, _Node, _Lang) -> @@ -359,41 +351,37 @@ get_sm_items(empty, From, To, _Node, _Lang) -> {error, 'not-allowed'} end. -process_sm_iq_info(From, To, IQ) -> - case exmpp_iq:get_type(IQ) of - set -> - exmpp_iq:error(IQ, 'not-allowed'); - get -> - Host = To#jid.ldomain, - SubEl = exmpp_iq:get_request(IQ), - Node = exmpp_xml:get_attribute(SubEl, 'node', ""), - Lang = exmpp_stanza:get_lang(IQ), - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - % XXX OLD FORMAT: Identity might be an #xmlelement. - Identity = ejabberd_hooks:run_fold(disco_sm_identity, - Host, - [], - [FromOld, ToOld, Node, Lang]), - case ejabberd_hooks:run_fold(disco_sm_features, - Host, - empty, - [FromOld, ToOld, Node, Lang]) of - {result, Features} -> - ANode = case Node of - "" -> []; - _ -> [#xmlattr{name = 'node', value = Node}] - end, - Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', - attrs = ANode, - children = Identity ++ lists:map(fun feature_to_xml/1, - Features)}, - exmpp_iq:result(IQ, Result); - {error, Error} -> - exmpp_iq:error(IQ, Error) - end - end. +process_sm_iq_info(From, To, #iq{type = get, payload = SubEl, + lang = Lang} = IQ_Rec) -> + Host = To#jid.ldomain, + Node = exmpp_xml:get_attribute(SubEl, 'node', ""), + % XXX OLD FORMAT: From, To. + FromOld = jlib:to_old_jid(From), + ToOld = jlib:to_old_jid(To), + % XXX OLD FORMAT: Identity might be an #xmlelement. + Identity = ejabberd_hooks:run_fold(disco_sm_identity, + Host, + [], + [FromOld, ToOld, Node, Lang]), + case ejabberd_hooks:run_fold(disco_sm_features, + Host, + empty, + [FromOld, ToOld, Node, Lang]) of + {result, Features} -> + ANode = case Node of + "" -> []; + _ -> [#xmlattr{name = 'node', value = Node}] + end, + Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', + attrs = ANode, + children = Identity ++ lists:map(fun feature_to_xml/1, + Features)}, + exmpp_iq:result(IQ_Rec, Result); + {error, Error} -> + exmpp_iq:error(IQ_Rec, Error) + end; +process_sm_iq_info(_From, _To, #iq{type = set} = IQ_Rec) -> + exmpp_iq:error(IQ_Rec, 'not-allowed'). get_sm_identity(Acc, _From, _To, _Node, _Lang) -> Acc. diff --git a/src/mod_last.erl b/src/mod_last.erl index dee915f86..b35ea1150 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -52,9 +52,9 @@ start(Host, Opts) -> [{disc_copies, [node()]}, {attributes, record_info(fields, last_activity)}]), update_table(), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY_s, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY_s, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY, ?MODULE, process_sm_iq, IQDisc), ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), @@ -66,62 +66,56 @@ stop(Host) -> ?MODULE, remove_user, 50), ejabberd_hooks:delete(unset_presence_hook, Host, ?MODULE, on_presence_update, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY_s), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY_s). + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY). -process_local_iq(_From, _To, IQ) -> - case exmpp_iq:get_type(IQ) of - set -> - exmpp_iq:error(IQ, 'not-allowed'); - get -> - Sec = trunc(element(1, erlang:statistics(wall_clock))/1000), - Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = - [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}]}, - exmpp_iq:result(IQ, Response) - end. +process_local_iq(_From, _To, #iq{type = get} = IQ_Rec) -> + Sec = trunc(element(1, erlang:statistics(wall_clock))/1000), + Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = + [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}]}, + exmpp_iq:result(IQ_Rec, Response); +process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> + exmpp_iq:error(IQ_Rec, 'not-allowed'). -process_sm_iq(From, To, IQ) -> - case exmpp_iq:get_type(IQ) of - set -> - exmpp_iq:error(IQ, 'not-allowed'); - get -> - User = To#jid.lnode, - Server = To#jid.ldomain, - {Subscription, _Groups} = - ejabberd_hooks:run_fold( - roster_get_jid_info, Server, - {none, []}, [User, Server, From]), - if - (Subscription == both) or (Subscription == from) -> - UserListRecord = ejabberd_hooks:run_fold( - privacy_get_user_list, Server, - #userlist{}, - [User, Server]), - case ejabberd_hooks:run_fold( - privacy_check_packet, Server, - allow, - [User, Server, UserListRecord, - {From, To, - exmpp_presence:available()}, - out]) of - allow -> - get_last(IQ, User, Server); - deny -> - exmpp_iq:error(IQ, 'not-allowed') - end; - true -> - exmpp_iq:error(IQ, 'not-allowed') - end - end. +process_sm_iq(From, To, #iq{type = get} = IQ_Rec) -> + User = To#jid.lnode, + Server = To#jid.ldomain, + {Subscription, _Groups} = + ejabberd_hooks:run_fold( + roster_get_jid_info, Server, + {none, []}, [User, Server, From]), + if + (Subscription == both) or (Subscription == from) -> + UserListRecord = ejabberd_hooks:run_fold( + privacy_get_user_list, Server, + #userlist{}, + [User, Server]), + case ejabberd_hooks:run_fold( + privacy_check_packet, Server, + allow, + [User, Server, UserListRecord, + {From, To, + exmpp_presence:available()}, + out]) of + allow -> + get_last(IQ_Rec, User, Server); + deny -> + exmpp_iq:error(IQ_Rec, 'not-allowed') + end; + true -> + exmpp_iq:error(IQ_Rec, 'not-allowed') + end; +process_sm_iq(_From, _To, #iq{type = set} = IQ_Rec) -> + exmpp_iq:error(IQ_Rec, 'not-allowed'). %% TODO: This function could use get_last_info/2 -get_last(IQ, LUser, LServer) -> +get_last(IQ_Rec, LUser, LServer) -> case catch mnesia:dirty_read(last_activity, {LUser, LServer}) of {'EXIT', _Reason} -> - exmpp_iq:error(IQ, 'internal-server-error'); + exmpp_iq:error(IQ_Rec, 'internal-server-error'); [] -> - exmpp_iq:error(IQ, 'service-unavailable'); + exmpp_iq:error(IQ_Rec, 'service-unavailable'); [#last_activity{timestamp = TimeStamp, status = Status}] -> {MegaSecs, Secs, _MicroSecs} = now(), TimeStamp2 = MegaSecs * 1000000 + Secs, @@ -129,7 +123,7 @@ get_last(IQ, LUser, LServer) -> Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}], children = [#xmlcdata{cdata = list_to_binary(Status)}]}, - exmpp_iq:result(IQ, Response) + exmpp_iq:result(IQ_Rec, Response) end. diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 57cc60f14..e67eb58c6 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -78,8 +78,7 @@ start(Host, Opts) -> ?MODULE, webadmin_page, 50), ejabberd_hooks:add(webadmin_user, Host, ?MODULE, webadmin_user, 50), - % XXX OLD FORMAT: NS as string. - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, atom_to_list(?NS_ROSTER), + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ROSTER, ?MODULE, process_iq, IQDisc). stop(Host) -> @@ -103,41 +102,38 @@ stop(Host) -> ?MODULE, webadmin_page, 50), ejabberd_hooks:delete(webadmin_user, Host, ?MODULE, webadmin_user, 50), - % XXX OLD FORMAT: NS as string. gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, - atom_to_list(?NS_ROSTER)). + ?NS_ROSTER). -process_iq(From, To, IQ) -> +process_iq(From, To, IQ_Rec) -> #jid{ldomain = LServer} = From, case lists:member(LServer, ?MYHOSTS) of true -> - process_local_iq(From, To, IQ); + process_local_iq(From, To, IQ_Rec); _ -> - exmpp_iq:error(IQ, 'item-not-found') + exmpp_iq:error(IQ_Rec, 'item-not-found') end. -process_local_iq(From, To, IQ) -> - case exmpp_iq:get_type(IQ) of - set -> - process_iq_set(From, To, IQ); - get -> - process_iq_get(From, To, IQ) - end. +process_local_iq(From, To, #iq{type = get} = IQ_Rec) -> + process_iq_get(From, To, IQ_Rec); +process_local_iq(From, To, #iq{type = set} = IQ_Rec) -> + process_iq_set(From, To, IQ_Rec). -process_iq_get(From, To, IQ) -> +process_iq_get(From, To, IQ_Rec) -> LUser = From#jid.lnode, LServer = From#jid.ldomain, US = {LUser, LServer}, case catch ejabberd_hooks:run_fold(roster_get, To#jid.ldomain, [], [US]) of Items when is_list(Items) -> XItems = lists:map(fun item_to_xml/1, Items), - exmpp_iq:result(IQ, #xmlel{ns = ?NS_ROSTER, name = 'query', - children = XItems}); + Result = #xmlel{ns = ?NS_ROSTER, name = 'query', + children = XItems}, + exmpp_iq:result(IQ_Rec, Result); _ -> - exmpp_iq:error(IQ, 'internal-server-error') + exmpp_iq:error(IQ_Rec, 'internal-server-error') end. get_user_roster(Acc, US) -> @@ -183,14 +179,14 @@ item_to_xml(Item) -> #xmlel{ns = ?NS_ROSTER, name = 'item', attrs = Attrs4, children = SubEls}. -process_iq_set(From, To, IQ) -> - case exmpp_iq:get_request(IQ) of +process_iq_set(From, To, #iq{payload = Request} = IQ_Rec) -> + case Request of #xmlel{children = Els} -> lists:foreach(fun(El) -> process_item_set(From, To, El) end, Els); _ -> ok end, - exmpp_iq:result(IQ). + exmpp_iq:result(IQ_Rec). process_item_set(From, To, #xmlel{} = Item) -> try diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index cf0690637..0447d5920 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -84,11 +84,9 @@ start(Host, Opts) -> ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - % XXX OLD FORMAT: NS as string. - gen_iq_handler:add_iq_handler(ejabberd_local, Host, atom_to_list(?NS_VCARD), + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD, ?MODULE, process_local_iq, IQDisc), - % XXX OLD FORMAT: NS as string. - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, atom_to_list(?NS_VCARD), + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD, ?MODULE, process_sm_iq, IQDisc), ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50), MyHost = gen_mod:get_opt_host(Host, Opts, "vjud.@HOST@"), @@ -126,12 +124,10 @@ loop(Host, ServerHost) -> stop(Host) -> ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50), - % XXX OLD FORMAT: NS as string. gen_iq_handler:remove_iq_handler(ejabberd_local, Host, - atom_to_list(?NS_VCARD)), - % XXX OLD FORMAT: NS as string. + ?NS_VCARD), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, - atom_to_list(?NS_VCARD)), + ?NS_VCARD), ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), Proc ! stop, @@ -155,63 +151,53 @@ get_sm_features(Acc, _From, _To, Node, _Lang) -> Acc end. -process_local_iq(_From, _To, IQ) -> - case exmpp_iq:get_type(IQ) of - set -> - exmpp_iq:error(IQ, 'not-allowed'); - get -> - Lang = case exmpp_stanza:get_lang(IQ) of - undefined -> ""; - L -> L - end, - Result = #xmlel{ns = ?NS_VCARD, name = 'vCard', children = [ - exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'FN'}, - "ejabberd"), - exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'URL'}, - ?EJABBERD_URI), - exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'DESC'}, - translate:translate(Lang, "Erlang Jabber Server") ++ - "\nCopyright (c) 2002-2008 ProcessOne"), - exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'BDAY'}, - "2002-11-16") - ]}, - exmpp_iq:result(IQ, Result) - end. +process_local_iq(_From, _To, #iq{type = get, lang = Lang} = IQ_Rec) -> + Result = #xmlel{ns = ?NS_VCARD, name = 'vCard', children = [ + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'FN'}, + "ejabberd"), + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'URL'}, + ?EJABBERD_URI), + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'DESC'}, + translate:translate(Lang, "Erlang Jabber Server") ++ + "\nCopyright (c) 2002-2008 ProcessOne"), + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'BDAY'}, + "2002-11-16") + ]}, + exmpp_iq:result(IQ_Rec, Result); +process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> + exmpp_iq:error(IQ_Rec, 'not-allowed'). -process_sm_iq(From, To, IQ) -> - case exmpp_iq:get_type(IQ) of - set -> - #jid{node = User, ldomain = LServer} = From, - case lists:member(LServer, ?MYHOSTS) of - true -> - set_vcard(User, LServer, exmpp_iq:get_request(IQ)), - exmpp_iq:result(IQ); - false -> - exmpp_iq:error(IQ, 'not-allowed') - end; - get -> - #jid{lnode = LUser, ldomain = LServer} = To, - US = {LUser, LServer}, - F = fun() -> - mnesia:read({vcard, US}) - end, - Els = case mnesia:transaction(F) of - {atomic, Rs} -> - lists:map(fun(R) -> - case R#vcard.vcard of - #xmlel{} = E -> - E; - #xmlelement{} = E -> - % XXX OLD FORMAT: Base contains old elements. - io:format("VCARD: Old element in base: ~p~n", [E]), - exmpp_xml:xmlelement_to_xmlel(E, [?NS_VCARD], []) - end - end, Rs); - {aborted, _Reason} -> - [] - end, - exmpp_iq:result(IQ, Els) +process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> + #jid{lnode = LUser, ldomain = LServer} = To, + US = {LUser, LServer}, + F = fun() -> + mnesia:read({vcard, US}) + end, + [VCard | _] = case mnesia:transaction(F) of + {atomic, Rs} -> + lists:map(fun(R) -> + case R#vcard.vcard of + #xmlel{} = E -> + E; + #xmlelement{} = E -> + % XXX OLD FORMAT: Base contains old elements. + io:format("VCARD: Old element in base: ~p~n", [E]), + exmpp_xml:xmlelement_to_xmlel(E, [?NS_VCARD], []) + end + end, Rs); + {aborted, _Reason} -> + [] + end, + exmpp_iq:result(IQ_Rec, VCard); +process_sm_iq(From, _To, #iq{type = set, payload = Request} = IQ_Rec) -> + #jid{node = User, ldomain = LServer} = From, + case lists:member(LServer, ?MYHOSTS) of + true -> + set_vcard(User, LServer, Request), + exmpp_iq:result(IQ_Rec); + false -> + exmpp_iq:error(IQ_Rec, 'not-allowed') end. set_vcard(User, LServer, VCARD) -> From ab75683bc9265990678b149c6d5599fd2129ecec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 26 Aug 2008 12:56:45 +0000 Subject: [PATCH 059/582] short_jid/1 and short_bare_jid/1 now produce a short JID from the user-provided JID parts. To obtain a short JID from the STRINGPREP'd parts, use the new short_prepd_jid/1 and short_prepd_bare_jid/1 functions. SVN Revision: 1543 --- ChangeLog | 7 +++++++ src/jlib.erl | 22 +++++++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index d45411378..a17316813 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2008-08-26 Jean-Sébastien Pédron + + * src/jlib.erl: short_jid/1 and short_bare_jid/1 now produce a short + JID from the user-provided JID parts. To obtain a short JID from the + STRINGPREP'd parts, use the new short_prepd_jid/1 and + short_prepd_bare_jid/1 functions. + 2008-08-14 Jean-Sébastien Pédron * translate.erl (ascii_tolower): Accept 'undefined' as a language and diff --git a/src/jlib.erl b/src/jlib.erl index 698e704e4..2268f326c 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -64,7 +64,9 @@ from_old_jid/1, to_old_jid/1, short_jid/1, - short_bare_jid/1]). + short_bare_jid/1, + short_prepd_jid/1, + short_prepd_bare_jid/1]). -include("jlib.hrl"). @@ -761,10 +763,20 @@ to_old_jid(#jid{user = Node, resource = Resource, JID#jid{user = Node1, resource = Resource1, luser = LNode1, lresource = LResource1}. -short_jid(JID) -> - JID1 = to_old_jid(JID), - {JID1#jid.luser, JID1#jid.lserver, JID1#jid.lresource}. +short_jid(JID1) -> + %JID1 = to_old_jid(JID), + {JID1#jid.user, JID1#jid.server, JID1#jid.resource}. short_bare_jid(JID) -> - JID1 = to_old_jid(exmpp_jid:jid_to_bare_jid(JID)), + %JID1 = to_old_jid(exmpp_jid:jid_to_bare_jid(JID)), + JID1 = exmpp_jid:jid_to_bare_jid(JID), + {JID1#jid.user, JID1#jid.server, JID1#jid.resource}. + +short_prepd_jid(JID1) -> + %JID1 = to_old_jid(JID), + {JID1#jid.luser, JID1#jid.lserver, JID1#jid.lresource}. + +short_prepd_bare_jid(JID) -> + %JID1 = to_old_jid(exmpp_jid:jid_to_bare_jid(JID)), + JID1 = exmpp_jid:jid_to_bare_jid(JID), {JID1#jid.luser, JID1#jid.lserver, JID1#jid.lresource}. From 5aead429644bb0a6e2c5b7bd21ee7c2521a6fc0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 26 Aug 2008 12:58:13 +0000 Subject: [PATCH 060/582] Use the new short_prepd_jid/1 function from jlib. SVN Revision: 1544 --- ChangeLog | 2 ++ src/acl.erl | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index a17316813..fc115fe9e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,8 @@ STRINGPREP'd parts, use the new short_prepd_jid/1 and short_prepd_bare_jid/1 functions. + * src/acl.erl: Use the new short_prepd_jid/1 function from jlib. + 2008-08-14 Jean-Sébastien Pédron * translate.erl (ascii_tolower): Accept 'undefined' as a language and diff --git a/src/acl.erl b/src/acl.erl index e65c34c4a..21bacf618 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -158,7 +158,7 @@ match_acl(ACL, JID, Host) -> all -> true; none -> false; _ -> - {User, Server, Resource} = jlib:short_jid(JID), + {User, Server, Resource} = jlib:short_prepd_jid(JID), lists:any(fun(#acl{aclspec = Spec}) -> case Spec of all -> From 80fcd2eb566628e25da5190cf2cec4a477948961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 26 Aug 2008 13:00:35 +0000 Subject: [PATCH 061/582] Remove commented-out code and use proper variable names. SVN Revision: 1545 --- ChangeLog | 3 ++- src/jlib.erl | 20 ++++++++------------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index fc115fe9e..c011e84b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,7 +3,8 @@ * src/jlib.erl: short_jid/1 and short_bare_jid/1 now produce a short JID from the user-provided JID parts. To obtain a short JID from the STRINGPREP'd parts, use the new short_prepd_jid/1 and - short_prepd_bare_jid/1 functions. + short_prepd_bare_jid/1 functions. Remove commented-out code and use + proper variable names. * src/acl.erl: Use the new short_prepd_jid/1 function from jlib. diff --git a/src/jlib.erl b/src/jlib.erl index 2268f326c..acf08a550 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -763,20 +763,16 @@ to_old_jid(#jid{user = Node, resource = Resource, JID#jid{user = Node1, resource = Resource1, luser = LNode1, lresource = LResource1}. -short_jid(JID1) -> - %JID1 = to_old_jid(JID), - {JID1#jid.user, JID1#jid.server, JID1#jid.resource}. +short_jid(JID) -> + {JID#jid.user, JID#jid.server, JID#jid.resource}. short_bare_jid(JID) -> - %JID1 = to_old_jid(exmpp_jid:jid_to_bare_jid(JID)), - JID1 = exmpp_jid:jid_to_bare_jid(JID), - {JID1#jid.user, JID1#jid.server, JID1#jid.resource}. + Bare_JID = exmpp_jid:jid_to_bare_jid(JID), + {Bare_JID#jid.user, Bare_JID#jid.server, Bare_JID#jid.resource}. -short_prepd_jid(JID1) -> - %JID1 = to_old_jid(JID), - {JID1#jid.luser, JID1#jid.lserver, JID1#jid.lresource}. +short_prepd_jid(JID) -> + {JID#jid.luser, JID#jid.lserver, JID#jid.lresource}. short_prepd_bare_jid(JID) -> - %JID1 = to_old_jid(exmpp_jid:jid_to_bare_jid(JID)), - JID1 = exmpp_jid:jid_to_bare_jid(JID), - {JID1#jid.luser, JID1#jid.lserver, JID1#jid.lresource}. + Bare_JID = exmpp_jid:jid_to_bare_jid(JID), + {Bare_JID#jid.luser, Bare_JID#jid.lserver, Bare_JID#jid.lresource}. From 9f0d79da9a750ce4da28e3d833dc2b6b008ac74e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 26 Aug 2008 13:38:49 +0000 Subject: [PATCH 062/582] o Use the new functions from jlib. o Remove the compatibility code. It's becoming confusing to handle every case every where. Also, in JIDs (normal and short), the atom "undefined' is expected, not the empty string anymore! SVN Revision: 1546 --- ChangeLog | 13 ++- src/ejabberd_c2s.erl | 235 ++++++++++----------------------------- src/ejabberd_local.erl | 7 +- src/ejabberd_router.erl | 22 +--- src/ejabberd_s2s.erl | 7 +- src/ejabberd_s2s_in.erl | 23 ++-- src/ejabberd_s2s_out.erl | 10 +- src/ejabberd_sm.erl | 44 ++------ 8 files changed, 99 insertions(+), 262 deletions(-) diff --git a/ChangeLog b/ChangeLog index c011e84b1..32a5d3c7a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,9 +4,18 @@ JID from the user-provided JID parts. To obtain a short JID from the STRINGPREP'd parts, use the new short_prepd_jid/1 and short_prepd_bare_jid/1 functions. Remove commented-out code and use - proper variable names. + proper variable names. Those functions use the atom 'undefined' and + NOT the empty string anymore! - * src/acl.erl: Use the new short_prepd_jid/1 function from jlib. + * src/acl.erl, src/ejabberd_router.erl: Use the new functions from + jlib. + + * src/ejabberd_router.erl, src/ejabberd_local.erl, + src/ejabberd_sm.erl, src/ejabberd_s2s.erl, src/ejabberd_s2s_in.erl, + src/ejabberd_s2s_out.erl, src/ejabberd_c2s.erl: Remove the + compatibility code. It's becoming confusing to handle every case every + where. Also, in JIDs (normal and short), the atom "undefined' is + expected, not the empty string anymore! 2008-08-14 Jean-Sébastien Pédron diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index d006e2a5a..6c86d1149 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -76,7 +76,7 @@ tls_options = [], authenticated = false, jid, - user = "", server = ?MYNAME, resource = "", + user = undefined, server = ?MYNAME, resource = undefined, sid, pres_t = ?SETS:new(), pres_f = ?SETS:new(), @@ -273,12 +273,10 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> false -> [] end, - % XXX OLD FORMAT: Other_Feats. - Other_FeatsOld = ejabberd_hooks:run_fold( + Other_Feats = ejabberd_hooks:run_fold( c2s_stream_features, Server, [], []), - Other_Feats = [exmpp_xml:xmlelement_to_xmlel(F, [?DEFAULT_NS], ?PREFIXED_NS) || F <- Other_FeatsOld], send_element(StateData, exmpp_stream:features( TLSFeature ++ @@ -292,7 +290,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> lang = Lang}); _ -> case StateData#state.resource of - "" -> + undefined -> send_element( StateData, exmpp_stream:features([ @@ -413,7 +411,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> StateData#state.server, {[], []}, [U, StateData#state.server]), - LJID = jlib:short_bare_jid(JID), + LJID = jlib:short_prepd_bare_jid(JID), Fs1 = [LJID | Fs], Ts1 = [LJID | Ts], PrivList = ejabberd_hooks:run_fold( @@ -728,7 +726,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> StateData#state.server, {[], []}, [U, StateData#state.server]), - LJID = jlib:short_bare_jid(JID), + LJID = jlib:short_prepd_bare_jid(JID), Fs1 = [LJID | Fs], Ts1 = [LJID | Ts], PrivList = @@ -744,10 +742,8 @@ wait_for_session({xmlstreamelement, El}, StateData) -> pres_t = ?SETS:from_list(Ts1), privacy_list = PrivList}); _ -> - % XXX OLD FORMAT: Jid. - JIDOld = jlib:to_old_jid(JID), ejabberd_hooks:run(forbidden_session_hook, - StateData#state.server, [JIDOld]), + StateData#state.server, [JID]), ?INFO_MSG("(~w) Forbidden session for ~s", [StateData#state.socket, exmpp_jid:jid_to_list(JID)]), @@ -801,22 +797,15 @@ session_established({xmlstreamelement, El}, StateData) -> end, NewState = case El of #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence'} -> - % XXX OLD FORMAT: NewEl. - PresenceElOld = ejabberd_hooks:run_fold( + PresenceEl = ejabberd_hooks:run_fold( c2s_update_presence, Server, - exmpp_xml:xmlel_to_xmlelement(NewEl, - [?DEFAULT_NS], ?PREFIXED_NS), + NewEl, [User, Server]), - PresenceEl = exmpp_xml:xmlelement_to_xmlel(PresenceElOld, - [?DEFAULT_NS], ?PREFIXED_NS), - % XXX OLD FORMAT: PresenceElOld, *JID. - FromJIDOld = jlib:to_old_jid(FromJID), - ToJIDOld = jlib:to_old_jid(ToJID), ejabberd_hooks:run( user_send_packet, Server, - [FromJIDOld, ToJIDOld, PresenceElOld]), + [FromJID, ToJID, PresenceEl]), case ToJID of #jid{node = User, domain = Server, @@ -830,43 +819,29 @@ session_established({xmlstreamelement, El}, StateData) -> StateData) end; #xmlel{ns = ?NS_JABBER_CLIENT, name = 'iq'} -> - % XXX OLD FORMAT: JIDs. - FromJIDOld = jlib:to_old_jid(FromJID), - ToJIDOld = jlib:to_old_jid(ToJID), - case exmpp_iq:get_payload(El) of - #xmlel{ns = ?NS_PRIVACY} -> + case exmpp_iq:xmlel_to_iq(El) of + #iq{kind = request, ns = ?NS_PRIVACY} = IQ_Rec -> process_privacy_iq( - FromJID, ToJID, El, StateData); + FromJID, ToJID, IQ_Rec, StateData); _ -> - % XXX OLD FORMAT: NewElOld. - NewElOld = exmpp_xml:xmlel_to_xmlelement(NewEl, - [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_hooks:run( user_send_packet, Server, - [FromJIDOld, ToJIDOld, NewElOld]), + [FromJID, ToJID, NewEl]), ejabberd_router:route( FromJID, ToJID, NewEl), StateData end; #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message'} -> - % XXX OLD FORMAT: NewElOld, JIDs. - NewElOld = exmpp_xml:xmlel_to_xmlelement(NewEl, - [?DEFAULT_NS], ?PREFIXED_NS), - FromJIDOld = jlib:to_old_jid(FromJID), - ToJIDOld = jlib:to_old_jid(ToJID), ejabberd_hooks:run(user_send_packet, Server, - [FromJIDOld, ToJIDOld, NewElOld]), + [FromJID, ToJID, NewEl]), ejabberd_router:route(FromJID, ToJID, NewEl), StateData; _ -> StateData end, - % XXX OLD FORMAT: El. - ElOld = exmpp_xml:xmlel_to_xmlelement(El, - [?DEFAULT_NS], ?PREFIXED_NS), - ejabberd_hooks:run(c2s_loop_debug, [{xmlstreamelement, ElOld}]), + ejabberd_hooks:run(c2s_loop_debug, [{xmlstreamelement, El}]), fsm_next_state(session_established, NewState) catch throw:{stringprep, _, _, _} -> @@ -879,10 +854,7 @@ session_established({xmlstreamelement, El}, StateData) -> 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}]), + ejabberd_hooks:run(c2s_loop_debug, [{xmlstreamelement, El}]), fsm_next_state(session_established, StateData); throw:Exception -> io:format("SESSION ESTABLISHED: Exception=~p~n", [Exception]), @@ -963,9 +935,8 @@ handle_sync_event({get_presence}, _From, StateName, StateData) -> handle_sync_event(get_subscribed_and_online, _From, StateName, StateData) -> Subscribed = StateData#state.pres_f, Online = StateData#state.pres_available, - % XXX OLF FORMAT: short JID with empty string(s). Pred = fun({U, S, _R} = User, _Caps) -> - ?SETS:is_element({U, S, ""}, + ?SETS:is_element({U, S, undefined}, Subscribed) orelse ?SETS:is_element(User, Subscribed) end, @@ -994,19 +965,14 @@ handle_info(replaced, _StateName, StateData) -> send_element(StateData, exmpp_stream:error('conflict')), send_element(StateData, exmpp_stream:closing()), {stop, normal, StateData#state{authenticated = replaced}}; -handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> - %% XXX OLD FORMAT: From, To and Packet are in the old format. - Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, - [?DEFAULT_NS], ?PREFIXED_NS), - From = jlib:from_old_jid(FromOld), - To = jlib:from_old_jid(ToOld), +handle_info({route, From, To, Packet}, StateName, StateData) -> {Pass, NewAttrs, NewState} = case Packet of #xmlel{attrs = Attrs} when ?IS_PRESENCE(Packet) -> case exmpp_presence:get_type(Packet) of 'probe' -> - LFrom = jlib:short_jid(From), - LBFrom = jlib:short_bare_jid(From), + LFrom = jlib:short_prepd_jid(From), + LBFrom = jlib:short_prepd_bare_jid(From), NewStateData = case ?SETS:is_element( LFrom, StateData#state.pres_a) orelse @@ -1038,7 +1004,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> process_presence_probe(From, To, NewStateData), {false, Attrs, NewStateData}; 'error' -> - LFrom = jlib:short_jid(From), + LFrom = jlib:short_prepd_jid(From), NewA = remove_element(LFrom, StateData#state.pres_a), {true, Attrs, StateData#state{pres_a = NewA}}; @@ -1055,18 +1021,17 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> 'unsubscribed' -> {true, Attrs, StateData}; _ -> - % XXX OLD FORMAT: From, To, Packet. case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {FromOld, ToOld, PacketOld}, + {From, To, Packet}, in]) of allow -> - LFrom = jlib:short_jid(From), - LBFrom = jlib:short_bare_jid(From), + LFrom = jlib:short_prepd_jid(From), + LBFrom = jlib:short_prepd_bare_jid(From), %% Note contact availability Els = Packet#xmlel.children, Caps = mod_caps:read_caps(Els), @@ -1144,9 +1109,7 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> case exmpp_iq:get_request(Packet) of #xmlel{ns = ?NS_VCARD} -> Host = StateData#state.server, - % XXX OLD FORMAT: sm_iqtable contains strings - % for namespaces. - case ets:lookup(sm_iqtable, {atom_to_list(?NS_VCARD), Host}) of + case ets:lookup(sm_iqtable, {?NS_VCARD, Host}) of [{_, Module, Function, Opts}] -> gen_iq_handler:handle(Host, Module, Function, Opts, From, To, Packet); @@ -1156,14 +1119,13 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> end, {false, Attrs, StateData}; _ -> - % XXX OLD FORMAT: From, To and Packet. case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {FromOld, ToOld, PacketOld}, + {From, To, Packet}, in]) of allow -> {true, Attrs, StateData}; @@ -1177,14 +1139,13 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> {true, Attrs, StateData} end; #xmlel{attrs = Attrs} when ?IS_MESSAGE(Packet) -> - % XXX OLD FORMAT: From, To and Packet. case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {FromOld, ToOld, PacketOld}, + {From, To, Packet}, in]) of allow -> {true, Attrs, StateData}; @@ -1203,19 +1164,13 @@ handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> Attrs3 = exmpp_stanza:set_recipient_in_attrs(Attrs2, To), FixedPacket = Packet#xmlel{attrs = Attrs3}, send_element(StateData, FixedPacket), - % XXX OLD FORMAT: JID, From, To, FixedPacket. - JIDOld = jlib:to_old_jid(StateData#state.jid), - FixedPacketOld = exmpp_xml:xmlel_to_xmlelement(FixedPacket, - [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_hooks:run(user_receive_packet, StateData#state.server, - [JIDOld, FromOld, ToOld, FixedPacketOld]), - % XXX OLD FORMAT: From, To, FixedPacket. - ejabberd_hooks:run(c2s_loop_debug, [{route, FromOld, ToOld, PacketOld}]), + [StateData#state.jid, From, To, FixedPacket]), + ejabberd_hooks:run(c2s_loop_debug, [{route, From, To, Packet}]), fsm_next_state(StateName, NewState); true -> - % XXX OLD FORMAT: From, To, FixedPacket. - ejabberd_hooks:run(c2s_loop_debug, [{route, FromOld, ToOld, PacketOld}]), + ejabberd_hooks:run(c2s_loop_debug, [{route, From, To, Packet}]), fsm_next_state(StateName, NewState) end; handle_info({'DOWN', Monitor, _Type, _Object, _Info}, _StateName, StateData) @@ -1353,8 +1308,8 @@ get_conn_type(StateData) -> end. process_presence_probe(From, To, StateData) -> - LFrom = jlib:short_jid(From), - LBFrom = jlib:short_bare_jid(From), + LFrom = jlib:short_prepd_jid(From), + LBFrom = jlib:short_prepd_bare_jid(From), case StateData#state.pres_last of undefined -> ok; @@ -1375,25 +1330,19 @@ process_presence_probe(From, To, StateData) -> if Cond1 -> Packet = StateData#state.pres_last, - % XXX OLD FORMAT: From, To, Packet. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - [?DEFAULT_NS], ?PREFIXED_NS), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {ToOld, FromOld, PacketOld}, + {To, From, Packet}, out]) of deny -> ok; allow -> Pid=element(2, StateData#state.sid), - % XXX OLD FORMAT: From, To. - ejabberd_hooks:run(presence_probe_hook, StateData#state.server, [FromOld, ToOld, Pid]), + ejabberd_hooks:run(presence_probe_hook, StateData#state.server, [From, To, Pid]), %% Don't route a presence probe to oneself case From == To of false -> @@ -1491,11 +1440,9 @@ presence_update(From, Packet, StateData) -> NewState = if FromUnavail -> - % XXX OLD FORMAT: JID. - JIDOld = jlib:to_old_jid(StateData#state.jid), ejabberd_hooks:run(user_available_hook, StateData#state.server, - [JIDOld]), + [StateData#state.jid]), if NewPriority >= 0 -> resend_offline_messages(StateData), resend_subscription_requests(StateData); @@ -1525,15 +1472,10 @@ presence_update(From, Packet, StateData) -> end. presence_track(From, To, Packet, StateData) -> - LTo = jlib:short_jid(To), + LTo = jlib:short_prepd_jid(To), User = StateData#state.user, Server = StateData#state.server, BFrom = exmpp_jid:jid_to_bare_jid(From), - % XXX OLD FORMAT: From, To, Packet. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - [?DEFAULT_NS], ?PREFIXED_NS), case exmpp_presence:get_type(Packet) of 'unavailable' -> ejabberd_router:route(From, To, Packet), @@ -1548,31 +1490,27 @@ presence_track(From, To, Packet, StateData) -> StateData#state{pres_i = I, pres_a = A}; 'subscribe' -> - % XXX OLD FORMAT: To. ejabberd_hooks:run(roster_out_subscription, Server, - [User, Server, ToOld, subscribe]), + [User, Server, To, subscribe]), ejabberd_router:route(BFrom, To, Packet), StateData; 'subscribed' -> - % XXX OLD FORMAT: To. ejabberd_hooks:run(roster_out_subscription, Server, - [User, Server, ToOld, subscribed]), + [User, Server, To, subscribed]), ejabberd_router:route(BFrom, To, Packet), StateData; 'unsubscribe' -> - % XXX OLD FORMAT: To. ejabberd_hooks:run(roster_out_subscription, Server, - [User, Server, ToOld, unsubscribe]), + [User, Server, To, unsubscribe]), ejabberd_router:route(BFrom, To, Packet), StateData; 'unsubscribed' -> - % XXX OLD FORMAT: To. ejabberd_hooks:run(roster_out_subscription, Server, - [User, Server, ToOld, unsubscribed]), + [User, Server, To, unsubscribed]), ejabberd_router:route(BFrom, To, Packet), StateData; 'error' -> @@ -1582,14 +1520,13 @@ presence_track(From, To, Packet, StateData) -> ejabberd_router:route(From, To, Packet), StateData; _ -> - % XXX OLD FORMAT: From, To, Packet. case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {FromOld, ToOld, PacketOld}, + {From, To, Packet}, out]) of deny -> ok; @@ -1605,18 +1542,13 @@ presence_track(From, To, Packet, StateData) -> presence_broadcast(StateData, From, JIDSet, Packet) -> lists:foreach(fun({U, S, R}) -> FJID = exmpp_jid:make_jid(U, S, R), - % XXX OLD FORMAT: From, FJID, Packet. - FJIDOld = jlib:to_old_jid(FJID), - FromOld = jlib:to_old_jid(From), - PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - [?DEFAULT_NS], ?PREFIXED_NS), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {FromOld, FJIDOld, PacketOld}, + {From, FJID, Packet}, out]) of deny -> ok; @@ -1626,24 +1558,18 @@ presence_broadcast(StateData, From, JIDSet, Packet) -> end, ?SETS:to_list(JIDSet)). presence_broadcast_to_trusted(StateData, From, T, A, Packet) -> - % XXX OLD FORMAT: From, Packet. - FromOld = jlib:to_old_jid(From), - PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - [?DEFAULT_NS], ?PREFIXED_NS), lists:foreach( fun({U, S, R} = JID) -> case ?SETS:is_element(JID, T) of true -> FJID = exmpp_jid:make_jid(U, S, R), - % XXX OLD FORMAT: FJID. - FJIDOld = jlib:to_old_jid(FJID), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {FromOld, FJIDOld, PacketOld}, + {From, FJID, Packet}, out]) of deny -> ok; @@ -1675,18 +1601,13 @@ presence_broadcast_first(From, StateData, Packet) -> As = ?SETS:fold( fun({U, S, R} = JID, A) -> FJID = exmpp_jid:make_jid(U, S, R), - % XXX OLD FORMAT: From, FJID, Packet. - FromOld = jlib:to_old_jid(From), - FJIDOld = jlib:to_old_jid(FJID), - PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - [?DEFAULT_NS], ?PREFIXED_NS), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {FromOld, FJIDOld, PacketOld}, + {From, FJID, Packet}, out]) of deny -> ok; @@ -1711,7 +1632,7 @@ remove_element(E, Set) -> roster_change(IJID, ISubscription, StateData) -> - LIJID = jlib:short_jid(IJID), + LIJID = jlib:short_prepd_jid(IJID), IsFrom = (ISubscription == both) or (ISubscription == from), IsTo = (ISubscription == both) or (ISubscription == to), OldIsFrom = ?SETS:is_element(LIJID, StateData#state.pres_f), @@ -1734,9 +1655,6 @@ roster_change(IJID, ISubscription, StateData) -> ?DEBUG("roster changed for ~p~n", [StateData#state.user]), From = StateData#state.jid, To = IJID, - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), Cond1 = (not StateData#state.pres_invis) and IsFrom and (not OldIsFrom), Cond2 = (not IsFrom) and OldIsFrom @@ -1745,17 +1663,13 @@ roster_change(IJID, ISubscription, StateData) -> if Cond1 -> ?DEBUG("C1: ~p~n", [LIJID]), - % XXX OLD FORMAT: P. - POld = exmpp_xml:xmlelement_to_xmlel(P, - [?DEFAULT_NS], ?PREFIXED_NS), - % XXX OLD FORMAT: From, To, P. case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {FromOld, ToOld, POld}, + {From, To, P}, out]) of deny -> ok; @@ -1770,17 +1684,13 @@ roster_change(IJID, ISubscription, StateData) -> Cond2 -> ?DEBUG("C2: ~p~n", [LIJID]), PU = exmpp_presence:unavailable(), - % XXX OLD FORMAT: PU. - PUOld = exmpp_xml:xmlelement_to_xmlel(PU, - [?DEFAULT_NS], ?PREFIXED_NS), - % XXX OLD FORMAT: From, To, PU. case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, [StateData#state.user, StateData#state.server, StateData#state.privacy_list, - {FromOld, ToOld, PUOld}, + {From, To, PU}, out]) of deny -> ok; @@ -1813,26 +1723,21 @@ update_priority(Priority, Packet, StateData) -> Info). process_privacy_iq(From, To, - El, + #iq{type = Type} = IQ_Rec, StateData) -> - % XXX OLD FORMAT: IQ_Rec is an #iq. - IQ_Rec = jlib:iq_query_info(El), - % XXX OLD FORMAT: JIDs. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), {Res, NewStateData} = - case exmpp_iq:get_type(El) of + case Type of get -> R = ejabberd_hooks:run_fold( privacy_iq_get, StateData#state.server, {error, ?ERR_FEATURE_NOT_IMPLEMENTED}, - [FromOld, ToOld, IQ_Rec, StateData#state.privacy_list]), + [From, To, IQ_Rec, StateData#state.privacy_list]), {R, StateData}; set -> case ejabberd_hooks:run_fold( privacy_iq_set, StateData#state.server, {error, ?ERR_FEATURE_NOT_IMPLEMENTED}, - [FromOld, ToOld, IQ_Rec]) of + [From, To, IQ_Rec]) of {result, R, NewPrivList} -> {{result, R}, StateData#state{privacy_list = NewPrivList}}; @@ -1841,14 +1746,10 @@ process_privacy_iq(From, To, end, IQRes = case Res of - {result, ResultOld} -> - Result = exmpp_xml:xmlelement_to_xmlel(ResultOld, - [?DEFAULT_NS], ?PREFIXED_NS), - exmpp_iq:result(El, Result); - {error, ErrorOld} -> - Error = exmpp_xml:xmlelement_to_xmlel(ErrorOld, - [?DEFAULT_NS], ?PREFIXED_NS), - exmpp_iq:error(El, Error) + {result, Result} -> + exmpp_iq:result(IQ_Rec, Result); + {error, Error} -> + exmpp_iq:error(IQ_Rec, Error) end, ejabberd_router:route( To, From, IQRes), @@ -1863,18 +1764,16 @@ resend_offline_messages(#state{user = User, [], [User, Server]) of Rs when list(Rs) -> - % XXX OLD FORMAT: From, To, Packet. - % XXX OLD FORMAT ON DISK! lists:foreach( fun({route, - FromOld, ToOld, PacketOld}) -> + From, To, Packet}) -> Pass = case ejabberd_hooks:run_fold( privacy_check_packet, Server, allow, [User, Server, PrivList, - {FromOld, ToOld, PacketOld}, + {From, To, Packet}, in]) of allow -> true; @@ -1883,11 +1782,6 @@ resend_offline_messages(#state{user = User, end, if Pass -> - % XXX OLD FORMAT: From, To, Packet. - From = jlib:from_old_jid(FromOld), - To = jlib:from_old_jid(ToOld), - Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, - [?DEFAULT_NS], ?PREFIXED_NS), Attrs1 = exmpp_stanza:set_sender_in_attrs( Packet#xmlel.attrs, From), Attrs2 = exmpp_stanza:set_recipient_in_attrs( @@ -1907,11 +1801,7 @@ resend_subscription_requests(#state{user = User, Server, [], [User, Server]), - % XXX OLD FORMAT: XMLPacket. - % XXX OLD FORMAT ON DISK! - lists:foreach(fun(XMLPacketOld) -> - XMLPacket = exmpp_xml:xmlelement_to_xmlel( - XMLPacketOld, [?DEFAULT_NS], ?PREFIXED_NS), + lists:foreach(fun(XMLPacket) -> send_element(StateData, XMLPacket) end, @@ -1920,14 +1810,13 @@ resend_subscription_requests(#state{user = User, process_unauthenticated_stanza(StateData, El) -> case exmpp_iq:get_kind(El) of request -> - % XXX OLD FORMAT: IQ_Rec is an #iq. - IQ_Rec = jlib:iq_query_info(El), - ResOld = ejabberd_hooks:run_fold(c2s_unauthenticated_iq, + IQ_Rec = exmpp_iq:xmlel_to_iq(El), + Res = ejabberd_hooks:run_fold(c2s_unauthenticated_iq, StateData#state.server, empty, [StateData#state.server, IQ_Rec, StateData#state.ip]), - case ResOld of + case Res of empty -> % The only reasonable IQ's here are auth and register IQ's % They contain secrets, so don't include subelements to response @@ -1938,8 +1827,6 @@ process_unauthenticated_stanza(StateData, El) -> Res2 = exmpp_stanza:remove_recipient(Res1), send_element(StateData, Res2); _ -> - Res = exmpp_xml:xmlelement_to_xmlel(ResOld, - [?DEFAULT_NS], ?PREFIXED_NS), send_element(StateData, Res) end; _ -> diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index f06b821e6..d77eb6968 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -321,14 +321,9 @@ do_route(From, To, Packet) -> "error" -> ok; "result" -> ok; _ -> - % XXX OLD FORMAT: From, To, Packet. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_hooks:run(local_send_to_resource_hook, To#jid.ldomain, - [FromOld, ToOld, PacketOld]) + [From, To, Packet]) end end. diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index cd7f02002..04bc76285 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -321,19 +321,9 @@ code_change(_OldVsn, State, _Extra) -> do_route(OrigFrom, OrigTo, OrigPacket) -> ?DEBUG("route~n\tfrom ~p~n\tto ~p~n\tpacket ~p~n", [OrigFrom, OrigTo, OrigPacket]), - % XXX OLD FORMAT: OrigFrom, OrigTo, OrigPacket. - OrigFromOld = jlib:to_old_jid(OrigFrom), - OrigToOld = jlib:to_old_jid(OrigTo), - OrigPacketOld = exmpp_xml:xmlel_to_xmlelement(OrigPacket, - [?NS_JABBER_CLIENT], [{?NS_XMPP, ?NS_XMPP_pfx}]), case ejabberd_hooks:run_fold(filter_packet, - {OrigFromOld, OrigToOld, OrigPacketOld}, []) of - {FromOld, ToOld, PacketOld} -> - % XXX OLD FORMAT: From, To, Packet. - From = jlib:from_old_jid(FromOld), - To = jlib:from_old_jid(ToOld), - Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, - [?NS_JABBER_CLIENT], [{?NS_XMPP, ?NS_XMPP_pfx}]), + {OrigFrom, OrigTo, OrigPacket}, []) of + {From, To, Packet} -> LDstDomain = To#jid.ldomain, case mnesia:dirty_read(route, LDstDomain) of [] -> @@ -358,12 +348,12 @@ do_route(OrigFrom, OrigTo, OrigPacket) -> {domain_balancing, LDstDomain}) of undefined -> now(); random -> now(); - source -> jlib:short_jid(From); - destination -> jlib:short_jid(To); + source -> jlib:short_prepd_jid(From); + destination -> jlib:short_prepd_jid(To); bare_source -> - jlib:short_bare_jid(From); + jlib:short_prepd_bare_jid(From); bare_destination -> - jlib:short_bare_jid(To) + jlib:short_prepd_bare_jid(To) end, case get_component_number(LDstDomain) of undefined -> diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index b8af4251f..492484c31 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -283,15 +283,10 @@ do_route(From, To, Packet) -> NewPacket1 = exmpp_stanza:set_sender(Packet, From), NewPacket = exmpp_stanza:set_recipient(NewPacket1, To), #jid{ldomain = MyServer} = From, - % XXX OLD FORMAT: From, To, NewPacket. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - NewPacketOld = exmpp_xml:xmlel_to_xmlelement(NewPacket, - [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_hooks:run( s2s_send_packet, MyServer, - [FromOld, ToOld, NewPacketOld]), + [From, To, NewPacket]), send_element(Pid, NewPacket), ok; {aborted, _Reason} -> diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 4804ff551..2fdcbac28 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -386,11 +386,8 @@ stream_established({xmlstreamelement, El}, StateData) -> _Exception2 -> error end end, - % XXX OLD FORMAT: El. - % XXX No namespace conversion (:server <-> :client) is done. + % No namespace conversion (:server <-> :client) is done. % This is handled by C2S and S2S send_element functions. - ElOld = exmpp_xml:xmlel_to_xmlelement(El, - [?DEFAULT_NS], ?PREFIXED_NS), if (To /= error) and (From /= error) -> LFrom = From#jid.ldomain, @@ -407,13 +404,10 @@ stream_established({xmlstreamelement, El}, StateData) -> if ((Name == 'iq') or (Name == 'message') or (Name == 'presence')) -> - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), ejabberd_hooks:run( s2s_receive_packet, LFrom, - [FromOld, ToOld, ElOld]), + [From, To, El]), ejabberd_router:route( From, To, El); true -> @@ -430,13 +424,10 @@ stream_established({xmlstreamelement, El}, StateData) -> if ((Name == 'iq') or (Name == 'message') or (Name == 'presence')) -> - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), ejabberd_hooks:run( s2s_receive_packet, LFrom, - [FromOld, ToOld, ElOld]), + [From, To, El]), ejabberd_router:route( From, To, El); true -> @@ -449,7 +440,7 @@ stream_established({xmlstreamelement, El}, StateData) -> true -> error end, - ejabberd_hooks:run(s2s_loop_debug, [{xmlstreamelement, ElOld}]), + ejabberd_hooks:run(s2s_loop_debug, [{xmlstreamelement, El}]), {next_state, stream_established, StateData#state{timer = Timer}} end; @@ -656,11 +647,11 @@ get_cert_domains(Cert) -> case 'XmppAddr':decode( 'XmppAddr', XmppAddr) of {ok, D} when is_binary(D) -> - case jlib:string_to_jid( + case exmpp_jid:list_to_jid( binary_to_list(D)) of - #jid{lnode = "", + #jid{lnode = undefined, ldomain = LD, - lresource = ""} -> + lresource = undefined} -> case idna:domain_utf8_to_ascii(LD) of false -> []; diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 5859b89cf..bbd792a2f 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -716,10 +716,7 @@ handle_info({send_text, Text}, StateName, StateData) -> {next_state, StateName, StateData#state{timer = Timer}, get_timeout_interval(StateName)}; -handle_info({send_element, ElOld}, StateName, StateData) -> - % XXX OLD FORMAT: El. - El = exmpp_xml:xmlelement_to_xmlel(ElOld, - [?NS_JABBER_CLIENT], ?PREFIXED_NS), +handle_info({send_element, El}, StateName, StateData) -> case StateName of stream_established -> cancel_timer(StateData#state.timer), @@ -839,10 +836,7 @@ cancel_timer(Timer) -> bounce_messages(Condition) -> receive - {send_element, ElOld} -> - % XXX OLD FORMAT: El. - El = exmpp_xml:xmlelement_to_xmlel(ElOld, - [?NS_JABBER_CLIENT], ?PREFIXED_NS), + {send_element, El} -> bounce_element(El, Condition), bounce_messages(Condition) after 0 -> diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index d9bc3c185..3cec22f04 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -107,10 +107,8 @@ open_session(SID, User, Server, Resource, Info) -> set_session(SID, User, Server, Resource, undefined, Info), check_for_sessions_to_replace(User, Server, Resource), JID = exmpp_jid:make_jid(User, Server, Resource), - % XXX OLD FORMAT: JID. - JIDOld = jlib:to_old_jid(JID), ejabberd_hooks:run(sm_register_connection_hook, JID#jid.ldomain, - [SID, JIDOld, Info]). + [SID, JID, Info]). close_session(SID, User, Server, Resource) -> Info = case mnesia:dirty_read({session, SID}) of @@ -122,10 +120,8 @@ close_session(SID, User, Server, Resource) -> end, mnesia:sync_dirty(F), JID = exmpp_jid:make_jid(User, Server, Resource), - % XXX OLD FORMAT: JID. - JIDOld = jlib:to_old_jid(JID), ejabberd_hooks:run(sm_remove_connection_hook, JID#jid.ldomain, - [SID, JIDOld, Info]). + [SID, JID, Info]). check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) -> case ejabberd_auth:is_user_exists(User, Server) of @@ -188,11 +184,8 @@ get_user_info(User, Server, Resource) -> set_presence(SID, User, Server, Resource, Priority, Presence, Info) -> set_session(SID, User, Server, Resource, Priority, Info), - % XXX OLD FORMAT: Presence. - PresenceOld = exmpp_xml:xmlel_to_xmlelement(Presence, - [?DEFAULT_NS], ?PREFIXED_NS), ejabberd_hooks:run(set_presence_hook, exmpp_stringprep:nameprep(Server), - [User, Server, Resource, PresenceOld]). + [User, Server, Resource, Presence]). unset_presence(SID, User, Server, Resource, Status, Info) -> set_session(SID, User, Server, Resource, undefined, Info), @@ -408,9 +401,6 @@ do_route(From, To, Packet) -> [From, To, Packet, 8]), #jid{node = User, domain = Server, lnode = LUser, ldomain = LServer, lresource = LResource} = To, - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), case LResource of undefined -> case Packet of @@ -419,36 +409,32 @@ do_route(From, To, Packet) -> case exmpp_presence:get_type(Packet) of 'subscribe' -> Reason = exmpp_presence:get_status(Packet), - % XXX OLD FORMAT: From. {ejabberd_hooks:run_fold( roster_in_subscription, LServer, false, - [User, Server, FromOld, subscribe, Reason]), + [User, Server, From, subscribe, Reason]), true}; 'subscribed' -> - % XXX OLD FORMAT: From. {ejabberd_hooks:run_fold( roster_in_subscription, LServer, false, - [User, Server, FromOld, subscribed, ""]), + [User, Server, From, subscribed, ""]), true}; 'unsubscribe' -> - % XXX OLD FORMAT: From. {ejabberd_hooks:run_fold( roster_in_subscription, LServer, false, - [User, Server, FromOld, unsubscribe, ""]), + [User, Server, From, unsubscribe, ""]), true}; 'unsubscribed' -> - % XXX OLD FORMAT: From. {ejabberd_hooks:run_fold( roster_in_subscription, LServer, false, - [User, Server, FromOld, unsubscribed, ""]), + [User, Server, From, unsubscribed, ""]), true}; _ -> {true, false} @@ -504,10 +490,7 @@ do_route(From, To, Packet) -> Session = lists:max(Ss), Pid = element(2, Session#session.sid), ?DEBUG("sending to process ~p~n", [Pid]), - % XXX OLD FORMAT: From, To, Packet. - PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - [?DEFAULT_NS], ?PREFIXED_NS), - Pid ! {route, FromOld, ToOld, PacketOld} + Pid ! {route, From, To, Packet} end end. @@ -515,11 +498,6 @@ route_message(From, To, Packet) -> LUser = To#jid.lnode, LServer = To#jid.ldomain, PrioRes = get_user_present_resources(LUser, LServer), - % XXX OLD FORMAT: From, To, Packet. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - [?DEFAULT_NS], ?PREFIXED_NS), case catch lists:max(PrioRes) of {Priority, _R} when is_integer(Priority), Priority >= 0 -> lists:foreach( @@ -535,8 +513,7 @@ route_message(From, To, Packet) -> Session = lists:max(Ss), Pid = element(2, Session#session.sid), ?DEBUG("sending to process ~p~n", [Pid]), - % XXX OLD FORMAT: From, To, Packet. - Pid ! {route, FromOld, ToOld, PacketOld} + Pid ! {route, From, To, Packet} end; %% Ignore other priority: ({_Prio, _Res}) -> @@ -554,10 +531,9 @@ route_message(From, To, Packet) -> _ -> case ejabberd_auth:is_user_exists(LUser, LServer) of true -> - % XXX OLD FORMAT: From, To, Packet. ejabberd_hooks:run(offline_message_hook, LServer, - [FromOld, ToOld, PacketOld]); + [From, To, Packet]); _ -> Err = exmpp_stanza:reply_with_error( Packet, 'service-unaivailable'), From 4e39f4cab1355329646d0ddb8bd6a33cb94f3e89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 26 Aug 2008 13:59:04 +0000 Subject: [PATCH 063/582] o Remove compatibility code. Use the atom 'undefined' in JIDs (normal and short). o Add try/catch blocks where Exmpp can raise exceptions. o Remove some unused code. o Convert on-disk Mnesia database: JIDs, extra XML elements and askmessage are concerned. o By default, 'askmessage' is now an empty binary instead of an empty string, for consistency's sake. o Fix some bugs. SVN Revision: 1547 --- ChangeLog | 8 + src/mod_roster.erl | 548 ++++++++++++++++++++++++++------------------- src/mod_roster.hrl | 2 +- 3 files changed, 322 insertions(+), 236 deletions(-) diff --git a/ChangeLog b/ChangeLog index 32a5d3c7a..b733ab458 100644 --- a/ChangeLog +++ b/ChangeLog @@ -17,6 +17,14 @@ where. Also, in JIDs (normal and short), the atom "undefined' is expected, not the empty string anymore! + * src/mod_roster.hrl, src/mod_roster.erl: Remove compatibility code. + Use the atom 'undefined' in JIDs (normal and short). Add try/catch + blocks where Exmpp can raise exceptions. Remove some unused code. + Convert on-disk Mnesia database: JIDs, extra XML elements and + askmessage are concerned. By default, 'askmessage' is now an empty + binary instead of an empty string, for consistency's sake. Fix some + bugs. + 2008-08-14 Jean-Sébastien Pédron * translate.erl (ascii_tolower): Accept 'undefined' as a language and diff --git a/src/mod_roster.erl b/src/mod_roster.erl index e67eb58c6..ec43d595a 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -123,9 +123,7 @@ process_local_iq(From, To, #iq{type = set} = IQ_Rec) -> process_iq_get(From, To, IQ_Rec) -> - LUser = From#jid.lnode, - LServer = From#jid.ldomain, - US = {LUser, LServer}, + US = {From#jid.lnode, From#jid.ldomain}, case catch ejabberd_hooks:run_fold(roster_get, To#jid.ldomain, [], [US]) of Items when is_list(Items) -> XItems = lists:map(fun item_to_xml/1, Items), @@ -188,14 +186,12 @@ process_iq_set(From, To, #iq{payload = Request} = IQ_Rec) -> end, exmpp_iq:result(IQ_Rec). -process_item_set(From, To, #xmlel{} = Item) -> +process_item_set(From, To, #xmlel{} = El) -> try - JID1 = exmpp_jid:list_to_jid(exmpp_xml:get_attribute(Item, 'jid', "")), - % XXX OLD FORMAT: old JID (with empty strings). - #jid{node = User, lnode = LUser, ldomain = LServer} = - jlib:to_old_jid(From), - JID = {JID1#jid.node, JID1#jid.domain, JID1#jid.resource}, - LJID = jlib:short_jid(JID1), + JID1 = exmpp_jid:list_to_jid(exmpp_xml:get_attribute(El, 'jid', "")), + #jid{node = User, lnode = LUser, ldomain = LServer} = From, + JID = jlib:short_jid(JID1), + LJID = jlib:short_prepd_jid(JID1), F = fun() -> Res = mnesia:read({roster, {LUser, LServer, LJID}}), Item = case Res of @@ -209,8 +205,8 @@ process_item_set(From, To, #xmlel{} = Item) -> groups = [], xs = []} end, - Item1 = process_item_attrs(Item, Item#xmlel.attrs), - Item2 = process_item_els(Item1, Item#xmlel.children), + Item1 = process_item_attrs(Item, El#xmlel.attrs), + Item2 = process_item_els(Item1, El#xmlel.children), case Item2#roster.subscription of remove -> mnesia:delete({roster, {LUser, LServer, LJID}}); @@ -270,15 +266,6 @@ process_item_set(_From, _To, _) -> process_item_attrs(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> case Attr of - 'jid' -> - try - JID1 = exmpp_jid:list_to_jid(Val), - JID = {JID1#jid.node, JID1#jid.domain, JID1#jid.resource}, - process_item_attrs(Item#roster{jid = JID}, Attrs) - catch - _ -> - process_item_attrs(Item, Attrs) - end; 'name' -> process_item_attrs(Item#roster{name = Val}, Attrs); 'subscription' -> @@ -319,7 +306,7 @@ process_item_els(Item, []) -> push_item(User, Server, From, Item) -> - ejabberd_sm:route(exmpp_jid:make_bare_jid(""), + ejabberd_sm:route(#jid{}, exmpp_jid:make_bare_jid(User, Server), #xmlel{name = 'broadcast', children = [{item, @@ -340,12 +327,17 @@ push_item(User, Server, Resource, From, Item) -> ResIQ). get_subscription_lists(_, User, Server) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - US = {LUser, LServer}, - case mnesia:dirty_index_read(roster, US, #roster.us) of - Items when is_list(Items) -> - fill_subscription_lists(Items, [], []); + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + case mnesia:dirty_index_read(roster, US, #roster.us) of + Items when is_list(Items) -> + fill_subscription_lists(Items, [], []); + _ -> + {[], []} + end + catch _ -> {[], []} end. @@ -378,84 +370,87 @@ out_subscription(User, Server, JID, Type) -> process_subscription(out, User, Server, JID, Type, []). process_subscription(Direction, User, Server, JID1, Type, Reason) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - US = {LUser, LServer}, - LJID = jlib:short_jid(JID1), - F = fun() -> - Item = case mnesia:read({roster, {LUser, LServer, LJID}}) of - [] -> - JID = {JID1#jid.node, - JID1#jid.domain, - JID1#jid.resource}, - #roster{usj = {LUser, LServer, LJID}, - us = US, - jid = JID}; - [I] -> - I - end, - NewState = case Direction of - out -> - out_state_change(Item#roster.subscription, - Item#roster.ask, - Type); - in -> - in_state_change(Item#roster.subscription, - Item#roster.ask, - Type) + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + LJID = jlib:short_prepd_jid(JID1), + F = fun() -> + Item = case mnesia:read({roster, {LUser, LServer, LJID}}) of + [] -> + JID = jlib:short_jid(JID1), + #roster{usj = {LUser, LServer, LJID}, + us = US, + jid = JID}; + [I] -> + I end, - AutoReply = case Direction of - out -> - none; - in -> - in_auto_reply(Item#roster.subscription, - Item#roster.ask, - Type) - end, - AskMessage = case NewState of - {_, both} -> Reason; - {_, in} -> Reason; - _ -> "" - end, - case NewState of - none -> - {none, AutoReply}; - {none, none} when Item#roster.subscription == none, - Item#roster.ask == in -> - mnesia:delete({roster, {LUser, LServer, LJID}}), - {none, AutoReply}; - {Subscription, Pending} -> - NewItem = Item#roster{subscription = Subscription, - ask = Pending, - askmessage = list_to_binary(AskMessage)}, - mnesia:write(NewItem), - {{push, NewItem}, AutoReply} - end - end, - case mnesia:transaction(F) of - {atomic, {Push, AutoReply}} -> - case AutoReply of - none -> - ok; - _ -> - ejabberd_router:route( - exmpp_jid:make_bare_jid(User, Server), JID1, - exmpp_presence:AutoReply()) + NewState = case Direction of + out -> + out_state_change(Item#roster.subscription, + Item#roster.ask, + Type); + in -> + in_state_change(Item#roster.subscription, + Item#roster.ask, + Type) + end, + AutoReply = case Direction of + out -> + none; + in -> + in_auto_reply(Item#roster.subscription, + Item#roster.ask, + Type) + end, + AskMessage = case NewState of + {_, both} -> Reason; + {_, in} -> Reason; + _ -> "" + end, + case NewState of + none -> + {none, AutoReply}; + {none, none} when Item#roster.subscription == none, + Item#roster.ask == in -> + mnesia:delete({roster, {LUser, LServer, LJID}}), + {none, AutoReply}; + {Subscription, Pending} -> + NewItem = Item#roster{subscription = Subscription, + ask = Pending, + askmessage = list_to_binary(AskMessage)}, + mnesia:write(NewItem), + {{push, NewItem}, AutoReply} + end end, - case Push of - {push, Item} -> - if - Item#roster.subscription == none, - Item#roster.ask == in -> - ok; - true -> - push_item(User, Server, - exmpp_jid:make_bare_jid(User, Server), Item) - end, - true; - none -> - false - end; + case mnesia:transaction(F) of + {atomic, {Push, AutoReply}} -> + case AutoReply of + none -> + ok; + _ -> + ejabberd_router:route( + exmpp_jid:make_bare_jid(User, Server), JID1, + exmpp_presence:AutoReply()) + end, + case Push of + {push, Item} -> + if + Item#roster.subscription == none, + Item#roster.ask == in -> + ok; + true -> + push_item(User, Server, + exmpp_jid:make_bare_jid(User, Server), Item) + end, + true; + none -> + false + end; + _ -> + false + end + catch _ -> false end. @@ -557,35 +552,44 @@ in_auto_reply(_, _, _) -> none. remove_user(User, Server) -> - LUser = exmpp_stringpre:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - US = {LUser, LServer}, - F = fun() -> - lists:foreach(fun(R) -> - mnesia:delete_object(R) - end, - mnesia:index_read(roster, US, #roster.us)) - end, - mnesia:transaction(F). + try + LUser = exmpp_stringpre:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + F = fun() -> + lists:foreach(fun(R) -> + mnesia:delete_object(R) + end, + mnesia:index_read(roster, US, #roster.us)) + end, + mnesia:transaction(F) + catch + _ -> + ok + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -set_items(User, Server, SubEl) -> - {xmlelement, _Name, _Attrs, Els} = SubEl, - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - F = fun() -> - lists:foreach(fun(El) -> - process_item_set_t(LUser, LServer, El) - end, Els) - end, - mnesia:transaction(F). +set_items(User, Server, #xmlel{children = Els}) -> + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + F = fun() -> + lists:foreach(fun(El) -> + process_item_set_t(LUser, LServer, El) + end, Els) + end, + mnesia:transaction(F) + catch + _ -> + ok + end. process_item_set_t(LUser, LServer, #xmlel{} = El) -> try JID1 = exmpp_jid:list_to_jid(exmpp_xml:get_attribute(El, 'jid', "")), - JID = {JID1#jid.node, JID1#jid.domain, JID1#jid.resource}, - LJID = {JID1#jid.lnode, JID1#jid.ldomain, JID1#jid.lresource}, + JID = jlib:short_jid(JID1), + LJID = jlib:short_prepd_jid(JID1), Item = #roster{usj = {LUser, LServer, LJID}, us = {LUser, LServer}, jid = JID}, @@ -606,15 +610,6 @@ process_item_set_t(_LUser, _LServer, _) -> process_item_attrs_ws(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> case Attr of - 'jid' -> - try - JID1 = exmpp_jid:list_to_jid(Val), - JID = {JID1#jid.node, JID1#jid.domain, JID1#jid.resource}, - process_item_attrs_ws(Item#roster{jid = JID}, Attrs) - catch - _ -> - process_item_attrs_ws(Item, Attrs) - end; 'name' -> process_item_attrs_ws(Item#roster{name = Val}, Attrs); 'subscription' -> @@ -650,14 +645,9 @@ get_in_pending_subscriptions(Ls, User, Server) -> US = {JID#jid.lnode, JID#jid.ldomain}, case mnesia:dirty_index_read(roster, US, #roster.us) of Result when list(Result) -> - Ls ++ lists:map( + Ls ++ lists:map( fun(R) -> Message = R#roster.askmessage, - Status = if is_binary(Message) -> - binary_to_list(Message); - true -> - "" - end, {U, S, R} = R#roster.jid, Attrs1 = exmpp_stanza:set_sender_in_list([], exmpp_jid:jid_to_list(U, S, R)), @@ -665,7 +655,7 @@ get_in_pending_subscriptions(Ls, User, Server) -> exmpp_jid:jid_to_list(JID)), Pres1 = exmpp_presence:subscribe(), Pres2 = Pres1#xmlel{attrs = Attrs2}, - exmpp_presence:set_status(Pres2, Status) + exmpp_presence:set_status(Pres2, Message) end, lists:filter( fun(R) -> @@ -684,27 +674,32 @@ get_in_pending_subscriptions(Ls, User, Server) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% get_jid_info(_, User, Server, JID) -> - LUser = exmpp_stringprep:nodeprep(User), - LJID = jlib:short_jid(JID), - LServer = exmpp_stringprep:nameprep(Server), - case catch mnesia:dirty_read(roster, {LUser, LServer, LJID}) of - [#roster{subscription = Subscription, groups = Groups}] -> - {Subscription, Groups}; + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + LJID = jlib:short_prepd_jid(JID), + case catch mnesia:dirty_read(roster, {LUser, LServer, LJID}) of + [#roster{subscription = Subscription, groups = Groups}] -> + {Subscription, Groups}; + _ -> + LRJID = jlib:short_prepd_bare_jid(JID), + if + LRJID == LJID -> + {none, []}; + true -> + case catch mnesia:dirty_read( + roster, {LUser, LServer, LRJID}) of + [#roster{subscription = Subscription, + groups = Groups}] -> + {Subscription, Groups}; + _ -> + {none, []} + end + end + end + catch _ -> - LRJID = jlib:short_jid(exmpp_jid:jid_to_bare_jid(JID)), - if - LRJID == LJID -> - {none, []}; - true -> - case catch mnesia:dirty_read( - roster, {LUser, LServer, LRJID}) of - [#roster{subscription = Subscription, - groups = Groups}] -> - {Subscription, Groups}; - _ -> - {none, []} - end - end + {none, []} end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -714,7 +709,7 @@ update_table() -> Fields = record_info(fields, roster), case mnesia:table_info(roster, attributes) of Fields -> - ok; + convert_to_exmpp(); [uj, user, jid, name, subscription, ask, groups, xattrs, xs] -> convert_table1(Fields); [usj, us, jid, name, subscription, ask, groups, xattrs, xs] -> @@ -742,11 +737,18 @@ convert_table1(Fields) -> F1 = fun() -> mnesia:write_lock_table(mod_roster_tmp_table), mnesia:foldl( - fun(#roster{usj = {U, JID}, us = U} = R, _) -> + fun(#roster{usj = {U, {JID_U, JID_S, JID_R}}, us = U, xs = XS, askmessage = AM} = R, _) -> + U1 = convert_jid_to_exmpp(U), + JID_U1 = convert_jid_to_exmpp(JID_U), + JID_R1 = convert_jid_to_exmpp(JID_R), + JID1 = {JID_U1, JID_S, JID_R1}, + XS1 = convert_xs_to_exmpp(XS), + AM1 = convert_askmessage_to_exmpp(AM), mnesia:dirty_write( mod_roster_tmp_table, - R#roster{usj = {U, Host, JID}, - us = {U, Host}}) + R#roster{usj = {U1, Host, JID1}, + us = {U1, Host}, xs = XS1, + askmessage = AM1}) end, ok, roster) end, mnesia:transaction(F1), @@ -766,9 +768,74 @@ convert_table1(Fields) -> convert_table2(Fields) -> ?INFO_MSG("Converting roster table from " "{usj, us, jid, name, subscription, ask, groups, xattrs, xs} format", []), - mnesia:transform_table(roster, ignore, Fields). + mnesia:transform_table(roster, ignore, Fields), + convert_to_exmpp(). +convert_to_exmpp() -> + Fun = fun() -> + case mnesia:first(roster) of + '$end_of_table' -> + none; + Key -> + case mnesia:read({roster, Key}) of + [#roster{jid = {_, _, undefined}}] -> + none; + [#roster{jid = {_, _, ""}}] -> + mnesia:foldl(fun convert_to_exmpp2/2, + done, roster, write) + end + end + end, + Ret = mnesia:transaction(Fun), + io:format("Conversion return value: ~p~n", [Ret]). + +convert_to_exmpp2(#roster{ + usj = {USJ_U, USJ_S, {USJ_JU, USJ_JS, USJ_JR}} = Key, + us = {US_U, US_S}, + jid = {JID_U, JID_S, JID_R}, + xs = XS, askmessage = AM} = R, Acc) -> + % Remove old entry. + mnesia:delete({roster, Key}), + % Convert "" to undefined in JIDs. + USJ_U1 = convert_jid_to_exmpp(USJ_U), + USJ_JU1 = convert_jid_to_exmpp(USJ_JU), + USJ_JR1 = convert_jid_to_exmpp(USJ_JR), + US_U1 = convert_jid_to_exmpp(US_U), + JID_U1 = convert_jid_to_exmpp(JID_U), + JID_R1 = convert_jid_to_exmpp(JID_R), + % Convert xs. + XS1 = convert_xs_to_exmpp(XS), + % Convert askmessage. + AM1 = convert_askmessage_to_exmpp(AM), + % Prepare the new record. + New_R = R#roster{ + usj = {USJ_U1, USJ_S, {USJ_JU1, USJ_JS, USJ_JR1}}, + us = {US_U1, US_S}, + jid = {JID_U1, JID_S, JID_R1}, + xs = XS1, askmessage = AM1}, + % Write the new record. + mnesia:write(New_R), + Acc. + +convert_jid_to_exmpp("") -> undefined; +convert_jid_to_exmpp(V) -> V. + +convert_xs_to_exmpp(Els) -> + convert_xs_to_exmpp(Els, []). + +convert_xs_to_exmpp([El | Rest], Result) -> + New_El = exmpp_xml:xmlelement_to_xmlel(El, + [?NS_JABBER_CLIENT], [{?NS_XMPP, ?NS_XMPP_pfx}]), + convert_xs_to_exmpp(Rest, [New_El | Result]); +convert_xs_to_exmpp([], Result) -> + lists:reverse(Result). + +convert_askmessage_to_exmpp(AM) when is_binary(AM) -> + AM; +convert_askmessage_to_exmpp(AM) -> + list_to_binary(AM). + webadmin_page(_, Host, #request{us = _US, path = ["user", U, "roster"], @@ -780,74 +847,85 @@ webadmin_page(_, Host, webadmin_page(Acc, _, _) -> Acc. user_roster(User, Server, Query, Lang) -> - US = {exmpp_stringprep:nodeprep(User), exmpp_stringprep:nameprep(Server)}, - Items1 = mnesia:dirty_index_read(roster, US, #roster.us), - Res = user_roster_parse_query(User, Server, Items1, Query), - Items = mnesia:dirty_index_read(roster, US, #roster.us), - SItems = lists:sort(Items), - FItems = - case SItems of - [] -> - [?CT("None")]; - _ -> - [?XE("table", - [?XE("thead", - [?XE("tr", - [?XCT("td", "Jabber ID"), - ?XCT("td", "Nickname"), - ?XCT("td", "Subscription"), - ?XCT("td", "Pending"), - ?XCT("td", "Groups") - ])]), - ?XE("tbody", - lists:map( - fun(R) -> - Groups = - lists:flatmap( - fun(Group) -> - [?C(Group), ?BR] - end, R#roster.groups), - Pending = ask_to_pending(R#roster.ask), - {U, S, R} = R#roster.jid, - ?XE("tr", - [?XAC("td", [{"class", "valign"}], - catch exmpp_jid:jid_to_list(U, S, R)), - ?XAC("td", [{"class", "valign"}], - R#roster.name), - ?XAC("td", [{"class", "valign"}], - atom_to_list(R#roster.subscription)), - ?XAC("td", [{"class", "valign"}], - atom_to_list(Pending)), - ?XAE("td", [{"class", "valign"}], Groups), - if - Pending == in -> - ?XAE("td", [{"class", "valign"}], - [?INPUTT("submit", - "validate" ++ - ejabberd_web_admin:term_to_id(R#roster.jid), - "Validate")]); - true -> - ?X("td") - end, - ?XAE("td", [{"class", "valign"}], - [?INPUTT("submit", - "remove" ++ - ejabberd_web_admin:term_to_id(R#roster.jid), - "Remove")])]) - end, SItems))])] - end, - [?XC("h1", ?T("Roster of ") ++ us_to_list(US))] ++ - case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; - nothing -> [] - end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], - FItems ++ - [?P, - ?INPUT("text", "newjid", ""), ?C(" "), - ?INPUTT("submit", "addjid", "Add Jabber ID") - ])]. + try + US = {exmpp_stringprep:nodeprep(User), exmpp_stringprep:nameprep(Server)}, + Items1 = mnesia:dirty_index_read(roster, US, #roster.us), + Res = user_roster_parse_query(User, Server, Items1, Query), + Items = mnesia:dirty_index_read(roster, US, #roster.us), + SItems = lists:sort(Items), + FItems = + case SItems of + [] -> + [?CT("None")]; + _ -> + [?XE("table", + [?XE("thead", + [?XE("tr", + [?XCT("td", "Jabber ID"), + ?XCT("td", "Nickname"), + ?XCT("td", "Subscription"), + ?XCT("td", "Pending"), + ?XCT("td", "Groups") + ])]), + ?XE("tbody", + lists:map( + fun(R) -> + Groups = + lists:flatmap( + fun(Group) -> + [?C(Group), ?BR] + end, R#roster.groups), + Pending = ask_to_pending(R#roster.ask), + {U, S, R} = R#roster.jid, + ?XE("tr", + [?XAC("td", [{"class", "valign"}], + catch exmpp_jid:jid_to_list(U, S, R)), + ?XAC("td", [{"class", "valign"}], + R#roster.name), + ?XAC("td", [{"class", "valign"}], + atom_to_list(R#roster.subscription)), + ?XAC("td", [{"class", "valign"}], + atom_to_list(Pending)), + ?XAE("td", [{"class", "valign"}], Groups), + if + Pending == in -> + ?XAE("td", [{"class", "valign"}], + [?INPUTT("submit", + "validate" ++ + ejabberd_web_admin:term_to_id(R#roster.jid), + "Validate")]); + true -> + ?X("td") + end, + ?XAE("td", [{"class", "valign"}], + [?INPUTT("submit", + "remove" ++ + ejabberd_web_admin:term_to_id(R#roster.jid), + "Remove")])]) + end, SItems))])] + end, + [?XC("h1", ?T("Roster of ") ++ us_to_list(US))] ++ + case Res of + ok -> [?CT("Submitted"), ?P]; + error -> [?CT("Bad format"), ?P]; + nothing -> [] + end ++ + [?XAE("form", [{"action", ""}, {"method", "post"}], + FItems ++ + [?P, + ?INPUT("text", "newjid", ""), ?C(" "), + ?INPUTT("submit", "addjid", "Add Jabber ID") + ])] + catch + _ -> + [?XC("h1", ?T("Roster of ") ++ us_to_list({User, Server}))] ++ + [?CT("Bad format"), ?P] ++ + [?XAE("form", [{"action", ""}, {"method", "post"}], + [?P, + ?INPUT("text", "newjid", ""), ?C(" "), + ?INPUTT("submit", "addjid", "Add Jabber ID") + ])] + end. user_roster_parse_query(User, Server, Items, Query) -> case lists:keysearch("addjid", 1, Query) of diff --git a/src/mod_roster.hrl b/src/mod_roster.hrl index 2a2e8bc72..380a4e246 100644 --- a/src/mod_roster.hrl +++ b/src/mod_roster.hrl @@ -26,6 +26,6 @@ subscription = none, ask = none, groups = [], - askmessage = [], + askmessage = <<>>, xs = []}). From 8baed0864116721743803e58fdfd86af90d38993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 27 Aug 2008 09:45:01 +0000 Subject: [PATCH 064/582] Remove a debugging io:format/2. SVN Revision: 1551 --- ChangeLog | 4 ++++ src/mod_roster.erl | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index b733ab458..1242e3a29 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2008-08-27 Jean-Sébastien Pédron + + * src/mod_roster.erl: Remove a debugging io:format/2. + 2008-08-26 Jean-Sébastien Pédron * src/jlib.erl: short_jid/1 and short_bare_jid/1 now produce a short diff --git a/src/mod_roster.erl b/src/mod_roster.erl index ec43d595a..fe2c740fe 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -787,8 +787,7 @@ convert_to_exmpp() -> end end end, - Ret = mnesia:transaction(Fun), - io:format("Conversion return value: ~p~n", [Ret]). + mnesia:transaction(Fun). convert_to_exmpp2(#roster{ usj = {USJ_U, USJ_S, {USJ_JU, USJ_JS, USJ_JR}} = Key, From 02e6bf875967e6ea5ba6ca8f02e57172d5ad1b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 27 Aug 2008 09:46:25 +0000 Subject: [PATCH 065/582] handle_cast({disco_response, ...}, ...) now receives an #iq record: update the code to handle this. SVN Revision: 1552 --- ChangeLog | 3 +++ src/mod_caps.erl | 13 ++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1242e3a29..5400cdd0c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,9 @@ * src/mod_roster.erl: Remove a debugging io:format/2. + * src/mod_caps.erl: handle_cast({disco_response, ...}, ...) now + receives an #iq record: update the code to handle this. + 2008-08-26 Jean-Sébastien Pédron * src/jlib.erl: short_jid/1 and short_bare_jid/1 now produce a short diff --git a/src/mod_caps.erl b/src/mod_caps.erl index a04a27f0a..852ae7e48 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -217,10 +217,9 @@ handle_cast({note_caps, From, ?ERROR_MSG("Transaction failed: ~p", [Error]), {noreply, State} end; -handle_cast({disco_response, From, _To, IQ}, +handle_cast({disco_response, From, _To, #iq{id = ID, type = Type, payload = Payload}}, #state{disco_requests = Requests} = State) -> - ID = exmpp_stanza:get_id(IQ), - case {exmpp_iq:get_type(IQ), exmpp_iq:get_payload(IQ)} of + case {Type, Payload} of {result, #xmlel{name = 'query', children = Els}} -> case ?DICT:find(ID, Requests) of {ok, {Node, SubNode}} -> @@ -255,8 +254,8 @@ handle_cast({disco_response, From, _To, IQ}, end; %gen_server:cast(self(), visit_feature_queries), %?DEBUG("Error IQ reponse from ~s:~n~p", [exmpp_jid:jid_to_list(From), SubEls]); - {result, _} -> - ?DEBUG("Invalid IQ contents from ~s:~n~p", [exmpp_jid:jid_to_list(From), IQ#xmlel.children]); + {result, Payload} -> + ?DEBUG("Invalid IQ contents from ~s:~n~p", [exmpp_jid:jid_to_list(From), Payload]); _ -> %% Can't do anything about errors ok @@ -287,10 +286,10 @@ handle_cast(visit_feature_queries, #state{feature_queries = FeatureQueries} = St end, [], FeatureQueries), {noreply, State#state{feature_queries = NewFeatureQueries}}. -handle_disco_response(From, To, IQ) -> +handle_disco_response(From, To, IQ_Rec) -> #jid{ldomain = Host} = To, Proc = gen_mod:get_module_proc(Host, ?PROCNAME), - gen_server:cast(Proc, {disco_response, From, To, IQ}). + gen_server:cast(Proc, {disco_response, From, To, IQ_Rec}). handle_info(_Info, State) -> {noreply, State}. From 414948d822ec504bbfb331e334d32d6080f355d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 27 Aug 2008 12:39:49 +0000 Subject: [PATCH 066/582] VCard are now stored as #xmlel. Mnesia tables are converted during startup. SVN Revision: 1553 --- ChangeLog | 3 +++ src/mod_vcard.erl | 43 ++++++++++++++++++++++++++++--------------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5400cdd0c..c03ba622c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,9 @@ * src/mod_caps.erl: handle_cast({disco_response, ...}, ...) now receives an #iq record: update the code to handle this. + * src/mod_vcard.erl: VCard are now stored as #xmlel. Mnesia tables are + converted during startup. + 2008-08-26 Jean-Sébastien Pédron * src/jlib.erl: short_jid/1 and short_bare_jid/1 now produce a short diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index 0447d5920..69fbcae7f 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -142,10 +142,10 @@ get_sm_features(Acc, _From, _To, Node, _Lang) -> case Acc of {result, Features} -> % XXX OLD FORMAT: NS as string. - {result, [atom_to_list(?NS_VCARD) | Features]}; + {result, [?NS_VCARD_s | Features]}; empty -> % XXX OLD FORMAT: NS as string. - {result, [atom_to_list(?NS_VCARD)]} + {result, [?NS_VCARD_s]} end; _ -> Acc @@ -177,14 +177,7 @@ process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> [VCard | _] = case mnesia:transaction(F) of {atomic, Rs} -> lists:map(fun(R) -> - case R#vcard.vcard of - #xmlel{} = E -> - E; - #xmlelement{} = E -> - % XXX OLD FORMAT: Base contains old elements. - io:format("VCARD: Old element in base: ~p~n", [E]), - exmpp_xml:xmlelement_to_xmlel(E, [?NS_VCARD], []) - end + R#vcard.vcard end, Rs); {aborted, _Reason} -> [] @@ -249,10 +242,7 @@ set_vcard(User, LServer, VCARD) -> US = {LUser, LServer}, F = fun() -> - % XXX OLD FORMAT: We keep persistent data in the old format - % for now. - VCARDOld = exmpp_xml:xmlel_to_xmlelement(VCARD, [?NS_VCARD], []), - mnesia:write(#vcard{us = US, vcard = VCARDOld}), + mnesia:write(#vcard{us = US, vcard = VCARD}), mnesia:write( #vcard_search{us = US, user = {User, LServer}, @@ -673,7 +663,7 @@ update_vcard_table() -> Fields = record_info(fields, vcard), case mnesia:table_info(vcard, attributes) of Fields -> - ok; + convert_to_exmpp(); [user, vcard] -> ?INFO_MSG("Converting vcard table from " "{user, vcard} format", []), @@ -712,6 +702,29 @@ update_vcard_table() -> end. +convert_to_exmpp() -> + Fun = fun() -> + case mnesia:first(vcard) of + '$end_of_table' -> + none; + Key -> + case mnesia:read({vcard, Key}) of + [#vcard{vcard = #xmlel{}}] -> + none; + [#vcard{vcard = #xmlelement{}}] -> + mnesia:foldl(fun convert_to_exmpp2/2, + done, vcard, write) + end + end + end, + mnesia:transaction(Fun). + +convert_to_exmpp2(#vcard{vcard = ElOld} = VCard, Acc) -> + El0 = exmpp_xml:xmlelement_to_xmlel(ElOld, [?NS_VCARD], []), + El = exmpp_xml:remove_whitespaces_deeply(El0), + mnesia:write(VCard#vcard{vcard = El}), + Acc. + update_vcard_search_table() -> Fields = record_info(fields, vcard_search), case mnesia:table_info(vcard_search, attributes) of From 4eaa8e19c9b6427596cda4734a0f719baf97d6b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 16 Sep 2008 14:39:57 +0000 Subject: [PATCH 067/582] Merge from trunk (r1457 to r1563). SVN Revision: 1564 --- ChangeLog | 272 ++- README | 6 +- contrib/ejabberd-modules.repo | 4 +- .../extract_translations.erl | 121 +- .../prepare-translation.sh | 172 +- doc/api/overview.edoc | 2 +- doc/guide.html | 186 +- doc/guide.tex | 217 ++- doc/release_notes_2.0.2.txt | 34 + src/Makefile.in | 3 + src/acl.erl | 2 +- src/adhoc.erl | 2 +- src/adhoc.hrl | 2 +- src/configure.erl | 2 +- src/cyrsasl.erl | 2 +- src/cyrsasl_anonymous.erl | 2 +- src/cyrsasl_plain.erl | 2 +- src/ejabberd.erl | 2 +- src/ejabberd.hrl | 2 +- src/ejabberd_admin.erl | 2 +- src/ejabberd_app.erl | 4 +- src/ejabberd_auth.erl | 11 +- src/ejabberd_auth_anonymous.erl | 2 +- src/ejabberd_auth_external.erl | 7 +- src/ejabberd_auth_internal.erl | 7 +- src/ejabberd_auth_ldap.erl | 2 +- src/ejabberd_auth_odbc.erl | 9 +- src/ejabberd_auth_pam.erl | 2 +- src/ejabberd_c2s.erl | 20 +- src/ejabberd_c2s_config.erl | 2 +- src/ejabberd_check.erl | 24 +- src/ejabberd_config.erl | 12 +- src/ejabberd_config.hrl | 2 +- src/ejabberd_ctl.erl | 11 +- src/ejabberd_ctl.hrl | 2 +- src/ejabberd_frontend_socket.erl | 2 +- src/ejabberd_hooks.erl | 2 +- src/ejabberd_listener.erl | 2 +- src/ejabberd_local.erl | 2 +- src/ejabberd_logger_h.erl | 2 +- src/ejabberd_loglevel.erl | 2 +- src/ejabberd_node_groups.erl | 2 +- src/ejabberd_rdbms.erl | 2 +- src/ejabberd_receiver.erl | 2 +- src/ejabberd_router.erl | 8 +- src/ejabberd_s2s.erl | 2 +- src/ejabberd_s2s_in.erl | 2 +- src/ejabberd_s2s_out.erl | 2 +- src/ejabberd_service.erl | 14 +- src/ejabberd_sm.erl | 2 +- src/ejabberd_socket.erl | 2 +- src/ejabberd_sup.erl | 2 +- src/ejabberd_system_monitor.erl | 2 +- src/ejabberd_tmp_sup.erl | 2 +- src/ejabberd_update.erl | 2 +- src/ejabberd_zlib/ejabberd_zlib.erl | 2 +- src/ejabberd_zlib/ejabberd_zlib_drv.c | 2 +- src/ejd2odbc.erl | 2 +- src/eldap/eldap.hrl | 2 +- src/eldap/eldap_filter.erl | 2 +- src/eldap/eldap_pool.erl | 2 +- src/eldap/eldap_utils.erl | 2 +- src/extauth.erl | 2 +- src/gen_iq_handler.erl | 2 +- src/gen_mod.erl | 23 +- src/idna.erl | 2 +- src/jd2ejd.erl | 2 +- src/jlib.erl | 2 +- src/jlib.hrl | 2 +- src/mod_adhoc.erl | 2 +- src/mod_announce.erl | 2 +- src/mod_caps.erl | 2 +- src/mod_configure.erl | 2 +- src/mod_configure2.erl | 2 +- src/mod_disco.erl | 2 +- src/mod_echo.erl | 2 +- src/mod_ip_blacklist.erl | 2 +- src/mod_irc/iconv.erl | 2 +- src/mod_irc/iconv_erl.c | 2 +- src/mod_irc/mod_irc.erl | 2 +- src/mod_irc/mod_irc_connection.erl | 2 +- src/mod_last.erl | 2 +- src/mod_last_odbc.erl | 14 +- src/mod_muc/mod_muc.erl | 2 +- src/mod_muc/mod_muc_log.erl | 233 ++- src/mod_muc/mod_muc_room.erl | 186 +- src/mod_offline.erl | 2 +- src/mod_offline_odbc.erl | 4 +- src/mod_privacy.erl | 2 +- src/mod_privacy.hrl | 2 +- src/mod_privacy_odbc.erl | 52 +- src/mod_private.erl | 2 +- src/mod_private_odbc.erl | 2 +- src/mod_proxy65/mod_proxy65.erl | 2 +- src/mod_proxy65/mod_proxy65.hrl | 2 +- src/mod_proxy65/mod_proxy65_lib.erl | 12 +- src/mod_proxy65/mod_proxy65_service.erl | 2 +- src/mod_proxy65/mod_proxy65_sm.erl | 2 +- src/mod_proxy65/mod_proxy65_stream.erl | 4 +- src/mod_pubsub/gen_pubsub_node.erl | 8 +- src/mod_pubsub/gen_pubsub_nodetree.erl | 8 +- src/mod_pubsub/mod_pubsub.erl | 97 +- src/mod_pubsub/node.template | 8 +- src/mod_pubsub/node_buddy.erl | 8 +- src/mod_pubsub/node_club.erl | 8 +- src/mod_pubsub/node_default.erl | 24 +- src/mod_pubsub/node_dispatch.erl | 10 +- src/mod_pubsub/node_pep.erl | 31 +- src/mod_pubsub/node_private.erl | 8 +- src/mod_pubsub/node_public.erl | 8 +- src/mod_pubsub/node_zoo.erl | 27 +- src/mod_pubsub/nodetree_default.erl | 13 +- src/mod_pubsub/nodetree_virtual.erl | 8 +- src/mod_pubsub/pubsub.hrl | 8 +- src/mod_register.erl | 27 +- src/mod_roster.erl | 2 +- src/mod_roster.hrl | 2 +- src/mod_roster_odbc.erl | 2 +- src/mod_service_log.erl | 2 +- src/mod_shared_roster.erl | 2 +- src/mod_stats.erl | 2 +- src/mod_time.erl | 2 +- src/mod_vcard.erl | 2 +- src/mod_vcard_ldap.erl | 2 +- src/mod_vcard_odbc.erl | 4 +- src/mod_version.erl | 2 +- src/msgs/ca.msg | 727 ++++---- src/msgs/ca.po | 1497 +++++++++++++++ src/msgs/cs.msg | 747 ++++---- src/msgs/cs.po | 1487 +++++++++++++++ src/msgs/de.msg | 727 ++++---- src/msgs/de.po | 1504 +++++++++++++++ src/msgs/ejabberd.pot | 1467 +++++++++++++++ src/msgs/eo.msg | 731 ++++---- src/msgs/eo.po | 1493 +++++++++++++++ src/msgs/es.msg | 726 ++++---- src/msgs/es.po | 1502 +++++++++++++++ src/msgs/fr.msg | 729 ++++---- src/msgs/fr.po | 1512 +++++++++++++++ src/msgs/gl.msg | 721 ++++---- src/msgs/gl.po | 1500 +++++++++++++++ src/msgs/it.msg | 727 ++++---- src/msgs/it.po | 1506 +++++++++++++++ src/msgs/ja.msg | 718 ++++---- src/msgs/ja.po | 1484 +++++++++++++++ src/msgs/nl.msg | 722 ++++---- src/msgs/nl.po | 1508 +++++++++++++++ src/msgs/no.msg | 727 ++++---- src/msgs/no.po | 1493 +++++++++++++++ src/msgs/pl.msg | 764 ++++---- src/msgs/pl.po | 1500 +++++++++++++++ src/msgs/pt-br.msg | 745 ++++---- src/msgs/pt-br.po | 1499 +++++++++++++++ src/msgs/pt.msg | 394 ++-- src/msgs/pt.po | 1626 +++++++++++++++++ src/msgs/ru.msg | 730 ++++---- src/msgs/ru.po | 1496 +++++++++++++++ src/msgs/sk.msg | 763 ++++---- src/msgs/sk.po | 1493 +++++++++++++++ src/msgs/sv.msg | 639 ++++--- src/msgs/sv.po | 1495 +++++++++++++++ src/msgs/th.msg | 702 ++++--- src/msgs/th.po | 1488 +++++++++++++++ src/msgs/tr.msg | 734 ++++---- src/msgs/tr.po | 1497 +++++++++++++++ src/msgs/uk.msg | 733 ++++---- src/msgs/uk.po | 1498 +++++++++++++++ src/msgs/vi.msg | 702 ++++--- src/msgs/vi.po | 1510 +++++++++++++++ src/msgs/wa.msg | 716 ++++---- src/msgs/wa.po | 1505 +++++++++++++++ src/msgs/zh.msg | 730 ++++---- src/msgs/zh.po | 1476 +++++++++++++++ src/odbc/ejabberd_odbc.erl | 37 +- src/odbc/ejabberd_odbc_sup.erl | 2 +- src/odbc/{mssql.sql => mssql2000.sql} | 2 +- src/odbc/mssql2005.sql | 1053 +++++++++++ src/odbc/mysql.sql | 2 +- src/odbc/odbc_queries.erl | 4 +- src/odbc/pg.sql | 2 +- src/p1_fsm.erl | 4 +- src/p1_mnesia.erl | 4 +- src/pam/epam.c | 2 +- src/pam/epam.erl | 2 +- src/randoms.erl | 2 +- src/sha.erl | 2 +- src/shaper.erl | 2 +- src/stringprep/stringprep.erl | 2 +- src/stringprep/stringprep_drv.c | 2 +- src/stringprep/stringprep_sup.erl | 2 +- src/tls/tls.erl | 2 +- src/tls/tls_drv.c | 2 +- src/translate.erl | 2 +- src/treap.erl | 2 +- src/web/ejabberd_http.erl | 72 +- src/web/ejabberd_http.hrl | 8 +- src/web/ejabberd_http_poll.erl | 2 +- src/web/ejabberd_web.erl | 2 +- src/web/ejabberd_web_admin.erl | 2 +- src/web/ejabberd_web_admin.hrl | 2 +- src/xml.erl | 2 +- src/xml_stream.erl | 2 +- 202 files changed, 46384 insertions(+), 9369 deletions(-) create mode 100644 doc/release_notes_2.0.2.txt create mode 100644 src/msgs/ca.po create mode 100644 src/msgs/cs.po create mode 100644 src/msgs/de.po create mode 100644 src/msgs/ejabberd.pot create mode 100644 src/msgs/eo.po create mode 100644 src/msgs/es.po create mode 100644 src/msgs/fr.po create mode 100644 src/msgs/gl.po create mode 100644 src/msgs/it.po create mode 100644 src/msgs/ja.po create mode 100644 src/msgs/nl.po create mode 100644 src/msgs/no.po create mode 100644 src/msgs/pl.po create mode 100644 src/msgs/pt-br.po create mode 100644 src/msgs/pt.po create mode 100644 src/msgs/ru.po create mode 100644 src/msgs/sk.po create mode 100644 src/msgs/sv.po create mode 100644 src/msgs/th.po create mode 100644 src/msgs/tr.po create mode 100644 src/msgs/uk.po create mode 100644 src/msgs/vi.po create mode 100644 src/msgs/wa.po create mode 100644 src/msgs/zh.po rename src/odbc/{mssql.sql => mssql2000.sql} (96%) create mode 100644 src/odbc/mssql2005.sql diff --git a/ChangeLog b/ChangeLog index c03ba622c..b7c0329aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2008-09-16 Jean-Sébastien Pédron + + Merge from trunk (r1457 to r1563). + +2008-09-15 Badlop + + * doc/guide.tex: Fix explanation of mod_muc's anonymous + option. Make clear that an ejabberd_service can only serve a + single external component. Provide Mnesia directory when setting + clustering (thanks to Matthew Reilly) + +2008-09-12 Badlop + + * src/web/ejabberd_http.hrl: Provide Host, Port, Headers and + Transfer Protocol in request (thanks to Eric Cestari)(EJAB-560) + * src/web/ejabberd_http.erl: Likewise + +2008-09-02 Badlop + + * doc/guide.tex: Fix mod_proxy configuration example + * doc/guide.html: Likewise + +2008-09-02 Mickael Remond + + * src/odbc/mssql2000.sql: Script for MSSQL 2000 + * src/odbc/mssql2005.sql: Script for MSSQL 2005 (EJAB-535) + * src/odbc/mssql.sql: removed + 2008-08-27 Jean-Sébastien Pédron * src/mod_roster.erl: Remove a debugging io:format/2. @@ -5,8 +33,14 @@ * src/mod_caps.erl: handle_cast({disco_response, ...}, ...) now receives an #iq record: update the code to handle this. - * src/mod_vcard.erl: VCard are now stored as #xmlel. Mnesia tables are - converted during startup. + * src/mod_vcard.erl: VCards are now stored as #xmlel. Mnesia tables + are converted during startup. + +2008-08-27 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: send last published events now + supports PEP events from unavailable users nodes (EJAB-698) + * src/ejabberd_c2s.erl: Likewise 2008-08-26 Jean-Sébastien Pédron @@ -35,6 +69,81 @@ binary instead of an empty string, for consistency's sake. Fix some bugs. +2008-08-26 Badlop + + * doc/release_notes_2.0.2.txt: Update for final release + + * doc/guide.tex: Windows binary installer requires MSVC++ 5 + * doc/guide.html: Likewise + +2008-08-26 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: get_items bugfix (EJAB-716) + +2008-08-25 Christophe Romain + + * src/mod_privacy_odbc.erl: Prevent case_clause error when + ejabber_odbc:sql_query returns {error, Reason} + * src/mod_vcard_odbc.erl: Likewise + * src/mod_last_odbc.erl: Likewise + * src/mod_offline_odbc.erl: Likewise + +2008-08-25 Badlop + + * src/ejabberd_check.erl: Detect correctly MSSQL and ODBC + configuration (EJAB-710) + +2008-08-24 Geoff Cant + + * src/mod_mud/mod_muc_room.erl: is_visitor/2 fix - use get_role + not get_affiliation + +2008-08-22 Badlop + + * src/ejabberd_router.erl: Fix call to mnesia match_object + +2008-08-21 Badlop + + * doc/guide.tex: Fix names of chatroom to room, user to occupant + * doc/guide.html: Likewise + +2008-08-18 Badlop + + * src/mod_muc/mod_muc_log.erl: MUC log files options: plaintext + format; filename with only room name (EJAB-596) + * doc/guide.tex: Document both options + * doc/guide.html: Likewise + + * src/mod_register.erl: Change password using mod_register always + returns success regardless of real result (EJAB-723) + * src/ejabberd_auth.erl: Likewise + * src/ejabberd_auth_external.erl: Likewise + * src/ejabberd_auth_internal.erl: Likewise + * src/ejabberd_auth_odbc.erl: Likewise + +2008-08-18 Christophe Romain + + * src/mod_pubsub/node_dispatch.erl: Fix call to unexported function + nodetree_default:get_subnodes/2 + +2008-08-17 Badlop + + * contrib/extract_translations/extract_translations.erl: Use + Gettext PO for translators, export to ejabberd MSG (EJAB-648) + * contrib/extract_translations/prepare-translation.sh: Likewise + * doc/guide.tex: Likewise + * doc/guide.html: Likewise + * src/Makefile.in: New option 'make translations' + * src/msgs/ejabberd.pot: Template translation file + * src/msgs/*.po: Generated from old MSG files + * src/msgs/*.msg: Automatic exported from PO files + +2008-08-16 Badlop + + * src/msgs/sv.msg: Fixed formatting typos + + * src/gen_mod.erl: Export stop_module_keep_config/2 (EJAB-706) + 2008-08-14 Jean-Sébastien Pédron * translate.erl (ascii_tolower): Accept 'undefined' as a language and @@ -49,6 +158,25 @@ src/mod_disco.erl, src/mod_last.erl: Convert to the new #iq record from Exmpp. +2008-08-13 Badlop + + * doc/guide.tex: Explain that LDAP is read-only storage (thanks to + Evgeniy Khramtsov) + * doc/guide.html: Likewise + +2008-08-10 Badlop + + * src/msgs/eo.msg: Updated (thanks to Andreas van Cranenburgh) + * src/msgs/nl.msg: Updated (thanks to Andreas van Cranenburgh) + * src/msgs/sk.msg: Updated (thanks to Marek Becka) + * src/msgs/sv.msg: Updated (thanks to Thore Alstromer and Heysan) + +2008-08-09 Badlop + + * src/ejabberd_service.erl: Fix XEP-0114 compliance: define xmlns + in header of error response; include in response the JID of served + component not server (thanks to Sergei Golovan)(EJAB-717) + 2008-08-06 Jean-Sébastien Pédron * src/mod_offline.erl, src/mod_offline_odbc.erl, src/mod_echo.erl, @@ -65,11 +193,131 @@ src/mod_echo.erl, src/mod_offline.erl, src/mod_roster.erl, src/mod_vcard.erl: Update to use the new names used in exmpp_jid. +2008-08-04 Jerome Sautret + + * src/odbc/ejabberd_odbc.erl: Restart the database connection when + it's lost or it reaches timeout with MySQL. Set transaction isolation level + to SERIALIZABLE when establishing connection to MySQL. + +2008-08-01 Badlop + + * doc/release_notes_2.0.2.txt: Added for ejabberd 2.0.2-beta1 + + * src/web/ejabberd_http.erl: Temporary solution for check of + packet size when HTTPS (EJAB-611)(EJAB-507)(EJAB-574) + +2008-07-31 Badlop + + * src/msgs/uk.msg: Fix: each string in a single line + * src/msgs/wa.msg: Likewise + + * src/msgs/es.msg: Fix typo + * src/msgs/gl.msg: Likewise + * src/msgs/pt-br.msg: Likewise + + * src/msgs/zh.msg: Fix some translations (thanks to Zhan Caibao) + + * src/msgs/ca.msg: Updated (thanks to Badlop) + * src/msgs/cs.msg: Updated (thanks to Lukas Poliuvk) + * src/msgs/de.msg: Updated (thanks to Nikolaus Polak) + * src/msgs/es.msg: Updated (thanks to Badlop) + * src/msgs/fr.msg: Updated (thanks to Christophe Romain) + * src/msgs/it.msg: Updated (thanks to Luca Brivio) + * src/msgs/ja.msg: Updated (thanks to Tsukasa Hamano) + * src/msgs/no.msg: Updated (thanks to Stian B. Barmen) + * src/msgs/pl.msg: Updated (thanks to Zbyszek Zolkiewski) + * src/msgs/pt-br.msg: Updated (thanks to Otavio Fernandes) + * src/msgs/ru.msg: Updated (thanks to Evgeniy Khramtsov) + * src/msgs/tr.msg: Updated (thanks to Doruk Fisek) + * src/msgs/uk.msg: Updated (thanks to Ruslan Rakhmanin) + * src/msgs/wa.msg: Updated (thanks to Pablo Saratxaga) + * src/msgs/zh.msg: Updated (thanks to Shelley Shyan) + + * README: Update location where mnesia, ebin and priv directories + are installed; install headers and doc (EJAB-696) + + * doc/guide.tex: Update Process-one name to ProcessOne (EJAB-708) + * doc/guide.html: Likewise + * doc/api/overview.edoc: Likewise + * src/*/*.erl: Likewise + * src/*/*.hrl: Likewise + * src/*/*.c: Likewise + * src/odbc/*.sql: Likewise + +2008-07-30 Badlop + + * src/mod_muc/mod_muc_room.erl: Support Reasons for all + affiliation and role changes (EJAB-306) + + * src/gen_mod.erl: When ejabberd is kindly stopped, don't forget + modules configuration (EJAB-706) + * src/ejabberd_app.erl: Likewise + +2008-07-28 Badlop + + * doc/guide.tex: Document how to get error message when ejabberd + crash dumps at start (EJAB-660) + * doc/guide.html: Likewise + 2008-07-25 Jean-Sébastien Pédron * src/adhoc.erl, src/mod_configure.erl, src/mod_announce.erl, src/mod_adhoc.erl, src/gen_iq_handler.erl: Convert to exmpp. +2008-07-25 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: Speedup startup with many pubsub + nodes (EJAB-669) + * src/mod_pubsub/nodetree_default.erl: Likewise + +2008-07-24 Badlop + + * doc/guide.tex: Include example PAM configuration file + ejabberd.pam (thanks to Evgeniy Khramtsov)(EJAB-704) + * doc/guide.html: Likewise + + * src/mod_proxy65/mod_proxy65_lib.erl: Send protocol compliant + SOCKS5 reply; this breaks support of uncompliant Psi<0.10 (thanks + to Felix Geyer)(EJAB-632) + * src/mod_proxy65/mod_proxy65_stream.erl: Likewise + + * src/mod_register.erl: When a registration is blocked due to IP + limitation, return description in error stanza (EJAB-692) + +2008-07-24 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: Allow owner to subscribe/get its own + node (EJAB-705) + +2008-07-24 Badlop + + * doc/guide.tex: Document room options allow_visitor_nickchange + and allow_visitor_status (EJAB-624) + * doc/guide.html: Likewise + +2008-07-23 Geoff Cant + + * src/mod_muc/mod_muc_room.erl: new room options, + allow_visitor_presence and allow_visitor_nickchange to + block/enable visitors to broadcast presence updates to the room + (EJAB-624). + * src/mod_muc/mod_muc_room.erl: renaming allow_visitor_presence to + allow_visitor_status and altering effect (when false) to remove + custom status tags in presence broadcasts to muc rooms by + visitors. + +2008-07-23 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: remove_user hook removes + subscriptions (EJAB-684), send the last published and not the + first published item (EJAB-675), remove the pubsub/nodes tree, + subscribing to a node sends only last items (EJAB-700) + * src/mod_pubsub/node_pep.erl: added acl and jid match on node + creation permission (EJAB-663) + * src/mod_pubsub/node_default.erl: fix node creation permission + issue for service + * src/mod_pubsub/node_zoo.erl: Likewise + 2008-07-22 Jean-Sébastien Pédron * src/mod_disco.erl, src/gen_iq_handler.erl: Convert to exmpp. @@ -80,6 +328,15 @@ * src/ejabberd_local.erl (process_iq_reply): IQ handler are now always called with arguments in the new format. +2008-07-22 Badlop + + * src/ejabberd_config.erl: If syntax mistake in config file, show + specific error message (EJAB-616) + +2008-07-22 Alexey Shchepin + + * src/odbc/odbc_queries.erl: Fixed a typo + 2008-07-21 Jean-Sébastien Pédron * src/gen_iq_handler.erl: Prepare gen_iq_handler to pass arguments in @@ -94,6 +351,15 @@ * src/jlib.erl: Add support for #xmlel to parse_xdata_submit/1 and friends. This fixes the user search in mod_vcard. +2008-07-03 Jerome Sautret + + * src/ejabberd_ctl.erl: Call reopen_log_hook for each virtual host. + +2008-07-17 Badlop + + * src/mod_muc/mod_muc_room.erl: Fix to allow a server admin to add + himself as owner of a room (EJAB-687) + 2008-07-17 Jean-Sébastien Pédron Merge revisions from 1444 to revision 1457 from trunk. @@ -243,7 +509,7 @@ automatically (EJAB-407) * src/mod_roster.erl: Likewise - + * src/mod_muc/mod_muc_log.erl: Fix XHTML compliance: ensure some language is set, include ID attribute in each message, add microseconds to ensure unique value (EJAB-497) diff --git a/README b/README index df5c68281..e798e9095 100644 --- a/README +++ b/README @@ -30,9 +30,11 @@ To install ejabberd, run this command with system administrator rights sudo make install These commands will: - - Install a startup script: /sbin/ejabberdctl - - Install ejabberd in /var/lib/ejabberd/ - Install the configuration files in /etc/ejabberd/ + - Install ejabberd binary, header and runtime files in /lib/ejabberd/ + - Install the administration script: /sbin/ejabberdctl + - Install ejabberd documentation in /share/doc/ejabberd/ + - Create a spool directory: /var/lib/ejabberd/ - Create a directory for log files: /var/log/ejabberd/ diff --git a/contrib/ejabberd-modules.repo b/contrib/ejabberd-modules.repo index d25d350e0..a38715e90 100644 --- a/contrib/ejabberd-modules.repo +++ b/contrib/ejabberd-modules.repo @@ -1,5 +1,5 @@ % List of ejabberd-modules to add for ejabberd packaging (source archive and installer) % % HTTP-binding: -https://svn.process-one.net/ejabberd-modules/http_bind/tags/ejabberd-2.0.0-beta1 -https://svn.process-one.net/ejabberd-modules/mod_http_fileserver/tags/ejabberd-2.0.0-beta1 +https://svn.process-one.net/ejabberd-modules/http_bind/trunk +https://svn.process-one.net/ejabberd-modules/mod_http_fileserver/trunk diff --git a/contrib/extract_translations/extract_translations.erl b/contrib/extract_translations/extract_translations.erl index 5c727e785..1f38cd08e 100644 --- a/contrib/extract_translations/extract_translations.erl +++ b/contrib/extract_translations/extract_translations.erl @@ -20,9 +20,14 @@ start() -> ets:new(translations, [named_table, public]), + ets:new(translations_obsolete, [named_table, public]), ets:new(files, [named_table, public]), ets:new(vars, [named_table, public]), case init:get_plain_arguments() of + ["-srcmsg2po", Dir, File] -> + print_po_header(File), + Status = process(Dir, File, srcmsg2po), + halt(Status); ["-unused", Dir, File] -> Status = process(Dir, File, unused), halt(Status); @@ -50,7 +55,11 @@ process(Dir, File, Used) -> unused -> ets:foldl(fun({Key, _}, _) -> io:format("~p~n", [Key]) - end, ok, translations); + end, ok, translations); + srcmsg2po -> + ets:foldl(fun({Key, Trans}, _) -> + print_translation_obsolete(Key, Trans) + end, ok, translations_obsolete); _ -> ok end, @@ -74,46 +83,52 @@ parse_form(Dir, File, Form, Used) -> {call, _, {remote, _, {atom, _, translate}, {atom, _, translate}}, - [_, {string, _, Str}] + [_, {string, Line, Str}] } -> - process_string(Dir, File, Str, Used); + process_string(Dir, File, Line, Str, Used); {call, _, {remote, _, {atom, _, translate}, {atom, _, translate}}, [_, {var, _, Name}] } -> case ets:lookup(vars, Name) of - [{_Name, Value}] -> - process_string(Dir, File, Value, Used); + [{_Name, Value, Line}] -> + process_string(Dir, File, Line, Value, Used); _ -> ok end; {match, _, {var, _, Name}, - {string, _, Value} + {string, Line, Value} } -> - ets:insert(vars, {Name, Value}); + ets:insert(vars, {Name, Value, Line}); L when is_list(L) -> lists:foreach( fun(F) -> - parse_form(Dir, File, F, Used) + parse_form(Dir, File, F, Used) end, L); T when is_tuple(T) -> lists:foreach( fun(F) -> - parse_form(Dir, File, F, Used) + parse_form(Dir, File, F, Used) end, tuple_to_list(T)); _ -> ok end. -process_string(_Dir, File, Str, Used) -> +process_string(_Dir, _File, _Line, "", _Used) -> + ok; + +process_string(_Dir, File, Line, Str, Used) -> case {ets:lookup(translations, Str), Used} of {[{_Key, _Trans}], unused} -> ets:delete(translations, Str); {[{_Key, _Trans}], used} -> ok; + {[{_Key, Trans}], srcmsg2po} -> + ets:delete(translations_obsolete, Str), + print_translation(File, Line, Str, Trans); {_, used} -> case ets:lookup(files, File) of [{_}] -> @@ -127,6 +142,15 @@ process_string(_Dir, File, Str, Used) -> _ -> io:format("{~p, \"\"}.~n", [Str]) end, ets:insert(translations, {Str, ""}); + {_, srcmsg2po} -> + case ets:lookup(files, File) of + [{_}] -> + ok; + _ -> + ets:insert(files, {File}) + end, + ets:insert(translations, {Str, ""}), + print_translation(File, Line, Str, ""); _ -> ok end. @@ -140,7 +164,8 @@ load_file(File) -> "" -> ok; _ -> - ets:insert(translations, {Orig, Trans}) + ets:insert(translations, {Orig, Trans}), + ets:insert(translations_obsolete, {Orig, Trans}) end end, Terms); Err -> @@ -191,3 +216,77 @@ print_usage() -> " extract_translations . ./msgs/ru.msg~n" ). + +%%% +%%% Gettext +%%% + +print_po_header(File) -> + MsgProps = get_msg_header_props(File), + {Language, [LastT | AddT]} = prepare_props(MsgProps), + application:load(ejabberd), + {ok, Version} = application:get_key(ejabberd, vsn), + print_po_header(Version, Language, LastT, AddT). + +get_msg_header_props(File) -> + {ok, F} = file:open(File, [read]), + Lines = get_msg_header_props(F, []), + file:close(F), + Lines. + +get_msg_header_props(F, Lines) -> + String = io:get_line(F, ""), + case io_lib:fread("% ", String) of + {ok, [], RemString} -> + case io_lib:fread("~s", RemString) of + {ok, [Key], Value} when Value /= "\n" -> + %% The first character in Value is a blankspace: + %% And the last characters are 'slash n' + ValueClean = string:substr(Value, 2, string:len(Value)-2), + get_msg_header_props(F, Lines ++ [{Key, ValueClean}]); + _ -> + get_msg_header_props(F, Lines) + end; + _ -> + Lines + end. + +prepare_props(MsgProps) -> + Language = proplists:get_value("Language:", MsgProps), + Authors = proplists:get_all_values("Author:", MsgProps), + {Language, Authors}. + +print_po_header(Version, Language, LastTranslator, AdditionalTranslatorsList) -> + AdditionalTranslatorsString = build_additional_translators(AdditionalTranslatorsList), + HeaderString = + "msgid \"\"\n" + "msgstr \"\"\n" + "\"Project-Id-Version: " ++ Version ++ "\\n\"\n" + ++ "\"X-Language: " ++ Language ++ "\\n\"\n" + "\"Last-Translator: " ++ LastTranslator ++ "\\n\"\n" + ++ AdditionalTranslatorsString ++ + "\"MIME-Version: 1.0\\n\"\n" + "\"Content-Type: text/plain; charset=UTF-8\\n\"\n" + "\"Content-Transfer-Encoding: 8bit\\n\"\n", + io:format("~s~n", [HeaderString]). + +build_additional_translators(List) -> + lists:foldl( + fun(T, Str) -> + Str ++ "\"X-Additional-Translator: " ++ T ++ "\\n\"\n" + end, + "", + List). + +print_translation(File, Line, Str, StrT) -> + {ok, StrQ, _} = regexp:gsub(Str, "\"", "\\\""), + {ok, StrTQ, _} = regexp:gsub(StrT, "\"", "\\\""), + io:format("#: ~s:~p~nmsgid \"~s\"~nmsgstr \"~s\"~n~n", [File, Line, StrQ, StrTQ]). + +print_translation_obsolete(Str, StrT) -> + File = "unknown.erl", + Line = 1, + {ok, StrQ, _} = regexp:gsub(Str, "\"", "\\\""), + {ok, StrTQ, _} = regexp:gsub(StrT, "\"", "\\\""), + io:format("#: ~s:~p~n#~~ msgid \"~s\"~n#~~ msgstr \"~s\"~n~n", [File, Line, StrQ, StrTQ]). + diff --git a/contrib/extract_translations/prepare-translation.sh b/contrib/extract_translations/prepare-translation.sh index 2fd895bf5..d1c435fbe 100755 --- a/contrib/extract_translations/prepare-translation.sh +++ b/contrib/extract_translations/prepare-translation.sh @@ -8,10 +8,10 @@ prepare_dirs () # Where is Erlang binary ERL=`which erl` - EJA_DIR=`pwd`/../.. + EJA_DIR=`pwd`/.. EXTRACT_DIR=$EJA_DIR/contrib/extract_translations/ - EXTRACT_ERL=extract_translations.erl - EXTRACT_BEAM=extract_translations.beam + EXTRACT_ERL=$EXTRACT_DIR/extract_translations.erl + EXTRACT_BEAM=$EXTRACT_DIR/extract_translations.beam SRC_DIR=$EJA_DIR/src MSGS_DIR=$SRC_DIR/msgs @@ -22,9 +22,7 @@ prepare_dirs () if !([[ -x $EXTRACT_BEAM ]]) then - echo -n "Compiling extract_translations.erl: " sh -c "cd $EXTRACT_DIR; $ERL -compile $EXTRACT_ERL" - echo "ok" fi } @@ -140,6 +138,116 @@ find_unused_full () cd .. } +extract_lang_srcmsg2po () +{ + LANG_CODE=$1 + MSGS_PATH=$MSGS_DIR/$LANG_CODE.msg + PO_PATH=$MSGS_DIR/$LANG_CODE.po + + $ERL -pa $EXTRACT_DIR -pa $SRC_DIR -noinput -noshell -s extract_translations -s init stop -extra -srcmsg2po . $MSGS_PATH >$PO_PATH.1 + sed -e 's/ \[\]$/ \"\"/g;' $PO_PATH.1 > $PO_PATH.2 + msguniq --sort-by-file $PO_PATH.2 --output-file=$PO_PATH + + rm $PO_PATH.* +} + +extract_lang_src2pot () +{ + LANG_CODE=ejabberd + MSGS_PATH=$MSGS_DIR/$LANG_CODE.msg + POT_PATH=$MSGS_DIR/$LANG_CODE.pot + + echo -n "" >$MSGS_PATH + echo "% Language: Language Name" >>$MSGS_PATH + echo "% Author: Translator name and contact method" >>$MSGS_PATH + echo "" >>$MSGS_PATH + + cd $SRC_DIR + $ERL -pa $EXTRACT_DIR -pa $SRC_DIR -noinput -noshell -s extract_translations -s init stop -extra -srcmsg2po . $MSGS_PATH >$POT_PATH.1 + sed -e 's/ \[\]$/ \"\"/g;' $POT_PATH.1 > $POT_PATH.2 + msguniq --sort-by-file $POT_PATH.2 --output-file=$POT_PATH + + rm $POT_PATH.* + rm $MSGS_PATH +} + +extract_lang_popot2po () +{ + LANG_CODE=$1 + PO_PATH=$MSGS_DIR/$LANG_CODE.po + POT_PATH=$MSGS_DIR/ejabberd.pot + + msgmerge $PO_PATH $POT_PATH >$PO_PATH.translate 2>/dev/null + mv $PO_PATH.translate $PO_PATH +} + +extract_lang_po2msg () +{ + LANG_CODE=$1 + PO_PATH=$LANG_CODE.po + MS_PATH=$PO_PATH.ms + MSGID_PATH=$PO_PATH.msgid + MSGSTR_PATH=$PO_PATH.msgstr + MSGS_PATH=$LANG_CODE.msg + + cd $MSGS_DIR + + # Check PO has correct ~ + # Let's convert to C format so we can use msgfmt + PO_TEMP=$LANG_CODE.po.temp + cat $PO_PATH | sed 's/%/perc/g' | sed 's/~/%/g' | sed 's/#:.*/#, c-format/g' >$PO_TEMP + msgfmt $PO_TEMP --check-format + result=$? + rm $PO_TEMP + if [ $result -ne 0 ] ; then + exit 1 + fi + + msgattrib $PO_PATH --translated --no-fuzzy --no-obsolete --no-location --no-wrap | grep "^msg" | tail --lines=+3 >$MS_PATH + grep "^msgid" $PO_PATH.ms | sed 's/^msgid //g' >$MSGID_PATH + grep "^msgstr" $PO_PATH.ms | sed 's/^msgstr //g' >$MSGSTR_PATH + paste $MSGID_PATH $MSGSTR_PATH --delimiter=, | awk '{print "{" $0 "}."}' | sort -g >$MSGS_PATH + + rm $MS_PATH + rm $MSGID_PATH + rm $MSGSTR_PATH +} + +extract_lang_updateall () +{ + echo "Generating POT" + extract_lang_src2pot + + cd $MSGS_DIR + echo "" + echo -e "File Missing Language Last translator" + echo -e "---- ------- -------- ---------------" + for i in *.msg; do + LANG_CODE=${i%.msg} + echo -n $LANG_CODE | awk '{printf "%-6s", $1 }' + + # Convert old MSG file to PO + PO=$LANG_CODE.po + [ -f $PO ] || extract_lang_srcmsg2po $LANG_CODE + + extract_lang_popot2po $LANG_CODE + extract_lang_po2msg $LANG_CODE + + MISSING=`msgfmt --statistics $PO 2>&1 | awk '{printf "%5s", $4 }'` + echo -n " $MISSING" + + LANGUAGE=`grep "Language:" $PO | sed 's/\"X-Language: //g' | sed 's/\\\\n\"//g' | awk '{printf "%-12s", $1}'` + echo -n " $LANGUAGE" + + LASTAUTH=`grep "Last-Translator" $PO | sed 's/\"Last-Translator: //g' | sed 's/\\\\n\"//g'` + echo " $LASTAUTH" + done + echo "" + rm messages.mo + + cd .. +} + translation_instructions () { echo "" @@ -158,34 +266,56 @@ translation_instructions () echo " $MSGS_PATH" } +prepare_dirs case "$1" in - -help) - echo "Options:" - echo " -langall" - echo " -lang LANGUAGE_FILE" - echo "" - echo "Example:" - echo " ./prepare-translation.sh -lang es.msg" - exit 0 - ;; -lang) LANGU=$2 - prepare_dirs extract_lang $LANGU shift shift ;; -langall) - prepare_dirs extract_lang_all shift ;; - *) - echo "unknown option: '$1 $2'" + -srcmsg2po) + LANG_CODE=$2 + extract_lang_srcmsg2po $LANG_CODE shift shift ;; + -popot2po) + LANG_CODE=$2 + extract_lang_popot2po $LANG_CODE + shift + shift + ;; + -src2pot) + extract_lang_src2pot + shift + ;; + -po2msg) + LANG_CODE=$2 + extract_lang_po2msg $LANG_CODE + shift + shift + ;; + -updateall) + extract_lang_updateall + shift + ;; + *) + echo "Options:" + echo " -langall" + echo " -lang LANGUAGE_FILE" + echo " -srcmsg2po LANGUAGE Construct .msg file using source code to PO file" + echo " -src2pot Generate template POT file from source code" + echo " -popot2po LANGUAGE Update PO file with template POT file" + echo " -po2msg LANGUAGE Export PO file to MSG file" + echo " -updateall Generate POT and update all PO" + echo "" + echo "Example:" + echo " ./prepare-translation.sh -lang es.msg" + exit 0 + ;; esac - -echo "" -echo "End." diff --git a/doc/api/overview.edoc b/doc/api/overview.edoc index 55f7b1f68..89815c8c0 100644 --- a/doc/api/overview.edoc +++ b/doc/api/overview.edoc @@ -1,6 +1,6 @@ @author Mickael Remond [http://www.process-one.net/] -@copyright 2007 Process-one +@copyright 2007 ProcessOne @version {@vsn}, {@date} {@time} @title ejabberd Development API Documentation diff --git a/doc/guide.html b/doc/guide.html index 02ea12132..97e0f9248 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -272,9 +272,9 @@ Support for virtual hosting.

    Chapter 2  Installing ejabberd

    2.1  Installing ejabberd with Binary Installer

    Probably the easiest way to install an ejabberd instant messaging server -is using the binary installer published by Process-one. +is using the binary installer published by ProcessOne. The binary installers of released ejabberd versions -are available in the Process-one ejabberd downloads page: +are available in the ProcessOne ejabberd downloads page: http://www.process-one.net/en/ejabberd/downloads

    The installer will deploy and configure a full featured ejabberd server and does not require any extra dependencies.

    In *nix systems, remember to set executable the binary installer before starting it. For example:

    chmod +x ejabberd-2.0.0_1-linux-x86-installer.bin
    @@ -290,7 +290,19 @@ go to the Windows service settings and set ejabberd to be automatically started.
     Note that the Windows service is a feature still in development, 
     and for example it doesn’t read the file ejabberdctl.cfg.

    On a *nix system, if you want ejabberd to be started as daemon at boot time, copy ejabberd.init from the ’bin’ directory to something like /etc/init.d/ejabberd -(depending on your distribution) and call /etc/inid.d/ejabberd start to start it.

    The ejabberdctl administration script is included in the bin directory. +(depending on your distribution) and call /etc/inid.d/ejabberd start to start it.

    If ejabberd doesn’t start correctly in Windows, +try to start it using the shortcut in desktop or start menu. +If the window shows error 14001, the solution is to install: +"Microsoft Visual C++ 2005 SP1 Redistributable Package". +You can download it from +www.microsoft.com. +Then uninstall ejabberd and install it again.

    If ejabberd doesn’t start correctly and a crash dump is generated, +there was a severe problem. +You can try starting ejabberd with +the script bin/live.bat in Windows, +or with the command bin/ejabberdctl live in other Operating Systems. +This way you see the error message provided by Erlang +and can identify what is exactly the problem.

    The ejabberdctl administration script is included in the bin directory. Please refer to the section 4.1 for details about ejabberdctl, and configurable options to fine tune the Erlang runtime system.

    2.2  Installing ejabberd with Operating System specific packages

    Some Operating Systems provide a specific ejabberd package adapted to @@ -324,7 +336,7 @@ GNU Make

  • GNU Iconv 1.8 or higher, for the IRC Transport (mod_irc). Optional. Not needed on systems with GNU Libc.
  • 2.4.2  Download Source Code

    -

    Released versions of ejabberd are available in the Process-one ejabberd downloads page: +

    Released versions of ejabberd are available in the ProcessOne ejabberd downloads page: http://www.process-one.net/en/ejabberd/downloads

    Alternatively, the latest development version can be retrieved from the Subversion repository using this command:

    svn co http://svn.process-one.net/ejabberd/trunk ejabberd
    @@ -405,7 +417,12 @@ Node ejabberd@localhost is started. Status: started
     ejabberd is running
     
     ejabberdctl stop
    -

    Please refer to the section 4.1 for details about ejabberdctl, +

    If ejabberd doesn’t start correctly and a crash dump is generated, +there was a severe problem. +You can try starting ejabberd with +the command ejabberdctl live +to see the error message provided by Erlang +and can identify what is exactly the problem.

    Please refer to the section 4.1 for details about ejabberdctl, and configurable options to fine tune the Erlang runtime system.

    2.4.6  Specific Notes for BSD

    The command to compile ejabberd in BSD systems is: @@ -976,8 +993,12 @@ version, you can kill(1) epam process periodically to reduce i consumption: ejabberd will restart this process immediately.

  • epam program tries to turn off delays on authentication failures. However, some PAM modules ignore this behavior and rely on their own configuration options. -The example configuration file ejabberd.pam shows how to turn off delays in -pam_unix.so module. It is not a ready to use configuration file: you must use it +You can create a configuration file ejabberd.pam. +This example shows how to turn off delays in pam_unix.so module: +
    #%PAM-1.0
    +auth        sufficient  pam_unix.so likeauth nullok nodelay
    +account     sufficient  pam_unix.so
    +
    That is not a ready to use configuration file: you must use it as a hint when building your own PAM configuration instead. Note that if you want to disable delays on authentication failures in the PAM configuration file, you have to restrict access to this file, so a malicious user can’t use your configuration to perform brute-force @@ -1113,7 +1134,7 @@ To define a shaper named ‘normal’ with traffic speed limi
  • 3.1.7  Default Language

    The option language defines the default language of server strings that -can be seen by Jabber clients. If a Jabber client do not support +can be seen by Jabber clients. If a Jabber client does not support xml:lang, the specified language is used. The default value is en. In order to take effect there must be a translation file <language>.msg in ejabberd’s msgs directory.

    Examples: @@ -1122,7 +1143,7 @@ To set Russian as default language:

    {language, "ru"}.
     
  • To set Spanish as default language:
    {language, "es"}.
    -
  • +

    Appendix A provides more details about internationalization and localization.

    3.1.8  Include Additional Configuration Files

    The option include_config_file in a configuration file instructs ejabberd to include other configuration files immediately.

    The basic usage is:

    {include_config_file, <filename>}.
    @@ -1422,7 +1443,9 @@ module loaded!

    3.2.5  LDAP

    ejabberd has built-in LDAP support. You can authenticate users against LDAP server and use LDAP directory as vCard storage. Shared rosters are not supported -yet.

    +yet.

    Note that ejabberd treats LDAP as a read-only storage: +it is possible to consult data, but not possible to +create accounts, change password or edit vCard that is stored in LDAP.

    Connection

    Parameters:

    ldap_servers
    List of IP addresses or DNS names of your @@ -1928,23 +1951,22 @@ connected user was last active on the server, or to query the uptime of the the processing discipline for Last activity (jabber:iq:last) IQ queries (see section 3.3.2).

    3.3.8  mod_muc

    -

    With this module enabled, your server will support Multi-User Chat -(XEP-0045). End users will be able to join text conferences.

    Some of the features of Multi-User Chat: +

    This module provides a Multi-User Chat (XEP-0045) service. +Users can discover existing rooms, join or create them. +Occupants of a room can chat in public or have private chats.

    Some of the features of Multi-User Chat:

    • -Sending private messages to room participants. -
    • Inviting users. -
    • Setting a conference topic. +Sending public and private messages to room occupants. +
    • Inviting other users to a room. +
    • Setting a room subject.
    • Creating password protected rooms. -
    • Kicking and banning participants. +
    • Kicking and banning occupants.

    The MUC service allows any Jabber ID to register a nickname, so nobody else can use that nickname in any room in the MUC service. To register a nickname, open the Service Discovery in your -Jabber client and Register in the MUC service.

    The MUC service allows the service administrator to send a message -to all existing chatrooms. -To do so, send the message to the Jabber ID of the MUC service.

    This module supports clustering and load +Jabber client and register in the MUC service.

    This module supports clustering and load balancing. One module can be started per cluster node. Rooms are distributed at creation time on all available MUC module -instances. The multi-user chat module is clustered but the room +instances. The multi-user chat module is clustered but the rooms themselves are not clustered nor fault-tolerant: if the node managing a set of rooms goes down, the rooms disappear and they will be recreated on an available node on first connection attempt.

    Module options: @@ -1956,19 +1978,19 @@ hostname of the virtual host with the prefix ‘conference.’ is replaced at start time with the real virtual host name.

    access
    You can specify who is allowed to use -the Multi-User Chat service (by default, everyone is allowed to use it). +the Multi-User Chat service. By default everyone is allowed to use it.
    access_create
    To configure who is allowed to create new rooms at the Multi-User Chat service, this option -can be used (by default, everybody is allowed to create rooms). +can be used. By default everybody is allowed to create rooms.
    access_persistent
    To configure who is -allowed to modify the ’persistent’ chatroom option -(by default, everybody is allowed to modify that option). +allowed to modify the ’persistent’ room option. +By default everybody is allowed to modify that option.
    access_admin
    This option specifies -who is allowed to administrate the Multi-User Chat service (the default +who is allowed to administrate the Multi-User Chat service. The default value is none, which means that only the room creator can -administer his room). +administer his room. The administrators can send a normal message to the service JID, -and it will be shown in every active room as a service message. +and it will be shown in all active rooms as a service message. The administrators can send a groupchat message to the JID of an active room, and the message will be shown in the room as a service message.
    history_size
    A small history of @@ -1978,44 +2000,43 @@ to keep and send to users joining the room. The value is an integer. Setting the value to 0 disables the history feature and, as a result, nothing is kept in memory. The default value is 20. This value is global and thus affects all rooms on the -server. +service.
    max_users
    This option defines at -the server level, the maximum number of users allowed per MUC +the service level, the maximum number of users allowed per room. It can be lowered in each room configuration but cannot be -increased in individual MUC room configuration. The default value is +increased in individual room configuration. The default value is 200.
    max_users_admin_threshold
    This option defines the -number of MUC admins or owners to allow to enter the room even if -the maximum number of allowed users is reached. The default limits -is 5. In most cases this default value is the best setting. +number of service admins or room owners allowed to enter the room when +the maximum number of allowed occupants was reached. The default limit +is 5.
    max_user_conferences
    - This option define the maximum -number of chat room any given user will be able to join. The default + This option defines the maximum +number of rooms that any given user can join. The default value is 10. This option is used to prevent possible abuses. Note that -this is a soft limits: Some users can sometime join more conferences +this is a soft limit: some users can sometimes join more conferences in cluster configurations.
    min_message_interval
    This option defines the minimum interval between two messages send -by a user in seconds. This option is global and valid for all chat +by an occupant in seconds. This option is global and valid for all rooms. A decimal value can be used. When this option is not defined, message rate is not limited. This feature can be used to protect a -MUC service from users abuses and limit number of messages that will +MUC service from occupant abuses and limit number of messages that will be broadcasted by the service. A good value for this minimum message -interval is 0.4 second. If a user tries to send messages faster, an -error is send back explaining that the message have been discarded +interval is 0.4 second. If an occupant tries to send messages faster, an +error is send back explaining that the message has been discarded and describing the reason why the message is not acceptable.
    min_presence_interval
    This option defines the -minimum of time between presence changes coming from a given user in -seconds. This option is global and valid for all chat rooms. A +minimum of time between presence changes coming from a given occupant in +seconds. This option is global and valid for all rooms. A decimal value can be used. When this option is not defined, no restriction is applied. This option can be used to protect a MUC -service for users abuses, as fastly changing a user presence will -result in possible large presence packet broadcast. If a user tries +service for occupants abuses. If an occupant tries to change its presence more often than the specified interval, the presence is cached by ejabberd and only the last presence is -broadcasted to all users in the room after expiration of the +broadcasted to all occupants in the room after expiration of the interval delay. Intermediate presence packets are silently discarded. A good value for this option is 4 seconds.
    default_room_options
    @@ -2028,6 +2049,12 @@ The available room options and the default values are:
    {allow_private_messages, true}
    Occupants can send private messages to other occupants.
    {allow_query_users, true}
    Occupants can send IQ queries to other occupants.
    {allow_user_invites, false}
    Allow occupants to send invitations. +
    {allow_visitor_nickchange, true}
    Allow visitors to +change nickname. +
    {allow_visitor_status, true}
    Allow visitors to send +status text in presence updates. If disallowed, the status +text is stripped before broadcasting the presence update to all +the room occupants.
    {anonymous, true}
    Occupants are allowed to see the real JIDs of other occupants.
    {logging, false}
    The public messages are logged using mod_muc_log.
    {max_users, 200}
    Maximum number of occupants in the room. @@ -2097,8 +2124,8 @@ and the default value of 20 history messages will be send to the users. {access_admin, muc_admins}]}, ... ]}. -
  • In the following example, MUC anti abuse options are used. A -user cannot send more than one message every 0.4 seconds and cannot +
  • In the following example, MUC anti abuse options are used. An +occupant cannot send more than one message every 0.4 seconds and cannot change its presence more than once every 4 seconds. No ACLs are defined, but some user restriction could be added as well:
    {modules,
      [
    @@ -2108,7 +2135,7 @@ defined, but some user restriction could be added as well:
       ...
      ]}.
     
  • This example shows how to use default_room_options to make sure -newly created chatrooms have by default those options. +the newly created rooms have by default those options.
    {modules,
      [
       ...
    @@ -2128,17 +2155,17 @@ newly created chatrooms have by default those options.
      ]}.
     
  • 3.3.9  mod_muc_log

    -

    This module enables optional logging of Multi-User Chat (MUC) conversations to -HTML. Once you enable this module, users can join a chatroom using a MUC capable +

    This module enables optional logging of Multi-User Chat (MUC) public conversations to +HTML. Once you enable this module, users can join a room using a MUC capable Jabber client, and if they have enough privileges, they can request the -configuration form in which they can set the option to enable chatroom logging.

    Features: +configuration form in which they can set the option to enable room logging.

    Features:

    • -Chatroom details are added on top of each page: room title, JID, +Room details are added on top of each page: room title, JID, author, subject and configuration.
    • -The room JID in the generated HTML is a link to join the chatroom (using +The room JID in the generated HTML is a link to join the room (using XMPP URI). -
    • Subject and chatroom configuration changes are tracked and displayed. +
    • Subject and room configuration changes are tracked and displayed.
    • Joins, leaves, nick changes, kicks, bans and ‘/me’ are tracked and displayed, including the reason if available.
    • Generated HTML files are XHTML 1.0 Transitional and CSS compliant. @@ -2151,7 +2178,7 @@ displayed, including the reason if available.

    Options:

    access_log
    -This option restricts which users are allowed to enable or disable chatroom +This option restricts which occupants are allowed to enable or disable room logging. The default value is muc_admin. Note for this default setting you need to have an access rule for muc_admin in order to take effect.
    cssfile
    @@ -2161,34 +2188,46 @@ file or if they need to use the embedded CSS file. Allowed values are include the embedded CSS code. With the latter, you can specify the URL of the custom CSS file (for example: ‘http://example.com/my.css’). The default value is false. +
    dirname
    +Allows to configure the name of the room directory. +Allowed values are room_jid and room_name. +With the first value, the room directory name will be the full room JID. +With the latter, the room directory name will be only the room name, +not including the MUC service name. +The default value is room_jid.
    dirtype
    The type of the created directories can be specified with this option. Allowed values are subdirs and plain. With the first value, subdirectories are created for each year and month. With the latter, the names of the log files contain the full date, and there are no subdirectories. The default value is subdirs. +
    file_format
    +Define the format of the log files: +html stores in HTML format, +plaintext stores in plain text. +The default value is html.
    outdir
    This option sets the full path to the directory in which the HTML files should be stored. Make sure the ejabberd daemon user has write access on that directory. The default value is "www/muc". -
    timezone
    -The time zone for the logs is configurable with this option. Allowed values -are local and universal. With the first value, the local time, -as reported to Erlang by the operating system, will be used. With the latter, -GMT/UTC time will be used. The default value is local.
    spam_prevention
    To prevent spam, the spam_prevention option adds a special attribute to links that prevent their indexation by search engines. The default value is true, which mean that nofollow attributes will be added to user submitted links. +
    timezone
    +The time zone for the logs is configurable with this option. Allowed values +are local and universal. With the first value, the local time, +as reported to Erlang by the operating system, will be used. With the latter, +GMT/UTC time will be used. The default value is local.
    top_link
    With this option you can customize the link on the top right corner of each log file. The syntax of this option is {"URL", "Text"}. The default value is {"/", "Home"}.

    Examples:

    • -In the first example any chatroom owner can enable logging, and a -custom CSS file will be used (http://example.com/my.css). Further, the names +In the first example any room owner can enable logging, and a +custom CSS file will be used (http://example.com/my.css). The names of the log files will contain the full date, and there will be no subdirectories. The log files will be stored in /var/www/muclogs, and the time zone will be GMT/UTC. Finally, the top link will be @@ -2202,6 +2241,7 @@ time zone will be GMT/UTC. Finally, the top link will be {access_log, muc}, {cssfile, "http://example.com/my.css"}, {dirtype, plain}, + {dirname, room_jid}, {outdir, "/var/www/muclogs"}, {timezone, universal}, {spam_prevention, true}, @@ -2211,7 +2251,7 @@ time zone will be GMT/UTC. Finally, the top link will be ]}.
    • In the second example only admin1@example.org and admin2@example.net can enable logging, and the embedded CSS file will be -used. Further, the names of the log files will only contain the day (number), +used. The names of the log files will only contain the day (number), and there will be subdirectories for each year and month. The log files will be stored in /var/www/muclogs, and the local time will be used. Finally, the top link will be the default <a href="/">Home</a>. @@ -2324,8 +2364,8 @@ The simpliest configuration of the module: {access, proxy65_access, [{allow, proxy_users}, {deny, all}]}. {acl, admin, {user, "admin", "example.org"}}. -{shaper, normal, {maxrate, 10240}}. %% 10 Kbytes/sec -{access, proxy65_shaper, [{none, admin}, {normal, all}]}. +{shaper, proxyrate, {maxrate, 10240}}. %% 10 Kbytes/sec +{access, proxy65_shaper, [{none, admin}, {proxyrate, proxy_users}]}. {modules, [ @@ -2652,7 +2692,9 @@ and that all virtual hosts will be searched instead of only the current one:

      3.3.22  mod_vcard_ldap

      ejabberd can map LDAP attributes to vCard fields. This behaviour is implemented in the mod_vcard_ldap module. This module does not depend on the -authentication method (see 3.2.5).

      The mod_vcard_ldap module has +authentication method (see 3.2.5).

      Note that ejabberd treats LDAP as a read-only storage: +it is possible to consult data, but not possible to +create accounts, change password or edit vCard that is stored in LDAP.

      The mod_vcard_ldap module has its own optional parameters. The first group of parameters has the same meaning as the top-level LDAP parameters to set the authentication method: ldap_servers, ldap_port, ldap_rootdn, @@ -3221,7 +3263,15 @@ so it is important to use it with extremely care. There are some simple and safe examples in the article Interconnecting Erlang Nodes

      To exit the shell, close the window or press the keys: control+c control+c.

      Appendix A  Internationalization and Localization

      -

      All built-in modules support the xml:lang attribute inside IQ queries. +

      The source code of ejabberd supports localization. +The translators can edit the +gettext .po files +using any capable program (KBabel, Lokalize, Poedit...) or a simple text editor.

      Then gettext +is used to extract, update and export those .po files to the .msg format read by ejabberd. +To perform those management tasks, in the src/ directory execute make translations. +The translatable strings are extracted from source code to generate the file ejabberd.pot. +This file is merged with each .po file to produce updated .po files. +Finally those .po files are exported to .msg files, that have a format easily readable by ejabberd.

      All built-in modules support the xml:lang attribute inside IQ queries. Figure A.1, for example, shows the reply to the following query:

      <iq id='5'
           to='example.org'
      @@ -3262,7 +3312,7 @@ Alexey Shchepin (xmpp:aleksey@jabber.ru
    • Vsevolod Pelipas (xmpp:vsevoload@jabber.ru)

    Appendix D  Copyright Information

    Ejabberd Installation and Operation Guide.
    -Copyright © 2003 — 2008 Process-one

    This document is free software; you can redistribute it and/or +Copyright © 2003 — 2008 ProcessOne

    This document 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 document is distributed in the hope that it will be useful, diff --git a/doc/guide.tex b/doc/guide.tex index 17cfbeb80..7d5631f9c 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -5,7 +5,7 @@ \usepackage{graphics} \usepackage{hevea} \usepackage[pdftex,colorlinks,unicode,urlcolor=blue,linkcolor=blue, - pdftitle=Ejabberd\ Installation\ and\ Operation\ Guide,pdfauthor=Process-one,pdfsubject=ejabberd,pdfkeywords=ejabberd, + pdftitle=Ejabberd\ Installation\ and\ Operation\ Guide,pdfauthor=ProcessOne,pdfsubject=ejabberd,pdfkeywords=ejabberd, pdfpagelabels=false]{hyperref} \usepackage{makeidx} %\usepackage{showidx} % Only for verifying the index entries. @@ -208,9 +208,9 @@ ejabberd Development Team \makesection{install.binary}{Installing \ejabberd{} with Binary Installer} Probably the easiest way to install an \ejabberd{} instant messaging server -is using the binary installer published by Process-one. +is using the binary installer published by ProcessOne. The binary installers of released \ejabberd{} versions -are available in the Process-one \ejabberd{} downloads page: +are available in the ProcessOne \ejabberd{} downloads page: \ahrefurl{http://www.process-one.net/en/ejabberd/downloads} The installer will deploy and configure a full featured \ejabberd{} @@ -241,6 +241,22 @@ On a *nix system, if you want ejabberd to be started as daemon at boot time, copy \term{ejabberd.init} from the 'bin' directory to something like \term{/etc/init.d/ejabberd} (depending on your distribution) and call \term{/etc/inid.d/ejabberd start} to start it. +If \term{ejabberd} doesn't start correctly in Windows, +try to start it using the shortcut in desktop or start menu. +If the window shows error 14001, the solution is to install: +"Microsoft Visual C++ 2005 SP1 Redistributable Package". +You can download it from +\footahref{http://www.microsoft.com/}{www.microsoft.com}. +Then uninstall \ejabberd{} and install it again. + +If \term{ejabberd} doesn't start correctly and a crash dump is generated, +there was a severe problem. +You can try starting \term{ejabberd} with +the script \term{bin/live.bat} in Windows, +or with the command \term{bin/ejabberdctl live} in other Operating Systems. +This way you see the error message provided by Erlang +and can identify what is exactly the problem. + The \term{ejabberdctl} administration script is included in the \term{bin} directory. Please refer to the section~\ref{ejabberdctl} for details about \term{ejabberdctl}, and configurable options to fine tune the Erlang runtime system. @@ -294,7 +310,7 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need: \makesubsection{download}{Download Source Code} \ind{install!download} -Released versions of \ejabberd{} are available in the Process-one \ejabberd{} downloads page: +Released versions of \ejabberd{} are available in the ProcessOne \ejabberd{} downloads page: \ahrefurl{http://www.process-one.net/en/ejabberd/downloads} \ind{Subversion repository} @@ -415,6 +431,13 @@ ejabberd is running ejabberdctl stop \end{verbatim} +If \term{ejabberd} doesn't start correctly and a crash dump is generated, +there was a severe problem. +You can try starting \term{ejabberd} with +the command \term{ejabberdctl live} +to see the error message provided by Erlang +and can identify what is exactly the problem. + Please refer to the section~\ref{ejabberdctl} for details about \term{ejabberdctl}, and configurable options to fine tune the Erlang runtime system. @@ -727,7 +750,7 @@ The available modules, their purpose and the options allowed by each one are: Handles incoming s2s connections.\\ Options: \texttt{inet6}, \texttt{ip}, \texttt{max\_stanza\_size} \titem{\texttt{ejabberd\_service}} - Interacts with \footahref{http://www.ejabberd.im/tutorials-transports}{external components} + Interacts with an \footahref{http://www.ejabberd.im/tutorials-transports}{external component} (as defined in the Jabber Component Protocol (\xepref{0114}).\\ Options: \texttt{access}, \texttt{hosts}, \texttt{inet6}, \texttt{ip}, \texttt{shaper}, \texttt{service\_check\_from} @@ -749,9 +772,10 @@ This is a detailed description of each option allowed by the listening modules: external components. The option can be either \term{true} or \term{false}. The default value is \term{true} which conforms to \xepref{0114}. \titem{\{hosts, [Hostnames], [HostOptions]\}} \ind{options!hosts} - This option of \term{ejabberd\_service} allows to define one or more hostnames - of external Jabber components that provide a service. - In \term{HostOptions} it is possible to define the password required to those components + The external Jabber component that connects to this \term{ejabberd\_service} + can serve one or more hostnames. + In \term{HostOptions} you can define options for the component; + currently the only allowed option is the password required to the component when attempt to connect to ejabberd: \poption{\{password, Secret\}}. Note that you cannot define in a single \term{ejabberd\_service} components of different services: add an \term{ejabberd\_service} for each service, @@ -1159,8 +1183,14 @@ version, you can \term{kill(1)} \term{epam} process periodically to reduce its m consumption: \ejabberd{} will restart this process immediately. \item \term{epam} program tries to turn off delays on authentication failures. However, some PAM modules ignore this behavior and rely on their own configuration options. -The example configuration file \term{ejabberd.pam} shows how to turn off delays in -\term{pam\_unix.so} module. It is not a ready to use configuration file: you must use it +You can create a configuration file \term{ejabberd.pam}. +This example shows how to turn off delays in \term{pam\_unix.so} module: +\begin{verbatim} +#%PAM-1.0 +auth sufficient pam_unix.so likeauth nullok nodelay +account sufficient pam_unix.so +\end{verbatim} +That is not a ready to use configuration file: you must use it as a hint when building your own PAM configuration instead. Note that if you want to disable delays on authentication failures in the PAM configuration file, you have to restrict access to this file, so a malicious user can't use your configuration to perform brute-force @@ -1371,7 +1401,7 @@ Examples: \ind{options!language}\ind{language} The option \option{language} defines the default language of server strings that -can be seen by \Jabber{} clients. If a \Jabber{} client do not support +can be seen by \Jabber{} clients. If a \Jabber{} client does not support \option{xml:lang}, the specified language is used. The default value is \term{en}. In order to take effect there must be a translation file \term{.msg} in \ejabberd{}'s \term{msgs} directory. @@ -1388,6 +1418,9 @@ Examples: \end{verbatim} \end{itemize} +Appendix \ref{i18ni10n} provides more details about internationalization and localization. + + \makesubsection{includeconfigfile}{Include Additional Configuration Files} \ind{options!includeconfigfile}\ind{includeconfigfile} @@ -1890,6 +1923,11 @@ module loaded! server and use LDAP directory as vCard storage. Shared rosters are not supported yet. +Note that \ejabberd{} treats LDAP as a read-only storage: +it is possible to consult data, but not possible to +create accounts, change password or edit vCard that is stored in LDAP. + + \makesubsubsection{ldapconnection}{Connection} Parameters: @@ -2534,31 +2572,28 @@ Options: \makesubsection{modmuc}{\modmuc{}} \ind{modules!\modmuc{}}\ind{protocols!XEP-0045: Multi-User Chat}\ind{conferencing} -With this module enabled, your server will support Multi-User Chat -(\xepref{0045}). End users will be able to join text conferences. +This module provides a Multi-User Chat (\xepref{0045}) service. +Users can discover existing rooms, join or create them. +Occupants of a room can chat in public or have private chats. Some of the features of Multi-User Chat: \begin{itemize} -\item Sending private messages to room participants. -\item Inviting users. -\item Setting a conference topic. +\item Sending public and private messages to room occupants. +\item Inviting other users to a room. +\item Setting a room subject. \item Creating password protected rooms. -\item Kicking and banning participants. +\item Kicking and banning occupants. \end{itemize} The MUC service allows any Jabber ID to register a nickname, so nobody else can use that nickname in any room in the MUC service. To register a nickname, open the Service Discovery in your -Jabber client and Register in the MUC service. - -The MUC service allows the service administrator to send a message -to all existing chatrooms. -To do so, send the message to the Jabber ID of the MUC service. +Jabber client and register in the MUC service. This module supports clustering and load balancing. One module can be started per cluster node. Rooms are distributed at creation time on all available MUC module -instances. The multi-user chat module is clustered but the room +instances. The multi-user chat module is clustered but the rooms themselves are not clustered nor fault-tolerant: if the node managing a set of rooms goes down, the rooms disappear and they will be recreated on an available node on first connection attempt. @@ -2567,19 +2602,19 @@ Module options: \begin{description} \hostitem{conference} \titem{access} \ind{options!access}You can specify who is allowed to use - the Multi-User Chat service (by default, everyone is allowed to use it). + the Multi-User Chat service. By default everyone is allowed to use it. \titem{access\_create} \ind{options!access\_create}To configure who is allowed to create new rooms at the Multi-User Chat service, this option - can be used (by default, everybody is allowed to create rooms). + can be used. By default everybody is allowed to create rooms. \titem{access\_persistent} \ind{options!access\_persistent}To configure who is - allowed to modify the 'persistent' chatroom option - (by default, everybody is allowed to modify that option). + allowed to modify the 'persistent' room option. + By default everybody is allowed to modify that option. \titem{access\_admin} \ind{options!access\_admin}This option specifies - who is allowed to administrate the Multi-User Chat service (the default + who is allowed to administrate the Multi-User Chat service. The default value is \term{none}, which means that only the room creator can - administer his room). + administer his room. The administrators can send a normal message to the service JID, - and it will be shown in every active room as a service message. + and it will be shown in all active rooms as a service message. The administrators can send a groupchat message to the JID of an active room, and the message will be shown in the room as a service message. \titem{history\_size} \ind{options!history\_size}A small history of @@ -2589,44 +2624,43 @@ Module options: integer. Setting the value to \term{0} disables the history feature and, as a result, nothing is kept in memory. The default value is \term{20}. This value is global and thus affects all rooms on the - server. + service. \titem{max\_users} \ind{options!max\_users} This option defines at - the server level, the maximum number of users allowed per MUC + the service level, the maximum number of users allowed per room. It can be lowered in each room configuration but cannot be - increased in individual MUC room configuration. The default value is + increased in individual room configuration. The default value is 200. \titem{max\_users\_admin\_threshold} \ind{options!max\_users\_admin\_threshold} This option defines the - number of MUC admins or owners to allow to enter the room even if - the maximum number of allowed users is reached. The default limits - is 5. In most cases this default value is the best setting. + number of service admins or room owners allowed to enter the room when + the maximum number of allowed occupants was reached. The default limit + is 5. \titem{max\_user\_conferences} - \ind{options!max\_user\_conferences} This option define the maximum - number of chat room any given user will be able to join. The default + \ind{options!max\_user\_conferences} This option defines the maximum + number of rooms that any given user can join. The default value is 10. This option is used to prevent possible abuses. Note that - this is a soft limits: Some users can sometime join more conferences + this is a soft limit: some users can sometimes join more conferences in cluster configurations. \titem{min\_message\_interval} \ind{options!min\_message\_interval} This option defines the minimum interval between two messages send - by a user in seconds. This option is global and valid for all chat + by an occupant in seconds. This option is global and valid for all rooms. A decimal value can be used. When this option is not defined, message rate is not limited. This feature can be used to protect a - MUC service from users abuses and limit number of messages that will + MUC service from occupant abuses and limit number of messages that will be broadcasted by the service. A good value for this minimum message - interval is 0.4 second. If a user tries to send messages faster, an - error is send back explaining that the message have been discarded + interval is 0.4 second. If an occupant tries to send messages faster, an + error is send back explaining that the message has been discarded and describing the reason why the message is not acceptable. \titem{min\_presence\_interval} \ind{options!min\_presence\_interval} This option defines the - minimum of time between presence changes coming from a given user in - seconds. This option is global and valid for all chat rooms. A + minimum of time between presence changes coming from a given occupant in + seconds. This option is global and valid for all rooms. A decimal value can be used. When this option is not defined, no restriction is applied. This option can be used to protect a MUC - service for users abuses, as fastly changing a user presence will - result in possible large presence packet broadcast. If a user tries + service for occupants abuses. If an occupant tries to change its presence more often than the specified interval, the presence is cached by \ejabberd{} and only the last presence is - broadcasted to all users in the room after expiration of the + broadcasted to all occupants in the room after expiration of the interval delay. Intermediate presence packets are silently discarded. A good value for this option is 4 seconds. \titem{default\_room\_options} \ind{options!default\_room\_options} @@ -2639,7 +2673,15 @@ Module options: \titem{\{allow\_private\_messages, true\}} Occupants can send private messages to other occupants. \titem{\{allow\_query\_users, true\}} Occupants can send IQ queries to other occupants. \titem{\{allow\_user\_invites, false\}} Allow occupants to send invitations. - \titem{\{anonymous, true\}} Occupants are allowed to see the real JIDs of other occupants. + \titem{\{allow\_visitor\_nickchange, true\}} Allow visitors to + change nickname. + \titem{\{allow\_visitor\_status, true\}} Allow visitors to send + status text in presence updates. If disallowed, the \term{status} + text is stripped before broadcasting the presence update to all + the room occupants. + \titem{\{anonymous, true\}} The room is anonymous: + occupants don't see the real JIDs of other occupants. + Note that the room moderators can always see the real JIDs of the occupants. \titem{\{logging, false\}} The public messages are logged using \term{mod\_muc\_log}. \titem{\{max\_users, 200\}} Maximum number of occupants in the room. \titem{\{members\_by\_default, true\}} The occupants that enter the room are participants by default, so they have 'voice'. @@ -2715,8 +2757,8 @@ Examples: ]}. \end{verbatim} -\item In the following example, MUC anti abuse options are used. A -user cannot send more than one message every 0.4 seconds and cannot +\item In the following example, MUC anti abuse options are used. An +occupant cannot send more than one message every 0.4 seconds and cannot change its presence more than once every 4 seconds. No ACLs are defined, but some user restriction could be added as well: @@ -2731,7 +2773,7 @@ defined, but some user restriction could be added as well: \end{verbatim} \item This example shows how to use \option{default\_room\_options} to make sure - newly created chatrooms have by default those options. + the newly created rooms have by default those options. \begin{verbatim} {modules, [ @@ -2756,19 +2798,19 @@ defined, but some user restriction could be added as well: \makesubsection{modmuclog}{\modmuclog{}} \ind{modules!\modmuclog{}} -This module enables optional logging of Multi-User Chat (MUC) conversations to -HTML. Once you enable this module, users can join a chatroom using a MUC capable +This module enables optional logging of Multi-User Chat (MUC) public conversations to +HTML. Once you enable this module, users can join a room using a MUC capable Jabber client, and if they have enough privileges, they can request the -configuration form in which they can set the option to enable chatroom logging. +configuration form in which they can set the option to enable room logging. Features: \begin{itemize} -\item Chatroom details are added on top of each page: room title, JID, +\item Room details are added on top of each page: room title, JID, author, subject and configuration. \item \ind{protocols!RFC 5122: Internationalized Resource Identifiers (IRIs) and Uniform Resource Identifiers (URIs) for the Extensible Messaging and Presence Protocol (XMPP)} - The room JID in the generated HTML is a link to join the chatroom (using + The room JID in the generated HTML is a link to join the room (using \footahref{http://www.xmpp.org/rfcs/rfc5122.html}{XMPP URI}). -\item Subject and chatroom configuration changes are tracked and displayed. +\item Subject and room configuration changes are tracked and displayed. \item Joins, leaves, nick changes, kicks, bans and `/me' are tracked and displayed, including the reason if available. \item Generated HTML files are XHTML 1.0 Transitional and CSS compliant. @@ -2783,7 +2825,7 @@ Features: Options: \begin{description} \titem{access\_log}\ind{options!access\_log} - This option restricts which users are allowed to enable or disable chatroom + This option restricts which occupants are allowed to enable or disable room logging. The default value is \term{muc\_admin}. Note for this default setting you need to have an access rule for \term{muc\_admin} in order to take effect. \titem{cssfile}\ind{options!cssfile} @@ -2793,26 +2835,38 @@ Options: include the embedded CSS code. With the latter, you can specify the URL of the custom CSS file (for example: `http://example.com/my.css'). The default value is \term{false}. +\titem{dirname}\ind{options!dirname} + Allows to configure the name of the room directory. + Allowed values are \term{room\_jid} and \term{room\_name}. + With the first value, the room directory name will be the full room JID. + With the latter, the room directory name will be only the room name, + not including the MUC service name. + The default value is \term{room\_jid}. \titem{dirtype}\ind{options!dirtype} The type of the created directories can be specified with this option. Allowed values are \term{subdirs} and \term{plain}. With the first value, subdirectories are created for each year and month. With the latter, the names of the log files contain the full date, and there are no subdirectories. The default value is \term{subdirs}. +\titem{file\_format}\ind{options!file\_format} + Define the format of the log files: + \term{html} stores in HTML format, + \term{plaintext} stores in plain text. + The default value is \term{html}. \titem{outdir}\ind{options!outdir} This option sets the full path to the directory in which the HTML files should be stored. Make sure the \ejabberd{} daemon user has write access on that directory. The default value is \term{"www/muc"}. -\titem{timezone}\ind{options!timezone} - The time zone for the logs is configurable with this option. Allowed values - are \term{local} and \term{universal}. With the first value, the local time, - as reported to Erlang by the operating system, will be used. With the latter, - GMT/UTC time will be used. The default value is \term{local}. \titem{spam\_prevention}\ind{options!spam\_prevention} To prevent spam, the \term{spam\_prevention} option adds a special attribute to links that prevent their indexation by search engines. The default value is \term{true}, which mean that nofollow attributes will be added to user submitted links. +\titem{timezone}\ind{options!timezone} + The time zone for the logs is configurable with this option. Allowed values + are \term{local} and \term{universal}. With the first value, the local time, + as reported to Erlang by the operating system, will be used. With the latter, + GMT/UTC time will be used. The default value is \term{local}. \titem{top\_link}\ind{options!top\_link} With this option you can customize the link on the top right corner of each log file. The syntax of this option is \term{\{"URL", "Text"\}}. The default @@ -2821,8 +2875,8 @@ Options: Examples: \begin{itemize} -\item In the first example any chatroom owner can enable logging, and a - custom CSS file will be used (http://example.com/my.css). Further, the names +\item In the first example any room owner can enable logging, and a + custom CSS file will be used (http://example.com/my.css). The names of the log files will contain the full date, and there will be no subdirectories. The log files will be stored in /var/www/muclogs, and the time zone will be GMT/UTC. Finally, the top link will be @@ -2837,6 +2891,7 @@ Examples: {access_log, muc}, {cssfile, "http://example.com/my.css"}, {dirtype, plain}, + {dirname, room_jid}, {outdir, "/var/www/muclogs"}, {timezone, universal}, {spam_prevention, true}, @@ -2847,7 +2902,7 @@ Examples: \end{verbatim} \item In the second example only \jid{admin1@example.org} and \jid{admin2@example.net} can enable logging, and the embedded CSS file will be - used. Further, the names of the log files will only contain the day (number), + used. The names of the log files will only contain the day (number), and there will be subdirectories for each year and month. The log files will be stored in /var/www/muclogs, and the local time will be used. Finally, the top link will be the default \verb|Home|. @@ -2986,8 +3041,8 @@ Examples: {access, proxy65_access, [{allow, proxy_users}, {deny, all}]}. {acl, admin, {user, "admin", "example.org"}}. -{shaper, normal, {maxrate, 10240}}. %% 10 Kbytes/sec -{access, proxy65_shaper, [{none, admin}, {normal, all}]}. +{shaper, proxyrate, {maxrate, 10240}}. %% 10 Kbytes/sec +{access, proxy65_shaper, [{none, admin}, {proxyrate, proxy_users}]}. {modules, [ @@ -3411,6 +3466,10 @@ Examples: implemented in the \modvcardldap{} module. This module does not depend on the authentication method (see~\ref{ldapauth}). +Note that \ejabberd{} treats LDAP as a read-only storage: +it is possible to consult data, but not possible to +create accounts, change password or edit vCard that is stored in LDAP. + The \modvcardldap{} module has its own optional parameters. The first group of parameters has the same meaning as the top-level LDAP parameters to set the authentication method: @@ -4052,6 +4111,7 @@ following steps: \begin{verbatim} erl -sname ejabberd \ + -mnesia dir "/var/lib/ejabberd/" \ -mnesia extra_db_nodes "['ejabberd@first']" \ -s mnesia \end{verbatim} @@ -4060,6 +4120,11 @@ erl -sname ejabberd \ You can check this by running the command `\verb|mnesia:info().|'. You should see a lot of remote tables and a line like the following: + Note: the Mnesia directory may be different in your system. + To know where does ejabberd expect Mnesia to be installed by default, + call \ref{ejabberdctl} without options and it will show some help, + including the Mnesia database spool dir. + \begin{verbatim} running db nodes = [ejabberd@first, ejabberd@second] \end{verbatim} @@ -4227,6 +4292,18 @@ To exit the shell, close the window or press the keys: control+c control+c. \makechapter{i18ni10n}{Internationalization and Localization} \ind{xml:lang}\ind{internationalization}\ind{localization}\ind{i18n}\ind{l10n} +The source code of \ejabberd{} supports localization. +The translators can edit the +\footahref{http://www.gnu.org/software/gettext/}{gettext} .po files +using any capable program (KBabel, Lokalize, Poedit...) or a simple text editor. + +Then gettext +is used to extract, update and export those .po files to the .msg format read by \ejabberd{}. +To perform those management tasks, in the \term{src/} directory execute \term{make translations}. +The translatable strings are extracted from source code to generate the file \term{ejabberd.pot}. +This file is merged with each .po file to produce updated .po files. +Finally those .po files are exported to .msg files, that have a format easily readable by \ejabberd{}. + All built-in modules support the \texttt{xml:lang} attribute inside IQ queries. Figure~\ref{fig:discorus}, for example, shows the reply to the following query: \begin{verbatim} @@ -4284,7 +4361,7 @@ Thanks to all people who contributed to this guide: \makechapter{copyright}{Copyright Information} Ejabberd Installation and Operation Guide.\\ -Copyright \copyright{} 2003 --- 2008 Process-one +Copyright \copyright{} 2003 --- 2008 ProcessOne This document is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/doc/release_notes_2.0.2.txt b/doc/release_notes_2.0.2.txt new file mode 100644 index 000000000..767ae1367 --- /dev/null +++ b/doc/release_notes_2.0.2.txt @@ -0,0 +1,34 @@ + + Release Notes + ejabberd 2.0.2 + 28 August 2008 + + ejabberd 2.0.2 is the second bug fix release for ejabberd 2.0.x branch. + + ejabberd 2.0.2 includes many bugfixes and a few improvements. + A complete list of changes can be retrieved from: + http://redir.process-one.net/ejabberd-2.0.2 + + The new code can be downloaded from ejabberd download page: + http://www.process-one.net/en/ejabberd/ + + + Recent changes include: + +- Anti-abuse feature: client blacklist support by IP. +- Guide: new section Securing ejabberd; improved usability. +- LDAP filter optimisation: ability to filter user in ejabberd and not LDAP. +- MUC improvements: room options to restrict visitors; broadcast reasons. +- Privacy rules: fix MySQL storage. +- Pub/Sub and PEP: many improvements in implementation and protocol compliance. +- Proxy65: send valid SOCKS5 reply (removed support for Psi < 0.10). +- Web server embedded: better support for HTTPS. +- Binary installers: SMP on Windows; don't remove config when uninstalling. + + + Bug reports + + You can officially report bugs on ProcessOne support site: + http://support.process-one.net/ + +END diff --git a/src/Makefile.in b/src/Makefile.in index 5dabf5431..93d29fc60 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -157,6 +157,9 @@ $(ERLSHLIBS): %.so: %.c -o $@ \ $(DYNAMIC_LIB_CFLAGS) +translations: + ../contrib/extract_translations/prepare-translation.sh -updateall + install: all # # Configuration files diff --git a/src/acl.erl b/src/acl.erl index 21bacf618..c21e62488 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -5,7 +5,7 @@ %%% Created : 18 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/adhoc.erl b/src/adhoc.erl index 0382062b0..26ea5a7c2 100644 --- a/src/adhoc.erl +++ b/src/adhoc.erl @@ -5,7 +5,7 @@ %%% Created : 31 Oct 2005 by Magnus Henoch %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/adhoc.hrl b/src/adhoc.hrl index 5dbc515bc..ab8a6f163 100644 --- a/src/adhoc.hrl +++ b/src/adhoc.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/configure.erl b/src/configure.erl index b9447c28d..379c79a82 100644 --- a/src/configure.erl +++ b/src/configure.erl @@ -5,7 +5,7 @@ %%% Created : 27 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/cyrsasl.erl b/src/cyrsasl.erl index e942aa3e8..7813df772 100644 --- a/src/cyrsasl.erl +++ b/src/cyrsasl.erl @@ -5,7 +5,7 @@ %%% Created : 8 Mar 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/cyrsasl_anonymous.erl b/src/cyrsasl_anonymous.erl index 4f1219882..fb033b3a7 100644 --- a/src/cyrsasl_anonymous.erl +++ b/src/cyrsasl_anonymous.erl @@ -6,7 +6,7 @@ %%% Created : 23 Aug 2005 by Magnus Henoch %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/cyrsasl_plain.erl b/src/cyrsasl_plain.erl index c0ca708d8..1533c463d 100644 --- a/src/cyrsasl_plain.erl +++ b/src/cyrsasl_plain.erl @@ -5,7 +5,7 @@ %%% Created : 8 Mar 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd.erl b/src/ejabberd.erl index de2727ca0..86113d97b 100644 --- a/src/ejabberd.erl +++ b/src/ejabberd.erl @@ -5,7 +5,7 @@ %%% Created : 16 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd.hrl b/src/ejabberd.hrl index d7b16f1e2..658037274 100644 --- a/src/ejabberd.hrl +++ b/src/ejabberd.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl index 44b7213ea..a0f101703 100644 --- a/src/ejabberd_admin.erl +++ b/src/ejabberd_admin.erl @@ -9,7 +9,7 @@ %%% Created : 7 May 2006 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index 8f335ad5b..e64c58635 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -5,7 +5,7 @@ %%% Created : 31 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -152,7 +152,7 @@ stop_modules() -> Modules -> lists:foreach( fun({Module, _Args}) -> - gen_mod:stop_module(Host, Module) + gen_mod:stop_module_keep_config(Host, Module) end, Modules) end end, ?MYHOSTS). diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 358d44ae0..33a575e30 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -5,7 +5,7 @@ %%% Created : 23 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -127,9 +127,12 @@ check_password_with_authmodule(User, Server, Password, StreamID, Digest) -> [AuthMod | _] -> {true, AuthMod} end. -%% We do not allow empty password: +%% @spec (User::string(), Server::string(), Password::string()) -> +%% ok | {error, ErrorType} +%% where ErrorType = empty_password | not_allowed | invalid_jid set_password(_User, _Server, "") -> - {error, not_allowed}; + %% We do not allow empty password + {error, empty_password}; set_password(User, Server, Password) -> lists:foldl( fun(M, {error, _}) -> @@ -138,8 +141,8 @@ set_password(User, Server, Password) -> Res end, {error, not_allowed}, auth_modules(Server)). -%% We do not allow empty password: try_register(_User, _Server, "") -> + %% We do not allow empty password {error, not_allowed}; try_register(User, Server, Password) -> case is_user_exists(User,Server) of diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index 8ba4d7336..955a0dc06 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -5,7 +5,7 @@ %%% Created : 17 Feb 2006 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl index 9684944a6..b86a94bb8 100644 --- a/src/ejabberd_auth_external.erl +++ b/src/ejabberd_auth_external.erl @@ -5,7 +5,7 @@ %%% Created : 12 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -61,7 +61,10 @@ check_password(User, Server, Password, _StreamID, _Digest) -> check_password(User, Server, Password). set_password(User, Server, Password) -> - extauth:set_password(User, Server, Password). + case extauth:set_password(User, Server, Password) of + true -> ok; + _ -> {error, unknown_problem} + end. try_register(_User, _Server, _Password) -> {error, not_allowed}. diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index 71d9086d7..cec18b319 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -5,7 +5,7 @@ %%% Created : 12 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -98,6 +98,8 @@ check_password(User, Server, Password, StreamID, Digest) -> false end. +%% @spec (User::string(), Server::string(), Password::string()) -> +%% ok | {error, invalid_jid} set_password(User, Server, Password) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), @@ -110,7 +112,8 @@ set_password(User, Server, Password) -> mnesia:write(#passwd{us = US, password = Password}) end, - mnesia:transaction(F) + {atomic, ok} = mnesia:transaction(F), + ok end. try_register(User, Server, Password) -> diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl index d576a82fd..303300e48 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -5,7 +5,7 @@ %%% Created : 12 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index 06ae695ea..26eca6ab3 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -5,7 +5,7 @@ %%% Created : 12 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -103,13 +103,18 @@ check_password(User, Server, Password, StreamID, Digest) -> false end. +%% @spec (User::string(), Server::string(), Password::string()) -> +%% ok | {error, invalid_jid} set_password(User, Server, Password) -> try LUser = exmpp_stringprep:nodeprep(User), Username = ejabberd_odbc:escape(LUser), Pass = ejabberd_odbc:escape(Password), LServer = exmpp_stringprep:nameprep(Server), - catch odbc_queries:set_password_t(LServer, Username, Pass) + case catch odbc_queries:set_password_t(LServer, Username, Pass) of + {atomic, ok} -> ok; + Other -> {error, Other} + end catch _ -> {error, invalid_jid} diff --git a/src/ejabberd_auth_pam.erl b/src/ejabberd_auth_pam.erl index 810ab7cf5..f26296d33 100644 --- a/src/ejabberd_auth_pam.erl +++ b/src/ejabberd_auth_pam.erl @@ -5,7 +5,7 @@ %%% Created : 5 Jul 2007 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 6c86d1149..5b00509f3 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -5,7 +5,7 @@ %%% Created : 16 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -37,6 +37,7 @@ send_element/2, socket_type/0, get_presence/1, + get_subscribed/1, get_subscribed_and_online/1]). %% gen_fsm callbacks @@ -201,6 +202,9 @@ init([{SockMod, Socket}, Opts]) -> %% Return list of all available resources of contacts, %% in form [{JID, Caps}]. +get_subscribed(FsmRef) -> + gen_fsm:sync_send_all_state_event( + FsmRef, get_subscribed, 1000). get_subscribed_and_online(FsmRef) -> gen_fsm:sync_send_all_state_event( FsmRef, get_subscribed_and_online, 1000). @@ -932,6 +936,20 @@ handle_sync_event({get_presence}, _From, StateName, StateData) -> Reply = {User, Resource, atom_to_list(Show), Status}, fsm_reply(Reply, StateName, StateData); +handle_sync_event(get_subscribed, _From, StateName, StateData) -> + Subscribed = StateData#state.pres_f, + Online = StateData#state.pres_available, + Pred = fun(User, _Caps) -> + ?SETS:is_element(jlib:jid_remove_resource(User), + Subscribed) orelse + ?SETS:is_element(User, Subscribed) + end, + SubscribedAndOnline = ?DICT:filter(Pred, Online), + SubscribedWithCaps = ?SETS:fold(fun(User, Acc) -> + [{User, undefined}|Acc] + end, ?DICT:to_list(SubscribedAndOnline), Subscribed), + {reply, SubscribedWithCaps, StateName, StateData}; + handle_sync_event(get_subscribed_and_online, _From, StateName, StateData) -> Subscribed = StateData#state.pres_f, Online = StateData#state.pres_available, diff --git a/src/ejabberd_c2s_config.erl b/src/ejabberd_c2s_config.erl index 35fa5a82d..4c1dae8fc 100644 --- a/src/ejabberd_c2s_config.erl +++ b/src/ejabberd_c2s_config.erl @@ -6,7 +6,7 @@ %%% Created : 2 Nov 2007 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_check.erl b/src/ejabberd_check.erl index 16aa78c68..260c54175 100644 --- a/src/ejabberd_check.erl +++ b/src/ejabberd_check.erl @@ -5,7 +5,7 @@ %%% Created : 27 Feb 2008 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -39,19 +39,21 @@ libs() -> ok. -%% Consistency check on ejabberd configuration +%% @doc Consistency check on ejabberd configuration config() -> check_database_modules(). check_database_modules() -> [check_database_module(M)||M<-get_db_used()]. +check_database_module(odbc) -> + check_modules(odbc, [odbc, odbc_app, odbc_sup, ejabberd_odbc, ejabberd_odbc_sup, odbc_queries]); check_database_module(mysql) -> check_modules(mysql, [mysql, mysql_auth, mysql_conn, mysql_recv]); check_database_module(pgsql) -> check_modules(pgsql, [pgsql, pgsql_proto, pgsql_tcp, pgsql_util]). -%% Issue a critical error and throw an exit if needing module is +%% @doc Issue a critical error and throw an exit if needing module is %% missing. check_modules(DB, Modules) -> case get_missing_modules(Modules) of @@ -63,7 +65,7 @@ check_modules(DB, Modules) -> end. -%% Return the list of undefined modules +%% @doc Return the list of undefined modules get_missing_modules(Modules) -> lists:filter(fun(Module) -> case catch Module:module_info() of @@ -73,7 +75,7 @@ get_missing_modules(Modules) -> end end, Modules). -%% Return the list of databases used +%% @doc Return the list of databases used get_db_used() -> %% Retrieve domains with a database configured: Domains = @@ -86,14 +88,22 @@ get_db_used() -> case check_odbc_option( ejabberd_config:get_local_option( {auth_method, Domain})) of - true -> [element(1, DB)|Acc]; + true -> [get_db_type(DB)|Acc]; _ -> Acc end end, [], Domains), lists:usort(DBs). -%% Return true if odbc option is used +%% @doc Depending in the DB definition, return which type of DB this is. +%% Note that MSSQL is detected as ODBC. +%% @spec (DB) -> mysql | pgsql | odbc +get_db_type(DB) when is_tuple(DB) -> + element(1, DB); +get_db_type(DB) when is_list(DB) -> + odbc. + +%% @doc Return true if odbc option is used check_odbc_option(odbc) -> true; check_odbc_option(AuthMethods) when is_list(AuthMethods) -> diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index c18cfe6de..182b4a216 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -5,7 +5,7 @@ %%% Created : 14 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -95,10 +95,14 @@ get_plain_terms_file(File1) -> case file:consult(File) of {ok, Terms} -> include_config_files(Terms); - {error, Reason} -> - ExitText = lists:flatten(File ++ ": around line " + {error, {_LineNumber, erl_parse, _ParseMessage} = Reason} -> + ExitText = lists:flatten(File ++ " approximately in the line " ++ file:format_error(Reason)), - ?ERROR_MSG("Problem loading ejabberd config file:~n~s", [ExitText]), + ?ERROR_MSG("Problem loading ejabberd config file ~n~s", [ExitText]), + exit(ExitText); + {error, Reason} -> + ExitText = lists:flatten(File ++ ": " ++ file:format_error(Reason)), + ?ERROR_MSG("Problem loading ejabberd config file ~n~s", [ExitText]), exit(ExitText) end. diff --git a/src/ejabberd_config.hrl b/src/ejabberd_config.hrl index aa783ea5e..982bbe23f 100644 --- a/src/ejabberd_config.hrl +++ b/src/ejabberd_config.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl index 9a84b592e..c66b93a38 100644 --- a/src/ejabberd_ctl.erl +++ b/src/ejabberd_ctl.erl @@ -5,7 +5,7 @@ %%% Created : 11 Jan 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -99,6 +99,9 @@ process(["restart"]) -> process(["reopen-log"]) -> ejabberd_hooks:run(reopen_log_hook, []), + lists:foreach(fun(Host) -> + ejabberd_hooks:run(reopen_log_hook, Host, [Host]) + end, ?MYHOSTS), %% TODO: Use the Reopen log API for logger_h ? ejabberd_logger_h:reopen_log(), ?STATUS_SUCCESS; @@ -158,7 +161,7 @@ process(["load", Path]) -> end; process(["restore", Path]) -> - case ejabberd_admin:restore(Path) of + case ejabberd_admin:restore(Path) of {atomic, _} -> ?STATUS_SUCCESS; {error, Reason} -> @@ -384,7 +387,7 @@ dump_to_textfile(yes, {ok, F}) -> end, Tabs1), Defs = lists:map( fun(T) -> {T, [{record_name, mnesia:table_info(T, record_name)}, - {attributes, mnesia:table_info(T, attributes)}]} + {attributes, mnesia:table_info(T, attributes)}]} end, Tabs), io:format(F, "~p.~n", [{tables, Defs}]), diff --git a/src/ejabberd_ctl.hrl b/src/ejabberd_ctl.hrl index e8daef90b..9b5ec0a4b 100644 --- a/src/ejabberd_ctl.hrl +++ b/src/ejabberd_ctl.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_frontend_socket.erl b/src/ejabberd_frontend_socket.erl index 5874afa6d..320968f70 100644 --- a/src/ejabberd_frontend_socket.erl +++ b/src/ejabberd_frontend_socket.erl @@ -5,7 +5,7 @@ %%% Created : 23 Aug 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl index 7fc2f07f0..0609e20d4 100644 --- a/src/ejabberd_hooks.erl +++ b/src/ejabberd_hooks.erl @@ -5,7 +5,7 @@ %%% Created : 8 Aug 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index b65a33785..e8bddf00e 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -5,7 +5,7 @@ %%% Created : 16 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index d77eb6968..232ce8415 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -5,7 +5,7 @@ %%% Created : 30 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_logger_h.erl b/src/ejabberd_logger_h.erl index a3af991bc..2e750ca34 100644 --- a/src/ejabberd_logger_h.erl +++ b/src/ejabberd_logger_h.erl @@ -5,7 +5,7 @@ %%% Created : 23 Oct 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_loglevel.erl b/src/ejabberd_loglevel.erl index 0f482b6fe..59c415196 100644 --- a/src/ejabberd_loglevel.erl +++ b/src/ejabberd_loglevel.erl @@ -9,7 +9,7 @@ %%% Created : 29 Nov 2006 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_node_groups.erl b/src/ejabberd_node_groups.erl index 6386a7e93..d5d8ce068 100644 --- a/src/ejabberd_node_groups.erl +++ b/src/ejabberd_node_groups.erl @@ -5,7 +5,7 @@ %%% Created : 1 Nov 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_rdbms.erl b/src/ejabberd_rdbms.erl index 540ffce0b..0eff6c3ca 100644 --- a/src/ejabberd_rdbms.erl +++ b/src/ejabberd_rdbms.erl @@ -5,7 +5,7 @@ %%% Created : 31 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_receiver.erl b/src/ejabberd_receiver.erl index 5fdad76af..6d5b30ec3 100644 --- a/src/ejabberd_receiver.erl +++ b/src/ejabberd_receiver.erl @@ -5,7 +5,7 @@ %%% Created : 10 Nov 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index 04bc76285..658f674fc 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -5,7 +5,7 @@ %%% Created : 27 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -161,9 +161,9 @@ unregister_route(Domain) -> mnesia:transaction(F); _ -> F = fun() -> - case mnesia:match(#route{domain = LDomain, - pid = Pid, - _ = '_'}) of + case mnesia:match_object(#route{domain=LDomain, + pid = Pid, + _ = '_'}) of [R] -> I = R#route.local_hint, mnesia:write( diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index 492484c31..53cc65e28 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -5,7 +5,7 @@ %%% Created : 7 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 2fdcbac28..8ac32bf63 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -5,7 +5,7 @@ %%% Created : 6 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index bbd792a2f..b73336245 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -5,7 +5,7 @@ %%% Created : 6 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 302211f07..8f16a6f6e 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -1,11 +1,11 @@ %%%---------------------------------------------------------------------- %%% File : ejabberd_service.erl %%% Author : Alexey Shchepin -%%% Purpose : External component management +%%% Purpose : External component management (XEP-0114) %%% Created : 6 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -147,11 +147,15 @@ init([{SockMod, Socket}, Opts]) -> %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- -wait_for_stream({xmlstreamstart, #xmlel{ns = NS}}, StateData) -> - % TODO +wait_for_stream({xmlstreamstart, #xmlel{ns = NS, attrs = Attrs}}, StateData) -> case NS of ?NS_COMPONENT_ACCEPT -> - Opening_Reply = exmpp_stream:opening_reply(?MYNAME, + %% Note: XEP-0114 requires to check that destination is a Jabber + %% component served by this Jabber server. + %% However several transports don't respect that, + %% so ejabberd doesn't check 'to' attribute (EJAB-717) + To = exmpp_stanza:get_recipient_from_attrs(Attrs), + Opening_Reply = exmpp_stream:opening_reply(xml:crypt(To), ?NS_COMPONENT_ACCEPT, {0, 0}, StateData#state.streamid), send_element(StateData, Opening_Reply), diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 3cec22f04..2d24d17a5 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -5,7 +5,7 @@ %%% Created : 24 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl index 389b3a106..115ffc750 100644 --- a/src/ejabberd_socket.erl +++ b/src/ejabberd_socket.erl @@ -5,7 +5,7 @@ %%% Created : 23 Aug 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_sup.erl b/src/ejabberd_sup.erl index 596dd7fa6..01efbfd76 100644 --- a/src/ejabberd_sup.erl +++ b/src/ejabberd_sup.erl @@ -5,7 +5,7 @@ %%% Created : 31 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl index eb1e305b2..e9a1a8ba3 100644 --- a/src/ejabberd_system_monitor.erl +++ b/src/ejabberd_system_monitor.erl @@ -5,7 +5,7 @@ %%% Created : 21 Mar 2007 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_tmp_sup.erl b/src/ejabberd_tmp_sup.erl index 733af4c26..7438f6628 100644 --- a/src/ejabberd_tmp_sup.erl +++ b/src/ejabberd_tmp_sup.erl @@ -5,7 +5,7 @@ %%% Created : 18 Jul 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_update.erl b/src/ejabberd_update.erl index 3f878337c..787f93fd7 100644 --- a/src/ejabberd_update.erl +++ b/src/ejabberd_update.erl @@ -5,7 +5,7 @@ %%% Created : 27 Jan 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_zlib/ejabberd_zlib.erl b/src/ejabberd_zlib/ejabberd_zlib.erl index 22bcaa8dd..18d5a3abf 100644 --- a/src/ejabberd_zlib/ejabberd_zlib.erl +++ b/src/ejabberd_zlib/ejabberd_zlib.erl @@ -5,7 +5,7 @@ %%% Created : 19 Jan 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_zlib/ejabberd_zlib_drv.c b/src/ejabberd_zlib/ejabberd_zlib_drv.c index abb3183c0..d1442d773 100644 --- a/src/ejabberd_zlib/ejabberd_zlib_drv.c +++ b/src/ejabberd_zlib/ejabberd_zlib_drv.c @@ -1,5 +1,5 @@ /* - * ejabberd, Copyright (C) 2002-2008 Process-one + * ejabberd, Copyright (C) 2002-2008 ProcessOne * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/ejd2odbc.erl b/src/ejd2odbc.erl index 2528e323d..c1399f987 100644 --- a/src/ejd2odbc.erl +++ b/src/ejd2odbc.erl @@ -5,7 +5,7 @@ %%% Created : 22 Aug 2005 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/eldap/eldap.hrl b/src/eldap/eldap.hrl index 75f6f76ef..d006c14df 100644 --- a/src/eldap/eldap.hrl +++ b/src/eldap/eldap.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/eldap/eldap_filter.erl b/src/eldap/eldap_filter.erl index 771f909a6..2feed1083 100644 --- a/src/eldap/eldap_filter.erl +++ b/src/eldap/eldap_filter.erl @@ -6,7 +6,7 @@ %%% Author: Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/eldap/eldap_pool.erl b/src/eldap/eldap_pool.erl index 13b45402a..7b9024de3 100644 --- a/src/eldap/eldap_pool.erl +++ b/src/eldap/eldap_pool.erl @@ -5,7 +5,7 @@ %%% Created : 12 Nov 2006 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/eldap/eldap_utils.erl b/src/eldap/eldap_utils.erl index 465d9ffe5..1f6d156d3 100644 --- a/src/eldap/eldap_utils.erl +++ b/src/eldap/eldap_utils.erl @@ -5,7 +5,7 @@ %%% Created : 12 Oct 2006 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/extauth.erl b/src/extauth.erl index 3819fcddf..c4acb305d 100644 --- a/src/extauth.erl +++ b/src/extauth.erl @@ -5,7 +5,7 @@ %%% Created : 30 Jul 2004 by Leif Johansson %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index b3e3beca5..a1f100c45 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -5,7 +5,7 @@ %%% Created : 22 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/gen_mod.erl b/src/gen_mod.erl index 29fbb1104..bbc4e860d 100644 --- a/src/gen_mod.erl +++ b/src/gen_mod.erl @@ -5,7 +5,7 @@ %%% Created : 24 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -30,6 +30,7 @@ -export([start/0, start_module/3, stop_module/2, + stop_module_keep_config/2, get_opt/2, get_opt/3, get_opt_host/3, @@ -72,22 +73,34 @@ start_module(Host, Module, Opts) -> ok end. +%% @doc Stop the module in a host, and forget its configuration. stop_module(Host, Module) -> + case stop_module_keep_config(Host, Module) of + error -> + error; + ok -> + del_module_mnesia(Host, Module) + end. + +%% @doc Stop the module in a host, but keep its configuration. +%% As the module configuration is kept in the Mnesia local_config table, +%% when ejabberd is restarted the module will be started again. +%% This function is useful when ejabberd is being stopped +%% and it stops all modules. +stop_module_keep_config(Host, Module) -> case catch Module:stop(Host) of {'EXIT', Reason} -> - ?ERROR_MSG("~p", [Reason]); + ?ERROR_MSG("~p", [Reason]), + error; {wait, ProcList} when is_list(ProcList) -> lists:foreach(fun wait_for_process/1, ProcList), - del_module_mnesia(Host, Module), ets:delete(ejabberd_modules, {Module, Host}), ok; {wait, Process} -> wait_for_process(Process), - del_module_mnesia(Host, Module), ets:delete(ejabberd_modules, {Module, Host}), ok; _ -> - del_module_mnesia(Host, Module), ets:delete(ejabberd_modules, {Module, Host}), ok end. diff --git a/src/idna.erl b/src/idna.erl index 6ad8c54cb..319262349 100644 --- a/src/idna.erl +++ b/src/idna.erl @@ -5,7 +5,7 @@ %%% Created : 10 Apr 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/jd2ejd.erl b/src/jd2ejd.erl index 9fac9c11f..193566cde 100644 --- a/src/jd2ejd.erl +++ b/src/jd2ejd.erl @@ -5,7 +5,7 @@ %%% Created : 2 Feb 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/jlib.erl b/src/jlib.erl index acf08a550..288e5f6c6 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -5,7 +5,7 @@ %%% Created : 23 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/jlib.hrl b/src/jlib.hrl index 3ea10b157..39731b14a 100644 --- a/src/jlib.hrl +++ b/src/jlib.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl index ad255f827..b1a2a7bf7 100644 --- a/src/mod_adhoc.erl +++ b/src/mod_adhoc.erl @@ -5,7 +5,7 @@ %%% Created : 15 Nov 2005 by Magnus Henoch %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_announce.erl b/src/mod_announce.erl index 5a744e6e0..e59e65fdb 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -5,7 +5,7 @@ %%% Created : 11 Aug 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 852ae7e48..d58b23587 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -5,7 +5,7 @@ %%% Created : 7 Oct 2006 by Magnus Henoch %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_configure.erl b/src/mod_configure.erl index f960eb08e..b1cb0cced 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -5,7 +5,7 @@ %%% Created : 19 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_configure2.erl b/src/mod_configure2.erl index 9acec3fc1..919927c38 100644 --- a/src/mod_configure2.erl +++ b/src/mod_configure2.erl @@ -5,7 +5,7 @@ %%% Created : 26 Oct 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 6907a4176..e1539fbd3 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -5,7 +5,7 @@ %%% Created : 1 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_echo.erl b/src/mod_echo.erl index fc043370c..9e9748b55 100644 --- a/src/mod_echo.erl +++ b/src/mod_echo.erl @@ -5,7 +5,7 @@ %%% Created : 15 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_ip_blacklist.erl b/src/mod_ip_blacklist.erl index 6a0cc3947..17280857e 100644 --- a/src/mod_ip_blacklist.erl +++ b/src/mod_ip_blacklist.erl @@ -7,7 +7,7 @@ %%% {mod_ip_blacklist, []} %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_irc/iconv.erl b/src/mod_irc/iconv.erl index 9c500978e..77c1ea56c 100644 --- a/src/mod_irc/iconv.erl +++ b/src/mod_irc/iconv.erl @@ -5,7 +5,7 @@ %%% Created : 16 Feb 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_irc/iconv_erl.c b/src/mod_irc/iconv_erl.c index 3cf82f4d5..3835aecbd 100644 --- a/src/mod_irc/iconv_erl.c +++ b/src/mod_irc/iconv_erl.c @@ -1,5 +1,5 @@ /* - * ejabberd, Copyright (C) 2002-2008 Process-one + * ejabberd, Copyright (C) 2002-2008 ProcessOne * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/mod_irc/mod_irc.erl b/src/mod_irc/mod_irc.erl index 4b2ae6adf..dd86037b9 100644 --- a/src/mod_irc/mod_irc.erl +++ b/src/mod_irc/mod_irc.erl @@ -5,7 +5,7 @@ %%% Created : 15 Feb 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_irc/mod_irc_connection.erl b/src/mod_irc/mod_irc_connection.erl index f62d99bde..244f5300d 100644 --- a/src/mod_irc/mod_irc_connection.erl +++ b/src/mod_irc/mod_irc_connection.erl @@ -5,7 +5,7 @@ %%% Created : 15 Feb 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_last.erl b/src/mod_last.erl index b35ea1150..cfdfa65e9 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -5,7 +5,7 @@ %%% Created : 24 Oct 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 76489b4c0..f2ac26114 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -5,7 +5,7 @@ %%% Created : 24 Oct 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -111,8 +111,6 @@ process_sm_iq(From, To, IQ) -> get_last(IQ, LUser, LServer) -> Username = ejabberd_odbc:escape(LUser), case catch odbc_queries:get_last(LServer, Username) of - {'EXIT', _Reason} -> - exmpp_iq:error(IQ, 'internal-server-error'); {selected, ["seconds","state"], []} -> exmpp_iq:error(IQ, 'service-unavailable'); {selected, ["seconds","state"], [{STimeStamp, Status}]} -> @@ -127,7 +125,9 @@ get_last(IQ, LUser, LServer) -> exmpp_iq:result(IQ, Response); _ -> exmpp_iq:error(IQ, 'internal-server-error') - end + end; + _ -> + exmpp_iq:error(IQ, 'internal-server-error') end. on_presence_update(User, Server, _Resource, Status) -> @@ -147,8 +147,6 @@ store_last_info(User, Server, TimeStamp, Status) -> get_last_info(LUser, LServer) -> Username = ejabberd_odbc:escape(LUser), case catch odbc_queries:get_last(LServer, Username) of - {'EXIT', _Reason} -> - not_found; {selected, ["seconds","state"], []} -> not_found; {selected, ["seconds","state"], [{STimeStamp, Status}]} -> @@ -157,7 +155,9 @@ get_last_info(LUser, LServer) -> {ok, TimeStamp, Status}; _ -> not_found - end + end; + _ -> + not_found end. remove_user(User, Server) -> diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index 90a74b70f..812c8de97 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -5,7 +5,7 @@ %%% Created : 19 Mar 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_muc/mod_muc_log.erl b/src/mod_muc/mod_muc_log.erl index 9ab8d4ce2..e76904193 100644 --- a/src/mod_muc/mod_muc_log.erl +++ b/src/mod_muc/mod_muc_log.erl @@ -5,7 +5,7 @@ %%% Created : 12 Mar 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -52,6 +52,8 @@ -record(state, {host, out_dir, dir_type, + dir_name, + file_format, css_file, access, lang, @@ -113,6 +115,8 @@ check_access_log(Host, From) -> init([Host, Opts]) -> OutDir = gen_mod:get_opt(outdir, Opts, "www/muc"), DirType = gen_mod:get_opt(dirtype, Opts, subdirs), + DirName = gen_mod:get_opt(dirname, Opts, room_jid), + FileFormat = gen_mod:get_opt(file_format, Opts, html), % Allowed values: html|plaintext CSSFile = gen_mod:get_opt(cssfile, Opts, false), AccessLog = gen_mod:get_opt(access_log, Opts, muc_admin), Timezone = gen_mod:get_opt(timezone, Opts, local), @@ -129,6 +133,8 @@ init([Host, Opts]) -> {ok, #state{host = Host, out_dir = OutDir, dir_type = DirType, + dir_name = DirName, + file_format = FileFormat, css_file = CSSFile, access = AccessLog, lang = Lang, @@ -231,10 +237,10 @@ add_to_log2(kickban, {Nick, Reason, Code}, Room, Opts, State) -> %%---------------------------------------------------------------------- %% Core -build_filename_string(TimeStamp, OutDir, RoomJID, DirType) -> +build_filename_string(TimeStamp, OutDir, RoomJID, DirType, DirName, FileFormat) -> {{Year, Month, Day}, _Time} = TimeStamp, - % Directory and file names + %% Directory and file names {Dir, Filename, Rel} = case DirType of subdirs -> @@ -248,55 +254,75 @@ build_filename_string(TimeStamp, OutDir, RoomJID, DirType) -> [Year, Month, Day])), {"", Date, "."} end, - Fd = filename:join([OutDir, RoomJID, Dir]), - Fn = filename:join([Fd, Filename ++ ".html"]), - Fnrel = filename:join([Rel, Dir, Filename ++ ".html"]), + + RoomString = case DirName of + room_jid -> RoomJID; + room_name -> get_room_name(RoomJID) + end, + Extension = case FileFormat of + html -> ".html"; + plaintext -> ".txt" + end, + Fd = filename:join([OutDir, RoomString, Dir]), + Fn = filename:join([Fd, Filename ++ Extension]), + Fnrel = filename:join([Rel, Dir, Filename ++ Extension]), {Fd, Fn, Fnrel}. -% calculate day before +get_room_name(RoomJID) -> + JID = jlib:string_to_jid(RoomJID), + JID#jid.user. + +%% calculate day before get_timestamp_daydiff(TimeStamp, Daydiff) -> {Date1, HMS} = TimeStamp, Date2 = calendar:gregorian_days_to_date( calendar:date_to_gregorian_days(Date1) + Daydiff), {Date2, HMS}. -% Try to close the previous day log, if it exists -close_previous_log(Fn, Images_dir) -> +%% Try to close the previous day log, if it exists +close_previous_log(Fn, Images_dir, FileFormat) -> case file:read_file_info(Fn) of {ok, _} -> {ok, F} = file:open(Fn, [append]), - %fw(F, "

    ejabberd/mod_muc log"), - fw(F, "
    "), - fw(F, " \"Powered", [Images_dir]), - fw(F, " \"Powered", [Images_dir]), - fw(F, ""), - fw(F, " \"Valid", [Images_dir]), - fw(F, " \"Valid", [Images_dir]), - fw(F, "
    "), + write_last_lines(F, Images_dir, FileFormat), file:close(F); _ -> ok end. +write_last_lines(_, _, plaintext) -> + ok; +write_last_lines(F, Images_dir, _FileFormat) -> + %%fw(F, "
    ejabberd/mod_muc log"), + fw(F, "
    "), + fw(F, " \"Powered", [Images_dir]), + fw(F, " \"Powered", [Images_dir]), + fw(F, ""), + fw(F, " \"Valid", [Images_dir]), + fw(F, " \"Valid", [Images_dir]), + fw(F, "
    "). + add_message_to_log(Nick1, Message, RoomJID, Opts, State) -> - Nick = htmlize(Nick1), #state{out_dir = OutDir, dir_type = DirType, + dir_name = DirName, + file_format = FileFormat, css_file = CSSFile, lang = Lang, timezone = Timezone, spam_prevention = NoFollow, top_link = TopLink} = State, Room = get_room_info(RoomJID, Opts), - + Nick = htmlize(Nick1, FileFormat), + Nick2 = htmlize("<"++Nick1++">", FileFormat), Now = now(), TimeStamp = case Timezone of local -> calendar:now_to_local_time(Now); universal -> calendar:now_to_universal_time(Now) end, - {Fd, Fn, _Dir} = build_filename_string(TimeStamp, OutDir, Room#room.jid, DirType), + {Fd, Fn, _Dir} = build_filename_string(TimeStamp, OutDir, Room#room.jid, DirType, DirName, FileFormat), {Date, Time} = TimeStamp, - % Open file, create if it does not exist, create parent dirs if needed + %% Open file, create if it does not exist, create parent dirs if needed case file:read_file_info(Fn) of {ok, _} -> {ok, F} = file:open(Fn, [append]); @@ -308,32 +334,32 @@ add_message_to_log(Nick1, Message, RoomJID, Opts, State) -> TimeStampYesterday = get_timestamp_daydiff(TimeStamp, -1), {_FdYesterday, FnYesterday, DatePrev} = build_filename_string( - TimeStampYesterday, OutDir, Room#room.jid, DirType), + TimeStampYesterday, OutDir, Room#room.jid, DirType, DirName, FileFormat), TimeStampTomorrow = get_timestamp_daydiff(TimeStamp, 1), {_FdTomorrow, _FnTomorrow, DateNext} = build_filename_string( - TimeStampTomorrow, OutDir, Room#room.jid, DirType), + TimeStampTomorrow, OutDir, Room#room.jid, DirType, DirName, FileFormat), HourOffset = calc_hour_offset(TimeStamp), put_header(F, Room, Datestring, CSSFile, Lang, - HourOffset, DatePrev, DateNext, TopLink), + HourOffset, DatePrev, DateNext, TopLink, FileFormat), - Images_dir = filename:join([OutDir, "images"]), + Images_dir = filename:join([OutDir, "images"]), file:make_dir(Images_dir), - create_image_files(Images_dir), - Images_url = case DirType of - subdirs -> "../../../images"; - plain -> "../images" - end, - close_previous_log(FnYesterday, Images_url) + create_image_files(Images_dir), + Images_url = case DirType of + subdirs -> "../../../images"; + plain -> "../images" + end, + close_previous_log(FnYesterday, Images_url, FileFormat) end, - % Build message + %% Build message Text = case Message of roomconfig_change -> - RoomConfig = roomconfig_to_string(Room#room.config, Lang), - put_room_config(F, RoomConfig, Lang), + RoomConfig = roomconfig_to_string(Room#room.config, Lang, FileFormat), + put_room_config(F, RoomConfig, Lang, FileFormat), io_lib:format("~s
    ", [?T("Chatroom configuration modified")]); join -> @@ -344,19 +370,19 @@ add_message_to_log(Nick1, Message, RoomJID, Opts, State) -> [Nick, ?T("leaves the room")]); {leave, Reason} -> io_lib:format("~s ~s: ~s
    ", - [Nick, ?T("leaves the room"), htmlize(Reason,NoFollow)]); + [Nick, ?T("leaves the room"), htmlize(Reason,NoFollow,FileFormat)]); {kickban, "301", ""} -> io_lib:format("~s ~s
    ", [Nick, ?T("has been banned")]); {kickban, "301", Reason} -> io_lib:format("~s ~s: ~s
    ", - [Nick, ?T("has been banned"), htmlize(Reason)]); + [Nick, ?T("has been banned"), htmlize(Reason,FileFormat)]); {kickban, "307", ""} -> io_lib:format("~s ~s
    ", [Nick, ?T("has been kicked")]); {kickban, "307", Reason} -> io_lib:format("~s ~s: ~s
    ", - [Nick, ?T("has been kicked"), htmlize(Reason)]); + [Nick, ?T("has been kicked"), htmlize(Reason,FileFormat)]); {kickban, "321", ""} -> io_lib:format("~s ~s
    ", [Nick, ?T("has been kicked because of an affiliation change")]); @@ -368,18 +394,18 @@ add_message_to_log(Nick1, Message, RoomJID, Opts, State) -> [Nick, ?T("has been kicked because of a system shutdown")]); {nickchange, OldNick} -> io_lib:format("~s ~s ~s
    ", - [htmlize(OldNick), ?T("is now known as"), Nick]); + [htmlize(OldNick,FileFormat), ?T("is now known as"), Nick]); {subject, T} -> io_lib:format("~s~s~s
    ", - [Nick, ?T(" has set the subject to: "), htmlize(T,NoFollow)]); + [Nick, ?T(" has set the subject to: "), htmlize(T,NoFollow,FileFormat)]); {body, T} -> case regexp:first_match(T, "^/me\s") of {match, _, _} -> io_lib:format("~s ~s
    ", - [Nick, string:substr(htmlize(T), 5)]); + [Nick, string:substr(htmlize(T,FileFormat), 5)]); nomatch -> - io_lib:format("<~s> ~s
    ", - [Nick, htmlize(T,NoFollow)]) + io_lib:format("~s ~s
    ", + [Nick2, htmlize(T,NoFollow,FileFormat)]) end end, {Hour, Minute, Second} = Time, @@ -388,11 +414,11 @@ add_message_to_log(Nick1, Message, RoomJID, Opts, State) -> {_, _, Microsecs} = Now, STimeUnique = io_lib:format("~s.~w", [STime, Microsecs]), - % Write message - file:write(F, io_lib:format("[~s] ~s~n", - [STimeUnique, STimeUnique, STimeUnique, STime, Text])), + %% Write message + fw(F, io_lib:format("[~s] ", + [STimeUnique, STimeUnique, STimeUnique, STime]) ++ Text, FileFormat), - % Close file + %% Close file file:close(F), ok. @@ -443,13 +469,13 @@ make_dir_rec(Dir) -> end. -% {ok, F1}=file:open("valid-xhtml10.png", [read]). -% {ok, F1b}=file:read(F1, 1000000). -% c("../../ejabberd/src/jlib.erl"). -% jlib:encode_base64(F1b). +%% {ok, F1}=file:open("valid-xhtml10.png", [read]). +%% {ok, F1b}=file:read(F1, 1000000). +%% c("../../ejabberd/src/jlib.erl"). +%% jlib:encode_base64(F1b). image_base64("powered-by-erlang.png") -> - "iVBORw0KGgoAAAANSUhEUgAAAGUAAAAfCAYAAAD+xQNoAAADN0lEQVRo3u1a" + "iVBORw0KGgoAAAANSUhEUgAAAGUAAAAfCAYAAAD+xQNoAAADN0lEQVRo3u1a" "P0waURz+rjGRRQ+nUyRCYmJyDPTapDARaSIbTUjt1gVSh8ZW69aBAR0cWLSx" "CXWp59LR1jbdqKnGxoQuRZZrSYyHEVM6iZMbHewROA7u3fHvkr5vOn737vcu" "33ffu9/vcQz+gef5Cij6CkmSGABgFEH29r5SVvqIsTEOHo8HkiQxDBXEOjg9" @@ -471,7 +497,7 @@ image_base64("powered-by-erlang.png") -> "KF/d/wX3cJvREzl1vAAAAABJRU5ErkJggg=="; image_base64("valid-xhtml10.png") -> - "iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAMAAAEjEcpEAAACiFBMVEUAAADe" + "iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAMAAAEjEcpEAAACiFBMVEUAAADe" "5+fOezmtra3ejEKlhELvvWO9WlrehELOe3vepaWclHvetVLGc3PerVKcCAj3" "vVqUjHOUe1JjlL0xOUpjjL2UAAC91ueMrc7vrVKlvdbW3u+EpcbO3ufO1ucY" "WpSMKQi9SiF7e3taWkoQEAiMczkQSoxaUkpzc3O1lEoICACEazEhGAgIAACE" @@ -527,7 +553,7 @@ image_base64("valid-xhtml10.png") -> "QZ+RYfpNE/4Xosmq7jsZAJsAAAAASUVORK5CYII="; image_base64("vcss.png") -> - "iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAMAAABUFvrSAAABKVBMVEUAAAAj" + "iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAMAAABUFvrSAAABKVBMVEUAAAAj" "Ix8MR51ZVUqAdlmdnZ3ejEWLDAuNjY1kiMG0n2d9fX19Ghfrp1FtbW3y39+3" "Ph6lIRNdXV2qJBFcVUhcVUhPT0/dsmpUfLr57+/u7u4/PDWZAACZAADOp1Gd" "GxG+SyTgvnNdSySzk16+mkuxw+BOS0BOS0DOzs7MzMy4T09RRDwsJBG+vr73" @@ -555,7 +581,7 @@ image_base64("vcss.png") -> "AElFTkSuQmCC"; image_base64("powered-by-ejabberd.png") -> - "iVBORw0KGgoAAAANSUhEUgAAAGUAAAAfCAMAAADJG/NaAAAAw1BMVEUAAAAj" + "iVBORw0KGgoAAAANSUhEUgAAAGUAAAAfCAMAAADJG/NaAAAAw1BMVEUAAAAj" "BgYtBAM5AwFCAAAYGAJNAABcAABIDQ5qAAAoJRV7AACFAAAoKSdJHByLAAAw" "Lwk1NQA1MzFJKyo4NxtDQQBEQT5KSCxSTgBSUBlgQ0JYSEpZWQJPUU5hYABb" "W0ZiYClcW1poaCVwbQRpaDhzYWNsakhuZ2VrbFZ8dwCEgAB3dnd4d2+OjACD" @@ -579,27 +605,43 @@ image_base64("powered-by-ejabberd.png") -> "AElFTkSuQmCC". create_image_files(Images_dir) -> - Filenames = [ - "powered-by-ejabberd.png", - "powered-by-erlang.png", - "valid-xhtml10.png", - "vcss.png" - ], - lists:foreach( - fun(Filename) -> - Filename_full = filename:join([Images_dir, Filename]), - {ok, F} = file:open(Filename_full, [write]), - Image = jlib:decode_base64(image_base64(Filename)), - io:format(F, "~s", [Image]), - file:close(F) - end, - Filenames), - ok. + Filenames = ["powered-by-ejabberd.png", + "powered-by-erlang.png", + "valid-xhtml10.png", + "vcss.png" + ], + lists:foreach( + fun(Filename) -> + Filename_full = filename:join([Images_dir, Filename]), + {ok, F} = file:open(Filename_full, [write]), + Image = jlib:decode_base64(image_base64(Filename)), + io:format(F, "~s", [Image]), + file:close(F) + end, + Filenames), + ok. -fw(F, S, O) -> io:format(F, S ++ "~n", O). -fw(F, S) -> fw(F, S, []). +fw(F, S) -> fw(F, S, [], html). -put_header(F, Room, Date, CSSFile, Lang, Hour_offset, Date_prev, Date_next, Top_link) -> +fw(F, S, O) when is_list(O) -> + fw(F, S, O, html); +fw(F, S, FileFormat) when is_atom(FileFormat) -> + fw(F, S, [], FileFormat). + +fw(F, S, O, FileFormat) -> + S1 = io_lib:format(S ++ "~n", O), + S2 = case FileFormat of + html -> + S1; + plaintext -> + {ok, Res, _} = regexp:gsub(S1, "<[^>]*>", ""), + Res + end, + io:format(F, S2, []). + +put_header(_, _, _, _, _, _, _, _, _, plaintext) -> + ok; +put_header(F, Room, Date, CSSFile, Lang, Hour_offset, Date_prev, Date_next, Top_link, FileFormat) -> fw(F, ""), fw(F, "", [Lang, Lang]), fw(F, ""), @@ -618,8 +660,8 @@ put_header(F, Room, Date, CSSFile, Lang, Hour_offset, Date_prev, Date_next, Top_ {"", ""} -> ok; {SuA, Su} -> fw(F, "
    ~s~s~s
    ", [SuA, ?T(" has set the subject to: "), Su]) end, - RoomConfig = roomconfig_to_string(Room#room.config, Lang), - put_room_config(F, RoomConfig, Lang), + RoomConfig = roomconfig_to_string(Room#room.config, Lang, FileFormat), + put_room_config(F, RoomConfig, Lang, FileFormat), Time_offset_str = case Hour_offset<0 of true -> io_lib:format("~p", [Hour_offset]); false -> io_lib:format("+~p", [Hour_offset]) @@ -669,7 +711,9 @@ put_header_script(F) -> fw(F, "else {document.getElementById(e).style.display='none';}}"), fw(F, ""). -put_room_config(F, RoomConfig, Lang) -> +put_room_config(_F, _RoomConfig, _Lang, plaintext) -> + ok; +put_room_config(F, RoomConfig, Lang, _FileFormat) -> {_, Now2, _} = now(), fw(F, "
    "), fw(F, "
    ~s
    ", [Now2, ?T("Room Configuration")]), @@ -680,11 +724,18 @@ put_room_config(F, RoomConfig, Lang) -> %% The default behaviour is to ignore the nofollow spam prevention on links %% (NoFollow=false) htmlize(S1) -> - htmlize(S1, false). + htmlize(S1, html). + +htmlize(S1, plaintext) -> + S1; +htmlize(S1, FileFormat) -> + htmlize(S1, false, FileFormat). %% The NoFollow parameter tell if the spam prevention should be applied to the link found %% true means 'apply nofollow on links'. -htmlize(S1, NoFollow) -> +htmlize(S1, _NoFollow, plaintext) -> + S1; +htmlize(S1, NoFollow, _FileFormat) -> S2_list = string:tokens(S1, "\n"), lists:foldl( fun(Si, Res) -> @@ -735,20 +786,20 @@ get_room_info(RoomJID, Opts) -> config = Opts }. -roomconfig_to_string(Options, Lang) -> - % Get title, if available +roomconfig_to_string(Options, Lang, FileFormat) -> + %% Get title, if available Title = case lists:keysearch(title, 1, Options) of {value, Tuple} -> [Tuple]; false -> [] end, - - % Remove title from list + + %% Remove title from list Os1 = lists:keydelete(title, 1, Options), - - % Order list + + %% Order list Os2 = lists:sort(Os1), - - % Add title to ordered list + + %% Add title to ordered list Options2 = Title ++ Os2, lists:foldl( @@ -765,7 +816,7 @@ roomconfig_to_string(Options, Lang) -> T -> case Opt of password -> "
    " ++ OptText ++ "
    "; - title -> "
    " ++ ?T("Room title") ++ ": \"" ++ htmlize(T) ++ "\"
    "; + title -> "
    " ++ ?T("Room title") ++ ": \"" ++ htmlize(T, FileFormat) ++ "\"
    "; _ -> "\"" ++ T ++ "\"" end end, @@ -795,7 +846,7 @@ get_roomconfig_text(_) -> undefined. get_proc_name(Host) -> gen_mod:get_module_proc(Host, ?PROCNAME). calc_hour_offset(TimeHere) -> - TimeZero = calendar:now_to_universal_time(now()), - TimeHereHour = calendar:datetime_to_gregorian_seconds(TimeHere) div 3600, - TimeZeroHour = calendar:datetime_to_gregorian_seconds(TimeZero) div 3600, - TimeHereHour - TimeZeroHour. + TimeZero = calendar:now_to_universal_time(now()), + TimeHereHour = calendar:datetime_to_gregorian_seconds(TimeHere) div 3600, + TimeZeroHour = calendar:datetime_to_gregorian_seconds(TimeZero) div 3600, + TimeHereHour - TimeZeroHour. diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 64957a70a..16268196f 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -5,7 +5,7 @@ %%% Created : 19 Mar 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -63,6 +63,8 @@ allow_change_subj = true, allow_query_users = true, allow_private_messages = true, + allow_visitor_status = true, + allow_visitor_nickchange = true, public = true, public_list = true, persistent = false, @@ -886,9 +888,8 @@ process_groupchat_message(From, {xmlelement, "message", Attrs, _Els} = Packet, %% Check the mod_muc option access_message_nonparticipant and wether this JID %% is allowed or denied is_user_allowed_message_nonparticipant(JID, StateData) -> - {_AccessRoute, _AccessCreate, AccessAdmin, _AccessPersistent} = StateData#state.access, - case acl:match_rule(StateData#state.server_host, AccessAdmin, JID) of - allow -> + case get_service_affiliation(JID, StateData) of + owner -> true; _ -> false end. @@ -941,8 +942,22 @@ process_presence(From, Nick, {xmlelement, "presence", Attrs, _Els} = Packet, true -> case {is_nick_exists(Nick, StateData), mod_muc:can_use_nick( - StateData#state.host, From, Nick)} of - {true, _} -> + StateData#state.host, From, Nick), + {(StateData#state.config)#config.allow_visitor_nickchange, + is_visitor(From, StateData)}} of + {_, _, {false, true}} -> + ErrText = "Visitors are not allowed to change their nicknames in this room", + Err = jlib:make_error_reply( + Packet, + ?ERRT_NOT_ALLOWED(Lang, ErrText)), + ejabberd_router:route( + % TODO: s/Nick/""/ + jlib:jid_replace_resource( + StateData#state.jid, + Nick), + From, Err), + StateData; + {true, _, _} -> Lang = xml:get_attr_s("xml:lang", Attrs), ErrText = "Nickname is already in use by another occupant", Err = jlib:make_error_reply( @@ -954,7 +969,7 @@ process_presence(From, Nick, {xmlelement, "presence", Attrs, _Els} = Packet, Nick), % TODO: s/Nick/""/ From, Err), StateData; - {_, false} -> + {_, false, _} -> ErrText = "Nickname is registered by another person", Err = jlib:make_error_reply( Packet, @@ -969,11 +984,17 @@ process_presence(From, Nick, {xmlelement, "presence", Attrs, _Els} = Packet, _ -> change_nick(From, Nick, StateData) end; - _ -> - NewState = - add_user_presence(From, Packet, StateData), - send_new_presence(From, NewState), - NewState + _NotNickChange -> + Stanza = case {(StateData#state.config)#config.allow_visitor_status, + is_visitor(From, StateData)} of + {false, true} -> + strip_status(Packet); + _Allowed -> + Packet + end, + NewState = add_user_presence(From, Stanza, StateData), + send_new_presence(From, NewState), + NewState end; _ -> add_new_user(From, Nick, Packet, StateData) @@ -1243,6 +1264,9 @@ get_default_role(Affiliation, StateData) -> end end. +is_visitor(Jid, StateData) -> + get_role(Jid, StateData) =:= visitor. + get_max_users(StateData) -> MaxUsers = (StateData#state.config)#config.max_users, ServiceMaxUsers = get_service_max_users(StateData), @@ -1347,6 +1371,13 @@ filter_presence({xmlelement, "presence", Attrs, Els}) -> end, Els), {xmlelement, "presence", Attrs, FEls}. +strip_status({xmlelement, "presence", Attrs, Els}) -> + FEls = lists:filter( + fun({xmlelement, "status", _Attrs1, _Els1}) -> + false; + (_) -> true + end, Els), + {xmlelement, "presence", Attrs, FEls}. add_user_presence(JID, Presence, StateData) -> LJID = jlib:jid_tolower(JID), @@ -1662,6 +1693,9 @@ extract_history([_ | Els], Type) -> send_update_presence(JID, StateData) -> + send_update_presence(JID, "", StateData). + +send_update_presence(JID, Reason, StateData) -> LJID = jlib:jid_tolower(JID), LJIDs = case LJID of {U, S, ""} -> @@ -1683,10 +1717,13 @@ send_update_presence(JID, StateData) -> end end, lists:foreach(fun(J) -> - send_new_presence(J, StateData) + send_new_presence(J, Reason, StateData) end, LJIDs). send_new_presence(NJID, StateData) -> + send_new_presence(NJID, "", StateData). + +send_new_presence(NJID, Reason, StateData) -> {ok, #user{jid = RealJID, nick = Nick, role = Role, @@ -1708,6 +1745,13 @@ send_new_presence(NJID, StateData) -> [{"affiliation", SAffiliation}, {"role", SRole}] end, + ItemEls = case Reason of + "" -> + []; + _ -> + [{xmlelement, "reason", [], + [{xmlcdata, Reason}]}] + end, Status = case StateData#state.just_created of true -> [{xmlelement, "status", [{"code", "201"}], []}]; @@ -1717,7 +1761,7 @@ send_new_presence(NJID, StateData) -> Packet = append_subtags( Presence, [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], - [{xmlelement, "item", ItemAttrs, []} | Status]}]), + [{xmlelement, "item", ItemAttrs, ItemEls} | Status]}]), ejabberd_router:route( jlib:jid_replace_resource(StateData#state.jid, Nick), Info#user.jid, @@ -2085,21 +2129,21 @@ process_admin_items_set(UJID, Items, Lang, StateData) -> set_affiliation_and_reason( JID, outcast, Reason, set_role(JID, none, SD)); - {JID, affiliation, A, _Reason} when + {JID, affiliation, A, Reason} when (A == admin) or (A == owner) -> - SD1 = set_affiliation(JID, A, SD), + SD1 = set_affiliation_and_reason(JID, A, Reason, SD), SD2 = set_role(JID, moderator, SD1), - send_update_presence(JID, SD2), + send_update_presence(JID, Reason, SD2), SD2; - {JID, affiliation, member, _Reason} -> - SD1 = set_affiliation( - JID, member, SD), + {JID, affiliation, member, Reason} -> + SD1 = set_affiliation_and_reason( + JID, member, Reason, SD), SD2 = set_role(JID, participant, SD1), - send_update_presence(JID, SD2), + send_update_presence(JID, Reason, SD2), SD2; - {JID, role, R, _Reason} -> - SD1 = set_role(JID, R, SD), - catch send_new_presence(JID, SD1), + {JID, role, Role, Reason} -> + SD1 = set_role(JID, Role, SD), + catch send_new_presence(JID, Reason, SD1), SD1; {JID, affiliation, A, _Reason} -> SD1 = set_affiliation(JID, A, SD), @@ -2187,11 +2231,13 @@ find_changed_items(UJID, UAffiliation, URole, [StrAffiliation]), {error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText1)}; SAffiliation -> + ServiceAf = get_service_affiliation(JID, StateData), CanChangeRA = case can_change_ra( UAffiliation, URole, TAffiliation, TRole, - affiliation, SAffiliation) of + affiliation, SAffiliation, + ServiceAf) of nothing -> nothing; true -> @@ -2242,11 +2288,13 @@ find_changed_items(UJID, UAffiliation, URole, [StrRole]), {error, ?ERRT_BAD_REQUEST(Lang, ErrText1)}; SRole -> + ServiceAf = get_service_affiliation(JID, StateData), CanChangeRA = case can_change_ra( UAffiliation, URole, TAffiliation, TRole, - role, SRole) of + role, SRole, + ServiceAf) of nothing -> nothing; true -> @@ -2292,143 +2340,149 @@ find_changed_items(_UJID, _UAffiliation, _URole, _Items, {error, ?ERR_BAD_REQUEST}. +can_change_ra(_FAffiliation, _FRole, + owner, _TRole, + affiliation, owner, owner) -> + %% A room owner tries to add as persistent owner a + %% participant that is already owner because he is MUC admin + true; can_change_ra(_FAffiliation, _FRole, TAffiliation, _TRole, - affiliation, Value) + affiliation, Value, _ServiceAf) when (TAffiliation == Value) -> nothing; can_change_ra(_FAffiliation, _FRole, _TAffiliation, TRole, - role, Value) + role, Value, _ServiceAf) when (TRole == Value) -> nothing; can_change_ra(FAffiliation, _FRole, outcast, _TRole, - affiliation, none) + affiliation, none, _ServiceAf) when (FAffiliation == owner) or (FAffiliation == admin) -> true; can_change_ra(FAffiliation, _FRole, outcast, _TRole, - affiliation, member) + affiliation, member, _ServiceAf) when (FAffiliation == owner) or (FAffiliation == admin) -> true; can_change_ra(owner, _FRole, outcast, _TRole, - affiliation, admin) -> + affiliation, admin, _ServiceAf) -> true; can_change_ra(owner, _FRole, outcast, _TRole, - affiliation, owner) -> + affiliation, owner, _ServiceAf) -> true; can_change_ra(FAffiliation, _FRole, none, _TRole, - affiliation, outcast) + affiliation, outcast, _ServiceAf) when (FAffiliation == owner) or (FAffiliation == admin) -> true; can_change_ra(FAffiliation, _FRole, none, _TRole, - affiliation, member) + affiliation, member, _ServiceAf) when (FAffiliation == owner) or (FAffiliation == admin) -> true; can_change_ra(owner, _FRole, none, _TRole, - affiliation, admin) -> + affiliation, admin, _ServiceAf) -> true; can_change_ra(owner, _FRole, none, _TRole, - affiliation, owner) -> + affiliation, owner, _ServiceAf) -> true; can_change_ra(FAffiliation, _FRole, member, _TRole, - affiliation, outcast) + affiliation, outcast, _ServiceAf) when (FAffiliation == owner) or (FAffiliation == admin) -> true; can_change_ra(FAffiliation, _FRole, member, _TRole, - affiliation, none) + affiliation, none, _ServiceAf) when (FAffiliation == owner) or (FAffiliation == admin) -> true; can_change_ra(owner, _FRole, member, _TRole, - affiliation, admin) -> + affiliation, admin, _ServiceAf) -> true; can_change_ra(owner, _FRole, member, _TRole, - affiliation, owner) -> + affiliation, owner, _ServiceAf) -> true; can_change_ra(owner, _FRole, admin, _TRole, - affiliation, _Affiliation) -> + affiliation, _Affiliation, _ServiceAf) -> true; can_change_ra(owner, _FRole, owner, _TRole, - affiliation, _Affiliation) -> + affiliation, _Affiliation, _ServiceAf) -> check_owner; can_change_ra(_FAffiliation, _FRole, _TAffiliation, _TRole, - affiliation, _Value) -> + affiliation, _Value, _ServiceAf) -> false; can_change_ra(_FAffiliation, moderator, _TAffiliation, visitor, - role, none) -> + role, none, _ServiceAf) -> true; can_change_ra(_FAffiliation, moderator, _TAffiliation, visitor, - role, participant) -> + role, participant, _ServiceAf) -> true; can_change_ra(FAffiliation, _FRole, _TAffiliation, visitor, - role, moderator) + role, moderator, _ServiceAf) when (FAffiliation == owner) or (FAffiliation == admin) -> true; can_change_ra(_FAffiliation, moderator, _TAffiliation, participant, - role, none) -> + role, none, _ServiceAf) -> true; can_change_ra(_FAffiliation, moderator, _TAffiliation, participant, - role, visitor) -> + role, visitor, _ServiceAf) -> true; can_change_ra(FAffiliation, _FRole, _TAffiliation, participant, - role, moderator) + role, moderator, _ServiceAf) when (FAffiliation == owner) or (FAffiliation == admin) -> true; can_change_ra(_FAffiliation, _FRole, owner, moderator, - role, visitor) -> + role, visitor, _ServiceAf) -> false; can_change_ra(owner, _FRole, _TAffiliation, moderator, - role, visitor) -> + role, visitor, _ServiceAf) -> true; can_change_ra(_FAffiliation, _FRole, admin, moderator, - role, visitor) -> + role, visitor, _ServiceAf) -> false; can_change_ra(admin, _FRole, _TAffiliation, moderator, - role, visitor) -> + role, visitor, _ServiceAf) -> true; can_change_ra(_FAffiliation, _FRole, owner, moderator, - role, participant) -> + role, participant, _ServiceAf) -> false; can_change_ra(owner, _FRole, _TAffiliation, moderator, - role, participant) -> + role, participant, _ServiceAf) -> true; can_change_ra(_FAffiliation, _FRole, admin, moderator, - role, participant) -> + role, participant, _ServiceAf) -> false; can_change_ra(admin, _FRole, _TAffiliation, moderator, - role, participant) -> + role, participant, _ServiceAf) -> true; can_change_ra(_FAffiliation, _FRole, _TAffiliation, _TRole, - role, _Value) -> + role, _Value, _ServiceAf) -> false. @@ -2700,7 +2754,13 @@ get_config(Lang, StateData, From) -> Config#config.allow_query_users), ?BOOLXFIELD("Allow users to send invites", "muc#roomconfig_allowinvites", - Config#config.allow_user_invites) + Config#config.allow_user_invites), + ?BOOLXFIELD("Allow visitors to send status text in presence updates", + "muc#roomconfig_allowvisitorstatus", + Config#config.allow_visitor_status), + ?BOOLXFIELD("Allow visitors to change nickname", + "muc#roomconfig_allowvisitornickchange", + Config#config.allow_visitor_nickchange) ] ++ case mod_muc_log:check_access_log( StateData#state.server_host, From) of @@ -2773,6 +2833,10 @@ set_xoption([{"allow_query_users", [Val]} | Opts], Config) -> ?SET_BOOL_XOPT(allow_query_users, Val); set_xoption([{"allow_private_messages", [Val]} | Opts], Config) -> ?SET_BOOL_XOPT(allow_private_messages, Val); +set_xoption([{"muc#roomconfig_allowvisitorstatus", [Val]} | Opts], Config) -> + ?SET_BOOL_XOPT(allow_visitor_status, Val); +set_xoption([{"muc#roomconfig_allowvisitornickchange", [Val]} | Opts], Config) -> + ?SET_BOOL_XOPT(allow_visitor_nickchange, Val); set_xoption([{"muc#roomconfig_publicroom", [Val]} | Opts], Config) -> ?SET_BOOL_XOPT(public, Val); set_xoption([{"public_list", [Val]} | Opts], Config) -> @@ -2866,6 +2930,8 @@ set_opts([{Opt, Val} | Opts], StateData) -> allow_change_subj -> StateData#state{config = (StateData#state.config)#config{allow_change_subj = Val}}; allow_query_users -> StateData#state{config = (StateData#state.config)#config{allow_query_users = Val}}; allow_private_messages -> StateData#state{config = (StateData#state.config)#config{allow_private_messages = Val}}; + allow_visitor_nickchange -> StateData#state{config = (StateData#state.config)#config{allow_visitor_nickchange = Val}}; + allow_visitor_status -> StateData#state{config = (StateData#state.config)#config{allow_visitor_status = Val}}; public -> StateData#state{config = (StateData#state.config)#config{public = Val}}; public_list -> StateData#state{config = (StateData#state.config)#config{public_list = Val}}; persistent -> StateData#state{config = (StateData#state.config)#config{persistent = Val}}; @@ -2906,6 +2972,8 @@ make_opts(StateData) -> ?MAKE_CONFIG_OPT(allow_change_subj), ?MAKE_CONFIG_OPT(allow_query_users), ?MAKE_CONFIG_OPT(allow_private_messages), + ?MAKE_CONFIG_OPT(allow_visitor_status), + ?MAKE_CONFIG_OPT(allow_visitor_nickchange), ?MAKE_CONFIG_OPT(public), ?MAKE_CONFIG_OPT(public_list), ?MAKE_CONFIG_OPT(persistent), diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 3712dadbf..f79b0c19f 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -5,7 +5,7 @@ %%% Created : 5 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index a8831aa0d..cfceb41e2 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -5,7 +5,7 @@ %%% Created : 5 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -118,6 +118,8 @@ loop(Host, MaxOfflineMsgs) -> case catch odbc_queries:add_spool(Host, Query) of {'EXIT', Reason} -> ?ERROR_MSG("~p~n", [Reason]); + {error, Reason} -> + ?ERROR_MSG("~p~n", [Reason]); _ -> ok end diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 3f696eb42..4de51b260 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -5,7 +5,7 @@ %%% Created : 21 Jul 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_privacy.hrl b/src/mod_privacy.hrl index 21ad1c961..50b07ab34 100644 --- a/src/mod_privacy.hrl +++ b/src/mod_privacy.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index b4e267d28..11e3956eb 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -5,7 +5,7 @@ %%% Created : 5 Oct 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -96,16 +96,14 @@ process_iq_get(_, From, _To, #iq{sub_el = SubEl}, process_lists_get(LUser, LServer, Active) -> Default = case catch sql_get_default_privacy_list(LUser, LServer) of - {'EXIT', _Reason} -> - none; {selected, ["name"], []} -> none; {selected, ["name"], [{DefName}]} -> - DefName + DefName; + _ -> + none end, case catch sql_get_privacy_list_names(LUser, LServer) of - {'EXIT', _Reason2} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; {selected, ["name"], []} -> {result, [{xmlelement, "query", [{"xmlns", ?NS_PRIVACY}], []}]}; {selected, ["name"], Names} -> @@ -132,19 +130,17 @@ process_lists_get(LUser, LServer, Active) -> end, {result, [{xmlelement, "query", [{"xmlns", ?NS_PRIVACY}], - ADItems}]} + ADItems}]}; + _ -> + {error, ?ERR_INTERNAL_SERVER_ERROR} end. process_list_get(LUser, LServer, {value, Name}) -> case catch sql_get_privacy_list_id(LUser, LServer, Name) of - {'EXIT', _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; {selected, ["id"], []} -> {error, ?ERR_ITEM_NOT_FOUND}; {selected, ["id"], [{ID}]} -> case catch sql_get_privacy_list_data_by_id(ID, LServer) of - {'EXIT', _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; {selected, ["t", "value", "action", "ord", "match_all", "match_iq", "match_message", "match_presence_in", "match_presence_out"], @@ -154,8 +150,12 @@ process_list_get(LUser, LServer, {value, Name}) -> {result, [{xmlelement, "query", [{"xmlns", ?NS_PRIVACY}], [{xmlelement, "list", - [{"name", Name}], LItems}]}]} - end + [{"name", Name}], LItems}]}]}; + _ -> + {error, ?ERR_INTERNAL_SERVER_ERROR} + end; + _ -> + {error, ?ERR_INTERNAL_SERVER_ERROR} end; process_list_get(_LUser, _LServer, false) -> @@ -294,6 +294,8 @@ process_default_set(LUser, LServer, false) -> case catch sql_unset_default_privacy_list(LUser, LServer) of {'EXIT', _Reason} -> {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, _Reason} -> + {error, ?ERR_INTERNAL_SERVER_ERROR}; _ -> {result, []} end. @@ -301,21 +303,21 @@ process_default_set(LUser, LServer, false) -> process_active_set(LUser, LServer, {value, Name}) -> case catch sql_get_privacy_list_id(LUser, LServer, Name) of - {'EXIT', _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; {selected, ["id"], []} -> {error, ?ERR_ITEM_NOT_FOUND}; {selected, ["id"], [{ID}]} -> case catch sql_get_privacy_list_data_by_id(ID, LServer) of - {'EXIT', _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; {selected, ["t", "value", "action", "ord", "match_all", "match_iq", "match_message", "match_presence_in", "match_presence_out"], RItems} -> Items = lists:map(fun raw_to_item/1, RItems), - {result, [], #userlist{name = Name, list = Items}} - end + {result, [], #userlist{name = Name, list = Items}}; + _ -> + {error, ?ERR_INTERNAL_SERVER_ERROR} + end; + _ -> + {error, ?ERR_INTERNAL_SERVER_ERROR} end; process_active_set(_LUser, _LServer, false) -> @@ -517,21 +519,21 @@ get_user_list(_, User, Server) -> LServer = jlib:nameprep(Server), case catch sql_get_default_privacy_list(LUser, LServer) of - {'EXIT', _Reason} -> - #userlist{}; {selected, ["name"], []} -> #userlist{}; {selected, ["name"], [{Default}]} -> case catch sql_get_privacy_list_data(LUser, LServer, Default) of - {'EXIT', _Reason} -> - #userlist{}; {selected, ["t", "value", "action", "ord", "match_all", "match_iq", "match_message", "match_presence_in", "match_presence_out"], RItems} -> Items = lists:map(fun raw_to_item/1, RItems), - #userlist{name = Default, list = Items} - end + #userlist{name = Default, list = Items}; + _ -> + #userlist{} + end; + _ -> + #userlist{} end. diff --git a/src/mod_private.erl b/src/mod_private.erl index 89c73fd02..1a4ad4fff 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -5,7 +5,7 @@ %%% Created : 16 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_private_odbc.erl b/src/mod_private_odbc.erl index 04248cb06..6ea9a9af2 100644 --- a/src/mod_private_odbc.erl +++ b/src/mod_private_odbc.erl @@ -5,7 +5,7 @@ %%% Created : 5 Oct 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_proxy65/mod_proxy65.erl b/src/mod_proxy65/mod_proxy65.erl index 970602eb5..67f900520 100644 --- a/src/mod_proxy65/mod_proxy65.erl +++ b/src/mod_proxy65/mod_proxy65.erl @@ -5,7 +5,7 @@ %%% Created : 12 Oct 2006 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_proxy65/mod_proxy65.hrl b/src/mod_proxy65/mod_proxy65.hrl index 66cb86f42..310cbac20 100644 --- a/src/mod_proxy65/mod_proxy65.hrl +++ b/src/mod_proxy65/mod_proxy65.hrl @@ -2,7 +2,7 @@ %%% RFC 1928 constants. %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_proxy65/mod_proxy65_lib.erl b/src/mod_proxy65/mod_proxy65_lib.erl index 8e30bb4a6..9f3a84fd0 100644 --- a/src/mod_proxy65/mod_proxy65_lib.erl +++ b/src/mod_proxy65/mod_proxy65_lib.erl @@ -5,7 +5,7 @@ %%% Created : 12 Oct 2006 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -35,7 +35,7 @@ unpack_request/1, make_init_reply/1, make_auth_reply/1, - make_reply/0, + make_reply/1, make_error_reply/1, make_error_reply/2 ]). @@ -73,12 +73,8 @@ make_init_reply(Method) -> make_auth_reply(true) -> [1, ?SUCCESS]; make_auth_reply(false) -> [1, ?ERR_NOT_ALLOWED]. -%% WARNING: According to SOCKS5 RFC, this reply is _incorrect_, but -%% Psi writes junk to the beginning of the file on correct reply. -%% I'm not sure, but there may be an issue with other clients. -%% Needs more testing. -make_reply() -> - [?VERSION_5, ?SUCCESS, 0, 0, 0, 0]. +make_reply(#s5_request{rsv = RSV, sha1 = SHA1}) -> + [?VERSION_5, ?SUCCESS, RSV, ?ATYP_DOMAINNAME, length(SHA1), SHA1, 0,0]. make_error_reply(Request) -> make_error_reply(Request, ?ERR_NOT_ALLOWED). diff --git a/src/mod_proxy65/mod_proxy65_service.erl b/src/mod_proxy65/mod_proxy65_service.erl index 4ee3ec61a..36d01b9c3 100644 --- a/src/mod_proxy65/mod_proxy65_service.erl +++ b/src/mod_proxy65/mod_proxy65_service.erl @@ -5,7 +5,7 @@ %%% Created : 12 Oct 2006 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_proxy65/mod_proxy65_sm.erl b/src/mod_proxy65/mod_proxy65_sm.erl index 591bf97c7..0db1f1537 100644 --- a/src/mod_proxy65/mod_proxy65_sm.erl +++ b/src/mod_proxy65/mod_proxy65_sm.erl @@ -5,7 +5,7 @@ %%% Created : 12 Oct 2006 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_proxy65/mod_proxy65_stream.erl b/src/mod_proxy65/mod_proxy65_stream.erl index 046ac8e71..9d42dcaa3 100644 --- a/src/mod_proxy65/mod_proxy65_stream.erl +++ b/src/mod_proxy65/mod_proxy65_stream.erl @@ -4,7 +4,7 @@ %%% Purpose : Bytestream process. %%% Created : 12 Oct 2006 by Evgeniy Khramtsov %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -172,7 +172,7 @@ wait_for_request(Packet, #state{socket=Socket} = StateData) -> case catch mod_proxy65_sm:register_stream(SHA1) of {atomic, ok} -> inet:setopts(Socket, [{active, false}]), - gen_tcp:send(Socket, mod_proxy65_lib:make_reply()), + gen_tcp:send(Socket, mod_proxy65_lib:make_reply(Request)), {next_state, wait_for_activation, StateData#state{sha1=SHA1}}; _ -> Err = mod_proxy65_lib:make_error_reply(Request), diff --git a/src/mod_pubsub/gen_pubsub_node.erl b/src/mod_pubsub/gen_pubsub_node.erl index bbbb5c409..a193a51cc 100644 --- a/src/mod_pubsub/gen_pubsub_node.erl +++ b/src/mod_pubsub/gen_pubsub_node.erl @@ -10,13 +10,13 @@ %%% the License for the specific language governing rights and limitations %%% under the License. %%% -%%% The Initial Developer of the Original Code is Process-one. -%%% Portions created by Process-one are Copyright 2006-2008, Process-one +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, Process-one. +%%% This software is copyright 2006-2008, ProcessOne. %%% %%% -%%% @copyright 2006-2008 Process-one +%%% @copyright 2006-2008 ProcessOne %%% @author Christophe Romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/gen_pubsub_nodetree.erl b/src/mod_pubsub/gen_pubsub_nodetree.erl index 668b71a8e..ebdeca450 100644 --- a/src/mod_pubsub/gen_pubsub_nodetree.erl +++ b/src/mod_pubsub/gen_pubsub_nodetree.erl @@ -10,13 +10,13 @@ %%% the License for the specific language governing rights and limitations %%% under the License. %%% -%%% The Initial Developer of the Original Code is Process-one. -%%% Portions created by Process-one are Copyright 2006-2008, Process-one +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, Process-one. +%%% This software is copyright 2006-2008, ProcessOne. %%% %%% -%%% @copyright 2006-2008 Process-one +%%% @copyright 2006-2008 ProcessOne %%% @author Christophe Romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index e83e0170f..dd86b91bb 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -10,12 +10,12 @@ %%% the License for the specific language governing rights and limitations %%% under the License. %%% -%%% The Initial Developer of the Original Code is Process-one. -%%% Portions created by Process-one are Copyright 2006-2008, Process-one +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, Process-one. +%%% This software is copyright 2006-2008, ProcessOne. %%% -%%% @copyright 2006-2008 Process-one +%%% @copyright 2006-2008 ProcessOne %%% @author Christophe Romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} @@ -226,8 +226,6 @@ terminate_plugins(Host, ServerHost, Plugins, TreePlugin) -> ok. init_nodes(Host, ServerHost) -> - create_node(Host, ServerHost, ["pubsub"], service_jid(Host), ?STDNODE), - create_node(Host, ServerHost, ["pubsub", "nodes"], service_jid(Host), ?STDNODE), create_node(Host, ServerHost, ["home"], service_jid(Host), ?STDNODE), create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), ?STDNODE), ok. @@ -285,8 +283,7 @@ update_database(Host) -> mnesia:delete_table(pubsub_node), mnesia:create_table(pubsub_node, [{disc_copies, [node()]}, - {attributes, record_info(fields, pubsub_node)}, - {index, [type, parentid]}]), + {attributes, record_info(fields, pubsub_node)}]), lists:foreach(fun(Record) -> mnesia:write(Record) end, NewRecords) @@ -416,7 +413,7 @@ remove_user(User, Server) -> LUser = jlib:nodeprep(User), LServer = jlib:nameprep(Server), Proc = gen_mod:get_module_proc(Server, ?PROCNAME), - gen_server:cast(Proc, {remove, LUser, LServer}). + gen_server:cast(Proc, {remove_user, LUser, LServer}). %%-------------------------------------------------------------------- %% Function: @@ -472,7 +469,7 @@ handle_cast({presence, JID, Pid}, State) -> end, Subscriptions) end, State#state.plugins), %% and send to From last PEP events published by its contacts - case catch ejabberd_c2s:get_subscribed_and_online(Pid) of + case catch ejabberd_c2s:get_subscribed(Pid) of ContactsWithCaps when is_list(ContactsWithCaps) -> Caps = proplists:get_value(LJID, ContactsWithCaps), ContactsUsers = lists:usort(lists:map( @@ -513,10 +510,27 @@ handle_cast({presence, JID, Pid}, State) -> end, {noreply, State}; -handle_cast({remove, User, Server}, State) -> - Owner = jlib:make_jid(User, Server, ""), - delete_nodes(Server, Owner), - {noreply, State}; +handle_cast({remove_user, User, Host}, State) -> + Owner = jlib:make_jid(User, Host, ""), + OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + %% remove user's subscriptions + lists:foreach(fun(Type) -> + {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, Owner]), + lists:foreach(fun + ({Node, subscribed}) -> + JID = jlib:jid_to_string(Owner), + unsubscribe_node(Host, Node, Owner, JID, all); + (_) -> + ok + end, Subscriptions) + end, State#state.plugins), + %% remove user's PEP nodes + lists:foreach(fun(#pubsub_node{nodeid={NodeKey, NodeName}}) -> + delete_node(NodeKey, NodeName, Owner) + end, tree_action(Host, get_nodes, [OwnerKey])), + %% remove user's nodes + delete_node(Host, ["home", Host, User], Owner), + {noreply, State}; handle_cast(_Msg, State) -> {noreply, State}. @@ -918,7 +932,7 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) -> ({xmlelement, "item", ItemAttrs, _}, Acc) -> case xml:get_attr_s("id", ItemAttrs) of "" -> Acc; - ItemID -> ItemID + ItemID -> [ItemID|Acc] end; (_, Acc) -> Acc @@ -1295,12 +1309,6 @@ delete_node(Host, Node, Owner) -> {result, Result} -> {result, Result} end. -delete_nodes(Host, Owner) -> - %% This removes only PEP nodes when user is removed - OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), - lists:foreach(fun(#pubsub_node{nodeid={NodeKey, NodeName}}) -> - delete_node(NodeKey, NodeName, Owner) - end, tree_action(Host, get_nodes, [OwnerKey])). %% @spec (Host, Node, From, JID) -> %% {error, Reason::stanzaError()} | @@ -1376,7 +1384,7 @@ subscribe_node(Host, Node, From, JID) -> {error, Error} -> {error, Error}; {result, {Result, subscribed, send_last}} -> - send_all_items(Host, Node, Subscriber), + send_last_item(Host, Node, Subscriber), case Result of default -> {result, Reply(subscribed)}; _ -> {result, Result} @@ -1683,8 +1691,8 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> [] -> Items; _ -> - lists:filter(fun(Item) -> - lists:member(Item, ItemIDs) + lists:filter(fun(#pubsub_item{itemid = {ItemId, _}}) -> + lists:member(ItemId, ItemIDs) end, Items) end, %% Generate the XML response (Item list), limiting the @@ -1723,21 +1731,25 @@ send_last_item(Host, Node, LJID) -> %% TODO use cache-last-item feature send_items(Host, Node, LJID, Number) -> - Items = get_items(Host, Node), - ToSend = case Number of - last -> lists:sublist(Items, 1); - all -> Items; - N when N > 0 -> lists:sublist(Items, N); - _ -> Items - end, + ToSend = case get_items(Host, Node) of + [] -> + []; + Items -> + case Number of + last -> lists:sublist(lists:reverse(Items), 1); + all -> Items; + N when N > 0 -> lists:nthtail(length(Items)-N, Items); + _ -> Items + end + end, ItemsEls = lists:map( - fun(#pubsub_item{itemid = {ItemId, _}, payload = Payload}) -> - ItemAttrs = case ItemId of - "" -> []; - _ -> [{"id", ItemId}] - end, - {xmlelement, "item", ItemAttrs, Payload} - end, ToSend), + fun(#pubsub_item{itemid = {ItemId, _}, payload = Payload}) -> + ItemAttrs = case ItemId of + "" -> []; + _ -> [{"id", ItemId}] + end, + {xmlelement, "item", ItemAttrs, Payload} + end, ToSend), Stanza = {xmlelement, "message", [], [{xmlelement, "event", [{"xmlns", ?NS_PUBSUB_EVENT}], [{xmlelement, "items", [{"node", node_to_string(Node)}], @@ -2000,7 +2012,8 @@ get_roster_info(OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, _}, A roster_get_jid_info, OwnerServer, {none, []}, [OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, ""}]), - PresenceSubscription = (Subscription == both) orelse (Subscription == from), + PresenceSubscription = (Subscription == both) orelse (Subscription == from) + orelse ({OwnerUser, OwnerServer} == {SubscriberUser, SubscriberServer}), RosterGroup = lists:any(fun(Group) -> lists:member(Group, AllowedGroups) end, Groups), @@ -2414,9 +2427,11 @@ get_default(Host, _Node, _From, Lang) -> %% The result depend of the node type plugin system. get_option([], _) -> false; get_option(Options, Var) -> + get_option(Options, Var, false). +get_option(Options, Var, Def) -> case lists:keysearch(Var, 1, Options) of {value, {_Val, Ret}} -> Ret; - _ -> false + _ -> Def end. %% Get default options from the module plugin. @@ -2461,7 +2476,7 @@ max_items(Options) -> -define(STRING_CONFIG_FIELD(Label, Var), ?STRINGXFIELD(Label, "pubsub#" ++ atom_to_list(Var), - get_option(Options, Var))). + get_option(Options, Var, ""))). -define(INTEGER_CONFIG_FIELD(Label, Var), ?STRINGXFIELD(Label, "pubsub#" ++ atom_to_list(Var), diff --git a/src/mod_pubsub/node.template b/src/mod_pubsub/node.template index 973aa38a4..9c2344ae1 100644 --- a/src/mod_pubsub/node.template +++ b/src/mod_pubsub/node.template @@ -10,12 +10,12 @@ %%% the License for the specific language governing rights and limitations %%% under the License. %%% -%%% The Initial Developer of the Original Code is Process-one. -%%% Portions created by Process-one are Copyright 2006-2008, Process-one +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, Process-one. +%%% This software is copyright 2006-2008, ProcessOne. %%% -%%% @copyright 2006-2008 Process-one +%%% @copyright 2006-2008 ProcessOne %%% @author Christophe romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl index cd051b66f..8bca962d3 100644 --- a/src/mod_pubsub/node_buddy.erl +++ b/src/mod_pubsub/node_buddy.erl @@ -10,13 +10,13 @@ %%% the License for the specific language governing rights and limitations %%% under the License. %%% -%%% The Initial Developer of the Original Code is Process-one. -%%% Portions created by Process-one are Copyright 2006-2008, Process-one +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, Process-one. +%%% This software is copyright 2006-2008, ProcessOne. %%% %%% -%%% @copyright 2006-2008 Process-one +%%% @copyright 2006-2008 ProcessOne %%% @author Christophe romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl index 155edc10a..978f6f39d 100644 --- a/src/mod_pubsub/node_club.erl +++ b/src/mod_pubsub/node_club.erl @@ -10,13 +10,13 @@ %%% the License for the specific language governing rights and limitations %%% under the License. %%% -%%% The Initial Developer of the Original Code is Process-one. -%%% Portions created by Process-one are Copyright 2006-2008, Process-one +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, Process-one. +%%% This software is copyright 2006-2008, ProcessOne. %%% %%% -%%% @copyright 2006-2008 Process-one +%%% @copyright 2006-2008 ProcessOne %%% @author Christophe romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 491676269..ddda469c6 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -10,13 +10,13 @@ %%% the License for the specific language governing rights and limitations %%% under the License. %%% -%%% The Initial Developer of the Original Code is Process-one. -%%% Portions created by Process-one are Copyright 2006-2008, Process-one +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, Process-one. +%%% This software is copyright 2006-2008, ProcessOne. %%% %%% -%%% @copyright 2006-2008 Process-one +%%% @copyright 2006-2008 ProcessOne %%% @author Christophe Romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} @@ -193,21 +193,23 @@ features() -> %% module by implementing this function like this: %% ```check_create_user_permission(Host, Node, Owner, Access) -> %% node_default:check_create_user_permission(Host, Node, Owner, Access).'''

    -create_node_permission(_Host, ServerHost, Node, _ParentNode, Owner, Access) -> +create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) -> LOwner = jlib:jid_tolower(Owner), {User, Server, _Resource} = LOwner, - Allowed = case acl:match_rule(ServerHost, Access, LOwner) of + Allowed = case LOwner of + {"", Host, ""} -> + true; % pubsub service always allowed + _ -> + case acl:match_rule(ServerHost, Access, LOwner) of allow -> case Node of ["home", Server, User | _] -> true; _ -> false end; _ -> - case Owner of - {jid, "", _, "", "", _, ""} -> true; - _ -> false - end - end, + false + end + end, {result, Allowed}. %% @spec (Host, Node, Owner) -> diff --git a/src/mod_pubsub/node_dispatch.erl b/src/mod_pubsub/node_dispatch.erl index 0532826d2..0d9e1dcd9 100644 --- a/src/mod_pubsub/node_dispatch.erl +++ b/src/mod_pubsub/node_dispatch.erl @@ -10,13 +10,13 @@ %%% the License for the specific language governing rights and limitations %%% under the License. %%% -%%% The Initial Developer of the Original Code is Process-one. -%%% Portions created by Process-one are Copyright 2006-2008, Process-one +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, Process-one. +%%% This software is copyright 2006-2008, ProcessOne. %%% %%% -%%% @copyright 2006-2008 Process-one +%%% @copyright 2006-2008 ProcessOne %%% @author Christophe romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} @@ -129,7 +129,7 @@ publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) -> node_default:publish_item( Host, SubNode, Publisher, Model, MaxItems, ItemId, Payload) - end, nodetree_default:get_subnodes(Host, Node)). + end, nodetree_default:get_subnodes(Host, Node, Publisher)). remove_extra_items(_Host, _Node, _MaxItems, ItemIds) -> {result, {ItemIds, []}}. diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index 2c648148d..ddbf13b4b 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -10,13 +10,13 @@ %%% the License for the specific language governing rights and limitations %%% under the License. %%% -%%% The Initial Developer of the Original Code is Process-one. -%%% Portions created by Process-one are Copyright 2006-2008, Process-one +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, Process-one. +%%% This software is copyright 2006-2008, ProcessOne. %%% %%% -%%% @copyright 2006-2008 Process-one +%%% @copyright 2006-2008 ProcessOne %%% @author Christophe Romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} @@ -110,10 +110,25 @@ features() -> "subscribe" %* ]. -create_node_permission(_Host, _ServerHost, _Node, _ParentNode, _Owner, _Access) -> - %% TODO may we check bare JID match ? - {result, true}. - +create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> + LOwner = jlib:jid_tolower(Owner), + {User, Server, _Resource} = LOwner, + Allowed = case LOwner of + {"", Host, ""} -> + true; % pubsub service always allowed + _ -> + case acl:match_rule(ServerHost, Access, LOwner) of + allow -> + case Host of + {User, Server, _} -> true; + _ -> false + end; + _ -> + false + end + end, + {result, Allowed}. + create_node(Host, Node, Owner) -> case node_default:create_node(Host, Node, Owner) of {result, _} -> {result, []}; diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl index 00e952392..08d6abd85 100644 --- a/src/mod_pubsub/node_private.erl +++ b/src/mod_pubsub/node_private.erl @@ -10,13 +10,13 @@ %%% the License for the specific language governing rights and limitations %%% under the License. %%% -%%% The Initial Developer of the Original Code is Process-one. -%%% Portions created by Process-one are Copyright 2006-2008, Process-one +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, Process-one. +%%% This software is copyright 2006-2008, ProcessOne. %%% %%% -%%% @copyright 2006-2008 Process-one +%%% @copyright 2006-2008 ProcessOne %%% @author Christophe romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl index ab4107a76..08559e423 100644 --- a/src/mod_pubsub/node_public.erl +++ b/src/mod_pubsub/node_public.erl @@ -10,13 +10,13 @@ %%% the License for the specific language governing rights and limitations %%% under the License. %%% -%%% The Initial Developer of the Original Code is Process-one. -%%% Portions created by Process-one are Copyright 2006-2008, Process-one +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, Process-one. +%%% This software is copyright 2006-2008, ProcessOne. %%% %%% -%%% @copyright 2006-2008 Process-one +%%% @copyright 2006-2008 ProcessOne %%% @author Christophe romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/node_zoo.erl b/src/mod_pubsub/node_zoo.erl index 45e601ed7..a0d8afb09 100644 --- a/src/mod_pubsub/node_zoo.erl +++ b/src/mod_pubsub/node_zoo.erl @@ -10,12 +10,12 @@ %%% the License for the specific language governing rights and limitations %%% under the License. %%% -%%% The Initial Developer of the Original Code is Process-one. -%%% Portions created by Process-one are Copyright 2006-2008, Process-one +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, Process-one. +%%% This software is copyright 2006-2008, ProcessOne. %%% -%%% @copyright 2006-2008 Process-one +%%% @copyright 2006-2008 ProcessOne %%% @author Christophe romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} @@ -91,18 +91,19 @@ features() -> %% use same code as node_default, but do not limite node to %% the home/localhost/user/... hierarchy %% any node is allowed -create_node_permission(_Host, ServerHost, _Node, _ParentNode, Owner, Access) -> +create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> LOwner = jlib:jid_tolower(Owner), - %%{_User, _Server, _Resource} = LOwner, - Allowed = case acl:match_rule(ServerHost, Access, LOwner) of + Allowed = case LOwner of + {"", Host, ""} -> + true; % pubsub service always allowed + _ -> + case acl:match_rule(ServerHost, Access, LOwner) of allow -> true; - _ -> - case Owner of - {jid, "", _, "", "", _, ""} -> true; - _ -> false - end - end, + _ -> + false + end + end, {result, Allowed}. create_node(Host, Node, Owner) -> diff --git a/src/mod_pubsub/nodetree_default.erl b/src/mod_pubsub/nodetree_default.erl index 6dec6c5e4..700397edb 100644 --- a/src/mod_pubsub/nodetree_default.erl +++ b/src/mod_pubsub/nodetree_default.erl @@ -10,13 +10,13 @@ %%% the License for the specific language governing rights and limitations %%% under the License. %%% -%%% The Initial Developer of the Original Code is Process-one. -%%% Portions created by Process-one are Copyright 2006-2008, Process-one +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, Process-one. +%%% This software is copyright 2006-2008, ProcessOne. %%% %%% -%%% @copyright 2006-2008 Process-one +%%% @copyright 2006-2008 ProcessOne %%% @author Christophe Romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} @@ -70,8 +70,7 @@ init(_Host, _ServerHost, _Opts) -> mnesia:create_table(pubsub_node, [{disc_copies, [node()]}, - {attributes, record_info(fields, pubsub_node)}, - {index, [type,parentid]}]), + {attributes, record_info(fields, pubsub_node)}]), NodesFields = record_info(fields, pubsub_node), case mnesia:table_info(pubsub_node, attributes) of [host_node, host_parent, info] -> ok; % old schema, updated later by pubsub @@ -115,7 +114,7 @@ get_nodes(Key) -> %% Node = mod_pubsub:pubsubNode() %% From = mod_pubsub:jid() get_subnodes(Host, Node, _From) -> - mnesia:index_read(pubsub_node, {Host, Node}, #pubsub_node.parentid). + mnesia:match_object(#pubsub_node{parentid = {Host, Node}, _ = '_'}). %% @spec (Host, Index) -> [pubsubNode()] | {error, Reason} %% Host = mod_pubsub:host() diff --git a/src/mod_pubsub/nodetree_virtual.erl b/src/mod_pubsub/nodetree_virtual.erl index 5ce256140..7b057a0fd 100644 --- a/src/mod_pubsub/nodetree_virtual.erl +++ b/src/mod_pubsub/nodetree_virtual.erl @@ -10,13 +10,13 @@ %%% the License for the specific language governing rights and limitations %%% under the License. %%% -%%% The Initial Developer of the Original Code is Process-one. -%%% Portions created by Process-one are Copyright 2006-2008, Process-one +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, Process-one. +%%% This software is copyright 2006-2008, ProcessOne. %%% %%% -%%% @copyright 2006-2008 Process-one +%%% @copyright 2006-2008 ProcessOne %%% @author Christophe Romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/pubsub.hrl b/src/mod_pubsub/pubsub.hrl index 25f60c36d..f763909a7 100644 --- a/src/mod_pubsub/pubsub.hrl +++ b/src/mod_pubsub/pubsub.hrl @@ -10,13 +10,13 @@ %%% the License for the specific language governing rights and limitations %%% under the License. %%% -%%% The Initial Developer of the Original Code is Process-one. -%%% Portions created by Process-one are Copyright 2006-2008, Process-one +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, Process-one. +%%% This software is copyright 2006-2008, ProcessOne. %%% %%% -%%% copyright 2006-2008 Process-one +%%% copyright 2006-2008 ProcessOne %%% %%% This file contains pubsub types definition. %%% ==================================================================== diff --git a/src/mod_register.erl b/src/mod_register.erl index a936ea5e1..7a4eca79f 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -5,7 +5,7 @@ %%% Created : 8 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -163,11 +163,10 @@ process_iq(From, To, Password = xml:get_tag_cdata(PTag), case From of #jid{user = User, lserver = Server} -> - ejabberd_auth:set_password(User, Server, Password), - IQ#iq{type = result, sub_el = [SubEl]}; + try_set_password(User, Server, Password, IQ, SubEl); _ -> case try_register(User, Server, Password, - Source) of + Source, Lang) of ok -> IQ#iq{type = result, sub_el = [SubEl]}; {error, Error} -> @@ -194,8 +193,22 @@ process_iq(From, To, {xmlelement, "password", [], []}]}]} end. +%% @doc Try to change password and return IQ response +try_set_password(User, Server, Password, IQ, SubEl) -> + case ejabberd_auth:set_password(User, Server, Password) of + ok -> + IQ#iq{type = result, sub_el = [SubEl]}; + {error, empty_password} -> + IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]}; + {error, not_allowed} -> + IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + {error, invalid_jid} -> + IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]}; + _ -> + IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]} + end. -try_register(User, Server, Password, Source) -> +try_register(User, Server, Password, Source, Lang) -> case jlib:is_nodename(User) of false -> {error, ?ERR_BAD_REQUEST}; @@ -229,7 +242,9 @@ try_register(User, Server, Password, Source) -> end end; false -> - {error, ?ERR_RESOURCE_CONSTRAINT} + ErrText = "Users are not allowed to register " + "accounts so fast", + {error, ?ERRT_RESOURCE_CONSTRAINT(Lang, ErrText)} end end end. diff --git a/src/mod_roster.erl b/src/mod_roster.erl index fe2c740fe..fb9ba3cbd 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -5,7 +5,7 @@ %%% Created : 11 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_roster.hrl b/src/mod_roster.hrl index 380a4e246..617e17df4 100644 --- a/src/mod_roster.hrl +++ b/src/mod_roster.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index d38121560..94b45ead8 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -5,7 +5,7 @@ %%% Created : 15 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_service_log.erl b/src/mod_service_log.erl index 29c312276..4dd967fbb 100644 --- a/src/mod_service_log.erl +++ b/src/mod_service_log.erl @@ -5,7 +5,7 @@ %%% Created : 24 Aug 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index ff378010d..c24ffb6cf 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -5,7 +5,7 @@ %%% Created : 5 Mar 2005 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_stats.erl b/src/mod_stats.erl index 9d6c2ee4d..234c7106e 100644 --- a/src/mod_stats.erl +++ b/src/mod_stats.erl @@ -5,7 +5,7 @@ %%% Created : 11 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_time.erl b/src/mod_time.erl index 6d9b65295..0bc72e599 100644 --- a/src/mod_time.erl +++ b/src/mod_time.erl @@ -5,7 +5,7 @@ %%% Created : 18 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index 69fbcae7f..c81b016f0 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -5,7 +5,7 @@ %%% Created : 2 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index 2b5e7faac..4c0ca6177 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -5,7 +5,7 @@ %%% Created : 2 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl index 9345c016f..7c3d78dab 100644 --- a/src/mod_vcard_odbc.erl +++ b/src/mod_vcard_odbc.erl @@ -5,7 +5,7 @@ %%% Created : 2 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -162,7 +162,7 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> end; {selected, ["vcard"], []} -> IQ#iq{type = result, sub_el = []}; - {'EXIT', _Reason} -> + _ -> IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]} end diff --git a/src/mod_version.erl b/src/mod_version.erl index 5822516d4..26a960dca 100644 --- a/src/mod_version.erl +++ b/src/mod_version.erl @@ -5,7 +5,7 @@ %%% Created : 18 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/msgs/ca.msg b/src/msgs/ca.msg index 0445e3a28..b4abbcb44 100644 --- a/src/msgs/ca.msg +++ b/src/msgs/ca.msg @@ -1,384 +1,343 @@ -% $Id$ -% Language: Catalan (català) -% Author: Vicent Alberola Canet - -% jlib.hrl -{"No resource provided", "Recurs no disponible"}. - -% mod_configure.erl -{"Restart Service", "Reiniciar el Servei"}. -{"Shut Down Service", "Apager el Servei"}. -{"Delete User", "Eliminar Usuari"}. -{"End User Session", "Finalitzar Sesió d'Usuari"}. -{"Get User Password", "Obtenir Password d'usuari"}. -{"Change User Password", "Canviar Password d'Usuari"}. -{"Get User Last Login Time", "Obtenir la última connexió d'Usuari"}. -{"Get User Statistics", "Obtenir Estadístiques d'Usuari"}. -{"Get Number of Registered Users", "Obtenir Número d'Usuaris Registrats"}. -{"Get Number of Online Users", "Obtenir Número d'Usuaris Connectats"}. -{"User Management", "Gestió d'Usuaris"}. -{"Time delay", "Temps de retràs"}. -{"Password Verification", "Verificació del Password"}. -{"Number of registered users", "Número d'Usuaris Registrats"}. -{"Number of online users", "Número d'usuaris connectats"}. -{"Last login", "Últim login"}. -{"Roster size", "Tamany de la llista"}. -{"IP addresses", "Adreça IP"}. -{"Resources", "Recursos"}. -{"Choose storage type of tables", "Selecciona el tipus d'almacenament de les taules"}. -{"RAM copy", "Còpia en RAM"}. -{"RAM and disc copy", "Còpia en RAM i disc"}. -{"Disc only copy", "Còpia sols en disc"}. -{"Remote copy", "Còpia remota"}. -{"Stop Modules at ", "Detindre mòduls en "}. -{"Choose modules to stop", "Selecciona mòduls a detindre"}. -{"Start Modules at ", "Iniciar mòduls en "}. -{"Enter list of {Module, [Options]}", "Introdueix llista de {mòdul, [opcions]}"}. -{"List of modules to start", "Llista de mòduls a iniciar"}. -{"Backup to File at ", "Desar còpia de seguretat a fitxer en "}. -{"Enter path to backup file", "Introdueix ruta al fitxer de còpia de seguretat"}. -{"Path to File", "Ruta al fitxer"}. -{"Restore Backup from File at ", "Restaura còpia de seguretat des del fitxer en "}. -{"Dump Backup to Text File at ", "Exporta còpia de seguretat a fitxer de text en "}. -{"Enter path to text file", "Introdueix ruta al fitxer de text"}. -{"Import User from File at ", "Importa usuari des de fitxer en "}. -{"Enter path to jabberd1.4 spool file", "Introdueix ruta al fitxer jabberd1.4 spool"}. -{"Import Users from Dir at ", "Importar usuaris des del directori en "}. -{"Enter path to jabberd1.4 spool dir", "Introdueix la ruta al directori de jabberd1.4 spools"}. -{"Path to Dir", "Ruta al directori"}. -{"Access Control List Configuration", "Configuració de la Llista de Control d'Accés"}. -{"Access control lists", "Llistes de Control de Accés"}. -{"Access Configuration", "Configuració d'accesos"}. -{"Access rules", "Regles d'accés"}. -{"Administration of ", "Administració de "}. -{"Action on user", "Acció en l'usuari"}. -{"Edit Properties", "Editar propietats"}. -{"Remove User", "Eliminar usuari"}. -{"Database", "Base de dades"}. -{"Outgoing s2s Connections", "Connexions s2s d'eixida"}. -{"Import Users From jabberd 1.4 Spool Files", "Importar usuaris de jabberd 1.4"}. -{"Database Tables Configuration at ", "Configuració de la base de dades en "}. - -% mod_disco.erl -{"Configuration", "Configuració"}. -{"Online Users", "Usuaris conectats"}. -{"All Users", "Tots els usuaris"}. -{"To ~s", "A ~s"}. -{"From ~s", "De ~s"}. -{"Running Nodes", "Nodes funcionant"}. -{"Stopped Nodes", "Nodes parats"}. -{"Access Control Lists", "Llista de Control d'Accés"}. -{"Access Rules", "Regles d'Accés"}. -{"Modules", "Mòduls"}. -{"Start Modules", "Iniciar mòduls"}. -{"Stop Modules", "Parar mòduls"}. -{"Backup Management", "Gestió de còpia de seguretat"}. -{"Backup", "Guardar còpia de seguretat"}. -{"Restore", "Restaurar"}. -{"Dump to Text File", "Exportar a fitxer de text"}. -{"Import File", "Importar fitxer"}. -{"Import Directory", "Importar directori"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Tria nom d'usuari i password per a registrar-te en aquest servidor"}. - -% mod_vcard.erl -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Emplena el formulari per a buscar usuaris Jabber. Afegix * al final d'un camp per a buscar subcadenes."}. -{"You need an x:data capable client to search", "Necesites un client amb suport x:data per a poder buscar"}. -{"Search users in ", "Cerca usuaris en "}. - -{"User", "Usuari"}. -{"Full Name", "Nom complet"}. -{"Name", "Nom"}. -{"Middle Name", "Segon nom"}. -{"Family Name", "Cognom"}. -{"Nickname", "Nickname"}. -{"Birthday", "Aniversari"}. -{"Country", "Pais"}. -{"City", "Ciutat"}. -{"Organization Name", "Nom de la organizació"}. -{"Organization Unit", "Unitat de la organizació"}. - -% mod_pubsub/mod_pubsub.erl -{"Roster groups allowed to subscribe", "Llista de grups que tenen permés subscriures"}. -{"ejabberd Publish-Subscribe module", "Mòdul ejannerd Publicar-Subscriure"}. -{"PubSub subscriber request", "Petició de PubSub subscriure"}. -{"Choose whether to approve this entity's subscription.", "Tria si aprova aquesta entitat de subscripció"}. -{"Node ID", "ID del Node"}. -{"Subscriber Address", "Adreça del Subscriptor"}. -{"Allow this JID to subscribe to this pubsub node?", "Deixar que aquesta JID es puga subscriure a aquest node pubsub"}. -{"Deliver event notifications", "Entrega de notificacions d'events"}. -{"Specify the access model", "Especificar el model d'accés"}. -{"When to send the last published item", "Quan s'ha enviat l'última publicació"}. -{"Deliver payloads with event notifications", "Enviar payloads junt a les notificacions d'events"}. -{"Notify subscribers when the node configuration changes", "Notificar subscriptors quan canvia la configuració del node"}. -{"Notify subscribers when the node is deleted", "Notificar subscriptors quan el node és eliminat"}. -{"Notify subscribers when items are removed from the node", "Notificar subscriptors quan els elements són eliminats del node"}. -{"Persist items to storage", "Persistir elements al guardar"}. -{"Max # of items to persist", "Màxim # d'elements que persistixen"}. -{"Whether to allow subscriptions", "Permetre subscripcions"}. -{"Specify the publisher model", "Especificar el model del publicant"}. -{"Max payload size in bytes", "Màxim tamany del payload en bytes"}. -{"Only deliver notifications to available users", "Sols enviar notificacions als usuaris disponibles"}. -{"Publish-Subscribe", "Publicar-subscriure't"}. - -% mod_muc/mod_muc.erl -{"You need an x:data capable client to register nickname", "Necessites un client amb suport x:data per a poder registrar el Nickname"}. -{"Nickname Registration at ", "Registre del Nickname en "}. -{"Enter nickname you want to register", "Introdueix el nickname que vols registrar"}. -{"Only service administrators are allowed to send service messages", "Sols els administradors del servei tenen permís per a enviar missatges de servei"}. -{"Conference room does not exist", "La sala de conferències no existeix"}. -{"Access denied by service policy", "Accés denegat per la política del servei"}. -{"Specified nickname is already registered", "El Nickname especificat ja està registrat, busca-te'n un altre"}. -{"Room creation is denied by service policy", "Se t'ha denegat el crear la sala per política del servei"}. -{"Chatrooms", "Sales de xat"}. -{"You must fill in field \"Nickname\" in the form", "Deus d'omplir el camp \"Nickname\" al formulari"}. -{"ejabberd MUC module", "mòdul ejabberd MUC"}. - -% mod_muc/mod_muc_room.erl -{"This participant is kicked from the room because he sent an error message", "Aquest participant ha sigut expulsat de la sala perque ha enviat un missatge d'error"}. -{"This participant is kicked from the room because he sent an error message to another participant", "Aquest participant ha sigut expulsat de la sala perque ha enviat un missatge erroni a un altre participant"}. -{"This participant is kicked from the room because he sent an error presence", "Aquest participant ha sigut expulsat de la sala perque ha enviat un error de presencia"}. -{"Make room moderated", "Crear una sala moderada"}. -{"Traffic rate limit is exceeded", "El llímit de tràfic ha sigut sobrepassat"}. -{"Maximum Number of Occupants", "Número màxim d'ocupants"}. -{"No limit", "Sense Llímit"}. -{"~s invites you to the room ~s", "~s et convida a la sala ~s"}. -{"the password is", "el password és"}. -{" has set the subject to: ", " ha posat l'assumpte: "}. -{"You need an x:data capable client to configure room", "Necessites un client amb suport x:data per a configurar la sala"}. -{"Configuration for ", "Configuració per a "}. -{"Room title", "Títol de la sala"}. -{"Password", "Password"}. -{"Only moderators and participants are allowed to change subject in this room", "Sols els moderadors i participants poden canviar l'assumpte d'aquesta sala"}. -{"Only moderators are allowed to change subject in this room", "Sols els moderadors poden canviar l'assumpte d'aquesta sala"}. -{"Visitors are not allowed to send messages to all occupants", "Els visitants no poden enviar missatges a tots els ocupants"}. -{"Only occupants are allowed to send messages to the conference", "Sols els ocupants poden enviar missatges a la sala"}. -{"It is not allowed to send private messages to the conference", "No està permés l'enviament de missatges privats a la sala"}. -{"Improper message type", "Tipus de missatge incorrecte"}. -{"Nickname is already in use by another occupant", "El Nickname està siguent utilitzat per una altra persona"}. -{"Nickname is registered by another person", "El Nickname ja està registrat per una altra persona"}. -{"It is not allowed to send private messages of type \"groupchat\"", "No està permés enviar missatges del tipus \"groupchat\""}. -{"Recipient is not in the conference room", "El receptor no està en la sala de conferència"}. -{"Only occupants are allowed to send queries to the conference", "Sols els ocupants poden enviar solicituts a la sala"}. -{"Queries to the conference members are not allowed in this room", " En aquesta sala no es permeten solicituts als membres de la sala"}. -{"You have been banned from this room", "Has sigut bloquejat en aquesta sala"}. -{"Membership required to enter this room", "Necessites ser membre d'aquesta sala per a poder entrar"}. -{"Password required to enter this room", "Es necessita password per a entrar en aquesta sala"}. -{"Incorrect password", "Password incorrecte"}. -{"Administrator privileges required", "Es necessita tenir privilegis d'administrador"}. -{"Moderator privileges required", "Es necessita tenir privilegis de moderador"}. -{"JID ~s is invalid", "El JID ~s no és vàlid"}. -{"Nickname ~s does not exist in the room", "El Nickname ~s no existeix a la sala"}. -{"Invalid affiliation: ~s", "Afiliació invàlida: ~s"}. -{"Invalid role: ~s", "Rol invàlid: ~s"}. -{"Owner privileges required", "Es requerixen privilegis de propietari de la sala"}. -{"private, ", "privat"}. -{"This room is not anonymous", "Aquesta sala no és anònima"}. -{"Make room persistent", "Crear una sala persistent"}. -{"Make room public searchable", "Crear una sala pública"}. -{"Make participants list public", "Crear una llista de participants pública"}. -{"Make room password protected", "Crear una sala amb password"}. -{"Present real JIDs to", "Presentar JID's reals a"}. -{"moderators only", "sols moderadors"}. -{"anyone", "qualsevol"}. -{"Make room members-only", "Crear una sala de \"soles membres\""}. -{"Default users as participants", "Els usuaris per defecte són els participants"}. -{"Allow users to change subject", "Permetre que els usuaris canvien el tema"}. -{"Allow users to send private messages", "Permetre que els usuaris envien missatges privats"}. -{"Allow users to query other users", "Permetre que els usuaris fagen peticions a altres usuaris"}. -{"Allow users to send invites", "Permetre que els usuaris envien invitacions"}. -{"Enable logging", "Habilitar el registre de la conversa"}. -{"Number of occupants", "Número d'ocupants"}. - -% mod_muc/mod_muc_log.erl -{"has been kicked because of an affiliation change", "Has sigut expulsat a causa d'un canvi d'afiliació"}. -{"has been kicked because the room has been changed to members-only", "Has sigut expulsat perquè la sala ha canviat a sols membres"}. -{"has been kicked because of a system shutdown", "Has sigut expulsat perquè el sistema s'ha apagat"}. -{"Chatroom configuration modified", "Configuració de la sala de xat modificada"}. -{"joins the room", "Entrar a la sala"}. -{"leaves the room", "Deixar la sala"}. -{"has been kicked", "Has sigut expulsat"}. -{"has been banned", "Has sigut banejat"}. -{"is now known as", "ara es conegut com"}. -{"Monday", "Dilluns"}. -{"Tuesday", "Dimarts"}. -{"Wednesday", "Dimecres"}. -{"Thursday", "Dijous"}. -{"Friday", "Divendres"}. -{"Saturday", "Dissabte"}. -{"Sunday", "Diumenge"}. -{"January", "Gener"}. -{"February", "Febrer"}. -{"March", "Març"}. -{"April", "Abril"}. -{"May", "Maig"}. -{"June", "Juny"}. -{"July", "Juliol"}. -{"August", "Agost"}. -{"September", "Setembre"}. -{"October", "Octubre"}. -{"November", "Novembre"}. -{"December", "Decembre"}. -{"Room Configuration", "Configuració de la sala"}. - -% mod_irc/mod_irc.erl -{"You need an x:data capable client to configure mod_irc settings", "Necessites un client amb suport x:data per a configurar les opcions de mod_irc"}. -{"Registration in mod_irc for ", "Registre en mod_irc per a"}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Introdueix el nom d'usuari i les codificacions de caràcters per a utilitzar als servidors de IRC"}. -{"IRC Username", "Nom d'usuari al IRC"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Si vols especificar codificacions de caràcters distints per a cada servidor IRC emplena aquesta llista amb els valors amb el format '{\"servidor irc\", \"codificació\"}'. Aquest servei utilitza per defecte la codificació \"~s\"."}. -{"Encodings", "Codificacions"}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Exemple: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"IRC Transport", "Transport a IRC"}. -{"ejabberd IRC module", "mòdul ejabberd IRC"}. - -% web/ejabberd_web_admin.erl -{"ejabberd Web Admin", "Web d'administració del ejabberd"}. -{"Users", "Usuaris"}. -{"Nodes", "Nodes"}. -{"Statistics", "Estadístiques"}. -{"Delete Selected", "Eliminar els seleccionats"}. -{"Submit", "Enviar"}. -{"~s access rule configuration", "Configuració de les Regles d'Accés ~s"}. -{"Node not found", "Node no trobat"}. -{"Add New", "Afegir nou"}. -{"Change Password", "Canviar password"}. -{"Connected Resources:", "Recursos connectats:"}. -{"Password:", "Password:"}. -{"None", "Cap"}. -{"Node ", "Node "}. -{"Restart", "Reiniciar"}. -{"Stop", "Detindre"}. -{"Name", "Nom"}. -{"Storage Type", "Tipus d'emmagatzematge"}. -{"Size", "Tamany"}. -{"Memory", "Memòria"}. -{"OK", "Acceptar"}. -{"Listened Ports at ", "Ports a la escolta en "}. -{"Port", "Port"}. -{"Module", "Mòdul"}. -{"Options", "Opcions"}. -{"Update", "Actualitzar"}. -{"Delete", "Eliminar"}. -{"Add User", "Afegir usuari"}. -{"Last Activity", "Última activitat"}. -{"Never", "Mai"}. -{"Time", "Data"}. -{"From", "De"}. -{"To", "Per a"}. -{"Packet", "Paquet"}. -{"Roster", "Llista de contactes"}. -{"Nickname", "Nickname"}. -{"Subscription", "Subscripció"}. -{"Pending", "Pendent"}. -{"Groups", "Grups"}. -{"Remove", "Borrar"}. -{"User ", "Usuari "}. -{"Roster of ", "Llista de contactes de "}. -{"Online", "Connectat"}. -{"Validate", "Validar"}. -{"Name:", "Nom:"}. -{"Description:", "Descripció:"}. -{"Members:", "Membre:"}. -{"Displayed Groups:", "Mostrar grups:"}. -{"Group ", "Grup "}. -{"Period: ", "Període: "}. -{"Last month", "Últim mes"}. -{"Last year", "Últim any"}. -{"All activity", "Tota l'activitat"}. -{"Show Ordinary Table", "Mostrar Taula Ordinaria"}. -{"Show Integral Table", "Mostrar Taula Integral"}. -{"Modules at ", "Mòduls en "}. -{"Start", "Iniciar"}. -{"Virtual Hosts", "Hosts Virtuals"}. -{"ejabberd virtual hosts", "Hosts virtuals del ejabberd"}. -{"Host", "Host"}. -{"Administration", "Administració"}. -{"(Raw)", "(en format text)"}. -{"Submitted", "Enviat"}. -{"Bad format", "Format erroni"}. -{"Raw", "en format text"}. -{"Users Last Activity", "Última activitat d'usuari"}. -{"Registered Users", "Usuaris registrats"}. -{"Offline Messages", "Missatges offline"}. -{"Registered Users:", "Usuaris registrats:"}. -{"Online Users:", "Usuaris en línia:"}. -{"Outgoing s2s Connections:", "Connexions d'eixida s2s"}. -{"Outgoing s2s Servers:", "Servidors d'eixida de s2s"}. -{"Offline Messages:", "Missatges fora de línia:"}. -{"~s's Offline Messages Queue", "~s's cua de missatges offline"}. -{"Add Jabber ID", "Afegir Jabber ID"}. -{"No Data", "No hi ha dades"}. -{"Listened Ports", "Ports a l'escolta"}. -{"RPC Call Error", "Error de cridada RPC"}. -{"Database Tables at ", "Taules de la base de dades en "}. -{"Backup of ", "Còpia de seguretat de "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "Recordar que estes opcions sols fan còpia de seguretat de la base de dades Mnesia. Si estàs utilitzant el mòdul d'ODBC també deus de fer una còpia de seguretat de la base de dades de SQL a part."}. -{"Store binary backup:", "Guardar una còpia de seguretat binària:"}. -{"Restore binary backup immediately:", "Restaurar una còpia de seguretat binària ara mateix."}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Restaurar una còpia de seguretat binària després de reiniciar el ejabberd (requereix menys memòria:"}. -{"Store plain text backup:", "Guardar una còpia de seguretat en format de text pla:"}. -{"Restore plain text backup immediately:", "Restaurar una còpia de seguretat en format de text pla ara mateix:"}. -{"Statistics of ~p", "Estadístiques de ~p"}. -{"CPU Time:", "Temps de CPU"}. -{"Transactions Commited:", "Transaccions Realitzades:"}. -{"Transactions Aborted:", "Transaccions Avortades"}. -{"Transactions Restarted:", "Transaccions reiniciades"}. -{"Transactions Logged:", "Transaccions registrades"}. -{"Update ", "Actualitzar"}. -{"Update plan", "Pla d'actualització"}. -{"Updated modules", "Mòduls actualitzats"}. -{"Update script", "Script d'actualització"}. -{"Low level update script", "Script d'actualització de baix nivell"}. -{"Script check", "Comprovar script"}. -{"Shared Roster Groups", "Grups de contactes compartits"}. -{"Uptime:", "Temps en marxa"}. - -% ejabberd_c2s.erl -{"Use of STARTTLS required", "És obligatori utilitzar STARTTLS"}. -{"Replaced by new connection", "Reemplaçat per una nova connexió"}. - -% mod_vcard_ldap.erl -{"Fill in fields to search for any matching Jabber User", "Emplena camps per a buscar usuaris Jabber que concorden"}. - -% mod_vcard_odbc.erl -{"Erlang Jabber Server", "Servidor Erlang Jabber"}. -{"Email", "Email"}. -{"vCard User Search", "Recerca de vCard d'usuari"}. -{"ejabberd vCard module", "Mòdul ejabberd vCard"}. -{"Search Results for ", "Resultat de la búsqueda"}. -{"Jabber ID", "ID Jabber"}. - -% mod_adhoc.erl -{"Commands", "Comandaments"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% mod_announce.erl -{"Send announcement to all users on all hosts", "Enviar anunci a tots els usuaris de tots els hosts"}. -{"Set message of the day on all hosts and send to online users", "Escriure missatge del dia en tots els hosts i envia als usuaris connectats"}. -{"Update message of the day on all hosts (don't send)", "Actualitza el missatge del dia en tots els hosts (no enviar)"}. -{"Delete message of the day on all hosts", "Elimina el missatge del dis de tots els hosts"}. -{"Really delete message of the day?", "Segur que vols eliminar el missatge del dia?"}. -{"Subject", "Assumpte"}. -{"Message body", "Missatge"}. -{"No body provided for announce message", "No hi ha proveedor per al missatge anunci"}. -{"Announcements", "Anuncis"}. -{"Send announcement to all users", "Enviar anunci a tots els usuaris"}. -{"Send announcement to all online users", "Enviar anunci a tots els usuaris connectats"}. -{"Send announcement to all online users on all hosts", "Enviar anunci a tots els usuaris connectats a tots els hosts"}. -{"Set message of the day and send to online users", "Configurar el missatge del dia i enviar a tots els usuaris"}. -{"Update message of the day (don't send)", "Actualitzar el missatge del dia (no enviar)"}. -{"Delete message of the day", "Eliminar el missatge del dia"}. - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "mòdul ejabberd SOCKS5 Bytestreams"}. - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "La cua de missatges offline és plena. El missatge ha sigut descartat"}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Configuració d'accesos"}. +{"Access Control List Configuration","Configuració de la Llista de Control d'Accés"}. +{"Access Control Lists","Llista de Control d'Accés"}. +{"Access control lists","Llistes de Control de Accés"}. +{"Access denied by service policy","Accés denegat per la política del servei"}. +{"Access rules","Regles d'accés"}. +{"Access Rules","Regles d'Accés"}. +{"Action on user","Acció en l'usuari"}. +{"Add Jabber ID","Afegir Jabber ID"}. +{"Add New","Afegir nou"}. +{"Add User","Afegir usuari"}. +{"Administration","Administració"}. +{"Administration of ","Administració de "}. +{"Administrator privileges required","Es necessita tenir privilegis d'administrador"}. +{"A friendly name for the node","Un nom per al node"}. +{"All activity","Tota l'activitat"}. +{"Allow this JID to subscribe to this pubsub node?","Permetre que aquesta JID es puga subscriure a aquest node pubsub"}. +{"Allow users to change subject","Permetre que els usuaris canvien el tema"}. +{"Allow users to query other users","Permetre que els usuaris fagen peticions a altres usuaris"}. +{"Allow users to send invites","Permetre que els usuaris envien invitacions"}. +{"Allow users to send private messages","Permetre que els usuaris envien missatges privats"}. +{"Allow visitors to change nickname","Permetre als visitants canviar el Nickname"}. +{"Allow visitors to send status text in presence updates","Permetre als visitants enviar text d'estat en les actualitzacions de presència"}. +{"All Users","Tots els usuaris"}. +{"Announcements","Anuncis"}. +{"anyone","qualsevol"}. +{"April","Abril"}. +{"August","Agost"}. +{"Backup","Guardar còpia de seguretat"}. +{"Backup Management","Gestió de còpia de seguretat"}. +{"Backup of ","Còpia de seguretat de "}. +{"Backup to File at ","Desar còpia de seguretat a fitxer en "}. +{"Bad format","Format erroni"}. +{"Birthday","Aniversari"}. +{"Change Password","Canviar password"}. +{"Change User Password","Canviar Password d'Usuari"}. +{"Chatroom configuration modified","Configuració de la sala de xat modificada"}. +{"Chatrooms","Sales de xat"}. +{"Choose a username and password to register with this server","Tria nom d'usuari i password per a registrar-te en aquest servidor"}. +{"Choose modules to stop","Selecciona mòduls a detindre"}. +{"Choose storage type of tables","Selecciona el tipus d'almacenament de les taules"}. +{"Choose whether to approve this entity's subscription.","Tria si aprova aquesta entitat de subscripció"}. +{"City","Ciutat"}. +{"Commands","Comandaments"}. +{"Conference room does not exist","La sala de conferències no existeix"}. +{"Configuration","Configuració"}. +{"Configuration for ","Configuració per a "}. +{"Connected Resources:","Recursos connectats:"}. +{"Country","Pais"}. +{"CPU Time:","Temps de CPU"}. +{"Database","Base de dades"}. +{"Database Tables at ","Taules de la base de dades en "}. +{"Database Tables Configuration at ","Configuració de la base de dades en "}. +{"December","Decembre"}. +{"Default users as participants","Els usuaris per defecte són els participants"}. +{"Delete","Eliminar"}. +{"Delete message of the day","Eliminar el missatge del dia"}. +{"Delete message of the day on all hosts","Elimina el missatge del dis de tots els hosts"}. +{"Delete Selected","Eliminar els seleccionats"}. +{"Delete User","Eliminar Usuari"}. +{"Deliver event notifications","Entrega de notificacions d'events"}. +{"Deliver payloads with event notifications","Enviar payloads junt a les notificacions d'events"}. +{"Description:","Descripció:"}. +{"Disc only copy","Còpia sols en disc"}. +{"Displayed Groups:","Mostrar grups:"}. +{"Dump Backup to Text File at ","Exporta còpia de seguretat a fitxer de text en "}. +{"Dump to Text File","Exportar a fitxer de text"}. +{"Edit Properties","Editar propietats"}. +{"ejabberd IRC module","mòdul ejabberd IRC"}. +{"ejabberd MUC module","mòdul ejabberd MUC"}. +{"ejabberd Publish-Subscribe module","Mòdul ejannerd Publicar-Subscriure"}. +{"ejabberd SOCKS5 Bytestreams module","mòdul ejabberd SOCKS5 Bytestreams"}. +{"ejabberd vCard module","Mòdul ejabberd vCard"}. +{"ejabberd virtual hosts","Hosts virtuals del ejabberd"}. +{"ejabberd Web Admin","Web d'administració del ejabberd"}. +{"Email","Email"}. +{"Enable logging","Habilitar el registre de la conversa"}. +{"Encodings","Codificacions"}. +{"End User Session","Finalitzar Sesió d'Usuari"}. +{"Enter list of {Module, [Options]}","Introdueix llista de {mòdul, [opcions]}"}. +{"Enter nickname you want to register","Introdueix el nickname que vols registrar"}. +{"Enter path to backup file","Introdueix ruta al fitxer de còpia de seguretat"}. +{"Enter path to jabberd1.4 spool dir","Introdueix la ruta al directori de jabberd1.4 spools"}. +{"Enter path to jabberd1.4 spool file","Introdueix ruta al fitxer jabberd1.4 spool"}. +{"Enter path to text file","Introdueix ruta al fitxer de text"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Introdueix el nom d'usuari i les codificacions de caràcters per a utilitzar als servidors de IRC"}. +{"Erlang Jabber Server","Servidor Erlang Jabber"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Exemple: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","Cognom"}. +{"February","Febrer"}. +{"Fill in fields to search for any matching Jabber User","Emplena camps per a buscar usuaris Jabber que concorden"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Emplena el formulari per a buscar usuaris Jabber. Afegix * al final d'un camp per a buscar subcadenes."}. +{"Friday","Divendres"}. +{"From","De"}. +{"From ~s","De ~s"}. +{"Full Name","Nom complet"}. +{"Get Number of Online Users","Obtenir Número d'Usuaris Connectats"}. +{"Get Number of Registered Users","Obtenir Número d'Usuaris Registrats"}. +{"Get User Last Login Time","Obtenir la última connexió d'Usuari"}. +{"Get User Password","Obtenir Password d'usuari"}. +{"Get User Statistics","Obtenir Estadístiques d'Usuari"}. +{"Group ","Grup "}. +{"Groups","Grups"}. +{"has been banned","Has sigut banejat"}. +{"has been kicked because of an affiliation change","Has sigut expulsat a causa d'un canvi d'afiliació"}. +{"has been kicked because of a system shutdown","Has sigut expulsat perquè el sistema s'ha apagat"}. +{"has been kicked because the room has been changed to members-only","Has sigut expulsat perquè la sala ha canviat a sols membres"}. +{"has been kicked","Has sigut expulsat"}. +{" has set the subject to: "," ha posat l'assumpte: "}. +{"Host","Host"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Si vols especificar codificacions de caràcters distints per a cada servidor IRC emplena aquesta llista amb els valors amb el format '{\"servidor irc\", \"codificació\"}'. Aquest servei utilitza per defecte la codificació \"~s\"."}. +{"Import Directory","Importar directori"}. +{"Import File","Importar fitxer"}. +{"Import User from File at ","Importa usuari des de fitxer en "}. +{"Import Users from Dir at ","Importar usuaris des del directori en "}. +{"Import Users From jabberd 1.4 Spool Files","Importar usuaris de jabberd 1.4"}. +{"Improper message type","Tipus de missatge incorrecte"}. +{"Incorrect password","Password incorrecte"}. +{"Invalid affiliation: ~s","Afiliació invàlida: ~s"}. +{"Invalid role: ~s","Rol invàlid: ~s"}. +{"IP addresses","Adreça IP"}. +{"IRC Transport","Transport a IRC"}. +{"IRC Username","Nom d'usuari al IRC"}. +{"is now known as","ara es conegut com"}. +{"It is not allowed to send private messages","No està permés enviar missatges privats"}. +{"It is not allowed to send private messages of type \"groupchat\"","No està permés enviar missatges del tipus \"groupchat\""}. +{"It is not allowed to send private messages to the conference","No està permés l'enviament de missatges privats a la sala"}. +{"Jabber ID","ID Jabber"}. +{"January","Gener"}. +{"JID ~s is invalid","El JID ~s no és vàlid"}. +{"joins the room","Entrar a la sala"}. +{"July","Juliol"}. +{"June","Juny"}. +{"Last Activity","Última activitat"}. +{"Last login","Últim login"}. +{"Last month","Últim mes"}. +{"Last year","Últim any"}. +{"leaves the room","Deixar la sala"}. +{"Listened Ports at ","Ports a la escolta en "}. +{"Listened Ports","Ports a l'escolta"}. +{"List of modules to start","Llista de mòduls a iniciar"}. +{"Low level update script","Script d'actualització de baix nivell"}. +{"Make participants list public","Crear una llista de participants pública"}. +{"Make room members-only","Crear una sala de \"soles membres\""}. +{"Make room moderated","Crear una sala moderada"}. +{"Make room password protected","Crear una sala amb password"}. +{"Make room persistent","Crear una sala persistent"}. +{"Make room public searchable","Crear una sala pública"}. +{"March","Març"}. +{"Maximum Number of Occupants","Número màxim d'ocupants"}. +{"Max # of items to persist","Màxim # d'elements que persistixen"}. +{"Max payload size in bytes","Màxim tamany del payload en bytes"}. +{"May","Maig"}. +{"Membership required to enter this room","Necessites ser membre d'aquesta sala per a poder entrar"}. +{"Members:","Membre:"}. +{"Memory","Memòria"}. +{"Message body","Missatge"}. +{"Middle Name","Segon nom"}. +{"Moderator privileges required","Es necessita tenir privilegis de moderador"}. +{"moderators only","sols moderadors"}. +{"Module","Mòdul"}. +{"Modules at ","Mòduls en "}. +{"Modules","Mòduls"}. +{"Monday","Dilluns"}. +{"Name:","Nom:"}. +{"Name","Nom"}. +{"Never","Mai"}. +{"Nickname is already in use by another occupant","El Nickname està siguent utilitzat per una altra persona"}. +{"Nickname is registered by another person","El Nickname ja està registrat per una altra persona"}. +{"Nickname","Nickname"}. +{"Nickname Registration at ","Registre del Nickname en "}. +{"Nickname ~s does not exist in the room","El Nickname ~s no existeix a la sala"}. +{"No body provided for announce message","No hi ha proveedor per al missatge anunci"}. +{"No Data","No hi ha dades"}. +{"Node ID","ID del Node"}. +{"Node ","Node "}. +{"Node not found","Node no trobat"}. +{"Nodes","Nodes"}. +{"No limit","Sense Llímit"}. +{"None","Cap"}. +{"No resource provided","Recurs no disponible"}. +{"Notify subscribers when items are removed from the node","Notificar subscriptors quan els elements són eliminats del node"}. +{"Notify subscribers when the node configuration changes","Notificar subscriptors quan canvia la configuració del node"}. +{"Notify subscribers when the node is deleted","Notificar subscriptors quan el node és eliminat"}. +{"November","Novembre"}. +{"Number of occupants","Número d'ocupants"}. +{"Number of online users","Número d'usuaris connectats"}. +{"Number of registered users","Número d'Usuaris Registrats"}. +{"October","Octubre"}. +{"Offline Messages:","Missatges fora de línia:"}. +{"Offline Messages","Missatges offline"}. +{"OK","Acceptar"}. +{"Online","Connectat"}. +{"Online Users","Usuaris conectats"}. +{"Online Users:","Usuaris en línia:"}. +{"Only deliver notifications to available users","Sols enviar notificacions als usuaris disponibles"}. +{"Only moderators and participants are allowed to change subject in this room","Sols els moderadors i participants poden canviar l'assumpte d'aquesta sala"}. +{"Only moderators are allowed to change subject in this room","Sols els moderadors poden canviar l'assumpte d'aquesta sala"}. +{"Only occupants are allowed to send messages to the conference","Sols els ocupants poden enviar missatges a la sala"}. +{"Only occupants are allowed to send queries to the conference","Sols els ocupants poden enviar solicituts a la sala"}. +{"Only service administrators are allowed to send service messages","Sols els administradors del servei tenen permís per a enviar missatges de servei"}. +{"Options","Opcions"}. +{"Organization Name","Nom de la organizació"}. +{"Organization Unit","Unitat de la organizació"}. +{"Outgoing s2s Connections:","Connexions d'eixida s2s"}. +{"Outgoing s2s Connections","Connexions s2s d'eixida"}. +{"Outgoing s2s Servers:","Servidors d'eixida de s2s"}. +{"Owner privileges required","Es requerixen privilegis de propietari de la sala"}. +{"Packet","Paquet"}. +{"Password:","Password:"}. +{"Password","Password"}. +{"Password required to enter this room","Es necessita password per a entrar en aquesta sala"}. +{"Password Verification","Verificació del Password"}. +{"Path to Dir","Ruta al directori"}. +{"Path to File","Ruta al fitxer"}. +{"Pending","Pendent"}. +{"Period: ","Període: "}. +{"Persist items to storage","Persistir elements al guardar"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","Port"}. +{"Present real JIDs to","Presentar JID's reals a"}. +{"private, ","privat"}. +{"Publish-Subscribe","Publicar-subscriure't"}. +{"PubSub subscriber request","Petició de PubSub subscriure"}. +{"Queries to the conference members are not allowed in this room"," En aquesta sala no es permeten solicituts als membres de la sala"}. +{"RAM and disc copy","Còpia en RAM i disc"}. +{"RAM copy","Còpia en RAM"}. +{"(Raw)","(en format text)"}. +{"Raw","en format text"}. +{"Really delete message of the day?","Segur que vols eliminar el missatge del dia?"}. +{"Recipient is not in the conference room","El receptor no està en la sala de conferència"}. +{"Registered Users:","Usuaris registrats:"}. +{"Registered Users","Usuaris registrats"}. +{"Registration in mod_irc for ","Registre en mod_irc per a"}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Recordar que estes opcions sols fan còpia de seguretat de la base de dades Mnesia. Si estàs utilitzant el mòdul d'ODBC també deus de fer una còpia de seguretat de la base de dades de SQL a part."}. +{"Remote copy","Còpia remota"}. +{"Remove","Borrar"}. +{"Remove User","Eliminar usuari"}. +{"Replaced by new connection","Reemplaçat per una nova connexió"}. +{"Resources","Recursos"}. +{"Restart","Reiniciar"}. +{"Restart Service","Reiniciar el Servei"}. +{"Restore Backup from File at ","Restaura còpia de seguretat des del fitxer en "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Restaurar una còpia de seguretat binària després de reiniciar el ejabberd (requereix menys memòria:"}. +{"Restore binary backup immediately:","Restaurar una còpia de seguretat binària ara mateix."}. +{"Restore plain text backup immediately:","Restaurar una còpia de seguretat en format de text pla ara mateix:"}. +{"Restore","Restaurar"}. +{"Room Configuration","Configuració de la sala"}. +{"Room creation is denied by service policy","Se t'ha denegat el crear la sala per política del servei"}. +{"Room title","Títol de la sala"}. +{"Roster groups allowed to subscribe","Llista de grups que tenen permés subscriures"}. +{"Roster","Llista de contactes"}. +{"Roster of ","Llista de contactes de "}. +{"Roster size","Tamany de la llista"}. +{"RPC Call Error","Error de cridada RPC"}. +{"Running Nodes","Nodes funcionant"}. +{"~s access rule configuration","Configuració de les Regles d'Accés ~s"}. +{"Saturday","Dissabte"}. +{"Script check","Comprovar script"}. +{"Search Results for ","Resultat de la búsqueda"}. +{"Search users in ","Cerca usuaris en "}. +{"Send announcement to all online users","Enviar anunci a tots els usuaris connectats"}. +{"Send announcement to all online users on all hosts","Enviar anunci a tots els usuaris connectats a tots els hosts"}. +{"Send announcement to all users","Enviar anunci a tots els usuaris"}. +{"Send announcement to all users on all hosts","Enviar anunci a tots els usuaris de tots els hosts"}. +{"September","Setembre"}. +{"Set message of the day and send to online users","Configurar el missatge del dia i enviar a tots els usuaris"}. +{"Set message of the day on all hosts and send to online users","Escriure missatge del dia en tots els hosts i envia als usuaris connectats"}. +{"Shared Roster Groups","Grups de contactes compartits"}. +{"Show Integral Table","Mostrar Taula Integral"}. +{"Show Ordinary Table","Mostrar Taula Ordinaria"}. +{"Shut Down Service","Apager el Servei"}. +{"~s invites you to the room ~s","~s et convida a la sala ~s"}. +{"Size","Tamany"}. +{"Specified nickname is already registered","El Nickname especificat ja està registrat, busca-te'n un altre"}. +{"Specify the access model","Especificar el model d'accés"}. +{"Specify the publisher model","Especificar el model del publicant"}. +{"~s's Offline Messages Queue","~s's cua de missatges offline"}. +{"Start","Iniciar"}. +{"Start Modules at ","Iniciar mòduls en "}. +{"Start Modules","Iniciar mòduls"}. +{"Statistics","Estadístiques"}. +{"Statistics of ~p","Estadístiques de ~p"}. +{"Stop","Detindre"}. +{"Stop Modules at ","Detindre mòduls en "}. +{"Stop Modules","Parar mòduls"}. +{"Stopped Nodes","Nodes parats"}. +{"Storage Type","Tipus d'emmagatzematge"}. +{"Store binary backup:","Guardar una còpia de seguretat binària:"}. +{"Store plain text backup:","Guardar una còpia de seguretat en format de text pla:"}. +{"Subject","Assumpte"}. +{"Submit","Enviar"}. +{"Submitted","Enviat"}. +{"Subscriber Address","Adreça del Subscriptor"}. +{"Subscription","Subscripció"}. +{"Sunday","Diumenge"}. +{"the password is","el password és"}. +{"This participant is kicked from the room because he sent an error message","Aquest participant ha sigut expulsat de la sala perque ha enviat un missatge d'error"}. +{"This participant is kicked from the room because he sent an error message to another participant","Aquest participant ha sigut expulsat de la sala perque ha enviat un missatge erroni a un altre participant"}. +{"This participant is kicked from the room because he sent an error presence","Aquest participant ha sigut expulsat de la sala perque ha enviat un error de presencia"}. +{"This room is not anonymous","Aquesta sala no és anònima"}. +{"Thursday","Dijous"}. +{"Time","Data"}. +{"Time delay","Temps de retràs"}. +{"To","Per a"}. +{"To ~s","A ~s"}. +{"Traffic rate limit is exceeded","El llímit de tràfic ha sigut sobrepassat"}. +{"Transactions Aborted:","Transaccions Avortades"}. +{"Transactions Commited:","Transaccions Realitzades:"}. +{"Transactions Logged:","Transaccions registrades"}. +{"Transactions Restarted:","Transaccions reiniciades"}. +{"Tuesday","Dimarts"}. +{"Update ","Actualitzar"}. +{"Update","Actualitzar"}. +{"Updated modules","Mòduls actualitzats"}. +{"Update message of the day (don't send)","Actualitzar el missatge del dia (no enviar)"}. +{"Update message of the day on all hosts (don't send)","Actualitza el missatge del dia en tots els hosts (no enviar)"}. +{"Update plan","Pla d'actualització"}. +{"Update script","Script d'actualització"}. +{"Uptime:","Temps en marxa"}. +{"Use of STARTTLS required","És obligatori utilitzar STARTTLS"}. +{"User Management","Gestió d'Usuaris"}. +{"Users are not allowed to register accounts so fast","Els usuarios no tenen permis per a crear comptes tan apresa"}. +{"Users Last Activity","Última activitat d'usuari"}. +{"Users","Usuaris"}. +{"User ","Usuari "}. +{"User","Usuari"}. +{"Validate","Validar"}. +{"vCard User Search","Recerca de vCard d'usuari"}. +{"Virtual Hosts","Hosts Virtuals"}. +{"Visitors are not allowed to change their nicknames in this room","Els visitants no tenen permés canviar el seus Nicknames en esta sala"}. +{"Visitors are not allowed to send messages to all occupants","Els visitants no poden enviar missatges a tots els ocupants"}. +{"Wednesday","Dimecres"}. +{"When to send the last published item","Quan s'ha enviat l'última publicació"}. +{"Whether to allow subscriptions","Permetre subscripcions"}. +{"You have been banned from this room","Has sigut bloquejat en aquesta sala"}. +{"You must fill in field \"Nickname\" in the form","Deus d'omplir el camp \"Nickname\" al formulari"}. +{"You need an x:data capable client to configure mod_irc settings","Necessites un client amb suport x:data per a configurar les opcions de mod_irc"}. +{"You need an x:data capable client to configure room","Necessites un client amb suport x:data per a configurar la sala"}. +{"You need an x:data capable client to register nickname","Necessites un client amb suport x:data per a poder registrar el Nickname"}. +{"You need an x:data capable client to search","Necesites un client amb suport x:data per a poder buscar"}. +{"Your contact offline message queue is full. The message has been discarded.","La cua de missatges offline és plena. El missatge ha sigut descartat"}. diff --git a/src/msgs/ca.po b/src/msgs/ca.po new file mode 100644 index 000000000..63393dd2d --- /dev/null +++ b/src/msgs/ca.po @@ -0,0 +1,1497 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Vicent Alberola Canet\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Catalan (català)\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "És obligatori utilitzar STARTTLS" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Recurs no disponible" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Reemplaçat per una nova connexió" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Comandaments" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Segur que vols eliminar el missatge del dia?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Assumpte" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Missatge" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "No hi ha proveedor per al missatge anunci" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Anuncis" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Enviar anunci a tots els usuaris" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Enviar anunci a tots els usuaris de tots els hosts" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Enviar anunci a tots els usuaris connectats" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "Enviar anunci a tots els usuaris connectats a tots els hosts" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Configurar el missatge del dia i enviar a tots els usuaris" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Escriure missatge del dia en tots els hosts i envia als usuaris connectats" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Actualitzar el missatge del dia (no enviar)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Actualitza el missatge del dia en tots els hosts (no enviar)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Eliminar el missatge del dia" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Elimina el missatge del dis de tots els hosts" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Configuració" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Base de dades" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Iniciar mòduls" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Parar mòduls" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Guardar còpia de seguretat" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Restaurar" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Exportar a fitxer de text" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Importar fitxer" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Importar directori" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Reiniciar el Servei" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Apager el Servei" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Afegir usuari" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Eliminar Usuari" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Finalitzar Sesió d'Usuari" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Obtenir Password d'usuari" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Canviar Password d'Usuari" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Obtenir la última connexió d'Usuari" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Obtenir Estadístiques d'Usuari" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Obtenir Número d'Usuaris Registrats" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Obtenir Número d'Usuaris Connectats" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Llista de Control d'Accés" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Regles d'Accés" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Gestió d'Usuaris" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Usuaris conectats" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Tots els usuaris" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Connexions s2s d'eixida" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Nodes funcionant" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Nodes parats" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Mòduls" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Gestió de còpia de seguretat" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Importar usuaris de jabberd 1.4" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "A ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "De ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Configuració de la base de dades en " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Selecciona el tipus d'almacenament de les taules" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Còpia sols en disc" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "Còpia en RAM i disc" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "Còpia en RAM" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Còpia remota" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Detindre mòduls en " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Selecciona mòduls a detindre" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Iniciar mòduls en " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Introdueix llista de {mòdul, [opcions]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Llista de mòduls a iniciar" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Desar còpia de seguretat a fitxer en " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Introdueix ruta al fitxer de còpia de seguretat" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Ruta al fitxer" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Restaura còpia de seguretat des del fitxer en " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Exporta còpia de seguretat a fitxer de text en " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Introdueix ruta al fitxer de text" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Importa usuari des de fitxer en " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Introdueix ruta al fitxer jabberd1.4 spool" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Importar usuaris des del directori en " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Introdueix la ruta al directori de jabberd1.4 spools" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Ruta al directori" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Temps de retràs" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Configuració de la Llista de Control d'Accés" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Llistes de Control de Accés" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Configuració d'accesos" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Regles d'accés" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "ID Jabber" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Password" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Verificació del Password" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Número d'Usuaris Registrats" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Número d'usuaris connectats" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Mai" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Connectat" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Últim login" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Tamany de la llista" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "Adreça IP" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Recursos" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Administració de " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Acció en l'usuari" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Editar propietats" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Eliminar usuari" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Accés denegat per la política del servei" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "Transport a IRC" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "mòdul ejabberd IRC" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "" +"Necessites un client amb suport x:data per a configurar les opcions de " +"mod_irc" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Registre en mod_irc per a" + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Introdueix el nom d'usuari i les codificacions de caràcters per a utilitzar " +"als servidors de IRC" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "Nom d'usuari al IRC" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Si vols especificar codificacions de caràcters distints per a cada servidor " +"IRC emplena aquesta llista amb els valors amb el format '{\"servidor irc\", " +"\"codificació\"}'. Aquest servei utilitza per defecte la codificació \"~s\"." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Exemple: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Codificacions" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "" +"Sols els administradors del servei tenen permís per a enviar missatges de " +"servei" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "Se t'ha denegat el crear la sala per política del servei" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "La sala de conferències no existeix" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Sales de xat" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "" +"Necessites un client amb suport x:data per a poder registrar el Nickname" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Registre del Nickname en " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Introdueix el nickname que vols registrar" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Nickname" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "El Nickname especificat ja està registrat, busca-te'n un altre" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Deus d'omplir el camp \"Nickname\" al formulari" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "mòdul ejabberd MUC" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Configuració de la sala de xat modificada" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "Entrar a la sala" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "Deixar la sala" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "Has sigut banejat" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "Has sigut expulsat" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "Has sigut expulsat a causa d'un canvi d'afiliació" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "Has sigut expulsat perquè la sala ha canviat a sols membres" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "Has sigut expulsat perquè el sistema s'ha apagat" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "ara es conegut com" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " ha posat l'assumpte: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "Dilluns" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "Dimarts" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "Dimecres" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "Dijous" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "Divendres" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "Dissabte" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "Diumenge" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "Gener" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "Febrer" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "Març" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "Abril" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "Maig" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "Juny" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "Juliol" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "Agost" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "Setembre" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "Octubre" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "Novembre" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "Decembre" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Configuració de la sala" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Títol de la sala" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "El llímit de tràfic ha sigut sobrepassat" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" +"Aquest participant ha sigut expulsat de la sala perque ha enviat un missatge " +"d'error" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "No està permés l'enviament de missatges privats a la sala" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Tipus de missatge incorrecte" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Aquest participant ha sigut expulsat de la sala perque ha enviat un missatge " +"erroni a un altre participant" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "No està permés enviar missatges del tipus \"groupchat\"" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "El receptor no està en la sala de conferència" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Sols els ocupants poden enviar missatges a la sala" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "No està permés enviar missatges privats" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Sols els ocupants poden enviar solicituts a la sala" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr " En aquesta sala no es permeten solicituts als membres de la sala" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "privat" + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "" +"Sols els moderadors i participants poden canviar l'assumpte d'aquesta sala" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Sols els moderadors poden canviar l'assumpte d'aquesta sala" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "Els visitants no poden enviar missatges a tots els ocupants" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" +"Aquest participant ha sigut expulsat de la sala perque ha enviat un error de " +"presencia" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Els visitants no tenen permés canviar el seus Nicknames en esta sala" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "El Nickname està siguent utilitzat per una altra persona" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "El Nickname ja està registrat per una altra persona" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Has sigut bloquejat en aquesta sala" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "Necessites ser membre d'aquesta sala per a poder entrar" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Aquesta sala no és anònima" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Es necessita password per a entrar en aquesta sala" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Password incorrecte" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Es necessita tenir privilegis d'administrador" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Es necessita tenir privilegis de moderador" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "El JID ~s no és vàlid" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "El Nickname ~s no existeix a la sala" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Afiliació invàlida: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Rol invàlid: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Es requerixen privilegis de propietari de la sala" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Configuració per a " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Descripció:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Crear una sala persistent" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Crear una sala pública" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Crear una llista de participants pública" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Crear una sala amb password" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Número màxim d'ocupants" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Sense Llímit" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Presentar JID's reals a" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "sols moderadors" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "qualsevol" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Crear una sala de \"soles membres\"" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Crear una sala moderada" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Els usuaris per defecte són els participants" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Permetre que els usuaris canvien el tema" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Permetre que els usuaris envien missatges privats" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Permetre que els usuaris fagen peticions a altres usuaris" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Permetre que els usuaris envien invitacions" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "" +"Permetre als visitants enviar text d'estat en les actualitzacions de " +"presència" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Permetre als visitants canviar el Nickname" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Habilitar el registre de la conversa" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "Necessites un client amb suport x:data per a configurar la sala" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Número d'ocupants" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s et convida a la sala ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "el password és" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "La cua de missatges offline és plena. El missatge ha sigut descartat" + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "~s's cua de missatges offline" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Enviat" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Data" + +#: mod_offline.erl:507 +msgid "From" +msgstr "De" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Per a" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Paquet" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Eliminar els seleccionats" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Missatges fora de línia:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "mòdul ejabberd SOCKS5 Bytestreams" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Publicar-subscriure't" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "Mòdul ejannerd Publicar-Subscriure" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "Petició de PubSub subscriure" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Tria si aprova aquesta entitat de subscripció" + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "ID del Node" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Adreça del Subscriptor" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Permetre que aquesta JID es puga subscriure a aquest node pubsub" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Enviar payloads junt a les notificacions d'events" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Entrega de notificacions d'events" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Notificar subscriptors quan canvia la configuració del node" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Notificar subscriptors quan el node és eliminat" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Notificar subscriptors quan els elements són eliminats del node" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Persistir elements al guardar" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "Un nom per al node" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Màxim # d'elements que persistixen" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Permetre subscripcions" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Especificar el model d'accés" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Llista de grups que tenen permés subscriures" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Especificar el model del publicant" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Màxim tamany del payload en bytes" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Quan s'ha enviat l'última publicació" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Sols enviar notificacions als usuaris disponibles" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "Tria nom d'usuari i password per a registrar-te en aquest servidor" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "Els usuarios no tenen permis per a crear comptes tan apresa" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Cap" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Subscripció" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Pendent" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Grups" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Validar" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Borrar" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Llista de contactes de " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Format erroni" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Afegir Jabber ID" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Llista de contactes" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Grups de contactes compartits" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Afegir nou" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Nom:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Descripció:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Membre:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Mostrar grups:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Grup " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Enviar" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Servidor Erlang Jabber" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Aniversari" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Ciutat" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "Pais" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "Email" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Cognom" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Emplena el formulari per a buscar usuaris Jabber. Afegix * al final d'un " +"camp per a buscar subcadenes." + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Nom complet" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Segon nom" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Nom" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Nom de la organizació" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Unitat de la organizació" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Cerca usuaris en " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Usuari" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "Necesites un client amb suport x:data per a poder buscar" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "Recerca de vCard d'usuari" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "Mòdul ejabberd vCard" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Resultat de la búsqueda" + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Emplena camps per a buscar usuaris Jabber que concorden" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "Web d'administració del ejabberd" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Administració" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Hosts Virtuals" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Nodes" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Estadístiques" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Usuaris" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Última activitat" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(en format text)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "en format text" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "Configuració de les Regles d'Accés ~s" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "Hosts virtuals del ejabberd" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Última activitat d'usuari" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Període: " + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Últim mes" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Últim any" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Tota l'activitat" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Mostrar Taula Ordinaria" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Mostrar Taula Integral" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Node no trobat" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Host" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Usuaris registrats" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Missatges offline" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Usuaris registrats:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Usuaris en línia:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Connexions d'eixida s2s" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Servidors d'eixida de s2s" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Canviar password" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Usuari " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Recursos connectats:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Password:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "No hi ha dades" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Node " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Ports a l'escolta" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Actualitzar" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Reiniciar" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Detindre" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "Error de cridada RPC" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Taules de la base de dades en " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Tipus d'emmagatzematge" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Tamany" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Memòria" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Còpia de seguretat de " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Recordar que estes opcions sols fan còpia de seguretat de la base de dades " +"Mnesia. Si estàs utilitzant el mòdul d'ODBC també deus de fer una còpia de " +"seguretat de la base de dades de SQL a part." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Guardar una còpia de seguretat binària:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "Acceptar" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Restaurar una còpia de seguretat binària ara mateix." + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"Restaurar una còpia de seguretat binària després de reiniciar el ejabberd " +"(requereix menys memòria:" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Guardar una còpia de seguretat en format de text pla:" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Restaurar una còpia de seguretat en format de text pla ara mateix:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Ports a la escolta en " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Mòduls en " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "Estadístiques de ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Temps en marxa" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "Temps de CPU" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Transaccions Realitzades:" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Transaccions Avortades" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Transaccions reiniciades" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Transaccions registrades" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Actualitzar" + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Pla d'actualització" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Mòduls actualitzats" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Script d'actualització" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Script d'actualització de baix nivell" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Comprovar script" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Port" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Mòdul" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Opcions" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Eliminar" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Iniciar" diff --git a/src/msgs/cs.msg b/src/msgs/cs.msg index 1b166fa7d..2e3be06e4 100644 --- a/src/msgs/cs.msg +++ b/src/msgs/cs.msg @@ -1,404 +1,343 @@ -% $Id$ -% Language: Czech (čeština) -% Author: Lukáš Polívka [spike411] xmpp:spike411@jabber.cz -% Author: Milos Svasek [DuxforD] from openheads.net - -% jlib.hrl -{"No resource provided", "Nebyl poskytnut žádný zdroj"}. - -% mod_configure.erl -{"Choose storage type of tables", "Vyberte typ úložiště pro tabulky"}. -{"RAM copy", "Kopie RAM"}. -{"RAM and disc copy", "Kopie RAM a disku"}. -{"Disc only copy", "Jen kopie disku"}. -{"Remote copy", "Vzdálená kopie"}. -{"Stop Modules at ", "Zastavit moduly na "}. -{"Choose modules to stop", "Vyberte moduly, které mají být zastaveny"}. -{"Start Modules at ", "Spustit moduly na "}. -{"Enter list of {Module, [Options]}", "Vložte seznam modulů {Modul, [Parametry]}"}. -{"List of modules to start", "Seznam modulů, které mají být spuštěné"}. -{"Backup to File at ", "Záloha do souboru na "}. -{"Enter path to backup file", "Zadajte cestu k souboru se zálohou"}. -{"Path to File", "Cesta k souboru"}. -{"Restore Backup from File at ", "Obnovit zálohu ze souboru na "}. -{"Dump Backup to Text File at ", "Uložit zálohu do textového souboru na "}. -{"Enter path to text file", "Zadajte cestu k textovému souboru"}. -{"Import User from File at ", "Importovat uživatele ze souboru na "}. -{"Enter path to jabberd1.4 spool file", "Zadejte cestu k spool souboru jabberd1.4"}. -{"Import Users from Dir at ", "Importovat uživatele z adresáře na "}. -{"Enter path to jabberd1.4 spool dir", "Zadejte cestu k jabberd1.4 spool adresáři"}. -{"Path to Dir", "Cesta k adresáři"}. -{"Access Control List Configuration", "Konfigurace seznamu přístupových práv (ACL)"}. -{"Access control lists", "Seznamy přístupových práv (ACL)"}. -{"Access Configuration", "Konfigurace přístupů"}. -{"Access rules", "Pravidla přístupů"}. -{"Administration of ", "Administrace "}. -{"Action on user", "Akce aplikovaná na uživatele"}. -{"Edit Properties", "Upravit vlastnosti"}. -{"Remove User", "Odstranit uživatele"}. -{"Restart Service", "Restartovat službu"}. -{"Shut Down Service", "Vypnout službu"}. -{"Delete User", "Smazat uživatele"}. -{"End User Session", "Ukončit sezení uživatele"}. -{"Get User Password", "Získat heslo uživatele"}. -{"Change User Password", "Změnit heslo uživatele"}. -{"Get User Last Login Time", "Získat čas podleního přihlášení uživatele"}. -{"Get User Statistics", "Získat statistiky uživatele"}. -{"Get Number of Registered Users", "Získat počet registrovaných uživatelů"}. -{"Get Number of Online Users", "Získat počet online uživatelů"}. -{"User Management", "Správa uživatelů"}. -{"Time delay", "Časový posun"}. -{"Password Verification", "Ověření hesla"}. -{"Number of registered users", "Počet registrovaných uživatelů"}. -{"Number of online users", "Počet online uživatelů"}. -{"Last login", "Poslední přihlášení"}. -{"Roster size", "Velikost seznamu kontaktů"}. -{"IP addresses", "IP adresy"}. -{"Resources", "Zdroje"}. - -% mod_disco.erl -{"Configuration", "Konfigurace"}. -{"Online Users", "Online uživatelé"}. -{"All Users", "Všichni uživatelé"}. -{"To ~s", "Pro ~s"}. -{"From ~s", "Od ~s"}. -{"Running Nodes", "Běžící uzly"}. -{"Stopped Nodes", "Zastavené uzly"}. -{"Access Control Lists", "Seznamy přístupových práv (ACL)"}. -{"Access Rules", "Pravidla přístupů"}. -{"Modules", "Moduly"}. -{"Start Modules", "Spustit moduly"}. -{"Stop Modules", "Zastavit moduly"}. -{"Backup Management", "Správa zálohování"}. -{"Backup", "Zálohovat"}. -{"Restore", "Obnovit"}. -{"Dump to Text File", "Uložit do textového souboru"}. -{"Import File", "Import souboru"}. -{"Import Directory", "Import adresáře"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Zadejte jméno uživatele a heslo pro registraci na tomto serveru"}. - -% mod_vcard.erl -{"You need an x:data capable client to search", "K vyhledávání potřebujete klienta podporujícího x:data"}. -{"Search users in ", "Hledat uživatele v "}. -{"Fill in fields to search for any matching Jabber User", "Vyplňte políčka pro vyhledání uživatele Jabberu"}. - -{"User", "Uživatel: "}. -{"Full Name", "Celé jméno: "}. -{"Name", "Jméno: "}. -{"Middle Name", "Druhé jméno: "}. -{"Family Name", "Příjmení: "}. -{"Nickname", "Přezdívka: "}. -{"Birthday", "Datum narození: "}. -{"Country", "Země: "}. -{"City", "Město: "}. -{"Organization Name", "Název firmy: "}. -{"Organization Unit", "Oddělení: "}. - -% mod_muc/mod_muc.erl -{"You need an x:data capable client to register nickname", "K registraci přezdívky potřebujete klienta podporujícího x:data"}. -{"Nickname Registration at ", "Registrace prezdívky na "}. -{"Enter nickname you want to register", "Zadejte přezdívku, kterou chcete zaregistrovat"}. -{"Only service administrators are allowed to send service messages", "Pouze správci služby mají povolené odesílání servisních zpráv"}. -{"Conference room does not exist", "Konferenční místnost neexistuje"}. -{"Access denied by service policy", "Přístup byl zamítnut nastavením služby"}. -{"Specified nickname is already registered", "Zadaná přezdívka je již zaregistrována"}. - -% mod_muc/mod_muc_room.erl -{"This participant is kicked from the room because he sent an error message", "Tento účastník byl vyhozen, protože odeslal chybovou zprávu"}. -{"This participant is kicked from the room because he sent an error message to another participant", "Tento účastník byl vyhozen, protože odeslal chybovou zprávu jinému účastníkovi"}. -{"This participant is kicked from the room because he sent an error presence", "Tento účastník byl vyhozen, protože odeslal chybový status"}. -{"Make room moderated", "Nastavit místnost jako moderovanou"}. -{" has set the subject to: ", " změnil(a) téma na: "}. -{"You need an x:data capable client to configure room", "Ke konfiguraci místnosti potřebujete klienta podporujícího x:data"}. -{"Configuration for ", "Konfigurace pro "}. -{"Room title", "Název místnosti"}. -{"Password", "Heslo"}. -{"Only moderators and participants are allowed to change subject in this room", "Jen moderátoři a účastníci mají povoleno měnit téma této místnosti"}. -{"Only moderators are allowed to change subject in this room", "Jen moderátoři mají povoleno měnit téma místnosti"}. -{"Visitors are not allowed to send messages to all occupants", "Návštevníci nemají povoleno zasílat zprávy všem přihlášeným do konference"}. -{"Only occupants are allowed to send messages to the conference", "Jen členové mají povolené zasílat správy do konference"}. -{"It is not allowed to send private messages to the conference", "Není povoleno odesílat soukromé zprávy do konference"}. -{"Improper message type", "Nesprávný typ zprávy"}. -{"Nickname is already in use by another occupant", "Přezdívka je již používána jiným členem"}. -{"Nickname is registered by another person", "Přezdívka je zaregistrována jinou osobou"}. -{"It is not allowed to send private messages of type \"groupchat\"", "Není dovoleno odeslání soukromé zprávy typu \"skupinová zpráva\" "}. -{"Recipient is not in the conference room", "Příjemce se nenachází v konferenční místnosti"}. -{"Only occupants are allowed to send queries to the conference", "Jen členové mohou odesílat požadavky (query) do konference"}. -{"Queries to the conference members are not allowed in this room", "Požadavky (queries) na členy konference nejsou v této místnosti povolené"}. -{"You have been banned from this room", "Byl jste vyloučen z této místnosti"}. -{"Membership required to enter this room", "Pro vstup do místnosti musíte být členem"}. -{"Password required to enter this room", "Pro vstup do místnosti musíte zadat heslo"}. -{"Incorrect password", "Nesprávné heslo"}. -{"Administrator privileges required", "Jsou potřebná práva administrátora"}. -{"Moderator privileges required", "Jsou potřebná práva moderátora"}. -{"JID ~s is invalid", "JID ~s je neplatné"}. -{"Nickname ~s does not exist in the room", "Přezdívka ~s v místnosti neexistuje"}. -{"Invalid affiliation: ~s", "Neplatné přiřazení: ~s"}. -{"Invalid role: ~s", "Neplatná role: ~s"}. -{"Owner privileges required", "Jsou vyžadována práva vlastníka"}. -{"private, ", "soukromá, "}. -{"Present real JIDs to", "Odhalovat skutečná Jabber ID"}. -{"moderators only", "moderátorům"}. -{"anyone", "každému"}. -{"Traffic rate limit is exceeded", "Byl překročen limit"}. -{"Maximum Number of Occupants", "Počet účastníků"}. -{"No limit", "Bez limitu"}. -{"~s invites you to the room ~s", "~s vás zve do místnosti ~s"}. -{"the password is", "heslo je"}. - -% mod_irc/mod_irc.erl -{"You need an x:data capable client to configure mod_irc settings", "Pro konfiguraci mod_irc potřebujete klienta podporujícího x:data"}. -{"Registration in mod_irc for ", "Registrace do mod_irc na "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Vložte jméno uživatele a kódování, které chcete používat při připojení na IRC server"}. -{"IRC Username", "IRC přezdívka"}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Příklad: [{\"irc.freenode.net\",\"utf-8\"}, {\"irc.freenode.net\", \"iso8859-2\"}]."}. -{"Encodings", "Kódování"}. -{"IRC Transport", "IRC transport"}. - -% web/ejabberd_web_admin.erl -{"ejabberd Web Admin", "Webová administrace ejabberd"}. -{"Users", "Uživatelé"}. -{"Nodes", "Uzly"}. -{"Statistics", "Statistiky"}. -{"Submitted", "Odeslané"}. -{"CPU Time:", "Čas procesoru"}. -{"Delete Selected", "Smazat vybrané"}. -{"Submit", "Odeslat"}. -{"~s access rule configuration", "~s konfigurace pravidla přístupu"}. -{"Node not found", "Uzel nenalezen"}. -{"Add New", "Přidat nový"}. -{"Change Password", "Změnit heslo"}. -{"Connected Resources:", "Připojené zdroje:"}. -{"Password:", "Heslo:"}. -{"None", "Nic"}. -{"Node ", "Uzel "}. -{"Restart", "Restart"}. -{"Stop", "Stop"}. -{"Name", "Jméno"}. -{"Storage Type", "Typ úložiště"}. -{"Size", "Velikost"}. -{"Memory", "Paměť"}. -{"OK", "OK"}. -{"Listened Ports at ", "Otevřené porty na "}. -{"Port", "Port"}. -{"Module", "Modul"}. -{"Options", "Nastavení"}. -{"Update", "Aktualizovat"}. -{"Delete", "Smazat"}. -{"Add User", "Přidat uživatele"}. -{"Last Activity", "Poslední aktivita"}. -{"Never", "Nikdy"}. -{"Time", "Čas"}. -{"From", "Od"}. -{"To", "Pro"}. -{"Packet", "Paket"}. -{"Roster", "Seznam kontaktů"}. -{"Nickname", "Prezdívka"}. -{"Subscription", "Přihlášení"}. -{"Pending", "Čekající"}. -{"Groups", "Skupiny"}. -{"Remove", "Odstranit"}. -{"User ", "Uživatel "}. -{"Roster of ", "Seznam kontaktů "}. -{"Online", "Online"}. -{"Validate", "Ověřit"}. -{"Name:", "Jméno:"}. -{"Description:", "Popis:"}. -{"Members:", "Členové:"}. -{"Displayed Groups:", "Zobrazené skupiny:"}. -{"Group ", "Skupina "}. -{"Period: ", "Čas:"}. -{"Last month", "Poslední měsíc"}. -{"Last year", "Poslední rok"}. -{"All activity", "Všechny aktivity"}. -{"Show Ordinary Table", "Zobrazit běžnou tabulku"}. -{"Show Integral Table", "Zobrazit kompletní tabulku"}. -{"Start", "Start"}. -{"Modules at ", "Moduly na "}. -{"Virtual Hosts", "Virtuální hostitelé"}. -{"ejabberd virtual hosts", "Virtuální hostitelé ejabberd"}. -{"Host", "Hostitel"}. - -% mod_vcard_odbc.erl -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Pro vyhledání uživatele Jabberu vyplňte formulář (přidejte znak * na konec, pro vyhledání podřetězce)"}. - -% ejabberd_c2s.erl -{"Use of STARTTLS required", "Je vyžadováno STARTTLS."}. -{"Replaced by new connection", "Nahrazeno novým spojením"}. - -% mod_pubsub/mod_pubsub.erl -{"Roster groups allowed to subscribe", "Skupiny kontaktů, které mohou odebírat"}. -{"Deliver payloads with event notifications", "Doručovat náklad s upozorněním na událost"}. -{"Notify subscribers when the node configuration changes", "Upozornit odběratele na změnu nastavení uzlu"}. -{"Notify subscribers when the node is deleted", "Upozornit odběratele na smazání uzlu"}. -{"Notify subscribers when items are removed from the node", "Upozornit odběratele na odstranění položek z uzlu"}. -{"Persist items to storage", "Uložit položky natrvalo do úložiště"}. -{"Max # of items to persist", "Maximální počet položek, které je možné natrvalo uložit"}. -{"Whether to allow subscriptions", "Povolit odebírání"}. -{"Specify the publisher model", "Specifikovat model pro publikování"}. -{"Max payload size in bytes", "Maximální náklad v bajtech"}. -{"Only deliver notifications to available users", "Doručovat upozornění jen právě přihlášeným uživatelům"}. -{"Publish-Subscribe", "Publish-Subscribe"}. -{"ejabberd Publish-Subscribe module", "ejabberd Publish-Subscribe modul"}. -{"PubSub subscriber request", "Žádost odběratele PubSub"}. -{"Choose whether to approve this entity's subscription.", "Zvolte, zda chcete schválit odebírání touto entitou"}. -{"Node ID", "ID uzlu"}. -{"Subscriber Address", "Adresa odběratele"}. -{"Allow this JID to subscribe to this pubsub node?", "Povolit tomuto JID odebírat tento pubsub uzel?"}. -{"Deliver event notifications", "Doručovat upozornění na události"}. -{"Specify the access model", "Uveďte přístupový model"}. -{"When to send the last published item", "Kdy odeslat poslední publikovanou položku"}. - -% mod_irc/mod_irc.erl -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Pokud chcete zadat jiné kódování pro IRC servery, vyplňte seznam s hodnotami ve formátu '{\"irc server\",\"encoding\"}'. Předvolené kódování pro tuto službu je \"~s\"."}. - -% mod_muc/mod_muc.erl -{"Room creation is denied by service policy", "Pravidla služby nepovolují vytvořit místnost"}. - -% mod_vcard_odbc.erl -{"Erlang Jabber Server", "Erlang Jabber Server"}. -{"Email", "E-mail"}. -{"ejabberd vCard module", "ejabberd vCard modul"}. -{"Search Results for ", "Výsledky hledání pro "}. -{"Jabber ID", "Jabber ID"}. - -% mod_adhoc.erl -{"Commands", "Příkazy"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% ejabberd_c2s.erl -{"Replaced by new connection", "Nahrazeno novým spojením"}. - -% mod_announce.erl -{"Really delete message of the day?", "Skutečně smazat zprávu dne?"}. -{"Subject", "Předmět"}. -{"Message body", "Tělo zprávy"}. -{"No body provided for announce message", "Zpráva neobsahuje text"}. -{"Announcements", "Oznámení"}. -{"Send announcement to all users", "Odeslat oznámení všem uživatelům"}. -{"Send announcement to all online users", "Odeslat oznámení všem online uživatelům"}. -{"Send announcement to all online users on all hosts", "Odeslat oznámení všem online uživatelům na všech hostitelích"}. -{"Set message of the day and send to online users", "Nastavit zprávu dne a odeslat ji online uživatelům"}. -{"Update message of the day (don't send)", "Aktualizovat zprávu dne (neodesílat)"}. -{"Delete message of the day", "Smazat zprávu dne"}. -{"Send announcement to all users on all hosts", "Odeslat oznámení všem uživatelům na všech hostitelích"}. -{"Set message of the day on all hosts and send to online users", "Nastavit zprávu dne a odeslat ji online uživatelům"}. -{"Update message of the day on all hosts (don't send)", "Aktualizovat zprávu dne pro všechny hostitele (neodesílat)"}. -{"Delete message of the day on all hosts", "Smazat zprávu dne na všech hostitelích"}. - -% mod_configure.erl -{"Database", "Databáze"}. -{"Outgoing s2s Connections", "Odchozí s2s spojení"}. -{"Import Users From jabberd 1.4 Spool Files", "Importovat uživatele z jabberd 1.4 spool souborů"}. -{"Database Tables Configuration at ", "Konfigurace databázových tabulek "}. - -% web/ejabberd_web_admin.erl -{"Administration", "Administrace"}. -{"(Raw)", "(Zdroj)"}. -{"Bad format", "Nesprávný formát"}. -{"Raw", "Zdroj"}. -{"Users Last Activity", "Poslední aktivita uživatele"}. -{"Registered Users", "Registrovaní uživatelé"}. -{"Offline Messages", "Offline zprávy"}. -{"Registered Users:", "Registrovaní živatelé:"}. -{"Online Users:", "Online uživatelé:"}. -{"Outgoing s2s Connections:", "Odchozí s2s spojení:"}. -{"Outgoing s2s Servers:", "Odchozí s2s servery:"}. -{"Offline Messages:", "Offline zprávy"}. -{"~s's Offline Messages Queue", "Fronta offline zpráv uživatele ~s"}. -{"Add Jabber ID", "Přidat JID"}. -{"No Data", "Žádná data"}. -{"Listened Ports", "Otevřené porty"}. -{"RPC Call Error", "Chyba RPC volání"}. -{"Database Tables at ", "Databázové tabulky na "}. -{"Backup of ", "Záloha na "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "Podotýkáme, že tato nastavení budou zálohována do zabudované databáze Mnesia. Pokud používáte ODBC modul, musíte zálohovat svoji SQL databázi samostatně."}. -{"Store binary backup:", "Uložit binární zálohu:"}. -{"Restore binary backup immediately:", "Okamžitě obnovit binární zálohu:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Obnovit binární zálohu při následujícím restartu ejabberd (vyžaduje méně paměti)"}. -{"Store plain text backup:", "Uložit zálohu do textového souboru:"}. -{"Restore plain text backup immediately:", "Okamžitě obnovit zálohu z textového souboru:"}. -{"Statistics of ~p", "Statistiky ~p"}. -{"Uptime:", "Čas běhu"}. -{"Transactions Commited:", "Transakce potvrzena"}. -{"Transactions Aborted:", "Transakce zrušena"}. -{"Transactions Restarted:", "Transakce restartována"}. -{"Transactions Logged:", "Transakce zaznamenána"}. -{"Update ", "Aktualizovat "}. -{"Update plan", "Aktualizovat plán"}. -{"Updated modules", "Aktualizované moduly"}. -{"Update script", "Aktualizované skripty"}. -{"Low level update script", "Nízkoúrovňový aktualizační skript"}. -{"Script check", "Kontrola skriptu"}. -{"Shared Roster Groups", "Skupiny pro sdílený seznam kontaktů"}. - -% mod_irc/mod_irc.erl -{"ejabberd IRC module", "Ejabberd IRC modul"}. - -% mod_muc/mod_muc_log.erl -{"has been kicked because of an affiliation change", "byl(a) vyhozen(a) kvůli změně přiřazení"}. -{"has been kicked because the room has been changed to members-only", "byl(a) vyhozen(a), protože mísnost je nyní pouze pro členy"}. -{"has been kicked because of a system shutdown", "byl(a) vyhozen(a), protože dojde k vypnutí systému"}. -{"Chatroom configuration modified", "Nastavení diskuzní místnosti bylo změněno"}. -{"joins the room", "vstoupil(a) do místnosti"}. -{"leaves the room", "opustil(a) místnost"}. -{"has been kicked", "byl(a) vyhozen(a) z místnosti"}. -{"has been banned", "byl(a) zablokován(a)"}. -{"is now known as", "se přejmenoval(a) na"}. -{"Monday", "Pondělí"}. -{"Tuesday", "Úterý"}. -{"Wednesday", "Středa"}. -{"Thursday", "Čtvrtek"}. -{"Friday", "Pátek"}. -{"Saturday", "Sobota"}. -{"Sunday", "Neděle"}. -{"January", ". ledna"}. -{"February", ". února"}. -{"March", ". března"}. -{"April", ". dubna"}. -{"May", ". května"}. -{"June", ". června"}. -{"July", ". července"}. -{"August", ". srpna"}. -{"September", ". září"}. -{"October", ". října"}. -{"November", ". listopadu"}. -{"December", ". prosince"}. -{"Room Configuration", "Nastavení místnosti"}. - -% mod_muc/mod_muc.erl -{"You must fill in field \"Nickname\" in the form", "Musíte vyplnit políčko \"Přezdívka\" ve formuláři"}. -{"ejabberd MUC module", "Ejabberd MUC modul"}. -{"Chatrooms", "Konference"}. - -% mod_muc/mod_muc_room.erl -{"This room is not anonymous", "Tato místnost není anonymní"}. -{"Make room persistent", "Nastavit místnost jako stálou"}. -{"Make room public searchable", "Nastavit místnost jako veřejnou"}. -{"Make participants list public", "Nastavit seznam účastníků jako veřejný"}. -{"Make room password protected", "Chránit místnost heslem"}. -{"Make room members-only", "Nastavit místnost jen pro členy"}. -{"Default users as participants", "Uživatelé jsou implicitně členy"}. -{"Allow users to change subject", "Povolit uživatelům měnit téma místnosti"}. -{"Allow users to send private messages", "Povolit uživatelům odesílat soukromé zprávy"}. -{"Allow users to query other users", "Povolit uživatelům odesílat požadavky (query) ostatním uživatelům"}. -{"Allow users to send invites", "Povolit uživatelům posílání pozvánek"}. -{"Enable logging", "Zaznamenávat konverzace"}. -{"Number of occupants", "Počet účastníků"}. - -% mod_vcard_odbc.erl -{"vCard User Search", "Hledání uživatelů podle vizitek"}. - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "Fronta offline zpráv pro váš kontakt je plná. Zpráva byla zahozena."}. - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "ejabberd SOCKS5 Bytestreams modul"}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Konfigurace přístupů"}. +{"Access Control List Configuration","Konfigurace seznamu přístupových práv (ACL)"}. +{"Access control lists","Seznamy přístupových práv (ACL)"}. +{"Access Control Lists","Seznamy přístupových práv (ACL)"}. +{"Access denied by service policy","Přístup byl zamítnut nastavením služby"}. +{"Access rules","Pravidla přístupů"}. +{"Access Rules","Pravidla přístupů"}. +{"Action on user","Akce aplikovaná na uživatele"}. +{"Add Jabber ID","Přidat JID"}. +{"Add New","Přidat nový"}. +{"Add User","Přidat uživatele"}. +{"Administration","Administrace"}. +{"Administration of ","Administrace "}. +{"Administrator privileges required","Jsou potřebná práva administrátora"}. +{"A friendly name for the node","Přívětivé jméno pro uzel"}. +{"All activity","Všechny aktivity"}. +{"Allow this JID to subscribe to this pubsub node?","Povolit tomuto JID odebírat tento pubsub uzel?"}. +{"Allow users to change subject","Povolit uživatelům měnit téma místnosti"}. +{"Allow users to query other users","Povolit uživatelům odesílat požadavky (query) ostatním uživatelům"}. +{"Allow users to send invites","Povolit uživatelům posílání pozvánek"}. +{"Allow users to send private messages","Povolit uživatelům odesílat soukromé zprávy"}. +{"Allow visitors to change nickname","Povolit návštěvníkům měnit přezdívku"}. +{"Allow visitors to send status text in presence updates","Povolit návštěvníkům posílat stavové zprávy ve statusu"}. +{"All Users","Všichni uživatelé"}. +{"Announcements","Oznámení"}. +{"anyone","každému"}. +{"April",". dubna"}. +{"August",". srpna"}. +{"Backup Management","Správa zálohování"}. +{"Backup of ","Záloha na "}. +{"Backup to File at ","Záloha do souboru na "}. +{"Backup","Zálohovat"}. +{"Bad format","Nesprávný formát"}. +{"Birthday","Datum narození: "}. +{"Change Password","Změnit heslo"}. +{"Change User Password","Změnit heslo uživatele"}. +{"Chatroom configuration modified","Nastavení diskuzní místnosti bylo změněno"}. +{"Chatrooms","Konference"}. +{"Choose a username and password to register with this server","Zadejte jméno uživatele a heslo pro registraci na tomto serveru"}. +{"Choose modules to stop","Vyberte moduly, které mají být zastaveny"}. +{"Choose storage type of tables","Vyberte typ úložiště pro tabulky"}. +{"Choose whether to approve this entity's subscription.","Zvolte, zda chcete schválit odebírání touto entitou"}. +{"City","Město: "}. +{"Commands","Příkazy"}. +{"Conference room does not exist","Konferenční místnost neexistuje"}. +{"Configuration for ","Konfigurace pro "}. +{"Configuration","Konfigurace"}. +{"Connected Resources:","Připojené zdroje:"}. +{"Country","Země: "}. +{"CPU Time:","Čas procesoru"}. +{"Database","Databáze"}. +{"Database Tables at ","Databázové tabulky na "}. +{"Database Tables Configuration at ","Konfigurace databázových tabulek "}. +{"December",". prosince"}. +{"Default users as participants","Uživatelé jsou implicitně členy"}. +{"Delete message of the day on all hosts","Smazat zprávu dne na všech hostitelích"}. +{"Delete message of the day","Smazat zprávu dne"}. +{"Delete Selected","Smazat vybrané"}. +{"Delete","Smazat"}. +{"Delete User","Smazat uživatele"}. +{"Deliver event notifications","Doručovat upozornění na události"}. +{"Deliver payloads with event notifications","Doručovat náklad s upozorněním na událost"}. +{"Description:","Popis:"}. +{"Disc only copy","Jen kopie disku"}. +{"Displayed Groups:","Zobrazené skupiny:"}. +{"Dump Backup to Text File at ","Uložit zálohu do textového souboru na "}. +{"Dump to Text File","Uložit do textového souboru"}. +{"Edit Properties","Upravit vlastnosti"}. +{"ejabberd IRC module","Ejabberd IRC modul"}. +{"ejabberd MUC module","Ejabberd MUC modul"}. +{"ejabberd Publish-Subscribe module","ejabberd Publish-Subscribe modul"}. +{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestreams modul"}. +{"ejabberd vCard module","ejabberd vCard modul"}. +{"ejabberd virtual hosts","Virtuální hostitelé ejabberd"}. +{"ejabberd Web Admin","Webová administrace ejabberd"}. +{"Email","E-mail"}. +{"Enable logging","Zaznamenávat konverzace"}. +{"Encodings","Kódování"}. +{"End User Session","Ukončit sezení uživatele"}. +{"Enter list of {Module, [Options]}","Vložte seznam modulů {Modul, [Parametry]}"}. +{"Enter nickname you want to register","Zadejte přezdívku, kterou chcete zaregistrovat"}. +{"Enter path to backup file","Zadajte cestu k souboru se zálohou"}. +{"Enter path to jabberd1.4 spool dir","Zadejte cestu k jabberd1.4 spool adresáři"}. +{"Enter path to jabberd1.4 spool file","Zadejte cestu k spool souboru jabberd1.4"}. +{"Enter path to text file","Zadajte cestu k textovému souboru"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Vložte jméno uživatele a kódování, které chcete používat při připojení na IRC server"}. +{"Erlang Jabber Server","Erlang Jabber Server"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Příklad: [{\"irc.freenode.net\",\"utf-8\"}, {\"irc.freenode.net\", \"iso8859-2\"}]."}. +{"Family Name","Příjmení: "}. +{"February",". února"}. +{"Fill in fields to search for any matching Jabber User","Vyplňte políčka pro vyhledání uživatele Jabberu"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Pro vyhledání uživatele Jabberu vyplňte formulář (přidejte znak * na konec, pro vyhledání podřetězce)"}. +{"Friday","Pátek"}. +{"From","Od"}. +{"From ~s","Od ~s"}. +{"Full Name","Celé jméno: "}. +{"Get Number of Online Users","Získat počet online uživatelů"}. +{"Get Number of Registered Users","Získat počet registrovaných uživatelů"}. +{"Get User Last Login Time","Získat čas podleního přihlášení uživatele"}. +{"Get User Password","Získat heslo uživatele"}. +{"Get User Statistics","Získat statistiky uživatele"}. +{"Group ","Skupina "}. +{"Groups","Skupiny"}. +{"has been banned","byl(a) zablokován(a)"}. +{"has been kicked because of an affiliation change","byl(a) vyhozen(a) kvůli změně přiřazení"}. +{"has been kicked because of a system shutdown","byl(a) vyhozen(a), protože dojde k vypnutí systému"}. +{"has been kicked because the room has been changed to members-only","byl(a) vyhozen(a), protože mísnost je nyní pouze pro členy"}. +{"has been kicked","byl(a) vyhozen(a) z místnosti"}. +{" has set the subject to: "," změnil(a) téma na: "}. +{"Host","Hostitel"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Pokud chcete zadat jiné kódování pro IRC servery, vyplňte seznam s hodnotami ve formátu '{\"irc server\",\"encoding\"}'. Předvolené kódování pro tuto službu je \"~s\"."}. +{"Import Directory","Import adresáře"}. +{"Import File","Import souboru"}. +{"Import User from File at ","Importovat uživatele ze souboru na "}. +{"Import Users from Dir at ","Importovat uživatele z adresáře na "}. +{"Import Users From jabberd 1.4 Spool Files","Importovat uživatele z jabberd 1.4 spool souborů"}. +{"Improper message type","Nesprávný typ zprávy"}. +{"Incorrect password","Nesprávné heslo"}. +{"Invalid affiliation: ~s","Neplatné přiřazení: ~s"}. +{"Invalid role: ~s","Neplatná role: ~s"}. +{"IP addresses","IP adresy"}. +{"IRC Transport","IRC transport"}. +{"IRC Username","IRC přezdívka"}. +{"is now known as","se přejmenoval(a) na"}. +{"It is not allowed to send private messages","Je zakázáno posílat soukromé zprávy"}. +{"It is not allowed to send private messages of type \"groupchat\"","Není dovoleno odeslání soukromé zprávy typu \"skupinová zpráva\" "}. +{"It is not allowed to send private messages to the conference","Není povoleno odesílat soukromé zprávy do konference"}. +{"Jabber ID","Jabber ID"}. +{"January",". ledna"}. +{"JID ~s is invalid","JID ~s je neplatné"}. +{"joins the room","vstoupil(a) do místnosti"}. +{"July",". července"}. +{"June",". června"}. +{"Last Activity","Poslední aktivita"}. +{"Last login","Poslední přihlášení"}. +{"Last month","Poslední měsíc"}. +{"Last year","Poslední rok"}. +{"leaves the room","opustil(a) místnost"}. +{"Listened Ports at ","Otevřené porty na "}. +{"Listened Ports","Otevřené porty"}. +{"List of modules to start","Seznam modulů, které mají být spuštěné"}. +{"Low level update script","Nízkoúrovňový aktualizační skript"}. +{"Make participants list public","Nastavit seznam účastníků jako veřejný"}. +{"Make room members-only","Nastavit místnost jen pro členy"}. +{"Make room moderated","Nastavit místnost jako moderovanou"}. +{"Make room password protected","Chránit místnost heslem"}. +{"Make room persistent","Nastavit místnost jako stálou"}. +{"Make room public searchable","Nastavit místnost jako veřejnou"}. +{"March",". března"}. +{"Maximum Number of Occupants","Počet účastníků"}. +{"Max # of items to persist","Maximální počet položek, které je možné natrvalo uložit"}. +{"Max payload size in bytes","Maximální náklad v bajtech"}. +{"May",". května"}. +{"Members:","Členové:"}. +{"Membership required to enter this room","Pro vstup do místnosti musíte být členem"}. +{"Memory","Paměť"}. +{"Message body","Tělo zprávy"}. +{"Middle Name","Druhé jméno: "}. +{"Moderator privileges required","Jsou potřebná práva moderátora"}. +{"moderators only","moderátorům"}. +{"Module","Modul"}. +{"Modules at ","Moduly na "}. +{"Modules","Moduly"}. +{"Monday","Pondělí"}. +{"Name:","Jméno:"}. +{"Name","Jméno"}. +{"Never","Nikdy"}. +{"Nickname is already in use by another occupant","Přezdívka je již používána jiným členem"}. +{"Nickname is registered by another person","Přezdívka je zaregistrována jinou osobou"}. +{"Nickname","Prezdívka"}. +{"Nickname Registration at ","Registrace prezdívky na "}. +{"Nickname ~s does not exist in the room","Přezdívka ~s v místnosti neexistuje"}. +{"No body provided for announce message","Zpráva neobsahuje text"}. +{"No Data","Žádná data"}. +{"Node ID","ID uzlu"}. +{"Node not found","Uzel nenalezen"}. +{"Nodes","Uzly"}. +{"Node ","Uzel "}. +{"No limit","Bez limitu"}. +{"None","Nic"}. +{"No resource provided","Nebyl poskytnut žádný zdroj"}. +{"Notify subscribers when items are removed from the node","Upozornit odběratele na odstranění položek z uzlu"}. +{"Notify subscribers when the node configuration changes","Upozornit odběratele na změnu nastavení uzlu"}. +{"Notify subscribers when the node is deleted","Upozornit odběratele na smazání uzlu"}. +{"November",". listopadu"}. +{"Number of occupants","Počet účastníků"}. +{"Number of online users","Počet online uživatelů"}. +{"Number of registered users","Počet registrovaných uživatelů"}. +{"October",". října"}. +{"Offline Messages:","Offline zprávy"}. +{"Offline Messages","Offline zprávy"}. +{"OK","OK"}. +{"Online","Online"}. +{"Online Users:","Online uživatelé:"}. +{"Online Users","Online uživatelé"}. +{"Only deliver notifications to available users","Doručovat upozornění jen právě přihlášeným uživatelům"}. +{"Only moderators and participants are allowed to change subject in this room","Jen moderátoři a účastníci mají povoleno měnit téma této místnosti"}. +{"Only moderators are allowed to change subject in this room","Jen moderátoři mají povoleno měnit téma místnosti"}. +{"Only occupants are allowed to send messages to the conference","Jen členové mají povolené zasílat správy do konference"}. +{"Only occupants are allowed to send queries to the conference","Jen členové mohou odesílat požadavky (query) do konference"}. +{"Only service administrators are allowed to send service messages","Pouze správci služby mají povolené odesílání servisních zpráv"}. +{"Options","Nastavení"}. +{"Organization Name","Název firmy: "}. +{"Organization Unit","Oddělení: "}. +{"Outgoing s2s Connections:","Odchozí s2s spojení:"}. +{"Outgoing s2s Connections","Odchozí s2s spojení"}. +{"Outgoing s2s Servers:","Odchozí s2s servery:"}. +{"Owner privileges required","Jsou vyžadována práva vlastníka"}. +{"Packet","Paket"}. +{"Password:","Heslo:"}. +{"Password","Heslo"}. +{"Password required to enter this room","Pro vstup do místnosti musíte zadat heslo"}. +{"Password Verification","Ověření hesla"}. +{"Path to Dir","Cesta k adresáři"}. +{"Path to File","Cesta k souboru"}. +{"Pending","Čekající"}. +{"Period: ","Čas:"}. +{"Persist items to storage","Uložit položky natrvalo do úložiště"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","Port"}. +{"Present real JIDs to","Odhalovat skutečná Jabber ID"}. +{"private, ","soukromá, "}. +{"Publish-Subscribe","Publish-Subscribe"}. +{"PubSub subscriber request","Žádost odběratele PubSub"}. +{"Queries to the conference members are not allowed in this room","Požadavky (queries) na členy konference nejsou v této místnosti povolené"}. +{"RAM and disc copy","Kopie RAM a disku"}. +{"RAM copy","Kopie RAM"}. +{"(Raw)","(Zdroj)"}. +{"Raw","Zdroj"}. +{"Really delete message of the day?","Skutečně smazat zprávu dne?"}. +{"Recipient is not in the conference room","Příjemce se nenachází v konferenční místnosti"}. +{"Registered Users","Registrovaní uživatelé"}. +{"Registered Users:","Registrovaní živatelé:"}. +{"Registration in mod_irc for ","Registrace do mod_irc na "}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Podotýkáme, že tato nastavení budou zálohována do zabudované databáze Mnesia. Pokud používáte ODBC modul, musíte zálohovat svoji SQL databázi samostatně."}. +{"Remote copy","Vzdálená kopie"}. +{"Remove","Odstranit"}. +{"Remove User","Odstranit uživatele"}. +{"Replaced by new connection","Nahrazeno novým spojením"}. +{"Resources","Zdroje"}. +{"Restart","Restart"}. +{"Restart Service","Restartovat službu"}. +{"Restore Backup from File at ","Obnovit zálohu ze souboru na "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Obnovit binární zálohu při následujícím restartu ejabberd (vyžaduje méně paměti)"}. +{"Restore binary backup immediately:","Okamžitě obnovit binární zálohu:"}. +{"Restore","Obnovit"}. +{"Restore plain text backup immediately:","Okamžitě obnovit zálohu z textového souboru:"}. +{"Room Configuration","Nastavení místnosti"}. +{"Room creation is denied by service policy","Pravidla služby nepovolují vytvořit místnost"}. +{"Room title","Název místnosti"}. +{"Roster groups allowed to subscribe","Skupiny kontaktů, které mohou odebírat"}. +{"Roster of ","Seznam kontaktů "}. +{"Roster","Seznam kontaktů"}. +{"Roster size","Velikost seznamu kontaktů"}. +{"RPC Call Error","Chyba RPC volání"}. +{"Running Nodes","Běžící uzly"}. +{"~s access rule configuration","~s konfigurace pravidla přístupu"}. +{"Saturday","Sobota"}. +{"Script check","Kontrola skriptu"}. +{"Search Results for ","Výsledky hledání pro "}. +{"Search users in ","Hledat uživatele v "}. +{"Send announcement to all online users","Odeslat oznámení všem online uživatelům"}. +{"Send announcement to all online users on all hosts","Odeslat oznámení všem online uživatelům na všech hostitelích"}. +{"Send announcement to all users","Odeslat oznámení všem uživatelům"}. +{"Send announcement to all users on all hosts","Odeslat oznámení všem uživatelům na všech hostitelích"}. +{"September",". září"}. +{"Set message of the day and send to online users","Nastavit zprávu dne a odeslat ji online uživatelům"}. +{"Set message of the day on all hosts and send to online users","Nastavit zprávu dne a odeslat ji online uživatelům"}. +{"Shared Roster Groups","Skupiny pro sdílený seznam kontaktů"}. +{"Show Integral Table","Zobrazit kompletní tabulku"}. +{"Show Ordinary Table","Zobrazit běžnou tabulku"}. +{"Shut Down Service","Vypnout službu"}. +{"~s invites you to the room ~s","~s vás zve do místnosti ~s"}. +{"Size","Velikost"}. +{"Specified nickname is already registered","Zadaná přezdívka je již zaregistrována"}. +{"Specify the access model","Uveďte přístupový model"}. +{"Specify the publisher model","Specifikovat model pro publikování"}. +{"~s's Offline Messages Queue","Fronta offline zpráv uživatele ~s"}. +{"Start Modules at ","Spustit moduly na "}. +{"Start Modules","Spustit moduly"}. +{"Start","Start"}. +{"Statistics of ~p","Statistiky ~p"}. +{"Statistics","Statistiky"}. +{"Stop Modules at ","Zastavit moduly na "}. +{"Stop Modules","Zastavit moduly"}. +{"Stopped Nodes","Zastavené uzly"}. +{"Stop","Stop"}. +{"Storage Type","Typ úložiště"}. +{"Store binary backup:","Uložit binární zálohu:"}. +{"Store plain text backup:","Uložit zálohu do textového souboru:"}. +{"Subject","Předmět"}. +{"Submit","Odeslat"}. +{"Submitted","Odeslané"}. +{"Subscriber Address","Adresa odběratele"}. +{"Subscription","Přihlášení"}. +{"Sunday","Neděle"}. +{"the password is","heslo je"}. +{"This participant is kicked from the room because he sent an error message","Tento účastník byl vyhozen, protože odeslal chybovou zprávu"}. +{"This participant is kicked from the room because he sent an error message to another participant","Tento účastník byl vyhozen, protože odeslal chybovou zprávu jinému účastníkovi"}. +{"This participant is kicked from the room because he sent an error presence","Tento účastník byl vyhozen, protože odeslal chybový status"}. +{"This room is not anonymous","Tato místnost není anonymní"}. +{"Thursday","Čtvrtek"}. +{"Time","Čas"}. +{"Time delay","Časový posun"}. +{"To","Pro"}. +{"To ~s","Pro ~s"}. +{"Traffic rate limit is exceeded","Byl překročen limit"}. +{"Transactions Aborted:","Transakce zrušena"}. +{"Transactions Commited:","Transakce potvrzena"}. +{"Transactions Logged:","Transakce zaznamenána"}. +{"Transactions Restarted:","Transakce restartována"}. +{"Tuesday","Úterý"}. +{"Update ","Aktualizovat "}. +{"Update","Aktualizovat"}. +{"Updated modules","Aktualizované moduly"}. +{"Update message of the day (don't send)","Aktualizovat zprávu dne (neodesílat)"}. +{"Update message of the day on all hosts (don't send)","Aktualizovat zprávu dne pro všechny hostitele (neodesílat)"}. +{"Update plan","Aktualizovat plán"}. +{"Update script","Aktualizované skripty"}. +{"Uptime:","Čas běhu"}. +{"Use of STARTTLS required","Je vyžadováno STARTTLS."}. +{"User Management","Správa uživatelů"}. +{"Users are not allowed to register accounts so fast","Je zakázáno registrovat účty v tak rychlém sledu"}. +{"Users Last Activity","Poslední aktivita uživatele"}. +{"Users","Uživatelé"}. +{"User ","Uživatel "}. +{"User","Uživatel: "}. +{"Validate","Ověřit"}. +{"vCard User Search","Hledání uživatelů podle vizitek"}. +{"Virtual Hosts","Virtuální hostitelé"}. +{"Visitors are not allowed to change their nicknames in this room","Návštěvníkům této místnosti je zakázáno měnit přezdívku"}. +{"Visitors are not allowed to send messages to all occupants","Návštevníci nemají povoleno zasílat zprávy všem přihlášeným do konference"}. +{"Wednesday","Středa"}. +{"When to send the last published item","Kdy odeslat poslední publikovanou položku"}. +{"Whether to allow subscriptions","Povolit odebírání"}. +{"You have been banned from this room","Byl jste vyloučen z této místnosti"}. +{"You must fill in field \"Nickname\" in the form","Musíte vyplnit políčko \"Přezdívka\" ve formuláři"}. +{"You need an x:data capable client to configure mod_irc settings","Pro konfiguraci mod_irc potřebujete klienta podporujícího x:data"}. +{"You need an x:data capable client to configure room","Ke konfiguraci místnosti potřebujete klienta podporujícího x:data"}. +{"You need an x:data capable client to register nickname","K registraci přezdívky potřebujete klienta podporujícího x:data"}. +{"You need an x:data capable client to search","K vyhledávání potřebujete klienta podporujícího x:data"}. +{"Your contact offline message queue is full. The message has been discarded.","Fronta offline zpráv pro váš kontakt je plná. Zpráva byla zahozena."}. diff --git a/src/msgs/cs.po b/src/msgs/cs.po new file mode 100644 index 000000000..e02387e6e --- /dev/null +++ b/src/msgs/cs.po @@ -0,0 +1,1487 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Lukáš Polívka [spike411] xmpp:spike411@jabber.cz\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Czech (čeština)\n" +"X-Additional-Translator: Milos Svasek [DuxforD] from openheads.net\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "Je vyžadováno STARTTLS." + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Nebyl poskytnut žádný zdroj" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Nahrazeno novým spojením" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Příkazy" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Skutečně smazat zprávu dne?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Předmět" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Tělo zprávy" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "Zpráva neobsahuje text" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Oznámení" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Odeslat oznámení všem uživatelům" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Odeslat oznámení všem uživatelům na všech hostitelích" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Odeslat oznámení všem online uživatelům" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "Odeslat oznámení všem online uživatelům na všech hostitelích" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Nastavit zprávu dne a odeslat ji online uživatelům" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "Nastavit zprávu dne a odeslat ji online uživatelům" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Aktualizovat zprávu dne (neodesílat)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Aktualizovat zprávu dne pro všechny hostitele (neodesílat)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Smazat zprávu dne" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Smazat zprávu dne na všech hostitelích" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Konfigurace" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Databáze" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Spustit moduly" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Zastavit moduly" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Zálohovat" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Obnovit" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Uložit do textového souboru" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Import souboru" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Import adresáře" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Restartovat službu" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Vypnout službu" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Přidat uživatele" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Smazat uživatele" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Ukončit sezení uživatele" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Získat heslo uživatele" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Změnit heslo uživatele" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Získat čas podleního přihlášení uživatele" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Získat statistiky uživatele" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Získat počet registrovaných uživatelů" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Získat počet online uživatelů" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Seznamy přístupových práv (ACL)" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Pravidla přístupů" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Správa uživatelů" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Online uživatelé" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Všichni uživatelé" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Odchozí s2s spojení" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Běžící uzly" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Zastavené uzly" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Moduly" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Správa zálohování" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Importovat uživatele z jabberd 1.4 spool souborů" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "Pro ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "Od ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Konfigurace databázových tabulek " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Vyberte typ úložiště pro tabulky" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Jen kopie disku" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "Kopie RAM a disku" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "Kopie RAM" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Vzdálená kopie" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Zastavit moduly na " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Vyberte moduly, které mají být zastaveny" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Spustit moduly na " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Vložte seznam modulů {Modul, [Parametry]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Seznam modulů, které mají být spuštěné" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Záloha do souboru na " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Zadajte cestu k souboru se zálohou" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Cesta k souboru" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Obnovit zálohu ze souboru na " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Uložit zálohu do textového souboru na " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Zadajte cestu k textovému souboru" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Importovat uživatele ze souboru na " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Zadejte cestu k spool souboru jabberd1.4" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Importovat uživatele z adresáře na " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Zadejte cestu k jabberd1.4 spool adresáři" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Cesta k adresáři" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Časový posun" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Konfigurace seznamu přístupových práv (ACL)" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Seznamy přístupových práv (ACL)" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Konfigurace přístupů" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Pravidla přístupů" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Heslo" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Ověření hesla" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Počet registrovaných uživatelů" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Počet online uživatelů" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Nikdy" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Online" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Poslední přihlášení" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Velikost seznamu kontaktů" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "IP adresy" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Zdroje" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Administrace " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Akce aplikovaná na uživatele" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Upravit vlastnosti" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Odstranit uživatele" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Přístup byl zamítnut nastavením služby" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "IRC transport" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "Ejabberd IRC modul" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "Pro konfiguraci mod_irc potřebujete klienta podporujícího x:data" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Registrace do mod_irc na " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Vložte jméno uživatele a kódování, které chcete používat při připojení na " +"IRC server" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "IRC přezdívka" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Pokud chcete zadat jiné kódování pro IRC servery, vyplňte seznam s hodnotami " +"ve formátu '{\"irc server\",\"encoding\"}'. Předvolené kódování pro tuto " +"službu je \"~s\"." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Příklad: [{\"irc.freenode.net\",\"utf-8\"}, {\"irc.freenode.net\", \"iso8859-" +"2\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Kódování" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "Pouze správci služby mají povolené odesílání servisních zpráv" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "Pravidla služby nepovolují vytvořit místnost" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "Konferenční místnost neexistuje" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Konference" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "K registraci přezdívky potřebujete klienta podporujícího x:data" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Registrace prezdívky na " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Zadejte přezdívku, kterou chcete zaregistrovat" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Prezdívka" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "Zadaná přezdívka je již zaregistrována" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Musíte vyplnit políčko \"Přezdívka\" ve formuláři" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "Ejabberd MUC modul" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Nastavení diskuzní místnosti bylo změněno" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "vstoupil(a) do místnosti" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "opustil(a) místnost" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "byl(a) zablokován(a)" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "byl(a) vyhozen(a) z místnosti" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "byl(a) vyhozen(a) kvůli změně přiřazení" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "byl(a) vyhozen(a), protože mísnost je nyní pouze pro členy" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "byl(a) vyhozen(a), protože dojde k vypnutí systému" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "se přejmenoval(a) na" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " změnil(a) téma na: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "Pondělí" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "Úterý" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "Středa" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "Čtvrtek" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "Pátek" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "Sobota" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "Neděle" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr ". ledna" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr ". února" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr ". března" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr ". dubna" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr ". května" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr ". června" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr ". července" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr ". srpna" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr ". září" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr ". října" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr ". listopadu" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr ". prosince" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Nastavení místnosti" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Název místnosti" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Byl překročen limit" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "Tento účastník byl vyhozen, protože odeslal chybovou zprávu" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Není povoleno odesílat soukromé zprávy do konference" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Nesprávný typ zprávy" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Tento účastník byl vyhozen, protože odeslal chybovou zprávu jinému " +"účastníkovi" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "Není dovoleno odeslání soukromé zprávy typu \"skupinová zpráva\" " + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "Příjemce se nenachází v konferenční místnosti" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Jen členové mají povolené zasílat správy do konference" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "Je zakázáno posílat soukromé zprávy" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Jen členové mohou odesílat požadavky (query) do konference" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "" +"Požadavky (queries) na členy konference nejsou v této místnosti povolené" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "soukromá, " + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "Jen moderátoři a účastníci mají povoleno měnit téma této místnosti" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Jen moderátoři mají povoleno měnit téma místnosti" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "" +"Návštevníci nemají povoleno zasílat zprávy všem přihlášeným do konference" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "Tento účastník byl vyhozen, protože odeslal chybový status" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Návštěvníkům této místnosti je zakázáno měnit přezdívku" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "Přezdívka je již používána jiným členem" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "Přezdívka je zaregistrována jinou osobou" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Byl jste vyloučen z této místnosti" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "Pro vstup do místnosti musíte být členem" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Tato místnost není anonymní" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Pro vstup do místnosti musíte zadat heslo" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Nesprávné heslo" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Jsou potřebná práva administrátora" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Jsou potřebná práva moderátora" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "JID ~s je neplatné" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "Přezdívka ~s v místnosti neexistuje" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Neplatné přiřazení: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Neplatná role: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Jsou vyžadována práva vlastníka" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Konfigurace pro " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Popis:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Nastavit místnost jako stálou" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Nastavit místnost jako veřejnou" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Nastavit seznam účastníků jako veřejný" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Chránit místnost heslem" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Počet účastníků" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Bez limitu" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Odhalovat skutečná Jabber ID" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "moderátorům" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "každému" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Nastavit místnost jen pro členy" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Nastavit místnost jako moderovanou" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Uživatelé jsou implicitně členy" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Povolit uživatelům měnit téma místnosti" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Povolit uživatelům odesílat soukromé zprávy" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Povolit uživatelům odesílat požadavky (query) ostatním uživatelům" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Povolit uživatelům posílání pozvánek" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "Povolit návštěvníkům posílat stavové zprávy ve statusu" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Povolit návštěvníkům měnit přezdívku" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Zaznamenávat konverzace" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "Ke konfiguraci místnosti potřebujete klienta podporujícího x:data" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Počet účastníků" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s vás zve do místnosti ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "heslo je" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "Fronta offline zpráv pro váš kontakt je plná. Zpráva byla zahozena." + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "Fronta offline zpráv uživatele ~s" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Odeslané" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Čas" + +#: mod_offline.erl:507 +msgid "From" +msgstr "Od" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Pro" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Paket" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Smazat vybrané" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Offline zprávy" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "ejabberd SOCKS5 Bytestreams modul" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Publish-Subscribe" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "ejabberd Publish-Subscribe modul" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "Žádost odběratele PubSub" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Zvolte, zda chcete schválit odebírání touto entitou" + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "ID uzlu" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Adresa odběratele" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Povolit tomuto JID odebírat tento pubsub uzel?" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Doručovat náklad s upozorněním na událost" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Doručovat upozornění na události" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Upozornit odběratele na změnu nastavení uzlu" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Upozornit odběratele na smazání uzlu" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Upozornit odběratele na odstranění položek z uzlu" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Uložit položky natrvalo do úložiště" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "Přívětivé jméno pro uzel" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Maximální počet položek, které je možné natrvalo uložit" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Povolit odebírání" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Uveďte přístupový model" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Skupiny kontaktů, které mohou odebírat" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Specifikovat model pro publikování" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Maximální náklad v bajtech" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Kdy odeslat poslední publikovanou položku" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Doručovat upozornění jen právě přihlášeným uživatelům" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "Zadejte jméno uživatele a heslo pro registraci na tomto serveru" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "Je zakázáno registrovat účty v tak rychlém sledu" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Nic" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Přihlášení" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Čekající" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Skupiny" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Ověřit" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Odstranit" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Seznam kontaktů " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Nesprávný formát" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Přidat JID" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Seznam kontaktů" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Skupiny pro sdílený seznam kontaktů" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Přidat nový" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Jméno:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Popis:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Členové:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Zobrazené skupiny:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Skupina " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Odeslat" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Erlang Jabber Server" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Datum narození: " + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Město: " + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "Země: " + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "E-mail" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Příjmení: " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Pro vyhledání uživatele Jabberu vyplňte formulář (přidejte znak * na konec, " +"pro vyhledání podřetězce)" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Celé jméno: " + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Druhé jméno: " + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Jméno" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Název firmy: " + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Oddělení: " + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Hledat uživatele v " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Uživatel: " + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "K vyhledávání potřebujete klienta podporujícího x:data" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "Hledání uživatelů podle vizitek" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "ejabberd vCard modul" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Výsledky hledání pro " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Vyplňte políčka pro vyhledání uživatele Jabberu" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "Webová administrace ejabberd" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Administrace" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Virtuální hostitelé" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Uzly" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Statistiky" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Uživatelé" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Poslední aktivita" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Zdroj)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Zdroj" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "~s konfigurace pravidla přístupu" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "Virtuální hostitelé ejabberd" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Poslední aktivita uživatele" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Čas:" + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Poslední měsíc" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Poslední rok" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Všechny aktivity" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Zobrazit běžnou tabulku" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Zobrazit kompletní tabulku" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Uzel nenalezen" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Hostitel" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Registrovaní uživatelé" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Offline zprávy" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Registrovaní živatelé:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Online uživatelé:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Odchozí s2s spojení:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Odchozí s2s servery:" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Změnit heslo" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Uživatel " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Připojené zdroje:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Heslo:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Žádná data" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Uzel " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Otevřené porty" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Aktualizovat" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Restart" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Stop" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "Chyba RPC volání" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Databázové tabulky na " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Typ úložiště" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Velikost" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Paměť" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Záloha na " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Podotýkáme, že tato nastavení budou zálohována do zabudované databáze " +"Mnesia. Pokud používáte ODBC modul, musíte zálohovat svoji SQL databázi " +"samostatně." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Uložit binární zálohu:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "OK" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Okamžitě obnovit binární zálohu:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"Obnovit binární zálohu při následujícím restartu ejabberd (vyžaduje méně " +"paměti)" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Uložit zálohu do textového souboru:" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Okamžitě obnovit zálohu z textového souboru:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Otevřené porty na " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Moduly na " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "Statistiky ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Čas běhu" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "Čas procesoru" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Transakce potvrzena" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Transakce zrušena" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Transakce restartována" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Transakce zaznamenána" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Aktualizovat " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Aktualizovat plán" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Aktualizované moduly" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Aktualizované skripty" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Nízkoúrovňový aktualizační skript" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Kontrola skriptu" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Port" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Modul" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Nastavení" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Smazat" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Start" diff --git a/src/msgs/de.msg b/src/msgs/de.msg index b5c89b9e8..8e45f01ed 100644 --- a/src/msgs/de.msg +++ b/src/msgs/de.msg @@ -1,384 +1,343 @@ -% $Id$ -% Language: German (deutsch) -% Author: Cord Beermann -% Author: Nikolaus Polak -% Author: Marvin Preuss -% Author: Patrick Dreker -% Author: Torsten Werner -% Author: Marina Hahn - -% mod_offline.erl -{"Your contact offline message queue is full. The message has been discarded.", "Ihre offline Kontakt Warteschlange ist voll. Die Nachricht wurde verworfen."}. -{"~s's Offline Messages Queue", "~s's Offline Nachrichten Warteschlange"}. -{"Submitted", "Gesendet"}. -{"Time", "Zeit"}. -{"From", "Von"}. -{"To", "Zu"}. -{"Packet", "Paket"}. -{"Delete Selected", "Markiertes löschen"}. -{"Offline Messages:", "Offline Nachrichten:"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Wählen Sie zum Registrieren einen Benutzernamen und ein Passwort"}. - -% mod_roster_odbc.erl -{"None", "Keine"}. -{"Jabber ID", "Jabber ID"}. -{"Nickname", "Spitzname"}. -{"Subscription", "Abonnement"}. -{"Pending", "schwebend"}. -{"Groups", "Gruppen"}. -{"Validate", "Validieren"}. -{"Remove", "Entfernen"}. -{"Roster of ", "Kontaktliste von "}. -{"Bad format", "Ungültiges Format"}. -{"Add Jabber ID", "Jabber ID hinzufügen"}. -{"Roster", "Kontaktliste"}. - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "ejabberd SOCKS5 Bytestreams Modul"}. - -% mod_vcard_odbc.erl -{"Erlang Jabber Server", "Erlang Jabber Server"}. -{"You need an x:data capable client to search", "Sie benötigen einen Client, der x:data unterstützt, um suchen zu können"}. -{"Search users in ", "Benutzer suchen in "}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Füllen Sie die Felder aus, um nach passenden Jabber Benutzern zu suchen (beenden Sie ein Feld mit *, um auch nach Teilzeichenketten zu suchen)"}. -{"User", "Benutzer"}. -{"Full Name", "Ganzer Name"}. -{"Name", "Vorname"}. -{"Middle Name", "Zweiter Vorname"}. -{"Family Name", "Nachname"}. -{"Birthday", "Geburtsdatum"}. -{"Country", "Land"}. -{"City", "Stadt"}. -{"Email", "E-Mail"}. -{"Organization Name", "Firmenname"}. -{"Organization Unit", "Abteilung"}. -{"vCard User Search", "vCard Benutzer Suche"}. -{"ejabberd vCard module", "ejabberd vCard Modul"}. -{"Search Results for ", "Suchergebnisse für "}. - -% mod_adhoc.erl -{"Commands", "Befehle"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% mod_announce.erl -{"Really delete message of the day?", "Wirklich die Nachricht des Tages löschen?"}. -{"Subject", "Thema"}. -{"Message body", "Nachrichtentext"}. -{"No body provided for announce message", "Kein Text für die Ankündigung angegeben"}. -{"Announcements", "Ankündigungen"}. -{"Send announcement to all users", "Sende Ankündigung an alle Benutzer"}. -{"Send announcement to all users on all hosts", "Sende Ankündigung an alle Benutzer auf allen Hosts"}. -{"Send announcement to all online users", "Sende Ankündigung an alle angemeldeten Benutzer"}. -{"Send announcement to all online users on all hosts", "Sende Ankündigung an alle angemeldeten Benutzer auf allen Hosts"}. -{"Set message of the day and send to online users", "Setze Nachricht des Tages und sende sie an alle angemeldeten Benutzer"}. -{"Set message of the day on all hosts and send to online users", "Setze Nachricht des Tages auf allen Hosts und sende sie an alle angemeldeten Benutzer"}. -{"Update message of the day (don't send)", "Aktualisiere Nachricht des Tages (nicht senden)"}. -{"Update message of the day on all hosts (don't send)", "Aktualisiere Nachricht des Tages auf allen Hosts (nicht senden)"}. -{"Delete message of the day", "Lösche Nachricht des Tages"}. -{"Delete message of the day on all hosts", "Lösche Nachricht des Tages auf allen Hosts"}. - -% ejabberd_c2s.erl -{"Use of STARTTLS required", "Verwendung von STARTTLS erforderlich"}. -{"No resource provided", "Keine Ressource angegeben"}. -{"Replaced by new connection", "Durch neue Verbindung ersetzt"}. - -% mod_pubsub/mod_pubsub.erl -{"Roster groups allowed to subscribe", "Kontaktlisten-Gruppen die abonnieren dürfen"}. -{"Publish-Subscribe", "Publish-Subscribe"}. -{"ejabberd Publish-Subscribe module", "ejabberd Publish-Subscribe Modul"}. -{"PubSub subscriber request", "PubSub Abonnenten Anfrage"}. -{"Choose whether to approve this entity's subscription.", "Wähle ob dieses Abonnement bestätigt wird."}. -{"Node ID", "Knoten ID"}. -{"Subscriber Address", "Abonnenten Adresse"}. -{"Allow this JID to subscribe to this pubsub node?", "Erlauben Sie dieser JID das Abonnement dieses pubsub Knotens?"}. -{"Deliver payloads with event notifications", "Versende Nutzlast mit Ereignis Benachrichtigung"}. -{"Deliver event notifications", "Versende Ereignisbenachrichtigung"}. -{"Notify subscribers when the node configuration changes", "Abonnenten benachrichtigen, wenn die Knotenkonfiguration sich ändert"}. -{"Notify subscribers when the node is deleted", "Abonnenten benachrichtigen, wenn der Knoten gelöscht wird"}. -{"Notify subscribers when items are removed from the node", "Abonnenten benachrichtigen, wenn Einträge vom Knoten entfernt werden"}. -{"Persist items to storage", "Einträge dauerhaft speichern"}. -{"Max # of items to persist", "Maximale Anzahl dauerhaft zu speichernder Einträge"}. -{"Whether to allow subscriptions", "Ob Abonnements erlaubt sind"}. -{"Specify the access model", "Geben Sie das Zugangsmodell an"}. -{"Specify the publisher model", "Geben Sie das Publikationsmodell an"}. -{"Max payload size in bytes", "Maximale Nutzlastgrösse in Bytes"}. -{"When to send the last published item", "Wann soll das letzte veröffentlichte Objekt gesendet werden"}. -{"Only deliver notifications to available users", "Benachrichtigungen nur an verfügbare Benutzer schicken"}. - -% mod_configure.erl -{"Configuration", "Konfiguration"}. -{"Database", "Datenbank"}. -{"Start Modules", "Module starten"}. -{"Stop Modules", "Module stoppen"}. -{"Backup", "Datensicherung"}. -{"Restore", "Wiederherstellung"}. -{"Dump to Text File", "Ausgabe in Textdatei"}. -{"Import File", "Datei importieren"}. -{"Import Directory", "Verzeichnis importieren"}. -{"Restart Service", "Dienst neustarten"}. -{"Shut Down Service", "Dienst herunterfahren"}. -{"Add User", "Benutzer hinzufügen"}. -{"Delete User", "Benutzer löschen"}. -{"End User Session", "Benutzer Sitzung beenden"}. -{"Get User Password", "Benutzer Passwort abrufen"}. -{"Change User Password", "Benutzer Passwort ändern"}. -{"Get User Last Login Time", "letzte Anmeldezeit abrufen"}. -{"Get User Statistics", "Benutzer Statistik abrufen"}. -{"Get Number of Registered Users", "Anzahl der registrierten Benutzer abrufen"}. -{"Get Number of Online Users", "Anzahl der angemeldeten Benutzer abrufen"}. -{"Access Control Lists", "Zugangskontroll-Listen (ACL)"}. -{"Access Rules", "Zugangsregeln"}. -{"User Management", "Benutzer Verwaltung"}. -{"Online Users", "Angemeldete Benutzer"}. -{"All Users", "Alle Benutzer"}. -{"Outgoing s2s Connections", "Ausgehende s2s Verbindungen"}. -{"Running Nodes", "Aktive Knoten"}. -{"Stopped Nodes", "Inaktive Knoten"}. -{"Modules", "Module"}. -{"Backup Management", "Datensicherungsmanagement"}. -{"Import Users From jabberd 1.4 Spool Files", "Importiere Benutzer von jabberd 1.4 Spool Dateien"}. -{"To ~s", "An ~s"}. -{"From ~s", "Von ~s"}. -{"Database Tables Configuration at ", "Datenbank Tabellen Konfiguration bei "}. -{"Choose storage type of tables", "Wähle Speichertyp der Tabellen"}. -{"RAM copy", "RAM Kopie"}. -{"RAM and disc copy", "RAM und Festplatten Kopie"}. -{"Disc only copy", "Festplatten Kopie"}. -{"Remote copy", "Fernkopie"}. -{"Stop Modules at ", "Stoppe Module bei "}. -{"Choose modules to stop", "Wähle zu stoppende Module"}. -{"Start Modules at ", "Starte Module bei "}. -{"Enter list of {Module, [Options]}", "Geben Sie eine Liste bestehend aus {Modul, [Optionen]} ein"}. -{"List of modules to start", "Liste der zu startenden Module"}. -{"Backup to File at ", "Datensicherung in die Datei "}. -{"Enter path to backup file", "Geben Sie den Pfad zur Datensicherung ein"}. -{"Path to File", "Pfad zur Datei"}. -{"Restore Backup from File at ", "Datenwiederherstellung aus der Datei "}. -{"Dump Backup to Text File at ", "Ausgabe der Sicherung in diese Textdatei "}. -{"Enter path to text file", "Geben Sie den Pfad zur Textdatei ein"}. -{"Import User from File at ", "Benutzer aus dieser Datei importieren "}. -{"Enter path to jabberd1.4 spool file", "Geben Sie den Pfad zur jabberd1.4 spool Datei ein"}. -{"Import Users from Dir at ", "Benutzer vom Verzeichnis importieren "}. -{"Enter path to jabberd1.4 spool dir", "Geben Sie den Pfad zum jabberd1.4 spool Verzeichnis ein"}. -{"Path to Dir", "Pfad zum Verzeichnis"}. -{"Time delay", "Zeitverzögerung"}. -{"Access Control List Configuration", "Zugangskontroll-Liste (ACL) Konfiguration"}. -{"Access control lists", "Zugangskontroll-Listen (ACL)"}. -{"Access Configuration", "Zugangskonfiguration"}. -{"Access rules", "Zugangsregeln"}. -{"Password", "Passwort"}. -{"Password Verification", "Passwort bestätigen"}. -{"Number of registered users", "Anzahl der registrierten Benutzer"}. -{"Number of online users", "Anzahl der angemeldeten Benutzer"}. -{"Never", "Nie"}. -{"Online", "Angemeldet"}. -{"Last login", "Letzte Anmeldung"}. -{"Roster size", "Kontaktlistengrösse"}. -{"IP addresses", "IP Addresse"}. -{"Resources", "Resource"}. -{"Administration of ", "Administration der "}. -{"Action on user", "Aktion auf Benutzer"}. -{"Edit Properties", "Einstellungen ändern"}. -{"Remove User", "Benutzer löschen"}. - -% web/ejabberd_web_admin.erl -{"ejabberd Web Admin", "ejabberd Web Admin"}. -{"Administration", "Verwaltung"}. -{"Virtual Hosts", "Virtuelle Hosts"}. -{"Nodes", "Knoten"}. -{"Statistics", "Statistik"}. -{"Users", "Benutzer"}. -{"Last Activity", "Letzte Aktion"}. -{"(Raw)", "(unformatiert)"}. -{"Submit", "Senden"}. -{"Raw", "Unformatiert"}. -{"~s access rule configuration", "~s Zugangsregel Konfiguration"}. -{"ejabberd virtual hosts", "ejabberd virtuelle Hosts"}. -{"Users Last Activity", "Letzte Benutzeraktivität"}. -{"Period: ", "Zeitraum: "}. -{"Last month", "Letzter Monat"}. -{"Last year", "Letztes Jahr"}. -{"All activity", "Alle Aktivitäten"}. -{"Show Ordinary Table", "Normale Tabelle anzeigen"}. -{"Show Integral Table", "Vollständige Tabelle anzeigen"}. -{"Node not found", "Knoten nicht gefunden"}. -{"Add New", "Neuen hinzufügen"}. -{"Host", "Host"}. -{"Registered Users", "Registrierte Benutzer"}. -{"Offline Messages", "Offline Nachrichten"}. -{"Registered Users:", "Registrierte Benutzer:"}. -{"Online Users:", "Angemeldete Benutzer:"}. -{"Outgoing s2s Connections:", "Ausgehende s2s Verbindungen:"}. -{"Outgoing s2s Servers:", "Ausgehende s2s Server:"}. -{"Change Password", "Passwort ändern"}. -{"User ", "Benutzer "}. -{"Connected Resources:", "Verbundene Resourcen"}. -{"Password:", "Passwort:"}. -{"No Data", "Keine Daten"}. -{"Node ", "Knoten "}. -{"Listened Ports", "Aktive Ports"}. -{"Update", "Aktualisieren"}. -{"Restart", "Neustart"}. -{"Stop", "Stop"}. -{"RPC Call Error", "RPC Abruf-Fehler"}. -{"Database Tables at ", "Datenbank Tabellen bei "}. -{"Storage Type", "Speichertyp"}. -{"Size", "Grösse"}. -{"Memory", "Speicher"}. -{"Backup of ", "Sicherung von "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "Beachten sie, das diese Optionen nur die eingebaute Mnesia Datenbank sichert. Wenn sie das ODBC Modul verwenden, müssen sie die SQL Datenbank manuell sichern."}. -{"Store binary backup:", "Speichere binäre Sicherung:"}. -{"OK", "OK"}. -{"Restore binary backup immediately:", "Stelle binäre Sicherung sofort wieder her:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Stelle binäre Sicherung beim nächsten ejabberd Neustart wieder her (benötigt weniger Speicher):"}. -{"Store plain text backup:", "Speichere Klartext-Sicherung:"}. -{"Restore plain text backup immediately:", "Stelle Klartext-Sicherung sofort wieder her:"}. -{"Listened Ports at ", "aktive Ports "}. -{"Modules at ", "Module auf "}. -{"Statistics of ~p", "Statistiken von ~p"}. -{"Uptime:", "Betriebszeit:"}. -{"CPU Time:", "CPU Zeit:"}. -{"Transactions Commited:", "Vorgänge durchgeführt:"}. -{"Transactions Aborted:", "Vorgänge abgebrochen:"}. -{"Transactions Restarted:", "Vorgänge neu gestartet:"}. -{"Transactions Logged:", "Vorgänge protokolliert:"}. -{"Update ", "Aktualisierung "}. -{"Update plan", "Aktualisierungsplan"}. -{"Updated modules", "Aktualisierte Module"}. -{"Update script", "Aktualisierungsscript"}. -{"Low level update script", "Low level Aktualisierungsscript"}. -{"Script check", "Script Überprüfung"}. -{"Port", "Port"}. -{"Module", "Modul"}. -{"Options", "Optionen"}. -{"Delete", "Löschen"}. -{"Start", "Anfang"}. - -% mod_irc/mod_irc.erl -{"Access denied by service policy", "Zugang aufgrund der Dienstrichtlinien verweigert"}. -{"IRC Transport", "IRC Transport"}. -{"ejabberd IRC module", "ejabberd IRC Modul"}. -{"You need an x:data capable client to configure mod_irc settings", "Sie benötigen einen Client, der x:data unterstützt, um die mod_irc Einstellungen zu konfigurieren"}. -{"Registration in mod_irc for ", "Registrierung in mod_irc für "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Geben Sie Benutzernamen und Kodierung für die Verbindung zum IRC Server an"}. -{"IRC Username", "IRC Benutzername"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Wenn Sie verschiedene Kodierungen für IRC Server angeben, schreiben Sie diese im Format '{\"Irc Server\", \"Kodierung\"}'. Standardmässig benutzt der Dienst die \"~s\" Kodierung"}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Beispiel: [{\"irc.lucky.net\",\"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"Encodings", "Kodierung"}. - -% mod_shared_roster.erl -{"Shared Roster Groups", "Gruppen der gemeinsamen Kontaktliste"}. -{"Name:", "Name:"}. -{"Description:", "Beschreibung:"}. -{"Members:", "Mitglieder:"}. -{"Displayed Groups:", "Angezeigte Gruppen:"}. -{"Group ", "Gruppe "}. - -% mod_vcard_ldap.erl -{"Fill in fields to search for any matching Jabber User", "Felder ausfüllen, um nach passenden Jabber Benutzern zu suchen"}. - -% mod_muc/mod_muc_log.erl -{"Chatroom configuration modified", "Chatraum Konfiguration geändert"}. -{"joins the room", "kommt in den Raum"}. -{"leaves the room", "verlässt den Raum"}. -{"has been banned", "wurde gebannt"}. -{"has been kicked", "wurde gekickt"}. -{"has been kicked because of an affiliation change", "wurde wegen Änderung des Mitgliederstatus gekickt"}. -{"has been kicked because the room has been changed to members-only", "wurde gekickt weil der Raum auf Nur-Mitglieder umgestellt wurde"}. -{"has been kicked because of a system shutdown", "wurde wegen Systemabschaltung gekickt"}. -{"is now known as", "ist nun bekannt als"}. -{" has set the subject to: ", " hat das Thema geändert auf: "}. -{"Monday", "Montag"}. -{"Tuesday", "Dienstag"}. -{"Wednesday", "Mittwoch"}. -{"Thursday", "Donnerstag"}. -{"Friday", "Freitag"}. -{"Saturday", "Samstag"}. -{"Sunday", "Sonntag"}. -{"January", "Januar"}. -{"February", "Februar"}. -{"March", "März"}. -{"April", "April"}. -{"May", "Mai"}. -{"June", "Juni"}. -{"July", "Juli"}. -{"August", "August"}. -{"September", "September"}. -{"October", "Oktober"}. -{"November", "November"}. -{"December", "Dezember"}. -{"Room Configuration", "Raum Konfiguration"}. -{"Room title", "Raumname"}. - -% mod_muc/mod_muc.erl -{"Only service administrators are allowed to send service messages", "Nur Service Administratoren sind berechtigt, Servicenachrichten zu senden"}. -{"Room creation is denied by service policy", "Anlegen des Raumes aufgrund der Dienstrichtlinien verweigert"}. -{"Conference room does not exist", "Konferenzraum existiert nicht"}. -{"Chatrooms", "Raum"}. -{"You need an x:data capable client to register nickname", "Sie benötigen einen Client, der x:data unterstützt, um Ihren Spitznamen zu registrieren"}. -{"Nickname Registration at ", "Registrieren des Spitznamens "}. -{"Enter nickname you want to register", "Geben Sie den zu registrierenden Spitznamen ein"}. -{"Specified nickname is already registered", "Der angegebene Name ist bereits vergeben"}. -{"You must fill in field \"Nickname\" in the form", "Sie müssen das Feld \"Spitzname\" ausfüllen"}. -{"ejabberd MUC module", "ejabberd MUC Modul"}. - -% mod_muc/mod_muc_room.erl -{"This participant is kicked from the room because he sent an error message", "Dieser Teilnehmer wurde aus dem Raum gekickt, da er eine Fehlernachricht gesendet hat"}. -{"This participant is kicked from the room because he sent an error message to another participant", "Dieser Teilnehmer wurde aus dem Raum gekickt, da er eine Fehlernachricht an einen anderen Teilnehmer gesendet hat"}. -{"This participant is kicked from the room because he sent an error presence", "Dieser Teilnehmer wurde aus dem Raum gekickt, da er einen fehlerhaften Status gesendet hat"}. -{"Make room moderated", "Raum modieriert machen"}. -{"Traffic rate limit is exceeded", "Datenrate ist zu hoch"}. -{"It is not allowed to send private messages to the conference", "Es ist nicht erlaubt private Nachrichten an den Raum zu schicken"}. -{"Improper message type", "Unzulässiger Nachrichtentyp"}. -{"Only occupants are allowed to send messages to the conference", "Nur Teilnehmer dürfen Nachrichten an den Raum schicken"}. -{"It is not allowed to send private messages of type \"groupchat\"", "Es ist nicht erlaubt private Nachrichten des Typs \"Gruppenchat\" zu senden"}. -{"Recipient is not in the conference room", "Der Empfänger ist nicht im Raum"}. -{"Only occupants are allowed to send queries to the conference", "Nur Teilnehmer sind berechtig Anfragen an die Konferenz zu senden"}. -{"Queries to the conference members are not allowed in this room", "Anfragen an die Teilnehmer sind in diesem Raum nicht erlaubt"}. -{"private, ", "privat, "}. -{"Only moderators and participants are allowed to change subject in this room", "Nur Moderatoren und Teilnehmer dürfen das Thema in diesem Raum ändern"}. -{"Only moderators are allowed to change subject in this room", "Nur Moderatoren dürfen das Thema in diesem Raum ändern"}. -{"Visitors are not allowed to send messages to all occupants", "Besucher dürfen nicht an alle Teilnehmer Nachrichten verschicken"}. -{"Nickname is already in use by another occupant", "Spitzname wird bereits von einem Teilnehmer genutzt"}. -{"Nickname is registered by another person", "Spitzname wurde bereits von jemand anderem registriert"}. -{"You have been banned from this room", "Sie wurden aus diesem Raum verbannt"}. -{"Membership required to enter this room", "Um diesen Raum zu betreten müssen sie Mitglied sein"}. -{"This room is not anonymous", "Dieser Raum ist nicht anonym"}. -{"Password required to enter this room", "Sie brauchen ein Passwort um diesen Raum zu betreten"}. -{"Incorrect password", "Falsches Passwort"}. -{"Administrator privileges required", "Administratorenrechte benötigt"}. -{"Moderator privileges required", "Moderatorrechte benötigt"}. -{"JID ~s is invalid", "JID ~s ist ungültig"}. -{"Nickname ~s does not exist in the room", "Spitzname ~s existiert im Raum nicht"}. -{"Invalid affiliation: ~s", "Ungültige Mitgliedschaft: ~s"}. -{"Invalid role: ~s", "Ungültige Rolle: ~s"}. -{"Owner privileges required", "Besitzerrechte benötigt"}. -{"Configuration for ", "Konfiguration für "}. -{"Make room persistent", "Raum persistent machen"}. -{"Make room public searchable", "Raum öffentlich suchbar machen"}. -{"Make participants list public", "Teilnehmerliste öffentlich machen"}. -{"Make room password protected", "Raum passwortgeschützt machen"}. -{"Maximum Number of Occupants", "maximale Anzahl von Teilnehmern"}. -{"No limit", "keine Begrenzung"}. -{"Present real JIDs to", "Echte Jabber IDs anzeigen für"}. -{"moderators only", "ausschliesslich Moderatoren"}. -{"anyone", "jeder"}. -{"Make room members-only", "Raum nur für Mitglieder zugänglich machen"}. -{"Default users as participants", "Standardbenutzer als Teilnehmer"}. -{"Allow users to change subject", "Erlaube Benutzern das Thema zu ändern"}. -{"Allow users to send private messages", "Erlaube Benutzern private Nachrichten zu senden"}. -{"Allow users to query other users", "Erlaube Benutzern andere Benutzer abzufragen"}. -{"Allow users to send invites", "Erlaube Benutzern Einladungen zu senden"}. -{"Enable logging", "Log-Funktion aktivieren"}. -{"You need an x:data capable client to configure room", "Sie benötigen einen Client, der x:data unterstützt, um den Raum zu konfigurieren"}. -{"Number of occupants", "Anzahl der Teilnehmer"}. -{"~s invites you to the room ~s", "~s lädt sie in den Raum ~s ein"}. -{"the password is", "das Passwort ist"}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Zugangskonfiguration"}. +{"Access Control List Configuration","Zugangskontroll-Liste (ACL) Konfiguration"}. +{"Access control lists","Zugangskontroll-Listen (ACL)"}. +{"Access Control Lists","Zugangskontroll-Listen (ACL)"}. +{"Access denied by service policy","Zugang aufgrund der Dienstrichtlinien verweigert"}. +{"Access rules","Zugangsregeln"}. +{"Access Rules","Zugangsregeln"}. +{"Action on user","Aktion auf Benutzer"}. +{"Add Jabber ID","Jabber ID hinzufügen"}. +{"Add New","Neuen hinzufügen"}. +{"Add User","Benutzer hinzufügen"}. +{"Administration of ","Administration der "}. +{"Administration","Verwaltung"}. +{"Administrator privileges required","Administratorenrechte benötigt"}. +{"A friendly name for the node","Ein passender Name für den Knoten"}. +{"All activity","Alle Aktivitäten"}. +{"Allow this JID to subscribe to this pubsub node?","Erlauben Sie dieser JID das Abonnement dieses pubsub Knotens?"}. +{"Allow users to change subject","Erlaube Benutzern das Thema zu ändern"}. +{"Allow users to query other users","Erlaube Benutzern andere Benutzer abzufragen"}. +{"Allow users to send invites","Erlaube Benutzern Einladungen zu senden"}. +{"Allow users to send private messages","Erlaube Benutzern private Nachrichten zu senden"}. +{"Allow visitors to change nickname","Erlaube Besuchern ihren Spitznamen zu ändern"}. +{"Allow visitors to send status text in presence updates","Erlaube Besuchern einen Text bei Statusänderung zu setzen"}. +{"All Users","Alle Benutzer"}. +{"Announcements","Ankündigungen"}. +{"anyone","jeder"}. +{"April","April"}. +{"August","August"}. +{"Backup","Datensicherung"}. +{"Backup Management","Datensicherungsmanagement"}. +{"Backup of ","Sicherung von "}. +{"Backup to File at ","Datensicherung in die Datei "}. +{"Bad format","Ungültiges Format"}. +{"Birthday","Geburtsdatum"}. +{"Change Password","Passwort ändern"}. +{"Change User Password","Benutzer Passwort ändern"}. +{"Chatroom configuration modified","Chatraum Konfiguration geändert"}. +{"Chatrooms","Chaträume"}. +{"Choose a username and password to register with this server","Wählen Sie zum Registrieren einen Benutzernamen und ein Passwort"}. +{"Choose modules to stop","Wähle zu stoppende Module"}. +{"Choose storage type of tables","Wähle Speichertyp der Tabellen"}. +{"Choose whether to approve this entity's subscription.","Wähle ob dieses Abonnement bestätigt wird."}. +{"City","Stadt"}. +{"Commands","Befehle"}. +{"Conference room does not exist","Konferenzraum existiert nicht"}. +{"Configuration for ","Konfiguration für "}. +{"Configuration","Konfiguration"}. +{"Connected Resources:","Verbundene Resourcen"}. +{"Country","Land"}. +{"CPU Time:","CPU Zeit:"}. +{"Database","Datenbank"}. +{"Database Tables at ","Datenbank Tabellen bei "}. +{"Database Tables Configuration at ","Datenbank Tabellen Konfiguration bei "}. +{"December","Dezember"}. +{"Default users as participants","Standardbenutzer als Teilnehmer"}. +{"Delete","Löschen"}. +{"Delete message of the day","Lösche Nachricht des Tages"}. +{"Delete message of the day on all hosts","Lösche Nachricht des Tages auf allen Hosts"}. +{"Delete Selected","Markiertes löschen"}. +{"Delete User","Benutzer löschen"}. +{"Deliver event notifications","Versende Ereignisbenachrichtigung"}. +{"Deliver payloads with event notifications","Versende Nutzlast mit Ereignis Benachrichtigung"}. +{"Description:","Beschreibung:"}. +{"Disc only copy","Festplatten Kopie"}. +{"Displayed Groups:","Angezeigte Gruppen:"}. +{"Dump Backup to Text File at ","Ausgabe der Sicherung in diese Textdatei "}. +{"Dump to Text File","Ausgabe in Textdatei"}. +{"Edit Properties","Einstellungen ändern"}. +{"ejabberd IRC module","ejabberd IRC Modul"}. +{"ejabberd MUC module","ejabberd MUC Modul"}. +{"ejabberd Publish-Subscribe module","ejabberd Publish-Subscribe Modul"}. +{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestreams Modul"}. +{"ejabberd vCard module","ejabberd vCard Modul"}. +{"ejabberd virtual hosts","ejabberd virtuelle Hosts"}. +{"ejabberd Web Admin","ejabberd Web Admin"}. +{"Email","E-Mail"}. +{"Enable logging","Log-Funktion aktivieren"}. +{"Encodings","Kodierung"}. +{"End User Session","Benutzer Sitzung beenden"}. +{"Enter list of {Module, [Options]}","Geben Sie eine Liste bestehend aus {Modul, [Optionen]} ein"}. +{"Enter nickname you want to register","Geben Sie den zu registrierenden Spitznamen ein"}. +{"Enter path to backup file","Geben Sie den Pfad zur Datensicherung ein"}. +{"Enter path to jabberd1.4 spool dir","Geben Sie den Pfad zum jabberd1.4 spool Verzeichnis ein"}. +{"Enter path to jabberd1.4 spool file","Geben Sie den Pfad zur jabberd1.4 spool Datei ein"}. +{"Enter path to text file","Geben Sie den Pfad zur Textdatei ein"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Geben Sie Benutzernamen und Kodierung für die Verbindung zum IRC Server an"}. +{"Erlang Jabber Server","Erlang Jabber Server"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Beispiel: [{\"irc.lucky.net\",\"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","Nachname"}. +{"February","Februar"}. +{"Fill in fields to search for any matching Jabber User","Felder ausfüllen, um nach passenden Jabber Benutzern zu suchen"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Füllen Sie die Felder aus, um nach passenden Jabber Benutzern zu suchen (beenden Sie ein Feld mit *, um auch nach Teilzeichenketten zu suchen)"}. +{"Friday","Freitag"}. +{"From ~s","Von ~s"}. +{"From","Von"}. +{"Full Name","Ganzer Name"}. +{"Get Number of Online Users","Anzahl der angemeldeten Benutzer abrufen"}. +{"Get Number of Registered Users","Anzahl der registrierten Benutzer abrufen"}. +{"Get User Last Login Time","letzte Anmeldezeit abrufen"}. +{"Get User Password","Benutzer Passwort abrufen"}. +{"Get User Statistics","Benutzer Statistik abrufen"}. +{"Group ","Gruppe "}. +{"Groups","Gruppen"}. +{"has been banned","wurde gebannt"}. +{"has been kicked because of an affiliation change","wurde wegen Änderung des Mitgliederstatus gekickt"}. +{"has been kicked because of a system shutdown","wurde wegen Systemabschaltung gekickt"}. +{"has been kicked because the room has been changed to members-only","wurde gekickt weil der Raum auf Nur-Mitglieder umgestellt wurde"}. +{"has been kicked","wurde gekickt"}. +{" has set the subject to: "," hat das Thema geändert auf: "}. +{"Host","Host"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Wenn Sie verschiedene Kodierungen für IRC Server angeben, schreiben Sie diese im Format '{\"Irc Server\", \"Kodierung\"}'. Standardmässig benutzt der Dienst die \"~s\" Kodierung"}. +{"Import Directory","Verzeichnis importieren"}. +{"Import File","Datei importieren"}. +{"Import User from File at ","Benutzer aus dieser Datei importieren "}. +{"Import Users from Dir at ","Benutzer vom Verzeichnis importieren "}. +{"Import Users From jabberd 1.4 Spool Files","Importiere Benutzer von jabberd 1.4 Spool Dateien"}. +{"Improper message type","Unzulässiger Nachrichtentyp"}. +{"Incorrect password","Falsches Passwort"}. +{"Invalid affiliation: ~s","Ungültige Mitgliedschaft: ~s"}. +{"Invalid role: ~s","Ungültige Rolle: ~s"}. +{"IP addresses","IP Addresse"}. +{"IRC Transport","IRC Transport"}. +{"IRC Username","IRC Benutzername"}. +{"is now known as","ist nun bekannt als"}. +{"It is not allowed to send private messages","Es ist nicht erlaubt private Nachrichten zu senden"}. +{"It is not allowed to send private messages of type \"groupchat\"","Es ist nicht erlaubt private Nachrichten des Typs \"Gruppenchat\" zu senden"}. +{"It is not allowed to send private messages to the conference","Es ist nicht erlaubt private Nachrichten an den Raum zu schicken"}. +{"Jabber ID","Jabber ID"}. +{"January","Januar"}. +{"JID ~s is invalid","JID ~s ist ungültig"}. +{"joins the room","kommt in den Raum"}. +{"July","Juli"}. +{"June","Juni"}. +{"Last Activity","Letzte Aktion"}. +{"Last login","Letzte Anmeldung"}. +{"Last month","Letzter Monat"}. +{"Last year","Letztes Jahr"}. +{"leaves the room","verlässt den Raum"}. +{"Listened Ports","Aktive Ports"}. +{"Listened Ports at ","aktive Ports "}. +{"List of modules to start","Liste der zu startenden Module"}. +{"Low level update script","Low level Aktualisierungsscript"}. +{"Make participants list public","Teilnehmerliste öffentlich machen"}. +{"Make room members-only","Raum nur für Mitglieder zugänglich machen"}. +{"Make room moderated","Raum modieriert machen"}. +{"Make room password protected","Raum passwortgeschützt machen"}. +{"Make room persistent","Raum persistent machen"}. +{"Make room public searchable","Raum öffentlich suchbar machen"}. +{"March","März"}. +{"Maximum Number of Occupants","maximale Anzahl von Teilnehmern"}. +{"Max # of items to persist","Maximale Anzahl dauerhaft zu speichernder Einträge"}. +{"Max payload size in bytes","Maximale Nutzlastgrösse in Bytes"}. +{"May","Mai"}. +{"Membership required to enter this room","Um diesen Raum zu betreten müssen sie Mitglied sein"}. +{"Members:","Mitglieder:"}. +{"Memory","Speicher"}. +{"Message body","Nachrichtentext"}. +{"Middle Name","Zweiter Vorname"}. +{"Moderator privileges required","Moderatorrechte benötigt"}. +{"moderators only","ausschliesslich Moderatoren"}. +{"Module","Modul"}. +{"Modules at ","Module auf "}. +{"Modules","Module"}. +{"Monday","Montag"}. +{"Name:","Name:"}. +{"Name","Vorname"}. +{"Never","Nie"}. +{"Nickname is already in use by another occupant","Spitzname wird bereits von einem Teilnehmer genutzt"}. +{"Nickname is registered by another person","Spitzname wurde bereits von jemand anderem registriert"}. +{"Nickname Registration at ","Registrieren des Spitznamens "}. +{"Nickname ~s does not exist in the room","Spitzname ~s existiert im Raum nicht"}. +{"Nickname","Spitzname"}. +{"No body provided for announce message","Kein Text für die Ankündigung angegeben"}. +{"No Data","Keine Daten"}. +{"Node ID","Knoten ID"}. +{"Node ","Knoten "}. +{"Node not found","Knoten nicht gefunden"}. +{"Nodes","Knoten"}. +{"No limit","keine Begrenzung"}. +{"None","Keine"}. +{"No resource provided","Keine Ressource angegeben"}. +{"Notify subscribers when items are removed from the node","Abonnenten benachrichtigen, wenn Einträge vom Knoten entfernt werden"}. +{"Notify subscribers when the node configuration changes","Abonnenten benachrichtigen, wenn die Knotenkonfiguration sich ändert"}. +{"Notify subscribers when the node is deleted","Abonnenten benachrichtigen, wenn der Knoten gelöscht wird"}. +{"November","November"}. +{"Number of occupants","Anzahl der Teilnehmer"}. +{"Number of online users","Anzahl der angemeldeten Benutzer"}. +{"Number of registered users","Anzahl der registrierten Benutzer"}. +{"October","Oktober"}. +{"Offline Messages:","Offline Nachrichten:"}. +{"Offline Messages","Offline Nachrichten"}. +{"OK","OK"}. +{"Online","Angemeldet"}. +{"Online Users:","Angemeldete Benutzer:"}. +{"Online Users","Angemeldete Benutzer"}. +{"Only deliver notifications to available users","Benachrichtigungen nur an verfügbare Benutzer schicken"}. +{"Only moderators and participants are allowed to change subject in this room","Nur Moderatoren und Teilnehmer dürfen das Thema in diesem Raum ändern"}. +{"Only moderators are allowed to change subject in this room","Nur Moderatoren dürfen das Thema in diesem Raum ändern"}. +{"Only occupants are allowed to send messages to the conference","Nur Teilnehmer dürfen Nachrichten an den Raum schicken"}. +{"Only occupants are allowed to send queries to the conference","Nur Teilnehmer sind berechtig Anfragen an die Konferenz zu senden"}. +{"Only service administrators are allowed to send service messages","Nur Service Administratoren sind berechtigt, Servicenachrichten zu senden"}. +{"Options","Optionen"}. +{"Organization Name","Firmenname"}. +{"Organization Unit","Abteilung"}. +{"Outgoing s2s Connections:","Ausgehende s2s Verbindungen:"}. +{"Outgoing s2s Connections","Ausgehende s2s Verbindungen"}. +{"Outgoing s2s Servers:","Ausgehende s2s Server:"}. +{"Owner privileges required","Besitzerrechte benötigt"}. +{"Packet","Paket"}. +{"Password:","Passwort:"}. +{"Password","Passwort"}. +{"Password required to enter this room","Sie brauchen ein Passwort um diesen Raum zu betreten"}. +{"Password Verification","Passwort bestätigen"}. +{"Path to Dir","Pfad zum Verzeichnis"}. +{"Path to File","Pfad zur Datei"}. +{"Pending","schwebend"}. +{"Period: ","Zeitraum: "}. +{"Persist items to storage","Einträge dauerhaft speichern"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","Port"}. +{"Present real JIDs to","Echte Jabber IDs anzeigen für"}. +{"private, ","privat, "}. +{"Publish-Subscribe","Publish-Subscribe"}. +{"PubSub subscriber request","PubSub Abonnenten Anfrage"}. +{"Queries to the conference members are not allowed in this room","Anfragen an die Teilnehmer sind in diesem Raum nicht erlaubt"}. +{"RAM and disc copy","RAM und Festplatten Kopie"}. +{"RAM copy","RAM Kopie"}. +{"(Raw)","(unformatiert)"}. +{"Raw","Unformatiert"}. +{"Really delete message of the day?","Wirklich die Nachricht des Tages löschen?"}. +{"Recipient is not in the conference room","Der Empfänger ist nicht im Raum"}. +{"Registered Users:","Registrierte Benutzer:"}. +{"Registered Users","Registrierte Benutzer"}. +{"Registration in mod_irc for ","Registrierung in mod_irc für "}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Beachten sie, das diese Optionen nur die eingebaute Mnesia Datenbank sichert. Wenn sie das ODBC Modul verwenden, müssen sie die SQL Datenbank manuell sichern."}. +{"Remote copy","Fernkopie"}. +{"Remove","Entfernen"}. +{"Remove User","Benutzer löschen"}. +{"Replaced by new connection","Durch neue Verbindung ersetzt"}. +{"Resources","Resource"}. +{"Restart","Neustart"}. +{"Restart Service","Dienst neustarten"}. +{"Restore Backup from File at ","Datenwiederherstellung aus der Datei "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Stelle binäre Sicherung beim nächsten ejabberd Neustart wieder her (benötigt weniger Speicher):"}. +{"Restore binary backup immediately:","Stelle binäre Sicherung sofort wieder her:"}. +{"Restore plain text backup immediately:","Stelle Klartext-Sicherung sofort wieder her:"}. +{"Restore","Wiederherstellung"}. +{"Room Configuration","Raum Konfiguration"}. +{"Room creation is denied by service policy","Anlegen des Raumes aufgrund der Dienstrichtlinien verweigert"}. +{"Room title","Raumname"}. +{"Roster groups allowed to subscribe","Kontaktlisten-Gruppen die abonnieren dürfen"}. +{"Roster","Kontaktliste"}. +{"Roster of ","Kontaktliste von "}. +{"Roster size","Kontaktlistengrösse"}. +{"RPC Call Error","RPC Abruf-Fehler"}. +{"Running Nodes","Aktive Knoten"}. +{"~s access rule configuration","~s Zugangsregel Konfiguration"}. +{"Saturday","Samstag"}. +{"Script check","Script Überprüfung"}. +{"Search Results for ","Suchergebnisse für "}. +{"Search users in ","Benutzer suchen in "}. +{"Send announcement to all online users on all hosts","Sende Ankündigung an alle angemeldeten Benutzer auf allen Hosts"}. +{"Send announcement to all online users","Sende Ankündigung an alle angemeldeten Benutzer"}. +{"Send announcement to all users on all hosts","Sende Ankündigung an alle Benutzer auf allen Hosts"}. +{"Send announcement to all users","Sende Ankündigung an alle Benutzer"}. +{"September","September"}. +{"Set message of the day and send to online users","Setze Nachricht des Tages und sende sie an alle angemeldeten Benutzer"}. +{"Set message of the day on all hosts and send to online users","Setze Nachricht des Tages auf allen Hosts und sende sie an alle angemeldeten Benutzer"}. +{"Shared Roster Groups","Gruppen der gemeinsamen Kontaktliste"}. +{"Show Integral Table","Vollständige Tabelle anzeigen"}. +{"Show Ordinary Table","Normale Tabelle anzeigen"}. +{"Shut Down Service","Dienst herunterfahren"}. +{"~s invites you to the room ~s","~s lädt sie in den Raum ~s ein"}. +{"Size","Grösse"}. +{"Specified nickname is already registered","Der angegebene Name ist bereits vergeben"}. +{"Specify the access model","Geben Sie das Zugangsmodell an"}. +{"Specify the publisher model","Geben Sie das Publikationsmodell an"}. +{"~s's Offline Messages Queue","~s's Offline Nachrichten Warteschlange"}. +{"Start","Anfang"}. +{"Start Modules at ","Starte Module bei "}. +{"Start Modules","Module starten"}. +{"Statistics of ~p","Statistiken von ~p"}. +{"Statistics","Statistik"}. +{"Stop Modules at ","Stoppe Module bei "}. +{"Stop Modules","Module stoppen"}. +{"Stopped Nodes","Inaktive Knoten"}. +{"Stop","Stop"}. +{"Storage Type","Speichertyp"}. +{"Store binary backup:","Speichere binäre Sicherung:"}. +{"Store plain text backup:","Speichere Klartext-Sicherung:"}. +{"Subject","Thema"}. +{"Submit","Senden"}. +{"Submitted","Gesendet"}. +{"Subscriber Address","Abonnenten Adresse"}. +{"Subscription","Abonnement"}. +{"Sunday","Sonntag"}. +{"the password is","das Passwort ist"}. +{"This participant is kicked from the room because he sent an error message","Dieser Teilnehmer wurde aus dem Raum gekickt, da er eine Fehlernachricht gesendet hat"}. +{"This participant is kicked from the room because he sent an error message to another participant","Dieser Teilnehmer wurde aus dem Raum gekickt, da er eine Fehlernachricht an einen anderen Teilnehmer gesendet hat"}. +{"This participant is kicked from the room because he sent an error presence","Dieser Teilnehmer wurde aus dem Raum gekickt, da er einen fehlerhaften Status gesendet hat"}. +{"This room is not anonymous","Dieser Raum ist nicht anonym"}. +{"Thursday","Donnerstag"}. +{"Time delay","Zeitverzögerung"}. +{"Time","Zeit"}. +{"To ~s","An ~s"}. +{"To","Zu"}. +{"Traffic rate limit is exceeded","Datenrate ist zu hoch"}. +{"Transactions Aborted:","Vorgänge abgebrochen:"}. +{"Transactions Commited:","Vorgänge durchgeführt:"}. +{"Transactions Logged:","Vorgänge protokolliert:"}. +{"Transactions Restarted:","Vorgänge neu gestartet:"}. +{"Tuesday","Dienstag"}. +{"Update","Aktualisieren"}. +{"Update ","Aktualisierung "}. +{"Updated modules","Aktualisierte Module"}. +{"Update message of the day (don't send)","Aktualisiere Nachricht des Tages (nicht senden)"}. +{"Update message of the day on all hosts (don't send)","Aktualisiere Nachricht des Tages auf allen Hosts (nicht senden)"}. +{"Update plan","Aktualisierungsplan"}. +{"Update script","Aktualisierungsscript"}. +{"Uptime:","Betriebszeit:"}. +{"Use of STARTTLS required","Verwendung von STARTTLS erforderlich"}. +{"User ","Benutzer "}. +{"User","Benutzer"}. +{"User Management","Benutzer Verwaltung"}. +{"Users are not allowed to register accounts so fast","Benutzer dürfen Konten nicht so schnell registrieren"}. +{"Users","Benutzer"}. +{"Users Last Activity","Letzte Benutzeraktivität"}. +{"Validate","Validieren"}. +{"vCard User Search","vCard Benutzer Suche"}. +{"Virtual Hosts","Virtuelle Hosts"}. +{"Visitors are not allowed to change their nicknames in this room","Besucher dürfen in diesem Raum ihren Spitznamen nicht ändern"}. +{"Visitors are not allowed to send messages to all occupants","Besucher dürfen nicht an alle Teilnehmer Nachrichten verschicken"}. +{"Wednesday","Mittwoch"}. +{"When to send the last published item","Wann soll das letzte veröffentlichte Objekt gesendet werden"}. +{"Whether to allow subscriptions","Ob Abonnements erlaubt sind"}. +{"You have been banned from this room","Sie wurden aus diesem Raum verbannt"}. +{"You must fill in field \"Nickname\" in the form","Sie müssen das Feld \"Spitzname\" ausfüllen"}. +{"You need an x:data capable client to configure mod_irc settings","Sie benötigen einen Client, der x:data unterstützt, um die mod_irc Einstellungen zu konfigurieren"}. +{"You need an x:data capable client to configure room","Sie benötigen einen Client, der x:data unterstützt, um den Raum zu konfigurieren"}. +{"You need an x:data capable client to register nickname","Sie benötigen einen Client, der x:data unterstützt, um Ihren Spitznamen zu registrieren"}. +{"You need an x:data capable client to search","Sie benötigen einen Client, der x:data unterstützt, um suchen zu können"}. +{"Your contact offline message queue is full. The message has been discarded.","Ihre offline Kontakt Warteschlange ist voll. Die Nachricht wurde verworfen."}. diff --git a/src/msgs/de.po b/src/msgs/de.po new file mode 100644 index 000000000..6537c1dda --- /dev/null +++ b/src/msgs/de.po @@ -0,0 +1,1504 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Nikolaus Polak\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: German (deutsch)\n" +"X-Additional-Translator: Cord Beermann\n" +"X-Additional-Translator: Marvin Preuss\n" +"X-Additional-Translator: Patrick Dreker\n" +"X-Additional-Translator: Torsten Werner\n" +"X-Additional-Translator: Marina Hahn\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "Verwendung von STARTTLS erforderlich" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Keine Ressource angegeben" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Durch neue Verbindung ersetzt" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Befehle" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Wirklich die Nachricht des Tages löschen?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Thema" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Nachrichtentext" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "Kein Text für die Ankündigung angegeben" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Ankündigungen" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Sende Ankündigung an alle Benutzer" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Sende Ankündigung an alle Benutzer auf allen Hosts" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Sende Ankündigung an alle angemeldeten Benutzer" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "Sende Ankündigung an alle angemeldeten Benutzer auf allen Hosts" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Setze Nachricht des Tages und sende sie an alle angemeldeten Benutzer" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Setze Nachricht des Tages auf allen Hosts und sende sie an alle angemeldeten " +"Benutzer" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Aktualisiere Nachricht des Tages (nicht senden)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Aktualisiere Nachricht des Tages auf allen Hosts (nicht senden)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Lösche Nachricht des Tages" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Lösche Nachricht des Tages auf allen Hosts" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Konfiguration" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Datenbank" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Module starten" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Module stoppen" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Datensicherung" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Wiederherstellung" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Ausgabe in Textdatei" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Datei importieren" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Verzeichnis importieren" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Dienst neustarten" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Dienst herunterfahren" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Benutzer hinzufügen" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Benutzer löschen" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Benutzer Sitzung beenden" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Benutzer Passwort abrufen" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Benutzer Passwort ändern" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "letzte Anmeldezeit abrufen" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Benutzer Statistik abrufen" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Anzahl der registrierten Benutzer abrufen" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Anzahl der angemeldeten Benutzer abrufen" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Zugangskontroll-Listen (ACL)" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Zugangsregeln" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Benutzer Verwaltung" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Angemeldete Benutzer" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Alle Benutzer" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Ausgehende s2s Verbindungen" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Aktive Knoten" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Inaktive Knoten" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Module" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Datensicherungsmanagement" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Importiere Benutzer von jabberd 1.4 Spool Dateien" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "An ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "Von ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Datenbank Tabellen Konfiguration bei " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Wähle Speichertyp der Tabellen" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Festplatten Kopie" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "RAM und Festplatten Kopie" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "RAM Kopie" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Fernkopie" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Stoppe Module bei " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Wähle zu stoppende Module" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Starte Module bei " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Geben Sie eine Liste bestehend aus {Modul, [Optionen]} ein" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Liste der zu startenden Module" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Datensicherung in die Datei " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Geben Sie den Pfad zur Datensicherung ein" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Pfad zur Datei" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Datenwiederherstellung aus der Datei " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Ausgabe der Sicherung in diese Textdatei " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Geben Sie den Pfad zur Textdatei ein" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Benutzer aus dieser Datei importieren " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Geben Sie den Pfad zur jabberd1.4 spool Datei ein" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Benutzer vom Verzeichnis importieren " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Geben Sie den Pfad zum jabberd1.4 spool Verzeichnis ein" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Pfad zum Verzeichnis" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Zeitverzögerung" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Zugangskontroll-Liste (ACL) Konfiguration" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Zugangskontroll-Listen (ACL)" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Zugangskonfiguration" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Zugangsregeln" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Passwort" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Passwort bestätigen" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Anzahl der registrierten Benutzer" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Anzahl der angemeldeten Benutzer" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Nie" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Angemeldet" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Letzte Anmeldung" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Kontaktlistengrösse" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "IP Addresse" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Resource" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Administration der " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Aktion auf Benutzer" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Einstellungen ändern" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Benutzer löschen" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Zugang aufgrund der Dienstrichtlinien verweigert" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "IRC Transport" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "ejabberd IRC Modul" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "" +"Sie benötigen einen Client, der x:data unterstützt, um die mod_irc " +"Einstellungen zu konfigurieren" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Registrierung in mod_irc für " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Geben Sie Benutzernamen und Kodierung für die Verbindung zum IRC Server an" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "IRC Benutzername" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Wenn Sie verschiedene Kodierungen für IRC Server angeben, schreiben Sie " +"diese im Format '{\"Irc Server\", \"Kodierung\"}'. Standardmässig benutzt " +"der Dienst die \"~s\" Kodierung" + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Beispiel: [{\"irc.lucky.net\",\"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Kodierung" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "" +"Nur Service Administratoren sind berechtigt, Servicenachrichten zu senden" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "Anlegen des Raumes aufgrund der Dienstrichtlinien verweigert" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "Konferenzraum existiert nicht" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Chaträume" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "" +"Sie benötigen einen Client, der x:data unterstützt, um Ihren Spitznamen zu " +"registrieren" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Registrieren des Spitznamens " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Geben Sie den zu registrierenden Spitznamen ein" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Spitzname" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "Der angegebene Name ist bereits vergeben" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Sie müssen das Feld \"Spitzname\" ausfüllen" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "ejabberd MUC Modul" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Chatraum Konfiguration geändert" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "kommt in den Raum" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "verlässt den Raum" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "wurde gebannt" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "wurde gekickt" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "wurde wegen Änderung des Mitgliederstatus gekickt" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "wurde gekickt weil der Raum auf Nur-Mitglieder umgestellt wurde" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "wurde wegen Systemabschaltung gekickt" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "ist nun bekannt als" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " hat das Thema geändert auf: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "Montag" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "Dienstag" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "Mittwoch" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "Donnerstag" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "Freitag" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "Samstag" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "Sonntag" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "Januar" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "Februar" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "März" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "April" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "Mai" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "Juni" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "Juli" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "August" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "September" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "Oktober" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "November" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "Dezember" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Raum Konfiguration" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Raumname" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Datenrate ist zu hoch" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" +"Dieser Teilnehmer wurde aus dem Raum gekickt, da er eine Fehlernachricht " +"gesendet hat" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Es ist nicht erlaubt private Nachrichten an den Raum zu schicken" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Unzulässiger Nachrichtentyp" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Dieser Teilnehmer wurde aus dem Raum gekickt, da er eine Fehlernachricht an " +"einen anderen Teilnehmer gesendet hat" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "" +"Es ist nicht erlaubt private Nachrichten des Typs \"Gruppenchat\" zu senden" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "Der Empfänger ist nicht im Raum" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Nur Teilnehmer dürfen Nachrichten an den Raum schicken" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "Es ist nicht erlaubt private Nachrichten zu senden" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Nur Teilnehmer sind berechtig Anfragen an die Konferenz zu senden" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "Anfragen an die Teilnehmer sind in diesem Raum nicht erlaubt" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "privat, " + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "Nur Moderatoren und Teilnehmer dürfen das Thema in diesem Raum ändern" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Nur Moderatoren dürfen das Thema in diesem Raum ändern" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "Besucher dürfen nicht an alle Teilnehmer Nachrichten verschicken" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" +"Dieser Teilnehmer wurde aus dem Raum gekickt, da er einen fehlerhaften " +"Status gesendet hat" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Besucher dürfen in diesem Raum ihren Spitznamen nicht ändern" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "Spitzname wird bereits von einem Teilnehmer genutzt" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "Spitzname wurde bereits von jemand anderem registriert" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Sie wurden aus diesem Raum verbannt" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "Um diesen Raum zu betreten müssen sie Mitglied sein" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Dieser Raum ist nicht anonym" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Sie brauchen ein Passwort um diesen Raum zu betreten" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Falsches Passwort" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Administratorenrechte benötigt" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Moderatorrechte benötigt" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "JID ~s ist ungültig" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "Spitzname ~s existiert im Raum nicht" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Ungültige Mitgliedschaft: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Ungültige Rolle: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Besitzerrechte benötigt" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Konfiguration für " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Beschreibung:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Raum persistent machen" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Raum öffentlich suchbar machen" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Teilnehmerliste öffentlich machen" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Raum passwortgeschützt machen" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "maximale Anzahl von Teilnehmern" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "keine Begrenzung" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Echte Jabber IDs anzeigen für" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "ausschliesslich Moderatoren" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "jeder" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Raum nur für Mitglieder zugänglich machen" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Raum modieriert machen" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Standardbenutzer als Teilnehmer" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Erlaube Benutzern das Thema zu ändern" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Erlaube Benutzern private Nachrichten zu senden" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Erlaube Benutzern andere Benutzer abzufragen" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Erlaube Benutzern Einladungen zu senden" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "Erlaube Besuchern einen Text bei Statusänderung zu setzen" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Erlaube Besuchern ihren Spitznamen zu ändern" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Log-Funktion aktivieren" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "" +"Sie benötigen einen Client, der x:data unterstützt, um den Raum zu " +"konfigurieren" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Anzahl der Teilnehmer" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s lädt sie in den Raum ~s ein" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "das Passwort ist" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "" +"Ihre offline Kontakt Warteschlange ist voll. Die Nachricht wurde verworfen." + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "~s's Offline Nachrichten Warteschlange" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Gesendet" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Zeit" + +#: mod_offline.erl:507 +msgid "From" +msgstr "Von" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Zu" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Paket" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Markiertes löschen" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Offline Nachrichten:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "ejabberd SOCKS5 Bytestreams Modul" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Publish-Subscribe" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "ejabberd Publish-Subscribe Modul" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "PubSub Abonnenten Anfrage" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Wähle ob dieses Abonnement bestätigt wird." + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "Knoten ID" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Abonnenten Adresse" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Erlauben Sie dieser JID das Abonnement dieses pubsub Knotens?" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Versende Nutzlast mit Ereignis Benachrichtigung" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Versende Ereignisbenachrichtigung" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Abonnenten benachrichtigen, wenn die Knotenkonfiguration sich ändert" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Abonnenten benachrichtigen, wenn der Knoten gelöscht wird" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Abonnenten benachrichtigen, wenn Einträge vom Knoten entfernt werden" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Einträge dauerhaft speichern" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "Ein passender Name für den Knoten" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Maximale Anzahl dauerhaft zu speichernder Einträge" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Ob Abonnements erlaubt sind" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Geben Sie das Zugangsmodell an" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Kontaktlisten-Gruppen die abonnieren dürfen" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Geben Sie das Publikationsmodell an" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Maximale Nutzlastgrösse in Bytes" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Wann soll das letzte veröffentlichte Objekt gesendet werden" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Benachrichtigungen nur an verfügbare Benutzer schicken" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "Wählen Sie zum Registrieren einen Benutzernamen und ein Passwort" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "Benutzer dürfen Konten nicht so schnell registrieren" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Keine" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Abonnement" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "schwebend" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Gruppen" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Validieren" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Entfernen" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Kontaktliste von " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Ungültiges Format" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Jabber ID hinzufügen" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Kontaktliste" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Gruppen der gemeinsamen Kontaktliste" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Neuen hinzufügen" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Name:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Beschreibung:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Mitglieder:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Angezeigte Gruppen:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Gruppe " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Senden" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Erlang Jabber Server" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Geburtsdatum" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Stadt" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "Land" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "E-Mail" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Nachname" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Füllen Sie die Felder aus, um nach passenden Jabber Benutzern zu suchen " +"(beenden Sie ein Feld mit *, um auch nach Teilzeichenketten zu suchen)" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Ganzer Name" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Zweiter Vorname" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Vorname" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Firmenname" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Abteilung" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Benutzer suchen in " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Benutzer" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "" +"Sie benötigen einen Client, der x:data unterstützt, um suchen zu können" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "vCard Benutzer Suche" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "ejabberd vCard Modul" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Suchergebnisse für " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Felder ausfüllen, um nach passenden Jabber Benutzern zu suchen" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "ejabberd Web Admin" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Verwaltung" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Virtuelle Hosts" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Knoten" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Statistik" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Benutzer" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Letzte Aktion" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(unformatiert)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Unformatiert" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "~s Zugangsregel Konfiguration" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "ejabberd virtuelle Hosts" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Letzte Benutzeraktivität" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Zeitraum: " + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Letzter Monat" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Letztes Jahr" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Alle Aktivitäten" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Normale Tabelle anzeigen" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Vollständige Tabelle anzeigen" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Knoten nicht gefunden" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Host" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Registrierte Benutzer" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Offline Nachrichten" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Registrierte Benutzer:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Angemeldete Benutzer:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Ausgehende s2s Verbindungen:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Ausgehende s2s Server:" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Passwort ändern" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Benutzer " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Verbundene Resourcen" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Passwort:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Keine Daten" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Knoten " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Aktive Ports" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Aktualisieren" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Neustart" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Stop" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "RPC Abruf-Fehler" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Datenbank Tabellen bei " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Speichertyp" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Grösse" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Speicher" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Sicherung von " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Beachten sie, das diese Optionen nur die eingebaute Mnesia Datenbank " +"sichert. Wenn sie das ODBC Modul verwenden, müssen sie die SQL Datenbank " +"manuell sichern." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Speichere binäre Sicherung:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "OK" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Stelle binäre Sicherung sofort wieder her:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"Stelle binäre Sicherung beim nächsten ejabberd Neustart wieder her (benötigt " +"weniger Speicher):" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Speichere Klartext-Sicherung:" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Stelle Klartext-Sicherung sofort wieder her:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "aktive Ports " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Module auf " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "Statistiken von ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Betriebszeit:" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "CPU Zeit:" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Vorgänge durchgeführt:" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Vorgänge abgebrochen:" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Vorgänge neu gestartet:" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Vorgänge protokolliert:" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Aktualisierung " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Aktualisierungsplan" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Aktualisierte Module" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Aktualisierungsscript" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Low level Aktualisierungsscript" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Script Überprüfung" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Port" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Modul" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Optionen" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Löschen" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Anfang" diff --git a/src/msgs/ejabberd.pot b/src/msgs/ejabberd.pot new file mode 100644 index 000000000..0f4a204cd --- /dev/null +++ b/src/msgs/ejabberd.pot @@ -0,0 +1,1467 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"X-Language: Language Name\n" +"Last-Translator: Translator name and contact method\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "" + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "" + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "" + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "" + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "" + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "" + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "" + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "" + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "" + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "" + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "" + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr "" + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "" + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "" + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +msgid "Room description" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "" + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "" + +#: mod_offline.erl:507 +msgid "From" +msgstr "" + +#: mod_offline.erl:508 +msgid "To" +msgstr "" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "" + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "" + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "" + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "" + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "" + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "" + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "" + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "" + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "" + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "" + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "" + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "" diff --git a/src/msgs/eo.msg b/src/msgs/eo.msg index b510b8bd9..eee050c2f 100644 --- a/src/msgs/eo.msg +++ b/src/msgs/eo.msg @@ -1,388 +1,343 @@ -% $Id$ -% Language: Esperanto -% Author: Andreas van Cranenburgh - -% ejabberd_c2s.erl -{"Use of STARTTLS required", "Uzo de STARTTLS bezonata"}. -{"Replaced by new connection", "Anstataŭigita je nova konekto"}. - -% jlib.hrl -{"No resource provided", "Neniu risurco donita"}. - -% mod_configure.erl -{"Database", "Datumbazo"}. -{"Restart Service", "Restartu Servon"}. -{"Shut Down Service", "Haltigu Servon"}. -{"Delete User", "Forigu Uzanton"}. -{"End User Session", "Haltigu Uzant-seancon"}. -{"Get User Password", "Montru pasvorton de uzanto"}. -{"Change User Password", "Ŝanĝu pasvorton de uzanto"}. -{"Get User Last Login Time", "Montru tempon de lasta ensaluto"}. -{"Get User Statistics", "Montru statistikojn de uzanto"}. -{"Get Number of Registered Users", "Montru nombron de registritaj uzantoj"}. -{"Get Number of Online Users", "Montru nombron de konektataj uzantoj"}. -{"User Management", "Uzanto-administrado"}. -{"Outgoing s2s Connections", "Elirantaj s-al-s-konektoj"}. -{"Import Users From jabberd 1.4 Spool Files", "Importu uzantojn de jabberd1.4-uzantdosieroj"}. -{"Database Tables Configuration at ", "Agordo de datumbaz-tabeloj je "}. -{"Time delay", "Prokrasto"}. -{"Password Verification", "Pasvortkontrolo"}. -{"Number of registered users", "Nombro de registritaj uzantoj"}. -{"Number of online users", "Nombro de konektataj uzantoj"}. -{"Last login", "Lasta ensaluto"}. -{"Roster size", "Kontaktlist-grando"}. -{"IP addresses", "IP-adresoj"}. -{"Resources", "Risurcoj"}. -{"Choose storage type of tables", "Elektu konserv-tipon de tabeloj"}. -{"RAM copy", "RAM-kopio"}. -{"RAM and disc copy", "RAM- kaj disk-kopio"}. -{"Disc only copy", "Nur disk-kopio"}. -{"Remote copy", "Fora kopio"}. -{"Stop Modules at ", "Haltigu modulojn je "}. -{"Choose modules to stop", "Elektu modulojn por fini"}. -{"Start Modules at ", "Startu modulojn je "}. -{"Enter list of {Module, [Options]}", "Enmetu liston de {Modulo, [Elektebloj]}"}. -{"List of modules to start", "Listo de moduloj por starti"}. -{"Backup to File at ", "Faru sekurkopion je "}. -{"Enter path to backup file", "Enmetu vojon por sekurkopio"}. -{"Path to File", "Voje de dosiero"}. -{"Restore Backup from File at ", "Restaŭrigu de dosiero el "}. -{"Dump Backup to Text File at ", "Skribu sekurkopion en plata teksto al "}. -{"Enter path to text file", "Enmetu vojon al plata teksto"}. -{"Import User from File at ", "Importu uzanton de dosiero el "}. -{"Enter path to jabberd1.4 spool file", "Enmetu vojon al jabberd1.4-uzantdosiero"}. -{"Import Users from Dir at ", "Importu uzantojn de dosierujo ĉe "}. -{"Enter path to jabberd1.4 spool dir", "Enmetu vojon al jabberd1.4-uzantdosierujo"}. -{"Path to Dir", "Vojo al dosierujo"}. -{"Access Control List Configuration", "Agordo de atingokontrolo"}. -{"Access control lists", "Atingokontrol-listoj"}. -{"Access Configuration", "Agordo de atingo"}. -{"Access rules", "Atingo-reguloj"}. -{"Administration of ", "Mastrumado de "}. -{"Action on user", "Ago je uzanto"}. -{"Edit Properties", "Redaktu atributojn"}. -{"Remove User", "Forigu uzanton"}. - -% mod_disco.erl -{"Configuration", "Agordo"}. -{"Online Users", "Konektataj Uzantoj"}. -{"All Users", "Ĉiuj Uzantoj"}. -{"To ~s", "Al ~s"}. -{"From ~s", "De ~s"}. -{"Running Nodes", "Funkciantaj Nodoj"}. -{"Stopped Nodes", "Neaktivaj Nodoj"}. -{"Access Control Lists", "Atingokontrol-listoj"}. -{"Access Rules", "Atingo-reguloj"}. -{"Modules", "Moduloj"}. -{"Start Modules", "Startu Modulojn"}. -{"Stop Modules", "Haltigu Modulojn"}. -{"Backup Management", "Mastrumado de sekurkopioj"}. -{"Backup", "Faru Sekurkopion"}. -{"Restore", "Restaŭru"}. -{"Dump to Text File", "Skribu en plata tekst-dosiero"}. -{"Import File", "Importu dosieron"}. -{"Import Directory", "Importu dosierujo"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Elektu uzantnomon kaj pasvorton por registri je ĉi tiu servilo"}. - -% mod_vcard.erl -{"Erlang Jabber Server", "Erlang-a Jabber-Servilo"}. -{"ejabberd vCard module", "ejabberd vCard-modulo"}. -{"You need an x:data capable client to search", "Vi bezonas klienton kun x:data-funkcio por serĉado"}. -{"Search users in ", "Serĉu uzantojn en "}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Kompletigu la formon por serĉi rekonata Jabber-uzanto (Aldonu * je la fino de la kampo por rekoni subĉenon"}. -{"User", "Uzanto"}. -{"Full Name", "Plena Nomo"}. -{"Name", "Nomo"}. -{"Middle Name", "Meza Nomo"}. -{"Family Name", "Lasta Nomo"}. -{"Nickname", "Kaŝnomo"}. -{"Birthday", "Naskiĝtago"}. -{"Country", "Lando"}. -{"City", "Urbo"}. -{"Organization Name", "Organiz-nomo"}. -{"Organization Unit", "Organiz-parto"}. - -% mod_vcard_ldap.erl -{"Fill in fields to search for any matching Jabber User", "Kompletigu la formon por serĉi rekonata Jabber-uzanto"}. - -% mod_vcard_odbc.erl -{"Email", "Retpoŝto"}. -{"vCard User Search", "Serĉado de vizitkartoj"}. -{"Search Results for ", "Serĉ-rezultoj de "}. -{"Jabber ID", "Jabber ID"}. - -% mod_pubsub/mod_pubsub.erl -{"Roster groups allowed to subscribe", "Kontaktlist-grupoj kiuj rajtas aboni"}. -{"Publish-Subscribe", "Public-Abonado"}. -{"ejabberd Publish-Subscribe module", "ejabberd Public-Abonada modulo"}. -{"PubSub subscriber request", "PubAbo abonpeto"}. -{"Choose whether to approve this entity's subscription.", "Elektu ĉu permesi la abonon de ĉi tiu ento"}. -{"Node ID", "Nodo ID"}. -{"Subscriber Address", "Abonanta adreso"}. -{"Allow this JID to subscribe to this pubsub node?", "Ĉu permesi ĉi tiun JID aboni al la jena PubAbo-nodo"}. -{"Deliver event notifications", "Liveru event-sciigojn"}. -{"Specify the access model", "Specifu atingo-modelon"}. -{"When to send the last published item", "Kiam sendi la laste publicitan eron"}. -{"Deliver payloads with event notifications", "Liveru aĵojn de event-sciigoj"}. -{"Notify subscribers when the node configuration changes", "Sciigu abonantoj kiam la agordo de la nodo ŝanĝas"}. -{"Notify subscribers when the node is deleted", "Sciigu abonantoj kiam la nodo estas forigita"}. -{"Notify subscribers when items are removed from the node", "Sciigu abonantoj kiam eroj estas forigita de la nodo"}. -{"Persist items to storage", "Savu erojn en konservado"}. -{"Max # of items to persist", "Maksimuma kiomo de eroj en konservado"}. -{"Whether to allow subscriptions", "Ĉu permesi aboni"}. -{"Specify the publisher model", "Enmetu publikadan modelon"}. -{"Max payload size in bytes", "Maksimuma aĵo-grando je bajtoj"}. -{"Only deliver notifications to available users", "Nur liveru sciigojn al konektataj uzantoj"}. - -% mod_muc/mod_muc.erl -{"Chatrooms", "Babilejoj"}. -{"You must fill in field \"Nickname\" in the form", "Vi devas kompletigi la \"Kaŝnomo\" kampon"}. -{"You need an x:data capable client to register nickname", "Vi bezonas klienton kun x:data-funkcio por registri kaŝnomon"}. -{"Nickname Registration at ", "Kaŝnomo-registrado je "}. -{"Enter nickname you want to register", "Enmetu kaŝnomon kiun vi volas registri"}. -{"ejabberd MUC module", "ejabberd MUC-modulo"}. -{"Only service administrators are allowed to send service messages", "Nur servo-administrantoj rajtas sendi serv-mesaĝojn"}. -{"Room creation is denied by service policy", "Ĉi tiu serv-politiko ne permesas babilejo-kreadon"}. -{"Conference room does not exist", "Babilejo ne ekzistas"}. -{"Access denied by service policy", "Atingo rifuzita de serv-politiko"}. -{"You must fill in field \"nick\" in the form", "Vi devas enmeti kampon \"kaŝnomo\""}. -{"Specified nickname is already registered", "Donita kaŝnomo jam estas registrita"}. - -% mod_muc/mod_muc_room.erl -{"This participant is kicked from the room because he sent an error message", "Ĉi tiu partoprenanta estas forpelata de la babilejo pro sendado de erar-mesaĝo"}. -{"This participant is kicked from the room because he sent an error message to another participant", "Ĉi tiu partoprenanto estas forpelata de la babilejo pro sendo de erar-mesaĝo al alia partoprenanto"}. -{"This participant is kicked from the room because he sent an error presence", "Ĉi tiu partoprenanto estas forpelata de la babilejo pro sendo de erar-ĉeesto"}. %FIXME: a less literal translation anyone? -{"Make room moderated", "Farigu babilejon moderigata"}. -{"Traffic rate limit is exceeded", "Trafikrapida limigo superita"}. -{"This room is not anonymous", "Ĉi tiu babilejo ne estas anonima"}. -{"Make room persistent", "Farigu babilejon daŭra"}. -{"Make room public searchable", "Farigu babilejon publike trovebla"}. -{"Make participants list public", "Farigu partoprento-liston publika"}. -{"Make room password protected", "Farigu babilejon protektata per pasvorto"}. -{"Maximum Number of Occupants", "Limigo de nombro de partoprenantoj"}. -{"No limit", "Neniu limigo"}. -{"Present real JIDs to", "Montru verajn JID-ojn al"}. % "jo-idojn" .. -{"moderators only", "moderantoj sole"}. -{"anyone", "iu ajn"}. -{"Make room members-only", "Farigu babilejon sole por membroj"}. -{"Default users as participants", "Kutime farigu uzantojn kiel partpoprenantoj"}. -{"Allow users to change subject", "Permesu uzantojn ŝanĝi la temon"}. -{"Allow users to send private messages", "Permesu uzantojn sendi privatajn mesaĝojn"}. -{"Allow users to query other users", "Permesu uzantojn informpeti aliajn uzantojn"}. %FIXME: two objects in one sentence? -{"Allow users to send invites", "Permesu uzantojn sendi invitojn"}. -{"Enable logging", "Ŝaltu protokoladon"}. -{"Number of occupants", "Nombro de ĉeestantoj"}. -{"~s invites you to the room ~s", "~s invitas vin al la babilejo ~s"}. -{"the password is", "la pasvorto estas"}. -{" has set the subject to: ", " ŝanĝis la temon al: "}. -{"You need an x:data capable client to configure room", "Vi bezonas klienton kun x:data-funkcio por agordi la babilejon"}. -{"Configuration for ", "Agordo de "}. -{"Room title", "Babilejo-nomo"}. -{"Password", "Pasvorto"}. -{"Only moderators and participants are allowed to change subject in this room", "Nur moderigantoj kaj partoprenantoj rajtas ŝanĝi la temon en ĉi tiu babilejo"}. -{"Only moderators are allowed to change subject in this room", "Nur moderigantoj rajtas ŝanĝi la temon en ĉi tiu babilejo"}. -{"Visitors are not allowed to send messages to all occupants", "Vizitantoj ne rajtas sendi mesaĝojn al ĉiuj partoprenantoj"}. -{"Only occupants are allowed to send messages to the conference", "Nur partoprenantoj rajtas sendi mesaĝojn al la babilejo"}. -{"It is not allowed to send private messages to the conference", "Nur partoprenantoj rajtas sendi privatajn mesaĝojn al la babilejo"}. -{"Improper message type", "Malĝusta mesaĝo-tipo"}. -{"Nickname is already in use by another occupant", "Kaŝnomo estas jam uzata de alia partoprenanto"}. -{"Nickname is registered by another person", "Kaŝnomo estas registrita de alia persono"}. -{"It is not allowed to send private messages of type \"groupchat\"", "Malpermesas sendi mesaĝojn de tipo \"groupchat\""}. -{"Recipient is not in the conference room", "Ricevanto ne ĉeestas en la babilejo "}. -{"Only occupants are allowed to send queries to the conference", "Nur partoprenantoj rajtas sendi informmendojn al la babilejoj"}. -{"Queries to the conference members are not allowed in this room", "Malpermesas informmendoj al partoprenantoj en ĉi tiu babilejo"}. -{"You have been banned from this room", "Vi estas malpermesata en ĉi tiu babilejo"}. -{"Membership required to enter this room", "Membreco estas bezonata por eniri ĉi tiun babilejon"}. -{"Password required to enter this room", "Pasvorto estas bezonata por eniri ĉi tiun babilejon"}. -{"Incorrect password", "Nekorekta pasvorto"}. -{"Administrator privileges required", "Administrantaj rajtoj bezonata"}. -{"Moderator privileges required", "Moderantaj rajtoj bezonata"}. -{"JID ~s is invalid", "JID ~s estas nevalida"}. -{"Nickname ~s does not exist in the room", "Kaŝnomo ~s ne ekzistas en la babilejo"}. -{"Invalid affiliation: ~s", "Nevalida aparteneco: ~s"}. -{"Invalid role: ~s", "Nevalida rolo: ~s"}. -{"Owner privileges required", "Mastraj rajtoj bezonata"}. -{"private, ", "privata, "}. - -% mod_irc/mod_irc.erl -{"IRC Transport", "IRC-transportilo"}. -{"ejabberd IRC module", "ejabberd IRC-modulo"}. -{"You need an x:data capable client to configure mod_irc settings", "Vi bezonas klienton kun x:data-funkcio por agordi mod_irc"}. -{"Registration in mod_irc for ", "Registraĵo en mod_irc de "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Enmetu uzantnomon kaj enkodigoj kiujn vi volas uzi por konektoj al IRC-serviloj"}. -{"IRC Username", "IRC-kaŝnomo"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Se vi volas specifi diversajn enkodigojn por IRC-serviloj, kompletigu la jenan liston kun la formo '{\"irc-servilo\", \"enkodigo\"}'. Se ne specifita, ĉi tiu servilo uzas la enkodigo \"~s\""}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Ekzemplo: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"Encodings", "Enkodigoj"}. - -% web/ejabberd_web_admin.erl -{"ejabberd Web Admin", "ejabberd Teksaĵa Administro"}. -{"Administration", "Administro"}. -{"(Raw)", "(Kruda)"}. -{"Raw", "Kruda"}. -{"Users Last Activity", "Lasta aktiveco de uzanto"}. -{"Registered Users", "Registritaj uzantoj"}. -{"Offline Messages", "Liverontaj mesaĝoj"}. -{"Registered Users:", "Registritaj uzantoj:"}. -{"Online Users:", "Konektataj uzantoj:"}. -{"Outgoing s2s Connections:", "Elirantaj s-al-s-konektoj:"}. -{"Outgoing s2s Servers:", "Elirantaj s-al-s-serviloj"}. -{"No Data", "Neniu datumo"}. -{"Listened Ports", "Atentataj pordoj"}. -{"RPC Call Error", "Eraro de RPC-alvoko"}. -{"Database Tables at ", "Datumbaz-tabeloj je "}. -{"Backup of ", "Sekurkopio de "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "Rimarku ke ĉi tiuj elektebloj nur sekurkopias la propran Mnesia-datumbazon. Se vi uzas la ODBC-modulon, vi ankaŭ devas sekurkopii tiujn SQL-datumbazoj aparte."}. -{"Store binary backup:", "Konservu duuman sekurkopion:"}. -{"Restore binary backup immediately:", "Restaŭrigu duuman sekurkopion tuj:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Restaŭrigu duuman sekurkopion post sekvonta ejabberd-restarto"}. -{"Store plain text backup:", "Skribu sekurkopion en plata tekstdosiero"}. -{"Restore plain text backup immediately:", "Restaŭrigu sekurkopion el plata tekstdosiero tuj"}. -{"Statistics of ~p", "Statistikoj de ~p"}. -{"Uptime:", "Daŭro de funkciado"}. -{"CPU Time:", "CPU-tempo"}. -{"Transactions Commited:", "Transakcioj enmetitaj"}. -{"Transactions Aborted:", "Transakcioj nuligitaj"}. -{"Transactions Restarted:", "Transakcioj restartitaj"}. -{"Transactions Logged:", "Transakcioj protokolitaj"}. -{"Update ", "Ĝisdatigu "}. -{"Update plan", "Ĝisdatigo-plano"}. -{"Updated modules", "Ĝisdatigitaj moduloj"}. -{"Update script", "Ĝisdatigo-skripto"}. -{"Low level update script", "Bazanivela ĝisdatigo-skripto"}. -{"Script check", "Skript-kontrolo"}. -{"Users", "Uzantoj"}. -{"Nodes", "Nodoj"}. -{"Statistics", "Statistikoj"}. -{"Delete Selected", "Forigu elektata(j)n"}. -{"Submit", "Sendu"}. -{"~s access rule configuration", "Agordo de atingo-reguloj de ~s"}. -{"Node not found", "Nodo ne trovita"}. -{"Add New", "Aldonu novan"}. -{"Change Password", "Ŝanĝu pasvorton"}. -{"Connected Resources:", "Konektataj risurcoj:"}. -{"Password:", "Pasvorto:"}. -{"None", "Nenio"}. -{"Node ", "Nodo "}. -{"Restart", "Restartu"}. -{"Stop", "Haltigu"}. -{"Name", "Nomo"}. -{"Storage Type", "Konserv-tipo"}. -{"Size", "Grando"}. -{"Memory", "Memoro"}. -{"OK", "Bone"}. -{"Listened Ports at ", "Atentataj pordoj je "}. -{"Port", "Pordo"}. -{"Module", "Modulo"}. -{"Options", "Elektebloj"}. -{"Update", "Ĝisdatigu"}. -{"Delete", "Forigu"}. -{"Add User", "Aldonu Uzanton"}. -{"Last Activity", "Lasta aktiveco"}. -{"Never", "Neniam"}. -{"Time", "Tempo"}. -{"From", "De"}. -{"To", "Ĝis"}. -{"Packet", "Pakaĵo"}. -{"Roster", "Kontaktlisto"}. -{"Nickname", "Kaŝnomo"}. -{"Subscription", "Abono"}. -{"Pending", "Atendanta"}. -{"Groups", "Grupoj"}. -{"Remove", "Forigu"}. -{"User ", "Uzanto "}. -{"Roster of ", "Kontaktlisto de "}. -{"Online", "Konektata"}. -{"Validate", "Validigu"}. -{"Name:", "Nomo:"}. -{"Description:", "Priskribo:"}. -{"Members:", "Membroj:"}. -{"Displayed Groups:", "Montrataj grupoj:"}. -{"Group ", "Grupo "}. -{"Virtual Hosts", "Virtual-gastigoj"}. %ĉu eble pli bone "ŝajn-gastigoj"? -{"ejabberd virtual hosts", "ejabberd virtual-gastigoj"}. -{"Period: ", "Periodo: "}. -{"Last month", "Lasta monato"}. -{"Last year", "Lasta jaro"}. -{"All activity", "Ĉiu aktiveco"}. -{"Show Ordinary Table", "Montru ordinaran tabelon"}. -{"Show Integral Table", "Montru integran tabelon"}. -{"Host", "Gastigo"}. -{"Modules at ", "Moduloj je "}. -{"Start", "Startu"}. - -% mod_roster.erl -{"Submitted", "Sendita"}. -{"Bad format", "Malĝusta formo"}. -{"Add Jabber ID", "Aldonu Jabber ID"}. - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "Mesaĝo-atendovico de la senkonekta kontakto estas plena. La mesaĝo estas forĵetita"}. -{"~s's Offline Messages Queue", "Mesaĝo-atendovico de ~s"}. %FIXME: "message queue" is not really offline, neither are the messages.. -{"Offline Messages:", "Liverontaj mesaĝoj"}. - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "ejabberd SOCKS5 Bajtfluo modulo"}. - -% mod_shared_roster.erl -{"Shared Roster Groups", "Komuna Kontaktlist-grupo"}. - -% mod_announce.erl -{"Really delete message of the day?", "Ĉu vere forigi mesaĝon de la tago?"}. -{"Subject", "Temo"}. -{"Message body", "Teksto de mesaĝo"}. -{"No body provided for announce message", "Neniu teksto donita por anonc-mesaĝo"}. -{"Announcements", "Anoncoj"}. -{"Send announcement to all users", "Sendu anoncon al ĉiu uzanto"}. -{"Send announcement to all users on all hosts", "Sendu anoncon al ĉiu uzanto de ĉiu gastigo"}. -{"Send announcement to all online users", "Sendu anoncon al ĉiu konektata uzanto"}. -{"Send announcement to all online users on all hosts", "Sendu anoncon al ĉiu konektata uzanto de ĉiu gastigo"}. -{"Set message of the day and send to online users", "Enmetu mesaĝon de la tago kaj sendu al konektataj uzantoj"}. -{"Set message of the day on all hosts and send to online users", "Enmetu mesaĝon de la tago je ĉiu gastigo kaj sendu al konektataj uzantoj"}. -{"Update message of the day (don't send)", "Ŝanĝu mesaĝon de la tago (ne sendu)"}. -{"Update message of the day on all hosts (don't send)", "Ŝanĝu mesaĝon de la tago je ĉiu gastigo (ne sendu)"}. -{"Delete message of the day", "Forigu mesaĝo de la tago"}. -{"Delete message of the day on all hosts", "Forigu mesaĝo de la tago je ĉiu gastigo"}. - -% mod_adhoc.erl -{"Commands", "Ordonoj"}. -{"Ping", "Sondaĵo"}. %FIXME: perhaps there's a corresponding sound in Esperanto? -{"Pong", "Resondaĵo"}. - -% mod_muc/mod_muc_log.erl -{"Chatroom configuration modified", "Agordo de babilejo ŝanĝita"}. -{"joins the room", "eniras la babilejo"}. -{"leaves the room", "eliras la babilejo"}. -{"has been banned", "estas forbarita"}. -{"has been kicked", "estas forpelita"}. -{"has been kicked because of an affiliation change", "estas forpelita pro aparteneca ŝanĝo"}. -{"has been kicked because the room has been changed to members-only", "estas forpelita ĉar la babilejo fariĝis sole por membroj"}. -{"has been kicked because of a system shutdown", "estas forpelita pro sistem-haltigo"}. -{"is now known as", "nun nomiĝas"}. -{"Monday", "Lundo"}. -{"Tuesday", "Mardo"}. -{"Wednesday", "Merkredo"}. -{"Thursday", "Ĵaŭdo"}. -{"Friday", "Vendredo"}. -{"Saturday", "Sabato"}. -{"Sunday", "Dimanĉo"}. -{"January", "Januaro"}. -{"February", "Februaro"}. -{"March", "Marĉo"}. -{"April", "Aprilo"}. -{"May", "Majo"}. -{"June", "Junio"}. -{"July", "Julio"}. -{"August", "Aŭgusto"}. -{"September", "Septembro"}. -{"October", "Oktobro"}. -{"November", "Novembro"}. -{"December", "Decembro"}. -{"Room Configuration", "Babilejo-agordo"}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Agordo de atingo"}. +{"Access Control List Configuration","Agordo de atingokontrolo"}. +{"Access control lists","Atingokontrol-listoj"}. +{"Access Control Lists","Atingokontrol-listoj"}. +{"Access denied by service policy","Atingo rifuzita de serv-politiko"}. +{"Access rules","Atingo-reguloj"}. +{"Access Rules","Atingo-reguloj"}. +{"Action on user","Ago je uzanto"}. +{"Add Jabber ID","Aldonu Jabber ID"}. +{"Add New","Aldonu novan"}. +{"Add User","Aldonu Uzanton"}. +{"Administration","Administro"}. +{"Administration of ","Mastrumado de "}. +{"Administrator privileges required","Administrantaj rajtoj bezonata"}. +{"A friendly name for the node","Kromnomo por ĉi tiu nodo"}. +{"All activity","Ĉiu aktiveco"}. +{"Allow this JID to subscribe to this pubsub node?","Ĉu permesi ĉi tiun JID aboni al la jena PubAbo-nodo"}. +{"Allow users to change subject","Permesu uzantojn ŝanĝi la temon"}. +{"Allow users to query other users","Permesu uzantojn informpeti aliajn uzantojn"}. +{"Allow users to send invites","Permesu uzantojn sendi invitojn"}. +{"Allow users to send private messages","Permesu uzantojn sendi privatajn mesaĝojn"}. +{"Allow visitors to change nickname","Permesu al vizitantoj ŝanĝi siajn kaŝnomojn"}. +{"Allow visitors to send status text in presence updates","Permesu al vizitantoj sendi statmesaĝon en ĉeest-sciigoj"}. +{"All Users","Ĉiuj Uzantoj"}. +{"Announcements","Anoncoj"}. +{"anyone","iu ajn"}. +{"April","Aprilo"}. +{"August","Aŭgusto"}. +{"Backup","Faru Sekurkopion"}. +{"Backup Management","Mastrumado de sekurkopioj"}. +{"Backup of ","Sekurkopio de "}. +{"Backup to File at ","Faru sekurkopion je "}. +{"Bad format","Malĝusta formo"}. +{"Birthday","Naskiĝtago"}. +{"Change Password","Ŝanĝu pasvorton"}. +{"Change User Password","Ŝanĝu pasvorton de uzanto"}. +{"Chatroom configuration modified","Agordo de babilejo ŝanĝita"}. +{"Chatrooms","Babilejoj"}. +{"Choose a username and password to register with this server","Elektu uzantnomon kaj pasvorton por registri je ĉi tiu servilo"}. +{"Choose modules to stop","Elektu modulojn por fini"}. +{"Choose storage type of tables","Elektu konserv-tipon de tabeloj"}. +{"Choose whether to approve this entity's subscription.","Elektu ĉu permesi la abonon de ĉi tiu ento"}. +{"City","Urbo"}. +{"Commands","Ordonoj"}. +{"Conference room does not exist","Babilejo ne ekzistas"}. +{"Configuration","Agordo"}. +{"Configuration for ","Agordo de "}. +{"Connected Resources:","Konektataj risurcoj:"}. +{"Country","Lando"}. +{"CPU Time:","CPU-tempo"}. +{"Database","Datumbazo"}. +{"Database Tables at ","Datumbaz-tabeloj je "}. +{"Database Tables Configuration at ","Agordo de datumbaz-tabeloj je "}. +{"December","Decembro"}. +{"Default users as participants","Kutime farigu uzantojn kiel partpoprenantoj"}. +{"Delete","Forigu"}. +{"Delete message of the day","Forigu mesaĝo de la tago"}. +{"Delete message of the day on all hosts","Forigu mesaĝo de la tago je ĉiu gastigo"}. +{"Delete Selected","Forigu elektata(j)n"}. +{"Delete User","Forigu Uzanton"}. +{"Deliver event notifications","Liveru event-sciigojn"}. +{"Deliver payloads with event notifications","Liveru aĵojn de event-sciigoj"}. +{"Description:","Priskribo:"}. +{"Disc only copy","Nur disk-kopio"}. +{"Displayed Groups:","Montrataj grupoj:"}. +{"Dump Backup to Text File at ","Skribu sekurkopion en plata teksto al "}. +{"Dump to Text File","Skribu en plata tekst-dosiero"}. +{"Edit Properties","Redaktu atributojn"}. +{"ejabberd IRC module","ejabberd IRC-modulo"}. +{"ejabberd MUC module","ejabberd MUC-modulo"}. +{"ejabberd Publish-Subscribe module","ejabberd Public-Abonada modulo"}. +{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bajtfluo modulo"}. +{"ejabberd vCard module","ejabberd vCard-modulo"}. +{"ejabberd virtual hosts","ejabberd virtual-gastigoj"}. +{"ejabberd Web Admin","ejabberd Teksaĵa Administro"}. +{"Email","Retpoŝto"}. +{"Enable logging","Ŝaltu protokoladon"}. +{"Encodings","Enkodigoj"}. +{"End User Session","Haltigu Uzant-seancon"}. +{"Enter list of {Module, [Options]}","Enmetu liston de {Modulo, [Elektebloj]}"}. +{"Enter nickname you want to register","Enmetu kaŝnomon kiun vi volas registri"}. +{"Enter path to backup file","Enmetu vojon por sekurkopio"}. +{"Enter path to jabberd1.4 spool dir","Enmetu vojon al jabberd1.4-uzantdosierujo"}. +{"Enter path to jabberd1.4 spool file","Enmetu vojon al jabberd1.4-uzantdosiero"}. +{"Enter path to text file","Enmetu vojon al plata teksto"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Enmetu uzantnomon kaj enkodigoj kiujn vi volas uzi por konektoj al IRC-serviloj"}. +{"Erlang Jabber Server","Erlang-a Jabber-Servilo"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Ekzemplo: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","Lasta Nomo"}. +{"February","Februaro"}. +{"Fill in fields to search for any matching Jabber User","Kompletigu la formon por serĉi rekonata Jabber-uzanto"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Kompletigu la formon por serĉi rekonata Jabber-uzanto (Aldonu * je la fino de la kampo por rekoni subĉenon"}. +{"Friday","Vendredo"}. +{"From","De"}. +{"From ~s","De ~s"}. +{"Full Name","Plena Nomo"}. +{"Get Number of Online Users","Montru nombron de konektataj uzantoj"}. +{"Get Number of Registered Users","Montru nombron de registritaj uzantoj"}. +{"Get User Last Login Time","Montru tempon de lasta ensaluto"}. +{"Get User Password","Montru pasvorton de uzanto"}. +{"Get User Statistics","Montru statistikojn de uzanto"}. +{"Group ","Grupo "}. +{"Groups","Grupoj"}. +{"has been banned","estas forbarita"}. +{"has been kicked because of an affiliation change","estas forpelita pro aparteneca ŝanĝo"}. +{"has been kicked because of a system shutdown","estas forpelita pro sistem-haltigo"}. +{"has been kicked because the room has been changed to members-only","estas forpelita ĉar la babilejo fariĝis sole por membroj"}. +{"has been kicked","estas forpelita"}. +{" has set the subject to: "," ŝanĝis la temon al: "}. +{"Host","Gastigo"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Se vi volas specifi diversajn enkodigojn por IRC-serviloj, kompletigu la jenan liston kun la formo '{\"irc-servilo\", \"enkodigo\"}'. Se ne specifita, ĉi tiu servilo uzas la enkodigo \"~s\""}. +{"Import Directory","Importu dosierujo"}. +{"Import File","Importu dosieron"}. +{"Import User from File at ","Importu uzanton de dosiero el "}. +{"Import Users from Dir at ","Importu uzantojn de dosierujo ĉe "}. +{"Import Users From jabberd 1.4 Spool Files","Importu uzantojn de jabberd1.4-uzantdosieroj"}. +{"Improper message type","Malĝusta mesaĝo-tipo"}. +{"Incorrect password","Nekorekta pasvorto"}. +{"Invalid affiliation: ~s","Nevalida aparteneco: ~s"}. +{"Invalid role: ~s","Nevalida rolo: ~s"}. +{"IP addresses","IP-adresoj"}. +{"IRC Transport","IRC-transportilo"}. +{"IRC Username","IRC-kaŝnomo"}. +{"is now known as","nun nomiĝas"}. +{"It is not allowed to send private messages","Ne estas permesata sendi privatajn mesaĝojn"}. +{"It is not allowed to send private messages of type \"groupchat\"","Malpermesas sendi mesaĝojn de tipo \"groupchat\""}. +{"It is not allowed to send private messages to the conference","Nur partoprenantoj rajtas sendi privatajn mesaĝojn al la babilejo"}. +{"Jabber ID","Jabber ID"}. +{"January","Januaro"}. +{"JID ~s is invalid","JID ~s estas nevalida"}. +{"joins the room","eniras la babilejo"}. +{"July","Julio"}. +{"June","Junio"}. +{"Last Activity","Lasta aktiveco"}. +{"Last login","Lasta ensaluto"}. +{"Last month","Lasta monato"}. +{"Last year","Lasta jaro"}. +{"leaves the room","eliras la babilejo"}. +{"Listened Ports at ","Atentataj pordoj je "}. +{"Listened Ports","Atentataj pordoj"}. +{"List of modules to start","Listo de moduloj por starti"}. +{"Low level update script","Bazanivela ĝisdatigo-skripto"}. +{"Make participants list public","Farigu partoprento-liston publika"}. +{"Make room members-only","Farigu babilejon sole por membroj"}. +{"Make room moderated","Farigu babilejon moderigata"}. +{"Make room password protected","Farigu babilejon protektata per pasvorto"}. +{"Make room persistent","Farigu babilejon daŭra"}. +{"Make room public searchable","Farigu babilejon publike trovebla"}. +{"March","Marĉo"}. +{"Maximum Number of Occupants","Limigo de nombro de partoprenantoj"}. +{"Max # of items to persist","Maksimuma kiomo de eroj en konservado"}. +{"Max payload size in bytes","Maksimuma aĵo-grando je bajtoj"}. +{"May","Majo"}. +{"Membership required to enter this room","Membreco estas bezonata por eniri ĉi tiun babilejon"}. +{"Members:","Membroj:"}. +{"Memory","Memoro"}. +{"Message body","Teksto de mesaĝo"}. +{"Middle Name","Meza Nomo"}. +{"Moderator privileges required","Moderantaj rajtoj bezonata"}. +{"moderators only","moderantoj sole"}. +{"Module","Modulo"}. +{"Modules at ","Moduloj je "}. +{"Modules","Moduloj"}. +{"Monday","Lundo"}. +{"Name:","Nomo:"}. +{"Name","Nomo"}. +{"Never","Neniam"}. +{"Nickname is already in use by another occupant","Kaŝnomo estas jam uzata de alia partoprenanto"}. +{"Nickname is registered by another person","Kaŝnomo estas registrita de alia persono"}. +{"Nickname","Kaŝnomo"}. +{"Nickname Registration at ","Kaŝnomo-registrado je "}. +{"Nickname ~s does not exist in the room","Kaŝnomo ~s ne ekzistas en la babilejo"}. +{"No body provided for announce message","Neniu teksto donita por anonc-mesaĝo"}. +{"No Data","Neniu datumo"}. +{"Node ID","Nodo ID"}. +{"Node ","Nodo "}. +{"Node not found","Nodo ne trovita"}. +{"Nodes","Nodoj"}. +{"No limit","Neniu limigo"}. +{"None","Nenio"}. +{"No resource provided","Neniu risurco donita"}. +{"Notify subscribers when items are removed from the node","Sciigu abonantoj kiam eroj estas forigita de la nodo"}. +{"Notify subscribers when the node configuration changes","Sciigu abonantoj kiam la agordo de la nodo ŝanĝas"}. +{"Notify subscribers when the node is deleted","Sciigu abonantoj kiam la nodo estas forigita"}. +{"November","Novembro"}. +{"Number of occupants","Nombro de ĉeestantoj"}. +{"Number of online users","Nombro de konektataj uzantoj"}. +{"Number of registered users","Nombro de registritaj uzantoj"}. +{"October","Oktobro"}. +{"Offline Messages:","Liverontaj mesaĝoj"}. +{"Offline Messages","Liverontaj mesaĝoj"}. +{"OK","Bone"}. +{"Online","Konektata"}. +{"Online Users:","Konektataj uzantoj:"}. +{"Online Users","Konektataj Uzantoj"}. +{"Only deliver notifications to available users","Nur liveru sciigojn al konektataj uzantoj"}. +{"Only moderators and participants are allowed to change subject in this room","Nur moderigantoj kaj partoprenantoj rajtas ŝanĝi la temon en ĉi tiu babilejo"}. +{"Only moderators are allowed to change subject in this room","Nur moderigantoj rajtas ŝanĝi la temon en ĉi tiu babilejo"}. +{"Only occupants are allowed to send messages to the conference","Nur partoprenantoj rajtas sendi mesaĝojn al la babilejo"}. +{"Only occupants are allowed to send queries to the conference","Nur partoprenantoj rajtas sendi informmendojn al la babilejoj"}. +{"Only service administrators are allowed to send service messages","Nur servo-administrantoj rajtas sendi serv-mesaĝojn"}. +{"Options","Elektebloj"}. +{"Organization Name","Organiz-nomo"}. +{"Organization Unit","Organiz-parto"}. +{"Outgoing s2s Connections:","Elirantaj s-al-s-konektoj:"}. +{"Outgoing s2s Connections","Elirantaj s-al-s-konektoj"}. +{"Outgoing s2s Servers:","Elirantaj s-al-s-serviloj"}. +{"Owner privileges required","Mastraj rajtoj bezonata"}. +{"Packet","Pakaĵo"}. +{"Password:","Pasvorto:"}. +{"Password","Pasvorto"}. +{"Password required to enter this room","Pasvorto estas bezonata por eniri ĉi tiun babilejon"}. +{"Password Verification","Pasvortkontrolo"}. +{"Path to Dir","Vojo al dosierujo"}. +{"Path to File","Voje de dosiero"}. +{"Pending","Atendanta"}. +{"Period: ","Periodo: "}. +{"Persist items to storage","Savu erojn en konservado"}. +{"Ping","Sondaĵo"}. +{"Pong","Resondaĵo"}. +{"Port","Pordo"}. +{"Present real JIDs to","Montru verajn JID-ojn al"}. +{"private, ","privata, "}. +{"Publish-Subscribe","Public-Abonado"}. +{"PubSub subscriber request","PubAbo abonpeto"}. +{"Queries to the conference members are not allowed in this room","Malpermesas informmendoj al partoprenantoj en ĉi tiu babilejo"}. +{"RAM and disc copy","RAM- kaj disk-kopio"}. +{"RAM copy","RAM-kopio"}. +{"(Raw)","(Kruda)"}. +{"Raw","Kruda"}. +{"Really delete message of the day?","Ĉu vere forigi mesaĝon de la tago?"}. +{"Recipient is not in the conference room","Ricevanto ne ĉeestas en la babilejo "}. +{"Registered Users:","Registritaj uzantoj:"}. +{"Registered Users","Registritaj uzantoj"}. +{"Registration in mod_irc for ","Registraĵo en mod_irc de "}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Rimarku ke ĉi tiuj elektebloj nur sekurkopias la propran Mnesia-datumbazon. Se vi uzas la ODBC-modulon, vi ankaŭ devas sekurkopii tiujn SQL-datumbazoj aparte."}. +{"Remote copy","Fora kopio"}. +{"Remove","Forigu"}. +{"Remove User","Forigu uzanton"}. +{"Replaced by new connection","Anstataŭigita je nova konekto"}. +{"Resources","Risurcoj"}. +{"Restart","Restartu"}. +{"Restart Service","Restartu Servon"}. +{"Restore Backup from File at ","Restaŭrigu de dosiero el "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Restaŭrigu duuman sekurkopion post sekvonta ejabberd-restarto"}. +{"Restore binary backup immediately:","Restaŭrigu duuman sekurkopion tuj:"}. +{"Restore plain text backup immediately:","Restaŭrigu sekurkopion el plata tekstdosiero tuj"}. +{"Restore","Restaŭru"}. +{"Room Configuration","Babilejo-agordo"}. +{"Room creation is denied by service policy","Ĉi tiu serv-politiko ne permesas babilejo-kreadon"}. +{"Room title","Babilejo-nomo"}. +{"Roster groups allowed to subscribe","Kontaktlist-grupoj kiuj rajtas aboni"}. +{"Roster","Kontaktlisto"}. +{"Roster of ","Kontaktlisto de "}. +{"Roster size","Kontaktlist-grando"}. +{"RPC Call Error","Eraro de RPC-alvoko"}. +{"Running Nodes","Funkciantaj Nodoj"}. +{"~s access rule configuration","Agordo de atingo-reguloj de ~s"}. +{"Saturday","Sabato"}. +{"Script check","Skript-kontrolo"}. +{"Search Results for ","Serĉ-rezultoj de "}. +{"Search users in ","Serĉu uzantojn en "}. +{"Send announcement to all online users on all hosts","Sendu anoncon al ĉiu konektata uzanto de ĉiu gastigo"}. +{"Send announcement to all online users","Sendu anoncon al ĉiu konektata uzanto"}. +{"Send announcement to all users on all hosts","Sendu anoncon al ĉiu uzanto de ĉiu gastigo"}. +{"Send announcement to all users","Sendu anoncon al ĉiu uzanto"}. +{"September","Septembro"}. +{"Set message of the day and send to online users","Enmetu mesaĝon de la tago kaj sendu al konektataj uzantoj"}. +{"Set message of the day on all hosts and send to online users","Enmetu mesaĝon de la tago je ĉiu gastigo kaj sendu al konektataj uzantoj"}. +{"Shared Roster Groups","Komuna Kontaktlist-grupo"}. +{"Show Integral Table","Montru integran tabelon"}. +{"Show Ordinary Table","Montru ordinaran tabelon"}. +{"Shut Down Service","Haltigu Servon"}. +{"~s invites you to the room ~s","~s invitas vin al la babilejo ~s"}. +{"Size","Grando"}. +{"Specified nickname is already registered","Donita kaŝnomo jam estas registrita"}. +{"Specify the access model","Specifu atingo-modelon"}. +{"Specify the publisher model","Enmetu publikadan modelon"}. +{"~s's Offline Messages Queue","Mesaĝo-atendovico de ~s"}. +{"Start Modules at ","Startu modulojn je "}. +{"Start Modules","Startu Modulojn"}. +{"Start","Startu"}. +{"Statistics of ~p","Statistikoj de ~p"}. +{"Statistics","Statistikoj"}. +{"Stop","Haltigu"}. +{"Stop Modules at ","Haltigu modulojn je "}. +{"Stop Modules","Haltigu Modulojn"}. +{"Stopped Nodes","Neaktivaj Nodoj"}. +{"Storage Type","Konserv-tipo"}. +{"Store binary backup:","Konservu duuman sekurkopion:"}. +{"Store plain text backup:","Skribu sekurkopion en plata tekstdosiero"}. +{"Subject","Temo"}. +{"Submit","Sendu"}. +{"Submitted","Sendita"}. +{"Subscriber Address","Abonanta adreso"}. +{"Subscription","Abono"}. +{"Sunday","Dimanĉo"}. +{"the password is","la pasvorto estas"}. +{"This participant is kicked from the room because he sent an error message","Ĉi tiu partoprenanta estas forpelata de la babilejo pro sendado de erar-mesaĝo"}. +{"This participant is kicked from the room because he sent an error message to another participant","Ĉi tiu partoprenanto estas forpelata de la babilejo pro sendo de erar-mesaĝo al alia partoprenanto"}. +{"This participant is kicked from the room because he sent an error presence","Ĉi tiu partoprenanto estas forpelata de la babilejo pro sendo de erar-ĉeesto"}. +{"This room is not anonymous","Ĉi tiu babilejo ne estas anonima"}. +{"Thursday","Ĵaŭdo"}. +{"Time delay","Prokrasto"}. +{"Time","Tempo"}. +{"To","Ĝis"}. +{"To ~s","Al ~s"}. +{"Traffic rate limit is exceeded","Trafikrapida limigo superita"}. +{"Transactions Aborted:","Transakcioj nuligitaj"}. +{"Transactions Commited:","Transakcioj enmetitaj"}. +{"Transactions Logged:","Transakcioj protokolitaj"}. +{"Transactions Restarted:","Transakcioj restartitaj"}. +{"Tuesday","Mardo"}. +{"Updated modules","Ĝisdatigitaj moduloj"}. +{"Update ","Ĝisdatigu "}. +{"Update","Ĝisdatigu"}. +{"Update message of the day (don't send)","Ŝanĝu mesaĝon de la tago (ne sendu)"}. +{"Update message of the day on all hosts (don't send)","Ŝanĝu mesaĝon de la tago je ĉiu gastigo (ne sendu)"}. +{"Update plan","Ĝisdatigo-plano"}. +{"Update script","Ĝisdatigo-skripto"}. +{"Uptime:","Daŭro de funkciado"}. +{"Use of STARTTLS required","Uzo de STARTTLS bezonata"}. +{"User Management","Uzanto-administrado"}. +{"Users are not allowed to register accounts so fast","Ne estas permesata al uzantoj registri tiel rapide"}. +{"Users Last Activity","Lasta aktiveco de uzanto"}. +{"Users","Uzantoj"}. +{"User ","Uzanto "}. +{"User","Uzanto"}. +{"Validate","Validigu"}. +{"vCard User Search","Serĉado de vizitkartoj"}. +{"Virtual Hosts","Virtual-gastigoj"}. +{"Visitors are not allowed to change their nicknames in this room","Ne estas permesata al vizitantoj ŝanĝi siajn kaŝnomojn en ĉi tiu ĉambro"}. +{"Visitors are not allowed to send messages to all occupants","Vizitantoj ne rajtas sendi mesaĝojn al ĉiuj partoprenantoj"}. +{"Wednesday","Merkredo"}. +{"When to send the last published item","Kiam sendi la laste publicitan eron"}. +{"Whether to allow subscriptions","Ĉu permesi aboni"}. +{"You have been banned from this room","Vi estas malpermesata en ĉi tiu babilejo"}. +{"You must fill in field \"Nickname\" in the form","Vi devas kompletigi la \"Kaŝnomo\" kampon"}. +{"You need an x:data capable client to configure mod_irc settings","Vi bezonas klienton kun x:data-funkcio por agordi mod_irc"}. +{"You need an x:data capable client to configure room","Vi bezonas klienton kun x:data-funkcio por agordi la babilejon"}. +{"You need an x:data capable client to register nickname","Vi bezonas klienton kun x:data-funkcio por registri kaŝnomon"}. +{"You need an x:data capable client to search","Vi bezonas klienton kun x:data-funkcio por serĉado"}. +{"Your contact offline message queue is full. The message has been discarded.","Mesaĝo-atendovico de la senkonekta kontakto estas plena. La mesaĝo estas forĵetita"}. diff --git a/src/msgs/eo.po b/src/msgs/eo.po new file mode 100644 index 000000000..8b4d55693 --- /dev/null +++ b/src/msgs/eo.po @@ -0,0 +1,1493 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Andreas van Cranenburgh\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Esperanto\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "Uzo de STARTTLS bezonata" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Neniu risurco donita" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Anstataŭigita je nova konekto" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Ordonoj" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Sondaĵo" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Resondaĵo" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Ĉu vere forigi mesaĝon de la tago?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Temo" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Teksto de mesaĝo" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "Neniu teksto donita por anonc-mesaĝo" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Anoncoj" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Sendu anoncon al ĉiu uzanto" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Sendu anoncon al ĉiu uzanto de ĉiu gastigo" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Sendu anoncon al ĉiu konektata uzanto" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "Sendu anoncon al ĉiu konektata uzanto de ĉiu gastigo" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Enmetu mesaĝon de la tago kaj sendu al konektataj uzantoj" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Enmetu mesaĝon de la tago je ĉiu gastigo kaj sendu al konektataj uzantoj" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Ŝanĝu mesaĝon de la tago (ne sendu)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Ŝanĝu mesaĝon de la tago je ĉiu gastigo (ne sendu)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Forigu mesaĝo de la tago" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Forigu mesaĝo de la tago je ĉiu gastigo" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Agordo" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Datumbazo" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Startu Modulojn" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Haltigu Modulojn" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Faru Sekurkopion" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Restaŭru" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Skribu en plata tekst-dosiero" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Importu dosieron" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Importu dosierujo" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Restartu Servon" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Haltigu Servon" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Aldonu Uzanton" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Forigu Uzanton" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Haltigu Uzant-seancon" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Montru pasvorton de uzanto" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Ŝanĝu pasvorton de uzanto" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Montru tempon de lasta ensaluto" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Montru statistikojn de uzanto" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Montru nombron de registritaj uzantoj" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Montru nombron de konektataj uzantoj" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Atingokontrol-listoj" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Atingo-reguloj" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Uzanto-administrado" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Konektataj Uzantoj" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Ĉiuj Uzantoj" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Elirantaj s-al-s-konektoj" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Funkciantaj Nodoj" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Neaktivaj Nodoj" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Moduloj" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Mastrumado de sekurkopioj" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Importu uzantojn de jabberd1.4-uzantdosieroj" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "Al ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "De ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Agordo de datumbaz-tabeloj je " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Elektu konserv-tipon de tabeloj" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Nur disk-kopio" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "RAM- kaj disk-kopio" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "RAM-kopio" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Fora kopio" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Haltigu modulojn je " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Elektu modulojn por fini" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Startu modulojn je " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Enmetu liston de {Modulo, [Elektebloj]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Listo de moduloj por starti" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Faru sekurkopion je " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Enmetu vojon por sekurkopio" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Voje de dosiero" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Restaŭrigu de dosiero el " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Skribu sekurkopion en plata teksto al " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Enmetu vojon al plata teksto" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Importu uzanton de dosiero el " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Enmetu vojon al jabberd1.4-uzantdosiero" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Importu uzantojn de dosierujo ĉe " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Enmetu vojon al jabberd1.4-uzantdosierujo" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Vojo al dosierujo" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Prokrasto" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Agordo de atingokontrolo" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Atingokontrol-listoj" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Agordo de atingo" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Atingo-reguloj" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Pasvorto" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Pasvortkontrolo" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Nombro de registritaj uzantoj" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Nombro de konektataj uzantoj" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Neniam" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Konektata" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Lasta ensaluto" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Kontaktlist-grando" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "IP-adresoj" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Risurcoj" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Mastrumado de " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Ago je uzanto" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Redaktu atributojn" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Forigu uzanton" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Atingo rifuzita de serv-politiko" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "IRC-transportilo" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "ejabberd IRC-modulo" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "Vi bezonas klienton kun x:data-funkcio por agordi mod_irc" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Registraĵo en mod_irc de " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Enmetu uzantnomon kaj enkodigoj kiujn vi volas uzi por konektoj al IRC-" +"serviloj" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "IRC-kaŝnomo" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Se vi volas specifi diversajn enkodigojn por IRC-serviloj, kompletigu la " +"jenan liston kun la formo '{\"irc-servilo\", \"enkodigo\"}'. Se ne " +"specifita, ĉi tiu servilo uzas la enkodigo \"~s\"" + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Ekzemplo: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-" +"1\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Enkodigoj" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "Nur servo-administrantoj rajtas sendi serv-mesaĝojn" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "Ĉi tiu serv-politiko ne permesas babilejo-kreadon" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "Babilejo ne ekzistas" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Babilejoj" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "Vi bezonas klienton kun x:data-funkcio por registri kaŝnomon" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Kaŝnomo-registrado je " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Enmetu kaŝnomon kiun vi volas registri" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Kaŝnomo" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "Donita kaŝnomo jam estas registrita" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Vi devas kompletigi la \"Kaŝnomo\" kampon" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "ejabberd MUC-modulo" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Agordo de babilejo ŝanĝita" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "eniras la babilejo" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "eliras la babilejo" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "estas forbarita" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "estas forpelita" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "estas forpelita pro aparteneca ŝanĝo" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "estas forpelita ĉar la babilejo fariĝis sole por membroj" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "estas forpelita pro sistem-haltigo" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "nun nomiĝas" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " ŝanĝis la temon al: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "Lundo" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "Mardo" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "Merkredo" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "Ĵaŭdo" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "Vendredo" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "Sabato" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "Dimanĉo" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "Januaro" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "Februaro" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "Marĉo" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "Aprilo" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "Majo" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "Junio" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "Julio" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "Aŭgusto" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "Septembro" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "Oktobro" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "Novembro" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "Decembro" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Babilejo-agordo" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Babilejo-nomo" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Trafikrapida limigo superita" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" +"Ĉi tiu partoprenanta estas forpelata de la babilejo pro sendado de erar-" +"mesaĝo" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Nur partoprenantoj rajtas sendi privatajn mesaĝojn al la babilejo" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Malĝusta mesaĝo-tipo" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Ĉi tiu partoprenanto estas forpelata de la babilejo pro sendo de erar-mesaĝo " +"al alia partoprenanto" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "Malpermesas sendi mesaĝojn de tipo \"groupchat\"" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "Ricevanto ne ĉeestas en la babilejo " + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Nur partoprenantoj rajtas sendi mesaĝojn al la babilejo" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "Ne estas permesata sendi privatajn mesaĝojn" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Nur partoprenantoj rajtas sendi informmendojn al la babilejoj" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "Malpermesas informmendoj al partoprenantoj en ĉi tiu babilejo" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "privata, " + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "" +"Nur moderigantoj kaj partoprenantoj rajtas ŝanĝi la temon en ĉi tiu babilejo" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Nur moderigantoj rajtas ŝanĝi la temon en ĉi tiu babilejo" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "Vizitantoj ne rajtas sendi mesaĝojn al ĉiuj partoprenantoj" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" +"Ĉi tiu partoprenanto estas forpelata de la babilejo pro sendo de erar-ĉeesto" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "" +"Ne estas permesata al vizitantoj ŝanĝi siajn kaŝnomojn en ĉi tiu ĉambro" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "Kaŝnomo estas jam uzata de alia partoprenanto" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "Kaŝnomo estas registrita de alia persono" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Vi estas malpermesata en ĉi tiu babilejo" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "Membreco estas bezonata por eniri ĉi tiun babilejon" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Ĉi tiu babilejo ne estas anonima" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Pasvorto estas bezonata por eniri ĉi tiun babilejon" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Nekorekta pasvorto" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Administrantaj rajtoj bezonata" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Moderantaj rajtoj bezonata" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "JID ~s estas nevalida" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "Kaŝnomo ~s ne ekzistas en la babilejo" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Nevalida aparteneco: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Nevalida rolo: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Mastraj rajtoj bezonata" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Agordo de " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Priskribo:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Farigu babilejon daŭra" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Farigu babilejon publike trovebla" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Farigu partoprento-liston publika" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Farigu babilejon protektata per pasvorto" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Limigo de nombro de partoprenantoj" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Neniu limigo" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Montru verajn JID-ojn al" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "moderantoj sole" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "iu ajn" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Farigu babilejon sole por membroj" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Farigu babilejon moderigata" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Kutime farigu uzantojn kiel partpoprenantoj" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Permesu uzantojn ŝanĝi la temon" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Permesu uzantojn sendi privatajn mesaĝojn" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Permesu uzantojn informpeti aliajn uzantojn" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Permesu uzantojn sendi invitojn" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "Permesu al vizitantoj sendi statmesaĝon en ĉeest-sciigoj" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Permesu al vizitantoj ŝanĝi siajn kaŝnomojn" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Ŝaltu protokoladon" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "Vi bezonas klienton kun x:data-funkcio por agordi la babilejon" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Nombro de ĉeestantoj" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s invitas vin al la babilejo ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "la pasvorto estas" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "" +"Mesaĝo-atendovico de la senkonekta kontakto estas plena. La mesaĝo estas " +"forĵetita" + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "Mesaĝo-atendovico de ~s" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Sendita" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Tempo" + +#: mod_offline.erl:507 +msgid "From" +msgstr "De" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Ĝis" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Pakaĵo" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Forigu elektata(j)n" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Liverontaj mesaĝoj" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "ejabberd SOCKS5 Bajtfluo modulo" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Public-Abonado" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "ejabberd Public-Abonada modulo" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "PubAbo abonpeto" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Elektu ĉu permesi la abonon de ĉi tiu ento" + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "Nodo ID" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Abonanta adreso" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Ĉu permesi ĉi tiun JID aboni al la jena PubAbo-nodo" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Liveru aĵojn de event-sciigoj" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Liveru event-sciigojn" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Sciigu abonantoj kiam la agordo de la nodo ŝanĝas" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Sciigu abonantoj kiam la nodo estas forigita" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Sciigu abonantoj kiam eroj estas forigita de la nodo" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Savu erojn en konservado" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "Kromnomo por ĉi tiu nodo" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Maksimuma kiomo de eroj en konservado" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Ĉu permesi aboni" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Specifu atingo-modelon" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Kontaktlist-grupoj kiuj rajtas aboni" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Enmetu publikadan modelon" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Maksimuma aĵo-grando je bajtoj" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Kiam sendi la laste publicitan eron" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Nur liveru sciigojn al konektataj uzantoj" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "Elektu uzantnomon kaj pasvorton por registri je ĉi tiu servilo" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "Ne estas permesata al uzantoj registri tiel rapide" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Nenio" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Abono" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Atendanta" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Grupoj" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Validigu" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Forigu" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Kontaktlisto de " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Malĝusta formo" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Aldonu Jabber ID" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Kontaktlisto" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Komuna Kontaktlist-grupo" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Aldonu novan" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Nomo:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Priskribo:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Membroj:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Montrataj grupoj:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Grupo " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Sendu" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Erlang-a Jabber-Servilo" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Naskiĝtago" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Urbo" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "Lando" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "Retpoŝto" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Lasta Nomo" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Kompletigu la formon por serĉi rekonata Jabber-uzanto (Aldonu * je la fino " +"de la kampo por rekoni subĉenon" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Plena Nomo" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Meza Nomo" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Nomo" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Organiz-nomo" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Organiz-parto" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Serĉu uzantojn en " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Uzanto" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "Vi bezonas klienton kun x:data-funkcio por serĉado" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "Serĉado de vizitkartoj" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "ejabberd vCard-modulo" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Serĉ-rezultoj de " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Kompletigu la formon por serĉi rekonata Jabber-uzanto" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "ejabberd Teksaĵa Administro" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Administro" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Virtual-gastigoj" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Nodoj" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Statistikoj" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Uzantoj" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Lasta aktiveco" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Kruda)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Kruda" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "Agordo de atingo-reguloj de ~s" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "ejabberd virtual-gastigoj" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Lasta aktiveco de uzanto" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Periodo: " + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Lasta monato" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Lasta jaro" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Ĉiu aktiveco" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Montru ordinaran tabelon" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Montru integran tabelon" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Nodo ne trovita" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Gastigo" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Registritaj uzantoj" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Liverontaj mesaĝoj" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Registritaj uzantoj:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Konektataj uzantoj:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Elirantaj s-al-s-konektoj:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Elirantaj s-al-s-serviloj" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Ŝanĝu pasvorton" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Uzanto " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Konektataj risurcoj:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Pasvorto:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Neniu datumo" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Nodo " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Atentataj pordoj" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Ĝisdatigu" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Restartu" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Haltigu" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "Eraro de RPC-alvoko" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Datumbaz-tabeloj je " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Konserv-tipo" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Grando" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Memoro" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Sekurkopio de " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Rimarku ke ĉi tiuj elektebloj nur sekurkopias la propran Mnesia-datumbazon. " +"Se vi uzas la ODBC-modulon, vi ankaŭ devas sekurkopii tiujn SQL-datumbazoj " +"aparte." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Konservu duuman sekurkopion:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "Bone" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Restaŭrigu duuman sekurkopion tuj:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "Restaŭrigu duuman sekurkopion post sekvonta ejabberd-restarto" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Skribu sekurkopion en plata tekstdosiero" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Restaŭrigu sekurkopion el plata tekstdosiero tuj" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Atentataj pordoj je " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Moduloj je " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "Statistikoj de ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Daŭro de funkciado" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "CPU-tempo" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Transakcioj enmetitaj" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Transakcioj nuligitaj" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Transakcioj restartitaj" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Transakcioj protokolitaj" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Ĝisdatigu " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Ĝisdatigo-plano" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Ĝisdatigitaj moduloj" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Ĝisdatigo-skripto" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Bazanivela ĝisdatigo-skripto" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Skript-kontrolo" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Pordo" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Modulo" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Elektebloj" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Forigu" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Startu" + +#~ msgid "You must fill in field \"nick\" in the form" +#~ msgstr "Vi devas enmeti kampon \"kaŝnomo\"" diff --git a/src/msgs/es.msg b/src/msgs/es.msg index dc19f5770..1a30803f7 100644 --- a/src/msgs/es.msg +++ b/src/msgs/es.msg @@ -1,383 +1,343 @@ -% $Id$ -% Language: Spanish (castellano) -% Author: Badlop - -% jlib.hrl -{"No resource provided", "No se ha proporcionado recurso"}. - -% mod_configure.erl -{"Choose storage type of tables", "Selecciona tipo de almacenamiento de las tablas"}. -{"RAM copy", "Copia en RAM"}. -{"RAM and disc copy", "Copia en RAM y disco"}. -{"Disc only copy", "Copia en disco solamente"}. -{"Remote copy", "Copia remota"}. -{"Stop Modules at ", "Detener módulos en "}. -{"Choose modules to stop", "Selecciona módulos a detener"}. -{"Start Modules at ", "Iniciar módulos en "}. -{"Enter list of {Module, [Options]}", "Introduce lista de {módulo, [opciones]}"}. -{"List of modules to start", "Lista de módulos a iniciar"}. -{"Backup to File at ", "Guardar copia de seguridad en fichero en "}. -{"Enter path to backup file", "Introduce ruta al fichero de copia de seguridad"}. -{"Path to File", "Ruta al fichero"}. -{"Restore Backup from File at ", "Restaura copia de seguridad desde el fichero en "}. -{"Dump Backup to Text File at ", "Exporta copia de seguridad a fichero de texto en "}. -{"Enter path to text file", "Introduce ruta al fichero de texto"}. -{"Import User from File at ", "Importa usuario desde fichero en "}. -{"Enter path to jabberd1.4 spool file", "Introduce ruta al fichero jabberd1.4 spool"}. -{"Import Users from Dir at ", "Importar usuarios desde el directorio en "}. -{"Enter path to jabberd1.4 spool dir", "Introduce la ruta al directorio de jabberd1.4 spools"}. -{"Path to Dir", "Ruta al directorio"}. -{"Access Control List Configuration", "Configuración de la Lista de Control de Acceso"}. -{"Access control lists", "Listas de Control de Acceso"}. -{"Access Configuration", "Configuración de accesos"}. -{"Access rules", "Reglas de acceso"}. -{"Administration of ", "Administración de "}. -{"Action on user", "Acción en el usuario"}. -{"Edit Properties", "Editar propiedades"}. -{"Remove User", "Eliminar usuario"}. -{"Database", "Base de datos"}. -{"Outgoing s2s Connections", "Conexiones S2S salientes"}. -{"Import Users From jabberd 1.4 Spool Files", "Importar usuarios de ficheros spool de jabberd-1.4"}. -{"Database Tables Configuration at ", "Configuración de tablas de la base de datos en "}. -{"Restart Service", "Reiniciar el servicio"}. -{"Shut Down Service", "Detener el servicio"}. -{"Delete User", "Borrar usuario"}. -{"End User Session", "Cerrar sesión de usuario"}. -{"Get User Password", "Ver contraseña de usuario"}. -{"Change User Password", "Cambiar contraseña de usuario"}. -{"Get User Last Login Time", "Ver fecha de la última conexión de usuario"}. -{"Get User Statistics", "Ver estadísticas de usuario"}. -{"Get Number of Registered Users", "Ver número de usuarios registrados"}. -{"Get Number of Online Users", "Ver número de usuarios conectados"}. -{"User Management", "Administración de usuarios"}. -{"Time delay", "Retraso temporal"}. -{"Password Verification", "Verificación de la contraseña"}. -{"Number of registered users", "Número de usuarios registrados"}. -{"Number of online users", "Número de usuarios conectados"}. -{"Last login", "Última conexión"}. -{"Roster size", "Tamaño de la lista de contactos"}. -{"IP addresses", "Direcciones IP"}. -{"Resources", "Recursos"}. - -% mod_disco.erl -{"Configuration", "Configuración"}. -{"Online Users", "Usuarios conectados"}. -{"All Users", "Todos los usuarios"}. -{"To ~s", "A ~s"}. -{"From ~s", "De ~s"}. -{"Running Nodes", "Nodos funcionando"}. -{"Stopped Nodes", "Nodos detenidos"}. -{"Access Control Lists", "Listas de Control de Acceso"}. -{"Access Rules", "Reglas de Acceso"}. -{"Modules", "Módulos"}. -{"Start Modules", "Iniciar módulos"}. -{"Stop Modules", "Detener módulos"}. -{"Backup", "Guardar copia de seguridad"}. -{"Restore", "Restaurar"}. -{"Dump to Text File", "Exportar a fichero de texto"}. -{"Import File", "Importar fichero"}. -{"Import Directory", "Importar directorio"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Escoge un nombre de usuario y contraseña para registrarte en este servidor"}. - -% mod_vcard.erl -{"Erlang Jabber Server", "Servidor Jabber en Erlang"}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Rellena el formulario para buscar usuarios Jabber. Añade * al final de un campo para buscar subcadenas."}. -{"ejabberd vCard module", "Módulo vCard para ejabberd"}. -{"You need an x:data capable client to search", "Necesitas un cliente con soporte de x:data para poder buscar"}. -{"Search users in ", "Buscar usuarios en "}. - -% mod_vcard_odbc.erl -{"Email", "correo"}. -{"Search Results for ", "Buscar resultados por "}. -{"Jabber ID", "Jabber ID"}. -{"vCard User Search", "Buscar vCard de usuario"}. -{"User", "Usuario"}. -{"Full Name", "Nombre completo"}. -{"Name", "Nombre"}. -{"Middle Name", "Segundo nombre"}. -{"Family Name", "Apellido"}. -{"Nickname", "Apodo"}. -{"Birthday", "Cumpleaños"}. -{"Country", "País"}. -{"City", "Ciudad"}. -{"Organization Name", "Nombre de la organización"}. -{"Organization Unit", "Unidad de la organización"}. - -% mod_pubsub/mod_pubsub.erl -{"Roster groups allowed to subscribe", "Grupos de contactos que pueden suscribirse"}. -{"Deliver payloads with event notifications", "Enviar payloads junto con las notificaciones de eventos"}. -{"Notify subscribers when the node configuration changes", "Notificar subscriptores cuando cambia la configuración del nodo"}. -{"Notify subscribers when the node is deleted", "Notificar subscriptores cuando el nodo se borra"}. -{"Notify subscribers when items are removed from the node", "Notificar subscriptores cuando los elementos se borran del nodo"}. -{"Persist items to storage", "Persistir elementos al almacenar"}. -{"Max # of items to persist", "Máximo # de elementos que persisten"}. -{"Whether to allow subscriptions", "Permitir subscripciones"}. -{"Specify the publisher model", "Especificar el modelo del publicante"}. -{"Max payload size in bytes", "Máximo tamaño del payload en bytes"}. -{"Only deliver notifications to available users", "Solo enviar notificaciones a los usuarios disponibles"}. -{"Publish-Subscribe", "Servicio de Publicar-Subscribir"}. -{"ejabberd Publish-Subscribe module", "Módulo de Publicar-Subscribir de ejabberd"}. -{"PubSub subscriber request", "Petición de subscriptor de PubSub"}. -{"Choose whether to approve this entity's subscription.", "Decidir si aprobar la subscripción de esta entidad."}. -{"Node ID", "Nodo ID"}. -{"Subscriber Address", "Dirección del subscriptor"}. -{"Allow this JID to subscribe to this pubsub node?", "¿Deseas permitir a este JabberID que se subscriba a este nodo PubSub?"}. -{"Deliver event notifications", "Entregar notificaciones de eventos"}. -{"Specify the access model", "Especifica el modelo de acceso"}. -{"When to send the last published item", "Cuando enviar el último elemento publicado"}. - -% mod_muc/mod_muc.erl -{"You need an x:data capable client to register nickname", "Necesitas un cliente con soporte de x:data para poder registrar el apodo"}. -{"Nickname Registration at ", "Registro del apodo en "}. -{"Enter nickname you want to register", "Introduce el apodo que quieras registrar"}. -{"Only service administrators are allowed to send service messages", "Solo los administradores del servicio tienen permiso para enviar mensajes de servicio"}. -{"Conference room does not exist", "La sala de conferencias no existe"}. -{"Access denied by service policy", "Acceso denegado por la política del servicio"}. -{"You must fill in field \"Nickname\" in the form", "Debes rellenar el campo \"Apodo\" en el formulario"}. -{"Specified nickname is already registered", "El apodo especificado ya está registrado, tendrás que buscar otro"}. -{"Room creation is denied by service policy", "Se te ha denegado crear la sala por política del servicio"}. -{"ejabberd MUC module", "Módulo de MUC para ejabbed"}. -{"Chatrooms", "Salas de charla"}. - -% mod_muc/mod_muc_room.erl -{"This participant is kicked from the room because he sent an error message to another participant", "Este participante ha sido expulsado de la sala porque envió un mensaje de error a otro participante"}. -{"This participant is kicked from the room because he sent an error message", "Este participante ha sido expulsado de la sala porque envió un mensaje de error"}. -{"This participant is kicked from the room because he sent an error presence", "Este participante ha sido expulsado de la sala porque envió una presencia de error"}. -{"Make room moderated", "Sala moderada"}. -{" has set the subject to: ", " ha puesto el asunto: "}. -{"You need an x:data capable client to configure room", "Necesitas un cliente con soporte de x:data para configurar la sala"}. -{"Configuration for ", "Configuración para "}. -{"Room title", "Título de la sala"}. -{"Allow users to change subject", "Permitir a los usuarios cambiar el asunto"}. -{"Allow users to query other users", "Permitir a los usuarios consultar a otros usuarios"}. -{"Allow users to send private messages", "Permitir a los usuarios enviar mensajes privados"}. -{"Make room public searchable", "Sala públicamente visible"}. -{"Make participants list public", "La lista de participantes es pública"}. -{"Make room persistent", "Sala permanente"}. -{"Default users as participants", "Los usuarios son participantes por defecto"}. -{"Make room members-only", "Sala sólo para miembros"}. -{"Allow users to send invites", "Permitir a los usuarios enviar invitaciones"}. -{"Make room password protected", "Proteger la sala con contraseña"}. -{"Password", "Contraseña"}. -{"This room is not anonymous", "Sala no anónima"}. -{"Enable logging", "Guardar históricos"}. -{"Only moderators and participants are allowed to change subject in this room", "Solo los moderadores y participantes pueden cambiar el asunto de esta sala"}. -{"Only moderators are allowed to change subject in this room", "Solo los moderadores pueden cambiar el asunto de esta sala"}. -{"Visitors are not allowed to send messages to all occupants", "Los visitantes no pueden enviar mensajes a todos los ocupantes"}. -{"Only occupants are allowed to send messages to the conference", "Solo los ocupantes pueden enviar mensajes a la sala"}. -{"It is not allowed to send private messages to the conference", "Impedir el envio de mensajes privados a la sala"}. -{"Improper message type", "Tipo de mensaje incorrecto"}. -{"Nickname is already in use by another occupant", "El apodo ya está siendo usado por otro ocupante"}. -{"Nickname is registered by another person", "El apodo ya está registrado por otra persona"}. -{"It is not allowed to send private messages of type \"groupchat\"", "No está permitido enviar mensajes privados del tipo \"groupchat\""}. -{"Recipient is not in the conference room", "El receptor no está en la sala de conferencia"}. -{"Only occupants are allowed to send queries to the conference", "Solo los ocupantes pueden enviar solicitudes a la sala"}. -{"Queries to the conference members are not allowed in this room", "En esta sala no se permiten solicitudes a los miembros de la sala"}. -{"You have been banned from this room", "Has sido bloqueado en esta sala"}. -{"Membership required to enter this room", "Necesitas ser miembro de esta sala para poder entrar"}. -{"Password required to enter this room", "Se necesita contraseña para entrar en esta sala"}. -{"Incorrect password", "Contraseña incorrecta"}. -{"Administrator privileges required", "Se necesita privilegios de administrador"}. -{"Moderator privileges required", "Se necesita privilegios de moderador"}. -{"JID ~s is invalid", "El JID ~s no es válido"}. -{"Nickname ~s does not exist in the room", "El apodo ~s no existe en la sala"}. -{"Invalid affiliation: ~s", "Afiliación no válida: ~s"}. -{"Invalid role: ~s", "Rol no válido: ~s"}. -{"Owner privileges required", "Se requieren privilegios de propietario de la sala"}. -{"private, ", "privado"}. -{"Number of occupants", "Número de ocupantes"}. -{"Present real JIDs to", "Los JID reales pueden verlos"}. -{"moderators only", "solo moderadores"}. -{"anyone", "cualquiera"}. -{"Traffic rate limit is exceeded", "Se ha exedido el límite de tráfico"}. -{"Maximum Number of Occupants", "Número máximo de ocupantes"}. -{"No limit", "Sin límite"}. -{"~s invites you to the room ~s", "~s te invita a la sala ~s"}. -{"the password is", "la contraseña es"}. - -% mod_muc/mod_muc_log.erl -{"has been kicked because of an affiliation change", "ha sido expulsado por un cambio de su afiliación"}. -{"has been kicked because the room has been changed to members-only", "ha sido expulsado porque la sala es ahora solo para miembros"}. -{"has been kicked because of a system shutdown", "ha sido expulsado porque el sistema se va a detener"}. -{"Chatroom configuration modified", "Configuración de la sala modificada"}. -{"joins the room", "entra en la sala"}. -{"leaves the room", "sale de la sala"}. -{"has been kicked", "ha sido expulsado"}. -{"has been banned", "ha sido bloqueado"}. -{"is now known as", "se cambia el nombre a"}. -{"Monday", "lunes"}. -{"Tuesday", "martes"}. -{"Wednesday", "miércoles"}. -{"Thursday", "jueves"}. -{"Friday", "viernes"}. -{"Saturday", "sábado"}. -{"Sunday", "domingo"}. -{"January", "enero"}. -{"February", "febrero"}. -{"March", "marzo"}. -{"April", "abril"}. -{"May", "mayo"}. -{"June", "junio"}. -{"July", "julio"}. -{"August", "agosto"}. -{"September", "septiembre"}. -{"October", "octubre"}. -{"November", "noviembre"}. -{"December", "diciembre"}. -{"Room Configuration", "Configuración de la sala"}. - -% mod_irc/mod_irc.erl -{"You need an x:data capable client to configure mod_irc settings", "Necesitas un cliente con soporte de x:data para configurar las opciones de mod_irc"}. -{"Registration in mod_irc for ", "Registro en mod_irc para"}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Introduce el nombre de usuario y codificaciones de carácteres que quieras usar al conectar en los servidores de IRC"}. -{"IRC Username", "Nombre de usuario en IRC"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Si quieres especificar codificaciones de carácteres distintos para cada servidor IRC rellena esta lista con valores en el formato '{\"servidor irc\", \"codificación\"}'. Este servicio usa por defecto la codificación \"~s\"."}. -{"Encodings", "Codificaciones"}. -{"ejabberd IRC module", "Módulo de IRC para ejabberd"}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Ejemplo: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"IRC Transport", "Transporte de IRC"}. - -% web/ejabberd_web_admin.erl -{"ejabberd Web Admin", "ejabberd Web Admin"}. -{"Users", "Usuarios"}. -{"Nodes", "Nodos"}. -{"Statistics", "Estadísticas"}. -{"Delete Selected", "Eliminar los seleccionados"}. -{"Submit", "Enviar"}. -{"~s access rule configuration", "Configuración de las Regla de Acceso ~s"}. -{"Node not found", "Nodo no encontrado"}. -{"Add New", "Añadir nuevo"}. -{"Change Password", "Cambiar contraseña"}. -{"Connected Resources:", "Recursos conectados:"}. -{"Password:", "Contraseña:"}. -{"None", "Ninguno"}. -{"Node ", "Nodo "}. -{"Restart", "Reiniciar"}. -{"Stop", "Detener"}. -{"Name", "Nombre"}. -{"Storage Type", "Tipo de almacenamiento"}. -{"Size", "Tamaño"}. -{"Memory", "Memoria"}. -{"Backup Management", "Gestión de copia de seguridad"}. -{"OK", "Aceptar"}. -{"Listened Ports at ", "Puertos de escucha en "}. -{"Port", "Puerto"}. -{"Module", "Módulo"}. -{"Options", "Opciones"}. -{"Update", "Actualizar"}. -{"Delete", "Eliminar"}. -{"Add User", "Añadir usuario"}. -{"Last Activity", "Última actividad"}. -{"Never", "Nunca"}. -{"Time", "Fecha"}. -{"From", "De"}. -{"To", "Para"}. -{"Packet", "Paquete"}. -{"Roster", "Lista de contactos"}. -{"Nickname", "Apodo"}. -{"Subscription", "Subscripción"}. -{"Pending", "Pendiente"}. -{"Groups", "Grupos"}. -{"Remove", "Borrar"}. -{"User ", "Usuario "}. -{"Roster of ", "Lista de contactos de "}. -{"Online", "Conectado"}. -{"Validate", "Validar"}. -{"Name:", "Nombre:"}. -{"Description:", "Descripción:"}. -{"Members:", "Miembros:"}. -{"Displayed Groups:", "Mostrar grupos:"}. -{"Group ", "Grupo "}. -{"Period: ", "Periodo: "}. -{"Last month", "Último mes"}. -{"Last year", "Último año"}. -{"All activity", "Toda la actividad"}. -{"Show Ordinary Table", "Mostrar Tabla Ordinaria"}. -{"Show Integral Table", "Mostrar Tabla Integral"}. -{"Modules at ", "Módulos en "}. -{"Start", "Iniciar"}. -{"Virtual Hosts", "Dominios"}. -{"ejabberd virtual hosts", "Dominios de ejabberd"}. -{"Host", "Dominio"}. -{"Restore plain text backup immediately:", "Restaurar copias de seguridad de texto plano inmediatamente:"}. -{"Statistics of ~p", "Estadísticas de ~p"}. -{"Uptime:", "Tiempo desde el inicio:"}. -{"CPU Time:", "Tiempo consumido de CPU:"}. -{"Transactions Commited:", "Transacciones finalizadas:"}. -{"Transactions Aborted:", "Transacciones abortadas:"}. -{"Transactions Restarted:", "Transacciones reiniciadas:"}. -{"Transactions Logged:", "Transacciones registradas:"}. -{"Update ", "Actualizar "}. -{"Update plan", "Plan de actualización"}. -{"Updated modules", "Módulos actualizados"}. -{"Update script", "Script de actualización"}. -{"Low level update script", "Script de actualización a bajo nivel"}. -{"Script check", "Comprobación de script"}. -{"Shared Roster Groups", "Grupos Compartidos"}. -{"Administration", "Administración"}. -{"(Raw)", "(crudo)"}. -{"Submitted", "Enviado"}. -{"Bad format", "Mal formato"}. -{"Raw", "Crudo"}. -{"Users Last Activity", "Última actividad de los usuarios"}. -{"Registered Users", "Usuarios registrados"}. -{"Offline Messages", "Mensajes diferidos"}. -{"Registered Users:", "Usuarios registrados:"}. -{"Online Users:", "Usuarios conectados:"}. -{"Outgoing s2s Connections:", "Conexiones S2S salientes:"}. -{"Outgoing s2s Servers:", "Servidores S2S salientes:"}. -{"Offline Messages:", "Mensajes diferidos:"}. -{"~s's Offline Messages Queue", "Cola de mensajes diferidos de ~s"}. -{"Add Jabber ID", "Añadir Jabber ID"}. -{"No Data", "Sin datos"}. -{"Listened Ports", "Puertos de escucha"}. -{"RPC Call Error", "Error en la llamada RPC"}. -{"Database Tables at ", "Tablas de la base de datos en "}. -{"Backup of ", "Copia de seguridad de "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "Ten en cuenta que estas opciones solo harán copia de seguridad de la base de datos Mnesia embebida. Si estás usando ODBC tendrás que hacer también copia de seguridad de tu base de datos SQL."}. -{"Store binary backup:", "Guardar copia de seguridad binaria:"}. -{"Restore binary backup immediately:", "Restaurar inmediatamente copia de seguridad binaria:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Restaurar copia de seguridad binaria en el siguiente reinicio de ejabberd (requiere menos memoria que si instantánea):"}. -{"Store plain text backup:", "Guardar copia de seguridad en texto plano:"}. - -% ejabberd_c2s.erl -{"Use of STARTTLS required", "Es obligatorio usar STARTTLS"}. -{"Replaced by new connection", "Reemplazado por una nueva conexión"}. - -% mod_vcard_ldap.erl -{"Fill in fields to search for any matching Jabber User", "Rellena campos para buscar usuarios Jabber que concuerden"}. - -% mod_adhoc.erl -{"Commands", "Comandos"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% mod_announce.erl -{"Really delete message of the day?", "¿Está seguro de quere borrar el mensaje del dia?"}. -{"Subject", "Asunto"}. -{"Message body", "Cuerpo del mensaje"}. -{"No body provided for announce message", "No se ha proporcionado cuerpo de mensaje para el anuncio"}. -{"Announcements", "Anuncios"}. -{"Send announcement to all users", "Enviar anuncio a todos los usuarios"}. -{"Send announcement to all online users", "Enviar anuncio a todos los usuarios conectados"}. -{"Send announcement to all online users on all hosts", "Enviar anuncio a todos los usuarios conectados en todos los dominios"}. -{"Set message of the day and send to online users", "Poner mensaje del dia y enviar a todos los usuarios conectados"}. -{"Update message of the day (don't send)", "Actualizar mensaje del dia, pero no enviarlo"}. -{"Delete message of the day", "Borrar mensaje del dia"}. -{"Send announcement to all users on all hosts", "Enviar anuncio a todos los usuarios en todos los dominios"}. -{"Set message of the day on all hosts and send to online users", "Poner mensaje del día en todos los dominios y enviar a los usuarios conectados"}. -{"Update message of the day on all hosts (don't send)", "Actualizar el mensaje del día en todos los dominos (pero no enviarlo)"}. -{"Delete message of the day on all hosts", "Borrar el mensaje del día en todos los dominios"}. - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "Módulo SOCKS5 Bytestreams para ejabberd"}. - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "Tu cola de mensajes diferidos de contactos está llena. El mensaje se ha descartado."}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Configuración de accesos"}. +{"Access Control List Configuration","Configuración de la Lista de Control de Acceso"}. +{"Access control lists","Listas de Control de Acceso"}. +{"Access Control Lists","Listas de Control de Acceso"}. +{"Access denied by service policy","Acceso denegado por la política del servicio"}. +{"Access rules","Reglas de acceso"}. +{"Access Rules","Reglas de Acceso"}. +{"Action on user","Acción en el usuario"}. +{"Add Jabber ID","Añadir Jabber ID"}. +{"Add New","Añadir nuevo"}. +{"Add User","Añadir usuario"}. +{"Administration","Administración"}. +{"Administration of ","Administración de "}. +{"Administrator privileges required","Se necesita privilegios de administrador"}. +{"A friendly name for the node","Un nombre sencillo para el nodo"}. +{"All activity","Toda la actividad"}. +{"Allow this JID to subscribe to this pubsub node?","¿Deseas permitir a este JabberID que se subscriba a este nodo PubSub?"}. +{"Allow users to change subject","Permitir a los usuarios cambiar el asunto"}. +{"Allow users to query other users","Permitir a los usuarios consultar a otros usuarios"}. +{"Allow users to send invites","Permitir a los usuarios enviar invitaciones"}. +{"Allow users to send private messages","Permitir a los usuarios enviar mensajes privados"}. +{"Allow visitors to change nickname","Permitir a los visitantes cambiarse el apodo"}. +{"Allow visitors to send status text in presence updates","Permitir a los visitantes enviar texto de estado en las actualizaciones de presencia"}. +{"All Users","Todos los usuarios"}. +{"Announcements","Anuncios"}. +{"anyone","cualquiera"}. +{"April","abril"}. +{"August","agosto"}. +{"Backup","Guardar copia de seguridad"}. +{"Backup Management","Gestión de copia de seguridad"}. +{"Backup of ","Copia de seguridad de "}. +{"Backup to File at ","Guardar copia de seguridad en fichero en "}. +{"Bad format","Mal formato"}. +{"Birthday","Cumpleaños"}. +{"Change Password","Cambiar contraseña"}. +{"Change User Password","Cambiar contraseña de usuario"}. +{"Chatroom configuration modified","Configuración de la sala modificada"}. +{"Chatrooms","Salas de charla"}. +{"Choose a username and password to register with this server","Escoge un nombre de usuario y contraseña para registrarte en este servidor"}. +{"Choose modules to stop","Selecciona módulos a detener"}. +{"Choose storage type of tables","Selecciona tipo de almacenamiento de las tablas"}. +{"Choose whether to approve this entity's subscription.","Decidir si aprobar la subscripción de esta entidad."}. +{"City","Ciudad"}. +{"Commands","Comandos"}. +{"Conference room does not exist","La sala de conferencias no existe"}. +{"Configuration","Configuración"}. +{"Configuration for ","Configuración para "}. +{"Connected Resources:","Recursos conectados:"}. +{"Country","País"}. +{"CPU Time:","Tiempo consumido de CPU:"}. +{"Database","Base de datos"}. +{"Database Tables at ","Tablas de la base de datos en "}. +{"Database Tables Configuration at ","Configuración de tablas de la base de datos en "}. +{"December","diciembre"}. +{"Default users as participants","Los usuarios son participantes por defecto"}. +{"Delete","Eliminar"}. +{"Delete message of the day","Borrar mensaje del dia"}. +{"Delete message of the day on all hosts","Borrar el mensaje del día en todos los dominios"}. +{"Delete Selected","Eliminar los seleccionados"}. +{"Delete User","Borrar usuario"}. +{"Deliver event notifications","Entregar notificaciones de eventos"}. +{"Deliver payloads with event notifications","Enviar contenidos junto con las notificaciones de eventos"}. +{"Description:","Descripción:"}. +{"Disc only copy","Copia en disco solamente"}. +{"Displayed Groups:","Mostrar grupos:"}. +{"Dump Backup to Text File at ","Exporta copia de seguridad a fichero de texto en "}. +{"Dump to Text File","Exportar a fichero de texto"}. +{"Edit Properties","Editar propiedades"}. +{"ejabberd IRC module","Módulo de IRC para ejabberd"}. +{"ejabberd MUC module","Módulo de MUC para ejabberd"}. +{"ejabberd Publish-Subscribe module","Módulo de Publicar-Subscribir de ejabberd"}. +{"ejabberd SOCKS5 Bytestreams module","Módulo SOCKS5 Bytestreams para ejabberd"}. +{"ejabberd vCard module","Módulo vCard para ejabberd"}. +{"ejabberd virtual hosts","Dominios de ejabberd"}. +{"ejabberd Web Admin","ejabberd Web Admin"}. +{"Email","correo"}. +{"Enable logging","Guardar históricos"}. +{"Encodings","Codificaciones"}. +{"End User Session","Cerrar sesión de usuario"}. +{"Enter list of {Module, [Options]}","Introduce lista de {módulo, [opciones]}"}. +{"Enter nickname you want to register","Introduce el apodo que quieras registrar"}. +{"Enter path to backup file","Introduce ruta al fichero de copia de seguridad"}. +{"Enter path to jabberd1.4 spool dir","Introduce la ruta al directorio de jabberd1.4 spools"}. +{"Enter path to jabberd1.4 spool file","Introduce ruta al fichero jabberd1.4 spool"}. +{"Enter path to text file","Introduce ruta al fichero de texto"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Introduce el nombre de usuario y codificaciones de carácteres que quieras usar al conectar en los servidores de IRC"}. +{"Erlang Jabber Server","Servidor Jabber en Erlang"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Ejemplo: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","Apellido"}. +{"February","febrero"}. +{"Fill in fields to search for any matching Jabber User","Rellena campos para buscar usuarios Jabber que concuerden"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Rellena el formulario para buscar usuarios Jabber. Añade * al final de un campo para buscar subcadenas."}. +{"Friday","viernes"}. +{"From","De"}. +{"From ~s","De ~s"}. +{"Full Name","Nombre completo"}. +{"Get Number of Online Users","Ver número de usuarios conectados"}. +{"Get Number of Registered Users","Ver número de usuarios registrados"}. +{"Get User Last Login Time","Ver fecha de la última conexión de usuario"}. +{"Get User Password","Ver contraseña de usuario"}. +{"Get User Statistics","Ver estadísticas de usuario"}. +{"Group ","Grupo "}. +{"Groups","Grupos"}. +{"has been banned","ha sido bloqueado"}. +{"has been kicked because of an affiliation change","ha sido expulsado por un cambio de su afiliación"}. +{"has been kicked because of a system shutdown","ha sido expulsado porque el sistema se va a detener"}. +{"has been kicked because the room has been changed to members-only","ha sido expulsado porque la sala es ahora solo para miembros"}. +{"has been kicked","ha sido expulsado"}. +{" has set the subject to: "," ha puesto el asunto: "}. +{"Host","Dominio"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Si quieres especificar codificaciones de carácteres distintos para cada servidor IRC rellena esta lista con valores en el formato '{\"servidor irc\", \"codificación\"}'. Este servicio usa por defecto la codificación \"~s\"."}. +{"Import Directory","Importar directorio"}. +{"Import File","Importar fichero"}. +{"Import User from File at ","Importa usuario desde fichero en "}. +{"Import Users from Dir at ","Importar usuarios desde el directorio en "}. +{"Import Users From jabberd 1.4 Spool Files","Importar usuarios de ficheros spool de jabberd-1.4"}. +{"Improper message type","Tipo de mensaje incorrecto"}. +{"Incorrect password","Contraseña incorrecta"}. +{"Invalid affiliation: ~s","Afiliación no válida: ~s"}. +{"Invalid role: ~s","Rol no válido: ~s"}. +{"IP addresses","Direcciones IP"}. +{"IRC Transport","Transporte de IRC"}. +{"IRC Username","Nombre de usuario en IRC"}. +{"is now known as","se cambia el nombre a"}. +{"It is not allowed to send private messages","No está permitido enviar mensajes privados"}. +{"It is not allowed to send private messages of type \"groupchat\"","No está permitido enviar mensajes privados del tipo \"groupchat\""}. +{"It is not allowed to send private messages to the conference","Impedir el envio de mensajes privados a la sala"}. +{"Jabber ID","Jabber ID"}. +{"January","enero"}. +{"JID ~s is invalid","El JID ~s no es válido"}. +{"joins the room","entra en la sala"}. +{"July","julio"}. +{"June","junio"}. +{"Last Activity","Última actividad"}. +{"Last login","Última conexión"}. +{"Last month","Último mes"}. +{"Last year","Último año"}. +{"leaves the room","sale de la sala"}. +{"Listened Ports at ","Puertos de escucha en "}. +{"Listened Ports","Puertos de escucha"}. +{"List of modules to start","Lista de módulos a iniciar"}. +{"Low level update script","Script de actualización a bajo nivel"}. +{"Make participants list public","La lista de participantes es pública"}. +{"Make room members-only","Sala sólo para miembros"}. +{"Make room moderated","Sala moderada"}. +{"Make room password protected","Proteger la sala con contraseña"}. +{"Make room persistent","Sala permanente"}. +{"Make room public searchable","Sala públicamente visible"}. +{"March","marzo"}. +{"Maximum Number of Occupants","Número máximo de ocupantes"}. +{"Max # of items to persist","Máximo # de elementos que persisten"}. +{"Max payload size in bytes","Máximo tamaño del contenido en bytes"}. +{"May","mayo"}. +{"Membership required to enter this room","Necesitas ser miembro de esta sala para poder entrar"}. +{"Members:","Miembros:"}. +{"Memory","Memoria"}. +{"Message body","Cuerpo del mensaje"}. +{"Middle Name","Segundo nombre"}. +{"Moderator privileges required","Se necesita privilegios de moderador"}. +{"moderators only","solo moderadores"}. +{"Module","Módulo"}. +{"Modules at ","Módulos en "}. +{"Modules","Módulos"}. +{"Monday","lunes"}. +{"Name:","Nombre:"}. +{"Name","Nombre"}. +{"Never","Nunca"}. +{"Nickname","Apodo"}. +{"Nickname is already in use by another occupant","El apodo ya está siendo usado por otro ocupante"}. +{"Nickname is registered by another person","El apodo ya está registrado por otra persona"}. +{"Nickname Registration at ","Registro del apodo en "}. +{"Nickname ~s does not exist in the room","El apodo ~s no existe en la sala"}. +{"No body provided for announce message","No se ha proporcionado cuerpo de mensaje para el anuncio"}. +{"No Data","Sin datos"}. +{"Node ID","Nodo ID"}. +{"Node ","Nodo "}. +{"Node not found","Nodo no encontrado"}. +{"Nodes","Nodos"}. +{"No limit","Sin límite"}. +{"None","Ninguno"}. +{"No resource provided","No se ha proporcionado recurso"}. +{"Notify subscribers when items are removed from the node","Notificar subscriptores cuando los elementos se borran del nodo"}. +{"Notify subscribers when the node configuration changes","Notificar subscriptores cuando cambia la configuración del nodo"}. +{"Notify subscribers when the node is deleted","Notificar subscriptores cuando el nodo se borra"}. +{"November","noviembre"}. +{"Number of occupants","Número de ocupantes"}. +{"Number of online users","Número de usuarios conectados"}. +{"Number of registered users","Número de usuarios registrados"}. +{"October","octubre"}. +{"Offline Messages:","Mensajes diferidos:"}. +{"Offline Messages","Mensajes diferidos"}. +{"OK","Aceptar"}. +{"Online","Conectado"}. +{"Online Users:","Usuarios conectados:"}. +{"Online Users","Usuarios conectados"}. +{"Only deliver notifications to available users","Solo enviar notificaciones a los usuarios disponibles"}. +{"Only moderators and participants are allowed to change subject in this room","Solo los moderadores y participantes pueden cambiar el asunto de esta sala"}. +{"Only moderators are allowed to change subject in this room","Solo los moderadores pueden cambiar el asunto de esta sala"}. +{"Only occupants are allowed to send messages to the conference","Solo los ocupantes pueden enviar mensajes a la sala"}. +{"Only occupants are allowed to send queries to the conference","Solo los ocupantes pueden enviar solicitudes a la sala"}. +{"Only service administrators are allowed to send service messages","Solo los administradores del servicio tienen permiso para enviar mensajes de servicio"}. +{"Options","Opciones"}. +{"Organization Name","Nombre de la organización"}. +{"Organization Unit","Unidad de la organización"}. +{"Outgoing s2s Connections:","Conexiones S2S salientes:"}. +{"Outgoing s2s Connections","Conexiones S2S salientes"}. +{"Outgoing s2s Servers:","Servidores S2S salientes:"}. +{"Owner privileges required","Se requieren privilegios de propietario de la sala"}. +{"Packet","Paquete"}. +{"Password:","Contraseña:"}. +{"Password","Contraseña"}. +{"Password required to enter this room","Se necesita contraseña para entrar en esta sala"}. +{"Password Verification","Verificación de la contraseña"}. +{"Path to Dir","Ruta al directorio"}. +{"Path to File","Ruta al fichero"}. +{"Pending","Pendiente"}. +{"Period: ","Periodo: "}. +{"Persist items to storage","Persistir elementos al almacenar"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","Puerto"}. +{"Present real JIDs to","Los JID reales pueden verlos"}. +{"private, ","privado"}. +{"Publish-Subscribe","Servicio de Publicar-Subscribir"}. +{"PubSub subscriber request","Petición de subscriptor de PubSub"}. +{"Queries to the conference members are not allowed in this room","En esta sala no se permiten solicitudes a los miembros de la sala"}. +{"RAM and disc copy","Copia en RAM y disco"}. +{"RAM copy","Copia en RAM"}. +{"(Raw)","(crudo)"}. +{"Raw","Crudo"}. +{"Really delete message of the day?","¿Está seguro de quere borrar el mensaje del dia?"}. +{"Recipient is not in the conference room","El receptor no está en la sala de conferencia"}. +{"Registered Users:","Usuarios registrados:"}. +{"Registered Users","Usuarios registrados"}. +{"Registration in mod_irc for ","Registro en mod_irc para"}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Ten en cuenta que estas opciones solo harán copia de seguridad de la base de datos Mnesia embebida. Si estás usando ODBC tendrás que hacer también copia de seguridad de tu base de datos SQL."}. +{"Remote copy","Copia remota"}. +{"Remove","Borrar"}. +{"Remove User","Eliminar usuario"}. +{"Replaced by new connection","Reemplazado por una nueva conexión"}. +{"Resources","Recursos"}. +{"Restart","Reiniciar"}. +{"Restart Service","Reiniciar el servicio"}. +{"Restore Backup from File at ","Restaura copia de seguridad desde el fichero en "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Restaurar copia de seguridad binaria en el siguiente reinicio de ejabberd (requiere menos memoria que si instantánea):"}. +{"Restore binary backup immediately:","Restaurar inmediatamente copia de seguridad binaria:"}. +{"Restore plain text backup immediately:","Restaurar copias de seguridad de texto plano inmediatamente:"}. +{"Restore","Restaurar"}. +{"Room Configuration","Configuración de la sala"}. +{"Room creation is denied by service policy","Se te ha denegado crear la sala por política del servicio"}. +{"Room title","Título de la sala"}. +{"Roster groups allowed to subscribe","Grupos de contactos que pueden suscribirse"}. +{"Roster","Lista de contactos"}. +{"Roster of ","Lista de contactos de "}. +{"Roster size","Tamaño de la lista de contactos"}. +{"RPC Call Error","Error en la llamada RPC"}. +{"Running Nodes","Nodos funcionando"}. +{"~s access rule configuration","Configuración de las Regla de Acceso ~s"}. +{"Saturday","sábado"}. +{"Script check","Comprobación de script"}. +{"Search Results for ","Buscar resultados por "}. +{"Search users in ","Buscar usuarios en "}. +{"Send announcement to all online users","Enviar anuncio a todos los usuarios conectados"}. +{"Send announcement to all online users on all hosts","Enviar anuncio a todos los usuarios conectados en todos los dominios"}. +{"Send announcement to all users","Enviar anuncio a todos los usuarios"}. +{"Send announcement to all users on all hosts","Enviar anuncio a todos los usuarios en todos los dominios"}. +{"September","septiembre"}. +{"Set message of the day and send to online users","Poner mensaje del dia y enviar a todos los usuarios conectados"}. +{"Set message of the day on all hosts and send to online users","Poner mensaje del día en todos los dominios y enviar a los usuarios conectados"}. +{"Shared Roster Groups","Grupos Compartidos"}. +{"Show Integral Table","Mostrar Tabla Integral"}. +{"Show Ordinary Table","Mostrar Tabla Ordinaria"}. +{"Shut Down Service","Detener el servicio"}. +{"~s invites you to the room ~s","~s te invita a la sala ~s"}. +{"Size","Tamaño"}. +{"Specified nickname is already registered","El apodo especificado ya está registrado, tendrás que buscar otro"}. +{"Specify the access model","Especifica el modelo de acceso"}. +{"Specify the publisher model","Especificar el modelo del publicante"}. +{"~s's Offline Messages Queue","Cola de mensajes diferidos de ~s"}. +{"Start","Iniciar"}. +{"Start Modules at ","Iniciar módulos en "}. +{"Start Modules","Iniciar módulos"}. +{"Statistics","Estadísticas"}. +{"Statistics of ~p","Estadísticas de ~p"}. +{"Stop","Detener"}. +{"Stop Modules at ","Detener módulos en "}. +{"Stop Modules","Detener módulos"}. +{"Stopped Nodes","Nodos detenidos"}. +{"Storage Type","Tipo de almacenamiento"}. +{"Store binary backup:","Guardar copia de seguridad binaria:"}. +{"Store plain text backup:","Guardar copia de seguridad en texto plano:"}. +{"Subject","Asunto"}. +{"Submit","Enviar"}. +{"Submitted","Enviado"}. +{"Subscriber Address","Dirección del subscriptor"}. +{"Subscription","Subscripción"}. +{"Sunday","domingo"}. +{"the password is","la contraseña es"}. +{"This participant is kicked from the room because he sent an error message","Este participante ha sido expulsado de la sala porque envió un mensaje de error"}. +{"This participant is kicked from the room because he sent an error message to another participant","Este participante ha sido expulsado de la sala porque envió un mensaje de error a otro participante"}. +{"This participant is kicked from the room because he sent an error presence","Este participante ha sido expulsado de la sala porque envió una presencia de error"}. +{"This room is not anonymous","Sala no anónima"}. +{"Thursday","jueves"}. +{"Time delay","Retraso temporal"}. +{"Time","Fecha"}. +{"To","Para"}. +{"To ~s","A ~s"}. +{"Traffic rate limit is exceeded","Se ha exedido el límite de tráfico"}. +{"Transactions Aborted:","Transacciones abortadas:"}. +{"Transactions Commited:","Transacciones finalizadas:"}. +{"Transactions Logged:","Transacciones registradas:"}. +{"Transactions Restarted:","Transacciones reiniciadas:"}. +{"Tuesday","martes"}. +{"Update ","Actualizar "}. +{"Update","Actualizar"}. +{"Updated modules","Módulos actualizados"}. +{"Update message of the day (don't send)","Actualizar mensaje del dia, pero no enviarlo"}. +{"Update message of the day on all hosts (don't send)","Actualizar el mensaje del día en todos los dominos (pero no enviarlo)"}. +{"Update plan","Plan de actualización"}. +{"Update script","Script de actualización"}. +{"Uptime:","Tiempo desde el inicio:"}. +{"Use of STARTTLS required","Es obligatorio usar STARTTLS"}. +{"User Management","Administración de usuarios"}. +{"Users are not allowed to register accounts so fast","Los usuarios no tienen permitido crear cuentas con tanta rapidez"}. +{"Users Last Activity","Última actividad de los usuarios"}. +{"Users","Usuarios"}. +{"User ","Usuario "}. +{"User","Usuario"}. +{"Validate","Validar"}. +{"vCard User Search","Buscar vCard de usuario"}. +{"Virtual Hosts","Dominios"}. +{"Visitors are not allowed to change their nicknames in this room","Los visitantes no tienen permitido cambiar sus apodos en esta sala"}. +{"Visitors are not allowed to send messages to all occupants","Los visitantes no pueden enviar mensajes a todos los ocupantes"}. +{"Wednesday","miércoles"}. +{"When to send the last published item","Cuando enviar el último elemento publicado"}. +{"Whether to allow subscriptions","Permitir subscripciones"}. +{"You have been banned from this room","Has sido bloqueado en esta sala"}. +{"You must fill in field \"Nickname\" in the form","Debes rellenar el campo \"Apodo\" en el formulario"}. +{"You need an x:data capable client to configure mod_irc settings","Necesitas un cliente con soporte de x:data para configurar las opciones de mod_irc"}. +{"You need an x:data capable client to configure room","Necesitas un cliente con soporte de x:data para configurar la sala"}. +{"You need an x:data capable client to register nickname","Necesitas un cliente con soporte de x:data para poder registrar el apodo"}. +{"You need an x:data capable client to search","Necesitas un cliente con soporte de x:data para poder buscar"}. +{"Your contact offline message queue is full. The message has been discarded.","Tu cola de mensajes diferidos de contactos está llena. El mensaje se ha descartado."}. diff --git a/src/msgs/es.po b/src/msgs/es.po new file mode 100644 index 000000000..7ae471974 --- /dev/null +++ b/src/msgs/es.po @@ -0,0 +1,1502 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Badlop\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Spanish (castellano)\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "Es obligatorio usar STARTTLS" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "No se ha proporcionado recurso" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Reemplazado por una nueva conexión" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Comandos" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "¿Está seguro de quere borrar el mensaje del dia?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Asunto" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Cuerpo del mensaje" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "No se ha proporcionado cuerpo de mensaje para el anuncio" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Anuncios" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Enviar anuncio a todos los usuarios" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Enviar anuncio a todos los usuarios en todos los dominios" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Enviar anuncio a todos los usuarios conectados" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "Enviar anuncio a todos los usuarios conectados en todos los dominios" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Poner mensaje del dia y enviar a todos los usuarios conectados" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Poner mensaje del día en todos los dominios y enviar a los usuarios " +"conectados" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Actualizar mensaje del dia, pero no enviarlo" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Actualizar el mensaje del día en todos los dominos (pero no enviarlo)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Borrar mensaje del dia" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Borrar el mensaje del día en todos los dominios" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Configuración" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Base de datos" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Iniciar módulos" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Detener módulos" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Guardar copia de seguridad" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Restaurar" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Exportar a fichero de texto" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Importar fichero" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Importar directorio" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Reiniciar el servicio" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Detener el servicio" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Añadir usuario" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Borrar usuario" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Cerrar sesión de usuario" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Ver contraseña de usuario" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Cambiar contraseña de usuario" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Ver fecha de la última conexión de usuario" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Ver estadísticas de usuario" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Ver número de usuarios registrados" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Ver número de usuarios conectados" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Listas de Control de Acceso" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Reglas de Acceso" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Administración de usuarios" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Usuarios conectados" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Todos los usuarios" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Conexiones S2S salientes" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Nodos funcionando" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Nodos detenidos" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Módulos" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Gestión de copia de seguridad" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Importar usuarios de ficheros spool de jabberd-1.4" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "A ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "De ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Configuración de tablas de la base de datos en " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Selecciona tipo de almacenamiento de las tablas" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Copia en disco solamente" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "Copia en RAM y disco" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "Copia en RAM" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Copia remota" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Detener módulos en " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Selecciona módulos a detener" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Iniciar módulos en " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Introduce lista de {módulo, [opciones]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Lista de módulos a iniciar" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Guardar copia de seguridad en fichero en " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Introduce ruta al fichero de copia de seguridad" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Ruta al fichero" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Restaura copia de seguridad desde el fichero en " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Exporta copia de seguridad a fichero de texto en " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Introduce ruta al fichero de texto" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Importa usuario desde fichero en " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Introduce ruta al fichero jabberd1.4 spool" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Importar usuarios desde el directorio en " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Introduce la ruta al directorio de jabberd1.4 spools" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Ruta al directorio" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Retraso temporal" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Configuración de la Lista de Control de Acceso" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Listas de Control de Acceso" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Configuración de accesos" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Reglas de acceso" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Contraseña" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Verificación de la contraseña" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Número de usuarios registrados" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Número de usuarios conectados" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Nunca" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Conectado" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Última conexión" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Tamaño de la lista de contactos" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "Direcciones IP" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Recursos" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Administración de " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Acción en el usuario" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Editar propiedades" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Eliminar usuario" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Acceso denegado por la política del servicio" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "Transporte de IRC" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "Módulo de IRC para ejabberd" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "" +"Necesitas un cliente con soporte de x:data para configurar las opciones de " +"mod_irc" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Registro en mod_irc para" + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Introduce el nombre de usuario y codificaciones de carácteres que quieras " +"usar al conectar en los servidores de IRC" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "Nombre de usuario en IRC" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Si quieres especificar codificaciones de carácteres distintos para cada " +"servidor IRC rellena esta lista con valores en el formato '{\"servidor irc" +"\", \"codificación\"}'. Este servicio usa por defecto la codificación \"~s" +"\"." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Ejemplo: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Codificaciones" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "" +"Solo los administradores del servicio tienen permiso para enviar mensajes de " +"servicio" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "Se te ha denegado crear la sala por política del servicio" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "La sala de conferencias no existe" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Salas de charla" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "" +"Necesitas un cliente con soporte de x:data para poder registrar el apodo" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Registro del apodo en " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Introduce el apodo que quieras registrar" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Apodo" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "El apodo especificado ya está registrado, tendrás que buscar otro" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Debes rellenar el campo \"Apodo\" en el formulario" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "Módulo de MUC para ejabberd" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Configuración de la sala modificada" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "entra en la sala" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "sale de la sala" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "ha sido bloqueado" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "ha sido expulsado" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "ha sido expulsado por un cambio de su afiliación" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "ha sido expulsado porque la sala es ahora solo para miembros" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "ha sido expulsado porque el sistema se va a detener" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "se cambia el nombre a" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " ha puesto el asunto: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "lunes" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "martes" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "miércoles" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "jueves" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "viernes" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "sábado" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "domingo" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "enero" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "febrero" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "marzo" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "abril" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "mayo" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "junio" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "julio" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "agosto" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "septiembre" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "octubre" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "noviembre" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "diciembre" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Configuración de la sala" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Título de la sala" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Se ha exedido el límite de tráfico" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" +"Este participante ha sido expulsado de la sala porque envió un mensaje de " +"error" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Impedir el envio de mensajes privados a la sala" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Tipo de mensaje incorrecto" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Este participante ha sido expulsado de la sala porque envió un mensaje de " +"error a otro participante" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "No está permitido enviar mensajes privados del tipo \"groupchat\"" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "El receptor no está en la sala de conferencia" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Solo los ocupantes pueden enviar mensajes a la sala" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "No está permitido enviar mensajes privados" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Solo los ocupantes pueden enviar solicitudes a la sala" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "En esta sala no se permiten solicitudes a los miembros de la sala" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "privado" + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "" +"Solo los moderadores y participantes pueden cambiar el asunto de esta sala" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Solo los moderadores pueden cambiar el asunto de esta sala" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "Los visitantes no pueden enviar mensajes a todos los ocupantes" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" +"Este participante ha sido expulsado de la sala porque envió una presencia de " +"error" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Los visitantes no tienen permitido cambiar sus apodos en esta sala" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "El apodo ya está siendo usado por otro ocupante" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "El apodo ya está registrado por otra persona" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Has sido bloqueado en esta sala" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "Necesitas ser miembro de esta sala para poder entrar" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Sala no anónima" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Se necesita contraseña para entrar en esta sala" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Contraseña incorrecta" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Se necesita privilegios de administrador" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Se necesita privilegios de moderador" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "El JID ~s no es válido" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "El apodo ~s no existe en la sala" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Afiliación no válida: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Rol no válido: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Se requieren privilegios de propietario de la sala" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Configuración para " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Descripción:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Sala permanente" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Sala públicamente visible" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "La lista de participantes es pública" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Proteger la sala con contraseña" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Número máximo de ocupantes" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Sin límite" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Los JID reales pueden verlos" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "solo moderadores" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "cualquiera" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Sala sólo para miembros" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Sala moderada" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Los usuarios son participantes por defecto" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Permitir a los usuarios cambiar el asunto" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Permitir a los usuarios enviar mensajes privados" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Permitir a los usuarios consultar a otros usuarios" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Permitir a los usuarios enviar invitaciones" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "" +"Permitir a los visitantes enviar texto de estado en las actualizaciones de " +"presencia" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Permitir a los visitantes cambiarse el apodo" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Guardar históricos" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "Necesitas un cliente con soporte de x:data para configurar la sala" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Número de ocupantes" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s te invita a la sala ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "la contraseña es" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "" +"Tu cola de mensajes diferidos de contactos está llena. El mensaje se ha " +"descartado." + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "Cola de mensajes diferidos de ~s" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Enviado" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Fecha" + +#: mod_offline.erl:507 +msgid "From" +msgstr "De" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Para" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Paquete" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Eliminar los seleccionados" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Mensajes diferidos:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "Módulo SOCKS5 Bytestreams para ejabberd" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Servicio de Publicar-Subscribir" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "Módulo de Publicar-Subscribir de ejabberd" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "Petición de subscriptor de PubSub" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Decidir si aprobar la subscripción de esta entidad." + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "Nodo ID" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Dirección del subscriptor" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "¿Deseas permitir a este JabberID que se subscriba a este nodo PubSub?" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Enviar contenidos junto con las notificaciones de eventos" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Entregar notificaciones de eventos" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Notificar subscriptores cuando cambia la configuración del nodo" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Notificar subscriptores cuando el nodo se borra" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Notificar subscriptores cuando los elementos se borran del nodo" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Persistir elementos al almacenar" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "Un nombre sencillo para el nodo" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Máximo # de elementos que persisten" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Permitir subscripciones" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Especifica el modelo de acceso" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Grupos de contactos que pueden suscribirse" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Especificar el modelo del publicante" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Máximo tamaño del contenido en bytes" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Cuando enviar el último elemento publicado" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Solo enviar notificaciones a los usuarios disponibles" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "" +"Escoge un nombre de usuario y contraseña para registrarte en este servidor" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "Los usuarios no tienen permitido crear cuentas con tanta rapidez" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Ninguno" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Subscripción" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Pendiente" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Grupos" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Validar" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Borrar" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Lista de contactos de " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Mal formato" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Añadir Jabber ID" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Lista de contactos" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Grupos Compartidos" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Añadir nuevo" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Nombre:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Descripción:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Miembros:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Mostrar grupos:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Grupo " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Enviar" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Servidor Jabber en Erlang" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Cumpleaños" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Ciudad" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "País" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "correo" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Apellido" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Rellena el formulario para buscar usuarios Jabber. Añade * al final de un " +"campo para buscar subcadenas." + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Nombre completo" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Segundo nombre" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Nombre" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Nombre de la organización" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Unidad de la organización" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Buscar usuarios en " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Usuario" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "Necesitas un cliente con soporte de x:data para poder buscar" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "Buscar vCard de usuario" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "Módulo vCard para ejabberd" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Buscar resultados por " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Rellena campos para buscar usuarios Jabber que concuerden" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "ejabberd Web Admin" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Administración" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Dominios" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Nodos" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Estadísticas" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Usuarios" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Última actividad" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(crudo)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Crudo" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "Configuración de las Regla de Acceso ~s" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "Dominios de ejabberd" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Última actividad de los usuarios" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Periodo: " + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Último mes" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Último año" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Toda la actividad" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Mostrar Tabla Ordinaria" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Mostrar Tabla Integral" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Nodo no encontrado" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Dominio" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Usuarios registrados" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Mensajes diferidos" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Usuarios registrados:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Usuarios conectados:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Conexiones S2S salientes:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Servidores S2S salientes:" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Cambiar contraseña" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Usuario " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Recursos conectados:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Contraseña:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Sin datos" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Nodo " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Puertos de escucha" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Actualizar" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Reiniciar" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Detener" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "Error en la llamada RPC" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Tablas de la base de datos en " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Tipo de almacenamiento" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Tamaño" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Memoria" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Copia de seguridad de " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Ten en cuenta que estas opciones solo harán copia de seguridad de la base de " +"datos Mnesia embebida. Si estás usando ODBC tendrás que hacer también copia " +"de seguridad de tu base de datos SQL." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Guardar copia de seguridad binaria:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "Aceptar" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Restaurar inmediatamente copia de seguridad binaria:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"Restaurar copia de seguridad binaria en el siguiente reinicio de ejabberd " +"(requiere menos memoria que si instantánea):" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Guardar copia de seguridad en texto plano:" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Restaurar copias de seguridad de texto plano inmediatamente:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Puertos de escucha en " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Módulos en " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "Estadísticas de ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Tiempo desde el inicio:" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "Tiempo consumido de CPU:" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Transacciones finalizadas:" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Transacciones abortadas:" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Transacciones reiniciadas:" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Transacciones registradas:" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Actualizar " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Plan de actualización" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Módulos actualizados" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Script de actualización" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Script de actualización a bajo nivel" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Comprobación de script" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Puerto" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Módulo" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Opciones" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Eliminar" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Iniciar" diff --git a/src/msgs/fr.msg b/src/msgs/fr.msg index aebdf52ff..831f0fc8e 100644 --- a/src/msgs/fr.msg +++ b/src/msgs/fr.msg @@ -1,386 +1,343 @@ -% $Id$ -% Language: French (française) -% Author: Christophe Romain -% Author: Mickaël Rémond -% Author: Vincent Ricard - -% jlib.hrl -{"No resource provided", "Aucune ressource fournie"}. - -% mod_configure.erl -{"Choose storage type of tables", "Choisissez un type de stockage pour les tables"}. -{"RAM copy", "Copie en mémoire vive (RAM)"}. -{"RAM and disc copy", "Copie en mémoire vive (RAM) et sur disque"}. -{"Disc only copy", "Copie sur disque uniquement"}. -{"Remote copy", "Copie distante"}. -{"Stop Modules at ", "Arrêter les modules sur "}. -{"Choose modules to stop", "Sélectionnez les modules à arrêter"}. -{"Start Modules at ", "Démarrer les modules sur "}. -{"Enter list of {Module, [Options]}", "Entrez une liste de {Module, [Options]}"}. -{"List of modules to start", "Liste des modules à démarrer"}. -{"Backup to File at ", "Sauvegarde sur fichier sur "}. -{"Enter path to backup file", "Entrez le chemin vers le fichier de sauvegarde"}. -{"Path to File", "Chemin vers le fichier"}. -{"Restore Backup from File at ", "Restaurer la sauvegarde depuis le fichier sur "}. -{"Dump Backup to Text File at ", "Enregistrer la sauvegarde dans un fichier texte sur "}. -{"Enter path to text file", "Entrez le chemin vers le fichier texte"}. -{"Import User from File at ", "Importer un utilisateur depuis le fichier sur "}. -{"Enter path to jabberd1.4 spool file", "Entrez le chemin vers le fichier spool jabberd1.4"}. -{"Import Users from Dir at ", "Importer des utilisateurs depuis le répertoire sur "}. -{"Enter path to jabberd1.4 spool dir", "Entrez le chemin vers le répertoire de spool jabberd1.4"}. -{"Path to Dir", "Chemin vers le répertoire"}. -{"Access Control List Configuration", "Configuration des droits (ACL)"}. -{"Access control lists", "Droits (ACL)"}. -{"Access Configuration", "Configuration d'accès"}. -{"Access rules", "Règles d'accès"}. -{"Administration of ", "Administration de "}. -{"Action on user", "Action sur l'utilisateur"}. -{"Edit Properties", "Modifier les propriétés"}. -{"Remove User", "Supprimer l'utilisateur"}. -{"Database", "Base de données"}. -{"Outgoing s2s Connections", "Connexions s2s sortantes"}. -{"Import Users From jabberd 1.4 Spool Files", "Importer des utilisateurs depuis un fichier spool Jabberd 1.4"}. -{"Database Tables Configuration at ", "Configuration des tables de base de données sur "}. -{"Restart Service", "Redémarrer le service"}. -{"Shut Down Service", "Arrêter le service"}. -{"Delete User", "Supprimer l'utilisateur"}. -{"End User Session", "Terminer la session de l'utilisateur"}. -{"Get User Password", "Récupérer le mot de passe de l'utilisateur"}. -{"Change User Password", "Changer le mot de passe de l'utilisateur"}. -{"Get User Last Login Time", "Récupérer la dernière date de connexion de l'utilisateur"}. -{"Get User Statistics", "Récupérer les statistiques de l'utilisateur"}. -{"Get Number of Registered Users", "Récupérer le nombre d'utilisateurs enregistrés"}. -{"Get Number of Online Users", "Récupérer le nombre d'utilisateurs en ligne"}. -{"User Management", "Gestion des utilisateurs"}. -{"Time delay", "Délais"}. -{"Password Verification", "Vérification du mot de passe"}. -{"Number of registered users", "Nombre d'utilisateurs enregistrés"}. -{"Number of online users", "Nombre d'utilisateurs en ligne"}. -{"Last login", "Dernière connexion"}. -{"Roster size", "Taille de la liste de contacts"}. -{"IP addresses", "Adresses IP"}. -{"Resources", "Ressources"}. - - -% src/ejabberd_c2s.erl -{"Use of STARTTLS required", "L'utilisation de STARTTLS est impérative"}. -{"Replaced by new connection", "Remplacé par une nouvelle connexion"}. - -% mod_disco.erl -{"Configuration", "Configuration"}. -{"Online Users", "Utilisateurs en ligne"}. -{"All Users", "Tous les utilisateurs"}. -{"To ~s", "A ~s"}. -{"From ~s", "De ~s"}. -{"Running Nodes", "Noeuds actifs"}. -{"Stopped Nodes", "Noeuds arrêtés"}. -{"Access Control Lists", "Droits (ACL)"}. -{"Access Rules", "Règles d'accès"}. -{"Modules", "Modules"}. -{"Start Modules", "Modules de démarrage"}. -{"Stop Modules", "Modules d'arrêt"}. -{"Backup Management", "Gestion des sauvegardes"}. -{"Backup", "Sauvegarde"}. -{"Restore", "Restauration"}. -{"Dump to Text File", "Sauvegarder dans un fichier texte"}. -{"Import File", "Importer un fichier"}. -{"Import Directory", "Importer une répertoire"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Choisissez un nom d'utilisateur et un mot de passe pour s'enregistrer sur ce serveur"}. - -% src/mod_vcard_ldap.erl -{"Erlang Jabber Server", "Serveur Jabber Erlang"}. -{"ejabberd vCard module", "Module vCard ejabberd"}. -{"Email", "Email"}. -{"Search Results for ", "Résultats de recherche pour "}. -{"Jabber ID", "Jabber ID"}. - -% mod_vcard.erl -{"You need an x:data capable client to search", "Vous avez besoin d'un client supportant x:data pour faire une recherche"}. -{"Search users in ", "Rechercher des utilisateurs "}. -{"vCard User Search", "Recherche dans l'annnuaire"}. -{"Fill in fields to search for any matching Jabber User", "Remplissez les champs pour rechercher un utilisateur Jabber"}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Remplissez le formulaire pour recherche un utilisateur Jabber (Ajouter * à la fin du champ pour chercher n'importe quelle fin de chaîne"}. -{"User", "Utilisateur"}. -{"Full Name", "Nom complet"}. -{"Name", "Nom"}. -{"Middle Name", "Autre nom"}. -{"Family Name", "Nom de famille"}. -{"Nickname", "Surnom"}. -{"Birthday", "Date d'anniversaire"}. -{"Country", "Pays"}. -{"City", "Ville"}. -{"Organization Name", "Nom de l'organisation"}. -{"Organization Unit", "Unité de l'organisation"}. - -% mod_adhoc.erl -{"Commands", "Commandes"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% mod_announce.erl -{"Really delete message of the day?", "Confirmer la suppression du message du jour ?"}. -{"Subject", "Sujet"}. -{"Message body", "Corps du message"}. -{"No body provided for announce message", "Pas de corps de message pour l'annonce"}. -{"Announcements", "Annonces"}. -{"Send announcement to all users", "Envoyer l'annonce à tous les utilisateurs"}. -{"Send announcement to all online users", "Envoyer l'annonce à tous les utilisateurs en ligne"}. -{"Send announcement to all online users on all hosts", "Envoyer l'annonce à tous les utilisateurs en ligne sur tous les serveurs"}. -{"Set message of the day and send to online users", "Définir le message du jour et l'envoyer aux utilisateurs en ligne"}. -{"Update message of the day (don't send)", "Mise à jour du message du jour (pas d'envoi)"}. -{"Delete message of the day", "Supprimer le message du jour"}. -{"Send announcement to all users on all hosts", "Envoyer une annonce à tous les utilisateurs de tous les domaines"}. -{"Set message of the day on all hosts and send to online users", "Définir le message du jour pour tous domaines et l'envoyer aux utilisateurs en ligne"}. -{"Update message of the day on all hosts (don't send)", "Mettre à jour le message du jour sur tous les domaines (ne pas envoyer)"}. -{"Delete message of the day on all hosts", "Supprimer le message du jour sur tous les domaines"}. - - -% mod_pubsub/mod_pubsub.erl -{"Choose whether to approve this entity's subscription.", "Accepter cet abonnement ?"}. -{"Roster groups allowed to subscribe", "Groupes de liste de contact autorisés à s'abonner"}. -{"Deliver payloads with event notifications", "Inclure le contenu du message avec la notification"}. -{"Notify subscribers when the node configuration changes", "Avertir les abonnés lorsque la configuration du noeud change"}. -{"Notify subscribers when the node is deleted", "Avertir les abonnés lorsque le noeud est supprimé"}. -{"Notify subscribers when items are removed from the node", "Avertir les abonnés lorsque des éléments sont supprimés sur le noeud"}. -{"Persist items to storage", "Stockage persistant des éléments"}. -{"Max # of items to persist", "Nombre maximum d'éléments à stocker"}. -{"Whether to allow subscriptions", "Autoriser l'abonnement ?"}. -{"Specify the publisher model", "Définir le modèle de publication"}. -{"Max payload size in bytes", "Taille maximum pour le contenu du message en octet"}. -{"Only deliver notifications to available users", "Envoyer les notifications uniquement aux utilisateurs disponibles"}. -{"Publish-Subscribe", "Publication-Abonnement"}. -{"ejabberd Publish-Subscribe module", "Module Publish-Subscribe d'ejabberd"}. -{"PubSub subscriber request", "Demande d'abonnement PubSub"}. -{"Node ID", "Identifiant du noeud"}. -{"Subscriber Address", "Adresse de l'abonné"}. -{"Allow this JID to subscribe to this pubsub node?", "Autoriser ce JID à s'abonner à ce noeud pubsub"}. -{"Deliver event notifications", "Envoyer les notifications d'événement"}. -{"Specify the access model", "Définir le modèle d'accès"}. -{"When to send the last published item", "A quel moment envoyer le dernier élément publié"}. - -% mod_muc/mod_muc_log.erl -{"Chatroom configuration modified", "Configuration du salon modifiée"}. -{"joins the room", "rejoint le salon"}. -{"leaves the room", "quitte le salon"}. -{"has been kicked", "a été expulsé"}. -{"has been banned", "a été banni"}. -{"is now known as", "est maintenant connu comme"}. -{"Monday", "Lundi"}. -{"Tuesday", "Mardi"}. -{"Wednesday", "Mercredi"}. -{"Thursday", "Jeudi"}. -{"Friday", "Vendredi"}. -{"Saturday", "Samedi"}. -{"Sunday", "Dimanche"}. -{"January", "Janvier"}. -{"February", "Février"}. -{"March", "Mars"}. -{"April", "Avril"}. -{"May", "Mai"}. -{"June", "Juin"}. -{"July", "Juillet"}. -{"August", "Août"}. -{"September", "Septembre"}. -{"October", "Octobre"}. -{"November", "Novembre"}. -{"December", "Décembre"}. -{"Room Configuration", "Configuration du salon"}. -{"has been kicked because of an affiliation change", "a été éjecté à cause d'un changement d'autorisation"}. -{"has been kicked because the room has been changed to members-only", "a été éjecté car la salle est désormais réservée aux membres"}. -{"has been kicked because of a system shutdown", "a été éjecté en raison de l'arrêt du système"}. - - -% mod_muc/mod_muc.erl -{"You need an x:data capable client to register nickname", "Vous avez besoin d'un client supportant x:data pour enregistrer un pseudo"}. -{"Nickname Registration at ", "Enregistrement d'un pseudo sur "}. -{"Enter nickname you want to register", "Entrez le pseudo que vous souhaitez enregistrer"}. -{"ejabberd MUC module", "Module MUC ejabberd"}. -{"Only service administrators are allowed to send service messages", "Seuls les administrateurs du service sont autoriser à envoyer des messages de service"}. -{"Room creation is denied by service policy", "La création de salons est interdite par le service"}. -{"Conference room does not exist", "La salle de conférence n'existe pas"}. -{"Access denied by service policy", "L'accès au service est refusé"}. -{"Specified nickname is already registered", "Le pseudo demandé est déjà enregistré"}. -{"You must fill in field \"Nickname\" in the form", "Vous devez préciser le champ \"pseudo\" dans le formulaire"}. -{"Chatrooms", "Salons de discussion"}. - -% mod_muc/mod_muc_room.erl -{"This participant is kicked from the room because he sent an error message", "Ce participant est expulsé du salon pour avoir envoyé un message erroné"}. -{"This participant is kicked from the room because he sent an error message to another participant", "Ce participant est expulsé du salon pour avoir envoyé un message erroné à un autre participant"}. -{"This participant is kicked from the room because he sent an error presence", "Ce participant est expulsé du salon pour avoir envoyé une présence erroné"}. -{"Make room moderated", "Rendre le salon modéré"}. -{" has set the subject to: ", " a changé le sujet pour: "}. -{"You need an x:data capable client to configure room", "Vous avez besoin d'un client supportant x:data pour configurer le salon"}. -{"Configuration for ", "Configuration pour "}. -{"Room title", "Titre du salon"}. -{"Password", "Mot de passe"}. -{"Only moderators and participants are allowed to change subject in this room", "Seuls les modérateurs et les participants peuvent changer le sujet dans ce salon"}. -{"Only moderators are allowed to change subject in this room", "Seuls les modérateurs peuvent changer le sujet dans ce salon"}. -{"Visitors are not allowed to send messages to all occupants", "Les visiteurs ne sont pas autorisés à envoyer des messages à tout les occupants"}. -{"Only occupants are allowed to send messages to the conference", "Seuls les occupants peuvent envoyer des messages à la conférence"}. -{"It is not allowed to send private messages to the conference", "Il n'est pas permis d'envoyer des messages \"normaux\" à la conférence"}. -{"Improper message type", "Mauvais type de message"}. -{"Nickname is already in use by another occupant", "Le pseudo est déjà utilisé par un autre occupant"}. -{"Nickname is registered by another person", "Le pseudo est enregistré par une autre personne"}. -{"It is not allowed to send private messages of type \"groupchat\"", "Il n'est pas permis d'envoyer des messages privés de type \"groupchat\""}. -{"Recipient is not in the conference room", "Le destinataire n'est pas dans la conférence"}. -{"Only occupants are allowed to send queries to the conference", "Seuls les occupants sont autorisés à envoyer des requêtes à la conférence"}. -{"Queries to the conference members are not allowed in this room", "Les requêtes sur les membres de la conférence ne sont pas autorisé dans ce salon"}. -{"You have been banned from this room", "Vous avez été exclus de ce salon"}. -{"Membership required to enter this room", "Vous devez être membre pour accèder à ce salon"}. -{"Password required to enter this room", "Un mot de passe est nécessaire pour accèder à ce salon"}. -{"Incorrect password", "Mot de passe incorrect"}. -{"Administrator privileges required", "Les droits d'administrateur sont nécessaires"}. -{"Moderator privileges required", "Les droits de modérateur sont nécessaires"}. -{"JID ~s is invalid", "Le JID ~s n'est pas valide"}. -{"Nickname ~s does not exist in the room", "Le pseudo ~s n'existe pas dans ce salon"}. -{"Invalid affiliation: ~s", "Affiliation invalide: ~s"}. -{"Invalid role: ~s", "Role invalide: ~s"}. -{"Owner privileges required", "Les droits de propriétaire sont nécessaires"}. -{"private, ", "privé"}. -{"This room is not anonymous", "Ce salon n'est pas anonyme"}. -{"Make room persistent", "Rendre le salon persistant"}. -{"Make room public searchable", "Rendre le salon public"}. -{"Make participants list public", "Rendre la liste des participants publique"}. -{"Make room password protected", "Protéger le salon par mot de passe"}. -{"Make room members-only", "Réserver le salon aux membres uniquement"}. -{"Default users as participants", "Les utilisateurs sont par défaut participant"}. -{"Allow users to change subject", "Autoriser les utilisateurs à changer le sujet"}. -{"Allow users to send private messages", "Autoriser les utilisateurs à envoyer des messages privés"}. -{"Allow users to query other users", "Permettre aux utilisateurs d'envoyer des requêtes aux autres utilisateurs"}. -{"Allow users to send invites", "Permettre aux utilisateurs d'envoyer des invitations"}. -{"Enable logging", "Activer l'archivage"}. -{"Number of occupants", "Nombre d'occupants"}. -{"Present real JIDs to", "Rendre le JID réel visible pour"}. -{"moderators only", "modérateurs seulement"}. -{"anyone", "tout le monde"}. -{"Traffic rate limit is exceeded", "La limite de trafic a été dépassée"}. -{"Maximum Number of Occupants", "Nombre maximum d'occupants"}. -{"No limit", "Pas de limite"}. -{"~s invites you to the room ~s", "~s vous a invité dans la salle de discussion ~s"}. -{"the password is", "le mot de passe est"}. - -% mod_irc/mod_irc.erl -{"ejabberd IRC module", "Module IRC ejabberd"}. -{"You need an x:data capable client to configure mod_irc settings", "Vous avez besoin d'un client supportant x:data pour configurer le module IRC"}. -{"Registration in mod_irc for ", "Enregistrement du mod_irc pour "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Entrez le nom d'utilisateur et les encodages que vous souhaitez utiliser pour vous connecter aux serveurs IRC"}. -{"IRC Username", "Nom d'utilisateur IRC"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Si vous voulez préciser différents encodages pour les serveurs IRC, remplissez cette liste avec des valeurs dans le format '{\"serveur irc\", \"encodage\"}'. Par défaut ce service utilise l'encodage \"~s\"."}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Exemple: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"Encodings", "Encodages"}. -{"IRC Transport", "Passerelle IRC"}. - -% web/ejabberd_web_admin.erl -{"ejabberd Web Admin", "Console Web d'administration de ejabberd"}. -{"Administration", "Administration"}. -{"Users", "Utilisateurs"}. -{"Nodes", "Noeuds"}. -{"Statistics", "Statistiques"}. -{"(Raw)", "(Brut)"}. -{"Submitted", "Soumis"}. -{"Bad format", "Mauvais format"}. -{"Raw", "Brut"}. -{"Delete Selected", "Suppression des éléments sélectionnés"}. -{"Submit", "Soumettre"}. -{"~s access rule configuration", "Configuration des règles d'accès ~s"}. -{"Node not found", "Noeud non trouvé"}. -{"Add New", "Ajouter"}. -{"Registered Users", "Utilisateurs enregistrés"}. -{"Registered Users:", "Utilisateurs enregistrés:"}. -{"Change Password", "Modifier le mot de passe"}. -{"Connected Resources:", "Ressources connectées:"}. -{"Password:", "Mot de passe:"}. -{"None", "Aucun"}. -{"Node ", "Noeud "}. -{"Listened Ports", "Ports ouverts"}. -{"Restart", "Redémarrer"}. -{"Stop", "Arrêter"}. -{"RPC Call Error", "Erreur d'appel RPC"}. -{"Name", "Nom"}. -{"Storage Type", "Type de stockage"}. -{"Size", "Taille"}. -{"Memory", "Mémoire"}. -{"OK", "OK"}. -{"Listened Ports at ", "Ports ouverts sur "}. -{"Uptime:", "Temps depuis le démarrage:"}. -{"CPU Time:", "Temps CPU:"}. -{"Transactions Commited:", "Transactions commitées:"}. -{"Transactions Aborted:", "Transactions annulées:"}. -{"Transactions Restarted:", "Transactions redémarrées:"}. -{"Transactions Logged:", "Transactions journalisées:"}. -{"Port", "Port"}. -{"Module", "Module"}. -{"Options", "Options"}. -{"Update", "Mettre à jour"}. -{"Delete", "Supprimer"}. -{"Add User", "Ajouter un utilisateur"}. -{"Offline Messages", "Messages en attente"}. -{"Users Last Activity", "Dernière activité des utilisateurs"}. -{"Never", "Jamais"}. -{"~s's Offline Messages Queue", "~s messages en file d'attente"}. -{"Time", "Heure"}. -{"From", "De"}. -{"To", "A"}. -{"Packet", "Paquet"}. -{"Offline Messages:", "Messages en attente:"}. -{"Roster", "Liste de contacts"}. -{"Nickname", "Pseudo"}. -{"Subscription", "Abonnement"}. -{"Pending", "En suspend"}. -{"Groups", "Groupes"}. -{"Remove", "Enlever"}. -{"Add Jabber ID", "Ajouter un Jabber ID"}. -{"User ", "Utilisateur "}. -{"Roster of ", "Liste de contact de "}. -{"Online", "En ligne"}. -{"Validate", "Valider"}. -{"Name:", "Nom:"}. -{"Description:", "Description:"}. -{"Members:", "Membres:"}. -{"Displayed Groups:", "Groupes affichés:"}. -{"Group ", "Groupe "}. -{"Period: ", "Période:"}. -{"Last month", "Dernier mois"}. -{"Last year", "Dernière année"}. -{"All activity", "Toute activité"}. -{"Show Ordinary Table", "Montrer la table ordinaire"}. -{"Show Integral Table", "Montrer la table intégralement"}. -{"Modules at ", "Modules sur "}. -{"Start", "Démarrer"}. -{"Virtual Hosts", "Serveurs virtuels"}. -{"ejabberd virtual hosts", "Serveurs virtuels d'ejabberd"}. -{"Host", "Serveur"}. -{"No Data", "Aucune information disponible"}. -{"Online Users:", "Utilisateurs connectés:"}. -{"Outgoing s2s Connections:", "Connexions s2s sortantes:"}. -{"Outgoing s2s Servers:", "Serveurs s2s sortants"}. -{"Database Tables at ", "Tables de base de données sur "}. -{"Backup of ", "Sauvegarde de "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "Ces options sauvegardent uniquement la base de données interne Mnesia. Si vous utilisez le module ODBC vous devez sauvegarde votre base SQL séparément."}. -{"Store binary backup:", "Sauvegarde binaire:"}. -{"Restore binary backup immediately:", "Restauration immédiate d'une sauvegarde binaire:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Restauration de la sauvegarde binaire après redémarrage (nécessite moins de mémoire):"}. -{"Store plain text backup:", "Sauvegarde texte:"}. -{"Restore plain text backup immediately:", "Restauration immédiate d'une sauvegarde texte:"}. -{"Statistics of ~p", "Statistiques de ~p"}. -{"Update ", "Mise à jour "}. -{"Update plan", "Plan de mise à jour"}. -{"Updated modules", "Modules mis à jours"}. -{"Update script", "Script de mise à jour"}. -{"Low level update script", "Script de mise à jour de bas-niveau"}. -{"Script check", "Validation du script"}. -{"Shared Roster Groups", "Groupes de liste de contacts partagée"}. -{"Last Activity", "Dernière Activité"}. - -% mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "ejabberd SOCKS5 Bytestreams module"}. - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "La file d'attente de message de votre contact est pleine. Votre message a été détruit."}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Configuration d'accès"}. +{"Access Control List Configuration","Configuration des droits (ACL)"}. +{"Access control lists","Droits (ACL)"}. +{"Access Control Lists","Droits (ACL)"}. +{"Access denied by service policy","L'accès au service est refusé"}. +{"Access rules","Règles d'accès"}. +{"Access Rules","Règles d'accès"}. +{"Action on user","Action sur l'utilisateur"}. +{"Add Jabber ID","Ajouter un Jabber ID"}. +{"Add New","Ajouter"}. +{"Add User","Ajouter un utilisateur"}. +{"Administration","Administration"}. +{"Administration of ","Administration de "}. +{"Administrator privileges required","Les droits d'administrateur sont nécessaires"}. +{"A friendly name for the node","Un nom convivial pour le noeud"}. +{"All activity","Toute activité"}. +{"Allow this JID to subscribe to this pubsub node?","Autoriser ce JID à s'abonner à ce noeud pubsub"}. +{"Allow users to change subject","Autoriser les utilisateurs à changer le sujet"}. +{"Allow users to query other users","Permettre aux utilisateurs d'envoyer des requêtes aux autres utilisateurs"}. +{"Allow users to send invites","Permettre aux utilisateurs d'envoyer des invitations"}. +{"Allow users to send private messages","Autoriser les utilisateurs à envoyer des messages privés"}. +{"Allow visitors to change nickname","Autoriser les visiteurs à changer de pseudo"}. +{"Allow visitors to send status text in presence updates","Autoriser les visiteurs à envoyer un message d'état avec leur présence"}. +{"All Users","Tous les utilisateurs"}. +{"Announcements","Annonces"}. +{"anyone","tout le monde"}. +{"April","Avril"}. +{"August","Août"}. +{"Backup Management","Gestion des sauvegardes"}. +{"Backup of ","Sauvegarde de "}. +{"Backup","Sauvegarde"}. +{"Backup to File at ","Sauvegarde sur fichier sur "}. +{"Bad format","Mauvais format"}. +{"Birthday","Date d'anniversaire"}. +{"Change Password","Modifier le mot de passe"}. +{"Change User Password","Changer le mot de passe de l'utilisateur"}. +{"Chatroom configuration modified","Configuration du salon modifiée"}. +{"Chatrooms","Salons de discussion"}. +{"Choose a username and password to register with this server","Choisissez un nom d'utilisateur et un mot de passe pour s'enregistrer sur ce serveur"}. +{"Choose modules to stop","Sélectionnez les modules à arrêter"}. +{"Choose storage type of tables","Choisissez un type de stockage pour les tables"}. +{"Choose whether to approve this entity's subscription.","Accepter cet abonnement ?"}. +{"City","Ville"}. +{"Commands","Commandes"}. +{"Conference room does not exist","La salle de conférence n'existe pas"}. +{"Configuration","Configuration"}. +{"Configuration for ","Configuration pour "}. +{"Connected Resources:","Ressources connectées:"}. +{"Country","Pays"}. +{"CPU Time:","Temps CPU:"}. +{"Database","Base de données"}. +{"Database Tables at ","Tables de base de données sur "}. +{"Database Tables Configuration at ","Configuration des tables de base de données sur "}. +{"December","Décembre"}. +{"Default users as participants","Les utilisateurs sont par défaut participant"}. +{"Delete message of the day on all hosts","Supprimer le message du jour sur tous les domaines"}. +{"Delete message of the day","Supprimer le message du jour"}. +{"Delete Selected","Suppression des éléments sélectionnés"}. +{"Delete","Supprimer"}. +{"Delete User","Supprimer l'utilisateur"}. +{"Deliver event notifications","Envoyer les notifications d'événement"}. +{"Deliver payloads with event notifications","Inclure le contenu du message avec la notification"}. +{"Description:","Description:"}. +{"Disc only copy","Copie sur disque uniquement"}. +{"Displayed Groups:","Groupes affichés:"}. +{"Dump Backup to Text File at ","Enregistrer la sauvegarde dans un fichier texte sur "}. +{"Dump to Text File","Sauvegarder dans un fichier texte"}. +{"Edit Properties","Modifier les propriétés"}. +{"ejabberd IRC module","Module IRC ejabberd"}. +{"ejabberd MUC module","Module MUC ejabberd"}. +{"ejabberd Publish-Subscribe module","Module Publish-Subscribe d'ejabberd"}. +{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestreams module"}. +{"ejabberd vCard module","Module vCard ejabberd"}. +{"ejabberd virtual hosts","Serveurs virtuels d'ejabberd"}. +{"ejabberd Web Admin","Console Web d'administration de ejabberd"}. +{"Email","Email"}. +{"Enable logging","Activer l'archivage"}. +{"Encodings","Encodages"}. +{"End User Session","Terminer la session de l'utilisateur"}. +{"Enter list of {Module, [Options]}","Entrez une liste de {Module, [Options]}"}. +{"Enter nickname you want to register","Entrez le pseudo que vous souhaitez enregistrer"}. +{"Enter path to backup file","Entrez le chemin vers le fichier de sauvegarde"}. +{"Enter path to jabberd1.4 spool dir","Entrez le chemin vers le répertoire de spool jabberd1.4"}. +{"Enter path to jabberd1.4 spool file","Entrez le chemin vers le fichier spool jabberd1.4"}. +{"Enter path to text file","Entrez le chemin vers le fichier texte"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Entrez le nom d'utilisateur et les encodages que vous souhaitez utiliser pour vous connecter aux serveurs IRC"}. +{"Erlang Jabber Server","Serveur Jabber Erlang"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Exemple: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","Nom de famille"}. +{"February","Février"}. +{"Fill in fields to search for any matching Jabber User","Remplissez les champs pour rechercher un utilisateur Jabber"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Remplissez le formulaire pour recherche un utilisateur Jabber (Ajouter * à la fin du champ pour chercher n'importe quelle fin de chaîne"}. +{"Friday","Vendredi"}. +{"From","De"}. +{"From ~s","De ~s"}. +{"Full Name","Nom complet"}. +{"Get Number of Online Users","Récupérer le nombre d'utilisateurs en ligne"}. +{"Get Number of Registered Users","Récupérer le nombre d'utilisateurs enregistrés"}. +{"Get User Last Login Time","Récupérer la dernière date de connexion de l'utilisateur"}. +{"Get User Password","Récupérer le mot de passe de l'utilisateur"}. +{"Get User Statistics","Récupérer les statistiques de l'utilisateur"}. +{"Group ","Groupe "}. +{"Groups","Groupes"}. +{"has been banned","a été banni"}. +{"has been kicked","a été expulsé"}. +{"has been kicked because of an affiliation change","a été éjecté à cause d'un changement d'autorisation"}. +{"has been kicked because of a system shutdown","a été éjecté en raison de l'arrêt du système"}. +{"has been kicked because the room has been changed to members-only","a été éjecté car la salle est désormais réservée aux membres"}. +{" has set the subject to: "," a changé le sujet pour: "}. +{"Host","Serveur"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Si vous voulez préciser différents encodages pour les serveurs IRC, remplissez cette liste avec des valeurs dans le format '{\"serveur irc\", \"encodage\"}'. Par défaut ce service utilise l'encodage \"~s\"."}. +{"Import Directory","Importer une répertoire"}. +{"Import File","Importer un fichier"}. +{"Import User from File at ","Importer un utilisateur depuis le fichier sur "}. +{"Import Users from Dir at ","Importer des utilisateurs depuis le répertoire sur "}. +{"Import Users From jabberd 1.4 Spool Files","Importer des utilisateurs depuis un fichier spool Jabberd 1.4"}. +{"Improper message type","Mauvais type de message"}. +{"Incorrect password","Mot de passe incorrect"}. +{"Invalid affiliation: ~s","Affiliation invalide: ~s"}. +{"Invalid role: ~s","Role invalide: ~s"}. +{"IP addresses","Adresses IP"}. +{"IRC Transport","Passerelle IRC"}. +{"IRC Username","Nom d'utilisateur IRC"}. +{"is now known as","est maintenant connu comme"}. +{"It is not allowed to send private messages","L'envoi de messages privés n'est pas autorisé"}. +{"It is not allowed to send private messages of type \"groupchat\"","Il n'est pas permis d'envoyer des messages privés de type \"groupchat\""}. +{"It is not allowed to send private messages to the conference","Il n'est pas permis d'envoyer des messages \"normaux\" à la conférence"}. +{"Jabber ID","Jabber ID"}. +{"January","Janvier"}. +{"JID ~s is invalid","Le JID ~s n'est pas valide"}. +{"joins the room","rejoint le salon"}. +{"July","Juillet"}. +{"June","Juin"}. +{"Last Activity","Dernière Activité"}. +{"Last login","Dernière connexion"}. +{"Last month","Dernier mois"}. +{"Last year","Dernière année"}. +{"leaves the room","quitte le salon"}. +{"Listened Ports at ","Ports ouverts sur "}. +{"Listened Ports","Ports ouverts"}. +{"List of modules to start","Liste des modules à démarrer"}. +{"Low level update script","Script de mise à jour de bas-niveau"}. +{"Make participants list public","Rendre la liste des participants publique"}. +{"Make room members-only","Réserver le salon aux membres uniquement"}. +{"Make room moderated","Rendre le salon modéré"}. +{"Make room password protected","Protéger le salon par mot de passe"}. +{"Make room persistent","Rendre le salon persistant"}. +{"Make room public searchable","Rendre le salon public"}. +{"March","Mars"}. +{"Maximum Number of Occupants","Nombre maximum d'occupants"}. +{"Max # of items to persist","Nombre maximum d'éléments à stocker"}. +{"Max payload size in bytes","Taille maximum pour le contenu du message en octet"}. +{"May","Mai"}. +{"Membership required to enter this room","Vous devez être membre pour accèder à ce salon"}. +{"Members:","Membres:"}. +{"Memory","Mémoire"}. +{"Message body","Corps du message"}. +{"Middle Name","Autre nom"}. +{"Moderator privileges required","Les droits de modérateur sont nécessaires"}. +{"moderators only","modérateurs seulement"}. +{"Module","Module"}. +{"Modules at ","Modules sur "}. +{"Modules","Modules"}. +{"Monday","Lundi"}. +{"Name:","Nom:"}. +{"Name","Nom"}. +{"Never","Jamais"}. +{"Nickname is already in use by another occupant","Le pseudo est déjà utilisé par un autre occupant"}. +{"Nickname is registered by another person","Le pseudo est enregistré par une autre personne"}. +{"Nickname","Pseudo"}. +{"Nickname Registration at ","Enregistrement d'un pseudo sur "}. +{"Nickname ~s does not exist in the room","Le pseudo ~s n'existe pas dans ce salon"}. +{"No body provided for announce message","Pas de corps de message pour l'annonce"}. +{"No Data","Aucune information disponible"}. +{"Node ID","Identifiant du noeud"}. +{"Node ","Noeud "}. +{"Node not found","Noeud non trouvé"}. +{"Nodes","Noeuds"}. +{"No limit","Pas de limite"}. +{"None","Aucun"}. +{"No resource provided","Aucune ressource fournie"}. +{"Notify subscribers when items are removed from the node","Avertir les abonnés lorsque des éléments sont supprimés sur le noeud"}. +{"Notify subscribers when the node configuration changes","Avertir les abonnés lorsque la configuration du noeud change"}. +{"Notify subscribers when the node is deleted","Avertir les abonnés lorsque le noeud est supprimé"}. +{"November","Novembre"}. +{"Number of occupants","Nombre d'occupants"}. +{"Number of online users","Nombre d'utilisateurs en ligne"}. +{"Number of registered users","Nombre d'utilisateurs enregistrés"}. +{"October","Octobre"}. +{"Offline Messages:","Messages en attente:"}. +{"Offline Messages","Messages en attente"}. +{"OK","OK"}. +{"Online","En ligne"}. +{"Online Users:","Utilisateurs connectés:"}. +{"Online Users","Utilisateurs en ligne"}. +{"Only deliver notifications to available users","Envoyer les notifications uniquement aux utilisateurs disponibles"}. +{"Only moderators and participants are allowed to change subject in this room","Seuls les modérateurs et les participants peuvent changer le sujet dans ce salon"}. +{"Only moderators are allowed to change subject in this room","Seuls les modérateurs peuvent changer le sujet dans ce salon"}. +{"Only occupants are allowed to send messages to the conference","Seuls les occupants peuvent envoyer des messages à la conférence"}. +{"Only occupants are allowed to send queries to the conference","Seuls les occupants sont autorisés à envoyer des requêtes à la conférence"}. +{"Only service administrators are allowed to send service messages","Seuls les administrateurs du service sont autoriser à envoyer des messages de service"}. +{"Options","Options"}. +{"Organization Name","Nom de l'organisation"}. +{"Organization Unit","Unité de l'organisation"}. +{"Outgoing s2s Connections:","Connexions s2s sortantes:"}. +{"Outgoing s2s Connections","Connexions s2s sortantes"}. +{"Outgoing s2s Servers:","Serveurs s2s sortants"}. +{"Owner privileges required","Les droits de propriétaire sont nécessaires"}. +{"Packet","Paquet"}. +{"Password:","Mot de passe:"}. +{"Password","Mot de passe"}. +{"Password required to enter this room","Un mot de passe est nécessaire pour accèder à ce salon"}. +{"Password Verification","Vérification du mot de passe"}. +{"Path to Dir","Chemin vers le répertoire"}. +{"Path to File","Chemin vers le fichier"}. +{"Pending","En suspend"}. +{"Period: ","Période:"}. +{"Persist items to storage","Stockage persistant des éléments"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","Port"}. +{"Present real JIDs to","Rendre le JID réel visible pour"}. +{"private, ","privé"}. +{"Publish-Subscribe","Publication-Abonnement"}. +{"PubSub subscriber request","Demande d'abonnement PubSub"}. +{"Queries to the conference members are not allowed in this room","Les requêtes sur les membres de la conférence ne sont pas autorisé dans ce salon"}. +{"RAM and disc copy","Copie en mémoire vive (RAM) et sur disque"}. +{"RAM copy","Copie en mémoire vive (RAM)"}. +{"(Raw)","(Brut)"}. +{"Raw","Brut"}. +{"Really delete message of the day?","Confirmer la suppression du message du jour ?"}. +{"Recipient is not in the conference room","Le destinataire n'est pas dans la conférence"}. +{"Registered Users:","Utilisateurs enregistrés:"}. +{"Registered Users","Utilisateurs enregistrés"}. +{"Registration in mod_irc for ","Enregistrement du mod_irc pour "}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Ces options sauvegardent uniquement la base de données interne Mnesia. Si vous utilisez le module ODBC vous devez sauvegarde votre base SQL séparément."}. +{"Remote copy","Copie distante"}. +{"Remove","Enlever"}. +{"Remove User","Supprimer l'utilisateur"}. +{"Replaced by new connection","Remplacé par une nouvelle connexion"}. +{"Resources","Ressources"}. +{"Restart","Redémarrer"}. +{"Restart Service","Redémarrer le service"}. +{"Restore Backup from File at ","Restaurer la sauvegarde depuis le fichier sur "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Restauration de la sauvegarde binaire après redémarrage (nécessite moins de mémoire):"}. +{"Restore binary backup immediately:","Restauration immédiate d'une sauvegarde binaire:"}. +{"Restore plain text backup immediately:","Restauration immédiate d'une sauvegarde texte:"}. +{"Restore","Restauration"}. +{"Room Configuration","Configuration du salon"}. +{"Room creation is denied by service policy","La création de salons est interdite par le service"}. +{"Room title","Titre du salon"}. +{"Roster groups allowed to subscribe","Groupes de liste de contact autorisés à s'abonner"}. +{"Roster","Liste de contacts"}. +{"Roster of ","Liste de contact de "}. +{"Roster size","Taille de la liste de contacts"}. +{"RPC Call Error","Erreur d'appel RPC"}. +{"Running Nodes","Noeuds actifs"}. +{"~s access rule configuration","Configuration des règles d'accès ~s"}. +{"Saturday","Samedi"}. +{"Script check","Validation du script"}. +{"Search Results for ","Résultats de recherche pour "}. +{"Search users in ","Rechercher des utilisateurs "}. +{"Send announcement to all online users","Envoyer l'annonce à tous les utilisateurs en ligne"}. +{"Send announcement to all online users on all hosts","Envoyer l'annonce à tous les utilisateurs en ligne sur tous les serveurs"}. +{"Send announcement to all users","Envoyer l'annonce à tous les utilisateurs"}. +{"Send announcement to all users on all hosts","Envoyer une annonce à tous les utilisateurs de tous les domaines"}. +{"September","Septembre"}. +{"Set message of the day and send to online users","Définir le message du jour et l'envoyer aux utilisateurs en ligne"}. +{"Set message of the day on all hosts and send to online users","Définir le message du jour pour tous domaines et l'envoyer aux utilisateurs en ligne"}. +{"Shared Roster Groups","Groupes de liste de contacts partagée"}. +{"Show Integral Table","Montrer la table intégralement"}. +{"Show Ordinary Table","Montrer la table ordinaire"}. +{"Shut Down Service","Arrêter le service"}. +{"~s invites you to the room ~s","~s vous a invité dans la salle de discussion ~s"}. +{"Size","Taille"}. +{"Specified nickname is already registered","Le pseudo demandé est déjà enregistré"}. +{"Specify the access model","Définir le modèle d'accès"}. +{"Specify the publisher model","Définir le modèle de publication"}. +{"~s's Offline Messages Queue","~s messages en file d'attente"}. +{"Start","Démarrer"}. +{"Start Modules at ","Démarrer les modules sur "}. +{"Start Modules","Modules de démarrage"}. +{"Statistics of ~p","Statistiques de ~p"}. +{"Statistics","Statistiques"}. +{"Stop","Arrêter"}. +{"Stop Modules at ","Arrêter les modules sur "}. +{"Stop Modules","Modules d'arrêt"}. +{"Stopped Nodes","Noeuds arrêtés"}. +{"Storage Type","Type de stockage"}. +{"Store binary backup:","Sauvegarde binaire:"}. +{"Store plain text backup:","Sauvegarde texte:"}. +{"Subject","Sujet"}. +{"Submit","Soumettre"}. +{"Submitted","Soumis"}. +{"Subscriber Address","Adresse de l'abonné"}. +{"Subscription","Abonnement"}. +{"Sunday","Dimanche"}. +{"the password is","le mot de passe est"}. +{"This participant is kicked from the room because he sent an error message","Ce participant est expulsé du salon pour avoir envoyé un message erroné"}. +{"This participant is kicked from the room because he sent an error message to another participant","Ce participant est expulsé du salon pour avoir envoyé un message erroné à un autre participant"}. +{"This participant is kicked from the room because he sent an error presence","Ce participant est expulsé du salon pour avoir envoyé une présence erroné"}. +{"This room is not anonymous","Ce salon n'est pas anonyme"}. +{"Thursday","Jeudi"}. +{"Time delay","Délais"}. +{"Time","Heure"}. +{"To","A"}. +{"To ~s","A ~s"}. +{"Traffic rate limit is exceeded","La limite de trafic a été dépassée"}. +{"Transactions Aborted:","Transactions annulées:"}. +{"Transactions Commited:","Transactions commitées:"}. +{"Transactions Logged:","Transactions journalisées:"}. +{"Transactions Restarted:","Transactions redémarrées:"}. +{"Tuesday","Mardi"}. +{"Updated modules","Modules mis à jours"}. +{"Update message of the day (don't send)","Mise à jour du message du jour (pas d'envoi)"}. +{"Update message of the day on all hosts (don't send)","Mettre à jour le message du jour sur tous les domaines (ne pas envoyer)"}. +{"Update","Mettre à jour"}. +{"Update ","Mise à jour "}. +{"Update plan","Plan de mise à jour"}. +{"Update script","Script de mise à jour"}. +{"Uptime:","Temps depuis le démarrage:"}. +{"Use of STARTTLS required","L'utilisation de STARTTLS est impérative"}. +{"User Management","Gestion des utilisateurs"}. +{"Users are not allowed to register accounts so fast","Les utilisateurs ne sont pas autorisés à enregistrer des comptes si rapidement"}. +{"Users Last Activity","Dernière activité des utilisateurs"}. +{"Users","Utilisateurs"}. +{"User ","Utilisateur "}. +{"User","Utilisateur"}. +{"Validate","Valider"}. +{"vCard User Search","Recherche dans l'annnuaire"}. +{"Virtual Hosts","Serveurs virtuels"}. +{"Visitors are not allowed to change their nicknames in this room","Les visiteurs ne sont pas autorisés à changer de pseudo dans ce salon"}. +{"Visitors are not allowed to send messages to all occupants","Les visiteurs ne sont pas autorisés à envoyer des messages à tout les occupants"}. +{"Wednesday","Mercredi"}. +{"When to send the last published item","A quel moment envoyer le dernier élément publié"}. +{"Whether to allow subscriptions","Autoriser l'abonnement ?"}. +{"You have been banned from this room","Vous avez été exclus de ce salon"}. +{"You must fill in field \"Nickname\" in the form","Vous devez préciser le champ \"pseudo\" dans le formulaire"}. +{"You need an x:data capable client to configure mod_irc settings","Vous avez besoin d'un client supportant x:data pour configurer le module IRC"}. +{"You need an x:data capable client to configure room","Vous avez besoin d'un client supportant x:data pour configurer le salon"}. +{"You need an x:data capable client to register nickname","Vous avez besoin d'un client supportant x:data pour enregistrer un pseudo"}. +{"You need an x:data capable client to search","Vous avez besoin d'un client supportant x:data pour faire une recherche"}. +{"Your contact offline message queue is full. The message has been discarded.","La file d'attente de message de votre contact est pleine. Votre message a été détruit."}. diff --git a/src/msgs/fr.po b/src/msgs/fr.po new file mode 100644 index 000000000..30f30d52c --- /dev/null +++ b/src/msgs/fr.po @@ -0,0 +1,1512 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Christophe Romain\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: French (française)\n" +"X-Additional-Translator: Mickaël Rémond\n" +"X-Additional-Translator: Vincent Ricard\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "L'utilisation de STARTTLS est impérative" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Aucune ressource fournie" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Remplacé par une nouvelle connexion" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Commandes" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Confirmer la suppression du message du jour ?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Sujet" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Corps du message" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "Pas de corps de message pour l'annonce" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Annonces" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Envoyer l'annonce à tous les utilisateurs" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Envoyer une annonce à tous les utilisateurs de tous les domaines" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Envoyer l'annonce à tous les utilisateurs en ligne" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "" +"Envoyer l'annonce à tous les utilisateurs en ligne sur tous les serveurs" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Définir le message du jour et l'envoyer aux utilisateurs en ligne" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Définir le message du jour pour tous domaines et l'envoyer aux utilisateurs " +"en ligne" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Mise à jour du message du jour (pas d'envoi)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "" +"Mettre à jour le message du jour sur tous les domaines (ne pas envoyer)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Supprimer le message du jour" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Supprimer le message du jour sur tous les domaines" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Configuration" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Base de données" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Modules de démarrage" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Modules d'arrêt" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Sauvegarde" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Restauration" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Sauvegarder dans un fichier texte" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Importer un fichier" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Importer une répertoire" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Redémarrer le service" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Arrêter le service" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Ajouter un utilisateur" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Supprimer l'utilisateur" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Terminer la session de l'utilisateur" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Récupérer le mot de passe de l'utilisateur" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Changer le mot de passe de l'utilisateur" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Récupérer la dernière date de connexion de l'utilisateur" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Récupérer les statistiques de l'utilisateur" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Récupérer le nombre d'utilisateurs enregistrés" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Récupérer le nombre d'utilisateurs en ligne" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Droits (ACL)" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Règles d'accès" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Gestion des utilisateurs" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Utilisateurs en ligne" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Tous les utilisateurs" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Connexions s2s sortantes" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Noeuds actifs" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Noeuds arrêtés" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Modules" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Gestion des sauvegardes" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Importer des utilisateurs depuis un fichier spool Jabberd 1.4" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "A ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "De ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Configuration des tables de base de données sur " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Choisissez un type de stockage pour les tables" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Copie sur disque uniquement" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "Copie en mémoire vive (RAM) et sur disque" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "Copie en mémoire vive (RAM)" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Copie distante" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Arrêter les modules sur " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Sélectionnez les modules à arrêter" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Démarrer les modules sur " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Entrez une liste de {Module, [Options]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Liste des modules à démarrer" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Sauvegarde sur fichier sur " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Entrez le chemin vers le fichier de sauvegarde" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Chemin vers le fichier" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Restaurer la sauvegarde depuis le fichier sur " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Enregistrer la sauvegarde dans un fichier texte sur " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Entrez le chemin vers le fichier texte" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Importer un utilisateur depuis le fichier sur " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Entrez le chemin vers le fichier spool jabberd1.4" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Importer des utilisateurs depuis le répertoire sur " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Entrez le chemin vers le répertoire de spool jabberd1.4" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Chemin vers le répertoire" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Délais" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Configuration des droits (ACL)" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Droits (ACL)" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Configuration d'accès" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Règles d'accès" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Mot de passe" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Vérification du mot de passe" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Nombre d'utilisateurs enregistrés" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Nombre d'utilisateurs en ligne" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Jamais" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "En ligne" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Dernière connexion" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Taille de la liste de contacts" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "Adresses IP" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Ressources" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Administration de " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Action sur l'utilisateur" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Modifier les propriétés" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Supprimer l'utilisateur" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "L'accès au service est refusé" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "Passerelle IRC" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "Module IRC ejabberd" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "" +"Vous avez besoin d'un client supportant x:data pour configurer le module IRC" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Enregistrement du mod_irc pour " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Entrez le nom d'utilisateur et les encodages que vous souhaitez utiliser " +"pour vous connecter aux serveurs IRC" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "Nom d'utilisateur IRC" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Si vous voulez préciser différents encodages pour les serveurs IRC, " +"remplissez cette liste avec des valeurs dans le format '{\"serveur irc\", " +"\"encodage\"}'. Par défaut ce service utilise l'encodage \"~s\"." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Exemple: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Encodages" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "" +"Seuls les administrateurs du service sont autoriser à envoyer des messages " +"de service" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "La création de salons est interdite par le service" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "La salle de conférence n'existe pas" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Salons de discussion" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "" +"Vous avez besoin d'un client supportant x:data pour enregistrer un pseudo" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Enregistrement d'un pseudo sur " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Entrez le pseudo que vous souhaitez enregistrer" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Pseudo" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "Le pseudo demandé est déjà enregistré" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Vous devez préciser le champ \"pseudo\" dans le formulaire" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "Module MUC ejabberd" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Configuration du salon modifiée" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "rejoint le salon" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "quitte le salon" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "a été banni" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "a été expulsé" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "a été éjecté à cause d'un changement d'autorisation" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "a été éjecté car la salle est désormais réservée aux membres" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "a été éjecté en raison de l'arrêt du système" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "est maintenant connu comme" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " a changé le sujet pour: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "Lundi" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "Mardi" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "Mercredi" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "Jeudi" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "Vendredi" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "Samedi" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "Dimanche" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "Janvier" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "Février" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "Mars" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "Avril" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "Mai" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "Juin" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "Juillet" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "Août" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "Septembre" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "Octobre" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "Novembre" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "Décembre" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Configuration du salon" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Titre du salon" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "La limite de trafic a été dépassée" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" +"Ce participant est expulsé du salon pour avoir envoyé un message erroné" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Il n'est pas permis d'envoyer des messages \"normaux\" à la conférence" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Mauvais type de message" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Ce participant est expulsé du salon pour avoir envoyé un message erroné à un " +"autre participant" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "" +"Il n'est pas permis d'envoyer des messages privés de type \"groupchat\"" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "Le destinataire n'est pas dans la conférence" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Seuls les occupants peuvent envoyer des messages à la conférence" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "L'envoi de messages privés n'est pas autorisé" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "" +"Seuls les occupants sont autorisés à envoyer des requêtes à la conférence" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "" +"Les requêtes sur les membres de la conférence ne sont pas autorisé dans ce " +"salon" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "privé" + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "" +"Seuls les modérateurs et les participants peuvent changer le sujet dans ce " +"salon" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Seuls les modérateurs peuvent changer le sujet dans ce salon" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "" +"Les visiteurs ne sont pas autorisés à envoyer des messages à tout les " +"occupants" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" +"Ce participant est expulsé du salon pour avoir envoyé une présence erroné" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Les visiteurs ne sont pas autorisés à changer de pseudo dans ce salon" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "Le pseudo est déjà utilisé par un autre occupant" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "Le pseudo est enregistré par une autre personne" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Vous avez été exclus de ce salon" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "Vous devez être membre pour accèder à ce salon" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Ce salon n'est pas anonyme" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Un mot de passe est nécessaire pour accèder à ce salon" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Mot de passe incorrect" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Les droits d'administrateur sont nécessaires" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Les droits de modérateur sont nécessaires" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "Le JID ~s n'est pas valide" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "Le pseudo ~s n'existe pas dans ce salon" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Affiliation invalide: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Role invalide: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Les droits de propriétaire sont nécessaires" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Configuration pour " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Description:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Rendre le salon persistant" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Rendre le salon public" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Rendre la liste des participants publique" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Protéger le salon par mot de passe" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Nombre maximum d'occupants" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Pas de limite" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Rendre le JID réel visible pour" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "modérateurs seulement" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "tout le monde" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Réserver le salon aux membres uniquement" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Rendre le salon modéré" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Les utilisateurs sont par défaut participant" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Autoriser les utilisateurs à changer le sujet" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Autoriser les utilisateurs à envoyer des messages privés" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "" +"Permettre aux utilisateurs d'envoyer des requêtes aux autres utilisateurs" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Permettre aux utilisateurs d'envoyer des invitations" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "Autoriser les visiteurs à envoyer un message d'état avec leur présence" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Autoriser les visiteurs à changer de pseudo" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Activer l'archivage" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "" +"Vous avez besoin d'un client supportant x:data pour configurer le salon" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Nombre d'occupants" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s vous a invité dans la salle de discussion ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "le mot de passe est" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "" +"La file d'attente de message de votre contact est pleine. Votre message a " +"été détruit." + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "~s messages en file d'attente" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Soumis" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Heure" + +#: mod_offline.erl:507 +msgid "From" +msgstr "De" + +#: mod_offline.erl:508 +msgid "To" +msgstr "A" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Paquet" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Suppression des éléments sélectionnés" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Messages en attente:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "ejabberd SOCKS5 Bytestreams module" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Publication-Abonnement" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "Module Publish-Subscribe d'ejabberd" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "Demande d'abonnement PubSub" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Accepter cet abonnement ?" + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "Identifiant du noeud" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Adresse de l'abonné" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Autoriser ce JID à s'abonner à ce noeud pubsub" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Inclure le contenu du message avec la notification" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Envoyer les notifications d'événement" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Avertir les abonnés lorsque la configuration du noeud change" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Avertir les abonnés lorsque le noeud est supprimé" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Avertir les abonnés lorsque des éléments sont supprimés sur le noeud" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Stockage persistant des éléments" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "Un nom convivial pour le noeud" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Nombre maximum d'éléments à stocker" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Autoriser l'abonnement ?" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Définir le modèle d'accès" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Groupes de liste de contact autorisés à s'abonner" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Définir le modèle de publication" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Taille maximum pour le contenu du message en octet" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "A quel moment envoyer le dernier élément publié" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Envoyer les notifications uniquement aux utilisateurs disponibles" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "" +"Choisissez un nom d'utilisateur et un mot de passe pour s'enregistrer sur ce " +"serveur" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "" +"Les utilisateurs ne sont pas autorisés à enregistrer des comptes si " +"rapidement" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Aucun" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Abonnement" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "En suspend" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Groupes" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Valider" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Enlever" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Liste de contact de " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Mauvais format" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Ajouter un Jabber ID" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Liste de contacts" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Groupes de liste de contacts partagée" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Ajouter" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Nom:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Description:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Membres:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Groupes affichés:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Groupe " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Soumettre" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Serveur Jabber Erlang" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Date d'anniversaire" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Ville" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "Pays" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "Email" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Nom de famille" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Remplissez le formulaire pour recherche un utilisateur Jabber (Ajouter * à " +"la fin du champ pour chercher n'importe quelle fin de chaîne" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Nom complet" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Autre nom" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Nom" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Nom de l'organisation" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Unité de l'organisation" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Rechercher des utilisateurs " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Utilisateur" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "" +"Vous avez besoin d'un client supportant x:data pour faire une recherche" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "Recherche dans l'annnuaire" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "Module vCard ejabberd" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Résultats de recherche pour " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Remplissez les champs pour rechercher un utilisateur Jabber" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "Console Web d'administration de ejabberd" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Administration" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Serveurs virtuels" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Noeuds" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Statistiques" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Utilisateurs" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Dernière Activité" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Brut)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Brut" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "Configuration des règles d'accès ~s" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "Serveurs virtuels d'ejabberd" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Dernière activité des utilisateurs" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Période:" + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Dernier mois" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Dernière année" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Toute activité" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Montrer la table ordinaire" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Montrer la table intégralement" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Noeud non trouvé" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Serveur" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Utilisateurs enregistrés" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Messages en attente" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Utilisateurs enregistrés:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Utilisateurs connectés:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Connexions s2s sortantes:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Serveurs s2s sortants" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Modifier le mot de passe" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Utilisateur " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Ressources connectées:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Mot de passe:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Aucune information disponible" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Noeud " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Ports ouverts" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Mettre à jour" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Redémarrer" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Arrêter" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "Erreur d'appel RPC" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Tables de base de données sur " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Type de stockage" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Taille" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Mémoire" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Sauvegarde de " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Ces options sauvegardent uniquement la base de données interne Mnesia. Si " +"vous utilisez le module ODBC vous devez sauvegarde votre base SQL séparément." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Sauvegarde binaire:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "OK" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Restauration immédiate d'une sauvegarde binaire:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"Restauration de la sauvegarde binaire après redémarrage (nécessite moins de " +"mémoire):" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Sauvegarde texte:" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Restauration immédiate d'une sauvegarde texte:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Ports ouverts sur " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Modules sur " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "Statistiques de ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Temps depuis le démarrage:" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "Temps CPU:" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Transactions commitées:" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Transactions annulées:" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Transactions redémarrées:" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Transactions journalisées:" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Mise à jour " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Plan de mise à jour" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Modules mis à jours" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Script de mise à jour" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Script de mise à jour de bas-niveau" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Validation du script" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Port" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Module" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Options" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Supprimer" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Démarrer" diff --git a/src/msgs/gl.msg b/src/msgs/gl.msg index 6d377c26e..fbfe06a95 100644 --- a/src/msgs/gl.msg +++ b/src/msgs/gl.msg @@ -1,384 +1,337 @@ -% $Id: gl.msg 641 2008-02-15 10:48:05Z mremond $ -% Language: Galician (galego) -% Author: Carlos E. Lopez - suso AT jabber-hispano.org - -% jlib.hrl -{"No resource provided", "Non se proporcionou recurso"}. - -% mod_configure.erl -{"Choose storage type of tables", "Selecciona tipo de almacenamento das táboas"}. -{"RAM copy", "Copia en RAM"}. -{"RAM and disc copy", "Copia en RAM e disco"}. -{"Disc only copy", "Copia en disco soamente"}. -{"Remote copy", "Copia remota"}. -{"Stop Modules at ", "Deter módulos en "}. -{"Choose modules to stop", "Selecciona módulos a deter"}. -{"Start Modules at ", "Iniciar módulos en "}. -{"Enter list of {Module, [Options]}", "Introduce lista de {módulo, [opcións]}"}. -{"List of modules to start", "Lista de módulos a iniciar"}. -{"Backup to File at ", "Gardar copia de seguridade en ficheiro en "}. -{"Enter path to backup file", "Introduce ruta ao ficheiro de copia de seguridade"}. -{"Path to File", "Ruta ao ficheiro"}. -{"Restore Backup from File at ", "Restaura copia de seguridade desde o ficheiro en "}. -{"Dump Backup to Text File at ", "Exporta copia de seguridade a ficheiro de texto en "}. -{"Enter path to text file", "Introduce ruta ao ficheiro de texto"}. -{"Import User from File at ", "Importa usuario desde ficheiro en "}. -{"Enter path to jabberd1.4 spool file", "Introduce ruta ao ficheiro jabberd1.4 spool"}. -{"Import Users from Dir at ", "Importar usuarios desde o directorio en "}. -{"Enter path to jabberd1.4 spool dir", "Introduce a ruta ao directorio de jabberd1.4 spools"}. -{"Path to Dir", "Ruta ao directorio"}. -{"Access Control List Configuration", "Configuración da Lista de Control de Acceso"}. -{"Access control lists", "Listas de Control de Acceso"}. -{"Access Configuration", "Configuración de accesos"}. -{"Access rules", "Regras de acceso"}. -{"Administration of ", "Administración de "}. -{"Action on user", "Acción no usuario"}. -{"Edit Properties", "Editar propiedades"}. -{"Remove User", "Eliminar usuario"}. -{"Database", "Base de datos"}. -{"Outgoing s2s Connections", "Conexións S2S saíntes"}. -{"Import Users From jabberd 1.4 Spool Files", "Importar usuarios de ficheiros spool de jabberd-1.4"}. -{"Database Tables Configuration at ", "Configuración de táboas da base de datos en "}. -{"Restart Service", "Reiniciar o servizo"}. -{"Shut Down Service", "Deter o servizo"}. -{"Delete User", "Borrar usuario"}. -{"End User Session", "Pechar sesión de usuario"}. -{"Get User Password", "Ver contraseña de usuario"}. -{"Change User Password", "Cambiar contraseña de usuario"}. -{"Get User Last Login Time", "Ver data da última conexión de usuario"}. -{"Get User Statistics", "Ver estatísticas de usuario"}. -{"Get Number of Registered Users", "Ver número de usuarios rexistrados"}. -{"Get Number of Online Users", "Ver número de usuarios conectados"}. -{"User Management", "Administración de usuarios"}. -{"Time delay", "Atraso temporal"}. -{"Password Verification", "Verificación da contraseña"}. -{"Number of registered users", "Número de usuarios rexistrados"}. -{"Number of online users", "Número de usuarios conectados"}. -{"Last login", "Última conexión"}. -{"Roster size", "Tamaño da lista de contactos"}. -{"IP addresses", "Direccións IP"}. -{"Resources", "Recursos"}. - -% mod_disco.erl -{"Configuration", "Configuración"}. -{"Online Users", "Usuarios conectados"}. -{"All Users", "Todos os usuarios"}. -{"To ~s", "A ~s"}. -{"From ~s", "De ~s"}. -{"Running Nodes", "Nodos funcionando"}. -{"Stopped Nodes", "Nodos detidos"}. -{"Access Control Lists", "Listas de Control de Acceso"}. -{"Access Rules", "Regras de Acceso"}. -{"Modules", "Módulos"}. -{"Start Modules", "Iniciar módulos"}. -{"Stop Modules", "Detener módulos"}. -{"Backup", "Gardar copia de seguridade"}. -{"Restore", "Restaurar"}. -{"Dump to Text File", "Exportar a ficheiro de texto"}. -{"Import File", "Importar ficheiro"}. -{"Import Directory", "Importar directorio"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Escolle un nome de usuario e contraseña para rexistrarche neste servidor"}. - -% mod_vcard.erl -{"Erlang Jabber Server", "Servidor Jabber en Erlang"}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Enche o formulario para buscar usuarios Jabber. Engade * ao final dun campo para buscar subcadenas."}. -{"ejabberd vCard module", "Módulo vCard para ejabberd"}. -{"You need an x:data capable client to search", "Necesitas un cliente con soporte de x:data para poder buscar"}. -{"Search users in ", "Buscar usuarios en "}. - -% mod_vcard_odbc.erl -{"Email", "Email"}. -{"Search Results for ", "Buscar resultados por "}. -{"Jabber ID", "Jabber ID"}. -{"User", "Usuario"}. -{"Full Name", "Nome completo"}. -{"Name", "Nome"}. -{"Middle Name", "Segundo nome"}. -{"Family Name", "Apelido"}. -{"Nickname", "Alcume"}. -{"Birthday", "Aniversario"}. -{"Country", "País"}. -{"City", "Cidade"}. -{"Organization Name", "Nome da organización"}. -{"Organization Unit", "Unidade da organización"}. -{"vCard User Search", "Procura de usuario en vCard"}. - -% mod_pubsub/mod_pubsub.erl -{"Deliver payloads with event notifications", "Enviar payloads xunto coas notificacións de eventos"}. -{"Notify subscribers when the node configuration changes", "Notificar subscriptores cando cambia a configuración do nodo"}. -{"Notify subscribers when the node is deleted", "Notificar subscriptores cando o nodo bórrase"}. -{"Notify subscribers when items are removed from the node", "Notificar subscriptores cando os elementos bórranse do nodo"}. -{"Persist items to storage", "Persistir elementos ao almacenar"}. -{"Max # of items to persist", "Máximo # de elementos que persisten"}. -{"Whether to allow subscriptions", "Permitir subscripciones"}. -{"Specify the publisher model", "Especificar o modelo do publicante"}. -{"Max payload size in bytes", "Máximo tamaño do payload en bytes"}. -{"Only deliver notifications to available users", "Só enviar notificacións aos usuarios dispoñibles"}. -{"Publish-Subscribe", "Publicar-Subscribir"}. -{"ejabberd Publish-Subscribe module", "Módulo de Publicar-Subscribir de ejabberd"}. -{"PubSub subscriber request", "Petición de subscriptor de PubSub"}. -{"Choose whether to approve this entity's subscription.", "Decidir se aprobar a subscripción desta entidade."}. -{"Node ID", "Nodo IDE"}. -{"Subscriber Address", "Dirección do subscriptor"}. -{"Allow this JID to subscribe to this pubsub node?", "Desexas permitir a este JabberID que se subscriba a este nodo PubSub?"}. -{"Deliver event notifications", "Entregar notificacións de eventos"}. -{"Specify the access model", "Especifica o modelo de acceso"}. - -{"When to send the last published item", "Cando enviar o último elemento publicado"}. -{"Roster groups allowed to subscribe", "Lista de grupos autorizados a subscribir"}. - -% mod_muc/mod_muc.erl -{"You need an x:data capable client to register nickname", "Necesitas un cliente con soporte de x:data para poder rexistrar o alcume"}. -{"Nickname Registration at ", "Rexistro do alcume en "}. -{"Enter nickname you want to register", "Introduce o alcume que queiras rexistrar"}. -{"Only service administrators are allowed to send service messages", "Só os administradores do servizo teñen permiso para enviar mensaxes de servizo"}. -{"Conference room does not exist", "A sala de conferencias non existe"}. -{"Access denied by service policy", "Acceso denegado pola política do servizo"}. -{"You must fill in field \"Nickname\" in the form", "Debes encher o campo \"Alcumo\" no formulario"}. -{"Specified nickname is already registered", "O alcume especificado xa está rexistrado, terás que buscar outro"}. -{"Room creation is denied by service policy", "Denegar crear a sala por política do servizo"}. -{"ejabberd MUC module", "Módulo de MUC para ejabbed"}. -{"Chatrooms", "Salas de charla"}. - -% mod_muc/mod_muc_room.erl -{" has set the subject to: ", " puxo o asunto: "}. -{"You need an x:data capable client to configure room", "Necesitas un cliente con soporte de x:data para configurar a sala"}. -{"Configuration for ", "Configuración para "}. -{"Room title", "Título da sala"}. -{"Allow users to change subject", "Permitir aos usuarios cambiar o asunto"}. -{"Allow users to query other users", "Permitir aos usuarios consultar a outros usuarios"}. -{"Allow users to send private messages", "Permitir aos usuarios enviar mensaxes privadas"}. -{"Make room public searchable", "Sala publicamente visible"}. -{"Make participants list public", "A lista de participantes é pública"}. -{"Make room persistent", "Sala permanente"}. -{"Default users as participants", "Os usuarios son participantes por defecto"}. -{"Make room members-only", "Sala só para membros"}. -{"Allow users to send invites", "Permitir aos usuarios enviar invitacións"}. -{"Make room password protected", "Protexer a sala con contraseña"}. -{"Password", "Contraseña"}. -{"This room is not anonymous", "Sala non anónima"}. -{"Enable logging", "Gardar históricos"}. -{"Only moderators and participants are allowed to change subject in this room", "Só os moderadores e participantes poden cambiar o asunto desta sala"}. -{"Only moderators are allowed to change subject in this room", "Só os moderadores poden cambiar o asunto desta sala"}. -{"Visitors are not allowed to send messages to all occupants", "Os visitantes non poden enviar mensaxes a todos os ocupantes"}. -{"Only occupants are allowed to send messages to the conference", "Só os ocupantes poden enviar mensaxes á sala"}. -{"It is not allowed to send private messages to the conference", "Impedir o envio de mensaxes privadas á sala"}. -{"Improper message type", "Tipo de mensaxe incorrecta"}. -{"Nickname is already in use by another occupant", "O alcume xa está sendo usado por outro ocupante"}. -{"Nickname is registered by another person", "O alcume xa está rexistrado por outra persoa"}. -{"It is not allowed to send private messages of type \"groupchat\"", "Non está permitido enviar mensaxes privadas do tipo \"groupchat\""}. -{"Recipient is not in the conference room", "O receptor non está na sala de conferencia"}. -{"Only occupants are allowed to send queries to the conference", "Só os ocupantes poden enviar solicitudes á sala"}. -{"Queries to the conference members are not allowed in this room", "Nesta sala non se permiten solicitudes aos membros da sala"}. -{"You have been banned from this room", "fuches bloqueado nesta sala"}. -{"Membership required to enter this room", "Necesitas ser membro desta sala para poder entrar"}. -{"Password required to enter this room", "Necesítase contraseña para entrar nesta sala"}. -{"Incorrect password", "Contraseña incorrecta"}. -{"Administrator privileges required", "Necesítase privilexios de administrador"}. -{"Moderator privileges required", "Necesítase privilexios de moderador"}. -{"JID ~s is invalid", "O JID ~s non é válido"}. -{"Nickname ~s does not exist in the room", "O alcume ~s non existe na sala"}. -{"Invalid affiliation: ~s", "Afiliación non válida: ~s"}. -{"Invalid role: ~s", "Rol non válido: ~s"}. -{"Owner privileges required", "Requírense privilexios de propietario da sala"}. -{"private, ", "privado"}. -{"Number of occupants", "Número de ocupantes"}. -{"Present real JIDs to", "Os JID reais poden velos"}. -{"moderators only", "só moderadores"}. -{"anyone", "calquera"}. -{"Traffic rate limit is exceeded", "Hase exedido o límite de tráfico"}. -{"Maximum Number of Occupants", "Número máximo de ocupantes"}. -{"No limit", "Sen límite"}. -{"~s invites you to the room ~s", "~s invítache á sala ~s"}. -{"the password is", "a contraseña é"}. -{"This participant is kicked from the room because he sent an error message", "Este participante é expulsado da sala, xa que enviou unha mensaxe de erro"}. -{"This participant is kicked from the room because he sent an error message to another participant", "Este participante é expulsado da sala, porque el enviou unha mensaxe de erro a outro participante"}. -{"This participant is kicked from the room because he sent an error presence", "Este participante é expulsado da sala, porque el enviou un erro de presenza"}. -{"Make room moderated", "Facer Sala moderada"}. - -% mod_muc/mod_muc_log.erl -{"Chatroom configuration modified", "Configuración de la sala modificada"}. -{"joins the room", "entra en la sala"}. -{"leaves the room", "sale de la sala"}. -{"has been kicked", "ha sido expulsado"}. -{"has been banned", "ha sido bloqueado"}. -{"is now known as", "cámbiase o nome a"}. -{"Monday", "Luns"}. -{"Tuesday", "Martes"}. -{"Wednesday", "Mércores"}. -{"Thursday", "Xoves"}. -{"Friday", "Venres"}. -{"Saturday", "Sábado"}. -{"Sunday", "Domingo"}. -{"January", "Xaneiro"}. -{"February", "Febreiro"}. -{"March", "Marzo"}. -{"April", "Abril"}. -{"May", "Maio"}. -{"June", "Xuño"}. -{"July", "Xullo"}. -{"August", "Agosto"}. -{"September", "Setembro"}. -{"October", "Outubro"}. -{"November", "Novembro"}. -{"December", "Decembro"}. -{"Room Configuration", "Configuración da Sala"}. -{"has been kicked because of an affiliation change", "foi expulsado debido a un cambio de afiliación"}. -{"has been kicked because the room has been changed to members-only", "foi expulsado, porque a sala cambiouse a só-membros"}. -{"has been kicked because of a system shutdown", "foi expulsado por mor dun sistema de peche"}. - -% mod_irc/mod_irc.erl -{"You need an x:data capable client to configure mod_irc settings", "Necesitas un cliente con soporte de x:data para configurar as opcións de mod_irc"}. -{"Registration in mod_irc for ", "Rexistro en mod_irc para"}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Introduce o nome de usuario e codificaciones de carácteres que queiras usar ao conectar nos servidores de IRC"}. -{"IRC Username", "Nome de usuario en IRC"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Se queres especificar codificaciones de carácteres distintos para cada servidor IRC rechea esta lista con valores no formato '{\"servidor irc\", \"codificación\"}'. Este servizo usa por defecto a codificación \"~s\"."}. -{"Encodings", "Codificaciones"}. -{"ejabberd IRC module", "Módulo de IRC para ejabberd"}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Ejemplo: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"IRC Transport", "Transporte IRC"}. - -% web/ejabberd_web_admin.erl -{"Users", "Usuarios"}. -{"Nodes", "Nodos"}. -{"Statistics", "Estatísticas"}. -{"Delete Selected", "Eliminar os seleccionados"}. -{"Submit", "Enviar"}. -{"~s access rule configuration", "Configuración das Regra de Acceso ~s"}. -{"Node not found", "Nodo non atopado"}. -{"Add New", "Engadir novo"}. -{"Change Password", "Cambiar contraseña"}. -{"Connected Resources:", "Recursos conectados:"}. -{"Password:", "Contraseña:"}. -{"None", "Ningún"}. -{"Node ", "Nodo "}. -{"Restart", "Reiniciar"}. -{"Stop", "Deter"}. -{"Name", "Nome"}. -{"Storage Type", "Tipo de almacenamiento"}. -{"Size", "Tamaño"}. -{"Memory", "Memoria"}. -{"Backup Management", "Xestión de copia de seguridade"}. -{"OK", "Aceptar"}. -{"Listened Ports at ", "Portos de escoita en "}. -{"Port", "Porto"}. -{"Module", "Módulo"}. -{"Options", "Opcións"}. -{"Update", "Actualizar"}. -{"Delete", "Eliminar"}. -{"Add User", "Engadir usuario"}. -{"Last Activity", "Última actividade"}. -{"Never", "Nunca"}. -{"Time", "Data"}. -{"From", "De"}. -{"To", "Para"}. -{"Packet", "Paquete"}. -{"Roster", "Lista de contactos"}. -{"Nickname", "Alcume"}. -{"Subscription", "Subscripción"}. -{"Pending", "Pendente"}. -{"Groups", "Grupos"}. -{"Remove", "Borrar"}. -{"User ", "Usuario "}. -{"Roster of ", "Lista de contactos de "}. -{"Online", "Conectado"}. -{"Validate", "Validar"}. -{"Name:", "Nome:"}. -{"Description:", "Descrición:"}. -{"Members:", "Membros:"}. -{"Displayed Groups:", "Mostrar grupos:"}. -{"Group ", "Grupo "}. -{"Period: ", "Periodo: "}. -{"Last month", "Último mes"}. -{"Last year", "Último ano"}. -{"All activity", "Toda a actividade"}. -{"Show Ordinary Table", "Mostrar Táboa Ordinaria"}. -{"Show Integral Table", "Mostrar Táboa Integral"}. -{"Modules at ", "Módulos en "}. -{"Start", "Iniciar"}. -{"Virtual Hosts", "Hosts Virtuais"}. -{"ejabberd virtual hosts", "Hosts virtuais de ejabberd"}. -{"Host", "Host"}. -{"Restore plain text backup immediately:", "Restaurar copias de seguridade de texto plano inmediatamente:"}. -{"Statistics of ~p", "Estatísticas de ~p"}. -{"Uptime:", "Tempo desde o inicio:"}. -{"CPU Time:", "Tempo consumido de CPU:"}. -{"Transactions Commited:", "Transaccións finalizadas:"}. -{"Transactions Aborted:", "Transaccións abortadas:"}. -{"Transactions Restarted:", "Transaccións reiniciadas:"}. -{"Transactions Logged:", "Transaccións rexistradas:"}. -{"Update ", "Actualizar"}. -{"Update plan", "Plan de actualización"}. -{"Updated modules", "Módulos actualizados"}. -{"Update script", "Script de actualización"}. -{"Low level update script", "Script de actualización a baixo nivel"}. -{"Script check", "Comprobación de script"}. -{"Shared Roster Groups", "Grupos Compartidos"}. -{"Administration", "Administración"}. -{"(Raw)", "(Cru)"}. -{"Submitted", "Enviado"}. -{"Bad format", "Mal formato"}. -{"Raw", "Cru"}. -{"Users Last Activity", "Última actividade dos usuarios"}. -{"Registered Users", "Usuarios rexistrados"}. -{"Offline Messages", "Mensaxes diferidas"}. -{"Registered Users:", "Usuarios rexistrados:"}. -{"Online Users:", "Usuarios conectados:"}. -{"Outgoing s2s Connections:", "Conexións S2S saíntes:"}. -{"Outgoing s2s Servers:", "Servidores S2S saíntes:"}. -{"Offline Messages:", "Mensaxes diferidas:"}. -{"~s's Offline Messages Queue", "Cola de mensaxes diferidas de ~s"}. -{"Add Jabber ID", "Engadir ID Jabber"}. -{"No Data", "Sen datos"}. -{"Listened Ports", "Portos de escoita"}. -{"RPC Call Error", "Erro na chamada RPC"}. -{"Database Tables at ", "Táboas da base de datos en "}. -{"Backup of ", "Copia de seguridade de "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "Ten en conta que estas opcións só farán copia de seguridade da base de datos Mnesia embebida. Se estás usando ODBC terás que facer tamén copia de seguridade da túa base de datos SQL."}. -{"Store binary backup:", "Gardar copia de seguridade binaria:"}. -{"Restore binary backup immediately:", "Restaurar inmediatamente copia de seguridade binaria:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Restaurar copia de seguridade binaria no seguinte reinicio de ejabberd (require menos memoria que se instantánea):"}. -{"Store plain text backup:", "Gardar copia de seguridade en texto plano:"}. -{"ejabberd Web Admin", "Ejabberd Administrador Web"}. - -% ejabberd_c2s.erl -{"Use of STARTTLS required", "É obrigatorio usar STARTTLS"}. -{"Replaced by new connection", "Substituído por unha nova conexión"}. - -% mod_vcard_ldap.erl -{"Fill in fields to search for any matching Jabber User", "Rechea campos para buscar usuarios Jabber que concuerden"}. - -% mod_adhoc.erl -{"Commands", "Comandos"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% mod_announce.erl -{"Really delete message of the day?", "Está seguro de quere borrar a mensaxe do dia?"}. -{"Subject", "Asunto"}. -{"Message body", "Corpo da mensaxe"}. -{"No body provided for announce message", "Non se proporcionou corpo de mensaxe para o anuncio"}. -{"Announcements", "Anuncios"}. -{"Send announcement to all users", "Enviar anuncio a todos os usuarios"}. -{"Send announcement to all online users", "Enviar anuncio a todos los usuarios conectados"}. -{"Send announcement to all online users on all hosts", "Enviar anuncio a todos os usuarios conectados en todos os dominios"}. -{"Set message of the day and send to online users", "Pór mensaxe do dia e enviar a todos os usuarios conectados"}. -{"Update message of the day (don't send)", "Actualizar mensaxe do dia, pero non envialo"}. -{"Delete message of the day", "Borrar mensaxe do dia"}. -{"Send announcement to all users on all hosts", "Enviar anuncio a todos os usuarios en todos os dominios"}. -{"Set message of the day on all hosts and send to online users", "Pór mensaxe do día en todos os dominios e enviar aos usuarios conectados"}. -{"Update message of the day on all hosts (don't send)", "Actualizar a mensaxe do día en todos os dominos (pero non envialo)"}. -{"Delete message of the day on all hosts", "Borrar a mensaxe do día en todos os dominios"}. - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "ejabberd SOCKS5 Bytestreams module"}. - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "A túa cola de mensaxes diferidas de contactos está chea. A mensaxe descartouse."}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Configuración de accesos"}. +{"Access Control List Configuration","Configuración da Lista de Control de Acceso"}. +{"Access control lists","Listas de Control de Acceso"}. +{"Access Control Lists","Listas de Control de Acceso"}. +{"Access denied by service policy","Acceso denegado pola política do servizo"}. +{"Access rules","Regras de acceso"}. +{"Access Rules","Regras de Acceso"}. +{"Action on user","Acción no usuario"}. +{"Add Jabber ID","Engadir ID Jabber"}. +{"Add New","Engadir novo"}. +{"Add User","Engadir usuario"}. +{"Administration","Administración"}. +{"Administration of ","Administración de "}. +{"Administrator privileges required","Necesítase privilexios de administrador"}. +{"All activity","Toda a actividade"}. +{"Allow this JID to subscribe to this pubsub node?","Desexas permitir a este JabberID que se subscriba a este nodo PubSub?"}. +{"Allow users to change subject","Permitir aos usuarios cambiar o asunto"}. +{"Allow users to query other users","Permitir aos usuarios consultar a outros usuarios"}. +{"Allow users to send invites","Permitir aos usuarios enviar invitacións"}. +{"Allow users to send private messages","Permitir aos usuarios enviar mensaxes privadas"}. +{"All Users","Todos os usuarios"}. +{"Announcements","Anuncios"}. +{"anyone","calquera"}. +{"April","Abril"}. +{"August","Agosto"}. +{"Backup","Gardar copia de seguridade"}. +{"Backup Management","Xestión de copia de seguridade"}. +{"Backup of ","Copia de seguridade de "}. +{"Backup to File at ","Gardar copia de seguridade en ficheiro en "}. +{"Bad format","Mal formato"}. +{"Birthday","Aniversario"}. +{"Change Password","Cambiar contraseña"}. +{"Change User Password","Cambiar contraseña de usuario"}. +{"Chatroom configuration modified","Configuración de la sala modificada"}. +{"Chatrooms","Salas de charla"}. +{"Choose a username and password to register with this server","Escolle un nome de usuario e contraseña para rexistrarche neste servidor"}. +{"Choose modules to stop","Selecciona módulos a deter"}. +{"Choose storage type of tables","Selecciona tipo de almacenamento das táboas"}. +{"Choose whether to approve this entity's subscription.","Decidir se aprobar a subscripción desta entidade."}. +{"City","Cidade"}. +{"Commands","Comandos"}. +{"Conference room does not exist","A sala de conferencias non existe"}. +{"Configuration","Configuración"}. +{"Configuration for ","Configuración para "}. +{"Connected Resources:","Recursos conectados:"}. +{"Country","País"}. +{"CPU Time:","Tempo consumido de CPU:"}. +{"Database","Base de datos"}. +{"Database Tables at ","Táboas da base de datos en "}. +{"Database Tables Configuration at ","Configuración de táboas da base de datos en "}. +{"December","Decembro"}. +{"Default users as participants","Os usuarios son participantes por defecto"}. +{"Delete","Eliminar"}. +{"Delete message of the day","Borrar mensaxe do dia"}. +{"Delete message of the day on all hosts","Borrar a mensaxe do día en todos os dominios"}. +{"Delete Selected","Eliminar os seleccionados"}. +{"Delete User","Borrar usuario"}. +{"Deliver event notifications","Entregar notificacións de eventos"}. +{"Deliver payloads with event notifications","Enviar payloads xunto coas notificacións de eventos"}. +{"Description:","Descrición:"}. +{"Disc only copy","Copia en disco soamente"}. +{"Displayed Groups:","Mostrar grupos:"}. +{"Dump Backup to Text File at ","Exporta copia de seguridade a ficheiro de texto en "}. +{"Dump to Text File","Exportar a ficheiro de texto"}. +{"Edit Properties","Editar propiedades"}. +{"ejabberd IRC module","Módulo de IRC para ejabberd"}. +{"ejabberd MUC module","Módulo de MUC para ejabberd"}. +{"ejabberd Publish-Subscribe module","Módulo de Publicar-Subscribir de ejabberd"}. +{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestreams module"}. +{"ejabberd vCard module","Módulo vCard para ejabberd"}. +{"ejabberd virtual hosts","Hosts virtuais de ejabberd"}. +{"ejabberd Web Admin","Ejabberd Administrador Web"}. +{"Email","Email"}. +{"Enable logging","Gardar históricos"}. +{"Encodings","Codificaciones"}. +{"End User Session","Pechar sesión de usuario"}. +{"Enter list of {Module, [Options]}","Introduce lista de {módulo, [opcións]}"}. +{"Enter nickname you want to register","Introduce o alcume que queiras rexistrar"}. +{"Enter path to backup file","Introduce ruta ao ficheiro de copia de seguridade"}. +{"Enter path to jabberd1.4 spool dir","Introduce a ruta ao directorio de jabberd1.4 spools"}. +{"Enter path to jabberd1.4 spool file","Introduce ruta ao ficheiro jabberd1.4 spool"}. +{"Enter path to text file","Introduce ruta ao ficheiro de texto"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Introduce o nome de usuario e codificaciones de carácteres que queiras usar ao conectar nos servidores de IRC"}. +{"Erlang Jabber Server","Servidor Jabber en Erlang"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Ejemplo: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","Apelido"}. +{"February","Febreiro"}. +{"Fill in fields to search for any matching Jabber User","Rechea campos para buscar usuarios Jabber que concuerden"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Enche o formulario para buscar usuarios Jabber. Engade * ao final dun campo para buscar subcadenas."}. +{"Friday","Venres"}. +{"From","De"}. +{"From ~s","De ~s"}. +{"Full Name","Nome completo"}. +{"Get Number of Online Users","Ver número de usuarios conectados"}. +{"Get Number of Registered Users","Ver número de usuarios rexistrados"}. +{"Get User Last Login Time","Ver data da última conexión de usuario"}. +{"Get User Password","Ver contraseña de usuario"}. +{"Get User Statistics","Ver estatísticas de usuario"}. +{"Group ","Grupo "}. +{"Groups","Grupos"}. +{"has been banned","ha sido bloqueado"}. +{"has been kicked because of an affiliation change","foi expulsado debido a un cambio de afiliación"}. +{"has been kicked because of a system shutdown","foi expulsado por mor dun sistema de peche"}. +{"has been kicked because the room has been changed to members-only","foi expulsado, porque a sala cambiouse a só-membros"}. +{"has been kicked","ha sido expulsado"}. +{" has set the subject to: "," puxo o asunto: "}. +{"Host","Host"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Se queres especificar codificaciones de carácteres distintos para cada servidor IRC rechea esta lista con valores no formato '{\"servidor irc\", \"codificación\"}'. Este servizo usa por defecto a codificación \"~s\"."}. +{"Import Directory","Importar directorio"}. +{"Import File","Importar ficheiro"}. +{"Import User from File at ","Importa usuario desde ficheiro en "}. +{"Import Users from Dir at ","Importar usuarios desde o directorio en "}. +{"Import Users From jabberd 1.4 Spool Files","Importar usuarios de ficheiros spool de jabberd-1.4"}. +{"Improper message type","Tipo de mensaxe incorrecta"}. +{"Incorrect password","Contraseña incorrecta"}. +{"Invalid affiliation: ~s","Afiliación non válida: ~s"}. +{"Invalid role: ~s","Rol non válido: ~s"}. +{"IP addresses","Direccións IP"}. +{"IRC Transport","Transporte IRC"}. +{"IRC Username","Nome de usuario en IRC"}. +{"is now known as","cámbiase o nome a"}. +{"It is not allowed to send private messages of type \"groupchat\"","Non está permitido enviar mensaxes privadas do tipo \"groupchat\""}. +{"It is not allowed to send private messages to the conference","Impedir o envio de mensaxes privadas á sala"}. +{"Jabber ID","Jabber ID"}. +{"January","Xaneiro"}. +{"JID ~s is invalid","O JID ~s non é válido"}. +{"joins the room","entra en la sala"}. +{"July","Xullo"}. +{"June","Xuño"}. +{"Last Activity","Última actividade"}. +{"Last login","Última conexión"}. +{"Last month","Último mes"}. +{"Last year","Último ano"}. +{"leaves the room","sale de la sala"}. +{"Listened Ports at ","Portos de escoita en "}. +{"Listened Ports","Portos de escoita"}. +{"List of modules to start","Lista de módulos a iniciar"}. +{"Low level update script","Script de actualización a baixo nivel"}. +{"Make participants list public","A lista de participantes é pública"}. +{"Make room members-only","Sala só para membros"}. +{"Make room moderated","Facer Sala moderada"}. +{"Make room password protected","Protexer a sala con contraseña"}. +{"Make room persistent","Sala permanente"}. +{"Make room public searchable","Sala publicamente visible"}. +{"March","Marzo"}. +{"Maximum Number of Occupants","Número máximo de ocupantes"}. +{"Max # of items to persist","Máximo # de elementos que persisten"}. +{"Max payload size in bytes","Máximo tamaño do payload en bytes"}. +{"May","Maio"}. +{"Membership required to enter this room","Necesitas ser membro desta sala para poder entrar"}. +{"Members:","Membros:"}. +{"Memory","Memoria"}. +{"Message body","Corpo da mensaxe"}. +{"Middle Name","Segundo nome"}. +{"Moderator privileges required","Necesítase privilexios de moderador"}. +{"moderators only","só moderadores"}. +{"Module","Módulo"}. +{"Modules at ","Módulos en "}. +{"Modules","Módulos"}. +{"Monday","Luns"}. +{"Name:","Nome:"}. +{"Name","Nome"}. +{"Never","Nunca"}. +{"Nickname","Alcume"}. +{"Nickname is already in use by another occupant","O alcume xa está sendo usado por outro ocupante"}. +{"Nickname is registered by another person","O alcume xa está rexistrado por outra persoa"}. +{"Nickname Registration at ","Rexistro do alcume en "}. +{"Nickname ~s does not exist in the room","O alcume ~s non existe na sala"}. +{"No body provided for announce message","Non se proporcionou corpo de mensaxe para o anuncio"}. +{"No Data","Sen datos"}. +{"Node ID","Nodo IDE"}. +{"Node ","Nodo "}. +{"Node not found","Nodo non atopado"}. +{"Nodes","Nodos"}. +{"No limit","Sen límite"}. +{"None","Ningún"}. +{"No resource provided","Non se proporcionou recurso"}. +{"Notify subscribers when items are removed from the node","Notificar subscriptores cando os elementos bórranse do nodo"}. +{"Notify subscribers when the node configuration changes","Notificar subscriptores cando cambia a configuración do nodo"}. +{"Notify subscribers when the node is deleted","Notificar subscriptores cando o nodo bórrase"}. +{"November","Novembro"}. +{"Number of occupants","Número de ocupantes"}. +{"Number of online users","Número de usuarios conectados"}. +{"Number of registered users","Número de usuarios rexistrados"}. +{"October","Outubro"}. +{"Offline Messages:","Mensaxes diferidas:"}. +{"Offline Messages","Mensaxes diferidas"}. +{"OK","Aceptar"}. +{"Online","Conectado"}. +{"Online Users:","Usuarios conectados:"}. +{"Online Users","Usuarios conectados"}. +{"Only deliver notifications to available users","Só enviar notificacións aos usuarios dispoñibles"}. +{"Only moderators and participants are allowed to change subject in this room","Só os moderadores e participantes poden cambiar o asunto desta sala"}. +{"Only moderators are allowed to change subject in this room","Só os moderadores poden cambiar o asunto desta sala"}. +{"Only occupants are allowed to send messages to the conference","Só os ocupantes poden enviar mensaxes á sala"}. +{"Only occupants are allowed to send queries to the conference","Só os ocupantes poden enviar solicitudes á sala"}. +{"Only service administrators are allowed to send service messages","Só os administradores do servizo teñen permiso para enviar mensaxes de servizo"}. +{"Options","Opcións"}. +{"Organization Name","Nome da organización"}. +{"Organization Unit","Unidade da organización"}. +{"Outgoing s2s Connections:","Conexións S2S saíntes:"}. +{"Outgoing s2s Connections","Conexións S2S saíntes"}. +{"Outgoing s2s Servers:","Servidores S2S saíntes:"}. +{"Owner privileges required","Requírense privilexios de propietario da sala"}. +{"Packet","Paquete"}. +{"Password:","Contraseña:"}. +{"Password","Contraseña"}. +{"Password required to enter this room","Necesítase contraseña para entrar nesta sala"}. +{"Password Verification","Verificación da contraseña"}. +{"Path to Dir","Ruta ao directorio"}. +{"Path to File","Ruta ao ficheiro"}. +{"Pending","Pendente"}. +{"Period: ","Periodo: "}. +{"Persist items to storage","Persistir elementos ao almacenar"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","Porto"}. +{"Present real JIDs to","Os JID reais poden velos"}. +{"private, ","privado"}. +{"Publish-Subscribe","Publicar-Subscribir"}. +{"PubSub subscriber request","Petición de subscriptor de PubSub"}. +{"Queries to the conference members are not allowed in this room","Nesta sala non se permiten solicitudes aos membros da sala"}. +{"RAM and disc copy","Copia en RAM e disco"}. +{"RAM copy","Copia en RAM"}. +{"(Raw)","(Cru)"}. +{"Raw","Cru"}. +{"Really delete message of the day?","Está seguro de quere borrar a mensaxe do dia?"}. +{"Recipient is not in the conference room","O receptor non está na sala de conferencia"}. +{"Registered Users:","Usuarios rexistrados:"}. +{"Registered Users","Usuarios rexistrados"}. +{"Registration in mod_irc for ","Rexistro en mod_irc para"}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Ten en conta que estas opcións só farán copia de seguridade da base de datos Mnesia embebida. Se estás usando ODBC terás que facer tamén copia de seguridade da túa base de datos SQL."}. +{"Remote copy","Copia remota"}. +{"Remove","Borrar"}. +{"Remove User","Eliminar usuario"}. +{"Replaced by new connection","Substituído por unha nova conexión"}. +{"Resources","Recursos"}. +{"Restart","Reiniciar"}. +{"Restart Service","Reiniciar o servizo"}. +{"Restore Backup from File at ","Restaura copia de seguridade desde o ficheiro en "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Restaurar copia de seguridade binaria no seguinte reinicio de ejabberd (require menos memoria que se instantánea):"}. +{"Restore binary backup immediately:","Restaurar inmediatamente copia de seguridade binaria:"}. +{"Restore plain text backup immediately:","Restaurar copias de seguridade de texto plano inmediatamente:"}. +{"Restore","Restaurar"}. +{"Room Configuration","Configuración da Sala"}. +{"Room creation is denied by service policy","Denegar crear a sala por política do servizo"}. +{"Room title","Título da sala"}. +{"Roster groups allowed to subscribe","Lista de grupos autorizados a subscribir"}. +{"Roster","Lista de contactos"}. +{"Roster of ","Lista de contactos de "}. +{"Roster size","Tamaño da lista de contactos"}. +{"RPC Call Error","Erro na chamada RPC"}. +{"Running Nodes","Nodos funcionando"}. +{"~s access rule configuration","Configuración das Regra de Acceso ~s"}. +{"Saturday","Sábado"}. +{"Script check","Comprobación de script"}. +{"Search Results for ","Buscar resultados por "}. +{"Search users in ","Buscar usuarios en "}. +{"Send announcement to all online users","Enviar anuncio a todos los usuarios conectados"}. +{"Send announcement to all online users on all hosts","Enviar anuncio a todos os usuarios conectados en todos os dominios"}. +{"Send announcement to all users","Enviar anuncio a todos os usuarios"}. +{"Send announcement to all users on all hosts","Enviar anuncio a todos os usuarios en todos os dominios"}. +{"September","Setembro"}. +{"Set message of the day and send to online users","Pór mensaxe do dia e enviar a todos os usuarios conectados"}. +{"Set message of the day on all hosts and send to online users","Pór mensaxe do día en todos os dominios e enviar aos usuarios conectados"}. +{"Shared Roster Groups","Grupos Compartidos"}. +{"Show Integral Table","Mostrar Táboa Integral"}. +{"Show Ordinary Table","Mostrar Táboa Ordinaria"}. +{"Shut Down Service","Deter o servizo"}. +{"~s invites you to the room ~s","~s invítache á sala ~s"}. +{"Size","Tamaño"}. +{"Specified nickname is already registered","O alcume especificado xa está rexistrado, terás que buscar outro"}. +{"Specify the access model","Especifica o modelo de acceso"}. +{"Specify the publisher model","Especificar o modelo do publicante"}. +{"~s's Offline Messages Queue","Cola de mensaxes diferidas de ~s"}. +{"Start","Iniciar"}. +{"Start Modules at ","Iniciar módulos en "}. +{"Start Modules","Iniciar módulos"}. +{"Statistics","Estatísticas"}. +{"Statistics of ~p","Estatísticas de ~p"}. +{"Stop","Deter"}. +{"Stop Modules at ","Deter módulos en "}. +{"Stop Modules","Detener módulos"}. +{"Stopped Nodes","Nodos detidos"}. +{"Storage Type","Tipo de almacenamiento"}. +{"Store binary backup:","Gardar copia de seguridade binaria:"}. +{"Store plain text backup:","Gardar copia de seguridade en texto plano:"}. +{"Subject","Asunto"}. +{"Submit","Enviar"}. +{"Submitted","Enviado"}. +{"Subscriber Address","Dirección do subscriptor"}. +{"Subscription","Subscripción"}. +{"Sunday","Domingo"}. +{"the password is","a contraseña é"}. +{"This participant is kicked from the room because he sent an error message","Este participante é expulsado da sala, xa que enviou unha mensaxe de erro"}. +{"This participant is kicked from the room because he sent an error message to another participant","Este participante é expulsado da sala, porque el enviou unha mensaxe de erro a outro participante"}. +{"This participant is kicked from the room because he sent an error presence","Este participante é expulsado da sala, porque el enviou un erro de presenza"}. +{"This room is not anonymous","Sala non anónima"}. +{"Thursday","Xoves"}. +{"Time","Data"}. +{"Time delay","Atraso temporal"}. +{"To","Para"}. +{"To ~s","A ~s"}. +{"Traffic rate limit is exceeded","Hase exedido o límite de tráfico"}. +{"Transactions Aborted:","Transaccións abortadas:"}. +{"Transactions Commited:","Transaccións finalizadas:"}. +{"Transactions Logged:","Transaccións rexistradas:"}. +{"Transactions Restarted:","Transaccións reiniciadas:"}. +{"Tuesday","Martes"}. +{"Update ","Actualizar"}. +{"Update","Actualizar"}. +{"Updated modules","Módulos actualizados"}. +{"Update message of the day (don't send)","Actualizar mensaxe do dia, pero non envialo"}. +{"Update message of the day on all hosts (don't send)","Actualizar a mensaxe do día en todos os dominos (pero non envialo)"}. +{"Update plan","Plan de actualización"}. +{"Update script","Script de actualización"}. +{"Uptime:","Tempo desde o inicio:"}. +{"Use of STARTTLS required","É obrigatorio usar STARTTLS"}. +{"User Management","Administración de usuarios"}. +{"Users Last Activity","Última actividade dos usuarios"}. +{"Users","Usuarios"}. +{"User ","Usuario "}. +{"User","Usuario"}. +{"Validate","Validar"}. +{"vCard User Search","Procura de usuario en vCard"}. +{"Virtual Hosts","Hosts Virtuais"}. +{"Visitors are not allowed to send messages to all occupants","Os visitantes non poden enviar mensaxes a todos os ocupantes"}. +{"Wednesday","Mércores"}. +{"When to send the last published item","Cando enviar o último elemento publicado"}. +{"Whether to allow subscriptions","Permitir subscripciones"}. +{"You have been banned from this room","fuches bloqueado nesta sala"}. +{"You must fill in field \"Nickname\" in the form","Debes encher o campo \"Alcumo\" no formulario"}. +{"You need an x:data capable client to configure mod_irc settings","Necesitas un cliente con soporte de x:data para configurar as opcións de mod_irc"}. +{"You need an x:data capable client to configure room","Necesitas un cliente con soporte de x:data para configurar a sala"}. +{"You need an x:data capable client to register nickname","Necesitas un cliente con soporte de x:data para poder rexistrar o alcume"}. +{"You need an x:data capable client to search","Necesitas un cliente con soporte de x:data para poder buscar"}. +{"Your contact offline message queue is full. The message has been discarded.","A túa cola de mensaxes diferidas de contactos está chea. A mensaxe descartouse."}. diff --git a/src/msgs/gl.po b/src/msgs/gl.po new file mode 100644 index 000000000..499e67dbb --- /dev/null +++ b/src/msgs/gl.po @@ -0,0 +1,1500 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Carlos E. Lopez - suso AT jabber-hispano.org\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Galician (galego)\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "É obrigatorio usar STARTTLS" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Non se proporcionou recurso" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Substituído por unha nova conexión" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Comandos" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Está seguro de quere borrar a mensaxe do dia?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Asunto" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Corpo da mensaxe" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "Non se proporcionou corpo de mensaxe para o anuncio" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Anuncios" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Enviar anuncio a todos os usuarios" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Enviar anuncio a todos os usuarios en todos os dominios" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Enviar anuncio a todos los usuarios conectados" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "Enviar anuncio a todos os usuarios conectados en todos os dominios" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Pór mensaxe do dia e enviar a todos os usuarios conectados" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Pór mensaxe do día en todos os dominios e enviar aos usuarios conectados" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Actualizar mensaxe do dia, pero non envialo" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Actualizar a mensaxe do día en todos os dominos (pero non envialo)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Borrar mensaxe do dia" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Borrar a mensaxe do día en todos os dominios" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Configuración" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Base de datos" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Iniciar módulos" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Detener módulos" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Gardar copia de seguridade" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Restaurar" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Exportar a ficheiro de texto" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Importar ficheiro" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Importar directorio" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Reiniciar o servizo" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Deter o servizo" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Engadir usuario" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Borrar usuario" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Pechar sesión de usuario" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Ver contraseña de usuario" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Cambiar contraseña de usuario" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Ver data da última conexión de usuario" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Ver estatísticas de usuario" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Ver número de usuarios rexistrados" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Ver número de usuarios conectados" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Listas de Control de Acceso" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Regras de Acceso" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Administración de usuarios" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Usuarios conectados" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Todos os usuarios" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Conexións S2S saíntes" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Nodos funcionando" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Nodos detidos" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Módulos" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Xestión de copia de seguridade" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Importar usuarios de ficheiros spool de jabberd-1.4" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "A ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "De ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Configuración de táboas da base de datos en " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Selecciona tipo de almacenamento das táboas" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Copia en disco soamente" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "Copia en RAM e disco" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "Copia en RAM" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Copia remota" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Deter módulos en " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Selecciona módulos a deter" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Iniciar módulos en " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Introduce lista de {módulo, [opcións]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Lista de módulos a iniciar" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Gardar copia de seguridade en ficheiro en " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Introduce ruta ao ficheiro de copia de seguridade" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Ruta ao ficheiro" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Restaura copia de seguridade desde o ficheiro en " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Exporta copia de seguridade a ficheiro de texto en " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Introduce ruta ao ficheiro de texto" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Importa usuario desde ficheiro en " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Introduce ruta ao ficheiro jabberd1.4 spool" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Importar usuarios desde o directorio en " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Introduce a ruta ao directorio de jabberd1.4 spools" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Ruta ao directorio" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Atraso temporal" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Configuración da Lista de Control de Acceso" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Listas de Control de Acceso" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Configuración de accesos" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Regras de acceso" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Contraseña" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Verificación da contraseña" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Número de usuarios rexistrados" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Número de usuarios conectados" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Nunca" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Conectado" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Última conexión" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Tamaño da lista de contactos" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "Direccións IP" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Recursos" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Administración de " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Acción no usuario" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Editar propiedades" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Eliminar usuario" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Acceso denegado pola política do servizo" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "Transporte IRC" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "Módulo de IRC para ejabberd" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "" +"Necesitas un cliente con soporte de x:data para configurar as opcións de " +"mod_irc" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Rexistro en mod_irc para" + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Introduce o nome de usuario e codificaciones de carácteres que queiras usar " +"ao conectar nos servidores de IRC" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "Nome de usuario en IRC" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Se queres especificar codificaciones de carácteres distintos para cada " +"servidor IRC rechea esta lista con valores no formato '{\"servidor irc\", " +"\"codificación\"}'. Este servizo usa por defecto a codificación \"~s\"." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Ejemplo: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Codificaciones" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "" +"Só os administradores do servizo teñen permiso para enviar mensaxes de " +"servizo" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "Denegar crear a sala por política do servizo" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "A sala de conferencias non existe" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Salas de charla" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "" +"Necesitas un cliente con soporte de x:data para poder rexistrar o alcume" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Rexistro do alcume en " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Introduce o alcume que queiras rexistrar" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Alcume" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "O alcume especificado xa está rexistrado, terás que buscar outro" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Debes encher o campo \"Alcumo\" no formulario" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "Módulo de MUC para ejabberd" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Configuración de la sala modificada" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "entra en la sala" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "sale de la sala" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "ha sido bloqueado" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "ha sido expulsado" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "foi expulsado debido a un cambio de afiliación" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "foi expulsado, porque a sala cambiouse a só-membros" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "foi expulsado por mor dun sistema de peche" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "cámbiase o nome a" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " puxo o asunto: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "Luns" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "Martes" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "Mércores" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "Xoves" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "Venres" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "Sábado" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "Domingo" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "Xaneiro" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "Febreiro" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "Marzo" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "Abril" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "Maio" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "Xuño" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "Xullo" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "Agosto" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "Setembro" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "Outubro" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "Novembro" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "Decembro" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Configuración da Sala" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Título da sala" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Hase exedido o límite de tráfico" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" +"Este participante é expulsado da sala, xa que enviou unha mensaxe de erro" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Impedir o envio de mensaxes privadas á sala" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Tipo de mensaxe incorrecta" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Este participante é expulsado da sala, porque el enviou unha mensaxe de erro " +"a outro participante" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "Non está permitido enviar mensaxes privadas do tipo \"groupchat\"" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "O receptor non está na sala de conferencia" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Só os ocupantes poden enviar mensaxes á sala" + +#: mod_muc/mod_muc_room.erl:528 +#, fuzzy +msgid "It is not allowed to send private messages" +msgstr "Impedir o envio de mensaxes privadas á sala" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Só os ocupantes poden enviar solicitudes á sala" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "Nesta sala non se permiten solicitudes aos membros da sala" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "privado" + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "Só os moderadores e participantes poden cambiar o asunto desta sala" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Só os moderadores poden cambiar o asunto desta sala" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "Os visitantes non poden enviar mensaxes a todos os ocupantes" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" +"Este participante é expulsado da sala, porque el enviou un erro de presenza" + +#: mod_muc/mod_muc_room.erl:949 +#, fuzzy +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Só os moderadores poden cambiar o asunto desta sala" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "O alcume xa está sendo usado por outro ocupante" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "O alcume xa está rexistrado por outra persoa" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "fuches bloqueado nesta sala" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "Necesitas ser membro desta sala para poder entrar" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Sala non anónima" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Necesítase contraseña para entrar nesta sala" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Contraseña incorrecta" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Necesítase privilexios de administrador" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Necesítase privilexios de moderador" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "O JID ~s non é válido" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "O alcume ~s non existe na sala" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Afiliación non válida: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Rol non válido: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Requírense privilexios de propietario da sala" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Configuración para " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Descrición:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Sala permanente" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Sala publicamente visible" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "A lista de participantes é pública" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Protexer a sala con contraseña" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Número máximo de ocupantes" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Sen límite" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Os JID reais poden velos" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "só moderadores" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "calquera" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Sala só para membros" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Facer Sala moderada" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Os usuarios son participantes por defecto" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Permitir aos usuarios cambiar o asunto" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Permitir aos usuarios enviar mensaxes privadas" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Permitir aos usuarios consultar a outros usuarios" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Permitir aos usuarios enviar invitacións" + +#: mod_muc/mod_muc_room.erl:2766 +#, fuzzy +msgid "Allow visitors to send status text in presence updates" +msgstr "Permitir aos usuarios enviar mensaxes privadas" + +#: mod_muc/mod_muc_room.erl:2769 +#, fuzzy +msgid "Allow visitors to change nickname" +msgstr "Permitir aos usuarios cambiar o asunto" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Gardar históricos" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "Necesitas un cliente con soporte de x:data para configurar a sala" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Número de ocupantes" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s invítache á sala ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "a contraseña é" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "" +"A túa cola de mensaxes diferidas de contactos está chea. A mensaxe " +"descartouse." + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "Cola de mensaxes diferidas de ~s" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Enviado" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Data" + +#: mod_offline.erl:507 +msgid "From" +msgstr "De" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Para" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Paquete" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Eliminar os seleccionados" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Mensaxes diferidas:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "ejabberd SOCKS5 Bytestreams module" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Publicar-Subscribir" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "Módulo de Publicar-Subscribir de ejabberd" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "Petición de subscriptor de PubSub" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Decidir se aprobar a subscripción desta entidade." + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "Nodo IDE" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Dirección do subscriptor" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Desexas permitir a este JabberID que se subscriba a este nodo PubSub?" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Enviar payloads xunto coas notificacións de eventos" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Entregar notificacións de eventos" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Notificar subscriptores cando cambia a configuración do nodo" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Notificar subscriptores cando o nodo bórrase" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Notificar subscriptores cando os elementos bórranse do nodo" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Persistir elementos ao almacenar" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Máximo # de elementos que persisten" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Permitir subscripciones" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Especifica o modelo de acceso" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Lista de grupos autorizados a subscribir" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Especificar o modelo do publicante" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Máximo tamaño do payload en bytes" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Cando enviar o último elemento publicado" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Só enviar notificacións aos usuarios dispoñibles" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "" +"Escolle un nome de usuario e contraseña para rexistrarche neste servidor" + +#: mod_register.erl:232 +#, fuzzy +msgid "Users are not allowed to register accounts so fast" +msgstr "Os visitantes non poden enviar mensaxes a todos os ocupantes" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Ningún" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Subscripción" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Pendente" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Grupos" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Validar" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Borrar" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Lista de contactos de " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Mal formato" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Engadir ID Jabber" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Lista de contactos" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Grupos Compartidos" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Engadir novo" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Nome:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Descrición:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Membros:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Mostrar grupos:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Grupo " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Enviar" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Servidor Jabber en Erlang" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Aniversario" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Cidade" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "País" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "Email" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Apelido" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Enche o formulario para buscar usuarios Jabber. Engade * ao final dun campo " +"para buscar subcadenas." + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Nome completo" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Segundo nome" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Nome" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Nome da organización" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Unidade da organización" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Buscar usuarios en " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Usuario" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "Necesitas un cliente con soporte de x:data para poder buscar" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "Procura de usuario en vCard" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "Módulo vCard para ejabberd" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Buscar resultados por " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Rechea campos para buscar usuarios Jabber que concuerden" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "Ejabberd Administrador Web" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Administración" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Hosts Virtuais" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Nodos" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Estatísticas" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Usuarios" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Última actividade" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Cru)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Cru" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "Configuración das Regra de Acceso ~s" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "Hosts virtuais de ejabberd" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Última actividade dos usuarios" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Periodo: " + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Último mes" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Último ano" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Toda a actividade" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Mostrar Táboa Ordinaria" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Mostrar Táboa Integral" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Nodo non atopado" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Host" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Usuarios rexistrados" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Mensaxes diferidas" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Usuarios rexistrados:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Usuarios conectados:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Conexións S2S saíntes:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Servidores S2S saíntes:" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Cambiar contraseña" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Usuario " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Recursos conectados:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Contraseña:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Sen datos" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Nodo " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Portos de escoita" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Actualizar" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Reiniciar" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Deter" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "Erro na chamada RPC" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Táboas da base de datos en " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Tipo de almacenamiento" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Tamaño" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Memoria" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Copia de seguridade de " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Ten en conta que estas opcións só farán copia de seguridade da base de datos " +"Mnesia embebida. Se estás usando ODBC terás que facer tamén copia de " +"seguridade da túa base de datos SQL." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Gardar copia de seguridade binaria:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "Aceptar" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Restaurar inmediatamente copia de seguridade binaria:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"Restaurar copia de seguridade binaria no seguinte reinicio de ejabberd " +"(require menos memoria que se instantánea):" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Gardar copia de seguridade en texto plano:" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Restaurar copias de seguridade de texto plano inmediatamente:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Portos de escoita en " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Módulos en " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "Estatísticas de ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Tempo desde o inicio:" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "Tempo consumido de CPU:" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Transaccións finalizadas:" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Transaccións abortadas:" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Transaccións reiniciadas:" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Transaccións rexistradas:" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Actualizar" + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Plan de actualización" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Módulos actualizados" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Script de actualización" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Script de actualización a baixo nivel" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Comprobación de script" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Porto" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Módulo" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Opcións" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Eliminar" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Iniciar" diff --git a/src/msgs/it.msg b/src/msgs/it.msg index 7042b33b6..e10994b7a 100644 --- a/src/msgs/it.msg +++ b/src/msgs/it.msg @@ -1,384 +1,343 @@ -% $Id$ -% Language: Italian (italiano) -% Author: Smart2128 -% Author: Luca Brivio - -% jlib.hrl -{"No resource provided", "Nessuna risorsa fornita"}. - -% mod_configure.erl -{"Restart Service", "Riavviare il servizio"}. -{"Shut Down Service", "Terminare il servizio"}. -{"Delete User", "Eliminare l'utente"}. -{"End User Session", "Terminare la sessione dell'utente"}. -{"Get User Password", "Ottenere la password dell'utente"}. -{"Change User Password", "Cambiare la password dell'utente"}. -{"Get User Last Login Time", "Ottenere la data di ultimo accesso dell'utente"}. -{"Get User Statistics", "Ottenere le statistiche dell'utente"}. -{"Get Number of Registered Users", "Ottenere il numero di utenti registrati"}. -{"Get Number of Online Users", "Ottenere il numero di utenti online"}. -{"User Management", "Gestione degli utenti"}. -{"Time delay", "Ritardo"}. -{"Password Verification", "Verifica della password"}. -{"Number of registered users", "Numero di utenti registrati"}. -{"Number of online users", "Numero di utenti online"}. -{"Last login", "Ultimo accesso"}. -{"Roster size", "Dimensione della lista dei contatti"}. -{"IP addresses", "Indirizzi IP"}. -{"Resources", "Risorse"}. -{"Choose storage type of tables", "Selezionare una modalità di conservazione delle tabelle"}. -{"RAM copy", "Copia in memoria (RAM)"}. -{"RAM and disc copy", "Copia in memoria (RAM) e su disco"}. -{"Disc only copy", "Copia su disco soltanto"}. -{"Remote copy", "Copia remota"}. -{"Stop Modules at ", "Arrestare moduli su "}. -{"Choose modules to stop", "Selezionare i moduli da arrestare"}. -{"Start Modules at ", "Avviare moduli su "}. -{"Enter list of {Module, [Options]}", "Immettere un elenco di {Modulo, [Opzioni]}"}. -{"List of modules to start", "Elenco dei moduli da avviare"}. -{"Backup to File at ", "Salvataggio sul file "}. -{"Enter path to backup file", "Immettere il percorso del file di salvataggio"}. -{"Path to File", "Percorso del file"}. -{"Restore Backup from File at ", "Recuperare il salvataggio dal file "}. -{"Dump Backup to Text File at ", "Trascrivere il salvataggio sul file di testo "}. -{"Enter path to text file", "Immettere il percorso del file di testo"}. -{"Import User from File at ", "Importare un utente dal file "}. -{"Enter path to jabberd1.4 spool file", "Immettere il percorso del file di spool di jabberd1.4"}. -{"Import Users from Dir at ", "Importare utenti dalla directory "}. -{"Enter path to jabberd1.4 spool dir", "Immettere il percorso della directory di spool di jabberd1.4"}. -{"Path to Dir", "Percorso della directory"}. -{"Access Control List Configuration", "Configurazione dei diritti di accesso (ACL)"}. -{"Access control lists", "Diritti di accesso (ACL)"}. -{"Access Configuration", "Configurazione dell'accesso"}. -{"Access rules", "Regole di accesso"}. -{"Administration of ", "Amministrazione di "}. -{"Action on user", "Azione sull'utente"}. -{"Edit Properties", "Modificare le proprietà"}. -{"Remove User", "Eliminare l'utente"}. -{"Database", "Database"}. -{"Outgoing s2s Connections", "Connessioni s2s in uscita"}. -{"Import Users From jabberd 1.4 Spool Files", "Importare utenti da file di spool di jabberd 1.4"}. -{"Database Tables Configuration at ", "Configurazione delle tabelle del database su "}. - -% src/ejabberd_c2s.erl -{"Use of STARTTLS required", "Utilizzo di STARTTLS obbligatorio"}. -{"Replaced by new connection", "Sostituito da una nuova connessione"}. - -% mod_disco.erl -{"Configuration", "Configurazione"}. -{"Online Users", "Utenti online"}. -{"All Users", "Tutti gli utenti"}. -{"To ~s", "A ~s"}. -{"From ~s", "Da ~s"}. -{"Running Nodes", "Nodi attivi"}. -{"Stopped Nodes", "Nodi arrestati"}. -{"Access Control Lists", "Diritti di accesso (ACL)"}. -{"Access Rules", "Regole di accesso"}. -{"Modules", "Moduli"}. -{"Start Modules", "Avviare moduli"}. -{"Stop Modules", "Arrestare moduli"}. -{"Backup Management", "Gestione dei salvataggi"}. -{"Backup", "Salvare"}. -{"Restore", "Recuperare"}. -{"Dump to Text File", "Trascrivere su file di testo"}. -{"Import File", "Importare un file"}. -{"Import Directory", "Importare una directory"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Scegliere un nome utente e una password per la registrazione con questo server"}. - -% src/mod_vcard_ldap.erl -{"Erlang Jabber Server", "Erlang Jabber Server"}. -{"ejabberd vCard module", "Modulo vCard per ejabberd"}. -{"Email", "E-mail"}. -{"Search Results for ", "Risultati della ricerca per "}. -{"Jabber ID", "Jabber ID (JID)"}. - -% mod_vcard.erl -{"You need an x:data capable client to search", "Per effettuare ricerche è necessario un client che supporti x:data"}. -{"Search users in ", "Cercare utenti in "}. -{"Fill in fields to search for any matching Jabber User", "Riempire i campi per la ricerca di utenti Jabber corrispondenti ai criteri"}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Riempire il modulo per la ricerca di utenti Jabber corrispondenti ai criteri (Aggiungere * alla fine del campo per la ricerca di una sottostringa"}. -{"User", "Utente"}. -{"Full Name", "Nome completo"}. -{"Name", "Nome"}. -{"Middle Name", "Altro nome"}. -{"Family Name", "Cognome"}. -{"Nickname", "Nickname"}. -{"Birthday", "Compleanno"}. -{"Country", "Paese"}. -{"City", "Città"}. -{"Organization Name", "Nome dell'organizzazione"}. -{"Organization Unit", "Unità dell'organizzazione"}. - -% mod_adhoc.erl -{"Commands", "Comandi"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% mod_announce.erl -{"Send announcement to all users on all hosts", "Inviare l'annuncio a tutti gli utenti su tutti gli host"}. -{"Set message of the day on all hosts and send to online users", "Impostare il messaggio del giorno (MOTD) su tutti gli host e inviarlo agli utenti online"}. -{"Update message of the day on all hosts (don't send)", "Aggiornare il messaggio del giorno (MOTD) su tutti gli host (non inviarlo)"}. -{"Delete message of the day on all hosts", "Eliminare il messaggio del giorno (MOTD) su tutti gli host"}. -{"Really delete message of the day?", "Si conferma l'eliminazione del messaggio del giorno (MOTD)?"}. -{"Subject", "Oggetto"}. -{"Message body", "Corpo del messaggio"}. -{"No body provided for announce message", "Nessun corpo fornito per il messaggio di annuncio"}. -{"Announcements", "Annunci"}. -{"Send announcement to all users", "Inviare l'annuncio a tutti gli utenti"}. -{"Send announcement to all online users", "Inviare l'annuncio a tutti gli utenti online"}. -{"Send announcement to all online users on all hosts", "Inviare l'annuncio a tutti gli utenti online su tutti gli host"}. -{"Set message of the day and send to online users", "Impostare il messaggio del giorno (MOTD) ed inviarlo agli utenti online"}. -{"Update message of the day (don't send)", "Aggiornare il messaggio del giorno (MOTD) (non inviarlo)"}. -{"Delete message of the day", "Eliminare il messaggio del giorno (MOTD)"}. - -% mod_pubsub/mod_pubsub.erl -{"Roster groups allowed to subscribe", "Gruppi roster abilitati alla registrazione"}. -{"Publish-Subscribe", "Pubblicazione-Iscrizione"}. -{"ejabberd Publish-Subscribe module", "Modulo Pubblicazione/Iscrizione (PubSub) per ejabberd"}. -{"PubSub subscriber request", "Richiesta di iscrizione per PubSub"}. -{"Choose whether to approve this entity's subscription.", "Scegliere se approvare l'iscrizione per questa entità"}. -{"Node ID", "ID del nodo"}. -{"Subscriber Address", "Indirizzo dell'iscritta/o"}. -{"Allow this JID to subscribe to this pubsub node?", "Consentire a questo JID l'iscrizione a questo nodo pubsub?"}. -{"Deliver event notifications", "Inviare notifiche degli eventi"}. -{"Specify the access model", "Specificare il modello di accesso"}. -{"When to send the last published item", "Quando inviare l'ultimo elemento pubblicato"}. -{"Deliver payloads with event notifications", "Inviare il contenuto del messaggio con la notifica dell'evento"}. -{"Notify subscribers when the node configuration changes", "Notificare gli iscritti quando la configurazione del nodo cambia"}. -{"Notify subscribers when the node is deleted", "Notificare gli iscritti quando il nodo è cancellato"}. -{"Notify subscribers when items are removed from the node", "Notificare gli iscritti quando sono eliminati degli elementi dal nodo"}. -{"Persist items to storage", "Conservazione persistente degli elementi"}. -{"Max # of items to persist", "Numero massimo di elementi da conservare persistentemente"}. -{"Whether to allow subscriptions", "Consentire iscrizioni?"}. -{"Specify the publisher model", "Definire il modello di pubblicazione"}. -{"Max payload size in bytes", "Dimensione massima del contenuto del messaggio in byte"}. -{"Only deliver notifications to available users", "Inviare le notifiche solamente agli utenti disponibili"}. - -% mod_muc/mod_muc_log.erl -{"has been kicked because of an affiliation change", "è stato espulso a causa di un cambiamento di appartenenza"}. -{"has been kicked because the room has been changed to members-only", "è stato espulso per la limitazione della stanza ai soli membri"}. -{"has been kicked because of a system shutdown", "è stato espulso a causa dello spegnimento del sistema"}. -{"Chatroom configuration modified", "Configurazione della stanza modificata"}. -{"joins the room", "entra nella stanza"}. -{"leaves the room", "esce dalla stanza"}. -{"has been kicked", "è stata/o espulsa/o"}. -{"has been banned", "è stata/o bandita/o"}. -{"is now known as", "è ora conosciuta/o come"}. -{"Monday", "Lunedì"}. -{"Tuesday", "Martedì"}. -{"Wednesday", "Mercoledì"}. -{"Thursday", "Giovedì"}. -{"Friday", "Venerdì"}. -{"Saturday", "Sabato"}. -{"Sunday", "Domenica"}. -{"January", "Gennaio"}. -{"February", "Febbraio"}. -{"March", "Marzo"}. -{"April", "Aprile"}. -{"May", "Maggio"}. -{"June", "Giugno"}. -{"July", "Luglio"}. -{"August", "Agosto"}. -{"September", "Settembre"}. -{"October", "Ottobre"}. -{"November", "Novembre"}. -{"December", "Dicembre"}. -{"Room Configuration", "Configurazione della stanza"}. - -% mod_muc/mod_muc.erl -{"Chatrooms", "Stanze"}. -{"You need an x:data capable client to register nickname", "Per registrare un nickname è necessario un client che supporti x:data"}. -{"Nickname Registration at ", "Registrazione di un nickname su "}. -{"Enter nickname you want to register", "Immettere il nickname che si vuole registrare"}. -{"ejabberd MUC module", "Modulo MUC per ejabberd"}. -{"Only service administrators are allowed to send service messages", "L'invio di messaggi di servizio è consentito solamente agli amministratori del servizio"}. -{"Room creation is denied by service policy", "La creazione di stanze è impedita dalle politiche del servizio"}. -{"Conference room does not exist", "La stanza per conferenze non esiste"}. -{"Access denied by service policy", "Accesso impedito dalle politiche del servizio"}. -{"Specified nickname is already registered", "Il nickname specificato è già registrato"}. -{"You must fill in field \"Nickname\" in the form", "Si deve riempire il campo \"Nickname\" nel modulo"}. - -% mod_muc/mod_muc_room.erl -{"This participant is kicked from the room because he sent an error message", "Partecipante espulso dalla stanza perché ha inviato un messaggio non valido"}. -{"This participant is kicked from the room because he sent an error message to another participant", "Partecipante espulso dalla stanza perché ha inviato un messaggio non valido a un altro partecipante"}. -{"This participant is kicked from the room because he sent an error presence", "Partecipante espulso dalla stanza perché ha inviato una presenza non valido"}. -{"Traffic rate limit is exceeded", "Limite di traffico superato"}. -{"Maximum Number of Occupants", "Numero massimo di occupanti"}. -{"No limit", "Nessun limite"}. -{"~s invites you to the room ~s", "~s ti invita nella stanza ~s"}. -{"the password is", "la password è"}. -{" has set the subject to: ", " ha modificato l'oggetto in: "}. -{"You need an x:data capable client to configure room", "Per la configurazione della stanza è necessario un client che supporti x:data"}. -{"Configuration for ", "Configurazione per "}. -{"Room title", "Titolo della stanza"}. -{"Password", "Password"}. -{"Only moderators and participants are allowed to change subject in this room", "La modifica dell'oggetto di questa stanza è consentita soltanto ai moderatori e ai partecipanti"}. -{"Only moderators are allowed to change subject in this room", "La modifica dell'oggetto di questa stanza è consentita soltanto ai moderatori"}. -{"Visitors are not allowed to send messages to all occupants", "Non è consentito ai visitatori l'invio di messaggi a tutti i presenti"}. -{"Only occupants are allowed to send messages to the conference", "L'invio di messaggi alla conferenza è consentito soltanto ai presenti"}. -{"It is not allowed to send private messages to the conference", "Non è consentito l'invio di messaggi privati alla conferenza"}. -{"Improper message type", "Tipo di messaggio non corretto"}. -{"Nickname is already in use by another occupant", "Il nickname è già in uso all'interno della conferenza"}. -{"Nickname is registered by another person", "Il nickname è registrato da un'altra persona"}. -{"It is not allowed to send private messages of type \"groupchat\"", "Non è consentito l'invio di messaggi privati di tipo \"groupchat\""}. -{"Recipient is not in the conference room", "Il destinatario non è nella stanza per conferenze"}. -{"Only occupants are allowed to send queries to the conference", "L'invio di query alla conferenza è consentito ai soli presenti"}. -{"Queries to the conference members are not allowed in this room", "In questa stanza non sono consentite query ai membri della conferenza"}. -{"You have been banned from this room", "Sei stata/o bandita/o da questa stanza"}. -{"Membership required to enter this room", "Per entrare in questa stanza è necessario essere membro"}. -{"Password required to enter this room", "Per entrare in questa stanza è prevista una password"}. -{"Incorrect password", "Password non esatta"}. -{"Administrator privileges required", "Necessari i privilegi di amministratore"}. -{"Moderator privileges required", "Necessari i privilegi di moderatore"}. -{"JID ~s is invalid", "Il JID ~s non è valido"}. -{"Nickname ~s does not exist in the room", "Il nickname ~s non esiste nella stanza"}. -{"Invalid affiliation: ~s", "Affiliazione non valida: ~s"}. -{"Invalid role: ~s", "Ruolo non valido: ~s"}. -{"Owner privileges required", "Necessari i privilegi di proprietario"}. -{"private, ", "privato, "}. -{"This room is not anonymous", "Questa stanza non è anonima"}. -{"Make room persistent", "Rendere la stanza persistente"}. -{"Make room public searchable", "Rendere la sala visibile al pubblico"}. -{"Make participants list public", "Rendere pubblica la lista dei partecipanti"}. -{"Make room password protected", "Rendere la stanza protetta da password"}. -{"Make room members-only", "Rendere la stanza riservata ai membri"}. -{"Make room moderated", "Rendere la stanza moderata"}. -{"Default users as participants", "Definire per default gli utenti come partecipanti"}. -{"Allow users to change subject", "Consentire agli utenti di cambiare l'oggetto"}. -{"Allow users to send private messages", "Consentire agli utenti l'invio di messaggi privati"}. -{"Allow users to query other users", "Consentire agli utenti query verso altri utenti"}. -{"Allow users to send invites", "Consentire agli utenti l'invio di inviti"}. -{"Enable logging", "Abilitare i log"}. -{"Number of occupants", "Numero di presenti"}. -{"Present real JIDs to", "Rendere visibile il JID reale a"}. -{"moderators only", "moderatori soltanto"}. -{"anyone", "tutti"}. - -% mod_irc/mod_irc.erl -{"IRC Transport", "Transport IRC"}. -{"ejabberd IRC module", "Modulo IRC per ejabberd"}. -{"You need an x:data capable client to configure mod_irc settings", "Per la configurazione del modulo IRC è necessario un client che supporti x:data"}. -{"Registration in mod_irc for ", "Registrazione in mod_irc per "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Immettere il nome utente e le codifiche che si desidera utilizzare per la connessione ai server IRC"}. -{"IRC Username", "Nome utente IRC"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Se si vogliono specificare differenti codifiche per i server IRC, si riempa questo elenco con valori nel formato '{\"server IRC\", \"codifica\"}'. Per default questo servizio utilizza la codifica \"~s\"."}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Esempio: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"Encodings", "Codifiche"}. - -% web/ejabberd_web_admin.erl -{"ejabberd Web Admin", "Amministrazione web ejabberd"}. -{"Administration", "Amministrazione"}. -{"Users", "Utenti"}. -{"Nodes", "Nodi"}. -{"Statistics", "Statistiche"}. -{"(Raw)", "(Grezzo)"}. -{"Submitted", "Inviato"}. -{"Bad format", "Formato non valido"}. -{"Raw", "Grezzo"}. -{"Delete Selected", "Eliminare gli elementi selezionati"}. -{"Submit", "Inviare"}. -{"~s access rule configuration", "Configurazione delle regole di accesso per ~s"}. -{"Node not found", "Nodo non trovato"}. -{"Add New", "Aggiungere nuovo"}. -{"Registered Users", "Utenti registrati"}. -{"Registered Users:", "Utenti registrati:"}. -{"Change Password", "Modificare la password"}. -{"Connected Resources:", "Risorse connesse:"}. -{"Password:", "Password:"}. -{"None", "Nessuno"}. -{"Node ", "Nodo "}. -{"Listened Ports", "Porte in ascolto"}. -{"Restart", "Riavviare"}. -{"Stop", "Arrestare"}. -{"RPC Call Error", "Errore di chiamata RPC"}. -{"Name", "Nome"}. -{"Storage Type", "Tipo di conservazione"}. -{"Size", "Dimensione"}. -{"Memory", "Memoria"}. -{"OK", "OK"}. -{"Listened Ports at ", "Porte in ascolto su "}. -{"Uptime:", "Tempo dall'avvio:"}. -{"CPU Time:", "Tempo CPU:"}. -{"Transactions Commited:", "Transazioni avvenute:"}. -{"Transactions Aborted:", "Transazioni abortite:"}. -{"Transactions Restarted:", "Transazioni riavviate:"}. -{"Transactions Logged:", "Transazioni con log:"}. -{"Port", "Porta"}. -{"Module", "Modulo"}. -{"Options", "Opzioni"}. -{"Update", "Aggiornare"}. -{"Delete", "Eliminare"}. -{"Add User", "Aggiungere un utente"}. -{"Offline Messages", "Messaggi offline"}. -{"Users Last Activity", "Ultima attività degli utenti"}. -{"Never", "Mai"}. -{"~s's Offline Messages Queue", "Coda di ~s messaggi offline"}. -{"Time", "Ora"}. -{"From", "Da"}. -{"To", "A"}. -{"Packet", "Pacchetto"}. -{"Offline Messages:", "Messaggi offline:"}. -{"Roster", "Lista dei contatti"}. -{"Nickname", "Nickname"}. -{"Subscription", "Iscrizione"}. -{"Pending", "Pendente"}. -{"Groups", "Gruppi"}. -{"Remove", "Eliminare"}. -{"Add Jabber ID", "Aggiungere un Jabber ID (JID)"}. -{"User ", "Utente "}. -{"Roster of ", "Lista dei contatti di "}. -{"Online", "Online"}. -{"Validate", "Validare"}. -{"Name:", "Nome:"}. -{"Description:", "Descrizione:"}. -{"Members:", "Membri:"}. -{"Displayed Groups:", "Gruppi visualizzati:"}. -{"Group ", "Gruppo "}. -{"Period: ", "Periodo:"}. -{"Last month", "Ultimo mese"}. -{"Last year", "Ultimo anno"}. -{"All activity", "Tutta l'attività"}. -{"Show Ordinary Table", "Mostrare la tabella normale"}. -{"Show Integral Table", "Mostrare la tabella integrale"}. -{"Modules at ", "Moduli su "}. -{"Start", "Avviare"}. -{"Virtual Hosts", "Host virtuali"}. -{"ejabberd virtual hosts", "Host virtuali di ejabberd"}. -{"Host", "Host"}. -{"No Data", "Nessuna informazione"}. -{"Online Users:", "Utenti connessi:"}. -{"Outgoing s2s Connections:", "Connessioni s2s in uscita:"}. -{"Outgoing s2s Servers:", "Server s2s in uscita"}. -{"Database Tables at ", "Tabelle del database su "}. -{"Backup of ", "Salvataggio di "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "N.B.: Queste opzioni comportano il salvataggio solamente del database interno Mnesia. Se si sta utilizzando il modulo ODBC, è necessario salvare il proprio database SQL separatamente."}. -{"Store binary backup:", "Conservare un salvataggio binario:"}. -{"Restore binary backup immediately:", "Recuperare un salvataggio binario adesso:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Recuperare un salvataggio binario dopo il prossimo riavvio di ejabberd (necessita di meno memoria):"}. -{"Store plain text backup:", "Conservare un salvataggio come semplice testo:"}. -{"Restore plain text backup immediately:", "Recuperare un salvataggio come semplice testo adesso:"}. -{"Statistics of ~p", "Statistiche di ~p"}. -{"Update ", "Aggiornare "}. -{"Update plan", "Piano di aggiornamento"}. -{"Updated modules", "Moduli aggiornati"}. -{"Update script", "Script di aggiornamento"}. -{"Low level update script", "Script di aggiornamento di basso livello"}. -{"Script check", "Verifica dello script"}. -{"Shared Roster Groups", "Gruppi di liste di contatti comuni"}. -{"Last Activity", "Ultima attività"}. - -% mod_vcard_odbc.erl -{"vCard User Search", "Ricerca di utenti per vCard"}. - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "La coda dei messaggi offline del contatto è piena. Il messaggio è stato scartato"}. - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "Modulo SOCKS5 Bytestreams per ejabberd"}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Configurazione dell'accesso"}. +{"Access Control List Configuration","Configurazione dei diritti di accesso (ACL)"}. +{"Access control lists","Diritti di accesso (ACL)"}. +{"Access Control Lists","Diritti di accesso (ACL)"}. +{"Access denied by service policy","Accesso impedito dalle politiche del servizio"}. +{"Access rules","Regole di accesso"}. +{"Access Rules","Regole di accesso"}. +{"Action on user","Azione sull'utente"}. +{"Add Jabber ID","Aggiungere un Jabber ID (JID)"}. +{"Add New","Aggiungere nuovo"}. +{"Add User","Aggiungere un utente"}. +{"Administration","Amministrazione"}. +{"Administration of ","Amministrazione di "}. +{"Administrator privileges required","Necessari i privilegi di amministratore"}. +{"A friendly name for the node","Un nome comodo per il nodo"}. +{"All activity","Tutta l'attività"}. +{"Allow this JID to subscribe to this pubsub node?","Consentire a questo JID l'iscrizione a questo nodo pubsub?"}. +{"Allow users to change subject","Consentire agli utenti di cambiare l'oggetto"}. +{"Allow users to query other users","Consentire agli utenti query verso altri utenti"}. +{"Allow users to send invites","Consentire agli utenti l'invio di inviti"}. +{"Allow users to send private messages","Consentire agli utenti l'invio di messaggi privati"}. +{"Allow visitors to change nickname","Consentire ai visitatori di cambiare il nickname"}. +{"Allow visitors to send status text in presence updates","Consentire ai visitatori l'invio di testo sullo stato in aggiornamenti sulla presenza"}. +{"All Users","Tutti gli utenti"}. +{"Announcements","Annunci"}. +{"anyone","tutti"}. +{"April","Aprile"}. +{"August","Agosto"}. +{"Backup Management","Gestione dei salvataggi"}. +{"Backup of ","Salvataggio di "}. +{"Backup","Salvare"}. +{"Backup to File at ","Salvataggio sul file "}. +{"Bad format","Formato non valido"}. +{"Birthday","Compleanno"}. +{"Change Password","Modificare la password"}. +{"Change User Password","Cambiare la password dell'utente"}. +{"Chatroom configuration modified","Configurazione della stanza modificata"}. +{"Chatrooms","Stanze"}. +{"Choose a username and password to register with this server","Scegliere un nome utente e una password per la registrazione con questo server"}. +{"Choose modules to stop","Selezionare i moduli da arrestare"}. +{"Choose storage type of tables","Selezionare una modalità di conservazione delle tabelle"}. +{"Choose whether to approve this entity's subscription.","Scegliere se approvare l'iscrizione per questa entità"}. +{"City","Città"}. +{"Commands","Comandi"}. +{"Conference room does not exist","La stanza per conferenze non esiste"}. +{"Configuration","Configurazione"}. +{"Configuration for ","Configurazione per "}. +{"Connected Resources:","Risorse connesse:"}. +{"Country","Paese"}. +{"CPU Time:","Tempo CPU:"}. +{"Database","Database"}. +{"Database Tables at ","Tabelle del database su "}. +{"Database Tables Configuration at ","Configurazione delle tabelle del database su "}. +{"December","Dicembre"}. +{"Default users as participants","Definire per default gli utenti come partecipanti"}. +{"Delete","Eliminare"}. +{"Delete message of the day","Eliminare il messaggio del giorno (MOTD)"}. +{"Delete message of the day on all hosts","Eliminare il messaggio del giorno (MOTD) su tutti gli host"}. +{"Delete Selected","Eliminare gli elementi selezionati"}. +{"Delete User","Eliminare l'utente"}. +{"Deliver event notifications","Inviare notifiche degli eventi"}. +{"Deliver payloads with event notifications","Inviare il contenuto del messaggio con la notifica dell'evento"}. +{"Description:","Descrizione:"}. +{"Disc only copy","Copia su disco soltanto"}. +{"Displayed Groups:","Gruppi visualizzati:"}. +{"Dump Backup to Text File at ","Trascrivere il salvataggio sul file di testo "}. +{"Dump to Text File","Trascrivere su file di testo"}. +{"Edit Properties","Modificare le proprietà"}. +{"ejabberd IRC module","Modulo IRC per ejabberd"}. +{"ejabberd MUC module","Modulo MUC per ejabberd"}. +{"ejabberd Publish-Subscribe module","Modulo Pubblicazione/Iscrizione (PubSub) per ejabberd"}. +{"ejabberd SOCKS5 Bytestreams module","Modulo SOCKS5 Bytestreams per ejabberd"}. +{"ejabberd vCard module","Modulo vCard per ejabberd"}. +{"ejabberd virtual hosts","Host virtuali di ejabberd"}. +{"ejabberd Web Admin","Amministrazione web ejabberd"}. +{"Email","E-mail"}. +{"Enable logging","Abilitare i log"}. +{"Encodings","Codifiche"}. +{"End User Session","Terminare la sessione dell'utente"}. +{"Enter list of {Module, [Options]}","Immettere un elenco di {Modulo, [Opzioni]}"}. +{"Enter nickname you want to register","Immettere il nickname che si vuole registrare"}. +{"Enter path to backup file","Immettere il percorso del file di salvataggio"}. +{"Enter path to jabberd1.4 spool dir","Immettere il percorso della directory di spool di jabberd1.4"}. +{"Enter path to jabberd1.4 spool file","Immettere il percorso del file di spool di jabberd1.4"}. +{"Enter path to text file","Immettere il percorso del file di testo"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Immettere il nome utente e le codifiche che si desidera utilizzare per la connessione ai server IRC"}. +{"Erlang Jabber Server","Erlang Jabber Server"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Esempio: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","Cognome"}. +{"February","Febbraio"}. +{"Fill in fields to search for any matching Jabber User","Riempire i campi per la ricerca di utenti Jabber corrispondenti ai criteri"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Riempire il modulo per la ricerca di utenti Jabber corrispondenti ai criteri (Aggiungere * alla fine del campo per la ricerca di una sottostringa"}. +{"Friday","Venerdì"}. +{"From","Da"}. +{"From ~s","Da ~s"}. +{"Full Name","Nome completo"}. +{"Get Number of Online Users","Ottenere il numero di utenti online"}. +{"Get Number of Registered Users","Ottenere il numero di utenti registrati"}. +{"Get User Last Login Time","Ottenere la data di ultimo accesso dell'utente"}. +{"Get User Password","Ottenere la password dell'utente"}. +{"Get User Statistics","Ottenere le statistiche dell'utente"}. +{"Group ","Gruppo "}. +{"Groups","Gruppi"}. +{"has been banned","è stata/o bandita/o"}. +{"has been kicked because of an affiliation change","è stato espulso a causa di un cambiamento di appartenenza"}. +{"has been kicked because of a system shutdown","è stato espulso a causa dello spegnimento del sistema"}. +{"has been kicked because the room has been changed to members-only","è stato espulso per la limitazione della stanza ai soli membri"}. +{"has been kicked","è stata/o espulsa/o"}. +{" has set the subject to: "," ha modificato l'oggetto in: "}. +{"Host","Host"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Se si vogliono specificare differenti codifiche per i server IRC, si riempa questo elenco con valori nel formato '{\"server IRC\", \"codifica\"}'. Per default questo servizio utilizza la codifica \"~s\"."}. +{"Import Directory","Importare una directory"}. +{"Import File","Importare un file"}. +{"Import User from File at ","Importare un utente dal file "}. +{"Import Users from Dir at ","Importare utenti dalla directory "}. +{"Import Users From jabberd 1.4 Spool Files","Importare utenti da file di spool di jabberd 1.4"}. +{"Improper message type","Tipo di messaggio non corretto"}. +{"Incorrect password","Password non esatta"}. +{"Invalid affiliation: ~s","Affiliazione non valida: ~s"}. +{"Invalid role: ~s","Ruolo non valido: ~s"}. +{"IP addresses","Indirizzi IP"}. +{"IRC Transport","Transport IRC"}. +{"IRC Username","Nome utente IRC"}. +{"is now known as","è ora conosciuta/o come"}. +{"It is not allowed to send private messages","Non è consentito l'invio di messaggi privati"}. +{"It is not allowed to send private messages of type \"groupchat\"","Non è consentito l'invio di messaggi privati di tipo \"groupchat\""}. +{"It is not allowed to send private messages to the conference","Non è consentito l'invio di messaggi privati alla conferenza"}. +{"Jabber ID","Jabber ID (JID)"}. +{"January","Gennaio"}. +{"JID ~s is invalid","Il JID ~s non è valido"}. +{"joins the room","entra nella stanza"}. +{"July","Luglio"}. +{"June","Giugno"}. +{"Last Activity","Ultima attività"}. +{"Last login","Ultimo accesso"}. +{"Last month","Ultimo mese"}. +{"Last year","Ultimo anno"}. +{"leaves the room","esce dalla stanza"}. +{"Listened Ports at ","Porte in ascolto su "}. +{"Listened Ports","Porte in ascolto"}. +{"List of modules to start","Elenco dei moduli da avviare"}. +{"Low level update script","Script di aggiornamento di basso livello"}. +{"Make participants list public","Rendere pubblica la lista dei partecipanti"}. +{"Make room members-only","Rendere la stanza riservata ai membri"}. +{"Make room moderated","Rendere la stanza moderata"}. +{"Make room password protected","Rendere la stanza protetta da password"}. +{"Make room persistent","Rendere la stanza persistente"}. +{"Make room public searchable","Rendere la sala visibile al pubblico"}. +{"March","Marzo"}. +{"Maximum Number of Occupants","Numero massimo di occupanti"}. +{"Max # of items to persist","Numero massimo di elementi da conservare persistentemente"}. +{"Max payload size in bytes","Dimensione massima del contenuto del messaggio in byte"}. +{"May","Maggio"}. +{"Membership required to enter this room","Per entrare in questa stanza è necessario essere membro"}. +{"Members:","Membri:"}. +{"Memory","Memoria"}. +{"Message body","Corpo del messaggio"}. +{"Middle Name","Altro nome"}. +{"Moderator privileges required","Necessari i privilegi di moderatore"}. +{"moderators only","moderatori soltanto"}. +{"Module","Modulo"}. +{"Modules at ","Moduli su "}. +{"Modules","Moduli"}. +{"Monday","Lunedì"}. +{"Name:","Nome:"}. +{"Name","Nome"}. +{"Never","Mai"}. +{"Nickname is already in use by another occupant","Il nickname è già in uso all'interno della conferenza"}. +{"Nickname is registered by another person","Il nickname è registrato da un'altra persona"}. +{"Nickname","Nickname"}. +{"Nickname Registration at ","Registrazione di un nickname su "}. +{"Nickname ~s does not exist in the room","Il nickname ~s non esiste nella stanza"}. +{"No body provided for announce message","Nessun corpo fornito per il messaggio di annuncio"}. +{"No Data","Nessuna informazione"}. +{"Node ID","ID del nodo"}. +{"Node ","Nodo "}. +{"Node not found","Nodo non trovato"}. +{"Nodes","Nodi"}. +{"No limit","Nessun limite"}. +{"None","Nessuno"}. +{"No resource provided","Nessuna risorsa fornita"}. +{"Notify subscribers when items are removed from the node","Notificare gli iscritti quando sono eliminati degli elementi dal nodo"}. +{"Notify subscribers when the node configuration changes","Notificare gli iscritti quando la configurazione del nodo cambia"}. +{"Notify subscribers when the node is deleted","Notificare gli iscritti quando il nodo è cancellato"}. +{"November","Novembre"}. +{"Number of occupants","Numero di presenti"}. +{"Number of online users","Numero di utenti online"}. +{"Number of registered users","Numero di utenti registrati"}. +{"October","Ottobre"}. +{"Offline Messages:","Messaggi offline:"}. +{"Offline Messages","Messaggi offline"}. +{"OK","OK"}. +{"Online","Online"}. +{"Online Users:","Utenti connessi:"}. +{"Online Users","Utenti online"}. +{"Only deliver notifications to available users","Inviare le notifiche solamente agli utenti disponibili"}. +{"Only moderators and participants are allowed to change subject in this room","La modifica dell'oggetto di questa stanza è consentita soltanto ai moderatori e ai partecipanti"}. +{"Only moderators are allowed to change subject in this room","La modifica dell'oggetto di questa stanza è consentita soltanto ai moderatori"}. +{"Only occupants are allowed to send messages to the conference","L'invio di messaggi alla conferenza è consentito soltanto ai presenti"}. +{"Only occupants are allowed to send queries to the conference","L'invio di query alla conferenza è consentito ai soli presenti"}. +{"Only service administrators are allowed to send service messages","L'invio di messaggi di servizio è consentito solamente agli amministratori del servizio"}. +{"Options","Opzioni"}. +{"Organization Name","Nome dell'organizzazione"}. +{"Organization Unit","Unità dell'organizzazione"}. +{"Outgoing s2s Connections:","Connessioni s2s in uscita:"}. +{"Outgoing s2s Connections","Connessioni s2s in uscita"}. +{"Outgoing s2s Servers:","Server s2s in uscita"}. +{"Owner privileges required","Necessari i privilegi di proprietario"}. +{"Packet","Pacchetto"}. +{"Password:","Password:"}. +{"Password","Password"}. +{"Password required to enter this room","Per entrare in questa stanza è prevista una password"}. +{"Password Verification","Verifica della password"}. +{"Path to Dir","Percorso della directory"}. +{"Path to File","Percorso del file"}. +{"Pending","Pendente"}. +{"Period: ","Periodo:"}. +{"Persist items to storage","Conservazione persistente degli elementi"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","Porta"}. +{"Present real JIDs to","Rendere visibile il JID reale a"}. +{"private, ","privato, "}. +{"Publish-Subscribe","Pubblicazione-Iscrizione"}. +{"PubSub subscriber request","Richiesta di iscrizione per PubSub"}. +{"Queries to the conference members are not allowed in this room","In questa stanza non sono consentite query ai membri della conferenza"}. +{"RAM and disc copy","Copia in memoria (RAM) e su disco"}. +{"RAM copy","Copia in memoria (RAM)"}. +{"(Raw)","(Grezzo)"}. +{"Raw","Grezzo"}. +{"Really delete message of the day?","Si conferma l'eliminazione del messaggio del giorno (MOTD)?"}. +{"Recipient is not in the conference room","Il destinatario non è nella stanza per conferenze"}. +{"Registered Users:","Utenti registrati:"}. +{"Registered Users","Utenti registrati"}. +{"Registration in mod_irc for ","Registrazione in mod_irc per "}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","N.B.: Queste opzioni comportano il salvataggio solamente del database interno Mnesia. Se si sta utilizzando il modulo ODBC, è necessario salvare il proprio database SQL separatamente."}. +{"Remote copy","Copia remota"}. +{"Remove","Eliminare"}. +{"Remove User","Eliminare l'utente"}. +{"Replaced by new connection","Sostituito da una nuova connessione"}. +{"Resources","Risorse"}. +{"Restart","Riavviare"}. +{"Restart Service","Riavviare il servizio"}. +{"Restore Backup from File at ","Recuperare il salvataggio dal file "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Recuperare un salvataggio binario dopo il prossimo riavvio di ejabberd (necessita di meno memoria):"}. +{"Restore binary backup immediately:","Recuperare un salvataggio binario adesso:"}. +{"Restore plain text backup immediately:","Recuperare un salvataggio come semplice testo adesso:"}. +{"Restore","Recuperare"}. +{"Room Configuration","Configurazione della stanza"}. +{"Room creation is denied by service policy","La creazione di stanze è impedita dalle politiche del servizio"}. +{"Room title","Titolo della stanza"}. +{"Roster groups allowed to subscribe","Gruppi roster abilitati alla registrazione"}. +{"Roster","Lista dei contatti"}. +{"Roster of ","Lista dei contatti di "}. +{"Roster size","Dimensione della lista dei contatti"}. +{"RPC Call Error","Errore di chiamata RPC"}. +{"Running Nodes","Nodi attivi"}. +{"~s access rule configuration","Configurazione delle regole di accesso per ~s"}. +{"Saturday","Sabato"}. +{"Script check","Verifica dello script"}. +{"Search Results for ","Risultati della ricerca per "}. +{"Search users in ","Cercare utenti in "}. +{"Send announcement to all online users","Inviare l'annuncio a tutti gli utenti online"}. +{"Send announcement to all online users on all hosts","Inviare l'annuncio a tutti gli utenti online su tutti gli host"}. +{"Send announcement to all users","Inviare l'annuncio a tutti gli utenti"}. +{"Send announcement to all users on all hosts","Inviare l'annuncio a tutti gli utenti su tutti gli host"}. +{"September","Settembre"}. +{"Set message of the day and send to online users","Impostare il messaggio del giorno (MOTD) ed inviarlo agli utenti online"}. +{"Set message of the day on all hosts and send to online users","Impostare il messaggio del giorno (MOTD) su tutti gli host e inviarlo agli utenti online"}. +{"Shared Roster Groups","Gruppi di liste di contatti comuni"}. +{"Show Integral Table","Mostrare la tabella integrale"}. +{"Show Ordinary Table","Mostrare la tabella normale"}. +{"Shut Down Service","Terminare il servizio"}. +{"~s invites you to the room ~s","~s ti invita nella stanza ~s"}. +{"Size","Dimensione"}. +{"Specified nickname is already registered","Il nickname specificato è già registrato"}. +{"Specify the access model","Specificare il modello di accesso"}. +{"Specify the publisher model","Definire il modello di pubblicazione"}. +{"~s's Offline Messages Queue","Coda di ~s messaggi offline"}. +{"Start","Avviare"}. +{"Start Modules at ","Avviare moduli su "}. +{"Start Modules","Avviare moduli"}. +{"Statistics of ~p","Statistiche di ~p"}. +{"Statistics","Statistiche"}. +{"Stop","Arrestare"}. +{"Stop Modules","Arrestare moduli"}. +{"Stop Modules at ","Arrestare moduli su "}. +{"Stopped Nodes","Nodi arrestati"}. +{"Storage Type","Tipo di conservazione"}. +{"Store binary backup:","Conservare un salvataggio binario:"}. +{"Store plain text backup:","Conservare un salvataggio come semplice testo:"}. +{"Subject","Oggetto"}. +{"Submit","Inviare"}. +{"Submitted","Inviato"}. +{"Subscriber Address","Indirizzo dell'iscritta/o"}. +{"Subscription","Iscrizione"}. +{"Sunday","Domenica"}. +{"the password is","la password è"}. +{"This participant is kicked from the room because he sent an error message","Partecipante espulso dalla stanza perché ha inviato un messaggio non valido"}. +{"This participant is kicked from the room because he sent an error message to another participant","Partecipante espulso dalla stanza perché ha inviato un messaggio non valido a un altro partecipante"}. +{"This participant is kicked from the room because he sent an error presence","Partecipante espulso dalla stanza perché ha inviato una presenza non valido"}. +{"This room is not anonymous","Questa stanza non è anonima"}. +{"Thursday","Giovedì"}. +{"Time delay","Ritardo"}. +{"Time","Ora"}. +{"To","A"}. +{"To ~s","A ~s"}. +{"Traffic rate limit is exceeded","Limite di traffico superato"}. +{"Transactions Aborted:","Transazioni abortite:"}. +{"Transactions Commited:","Transazioni avvenute:"}. +{"Transactions Logged:","Transazioni con log:"}. +{"Transactions Restarted:","Transazioni riavviate:"}. +{"Tuesday","Martedì"}. +{"Update ","Aggiornare "}. +{"Update","Aggiornare"}. +{"Updated modules","Moduli aggiornati"}. +{"Update message of the day (don't send)","Aggiornare il messaggio del giorno (MOTD) (non inviarlo)"}. +{"Update message of the day on all hosts (don't send)","Aggiornare il messaggio del giorno (MOTD) su tutti gli host (non inviarlo)"}. +{"Update plan","Piano di aggiornamento"}. +{"Update script","Script di aggiornamento"}. +{"Uptime:","Tempo dall'avvio:"}. +{"Use of STARTTLS required","Utilizzo di STARTTLS obbligatorio"}. +{"User Management","Gestione degli utenti"}. +{"Users are not allowed to register accounts so fast","Non è consentito agli utenti registrare account così rapidamente"}. +{"Users Last Activity","Ultima attività degli utenti"}. +{"Users","Utenti"}. +{"User ","Utente "}. +{"User","Utente"}. +{"Validate","Validare"}. +{"vCard User Search","Ricerca di utenti per vCard"}. +{"Virtual Hosts","Host virtuali"}. +{"Visitors are not allowed to change their nicknames in this room","Non è consentito ai visitatori cambiare il nickname in questa stanza"}. +{"Visitors are not allowed to send messages to all occupants","Non è consentito ai visitatori l'invio di messaggi a tutti i presenti"}. +{"Wednesday","Mercoledì"}. +{"When to send the last published item","Quando inviare l'ultimo elemento pubblicato"}. +{"Whether to allow subscriptions","Consentire iscrizioni?"}. +{"You have been banned from this room","Sei stata/o bandita/o da questa stanza"}. +{"You must fill in field \"Nickname\" in the form","Si deve riempire il campo \"Nickname\" nel modulo"}. +{"You need an x:data capable client to configure mod_irc settings","Per la configurazione del modulo IRC è necessario un client che supporti x:data"}. +{"You need an x:data capable client to configure room","Per la configurazione della stanza è necessario un client che supporti x:data"}. +{"You need an x:data capable client to register nickname","Per registrare un nickname è necessario un client che supporti x:data"}. +{"You need an x:data capable client to search","Per effettuare ricerche è necessario un client che supporti x:data"}. +{"Your contact offline message queue is full. The message has been discarded.","La coda dei messaggi offline del contatto è piena. Il messaggio è stato scartato"}. diff --git a/src/msgs/it.po b/src/msgs/it.po new file mode 100644 index 000000000..3f436c9bb --- /dev/null +++ b/src/msgs/it.po @@ -0,0 +1,1506 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Luca Brivio\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Italian (italiano)\n" +"X-Additional-Translator: Smart2128\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "Utilizzo di STARTTLS obbligatorio" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Nessuna risorsa fornita" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Sostituito da una nuova connessione" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Comandi" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Si conferma l'eliminazione del messaggio del giorno (MOTD)?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Oggetto" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Corpo del messaggio" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "Nessun corpo fornito per il messaggio di annuncio" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Annunci" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Inviare l'annuncio a tutti gli utenti" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Inviare l'annuncio a tutti gli utenti su tutti gli host" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Inviare l'annuncio a tutti gli utenti online" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "Inviare l'annuncio a tutti gli utenti online su tutti gli host" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "" +"Impostare il messaggio del giorno (MOTD) ed inviarlo agli utenti online" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Impostare il messaggio del giorno (MOTD) su tutti gli host e inviarlo agli " +"utenti online" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Aggiornare il messaggio del giorno (MOTD) (non inviarlo)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "" +"Aggiornare il messaggio del giorno (MOTD) su tutti gli host (non inviarlo)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Eliminare il messaggio del giorno (MOTD)" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Eliminare il messaggio del giorno (MOTD) su tutti gli host" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Configurazione" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Database" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Avviare moduli" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Arrestare moduli" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Salvare" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Recuperare" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Trascrivere su file di testo" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Importare un file" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Importare una directory" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Riavviare il servizio" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Terminare il servizio" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Aggiungere un utente" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Eliminare l'utente" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Terminare la sessione dell'utente" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Ottenere la password dell'utente" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Cambiare la password dell'utente" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Ottenere la data di ultimo accesso dell'utente" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Ottenere le statistiche dell'utente" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Ottenere il numero di utenti registrati" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Ottenere il numero di utenti online" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Diritti di accesso (ACL)" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Regole di accesso" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Gestione degli utenti" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Utenti online" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Tutti gli utenti" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Connessioni s2s in uscita" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Nodi attivi" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Nodi arrestati" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Moduli" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Gestione dei salvataggi" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Importare utenti da file di spool di jabberd 1.4" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "A ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "Da ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Configurazione delle tabelle del database su " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Selezionare una modalità di conservazione delle tabelle" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Copia su disco soltanto" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "Copia in memoria (RAM) e su disco" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "Copia in memoria (RAM)" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Copia remota" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Arrestare moduli su " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Selezionare i moduli da arrestare" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Avviare moduli su " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Immettere un elenco di {Modulo, [Opzioni]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Elenco dei moduli da avviare" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Salvataggio sul file " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Immettere il percorso del file di salvataggio" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Percorso del file" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Recuperare il salvataggio dal file " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Trascrivere il salvataggio sul file di testo " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Immettere il percorso del file di testo" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Importare un utente dal file " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Immettere il percorso del file di spool di jabberd1.4" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Importare utenti dalla directory " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Immettere il percorso della directory di spool di jabberd1.4" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Percorso della directory" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Ritardo" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Configurazione dei diritti di accesso (ACL)" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Diritti di accesso (ACL)" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Configurazione dell'accesso" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Regole di accesso" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID (JID)" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Password" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Verifica della password" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Numero di utenti registrati" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Numero di utenti online" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Mai" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Online" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Ultimo accesso" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Dimensione della lista dei contatti" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "Indirizzi IP" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Risorse" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Amministrazione di " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Azione sull'utente" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Modificare le proprietà" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Eliminare l'utente" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Accesso impedito dalle politiche del servizio" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "Transport IRC" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "Modulo IRC per ejabberd" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "" +"Per la configurazione del modulo IRC è necessario un client che supporti x:" +"data" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Registrazione in mod_irc per " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Immettere il nome utente e le codifiche che si desidera utilizzare per la " +"connessione ai server IRC" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "Nome utente IRC" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Se si vogliono specificare differenti codifiche per i server IRC, si riempa " +"questo elenco con valori nel formato '{\"server IRC\", \"codifica\"}'. Per " +"default questo servizio utilizza la codifica \"~s\"." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Esempio: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Codifiche" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "" +"L'invio di messaggi di servizio è consentito solamente agli amministratori " +"del servizio" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "La creazione di stanze è impedita dalle politiche del servizio" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "La stanza per conferenze non esiste" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Stanze" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "Per registrare un nickname è necessario un client che supporti x:data" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Registrazione di un nickname su " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Immettere il nickname che si vuole registrare" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Nickname" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "Il nickname specificato è già registrato" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Si deve riempire il campo \"Nickname\" nel modulo" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "Modulo MUC per ejabberd" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Configurazione della stanza modificata" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "entra nella stanza" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "esce dalla stanza" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "è stata/o bandita/o" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "è stata/o espulsa/o" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "è stato espulso a causa di un cambiamento di appartenenza" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "è stato espulso per la limitazione della stanza ai soli membri" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "è stato espulso a causa dello spegnimento del sistema" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "è ora conosciuta/o come" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " ha modificato l'oggetto in: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "Lunedì" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "Martedì" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "Mercoledì" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "Giovedì" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "Venerdì" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "Sabato" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "Domenica" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "Gennaio" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "Febbraio" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "Marzo" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "Aprile" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "Maggio" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "Giugno" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "Luglio" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "Agosto" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "Settembre" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "Ottobre" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "Novembre" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "Dicembre" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Configurazione della stanza" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Titolo della stanza" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Limite di traffico superato" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" +"Partecipante espulso dalla stanza perché ha inviato un messaggio non valido" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Non è consentito l'invio di messaggi privati alla conferenza" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Tipo di messaggio non corretto" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Partecipante espulso dalla stanza perché ha inviato un messaggio non valido " +"a un altro partecipante" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "Non è consentito l'invio di messaggi privati di tipo \"groupchat\"" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "Il destinatario non è nella stanza per conferenze" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "L'invio di messaggi alla conferenza è consentito soltanto ai presenti" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "Non è consentito l'invio di messaggi privati" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "L'invio di query alla conferenza è consentito ai soli presenti" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "In questa stanza non sono consentite query ai membri della conferenza" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "privato, " + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "" +"La modifica dell'oggetto di questa stanza è consentita soltanto ai " +"moderatori e ai partecipanti" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "" +"La modifica dell'oggetto di questa stanza è consentita soltanto ai moderatori" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "Non è consentito ai visitatori l'invio di messaggi a tutti i presenti" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" +"Partecipante espulso dalla stanza perché ha inviato una presenza non valido" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Non è consentito ai visitatori cambiare il nickname in questa stanza" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "Il nickname è già in uso all'interno della conferenza" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "Il nickname è registrato da un'altra persona" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Sei stata/o bandita/o da questa stanza" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "Per entrare in questa stanza è necessario essere membro" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Questa stanza non è anonima" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Per entrare in questa stanza è prevista una password" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Password non esatta" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Necessari i privilegi di amministratore" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Necessari i privilegi di moderatore" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "Il JID ~s non è valido" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "Il nickname ~s non esiste nella stanza" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Affiliazione non valida: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Ruolo non valido: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Necessari i privilegi di proprietario" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Configurazione per " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Descrizione:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Rendere la stanza persistente" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Rendere la sala visibile al pubblico" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Rendere pubblica la lista dei partecipanti" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Rendere la stanza protetta da password" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Numero massimo di occupanti" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Nessun limite" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Rendere visibile il JID reale a" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "moderatori soltanto" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "tutti" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Rendere la stanza riservata ai membri" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Rendere la stanza moderata" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Definire per default gli utenti come partecipanti" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Consentire agli utenti di cambiare l'oggetto" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Consentire agli utenti l'invio di messaggi privati" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Consentire agli utenti query verso altri utenti" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Consentire agli utenti l'invio di inviti" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "" +"Consentire ai visitatori l'invio di testo sullo stato in aggiornamenti sulla " +"presenza" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Consentire ai visitatori di cambiare il nickname" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Abilitare i log" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "" +"Per la configurazione della stanza è necessario un client che supporti x:data" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Numero di presenti" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s ti invita nella stanza ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "la password è" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "" +"La coda dei messaggi offline del contatto è piena. Il messaggio è stato " +"scartato" + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "Coda di ~s messaggi offline" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Inviato" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Ora" + +#: mod_offline.erl:507 +msgid "From" +msgstr "Da" + +#: mod_offline.erl:508 +msgid "To" +msgstr "A" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Pacchetto" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Eliminare gli elementi selezionati" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Messaggi offline:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "Modulo SOCKS5 Bytestreams per ejabberd" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Pubblicazione-Iscrizione" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "Modulo Pubblicazione/Iscrizione (PubSub) per ejabberd" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "Richiesta di iscrizione per PubSub" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Scegliere se approvare l'iscrizione per questa entità" + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "ID del nodo" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Indirizzo dell'iscritta/o" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Consentire a questo JID l'iscrizione a questo nodo pubsub?" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Inviare il contenuto del messaggio con la notifica dell'evento" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Inviare notifiche degli eventi" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Notificare gli iscritti quando la configurazione del nodo cambia" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Notificare gli iscritti quando il nodo è cancellato" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Notificare gli iscritti quando sono eliminati degli elementi dal nodo" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Conservazione persistente degli elementi" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "Un nome comodo per il nodo" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Numero massimo di elementi da conservare persistentemente" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Consentire iscrizioni?" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Specificare il modello di accesso" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Gruppi roster abilitati alla registrazione" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Definire il modello di pubblicazione" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Dimensione massima del contenuto del messaggio in byte" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Quando inviare l'ultimo elemento pubblicato" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Inviare le notifiche solamente agli utenti disponibili" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "" +"Scegliere un nome utente e una password per la registrazione con questo " +"server" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "Non è consentito agli utenti registrare account così rapidamente" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Nessuno" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Iscrizione" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Pendente" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Gruppi" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Validare" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Eliminare" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Lista dei contatti di " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Formato non valido" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Aggiungere un Jabber ID (JID)" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Lista dei contatti" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Gruppi di liste di contatti comuni" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Aggiungere nuovo" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Nome:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Descrizione:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Membri:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Gruppi visualizzati:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Gruppo " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Inviare" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Erlang Jabber Server" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Compleanno" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Città" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "Paese" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "E-mail" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Cognome" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Riempire il modulo per la ricerca di utenti Jabber corrispondenti ai criteri " +"(Aggiungere * alla fine del campo per la ricerca di una sottostringa" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Nome completo" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Altro nome" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Nome" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Nome dell'organizzazione" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Unità dell'organizzazione" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Cercare utenti in " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Utente" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "Per effettuare ricerche è necessario un client che supporti x:data" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "Ricerca di utenti per vCard" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "Modulo vCard per ejabberd" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Risultati della ricerca per " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "" +"Riempire i campi per la ricerca di utenti Jabber corrispondenti ai criteri" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "Amministrazione web ejabberd" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Amministrazione" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Host virtuali" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Nodi" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Statistiche" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Utenti" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Ultima attività" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Grezzo)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Grezzo" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "Configurazione delle regole di accesso per ~s" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "Host virtuali di ejabberd" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Ultima attività degli utenti" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Periodo:" + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Ultimo mese" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Ultimo anno" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Tutta l'attività" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Mostrare la tabella normale" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Mostrare la tabella integrale" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Nodo non trovato" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Host" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Utenti registrati" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Messaggi offline" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Utenti registrati:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Utenti connessi:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Connessioni s2s in uscita:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Server s2s in uscita" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Modificare la password" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Utente " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Risorse connesse:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Password:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Nessuna informazione" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Nodo " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Porte in ascolto" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Aggiornare" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Riavviare" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Arrestare" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "Errore di chiamata RPC" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Tabelle del database su " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Tipo di conservazione" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Dimensione" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Memoria" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Salvataggio di " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"N.B.: Queste opzioni comportano il salvataggio solamente del database " +"interno Mnesia. Se si sta utilizzando il modulo ODBC, è necessario salvare " +"il proprio database SQL separatamente." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Conservare un salvataggio binario:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "OK" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Recuperare un salvataggio binario adesso:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"Recuperare un salvataggio binario dopo il prossimo riavvio di ejabberd " +"(necessita di meno memoria):" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Conservare un salvataggio come semplice testo:" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Recuperare un salvataggio come semplice testo adesso:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Porte in ascolto su " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Moduli su " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "Statistiche di ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Tempo dall'avvio:" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "Tempo CPU:" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Transazioni avvenute:" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Transazioni abortite:" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Transazioni riavviate:" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Transazioni con log:" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Aggiornare " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Piano di aggiornamento" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Moduli aggiornati" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Script di aggiornamento" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Script di aggiornamento di basso livello" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Verifica dello script" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Porta" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Modulo" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Opzioni" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Eliminare" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Avviare" diff --git a/src/msgs/ja.msg b/src/msgs/ja.msg index 0f1189054..08de9b203 100644 --- a/src/msgs/ja.msg +++ b/src/msgs/ja.msg @@ -1,375 +1,343 @@ -% $Id$ -% Language: Japanese (日本語) -% Author: Tsukasa Hamano - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "宛先のオフラインメッセージキューが一杯です。このメッセージは破棄されます。"}. -{"~s's Offline Messages Queue", "~s's オフラインメッセージキュー"}. -{"Submitted", "送信完了"}. -{"Packet", "パケット"}. -{"Delete Selected", "選択した項目を削除"}. -{"Offline Messages:", "オフラインメッセージ"}. - -% mod_vcard_ldap.erl -{"Erlang Jabber Server", "Erlang Jabber Server"}. -{"You need an x:data capable client to search", "検索を行うためにはクライアントが x:data をサポートする必要があります"}. -{"Search users in ", "ユーザーの検索: "}. -{"Fill in fields to search for any matching Jabber User", "項目を埋めて Jabber User を検索して下さい"}. -{"vCard User Search", "vCard ユーザー検索"}. -{"ejabberd vCard module", "ejabberd vCard module"}. -{"Search Results for ", "検索結果: "}. -{"Jabber ID", "Jabber ID"}. - -% mod_vcard.erl -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "フォームを埋めて Jabber User を検索して下さい(* を使用すると部分文字列にマッチします)"}. -{"User", "ユーザー"}. -{"Full Name", "氏名"}. -{"Name", "名"}. -{"Middle Name", "ミドルネーム"}. -{"Family Name", "姓"}. -{"Nickname", "ニックネーム"}. -{"Birthday", "誕生日"}. -{"Country", "国"}. -{"City", "都道府県"}. -{"Email", "メールアドレス"}. -{"Organization Name", "会社名"}. -{"Organization Unit", "部署名"}. - -% mod_configure.erl -{"Action on user", "ユーザー操作"}. -{"Configuration", "設定"}. -{"Database", "データーベース"}. -{"Start Modules", "モジュールの起動"}. -{"Stop Modules", "モジュールの停止"}. -{"Backup", "バックアップ"}. -{"Restore", "リストア"}. -{"Dump to Text File", "テキストファイルに出力"}. -{"Import File", "ファイルかインポート"}. -{"Import Directory", "ディレクトリインポート"}. -{"Restart Service", "サービスを再起動"}. -{"Shut Down Service", "サービスを停止"}. -{"Add User", "ユーザーを追加"}. -{"Delete User", "ユーザを削除"}. -{"End User Session", "エンドユーザーセッション"}. -{"Get User Password", "パスワードを取得"}. -{"Change User Password", "パスワードを変更"}. -{"Get User Last Login Time", "最終ログイン時間の取得"}. -{"Get User Statistics", "ユーザー統計の取得"}. -{"Get Number of Registered Users", "登録ユーザー数を取得"}. -{"Get Number of Online Users", "登録ユーザーを取得"}. -{"Access Control Lists", "アクセスコントロールリスト"}. -{"Access Rules", "アクセスルール"}. -{"User Management", "ユーザー管理"}. -{"Online Users", "オンラインユーザー"}. -{"All Users", "全ユーザー"}. -{"Outgoing s2s Connections", "外向き s2s コネクション"}. -{"Running Nodes", "起動ノード"}. -{"Stopped Nodes", "停止ノード"}. -{"Modules", "モジュール"}. -{"Backup Management", "バックアップ管理"}. -{"Import Users From jabberd 1.4 Spool Files", "jabberd 1.4 Spool ファイルからユーザーをインポート"}. -{"To ~s", "宛先 ~s"}. -{"From ~s", "差出人 ~s"}. -{"Database Tables Configuration at ", "データーベーステーブル設定 "}. -{"Choose storage type of tables", "テーブルのストレージタイプの選択"}. -{"RAM copy", "RAMコピー"}. -{"RAM and disc copy", "RAM, ディスクコピー"}. -{"Disc only copy", "ディスクだけのコピー"}. -{"Remote copy", "リモートコピー"}. -{"Stop Modules at ", "モジュールの停止 "}. -{"Choose modules to stop", "停止するモジュールの選択"}. -{"Start Modules at ", "モジュールの開始"}. -{"Enter list of {Module, [Options]}", "{モジュール, [オプション]}のリストを入力して下さい"}. -{"List of modules to start", "起動モジュールの一覧"}. -{"Backup to File at ", "ファイルにバックアップ"}. -{"Enter path to backup file", "バックアップファイルのパスを入力して下さい"}. -{"Path to File", "ファイルパス"}. -{"Restore Backup from File at ", "ファイルからバックアップをリストア"}. -{"Dump Backup to Text File at ", "テキストファイルにバックアップ"}. -{"Enter path to text file", "テキストファイルのパスを入力して下さい"}. -{"Import User from File at ", "ファイルからユーザーをインポート"}. -{"Enter path to jabberd1.4 spool file", "jabberd1.4 spool ファイルのパスを入力して下さい"}. -{"Import Users from Dir at ", "ディレクトリからユーザーをインポート"}. -{"Enter path to jabberd1.4 spool dir", "jabberd1.4 spool ディレクトリのパスを入力して下さい"}. -{"Path to Dir", "ディレクトリのパス"}. -{"Time delay", "遅延時間"}. -{"Send announcement to all online users on all hosts", "全ホストのオンラインユーザへアナウンスを送信"}. -{"Subject", "件名"}. -{"Message body", "本文"}. -{"Access Control List Configuration", "アクセスコントロールリスト設定"}. -{"Access control lists", "アクセスコントロールリスト"}. -{"Access Configuration", "アクセス設定"}. -{"Access rules", "アクセスルール"}. -{"Password", "パスワード"}. -{"Password Verification", "パスワード(確認)"}. -{"Number of registered users", "登録ユーザー数"}. -{"Number of online users", "オンラインユーザー数"}. -{"Never", "無し"}. -{"Online", "オンライン"}. -{"Last login", "最終ログイン"}. -{"Roster size", "名簿サイズ"}. -{"IP addresses", "IPアドレス"}. -{"Resources", "リソース"}. -{"Administration of ", "管理: "}. -{"Edit Properties", "プロパティの編集"}. -{"Remove User", "ユーザーの削除"}. - -% mod_roster_odbc.erl -{"None", "無し"}. -{"Subscription", "認可"}. -{"Pending", "保留"}. -{"Groups", "グループ"}. -{"Validate", "検証"}. -{"Remove", "削除"}. -{"Roster of ", "名簿: "}. -{"Bad format", "不正なフォーマット"}. -{"Add Jabber ID", "Jabber ID の追加"}. -{"Roster", "名簿"}. - -% mod_offline.erl -{"Time", "時間"}. -{"From", "差出人"}. -{"To", "宛先"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "サーバーに登録するユーザー名とパスワードを選択して下さい"}. - -% ejabberd_c2s.erl -{"Replaced by new connection", "新しいコネクションによって置き換えられました"}. -{"Use of STARTTLS required", "STARTTLS を使用"}. -{"No resource provided", "リソースが提供されませんでした"}. - -% mod_muc/mod_muc_log.erl -{"Chatroom configuration modified", "チャットルームの設定を変更しました"}. -{"joins the room", "チャットルームに参加"}. -{"leaves the room", "チャットルームから退出"}. -{"has been kicked", "はキックされました"}. -{"has been banned", "はバンされました"}. -{" has set the subject to: ", " は件名を設定しました: "}. -{"Monday", "月曜日"}. -{"Tuesday", "火曜日"}. -{"Wednesday", "水曜日"}. -{"Thursday", "木曜日"}. -{"Friday", "金曜日"}. -{"Saturday", "土曜日"}. -{"Sunday", "日曜日"}. -{"January", "1月"}. -{"February", "2月"}. -{"March", "3月"}. -{"April", "4月"}. -{"May", "5月"}. -{"June", "6月"}. -{"July", "7月"}. -{"August", "8月"}. -{"September", "9月"}. -{"October", "10月"}. -{"November", "11月"}. -{"December", "12月"}. -{"Room Configuration", "チャットルーム設定"}. -{"Room title", "チャットルームタイトル"}. -{"is now known as", "は名前を変更しました: "}. - -% mod_muc/mod_muc.erl -{"Access denied by service policy", "サービスポリシーによってアクセスが禁止されました"}. -{"Only service administrators are allowed to send service messages", "カービス管理者のみがサービスメッセージを送信出来ます"}. -{"Room creation is denied by service policy", "サービスポリシーにっよってチャットルームの作成が禁止されています"}. -{"Conference room does not exist", "カンファレンスルームは存在しません"}. -{"Chatrooms", "チャットルーム"}. -{"You need an x:data capable client to register nickname", "ニックネームを登録するにはクライアントが x:data をサポートする必要があります"}. -{"Nickname Registration at ", "ニックネーム登録: "}. -{"Enter nickname you want to register", "登録するニックネームを入力して下さい"}. -{"Specified nickname is already registered", "指定されたニックネームは既に登録されています"}. -{"You must fill in field \"Nickname\" in the form", "フォームの\"ニックネーム\"フィールドを入力する必要があります"}. -{"ejabberd MUC module", "ejabberd MUC module"}. - -% mod_muc/mod_muc_room.erl -{"It is not allowed to send private messages of type \"groupchat\"", "種別が\"groupchat\" であるプライベートメッセージは許可されていません"}. -{"Invalid affiliation: ~s", "無効な提携です: ~s"}. -{"Invalid role: ~s", "無効なロールです: ~s"}. -{"Owner privileges required", "オーナー権限が必要です"}. -{"Configuration for ", "設定: "}. -{"Make room persistent", "チャットルームを永続化します"}. -{"Make room public searchable", "チャットルームを検索可能にします"}. -{"Make participants list public", "参加者一覧を公開します"}. -{"Make room password protected", "チャットルームにパスワードを設定します"}. -{"Maximum Number of Occupants", "最大移住者数"}. -{"No limit", "制限無し"}. -{"Present real JIDs to", "本当の JID を公開する"}. -{"moderators only", "モデレーターのみ"}. -{"anyone", "誰でも"}. -{"Make room members-only", "チャットルームをメンバーのみに制限する"}. -{"Default users as participants", "デフォルトのユーザーは参加者にする"}. -{"Allow users to change subject", "ユーザーによる件名の変更を許可する"}. -{"Allow users to send private messages", "ユーザーによるプライベートメッセージの送信を許可する"}. -{"Allow users to query other users", "ユーザーによる他のユーザーへの問い合わせを許可する"}. -{"Allow users to send invites", "ユーザーによる招待を許可する"}. -{"Enable logging", "ロギングを有効にする"}. -{"Number of occupants", "居住者の数"}. -{"~s invites you to the room ~s", "~s はあなたをチャットルーム ~s に招待しています"}. -{"the password is", "パスワードは"}. -{"Traffic rate limit is exceeded", "トラフィックレートの制限を超えました"}. -{"It is not allowed to send private messages to the conference", "カンファレンスルームにプライベートメッセージを送信することは出来ません"}. -{"Improper message type", "誤ったメッセージタイプです"}. -{"Only occupants are allowed to send messages to the conference", "移住者のみがカンファレンスに"}. -{"Recipient is not in the conference room", "受信者がカンファレンスルームに居ません"}. -{"Only occupants are allowed to send queries to the conference", "移住者のみがカンファレンスにクエリーを送信出来ます"}. -{"Queries to the conference members are not allowed in this room", "このチャットルームではカンファレンスメンバーへのクエリーは禁止されています"}. -{"private, ", "プライベート"}. -{"Only moderators and participants are allowed to change subject in this room", "モデレーターと参加者のみがチャットルームの件名を変更出来ます"}. -{"Only moderators are allowed to change subject in this room", "モデレーターのみがチャットルームの件名を変更出来ます"}. -{"Visitors are not allowed to send messages to all occupants", "ビジターが移住者ににメッセージを送ることは許可されていません"}. -{"Nickname is already in use by another occupant", "ニックネームは既に他の移住者によって使用されています"}. -{"Nickname is registered by another person", "ニックネームは他の人によって登録されています"}. -{"You have been banned from this room", "あなたはチャットルームからバンされています"}. -{"Membership required to enter this room", "チャットルームに入るにはメンバーでなければなりません"}. -{"This room is not anonymous", "このチャットルームは非匿名です"}. -{"Password required to enter this room", "チャットルームに入るにはパスワードが必要です"}. -{"Incorrect password", "パスワードが違います"}. -{"Administrator privileges required", "管理者権限が必要です"}. -{"Moderator privileges required", "モデレーター権限が必要です"}. -{"JID ~s is invalid", "JID ~s は無効です"}. -{"Nickname ~s does not exist in the room", "ニックネーム ~s はこのチャットルームに居ません"}. -{"You need an x:data capable client to configure room", "チャットルームを設定するにはにはクライアントが x:data をサポートする必要があります"}. - -% mod_irc/mod_irc.erl -{"Registration in mod_irc for ", "mod_irc での登録: "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "IRCサーバーに接続先する為のユーザー名と文字エンコーディングを入力して下さい"}. -{"IRC Username", "IRCユーザー名"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "別の文字エンコーディングを使用したい場合、'{\"irc server\", \"encoding\"}' という形式のリストを入力して下さい。デフォルトで \"~s\" を使用します"}. -{"IRC Transport", "IRC トランスポート"}. -{"ejabberd IRC module", "ejabberd IRC module"}. -{"You need an x:data capable client to configure mod_irc settings", "mod_irc の設定にはクライアントが x:data をサポートする必要があります"}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "例: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"Encodings", "エンコーディング"}. - -% mod_adhoc.erl -{"Commands", "コマンド"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% mod_announce.erl -{"Really delete message of the day?", "本当にお知らせメッセージを削除しますか?"}. -{"No body provided for announce message", "アナウンスメッセージはありませんでした"}. -{"Announcements", "アナウンス"}. -{"Set message of the day and send to online users", "お知らせメッセージを設定し、オンラインユーザーに送信する"}. -{"Set message of the day on all hosts and send to online users", "全ホストのお知らせメッセージを設定し、オンラインユーザーに送信する"}. -{"Update message of the day (don't send)", "お知らせメッセージを更新する(送信しない)"}. -{"Update message of the day on all hosts (don't send)", "全ホストのお知らせメッセージを更新する"}. -{"Delete message of the day", "お知らせメッセージを削除する"}. -{"Delete message of the day on all hosts", "全ホストのお知らせメッセージを削除する"}. -{"Send announcement to all users", "アナウンスを全てのユーザーに送信"}. -{"Send announcement to all users on all hosts", "アナウンスを全ホストのユーザーに送信"}. -{"Send announcement to all online users", "アナウンスを全てのオンラインユーザーに送信"}. - -% mod_shared_roster.erl -{"Add New", "新規追加"}. -{"Shared Roster Groups", "共有名簿グループ"}. -{"Name:", "名前: "}. -{"Description:", "詳細:"}. -{"Members:", "メンバー:"}. -{"Displayed Groups:", "表示グループ"}. -{"Group ", "グループ"}. -{"Submit", "送信"}. - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "ejabberd SOCKS5 Bytestreams module"}. - -% mod_pubsub/mod_pubsub.erl -{"Publish-Subscribe", "Publish-Subscribe"}. -{"ejabberd Publish-Subscribe module", "ejabberd Publish-Subscribe module"}. -{"PubSub subscriber request", "PubSub 購読リクエスト"}. -{"Choose whether to approve this entity's subscription.", "このエントリを承認するかどうかを選択して下さい"}. -{"Node ID", "ノードID"}. -{"Subscriber Address", "購読アドレス"}. -{"Allow this JID to subscribe to this pubsub node?", "この JID をこの pubsubノードへ購読することを許可しますか?"}. -{"Deliver payloads with event notifications", "イベント通知と同時にペイロードを配送します"}. -{"Deliver event notifications", "イベント通知を配送します"}. -{"Notify subscribers when the node configuration changes", "ノード設定に変更があった時に購読者へ通知します"}. -{"Notify subscribers when the node is deleted", "ノードが削除された時に購読者へ通知します"}. -{"Notify subscribers when items are removed from the node", "アイテムがノードから消された時に購読者へ通知します"}. -{"Persist items to storage", "アイテムをストレージに保存する"}. -{"Max # of items to persist", "アイテムの最大保存数 #"}. -{"Whether to allow subscriptions", "購読を許可するかどうか"}. -{"Specify the access model", "アクセスモデルを設定する"}. -{"Roster groups that may subscribe (if access model is roster)", "購読可能な名簿グループ(アクセスモデルが名簿であれば)"}. -{"Specify the publisher model", "公開モデルを指定する"}. -{"Max payload size in bytes", "最大ぺイロードサイズ(byte)"}. -{"When to send the last published item", "最後の公開アイテムを送信するタイミングで"}. -{"Only deliver notifications to available users", "有効なユーザーにのみ告知を送信する"}. - -% web/ejabberd_web_admin.erl -{"All activity", "全て"}. -{"Show Ordinary Table", "Ordinaryテーブルを表示"}. -{"Show Integral Table", "Integralテーブルを表示"}. -{"ejabberd Web Interface", "ejabberd WEBインターフェイス"}. -{"Administration", "管理"}. -{"Virtual Hosts", "ヴァーチャルホスト"}. -{"Nodes", "ノード"}. -{"Statistics", "統計"}. -{"ejabberd (c) 2002-2008 Alexey Shchepin, 2004-2008 Process One", "ejabberd (c) 2002-2008 Alexey Shchepin, 2004-2008 Process One"}. -{"Users", "ユーザー"}. -{"Last Activity", "活動履歴"}. -{"(Raw)", "(Raw)"}. -{"Raw", "Raw"}. -{"~s access rule configuration", "~s アクセスルール設定"}. -{"ejabberd virtual hosts", "ejabberd ヴァーチャルホスト"}. -{"Users Last Activity", "ユーザーの活動履歴"}. -{"Period: ", "期間: "}. -{"Last month", "先月"}. -{"Last year", "去年"}. -{"Node not found", "ノードが見つかりません"}. -{"Host", "ホスト"}. -{"Registered Users", "登録ユーザー"}. -{"Offline Messages", "オフラインメッセージ"}. -{"Registered Users:", "登録ユーザー:"}. -{"Online Users:", "オンラインユーザー:"}. -{"Outgoing s2s Connections:", "外向き s2s コネクション:"}. -{"Outgoing s2s Servers:", "外向き s2s サービス:"}. -{"Change Password", "パスワードの変更"}. -{"User ", "ユーザー "}. -{"Connected Resources:", "接続リソース:"}. -{"Password:", "パスワード"}. -{"No Data", "データ無し"}. -{"Node ", "ノード"}. -{"Listened Ports", "Listenポート"}. -{"Update", "更新"}. -{"Restart", "再起動"}. -{"Stop", "停止"}. -{"RPC Call Error", "RPC 呼び出しエラー"}. -{"Database Tables at ", "データーベーステーブル: "}. -{"Storage Type", "ストレージタイプ"}. -{"Size", "サイズ"}. -{"Memory", "メモリ"}. -{"Backup of ", "バックアップ: "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "これらのオプションは組み込みの Mnesiaデーターベースをバックアップのみを行うことに注意して下さい。もしも ODBCモジュールを使用している場合は SQLデーターベースのバックアップを別に行う必要があります。"}. -{"Store binary backup:", "バイナリバックアップの保存"}. -{"OK", "OK"}. -{"Restore binary backup immediately:", "直ちにバイナリバックアップからリストア"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "ejabberd の再起動時にバイナリバックアップからリストア"}. -{"Store plain text backup:", "プレーンテキストバックアップの保存"}. -{"Restore plain text backup immediately:", "直ちにプレーンテキストバックアップからリストア"}. -{"Listened Ports at ", "Listen ポート: "}. -{"Modules at ", "モジュール: "}. -{"Statistics of ~p", "~p の統計"}. -{"Uptime:", "起動時間"}. -{"CPU Time:", "CPU時間:"}. -{"Transactions Commited:", "トランザクションのコミット:"}. -{"Transactions Aborted:", "トランザクションの失敗:"}. -{"Transactions Restarted:", "トランザクションの再起動:"}. -{"Transactions Logged:", "トランザクションのログ: "}. -{"Update ", "更新 "}. -{"Update plan", "更新計画"}. -{"Updated modules", "モジュールを更新しました"}. -{"Update script", "スクリプトの更新"}. -{"Low level update script", "低レベル更新スクリプト"}. -{"Script check", "スクリプトチェック"}. -{"Port", "ポート"}. -{"Module", "モジュール"}. -{"Options", "オプション"}. -{"Delete", "削除"}. -{"Start", "開始"}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","アクセス設定"}. +{"Access Control List Configuration","アクセスコントロールリスト設定"}. +{"Access control lists","アクセスコントロールリスト"}. +{"Access Control Lists","アクセスコントロールリスト"}. +{"Access denied by service policy","サービスポリシーによってアクセスが禁止されました"}. +{"Access rules","アクセスルール"}. +{"Access Rules","アクセスルール"}. +{"Action on user","ユーザー操作"}. +{"Add Jabber ID","Jabber ID の追加"}. +{"Add New","新規追加"}. +{"Add User","ユーザーを追加"}. +{"Administration of ","管理: "}. +{"Administration","管理"}. +{"Administrator privileges required","管理者権限が必要です"}. +{"A friendly name for the node","ノードの為のフレンドリネーム"}. +{"All activity","全て"}. +{"Allow this JID to subscribe to this pubsub node?","この JID をこの pubsubノードへ購読することを許可しますか?"}. +{"Allow users to change subject","ユーザーによる件名の変更を許可する"}. +{"Allow users to query other users","ユーザーによる他のユーザーへの問い合わせを許可する"}. +{"Allow users to send invites","ユーザーによる招待を許可する"}. +{"Allow users to send private messages","ユーザーによるプライベートメッセージの送信を許可する"}. +{"Allow visitors to change nickname","ビジターがニックネームを変更する事を許可します"}. +{"Allow visitors to send status text in presence updates","ビジターがプレゼンス更新のステータス文を送信する事を許可する"}. +{"All Users","全ユーザー"}. +{"Announcements","アナウンス"}. +{"anyone","誰でも"}. +{"April","4月"}. +{"August","8月"}. +{"Backup","バックアップ"}. +{"Backup Management","バックアップ管理"}. +{"Backup of ","バックアップ: "}. +{"Backup to File at ","ファイルにバックアップ"}. +{"Bad format","不正なフォーマット"}. +{"Birthday","誕生日"}. +{"Change Password","パスワードの変更"}. +{"Change User Password","パスワードを変更"}. +{"Chatroom configuration modified","チャットルームの設定を変更しました"}. +{"Chatrooms","チャットルーム"}. +{"Choose a username and password to register with this server","サーバーに登録するユーザー名とパスワードを選択して下さい"}. +{"Choose modules to stop","停止するモジュールの選択"}. +{"Choose storage type of tables","テーブルのストレージタイプの選択"}. +{"Choose whether to approve this entity's subscription.","このエントリを承認するかどうかを選択して下さい"}. +{"City","都道府県"}. +{"Commands","コマンド"}. +{"Conference room does not exist","カンファレンスルームは存在しません"}. +{"Configuration for ","設定: "}. +{"Configuration","設定"}. +{"Connected Resources:","接続リソース:"}. +{"Country","国"}. +{"CPU Time:","CPU時間:"}. +{"Database","データーベース"}. +{"Database Tables at ","データーベーステーブル: "}. +{"Database Tables Configuration at ","データーベーステーブル設定 "}. +{"December","12月"}. +{"Default users as participants","デフォルトのユーザーは参加者にする"}. +{"Delete message of the day on all hosts","全ホストのお知らせメッセージを削除する"}. +{"Delete message of the day","お知らせメッセージを削除する"}. +{"Delete Selected","選択した項目を削除"}. +{"Delete User","ユーザを削除"}. +{"Delete","削除"}. +{"Deliver event notifications","イベント通知を配送します"}. +{"Deliver payloads with event notifications","イベント通知と同時にペイロードを配送します"}. +{"Description:","詳細:"}. +{"Disc only copy","ディスクだけのコピー"}. +{"Displayed Groups:","表示グループ"}. +{"Dump Backup to Text File at ","テキストファイルにバックアップ"}. +{"Dump to Text File","テキストファイルに出力"}. +{"Edit Properties","プロパティの編集"}. +{"ejabberd IRC module","ejabberd IRC module"}. +{"ejabberd MUC module","ejabberd MUC module"}. +{"ejabberd Publish-Subscribe module","ejabberd Publish-Subscribe module"}. +{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestreams module"}. +{"ejabberd vCard module","ejabberd vCard module"}. +{"ejabberd virtual hosts","ejabberd ヴァーチャルホスト"}. +{"ejabberd Web Admin","ejabberd Web 管理"}. +{"Email","メールアドレス"}. +{"Enable logging","ロギングを有効にする"}. +{"Encodings","エンコーディング"}. +{"End User Session","エンドユーザーセッション"}. +{"Enter list of {Module, [Options]}","{モジュール, [オプション]}のリストを入力して下さい"}. +{"Enter nickname you want to register","登録するニックネームを入力して下さい"}. +{"Enter path to backup file","バックアップファイルのパスを入力して下さい"}. +{"Enter path to jabberd1.4 spool dir","jabberd1.4 spool ディレクトリのパスを入力して下さい"}. +{"Enter path to jabberd1.4 spool file","jabberd1.4 spool ファイルのパスを入力して下さい"}. +{"Enter path to text file","テキストファイルのパスを入力して下さい"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","IRCサーバーに接続先する為のユーザー名と文字エンコーディングを入力して下さい"}. +{"Erlang Jabber Server","Erlang Jabber Server"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","例: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","姓"}. +{"February","2月"}. +{"Fill in fields to search for any matching Jabber User","項目を埋めて Jabber User を検索して下さい"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","フォームを埋めて Jabber User を検索して下さい(* を使用すると部分文字列にマッチします)"}. +{"Friday","金曜日"}. +{"From ~s","差出人 ~s"}. +{"From","差出人"}. +{"Full Name","氏名"}. +{"Get Number of Online Users","登録ユーザーを取得"}. +{"Get Number of Registered Users","登録ユーザー数を取得"}. +{"Get User Last Login Time","最終ログイン時間の取得"}. +{"Get User Password","パスワードを取得"}. +{"Get User Statistics","ユーザー統計の取得"}. +{"Group ","グループ"}. +{"Groups","グループ"}. +{"has been banned","はバンされました"}. +{"has been kicked","はキックされました"}. +{"has been kicked because of an affiliation change","は提携が変更されたためキックされました"}. +{"has been kicked because of a system shutdown","はシステムシャットダウンのためキックされました"}. +{"has been kicked because the room has been changed to members-only","はチャットルームのメンバー制限によりキックされました"}. +{" has set the subject to: "," は件名を設定しました: "}. +{"Host","ホスト"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","別の文字エンコーディングを使用したい場合、'{\"irc server\", \"encoding\"}' という形式のリストを入力して下さい。デフォルトで \"~s\" を使用します"}. +{"Import Directory","ディレクトリインポート"}. +{"Import File","ファイルかインポート"}. +{"Import User from File at ","ファイルからユーザーをインポート"}. +{"Import Users from Dir at ","ディレクトリからユーザーをインポート"}. +{"Import Users From jabberd 1.4 Spool Files","jabberd 1.4 Spool ファイルからユーザーをインポート"}. +{"Improper message type","誤ったメッセージタイプです"}. +{"Incorrect password","パスワードが違います"}. +{"Invalid affiliation: ~s","無効な提携です: ~s"}. +{"Invalid role: ~s","無効なロールです: ~s"}. +{"IP addresses","IPアドレス"}. +{"IRC Transport","IRC トランスポート"}. +{"IRC Username","IRCユーザー名"}. +{"is now known as","は名前を変更しました: "}. +{"It is not allowed to send private messages of type \"groupchat\"","種別が\"groupchat\" であるプライベートメッセージは許可されていません"}. +{"It is not allowed to send private messages to the conference","カンファレンスルームにプライベートメッセージを送信することは出来ません"}. +{"It is not allowed to send private messages","プライベートメッセージを送信することは許可されませんでした"}. +{"Jabber ID","Jabber ID"}. +{"January","1月"}. +{"JID ~s is invalid","JID ~s は無効です"}. +{"joins the room","チャットルームに参加"}. +{"July","7月"}. +{"June","6月"}. +{"Last Activity","活動履歴"}. +{"Last login","最終ログイン"}. +{"Last month","先月"}. +{"Last year","去年"}. +{"leaves the room","チャットルームから退出"}. +{"Listened Ports at ","Listen ポート: "}. +{"Listened Ports","Listenポート"}. +{"List of modules to start","起動モジュールの一覧"}. +{"Low level update script","低レベル更新スクリプト"}. +{"Make participants list public","参加者一覧を公開します"}. +{"Make room members-only","チャットルームをメンバーのみに制限する"}. +{"Make room moderated","チャットルームをモデレートする"}. +{"Make room password protected","チャットルームにパスワードを設定します"}. +{"Make room persistent","チャットルームを永続化します"}. +{"Make room public searchable","チャットルームを検索可能にします"}. +{"March","3月"}. +{"Maximum Number of Occupants","最大移住者数"}. +{"Max # of items to persist","アイテムの最大保存数 #"}. +{"Max payload size in bytes","最大ぺイロードサイズ(byte)"}. +{"May","5月"}. +{"Members:","メンバー:"}. +{"Membership required to enter this room","チャットルームに入るにはメンバーでなければなりません"}. +{"Memory","メモリ"}. +{"Message body","本文"}. +{"Middle Name","ミドルネーム"}. +{"Moderator privileges required","モデレーター権限が必要です"}. +{"moderators only","モデレーターのみ"}. +{"Module","モジュール"}. +{"Modules","モジュール"}. +{"Modules at ","モジュール: "}. +{"Monday","月曜日"}. +{"Name","名"}. +{"Name:","名前: "}. +{"Never","無し"}. +{"Nickname","ニックネーム"}. +{"Nickname is already in use by another occupant","ニックネームは既に他の移住者によって使用されています"}. +{"Nickname is registered by another person","ニックネームは他の人によって登録されています"}. +{"Nickname Registration at ","ニックネーム登録: "}. +{"Nickname ~s does not exist in the room","ニックネーム ~s はこのチャットルームに居ません"}. +{"No body provided for announce message","アナウンスメッセージはありませんでした"}. +{"No Data","データ無し"}. +{"Node ","ノード"}. +{"Node ID","ノードID"}. +{"Node not found","ノードが見つかりません"}. +{"Nodes","ノード"}. +{"No limit","制限無し"}. +{"None","無し"}. +{"No resource provided","リソースが提供されませんでした"}. +{"Notify subscribers when items are removed from the node","アイテムがノードから消された時に購読者へ通知します"}. +{"Notify subscribers when the node configuration changes","ノード設定に変更があった時に購読者へ通知します"}. +{"Notify subscribers when the node is deleted","ノードが削除された時に購読者へ通知します"}. +{"November","11月"}. +{"Number of occupants","居住者の数"}. +{"Number of online users","オンラインユーザー数"}. +{"Number of registered users","登録ユーザー数"}. +{"October","10月"}. +{"Offline Messages:","オフラインメッセージ"}. +{"Offline Messages","オフラインメッセージ"}. +{"OK","OK"}. +{"Online","オンライン"}. +{"Online Users:","オンラインユーザー:"}. +{"Online Users","オンラインユーザー"}. +{"Only deliver notifications to available users","有効なユーザーにのみ告知を送信する"}. +{"Only moderators and participants are allowed to change subject in this room","モデレーターと参加者のみがチャットルームの件名を変更出来ます"}. +{"Only moderators are allowed to change subject in this room","モデレーターのみがチャットルームの件名を変更出来ます"}. +{"Only occupants are allowed to send messages to the conference","移住者のみがカンファレンスに"}. +{"Only occupants are allowed to send queries to the conference","移住者のみがカンファレンスにクエリーを送信出来ます"}. +{"Only service administrators are allowed to send service messages","カービス管理者のみがサービスメッセージを送信出来ます"}. +{"Options","オプション"}. +{"Organization Name","会社名"}. +{"Organization Unit","部署名"}. +{"Outgoing s2s Connections:","外向き s2s コネクション:"}. +{"Outgoing s2s Connections","外向き s2s コネクション"}. +{"Outgoing s2s Servers:","外向き s2s サービス:"}. +{"Owner privileges required","オーナー権限が必要です"}. +{"Packet","パケット"}. +{"Password:","パスワード"}. +{"Password","パスワード"}. +{"Password required to enter this room","チャットルームに入るにはパスワードが必要です"}. +{"Password Verification","パスワード(確認)"}. +{"Path to Dir","ディレクトリのパス"}. +{"Path to File","ファイルパス"}. +{"Pending","保留"}. +{"Period: ","期間: "}. +{"Persist items to storage","アイテムをストレージに保存する"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","ポート"}. +{"Present real JIDs to","本当の JID を公開する"}. +{"private, ","プライベート"}. +{"Publish-Subscribe","Publish-Subscribe"}. +{"PubSub subscriber request","PubSub 購読リクエスト"}. +{"Queries to the conference members are not allowed in this room","このチャットルームではカンファレンスメンバーへのクエリーは禁止されています"}. +{"RAM and disc copy","RAM, ディスクコピー"}. +{"RAM copy","RAMコピー"}. +{"(Raw)","(Raw)"}. +{"Raw","Raw"}. +{"Really delete message of the day?","本当にお知らせメッセージを削除しますか?"}. +{"Recipient is not in the conference room","受信者がカンファレンスルームに居ません"}. +{"Registered Users:","登録ユーザー:"}. +{"Registered Users","登録ユーザー"}. +{"Registration in mod_irc for ","mod_irc での登録: "}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","これらのオプションは組み込みの Mnesiaデーターベースをバックアップのみを行うことに注意して下さい。もしも ODBCモジュールを使用している場合は SQLデーターベースのバックアップを別に行う必要があります。"}. +{"Remote copy","リモートコピー"}. +{"Remove User","ユーザーの削除"}. +{"Remove","削除"}. +{"Replaced by new connection","新しいコネクションによって置き換えられました"}. +{"Resources","リソース"}. +{"Restart Service","サービスを再起動"}. +{"Restart","再起動"}. +{"Restore","リストア"}. +{"Restore Backup from File at ","ファイルからバックアップをリストア"}. +{"Restore binary backup after next ejabberd restart (requires less memory):","ejabberd の再起動時にバイナリバックアップからリストア"}. +{"Restore binary backup immediately:","直ちにバイナリバックアップからリストア"}. +{"Restore plain text backup immediately:","直ちにプレーンテキストバックアップからリストア"}. +{"Room Configuration","チャットルーム設定"}. +{"Room creation is denied by service policy","サービスポリシーにっよってチャットルームの作成が禁止されています"}. +{"Room title","チャットルームタイトル"}. +{"Roster groups allowed to subscribe","名簿グループは購読を許可しました"}. +{"Roster of ","名簿: "}. +{"Roster size","名簿サイズ"}. +{"Roster","名簿"}. +{"RPC Call Error","RPC 呼び出しエラー"}. +{"Running Nodes","起動ノード"}. +{"~s access rule configuration","~s アクセスルール設定"}. +{"Saturday","土曜日"}. +{"Script check","スクリプトチェック"}. +{"Search Results for ","検索結果: "}. +{"Search users in ","ユーザーの検索: "}. +{"Send announcement to all online users on all hosts","全ホストのオンラインユーザへアナウンスを送信"}. +{"Send announcement to all online users","アナウンスを全てのオンラインユーザーに送信"}. +{"Send announcement to all users on all hosts","アナウンスを全ホストのユーザーに送信"}. +{"Send announcement to all users","アナウンスを全てのユーザーに送信"}. +{"September","9月"}. +{"Set message of the day and send to online users","お知らせメッセージを設定し、オンラインユーザーに送信する"}. +{"Set message of the day on all hosts and send to online users","全ホストのお知らせメッセージを設定し、オンラインユーザーに送信する"}. +{"Shared Roster Groups","共有名簿グループ"}. +{"Show Integral Table","Integralテーブルを表示"}. +{"Show Ordinary Table","Ordinaryテーブルを表示"}. +{"Shut Down Service","サービスを停止"}. +{"~s invites you to the room ~s","~s はあなたをチャットルーム ~s に招待しています"}. +{"Size","サイズ"}. +{"Specified nickname is already registered","指定されたニックネームは既に登録されています"}. +{"Specify the access model","アクセスモデルを設定する"}. +{"Specify the publisher model","公開モデルを指定する"}. +{"~s's Offline Messages Queue","~s's オフラインメッセージキュー"}. +{"Start Modules at ","モジュールの開始"}. +{"Start Modules","モジュールの起動"}. +{"Start","開始"}. +{"Statistics of ~p","~p の統計"}. +{"Statistics","統計"}. +{"Stop Modules at ","モジュールの停止 "}. +{"Stop Modules","モジュールの停止"}. +{"Stopped Nodes","停止ノード"}. +{"Stop","停止"}. +{"Storage Type","ストレージタイプ"}. +{"Store binary backup:","バイナリバックアップの保存"}. +{"Store plain text backup:","プレーンテキストバックアップの保存"}. +{"Subject","件名"}. +{"Submitted","送信完了"}. +{"Submit","送信"}. +{"Subscriber Address","購読アドレス"}. +{"Subscription","認可"}. +{"Sunday","日曜日"}. +{"the password is","パスワードは"}. +{"This participant is kicked from the room because he sent an error message to another participant","他の参加者にエラーメッセージを送信したため、この参加者はキックされました"}. +{"This participant is kicked from the room because he sent an error message","エラーメッセージを送信したため、この参加者はキックされました"}. +{"This participant is kicked from the room because he sent an error presence","エラープレゼンスを送信したため、この参加者はキックされました"}. +{"This room is not anonymous","このチャットルームは非匿名です"}. +{"Thursday","木曜日"}. +{"Time delay","遅延時間"}. +{"Time","時間"}. +{"To ~s","宛先 ~s"}. +{"To","宛先"}. +{"Traffic rate limit is exceeded","トラフィックレートの制限を超えました"}. +{"Transactions Aborted:","トランザクションの失敗:"}. +{"Transactions Commited:","トランザクションのコミット:"}. +{"Transactions Logged:","トランザクションのログ: "}. +{"Transactions Restarted:","トランザクションの再起動:"}. +{"Tuesday","火曜日"}. +{"Updated modules","モジュールを更新しました"}. +{"Update message of the day (don't send)","お知らせメッセージを更新する(送信しない)"}. +{"Update message of the day on all hosts (don't send)","全ホストのお知らせメッセージを更新する"}. +{"Update plan","更新計画"}. +{"Update script","スクリプトの更新"}. +{"Update ","更新 "}. +{"Update","更新"}. +{"Uptime:","起動時間"}. +{"Use of STARTTLS required","STARTTLS を使用"}. +{"User ","ユーザー "}. +{"User","ユーザー"}. +{"User Management","ユーザー管理"}. +{"Users","ユーザー"}. +{"Users are not allowed to register accounts so fast","早すぎるユーザーアカウント登録は許可されませんでした"}. +{"Users Last Activity","ユーザーの活動履歴"}. +{"Validate","検証"}. +{"vCard User Search","vCard ユーザー検索"}. +{"Virtual Hosts","ヴァーチャルホスト"}. +{"Visitors are not allowed to change their nicknames in this room","ビジターはこのチャットルームでニックネームを変更することは許可されていません"}. +{"Visitors are not allowed to send messages to all occupants","ビジターが移住者ににメッセージを送ることは許可されていません"}. +{"Wednesday","水曜日"}. +{"When to send the last published item","最後の公開アイテムを送信するタイミングで"}. +{"Whether to allow subscriptions","購読を許可するかどうか"}. +{"You have been banned from this room","あなたはチャットルームからバンされています"}. +{"You must fill in field \"Nickname\" in the form","フォームの\"ニックネーム\"フィールドを入力する必要があります"}. +{"You need an x:data capable client to configure mod_irc settings","mod_irc の設定にはクライアントが x:data をサポートする必要があります"}. +{"You need an x:data capable client to configure room","チャットルームを設定するにはにはクライアントが x:data をサポートする必要があります"}. +{"You need an x:data capable client to register nickname","ニックネームを登録するにはクライアントが x:data をサポートする必要があります"}. +{"You need an x:data capable client to search","検索を行うためにはクライアントが x:data をサポートする必要があります"}. +{"Your contact offline message queue is full. The message has been discarded.","宛先のオフラインメッセージキューが一杯です。このメッセージは破棄されます。"}. diff --git a/src/msgs/ja.po b/src/msgs/ja.po new file mode 100644 index 000000000..76ed42510 --- /dev/null +++ b/src/msgs/ja.po @@ -0,0 +1,1484 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Tsukasa Hamano\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Japanese (日本語)\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "STARTTLS を使用" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "リソースが提供されませんでした" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "新しいコネクションによって置き換えられました" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "コマンド" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "本当にお知らせメッセージを削除しますか?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "件名" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "本文" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "アナウンスメッセージはありませんでした" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "アナウンス" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "アナウンスを全てのユーザーに送信" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "アナウンスを全ホストのユーザーに送信" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "アナウンスを全てのオンラインユーザーに送信" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "全ホストのオンラインユーザへアナウンスを送信" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "お知らせメッセージを設定し、オンラインユーザーに送信する" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "全ホストのお知らせメッセージを設定し、オンラインユーザーに送信する" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "お知らせメッセージを更新する(送信しない)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "全ホストのお知らせメッセージを更新する" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "お知らせメッセージを削除する" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "全ホストのお知らせメッセージを削除する" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "設定" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "データーベース" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "モジュールの起動" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "モジュールの停止" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "バックアップ" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "リストア" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "テキストファイルに出力" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "ファイルかインポート" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "ディレクトリインポート" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "サービスを再起動" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "サービスを停止" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "ユーザーを追加" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "ユーザを削除" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "エンドユーザーセッション" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "パスワードを取得" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "パスワードを変更" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "最終ログイン時間の取得" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "ユーザー統計の取得" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "登録ユーザー数を取得" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "登録ユーザーを取得" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "アクセスコントロールリスト" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "アクセスルール" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "ユーザー管理" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "オンラインユーザー" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "全ユーザー" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "外向き s2s コネクション" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "起動ノード" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "停止ノード" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "モジュール" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "バックアップ管理" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "jabberd 1.4 Spool ファイルからユーザーをインポート" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "宛先 ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "差出人 ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "データーベーステーブル設定 " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "テーブルのストレージタイプの選択" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "ディスクだけのコピー" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "RAM, ディスクコピー" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "RAMコピー" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "リモートコピー" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "モジュールの停止 " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "停止するモジュールの選択" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "モジュールの開始" + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "{モジュール, [オプション]}のリストを入力して下さい" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "起動モジュールの一覧" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "ファイルにバックアップ" + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "バックアップファイルのパスを入力して下さい" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "ファイルパス" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "ファイルからバックアップをリストア" + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "テキストファイルにバックアップ" + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "テキストファイルのパスを入力して下さい" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "ファイルからユーザーをインポート" + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "jabberd1.4 spool ファイルのパスを入力して下さい" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "ディレクトリからユーザーをインポート" + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "jabberd1.4 spool ディレクトリのパスを入力して下さい" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "ディレクトリのパス" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "遅延時間" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "アクセスコントロールリスト設定" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "アクセスコントロールリスト" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "アクセス設定" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "アクセスルール" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "パスワード" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "パスワード(確認)" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "登録ユーザー数" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "オンラインユーザー数" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "無し" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "オンライン" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "最終ログイン" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "名簿サイズ" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "IPアドレス" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "リソース" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "管理: " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "ユーザー操作" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "プロパティの編集" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "ユーザーの削除" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "サービスポリシーによってアクセスが禁止されました" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "IRC トランスポート" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "ejabberd IRC module" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "mod_irc の設定にはクライアントが x:data をサポートする必要があります" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "mod_irc での登録: " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"IRCサーバーに接続先する為のユーザー名と文字エンコーディングを入力して下さい" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "IRCユーザー名" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"別の文字エンコーディングを使用したい場合、'{\"irc server\", \"encoding\"}' と" +"いう形式のリストを入力して下さい。デフォルトで \"~s\" を使用します" + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"例: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "エンコーディング" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "カービス管理者のみがサービスメッセージを送信出来ます" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "サービスポリシーにっよってチャットルームの作成が禁止されています" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "カンファレンスルームは存在しません" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "チャットルーム" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "" +"ニックネームを登録するにはクライアントが x:data をサポートする必要があります" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "ニックネーム登録: " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "登録するニックネームを入力して下さい" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "ニックネーム" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "指定されたニックネームは既に登録されています" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "フォームの\"ニックネーム\"フィールドを入力する必要があります" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "ejabberd MUC module" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "チャットルームの設定を変更しました" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "チャットルームに参加" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "チャットルームから退出" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "はバンされました" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "はキックされました" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "は提携が変更されたためキックされました" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "はチャットルームのメンバー制限によりキックされました" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "はシステムシャットダウンのためキックされました" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "は名前を変更しました: " + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " は件名を設定しました: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "月曜日" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "火曜日" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "水曜日" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "木曜日" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "金曜日" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "土曜日" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "日曜日" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "1月" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "2月" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "3月" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "4月" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "5月" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "6月" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "7月" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "8月" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "9月" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "10月" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "11月" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "12月" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "チャットルーム設定" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "チャットルームタイトル" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "トラフィックレートの制限を超えました" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "エラーメッセージを送信したため、この参加者はキックされました" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "カンファレンスルームにプライベートメッセージを送信することは出来ません" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "誤ったメッセージタイプです" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"他の参加者にエラーメッセージを送信したため、この参加者はキックされました" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "種別が\"groupchat\" であるプライベートメッセージは許可されていません" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "受信者がカンファレンスルームに居ません" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "移住者のみがカンファレンスに" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "プライベートメッセージを送信することは許可されませんでした" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "移住者のみがカンファレンスにクエリーを送信出来ます" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "" +"このチャットルームではカンファレンスメンバーへのクエリーは禁止されています" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "プライベート" + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "モデレーターと参加者のみがチャットルームの件名を変更出来ます" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "モデレーターのみがチャットルームの件名を変更出来ます" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "ビジターが移住者ににメッセージを送ることは許可されていません" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "エラープレゼンスを送信したため、この参加者はキックされました" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "" +"ビジターはこのチャットルームでニックネームを変更することは許可されていません" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "ニックネームは既に他の移住者によって使用されています" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "ニックネームは他の人によって登録されています" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "あなたはチャットルームからバンされています" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "チャットルームに入るにはメンバーでなければなりません" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "このチャットルームは非匿名です" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "チャットルームに入るにはパスワードが必要です" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "パスワードが違います" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "管理者権限が必要です" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "モデレーター権限が必要です" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "JID ~s は無効です" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "ニックネーム ~s はこのチャットルームに居ません" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "無効な提携です: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "無効なロールです: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "オーナー権限が必要です" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "設定: " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "詳細:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "チャットルームを永続化します" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "チャットルームを検索可能にします" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "参加者一覧を公開します" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "チャットルームにパスワードを設定します" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "最大移住者数" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "制限無し" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "本当の JID を公開する" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "モデレーターのみ" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "誰でも" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "チャットルームをメンバーのみに制限する" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "チャットルームをモデレートする" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "デフォルトのユーザーは参加者にする" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "ユーザーによる件名の変更を許可する" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "ユーザーによるプライベートメッセージの送信を許可する" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "ユーザーによる他のユーザーへの問い合わせを許可する" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "ユーザーによる招待を許可する" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "ビジターがプレゼンス更新のステータス文を送信する事を許可する" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "ビジターがニックネームを変更する事を許可します" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "ロギングを有効にする" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "" +"チャットルームを設定するにはにはクライアントが x:data をサポートする必要があ" +"ります" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "居住者の数" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s はあなたをチャットルーム ~s に招待しています" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "パスワードは" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "" +"宛先のオフラインメッセージキューが一杯です。このメッセージは破棄されます。" + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "~s's オフラインメッセージキュー" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "送信完了" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "時間" + +#: mod_offline.erl:507 +msgid "From" +msgstr "差出人" + +#: mod_offline.erl:508 +msgid "To" +msgstr "宛先" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "パケット" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "選択した項目を削除" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "オフラインメッセージ" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "ejabberd SOCKS5 Bytestreams module" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Publish-Subscribe" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "ejabberd Publish-Subscribe module" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "PubSub 購読リクエスト" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "このエントリを承認するかどうかを選択して下さい" + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "ノードID" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "購読アドレス" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "この JID をこの pubsubノードへ購読することを許可しますか?" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "イベント通知と同時にペイロードを配送します" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "イベント通知を配送します" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "ノード設定に変更があった時に購読者へ通知します" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "ノードが削除された時に購読者へ通知します" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "アイテムがノードから消された時に購読者へ通知します" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "アイテムをストレージに保存する" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "ノードの為のフレンドリネーム" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "アイテムの最大保存数 #" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "購読を許可するかどうか" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "アクセスモデルを設定する" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "名簿グループは購読を許可しました" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "公開モデルを指定する" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "最大ぺイロードサイズ(byte)" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "最後の公開アイテムを送信するタイミングで" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "有効なユーザーにのみ告知を送信する" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "サーバーに登録するユーザー名とパスワードを選択して下さい" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "早すぎるユーザーアカウント登録は許可されませんでした" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "無し" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "認可" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "保留" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "グループ" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "検証" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "削除" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "名簿: " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "不正なフォーマット" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Jabber ID の追加" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "名簿" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "共有名簿グループ" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "新規追加" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "名前: " + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "詳細:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "メンバー:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "表示グループ" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "グループ" + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "送信" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Erlang Jabber Server" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "誕生日" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "都道府県" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "国" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "メールアドレス" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "姓" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"フォームを埋めて Jabber User を検索して下さい(* を使用すると部分文字列にマッ" +"チします)" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "氏名" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "ミドルネーム" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "名" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "会社名" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "部署名" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "ユーザーの検索: " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "ユーザー" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "検索を行うためにはクライアントが x:data をサポートする必要があります" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "vCard ユーザー検索" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "ejabberd vCard module" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "検索結果: " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "項目を埋めて Jabber User を検索して下さい" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "ejabberd Web 管理" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "管理" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "ヴァーチャルホスト" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "ノード" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "統計" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "ユーザー" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "活動履歴" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Raw)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Raw" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "~s アクセスルール設定" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "ejabberd ヴァーチャルホスト" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "ユーザーの活動履歴" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "期間: " + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "先月" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "去年" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "全て" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Ordinaryテーブルを表示" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Integralテーブルを表示" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "ノードが見つかりません" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "ホスト" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "登録ユーザー" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "オフラインメッセージ" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "登録ユーザー:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "オンラインユーザー:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "外向き s2s コネクション:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "外向き s2s サービス:" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "パスワードの変更" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "ユーザー " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "接続リソース:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "パスワード" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "データ無し" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "ノード" + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Listenポート" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "更新" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "再起動" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "停止" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "RPC 呼び出しエラー" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "データーベーステーブル: " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "ストレージタイプ" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "サイズ" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "メモリ" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "バックアップ: " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"これらのオプションは組み込みの Mnesiaデーターベースをバックアップのみを行うこ" +"とに注意して下さい。もしも ODBCモジュールを使用している場合は SQLデーターベー" +"スのバックアップを別に行う必要があります。" + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "バイナリバックアップの保存" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "OK" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "直ちにバイナリバックアップからリストア" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "ejabberd の再起動時にバイナリバックアップからリストア" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "プレーンテキストバックアップの保存" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "直ちにプレーンテキストバックアップからリストア" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Listen ポート: " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "モジュール: " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "~p の統計" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "起動時間" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "CPU時間:" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "トランザクションのコミット:" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "トランザクションの失敗:" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "トランザクションの再起動:" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "トランザクションのログ: " + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "更新 " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "更新計画" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "モジュールを更新しました" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "スクリプトの更新" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "低レベル更新スクリプト" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "スクリプトチェック" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "ポート" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "モジュール" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "オプション" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "削除" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "開始" diff --git a/src/msgs/nl.msg b/src/msgs/nl.msg index 4764a394e..cb49db6f1 100644 --- a/src/msgs/nl.msg +++ b/src/msgs/nl.msg @@ -1,379 +1,343 @@ -% $Id$ -% Language: Dutch (nederlands) -% Author: Andreas van Cranenburgh -% Author: Sander Devrieze - -% mod_vcard_ldap.erl -{"Erlang Jabber Server", "Erlang Jabber Server"}. -{"You need an x:data capable client to search", "U hebt een client nodig die x:data ondersteunt om te zoeken"}. -{"Search users in ", "Gebruikers zoeken in "}. -{"Fill in fields to search for any matching Jabber User", "Vul de velden in om te zoeken naar Jabber-gebruikers op deze server"}. -{"User", "Gebruiker"}. -{"Full Name", "Volledige naam"}. -{"Middle Name", "Tussennaam"}. -{"Family Name", "Achternaam"}. -{"Nickname", "Bijnaam"}. -{"Birthday", "Geboortedatum"}. -{"Country", "Land"}. -{"City", "Plaats"}. -{"Email", "E-mail"}. -{"Organization Name", "Organisatie"}. -{"Organization Unit", "Afdeling"}. -{"ejabberd vCard module", "ejabberd's vCard-module"}. -{"Search Results for ", "Zoekresultaten voor "}. -{"Jabber ID", "Jabber ID"}. - -% mod_vcard.erl -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Gebruik de velden om te zoeken (Voeg achteraan het teken * toe om te zoeken naar alles wat met het eerste deel begint.)."}. -{"Name", "Naam"}. -% Probably needs to be "Given Name" - -% mod_configure.erl -{"Configuration", "Instellingen"}. -{"Database", "Database"}. -{"Start Modules", "Modules starten"}. -{"Stop Modules", "Modules stoppen"}. -{"Backup", "Backup"}. -{"Restore", "Binaire backup direct herstellen"}. -{"Dump to Text File", "Backup naar een tekstbestand schrijven"}. -{"Import File", "Bestand importeren"}. -{"Import Directory", "Directory importeren"}. -{"Access Control Lists", "Access control lists"}. -{"Access Rules", "Access rules"}. -{"Online Users", "Online gebruikers"}. -{"All Users", "Alle gebruikers"}. -{"Outgoing s2s Connections", "Uitgaande s2s-verbindingen"}. -{"Running Nodes", "Draaiende nodes"}. -{"Stopped Nodes", "Gestopte nodes"}. -{"Modules", "Modules"}. -{"Backup Management", "Backup"}. -{"Import Users From jabberd 1.4 Spool Files", "Importeer gebruikers via spool-bestanden van jabberd 1.4"}. -{"To ~s", "Naar ~s"}. -{"From ~s", "Van ~s"}. -{"Database Tables Configuration at ", "Instellingen van databasetabellen op "}. -{"Choose storage type of tables", "Opslagmethode voor tabellen kiezen"}. -{"RAM copy", "RAM"}. -{"RAM and disc copy", "RAM en harde schijf"}. -{"Disc only copy", "Harde schijf"}. -{"Remote copy", "Op andere nodes in de cluster"}. -{"Stop Modules at ", "Modules stoppen op "}. -{"Choose modules to stop", "Selecteer de modules die u wilt stoppen"}. -{"Start Modules at ", "Modules starten op "}. -{"Enter list of {Module, [Options]}", "Voer lijst met op te starten modules als volgt in: {Module, [Opties]}"}. -{"List of modules to start", "Lijst met op te starten modules"}. -{"Backup to File at ", "Binaire backup maken op "}. -{"Enter path to backup file", "Voer pad naar backupbestand in"}. -{"Path to File", "Pad naar bestand"}. -{"Restore Backup from File at ", "Binaire backup direct herstellen op "}. -{"Dump Backup to Text File at ", "Backup naar een tekstbestand schrijven op "}. -{"Enter path to text file", "Voer pad naar backupbestand in"}. -{"Import User from File at ", "Importeer gebruiker via bestand op "}. -{"Enter path to jabberd1.4 spool file", "Voer pad naar jabberd 1.4-spool-bestand in"}. -{"Import Users from Dir at ", "Gebruikers importeren vanaf directory op "}. -{"Enter path to jabberd1.4 spool dir", "Voer pad naar jabberd 1.4-spool-directory in"}. -{"Path to Dir", "Pad naar directory"}. -{"Access Control List Configuration", "Instellingen van access control lists"}. -{"Access control lists", "Access control lists"}. -{"Access Configuration", "Toegangsinstellingen"}. -{"Access rules", "Access rules"}. -{"Administration of ", "Beheer van "}. -{"Action on user", "Actie op gebruiker"}. -{"Edit Properties", "Eigenschappen bewerken"}. -{"Remove User", "Gebruiker verwijderen"}. -{"Password", "Wachtwoord"}. -{"Restart Service", "Herstart Service"}. -{"Shut Down Service", "Stop Service"}. -{"Delete User", "Verwijder Gebruiker"}. -{"End User Session", "Verwijder Gebruikers-sessie"}. -{"Get User Password", "Gebruikerswachtwoord Opvragen"}. -{"Change User Password", "Verander Gebruikerswachtwoord"}. -{"Get User Last Login Time", "Tijd van Laatste Aanmelding Opvragen"}. -{"Get User Statistics", "Gebruikers-statistieken Opvragen"}. -{"Get Number of Registered Users", "Aantal Geregistreerde Gebruikers Opvragen"}. -{"Get Number of Online Users", "Aantal Aanwezige Gebruikers Opvragen"}. -{"User Management", "Gebruikersbeheer"}. -{"Time delay", "Vertraging"}. -{"Password Verification", "Wachtwoord Bevestiging"}. -{"Number of registered users", "Aantal Geregistreerde Gebruikers"}. -{"Number of online users", "Aantal Aanwezige Gebruikers"}. -{"Last login", "Laatste Aanmelding"}. -{"Roster size", "Contactlijst Groote"}. -{"IP addresses", "IP-adres"}. -{"Resources", "Bronnen"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Kies een gebruikersnaam en een wachtwoord om u te registreren op deze server"}. - -% ejabberd_c2s.erl -{"Use of STARTTLS required", "Gebruik van STARTTLS is vereist"}. -{"No resource provided", "Geen bron opgegeven"}. -{"Replaced by new connection", "Vervangen door een nieuwe verbinding"}. - -% mod_muc/mod_muc_log.erl -{"has been kicked because of an affiliation change", "is weggestuurd vanwege een affiliatieverandering"}. -{"has been kicked because the room has been changed to members-only", "is weggestuurd omdat de chatruimte vanaf heden alleen toegankelijk is voor leden"}. -{"has been kicked because of a system shutdown", "is weggestuurd omdat het systeem gestopt wordt"}. -{"Chatroom configuration modified", "De instellingen van de chatruimte werden veranderd"}. -{"joins the room", "betrad de chatruimte"}. -{"leaves the room", "verliet de chatruimte"}. -{"has been kicked", "werd gekicked"}. -{"has been banned", "werd verbannen"}. -{"is now known as", "heet nu"}. -{" has set the subject to: ", " veranderde het onderwerp in: "}. -{"Monday", "maandag"}. -{"Tuesday", "dinsdag"}. -{"Wednesday", "woensdag"}. -{"Thursday", "donderdag"}. -{"Friday", "vrijdag"}. -{"Saturday", "zaterdag"}. -{"Sunday", "zondag"}. -{"January", "januari"}. -{"February", "februari"}. -{"March", "maart"}. -{"April", "april"}. -{"May", "mei"}. -{"June", "juni"}. -{"July", "juli"}. -{"August", "augustus"}. -{"September", "september"}. -{"October", "oktober"}. -{"November", "november"}. -{"December", "december"}. -{"Room Configuration", "Instellingen van de chatruimte"}. -{"Room title", "Naam van de chatruimte"}. - -% mod_muc/mod_muc.erl -{"Access denied by service policy", "De toegang werd geweigerd door het beleid van deze dienst"}. -{"Only service administrators are allowed to send service messages", "Alleen beheerders van deze dienst mogen mededelingen verzenden naar alle chatruimtes"}. -{"Room creation is denied by service policy", "De aanmaak van de chatruimte is verhinderd door de instellingen van deze server"}. -{"Conference room does not exist", "De chatruimte bestaat niet"}. -{"You need an x:data capable client to register nickname", "U hebt een client nodig die x:data ondersteunt om een bijnaam te registreren"}. -{"Nickname Registration at ", "Registratie van een bijnaam op "}. -{"Enter nickname you want to register", "Voer de bijnaam in die u wilt registreren"}. -{"Specified nickname is already registered", "De gekozen bijnaam is al geregistreerd"}. -{"You must fill in field \"Nickname\" in the form", "U moet het veld \"bijnaam\" invullen"}. -{"ejabberd MUC module", "ejabberd's MUC module"}. -{"Chatrooms", "Groepsgesprekken"}. - -% mod_muc/mod_muc_room.erl -{"This participant is kicked from the room because he sent an error message", "Deze deelnemer wordt weggestuurd vanwege het sturen van een foutmeldingsbericht"}. -{"This participant is kicked from the room because he sent an error message to another participant", "Deze deelnemer wordt weggestuurd vanwege het sturen van een foutmeldingsbericht aan een andere deelnemer"}. -{"This participant is kicked from the room because he sent an error presence", "Deze deelnemer wordt weggestuurd vanwege het sturen van een foutmelding-aanwezigheid"}. -{"Make room moderated", "Chatruimte gemodereerd maken"}. -{"Only moderators and participants are allowed to change subject in this room", "Alleen moderators en deelnemers mogen het onderwerp van deze chatruimte veranderen"}. -{"Only moderators are allowed to change subject in this room", "Alleen moderators mogen het onderwerp van deze chatruimte veranderen"}. -{"Visitors are not allowed to send messages to all occupants", "Bezoekers mogen geen berichten verzenden naar alle aanwezigen"}. -{"It is not allowed to send private messages to the conference", "Er mogen geen privéberichten naar de chatruimte worden verzonden"}. -{"Improper message type", "Onjuist berichttype"}. -{"Only occupants are allowed to send messages to the conference", "Alleen aanwezigen mogen berichten naar de chatruimte verzenden"}. -{"Nickname is already in use by another occupant", "Deze bijnaam is al in gebruik door een andere aanwezige"}. -{"Nickname is registered by another person", "Deze bijnaam is al geregistreerd door iemand anders"}. -{"It is not allowed to send private messages of type \"groupchat\"", "Er mogen geen privéberichten van het type \"groupchat\" worden verzonden"}. -{"Recipient is not in the conference room", "De ontvanger is niet in de chatruimte"}. -{"Only occupants are allowed to send queries to the conference", "Alleen aanwezigen mogen verzoeken verzenden naar de chatruimte"}. -{"Queries to the conference members are not allowed in this room", "Er mogen geen verzoeken verzenden worden naar deelnemers in deze chatruimte"}. -{"private, ", "privé, "}. -{"You have been banned from this room", "U werd verbannen uit deze chatruimte"}. -{"Membership required to enter this room", "U moet lid zijn om deze chatruimte te kunnen betreden"}. -{"This room is not anonymous", "Deze chatruimte is niet anoniem"}. -{"Password required to enter this room", "U hebt een wachtwoord nodig om deze chatruimte te kunnen betreden"}. -{"Incorrect password", "Foutief wachtwoord"}. -{"Administrator privileges required", "U hebt beheerdersprivileges nodig"}. -{"Moderator privileges required", "U hebt moderatorprivileges nodig"}. -{"JID ~s is invalid", "De Jabber ID ~s is ongeldig"}. -{"Nickname ~s does not exist in the room", "De bijnaam ~s bestaat niet in deze chatruimte"}. -{"Invalid affiliation: ~s", "Ongeldige affiliatie: ~s"}. -{"Invalid role: ~s", "Ongeldige rol: ~s"}. -{"Owner privileges required", "U hebt eigenaarsprivileges nodig"}. -{"Configuration for ", "Instellingen van "}. -{"Make room persistent", "Chatruimte blijvend maken"}. -{"Make room public searchable", "Chatruimte doorzoekbaar maken"}. -{"Make participants list public", "Deelnemerslijst publiek maken"}. -{"Make room password protected", "Chatruimte beveiligen met een wachtwoord"}. -{"Make room members-only", "Chatruimte enkel toegankelijk maken voor leden"}. -{"Default users as participants", "Gebruikers standaard instellen als deelnemers"}. -{"Allow users to change subject", "Gebruikers mogen het onderwerp veranderen"}. -{"Allow users to send private messages", "Gebruikers mogen privéberichten verzenden"}. -{"Allow users to query other users", "Gebruikers mogen naar andere gebruikers verzoeken verzenden"}. -{"Allow users to send invites", "Gebruikers mogen uitnodigingen verzenden"}. -{"Enable logging", "Logs aanzetten"}. -{"You need an x:data capable client to configure room", "U hebt een client nodig die x:data ondersteunt om deze chatruimte in te stellen"}. -{"Number of occupants", "Aantal aanwezigen"}. -{"Present real JIDs to", "Jabber ID's kunnen achterhaald worden door"}. -{"moderators only", "moderators"}. -{"anyone", "iedereen"}. -{"Traffic rate limit is exceeded", "Dataverkeerslimiet overschreden"}. -{"Maximum Number of Occupants", "Maximum aantal aanwezigen"}. -{"No limit", "Geen limiet"}. -{"~s invites you to the room ~s", "~s nodigt je uit voor het groepsgesprek ~s"}. -{"the password is", "het wachtwoord is"}. - -% mod_irc/mod_irc.erl -{"ejabberd IRC module", "ejabberd's IRC-module"}. -{"You need an x:data capable client to configure mod_irc settings", "U hebt een client nodig die x:data ondersteunt om dit IRC-transport in te stellen"}. -{"Registration in mod_irc for ", "Registratie van "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Voer de gebruikersnaam en de coderingen in die u wilt gebruiken voor verbindingen met IRC-servers"}. -{"IRC Username", "Gebruikersnaam voor IRC:"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Als u verschillende coderingen wilt opgeven voor elke IRC-server, ga dan voor elke server te werk op als volgt: '{\"IRC-server\", \"codering\"}'. Standaard gebruikt dit IRC-transport de codering \"~s\"."}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Voorbeeld: [{\"irc.example.org\", \"koi8-r\"}, {\"vendetta.example.net\", \"iso8859-1\"}]."}. -{"Encodings", "Coderingen:"}. -{"IRC Transport", "IRC Transport"}. - -% mod_adhoc.erl -{"Commands", "Commando's"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% mod_announce.erl -{"Really delete message of the day?", "Wilt u het bericht van de dag verwijderen?"}. -{"Subject", "Onderwerp"}. -{"Message body", "Bericht"}. -{"No body provided for announce message", "De mededeling bevat geen bericht"}. -{"Announcements", "Mededelingen"}. -{"Send announcement to all users", "Mededeling verzenden naar alle gebruikers"}. -{"Send announcement to all online users", "Mededeling verzenden naar alle online gebruikers"}. -{"Send announcement to all online users on all hosts", "Mededeling verzenden naar alle online gebruikers op alle virtuele hosts"}. -{"Set message of the day and send to online users", "Bericht van de dag instellen en verzenden naar online gebruikers"}. -{"Update message of the day (don't send)", "Bericht van de dag bijwerken (niet verzenden)"}. -{"Delete message of the day", "Bericht van de dag verwijderen"}. -{"Send announcement to all users on all hosts", "Stuur aankondiging aan alle gebruikers op alle hosts"}. -{"Set message of the day on all hosts and send to online users", "Stel bericht-van-de-dag in op alle hosts en stuur naar aanwezige gebruikers"}. -{"Update message of the day on all hosts (don't send)", "Verander bericht-van-de-dag op alle hosts (niet versturen)"}. -{"Delete message of the day on all hosts", "Verwijder bericht-van-de-dag op alle hosts"}. - -% mod_pubsub/mod_pubsub.erl -{"Roster groups allowed to subscribe", "Contactlijst-groepen die mogen abonneren"}. -{"Deliver payloads with event notifications", "Berichten bezorgen samen met gebeurtenisnotificaties"}. -{"Notify subscribers when the node configuration changes", "Abonnees informeren wanneer de instellingen van de node veranderen"}. -{"Notify subscribers when the node is deleted", "Abonnees informeren wanneer de node verwijderd word"}. -{"Notify subscribers when items are removed from the node", "Abonnees informeren wanneer items verwijderd worden uit de node"}. -{"Persist items to storage", "Items in het geheugen bewaren"}. -{"Max # of items to persist", "Maximum aantal in het geheugen te bewaren items"}. -{"Whether to allow subscriptions", "Abonnementsaanvraag toestaan"}. -{"Specify the publisher model", "Publicatietype opgeven"}. -{"Max payload size in bytes", "Maximumgrootte van bericht in bytes"}. -{"Only deliver notifications to available users", "Notificaties alleen verzenden naar online gebruikers"}. -{"Publish-Subscribe", "Publish-Subscribe"}. -{"ejabberd Publish-Subscribe module", "ejabberd Publish-Subscribe module"}. -{"PubSub subscriber request", "PubSub abonnee verzoek"}. -{"Choose whether to approve this entity's subscription.", "Beslis of dit verzoek tot abonneren zal worden goedgekeurd"}. -{"Node ID", "Node ID"}. -{"Subscriber Address", "Abonnee Adres"}. -{"Allow this JID to subscribe to this pubsub node?", "Deze gebruiker toestaan te abonneren op deze pubsub node?"}. -{"Deliver event notifications", "Gebeurtenisbevestigingen Sturen"}. -{"Specify the access model", "Geef toegangsmodel"}. -{"When to send the last published item", "Wanneer het laatst gepubliceerde item verzonden moet worden"}. - -% web/ejabberd_web_admin.erl -{"ejabberd Web Admin", "ejabberd Webbeheer"}. -{"Administration", "Beheer"}. -{"Virtual Hosts", "Virtuele hosts"}. -{"Nodes", "Nodes"}. -{"Statistics", "Statistieken"}. -{"Users", "Gebruikers"}. -{"Last Activity", "Laatste activiteit"}. -{"(Raw)", "(Ruw)"}. -{"Submitted", "Verzonden"}. -{"Bad format", "Slecht formaat"}. -{"Submit", "Verzenden"}. -{"Raw", "Ruw"}. -{"Delete Selected", "Geselecteerde verwijderen"}. -{"~s access rule configuration", "Access rules op ~s"}. -{"ejabberd virtual hosts", "Virtuele hosts"}. -{"Users Last Activity", "Laatste activiteit van gebruikers"}. -{"Period: ", "Periode: "}. -{"Last month", "Afgelopen maand"}. -{"Last year", "Afgelopen jaar"}. -{"All activity", "Alle activiteit"}. -{"Show Ordinary Table", "Deel van tabel laten zien"}. -{"Show Integral Table", "Volledige tabel laten zien"}. -{"Node not found", "Node niet gevonden"}. -{"Add New", "Toevoegen"}. -{"Host", "Host"}. -{"Registered Users", "Geregistreerde gebruikers"}. -{"Add User", "Gebruiker toevoegen"}. -{"Offline Messages", "Offline berichten"}. -{"Never", "Nooit"}. -{"Online", "Online"}. -{"Registered Users:", "Geregistreerde gebruikers:"}. -{"Online Users:", "Online gebruikers:"}. -{"Outgoing s2s Connections:", "Uitgaande s2s-verbindingen:"}. -{"Outgoing s2s Servers:", "Uitgaande s2s-verbindingen:"}. -{"None", "Geen"}. -{"Change Password", "Wachtwoord wijzigen"}. -{"User ", "Gebruiker "}. -{"Connected Resources:", "Verbonden bronnen:"}. -{"Password:", "Wachtwoord:"}. -{"Offline Messages:", "Offline berichten:"}. -{"Roster", "Roster"}. -{"~s's Offline Messages Queue", "offline berichten van ~s"}. -{"Time", "Tijd"}. -{"From", "Van"}. -{"To", "Aan"}. -{"Packet", "Pakket"}. -{"Subscription", "Inschrijving"}. -{"Pending", "Bezig"}. -{"Groups", "Groepen"}. -{"Validate", "Bevestigen"}. -{"Remove", "Verwijderen"}. -{"Roster of ", "Roster van "}. -{"Add Jabber ID", "Jabber ID toevoegen"}. -{"No Data", "Geen gegevens"}. -{"Node ", "Node "}. -{"Listened Ports", "Openstaande poorten"}. -{"Update", "Bijwerken"}. -{"Restart", "Herstarten"}. -{"Stop", "Stoppen"}. -{"RPC Call Error", "RPC-oproepfout"}. -{"Database Tables at ", "Databasetabellen van "}. -{"Storage Type", "Opslagmethode"}. -{"Size", "Grootte"}. -{"Memory", "Geheugen"}. -{"Backup of ", "Backup maken van "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "Merk op dat volgende opties enkel backups maken van de ingebouwde database Mnesia. Als u (een) andere database(s) gebruikt dan moet u daarvan (een) afzonderlijke backup(s) maken."}. -{"Store binary backup:", "Binaire backup maken:"}. -{"OK", "OK"}. -{"Restore binary backup immediately:", "Binaire backup direct herstellen:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Binaire backup herstellen na herstart van ejabberd (vereist minder geheugen):"}. -{"Store plain text backup:", "Backup naar een tekstbestand schrijven:"}. -{"Restore plain text backup immediately:", "Backup in een tekstbestand direct herstellen:"}. -{"Listened Ports at ", "Openstaande poorten op "}. -{"Modules at ", "Modules op "}. -{"Statistics of ~p", "Statistieken van ~p"}. -{"Uptime:", "Uptime:"}. -{"CPU Time:", "Processortijd:"}. -{"Transactions Commited:", "Bevestigde transacties:"}. -{"Transactions Aborted:", "Afgebroken transacties:"}. -{"Transactions Restarted:", "Herstarte transacties:"}. -{"Transactions Logged:", "Gelogde transacties:"}. -{"Update ", "Opwaarderen van "}. -{"Update plan", "Plan voor de opwaardering"}. -{"Updated modules", "Modules opwaarderen"}. -{"Update script", "Script voor de opwaardering"}. -{"Low level update script", "Lowlevel script voor de opwaardering"}. -{"Script check", "Controle van script"}. -{"Port", "Poort"}. -{"Module", "Module"}. -{"Options", "Opties"}. -{"Delete", "Verwijderen"}. -{"Start", "Starten"}. -{"Shared Roster Groups", "Gedeelde rostergroepen"}. -{"Name:", "Naam:"}. -{"Description:", "Beschrijving:"}. -{"Members:", "Groepsleden:"}. -{"Displayed Groups:", "Weergegeven groepen:"}. -{"Group ", "Groep "}. - -% mod_vcard_odbc.erl -{"vCard User Search", "Gebruikers zoeken"}. - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "Te veel offline berichten voor dit contactpersoon. Het bericht is niet opgeslagen."}. - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "ejabberd SOCKS5 Bytestreams module"}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Toegangsinstellingen"}. +{"Access Control List Configuration","Instellingen van access control lists"}. +{"Access control lists","Access control lists"}. +{"Access Control Lists","Access control lists"}. +{"Access denied by service policy","De toegang werd geweigerd door het beleid van deze dienst"}. +{"Access rules","Access rules"}. +{"Access Rules","Access rules"}. +{"Action on user","Actie op gebruiker"}. +{"Add Jabber ID","Jabber ID toevoegen"}. +{"Add New","Toevoegen"}. +{"Add User","Gebruiker toevoegen"}. +{"Administration","Beheer"}. +{"Administration of ","Beheer van "}. +{"Administrator privileges required","U hebt beheerdersprivileges nodig"}. +{"A friendly name for the node","Bijnaam voor deze knoop"}. +{"All activity","Alle activiteit"}. +{"Allow this JID to subscribe to this pubsub node?","Deze gebruiker toestaan te abonneren op deze pubsub node?"}. +{"Allow users to change subject","Gebruikers mogen het onderwerp veranderen"}. +{"Allow users to query other users","Gebruikers mogen naar andere gebruikers verzoeken verzenden"}. +{"Allow users to send invites","Gebruikers mogen uitnodigingen verzenden"}. +{"Allow users to send private messages","Gebruikers mogen privéberichten verzenden"}. +{"Allow visitors to change nickname","Sta bezoekers toe hun naam te veranderen"}. +{"Allow visitors to send status text in presence updates","Sta bezoekers toe hun statusbericht in te stellen"}. +{"All Users","Alle gebruikers"}. +{"Announcements","Mededelingen"}. +{"anyone","iedereen"}. +{"April","april"}. +{"August","augustus"}. +{"Backup","Backup"}. +{"Backup Management","Backup"}. +{"Backup of ","Backup maken van "}. +{"Backup to File at ","Binaire backup maken op "}. +{"Bad format","Slecht formaat"}. +{"Birthday","Geboortedatum"}. +{"Change Password","Wachtwoord wijzigen"}. +{"Change User Password","Verander Gebruikerswachtwoord"}. +{"Chatroom configuration modified","De instellingen van de chatruimte werden veranderd"}. +{"Chatrooms","Groepsgesprekken"}. +{"Choose a username and password to register with this server","Kies een gebruikersnaam en een wachtwoord om u te registreren op deze server"}. +{"Choose modules to stop","Selecteer de modules die u wilt stoppen"}. +{"Choose storage type of tables","Opslagmethode voor tabellen kiezen"}. +{"Choose whether to approve this entity's subscription.","Beslis of dit verzoek tot abonneren zal worden goedgekeurd"}. +{"City","Plaats"}. +{"Commands","Commando's"}. +{"Conference room does not exist","De chatruimte bestaat niet"}. +{"Configuration for ","Instellingen van "}. +{"Configuration","Instellingen"}. +{"Connected Resources:","Verbonden bronnen:"}. +{"Country","Land"}. +{"CPU Time:","Processortijd:"}. +{"Database","Database"}. +{"Database Tables at ","Databasetabellen van "}. +{"Database Tables Configuration at ","Instellingen van databasetabellen op "}. +{"December","december"}. +{"Default users as participants","Gebruikers standaard instellen als deelnemers"}. +{"Delete message of the day","Bericht van de dag verwijderen"}. +{"Delete message of the day on all hosts","Verwijder bericht-van-de-dag op alle hosts"}. +{"Delete Selected","Geselecteerde verwijderen"}. +{"Delete User","Verwijder Gebruiker"}. +{"Delete","Verwijderen"}. +{"Deliver event notifications","Gebeurtenisbevestigingen Sturen"}. +{"Deliver payloads with event notifications","Berichten bezorgen samen met gebeurtenisnotificaties"}. +{"Description:","Beschrijving:"}. +{"Disc only copy","Harde schijf"}. +{"Displayed Groups:","Weergegeven groepen:"}. +{"Dump Backup to Text File at ","Backup naar een tekstbestand schrijven op "}. +{"Dump to Text File","Backup naar een tekstbestand schrijven"}. +{"Edit Properties","Eigenschappen bewerken"}. +{"ejabberd IRC module","ejabberd's IRC-module"}. +{"ejabberd MUC module","ejabberd's MUC module"}. +{"ejabberd Publish-Subscribe module","ejabberd Publish-Subscribe module"}. +{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestreams module"}. +{"ejabberd vCard module","ejabberd's vCard-module"}. +{"ejabberd virtual hosts","Virtuele hosts"}. +{"ejabberd Web Admin","ejabberd Webbeheer"}. +{"Email","E-mail"}. +{"Enable logging","Logs aanzetten"}. +{"Encodings","Coderingen:"}. +{"End User Session","Verwijder Gebruikers-sessie"}. +{"Enter list of {Module, [Options]}","Voer lijst met op te starten modules als volgt in: {Module, [Opties]}"}. +{"Enter nickname you want to register","Voer de bijnaam in die u wilt registreren"}. +{"Enter path to backup file","Voer pad naar backupbestand in"}. +{"Enter path to jabberd1.4 spool dir","Voer pad naar jabberd 1.4-spool-directory in"}. +{"Enter path to jabberd1.4 spool file","Voer pad naar jabberd 1.4-spool-bestand in"}. +{"Enter path to text file","Voer pad naar backupbestand in"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Voer de gebruikersnaam en de coderingen in die u wilt gebruiken voor verbindingen met IRC-servers"}. +{"Erlang Jabber Server","Erlang Jabber Server"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Voorbeeld: [{\"irc.example.org\", \"koi8-r\"}, {\"vendetta.example.net\", \"iso8859-1\"}]."}. +{"Family Name","Achternaam"}. +{"February","februari"}. +{"Fill in fields to search for any matching Jabber User","Vul de velden in om te zoeken naar Jabber-gebruikers op deze server"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Gebruik de velden om te zoeken (Voeg achteraan het teken * toe om te zoeken naar alles wat met het eerste deel begint.)."}. +{"Friday","vrijdag"}. +{"From ~s","Van ~s"}. +{"From","Van"}. +{"Full Name","Volledige naam"}. +{"Get Number of Online Users","Aantal Aanwezige Gebruikers Opvragen"}. +{"Get Number of Registered Users","Aantal Geregistreerde Gebruikers Opvragen"}. +{"Get User Last Login Time","Tijd van Laatste Aanmelding Opvragen"}. +{"Get User Password","Gebruikerswachtwoord Opvragen"}. +{"Get User Statistics","Gebruikers-statistieken Opvragen"}. +{"Group ","Groep "}. +{"Groups","Groepen"}. +{"has been banned","werd verbannen"}. +{"has been kicked because of an affiliation change","is weggestuurd vanwege een affiliatieverandering"}. +{"has been kicked because of a system shutdown","is weggestuurd omdat het systeem gestopt wordt"}. +{"has been kicked because the room has been changed to members-only","is weggestuurd omdat de chatruimte vanaf heden alleen toegankelijk is voor leden"}. +{"has been kicked","werd gekicked"}. +{" has set the subject to: "," veranderde het onderwerp in: "}. +{"Host","Host"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Als u verschillende coderingen wilt opgeven voor elke IRC-server, ga dan voor elke server te werk op als volgt: '{\"IRC-server\", \"codering\"}'. Standaard gebruikt dit IRC-transport de codering \"~s\"."}. +{"Import Directory","Directory importeren"}. +{"Import File","Bestand importeren"}. +{"Import User from File at ","Importeer gebruiker via bestand op "}. +{"Import Users from Dir at ","Gebruikers importeren vanaf directory op "}. +{"Import Users From jabberd 1.4 Spool Files","Importeer gebruikers via spool-bestanden van jabberd 1.4"}. +{"Improper message type","Onjuist berichttype"}. +{"Incorrect password","Foutief wachtwoord"}. +{"Invalid affiliation: ~s","Ongeldige affiliatie: ~s"}. +{"Invalid role: ~s","Ongeldige rol: ~s"}. +{"IP addresses","IP-adres"}. +{"IRC Transport","IRC Transport"}. +{"IRC Username","Gebruikersnaam voor IRC:"}. +{"is now known as","heet nu"}. +{"It is not allowed to send private messages","Het is niet toegestaan priveberichten te sturen"}. +{"It is not allowed to send private messages of type \"groupchat\"","Er mogen geen privéberichten van het type \"groupchat\" worden verzonden"}. +{"It is not allowed to send private messages to the conference","Er mogen geen privéberichten naar de chatruimte worden verzonden"}. +{"Jabber ID","Jabber ID"}. +{"January","januari"}. +{"JID ~s is invalid","De Jabber ID ~s is ongeldig"}. +{"joins the room","betrad de chatruimte"}. +{"July","juli"}. +{"June","juni"}. +{"Last Activity","Laatste activiteit"}. +{"Last login","Laatste Aanmelding"}. +{"Last month","Afgelopen maand"}. +{"Last year","Afgelopen jaar"}. +{"leaves the room","verliet de chatruimte"}. +{"Listened Ports at ","Openstaande poorten op "}. +{"Listened Ports","Openstaande poorten"}. +{"List of modules to start","Lijst met op te starten modules"}. +{"Low level update script","Lowlevel script voor de opwaardering"}. +{"Make participants list public","Deelnemerslijst publiek maken"}. +{"Make room members-only","Chatruimte enkel toegankelijk maken voor leden"}. +{"Make room moderated","Chatruimte gemodereerd maken"}. +{"Make room password protected","Chatruimte beveiligen met een wachtwoord"}. +{"Make room persistent","Chatruimte blijvend maken"}. +{"Make room public searchable","Chatruimte doorzoekbaar maken"}. +{"March","maart"}. +{"Maximum Number of Occupants","Maximum aantal aanwezigen"}. +{"Max # of items to persist","Maximum aantal in het geheugen te bewaren items"}. +{"Max payload size in bytes","Maximumgrootte van bericht in bytes"}. +{"May","mei"}. +{"Members:","Groepsleden:"}. +{"Membership required to enter this room","U moet lid zijn om deze chatruimte te kunnen betreden"}. +{"Memory","Geheugen"}. +{"Message body","Bericht"}. +{"Middle Name","Tussennaam"}. +{"Moderator privileges required","U hebt moderatorprivileges nodig"}. +{"moderators only","moderators"}. +{"Module","Module"}. +{"Modules at ","Modules op "}. +{"Modules","Modules"}. +{"Monday","maandag"}. +{"Name:","Naam:"}. +{"Name","Naam"}. +{"Never","Nooit"}. +{"Nickname","Bijnaam"}. +{"Nickname is already in use by another occupant","Deze bijnaam is al in gebruik door een andere aanwezige"}. +{"Nickname is registered by another person","Deze bijnaam is al geregistreerd door iemand anders"}. +{"Nickname Registration at ","Registratie van een bijnaam op "}. +{"Nickname ~s does not exist in the room","De bijnaam ~s bestaat niet in deze chatruimte"}. +{"No body provided for announce message","De mededeling bevat geen bericht"}. +{"No Data","Geen gegevens"}. +{"Node ID","Node ID"}. +{"Node ","Node "}. +{"Node not found","Node niet gevonden"}. +{"Nodes","Nodes"}. +{"No limit","Geen limiet"}. +{"None","Geen"}. +{"No resource provided","Geen bron opgegeven"}. +{"Notify subscribers when items are removed from the node","Abonnees informeren wanneer items verwijderd worden uit de node"}. +{"Notify subscribers when the node configuration changes","Abonnees informeren wanneer de instellingen van de node veranderen"}. +{"Notify subscribers when the node is deleted","Abonnees informeren wanneer de node verwijderd word"}. +{"November","november"}. +{"Number of occupants","Aantal aanwezigen"}. +{"Number of online users","Aantal Aanwezige Gebruikers"}. +{"Number of registered users","Aantal Geregistreerde Gebruikers"}. +{"October","oktober"}. +{"Offline Messages:","Offline berichten:"}. +{"Offline Messages","Offline berichten"}. +{"OK","OK"}. +{"Online","Online"}. +{"Online Users:","Online gebruikers:"}. +{"Online Users","Online gebruikers"}. +{"Only deliver notifications to available users","Notificaties alleen verzenden naar online gebruikers"}. +{"Only moderators and participants are allowed to change subject in this room","Alleen moderators en deelnemers mogen het onderwerp van deze chatruimte veranderen"}. +{"Only moderators are allowed to change subject in this room","Alleen moderators mogen het onderwerp van deze chatruimte veranderen"}. +{"Only occupants are allowed to send messages to the conference","Alleen aanwezigen mogen berichten naar de chatruimte verzenden"}. +{"Only occupants are allowed to send queries to the conference","Alleen aanwezigen mogen verzoeken verzenden naar de chatruimte"}. +{"Only service administrators are allowed to send service messages","Alleen beheerders van deze dienst mogen mededelingen verzenden naar alle chatruimtes"}. +{"Options","Opties"}. +{"Organization Name","Organisatie"}. +{"Organization Unit","Afdeling"}. +{"Outgoing s2s Connections:","Uitgaande s2s-verbindingen:"}. +{"Outgoing s2s Connections","Uitgaande s2s-verbindingen"}. +{"Outgoing s2s Servers:","Uitgaande s2s-verbindingen:"}. +{"Owner privileges required","U hebt eigenaarsprivileges nodig"}. +{"Packet","Pakket"}. +{"Password required to enter this room","U hebt een wachtwoord nodig om deze chatruimte te kunnen betreden"}. +{"Password Verification","Wachtwoord Bevestiging"}. +{"Password:","Wachtwoord:"}. +{"Password","Wachtwoord"}. +{"Path to Dir","Pad naar directory"}. +{"Path to File","Pad naar bestand"}. +{"Pending","Bezig"}. +{"Period: ","Periode: "}. +{"Persist items to storage","Items in het geheugen bewaren"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","Poort"}. +{"Present real JIDs to","Jabber ID's kunnen achterhaald worden door"}. +{"private, ","privé, "}. +{"Publish-Subscribe","Publish-Subscribe"}. +{"PubSub subscriber request","PubSub abonnee verzoek"}. +{"Queries to the conference members are not allowed in this room","Er mogen geen verzoeken verzenden worden naar deelnemers in deze chatruimte"}. +{"RAM and disc copy","RAM en harde schijf"}. +{"RAM copy","RAM"}. +{"(Raw)","(Ruw)"}. +{"Raw","Ruw"}. +{"Really delete message of the day?","Wilt u het bericht van de dag verwijderen?"}. +{"Recipient is not in the conference room","De ontvanger is niet in de chatruimte"}. +{"Registered Users:","Geregistreerde gebruikers:"}. +{"Registered Users","Geregistreerde gebruikers"}. +{"Registration in mod_irc for ","Registratie van "}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Merk op dat volgende opties enkel backups maken van de ingebouwde database Mnesia. Als u (een) andere database(s) gebruikt dan moet u daarvan (een) afzonderlijke backup(s) maken."}. +{"Remote copy","Op andere nodes in de cluster"}. +{"Remove User","Gebruiker verwijderen"}. +{"Remove","Verwijderen"}. +{"Replaced by new connection","Vervangen door een nieuwe verbinding"}. +{"Resources","Bronnen"}. +{"Restart","Herstarten"}. +{"Restart Service","Herstart Service"}. +{"Restore Backup from File at ","Binaire backup direct herstellen op "}. +{"Restore","Binaire backup direct herstellen"}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Binaire backup herstellen na herstart van ejabberd (vereist minder geheugen):"}. +{"Restore binary backup immediately:","Binaire backup direct herstellen:"}. +{"Restore plain text backup immediately:","Backup in een tekstbestand direct herstellen:"}. +{"Room Configuration","Instellingen van de chatruimte"}. +{"Room creation is denied by service policy","De aanmaak van de chatruimte is verhinderd door de instellingen van deze server"}. +{"Room title","Naam van de chatruimte"}. +{"Roster groups allowed to subscribe","Contactlijst-groepen die mogen abonneren"}. +{"Roster of ","Roster van "}. +{"Roster","Roster"}. +{"Roster size","Contactlijst Groote"}. +{"RPC Call Error","RPC-oproepfout"}. +{"Running Nodes","Draaiende nodes"}. +{"~s access rule configuration","Access rules op ~s"}. +{"Saturday","zaterdag"}. +{"Script check","Controle van script"}. +{"Search Results for ","Zoekresultaten voor "}. +{"Search users in ","Gebruikers zoeken in "}. +{"Send announcement to all online users","Mededeling verzenden naar alle online gebruikers"}. +{"Send announcement to all online users on all hosts","Mededeling verzenden naar alle online gebruikers op alle virtuele hosts"}. +{"Send announcement to all users","Mededeling verzenden naar alle gebruikers"}. +{"Send announcement to all users on all hosts","Stuur aankondiging aan alle gebruikers op alle hosts"}. +{"September","september"}. +{"Set message of the day and send to online users","Bericht van de dag instellen en verzenden naar online gebruikers"}. +{"Set message of the day on all hosts and send to online users","Stel bericht-van-de-dag in op alle hosts en stuur naar aanwezige gebruikers"}. +{"Shared Roster Groups","Gedeelde rostergroepen"}. +{"Show Integral Table","Volledige tabel laten zien"}. +{"Show Ordinary Table","Deel van tabel laten zien"}. +{"Shut Down Service","Stop Service"}. +{"~s invites you to the room ~s","~s nodigt je uit voor het groepsgesprek ~s"}. +{"Size","Grootte"}. +{"Specified nickname is already registered","De gekozen bijnaam is al geregistreerd"}. +{"Specify the access model","Geef toegangsmodel"}. +{"Specify the publisher model","Publicatietype opgeven"}. +{"~s's Offline Messages Queue","offline berichten van ~s"}. +{"Start Modules at ","Modules starten op "}. +{"Start Modules","Modules starten"}. +{"Start","Starten"}. +{"Statistics of ~p","Statistieken van ~p"}. +{"Statistics","Statistieken"}. +{"Stop Modules at ","Modules stoppen op "}. +{"Stop Modules","Modules stoppen"}. +{"Stopped Nodes","Gestopte nodes"}. +{"Stop","Stoppen"}. +{"Storage Type","Opslagmethode"}. +{"Store binary backup:","Binaire backup maken:"}. +{"Store plain text backup:","Backup naar een tekstbestand schrijven:"}. +{"Subject","Onderwerp"}. +{"Submitted","Verzonden"}. +{"Submit","Verzenden"}. +{"Subscriber Address","Abonnee Adres"}. +{"Subscription","Inschrijving"}. +{"Sunday","zondag"}. +{"the password is","het wachtwoord is"}. +{"This participant is kicked from the room because he sent an error message","Deze deelnemer wordt weggestuurd vanwege het sturen van een foutmeldingsbericht"}. +{"This participant is kicked from the room because he sent an error message to another participant","Deze deelnemer wordt weggestuurd vanwege het sturen van een foutmeldingsbericht aan een andere deelnemer"}. +{"This participant is kicked from the room because he sent an error presence","Deze deelnemer wordt weggestuurd vanwege het sturen van een foutmelding-aanwezigheid"}. +{"This room is not anonymous","Deze chatruimte is niet anoniem"}. +{"Thursday","donderdag"}. +{"Time delay","Vertraging"}. +{"Time","Tijd"}. +{"To","Aan"}. +{"To ~s","Naar ~s"}. +{"Traffic rate limit is exceeded","Dataverkeerslimiet overschreden"}. +{"Transactions Aborted:","Afgebroken transacties:"}. +{"Transactions Commited:","Bevestigde transacties:"}. +{"Transactions Logged:","Gelogde transacties:"}. +{"Transactions Restarted:","Herstarte transacties:"}. +{"Tuesday","dinsdag"}. +{"Update","Bijwerken"}. +{"Updated modules","Modules opwaarderen"}. +{"Update message of the day (don't send)","Bericht van de dag bijwerken (niet verzenden)"}. +{"Update message of the day on all hosts (don't send)","Verander bericht-van-de-dag op alle hosts (niet versturen)"}. +{"Update ","Opwaarderen van "}. +{"Update plan","Plan voor de opwaardering"}. +{"Update script","Script voor de opwaardering"}. +{"Uptime:","Uptime:"}. +{"Use of STARTTLS required","Gebruik van STARTTLS is vereist"}. +{"User ","Gebruiker "}. +{"User","Gebruiker"}. +{"User Management","Gebruikersbeheer"}. +{"Users are not allowed to register accounts so fast","Het is gebruikers niet toegestaan zo snel achter elkaar te registreren"}. +{"Users","Gebruikers"}. +{"Users Last Activity","Laatste activiteit van gebruikers"}. +{"Validate","Bevestigen"}. +{"vCard User Search","Gebruikers zoeken"}. +{"Virtual Hosts","Virtuele hosts"}. +{"Visitors are not allowed to change their nicknames in this room","Het is bezoekers niet toegestaan hun naam te veranderen in dit kanaal"}. +{"Visitors are not allowed to send messages to all occupants","Bezoekers mogen geen berichten verzenden naar alle aanwezigen"}. +{"Wednesday","woensdag"}. +{"When to send the last published item","Wanneer het laatst gepubliceerde item verzonden moet worden"}. +{"Whether to allow subscriptions","Abonnementsaanvraag toestaan"}. +{"You have been banned from this room","U werd verbannen uit deze chatruimte"}. +{"You must fill in field \"Nickname\" in the form","U moet het veld \"bijnaam\" invullen"}. +{"You need an x:data capable client to configure mod_irc settings","U hebt een client nodig die x:data ondersteunt om dit IRC-transport in te stellen"}. +{"You need an x:data capable client to configure room","U hebt een client nodig die x:data ondersteunt om deze chatruimte in te stellen"}. +{"You need an x:data capable client to register nickname","U hebt een client nodig die x:data ondersteunt om een bijnaam te registreren"}. +{"You need an x:data capable client to search","U hebt een client nodig die x:data ondersteunt om te zoeken"}. +{"Your contact offline message queue is full. The message has been discarded.","Te veel offline berichten voor dit contactpersoon. Het bericht is niet opgeslagen."}. diff --git a/src/msgs/nl.po b/src/msgs/nl.po new file mode 100644 index 000000000..9bea8ba03 --- /dev/null +++ b/src/msgs/nl.po @@ -0,0 +1,1508 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Andreas van Cranenburgh\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Dutch (nederlands)\n" +"X-Additional-Translator: Sander Devrieze\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "Gebruik van STARTTLS is vereist" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Geen bron opgegeven" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Vervangen door een nieuwe verbinding" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Commando's" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Wilt u het bericht van de dag verwijderen?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Onderwerp" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Bericht" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "De mededeling bevat geen bericht" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Mededelingen" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Mededeling verzenden naar alle gebruikers" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Stuur aankondiging aan alle gebruikers op alle hosts" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Mededeling verzenden naar alle online gebruikers" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "" +"Mededeling verzenden naar alle online gebruikers op alle virtuele hosts" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Bericht van de dag instellen en verzenden naar online gebruikers" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Stel bericht-van-de-dag in op alle hosts en stuur naar aanwezige gebruikers" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Bericht van de dag bijwerken (niet verzenden)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Verander bericht-van-de-dag op alle hosts (niet versturen)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Bericht van de dag verwijderen" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Verwijder bericht-van-de-dag op alle hosts" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Instellingen" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Database" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Modules starten" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Modules stoppen" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Backup" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Binaire backup direct herstellen" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Backup naar een tekstbestand schrijven" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Bestand importeren" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Directory importeren" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Herstart Service" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Stop Service" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Gebruiker toevoegen" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Verwijder Gebruiker" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Verwijder Gebruikers-sessie" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Gebruikerswachtwoord Opvragen" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Verander Gebruikerswachtwoord" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Tijd van Laatste Aanmelding Opvragen" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Gebruikers-statistieken Opvragen" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Aantal Geregistreerde Gebruikers Opvragen" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Aantal Aanwezige Gebruikers Opvragen" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Access control lists" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Access rules" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Gebruikersbeheer" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Online gebruikers" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Alle gebruikers" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Uitgaande s2s-verbindingen" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Draaiende nodes" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Gestopte nodes" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Modules" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Backup" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Importeer gebruikers via spool-bestanden van jabberd 1.4" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "Naar ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "Van ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Instellingen van databasetabellen op " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Opslagmethode voor tabellen kiezen" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Harde schijf" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "RAM en harde schijf" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "RAM" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Op andere nodes in de cluster" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Modules stoppen op " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Selecteer de modules die u wilt stoppen" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Modules starten op " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Voer lijst met op te starten modules als volgt in: {Module, [Opties]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Lijst met op te starten modules" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Binaire backup maken op " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Voer pad naar backupbestand in" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Pad naar bestand" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Binaire backup direct herstellen op " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Backup naar een tekstbestand schrijven op " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Voer pad naar backupbestand in" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Importeer gebruiker via bestand op " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Voer pad naar jabberd 1.4-spool-bestand in" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Gebruikers importeren vanaf directory op " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Voer pad naar jabberd 1.4-spool-directory in" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Pad naar directory" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Vertraging" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Instellingen van access control lists" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Access control lists" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Toegangsinstellingen" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Access rules" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Wachtwoord" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Wachtwoord Bevestiging" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Aantal Geregistreerde Gebruikers" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Aantal Aanwezige Gebruikers" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Nooit" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Online" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Laatste Aanmelding" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Contactlijst Groote" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "IP-adres" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Bronnen" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Beheer van " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Actie op gebruiker" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Eigenschappen bewerken" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Gebruiker verwijderen" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "De toegang werd geweigerd door het beleid van deze dienst" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "IRC Transport" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "ejabberd's IRC-module" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "" +"U hebt een client nodig die x:data ondersteunt om dit IRC-transport in te " +"stellen" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Registratie van " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Voer de gebruikersnaam en de coderingen in die u wilt gebruiken voor " +"verbindingen met IRC-servers" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "Gebruikersnaam voor IRC:" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Als u verschillende coderingen wilt opgeven voor elke IRC-server, ga dan " +"voor elke server te werk op als volgt: '{\"IRC-server\", \"codering\"}'. " +"Standaard gebruikt dit IRC-transport de codering \"~s\"." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Voorbeeld: [{\"irc.example.org\", \"koi8-r\"}, {\"vendetta.example.net\", " +"\"iso8859-1\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Coderingen:" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "" +"Alleen beheerders van deze dienst mogen mededelingen verzenden naar alle " +"chatruimtes" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "" +"De aanmaak van de chatruimte is verhinderd door de instellingen van deze " +"server" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "De chatruimte bestaat niet" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Groepsgesprekken" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "" +"U hebt een client nodig die x:data ondersteunt om een bijnaam te registreren" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Registratie van een bijnaam op " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Voer de bijnaam in die u wilt registreren" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Bijnaam" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "De gekozen bijnaam is al geregistreerd" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "U moet het veld \"bijnaam\" invullen" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "ejabberd's MUC module" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "De instellingen van de chatruimte werden veranderd" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "betrad de chatruimte" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "verliet de chatruimte" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "werd verbannen" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "werd gekicked" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "is weggestuurd vanwege een affiliatieverandering" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "" +"is weggestuurd omdat de chatruimte vanaf heden alleen toegankelijk is voor " +"leden" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "is weggestuurd omdat het systeem gestopt wordt" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "heet nu" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " veranderde het onderwerp in: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "maandag" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "dinsdag" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "woensdag" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "donderdag" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "vrijdag" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "zaterdag" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "zondag" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "januari" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "februari" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "maart" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "april" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "mei" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "juni" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "juli" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "augustus" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "september" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "oktober" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "november" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "december" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Instellingen van de chatruimte" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Naam van de chatruimte" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Dataverkeerslimiet overschreden" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" +"Deze deelnemer wordt weggestuurd vanwege het sturen van een " +"foutmeldingsbericht" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Er mogen geen privéberichten naar de chatruimte worden verzonden" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Onjuist berichttype" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Deze deelnemer wordt weggestuurd vanwege het sturen van een " +"foutmeldingsbericht aan een andere deelnemer" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "" +"Er mogen geen privéberichten van het type \"groupchat\" worden verzonden" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "De ontvanger is niet in de chatruimte" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Alleen aanwezigen mogen berichten naar de chatruimte verzenden" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "Het is niet toegestaan priveberichten te sturen" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Alleen aanwezigen mogen verzoeken verzenden naar de chatruimte" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "" +"Er mogen geen verzoeken verzenden worden naar deelnemers in deze chatruimte" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "privé, " + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "" +"Alleen moderators en deelnemers mogen het onderwerp van deze chatruimte " +"veranderen" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Alleen moderators mogen het onderwerp van deze chatruimte veranderen" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "Bezoekers mogen geen berichten verzenden naar alle aanwezigen" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" +"Deze deelnemer wordt weggestuurd vanwege het sturen van een foutmelding-" +"aanwezigheid" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Het is bezoekers niet toegestaan hun naam te veranderen in dit kanaal" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "Deze bijnaam is al in gebruik door een andere aanwezige" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "Deze bijnaam is al geregistreerd door iemand anders" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "U werd verbannen uit deze chatruimte" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "U moet lid zijn om deze chatruimte te kunnen betreden" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Deze chatruimte is niet anoniem" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "U hebt een wachtwoord nodig om deze chatruimte te kunnen betreden" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Foutief wachtwoord" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "U hebt beheerdersprivileges nodig" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "U hebt moderatorprivileges nodig" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "De Jabber ID ~s is ongeldig" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "De bijnaam ~s bestaat niet in deze chatruimte" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Ongeldige affiliatie: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Ongeldige rol: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "U hebt eigenaarsprivileges nodig" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Instellingen van " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Beschrijving:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Chatruimte blijvend maken" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Chatruimte doorzoekbaar maken" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Deelnemerslijst publiek maken" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Chatruimte beveiligen met een wachtwoord" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Maximum aantal aanwezigen" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Geen limiet" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Jabber ID's kunnen achterhaald worden door" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "moderators" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "iedereen" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Chatruimte enkel toegankelijk maken voor leden" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Chatruimte gemodereerd maken" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Gebruikers standaard instellen als deelnemers" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Gebruikers mogen het onderwerp veranderen" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Gebruikers mogen privéberichten verzenden" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Gebruikers mogen naar andere gebruikers verzoeken verzenden" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Gebruikers mogen uitnodigingen verzenden" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "Sta bezoekers toe hun statusbericht in te stellen" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Sta bezoekers toe hun naam te veranderen" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Logs aanzetten" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "" +"U hebt een client nodig die x:data ondersteunt om deze chatruimte in te " +"stellen" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Aantal aanwezigen" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s nodigt je uit voor het groepsgesprek ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "het wachtwoord is" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "" +"Te veel offline berichten voor dit contactpersoon. Het bericht is niet " +"opgeslagen." + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "offline berichten van ~s" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Verzonden" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Tijd" + +#: mod_offline.erl:507 +msgid "From" +msgstr "Van" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Aan" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Pakket" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Geselecteerde verwijderen" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Offline berichten:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "ejabberd SOCKS5 Bytestreams module" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Publish-Subscribe" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "ejabberd Publish-Subscribe module" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "PubSub abonnee verzoek" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Beslis of dit verzoek tot abonneren zal worden goedgekeurd" + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "Node ID" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Abonnee Adres" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Deze gebruiker toestaan te abonneren op deze pubsub node?" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Berichten bezorgen samen met gebeurtenisnotificaties" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Gebeurtenisbevestigingen Sturen" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Abonnees informeren wanneer de instellingen van de node veranderen" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Abonnees informeren wanneer de node verwijderd word" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Abonnees informeren wanneer items verwijderd worden uit de node" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Items in het geheugen bewaren" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "Bijnaam voor deze knoop" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Maximum aantal in het geheugen te bewaren items" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Abonnementsaanvraag toestaan" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Geef toegangsmodel" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Contactlijst-groepen die mogen abonneren" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Publicatietype opgeven" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Maximumgrootte van bericht in bytes" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Wanneer het laatst gepubliceerde item verzonden moet worden" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Notificaties alleen verzenden naar online gebruikers" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "" +"Kies een gebruikersnaam en een wachtwoord om u te registreren op deze server" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "Het is gebruikers niet toegestaan zo snel achter elkaar te registreren" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Geen" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Inschrijving" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Bezig" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Groepen" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Bevestigen" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Verwijderen" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Roster van " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Slecht formaat" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Jabber ID toevoegen" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Roster" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Gedeelde rostergroepen" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Toevoegen" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Naam:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Beschrijving:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Groepsleden:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Weergegeven groepen:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Groep " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Verzenden" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Erlang Jabber Server" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Geboortedatum" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Plaats" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "Land" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "E-mail" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Achternaam" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Gebruik de velden om te zoeken (Voeg achteraan het teken * toe om te zoeken " +"naar alles wat met het eerste deel begint.)." + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Volledige naam" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Tussennaam" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Naam" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Organisatie" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Afdeling" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Gebruikers zoeken in " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Gebruiker" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "U hebt een client nodig die x:data ondersteunt om te zoeken" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "Gebruikers zoeken" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "ejabberd's vCard-module" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Zoekresultaten voor " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Vul de velden in om te zoeken naar Jabber-gebruikers op deze server" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "ejabberd Webbeheer" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Beheer" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Virtuele hosts" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Nodes" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Statistieken" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Gebruikers" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Laatste activiteit" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Ruw)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Ruw" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "Access rules op ~s" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "Virtuele hosts" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Laatste activiteit van gebruikers" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Periode: " + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Afgelopen maand" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Afgelopen jaar" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Alle activiteit" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Deel van tabel laten zien" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Volledige tabel laten zien" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Node niet gevonden" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Host" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Geregistreerde gebruikers" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Offline berichten" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Geregistreerde gebruikers:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Online gebruikers:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Uitgaande s2s-verbindingen:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Uitgaande s2s-verbindingen:" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Wachtwoord wijzigen" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Gebruiker " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Verbonden bronnen:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Wachtwoord:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Geen gegevens" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Node " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Openstaande poorten" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Bijwerken" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Herstarten" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Stoppen" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "RPC-oproepfout" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Databasetabellen van " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Opslagmethode" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Grootte" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Geheugen" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Backup maken van " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Merk op dat volgende opties enkel backups maken van de ingebouwde database " +"Mnesia. Als u (een) andere database(s) gebruikt dan moet u daarvan (een) " +"afzonderlijke backup(s) maken." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Binaire backup maken:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "OK" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Binaire backup direct herstellen:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"Binaire backup herstellen na herstart van ejabberd (vereist minder geheugen):" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Backup naar een tekstbestand schrijven:" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Backup in een tekstbestand direct herstellen:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Openstaande poorten op " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Modules op " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "Statistieken van ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Uptime:" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "Processortijd:" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Bevestigde transacties:" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Afgebroken transacties:" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Herstarte transacties:" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Gelogde transacties:" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Opwaarderen van " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Plan voor de opwaardering" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Modules opwaarderen" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Script voor de opwaardering" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Lowlevel script voor de opwaardering" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Controle van script" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Poort" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Module" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Opties" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Verwijderen" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Starten" diff --git a/src/msgs/no.msg b/src/msgs/no.msg index c2be55d88..195381574 100644 --- a/src/msgs/no.msg +++ b/src/msgs/no.msg @@ -1,388 +1,343 @@ -% $Id$ -% Language: Norwegian (bokmål) -% Author: Stian B. Barmen - -% ejabberd_c2s.erl -{"Use of STARTTLS required", "Bruk av STARTTLS kreves"}. -{"Replaced by new connection", "Erstattet av en ny tilkobling"}. - -% jlib.hrl -{"No resource provided", "Ingen ressurs angitt"}. - -% mod_configure.erl -{"Database", "Database"}. -{"Restart Service", "Start Tjeneste på Nytt"}. -{"Shut Down Service", "Avslutt Tjeneste"}. -{"Delete User", "Slett Bruker"}. -{"End User Session", "Avslutt Bruker Sesjon"}. -{"Get User Password", "Hent Brukers Passord"}. -{"Change User Password", "Endre Brukers Passord"}. -{"Get User Last Login Time", "Vis Brukers Siste Påloggings Tidspunkt"}. -{"Get User Statistics", "Vis Bruker Statistikk"}. -{"Get Number of Registered Users", "Vis Antall Registrerte Brukere"}. -{"Get Number of Online Users", "Vis Antall Tilkoblede Brukere"}. -{"User Management", "Bruker Behandling"}. -{"Outgoing s2s Connections", "Utgående s2s Koblinger"}. -{"Import Users From jabberd 1.4 Spool Files", "Importer Brukere Fra jabberd 1.4 Spoolfiler"}. -{"Database Tables Configuration at ", "Database Tabell Konfigurasjon på "}. -{"Time delay", "Tids forsinkelse"}. -{"Password Verification", "Passord Bekreftelse"}. -{"Number of registered users", "Antall registrerte brukere"}. -{"Number of online users", "Antall tilkoblede brukere"}. -{"Last login", "Siste pålogging"}. -{"Roster size", "Kontaktliste størrelse"}. -{"IP addresses", "IP adresser"}. -{"Resources", "Ressurser"}. -{"Choose storage type of tables", "Velg lagringstype for tabeller"}. -{"RAM copy", "RAM kopi"}. -{"RAM and disc copy", "RAM og diskkopi"}. -{"Disc only copy", "Kun diskkopi"}. -{"Remote copy", "Lagres ikke lokalt"}. -{"Stop Modules at ", "Stopp Moduler på "}. -{"Choose modules to stop", "Velg hvilke moduler som skal stoppes"}. -{"Start Modules at ", "Start Moduler på "}. -{"Enter list of {Module, [Options]}", "Skriv inn en liste av {Module, [Options]}"}. -{"List of modules to start", "Liste over moduler som skal startes"}. -{"Backup to File at ", "Sikkerhetskopiere til Fil på "}. -{"Enter path to backup file", "Skriv inn sti til sikkerhetskopi filen"}. -{"Path to File", "Sti til Fil"}. -{"Restore Backup from File at ", "Gjenopprett fra Sikkerhetsopifil på "}. -{"Dump Backup to Text File at ", "Dump Sikkerhetskopi til Tekstfil på "}. -{"Enter path to text file", "Skriv inn sti til tekstfil"}. -{"Import User from File at ", "Importer Bruker fra Fil på "}. -{"Enter path to jabberd1.4 spool file", "Skriv inn sti til jabberd1.4 spoolfil"}. -{"Import Users from Dir at ", "Importer Brukere fra Katalog på "}. -{"Enter path to jabberd1.4 spool dir", "Skriv inn sti til jabberd1.4 spoolkatalog"}. -{"Path to Dir", "Sti til Katalog"}. -{"Access Control List Configuration", "Konfigurasjon for Tilgangskontroll lister"}. -{"Access control lists", "Tilgangskontroll lister"}. -{"Access Configuration", "Tilgangskonfigurasjon"}. -{"Access rules", "Tilgangsregler"}. -{"Administration of ", "Administrasjon av "}. -{"Action on user", "Handling på bruker"}. -{"Edit Properties", "Redigere Egenskaper"}. -{"Remove User", "Fjern Bruker"}. - -% mod_disco.erl -{"Configuration", "Konfigurasjon"}. -{"Online Users", "Tilkoblede Brukere"}. -{"All Users", "Alle Brukere"}. -{"To ~s", "Til ~s"}. -{"From ~s", "Fra ~s"}. -{"Running Nodes", "Kjørende Noder"}. -{"Stopped Nodes", "Stoppede Noder"}. -{"Access Control Lists", "Tilgangskontrollister"}. -{"Access Rules", "Tilgangsregler"}. -{"Modules", "Moduler"}. -{"Start Modules", "Start Moduler"}. -{"Stop Modules", "Stop Moduler"}. -{"Backup Management", "Håndtere Sikkerehetskopiering"}. -{"Backup", "Sikkerhetskopier"}. -{"Restore", "Gjenopprett"}. -{"Dump to Text File", "Dump til Tekstfil"}. -{"Import File", "Importer File"}. -{"Import Directory", "Importer Katalog"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Velg et brukernavn og passord for å registrere på denne serveren"}. - -% mod_vcard.erl -{"Erlang Jabber Server", "Erlang Jabber Server"}. -{"ejabberd vCard module", "ejabberd vCard modul"}. -{"You need an x:data capable client to search", "Du tregner en klient som støtter x:data for å kunne søke"}. -{"Search users in ", "Søk etter brukere i "}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Fyll inn skjemaet for å søke etter Jabber bruker (Legg til * på slutten av feltet for å treffe alle som starter slik)"}. -{"User", "Bruker"}. -{"Full Name", "Fullstendig Navn"}. -{"Name", "Fornavn"}. -{"Middle Name", "Mellomnavn"}. -{"Family Name", "Etternavn"}. -{"Nickname", "Kallenavn"}. -{"Birthday", "Fødselsdag"}. -{"Country", "Land"}. -{"City", "By"}. -{"Organization Name", "Organisasjonsnavn"}. -{"Organization Unit", "Organisasjonsenhet"}. - -% mod_vcard_ldap.erl -{"Fill in fields to search for any matching Jabber User", "Fyll inn felt for å søke etter Jabber brukere"}. - -% mod_vcard_odbc.erl -{"Email", "Epost"}. -{"vCard User Search", "vCard Bruker Søk"}. -{"Search Results for ", "Søke Resultater for "}. -{"Jabber ID", "Jabber ID"}. - -% mod_pubsub/mod_pubsub.erl -{"Roster groups allowed to subscribe", "Kontaktliste grupper som tillates å abonnere"}. -{"Publish-Subscribe", "Publish-Subscribe"}. -{"ejabberd Publish-Subscribe module", "ejabberd Publish-Subscribe modul"}. -{"PubSub subscriber request", "PubSub abonements forespørsel"}. -{"Choose whether to approve this entity's subscription.", "Velg om du vil godkjenne denne eksistensens abonement"}. -{"Node ID", "Node ID"}. -{"Subscriber Address", "Abonnements Adresse"}. -{"Allow this JID to subscribe to this pubsub node?", "Tillat denne JID å abonnere på denne pubsub noden?"}. -{"Deliver event notifications", "Lever begivenhets kunngjøringer"}. -{"Specify the access model", "Spesifiser aksess modellen"}. -{"When to send the last published item", "Når skal siste publiserte artikkel sendes"}. -{"Deliver payloads with event notifications", "Send innhold sammen med kunngjøringer"}. -{"Notify subscribers when the node configuration changes", "Informer abonnenter når node konfigurasjonen endres"}. -{"Notify subscribers when the node is deleted", "Informer abonnenter når noden slettes"}. -{"Notify subscribers when items are removed from the node", "Informer abonnenter når elementer fjernes fra noden"}. -{"Persist items to storage", "Vedvarende elementer til lagring"}. -{"Max # of items to persist", "Høyeste # elementer som skal lagres"}. -{"Whether to allow subscriptions", "Om man skal tillate abonnenter"}. -{"Specify the publisher model", "Angi publiserings modell"}. -{"Max payload size in bytes", "Største innholdsstørrelse i byte"}. -{"Only deliver notifications to available users", "Send kunngjøringer bare til tilgjengelige brukere"}. - -% mod_muc/mod_muc.erl -{"Chatrooms", "Samtalerom"}. -{"You must fill in field \"Nickname\" in the form", "Du må fylle inn feltet \"Nickname\" i skjemaet"}. -{"You need an x:data capable client to register nickname", "Du trenger en klient som søtter x:data for å registrere kallenavn"}. -{"Nickname Registration at ", "Registrer Kallenavn på "}. -{"Enter nickname you want to register", "Skriv inn kallenavnet du ønsker å registrere"}. -{"ejabberd MUC module", "ejabberd MUC modul"}. -{"Only service administrators are allowed to send service messages", "Bare tjeneste administratorer er tilatt å sende tjeneste meldinger"}. -{"Room creation is denied by service policy", "Oppretting av rom nektes av en tjenste regel"}. -{"Conference room does not exist", "Konferanserommet finnes ikke"}. -{"Access denied by service policy", "Tilgang nektes på grunn av en tjeneste regel"}. -{"You must fill in field \"nick\" in the form", "Du må fylle inn feltet \"nick\" i skjemaet"}. -{"Specified nickname is already registered", "Dette kallenavnet er allerede registrert"}. - -% mod_muc/mod_muc_room.erl -{"This participant is kicked from the room because he sent an error message", "Denne deltakeren er kastet ut av rommet fordi han sendte en feilmelding"}. -{"This participant is kicked from the room because he sent an error message to another participant", "Denne deltakeren er kastet ut av rommet fordi han sendte en feilmelding til en annen deltaker"}. -{"This participant is kicked from the room because he sent an error presence", "Denne deltakeren er kastet ut av rommet fordi han sendte feil tilstederværelse"}. -{"Make room moderated", "Gjør rommet redaktørstyrt"}. -{"Traffic rate limit is exceeded", "Trafikkmengde grense overskredet"}. -{"This room is not anonymous", "Dette rommet er ikke anonymt"}. -{"Make room persistent", "Gjør rommet permanent"}. -{"Make room public searchable", "Gjør rommet offentlig søkbart"}. -{"Make participants list public", "Gjør deltakerlisten offentlig"}. -{"Make room password protected", "Passordbeskytt rommet"}. -{"Maximum Number of Occupants", "Maksimum Antall Deltakere"}. -{"No limit", "Ingen grense"}. -{"Present real JIDs to", "Presenter ekte JIDer til"}. -{"moderators only", "kun for redaktører"}. -{"anyone", "hvem som helst"}. -{"Make room members-only", "Gjør rommet tilgjengelig kun for medlemmer"}. -{"Default users as participants", "Standard brukere som deltakere"}. -{"Allow users to change subject", "Tillat brukere å endre emne"}. -{"Allow users to send private messages", "Tillat brukere å sende private meldinger"}. -{"Allow users to query other users", "Tillat brukere å sende forespørsel til andre brukere"}. -{"Allow users to send invites", "Tillat brukere å sende invitasjoner"}. -{"Enable logging", "Slå på logging"}. -{"Number of occupants", "Antall deltakere"}. -{"~s invites you to the room ~s", "~s inviterer deg til rommet ~s"}. -{"the password is", "passordet er"}. -{" has set the subject to: ", " har satt emnet til: "}. -{"You need an x:data capable client to configure room", "Du trenger en klient som støtter x:data for å konfigurere rommet"}. -{"Configuration for ", "Konfigurasjon for "}. -{"Room title", "Romtittel"}. -{"Password", "Passord"}. -{"Only moderators and participants are allowed to change subject in this room", "Bare redaktører og deltakere kan endre emnet i dette rommet"}. -{"Only moderators are allowed to change subject in this room", "Bare redaktører kan endre emnet i dette rommet"}. -{"Visitors are not allowed to send messages to all occupants", "Besøkende får ikke sende meldinger til alle deltakere"}. -{"Only occupants are allowed to send messages to the conference", "Bare deltakere får sende normale meldinger til konferansen"}. -{"It is not allowed to send private messages to the conference", "Det er ikke tillatt å sende private meldinger til konferansen"}. -{"Improper message type", "Feilaktig meldingstype"}. -{"Nickname is already in use by another occupant", "Kallenavnet er allerede i bruk av en annen bruker"}. -{"Nickname is registered by another person", "Kallenavnet er reservert av en annen person"}. -{"It is not allowed to send private messages of type \"groupchat\"", "Det er ikke tillatt å sende private meldinger med typen \"groupchat\""}. -{"Recipient is not in the conference room", "Mottakeren er ikke i konferanserommet"}. -{"Only occupants are allowed to send queries to the conference", "Bare deltakere er tillatt å sende forespørsler til konferansen"}. -{"Queries to the conference members are not allowed in this room", "Det er ikke tillatt å sende forespørsler til deltakerene i dette rommet"}. -{"You have been banned from this room", "Du har blitt bannlyst i dette rommet."}. -{"Membership required to enter this room", "Du må være medlem for å gå inn i dette rommet"}. -{"Password required to enter this room", "Passord kreves for å komme inn i dette rommet"}. -{"Incorrect password", "Feil passord"}. -{"Administrator privileges required", "Administratorprivilegier kreves"}. -{"Moderator privileges required", "Redaktørprivilegier kreves"}. -{"JID ~s is invalid", "Ugyldig JID ~s"}. -{"Nickname ~s does not exist in the room", "Kallenavn ~s eksisterer ikke i dette rommet"}. -{"Invalid affiliation: ~s", "Ugyldig rang: ~s"}. -{"Invalid role: ~s", "Ugyldig rolle: ~s"}. -{"Owner privileges required", "Eierprivilegier kreves"}. -{"private, ", "privat, "}. - -% mod_irc/mod_irc.erl -{"IRC Transport", "IRC Transport"}. -{"ejabberd IRC module", "ejabberd IRC modul"}. -{"You need an x:data capable client to configure mod_irc settings", "Du trenger en klient som støtter x:data for å konfigurere mod_irc instillinger"}. -{"Registration in mod_irc for ", "Registrering i mod_irc for "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Skriv inn brukernavn og tekstkoding du ønsker å bruke for å koble til IRC tjenere"}. -{"IRC Username", "IRC Brukernavn"}. +{"Access Configuration","Tilgangskonfigurasjon"}. +{"Access Control List Configuration","Konfigurasjon for Tilgangskontroll lister"}. +{"Access Control Lists","Tilgangskontrollister"}. +{"Access control lists","Tilgangskontroll lister"}. +{"Access denied by service policy","Tilgang nektes på grunn av en tjeneste regel"}. +{"Access rules","Tilgangsregler"}. +{"Access Rules","Tilgangsregler"}. +{"Action on user","Handling på bruker"}. +{"Add Jabber ID","Legg til Jabber ID"}. +{"Add New","Legg til ny"}. +{"Add User","Legg til Bruker"}. +{"Administration","Administrasjon"}. +{"Administration of ","Administrasjon av "}. +{"Administrator privileges required","Administratorprivilegier kreves"}. +{"A friendly name for the node","Et vennlig navn for noden"}. +{"All activity","All aktivitet"}. +{"Allow this JID to subscribe to this pubsub node?","Tillat denne JID å abonnere på denne pubsub noden?"}. +{"Allow users to change subject","Tillat brukere å endre emne"}. +{"Allow users to query other users","Tillat brukere å sende forespørsel til andre brukere"}. +{"Allow users to send invites","Tillat brukere å sende invitasjoner"}. +{"Allow users to send private messages","Tillat brukere å sende private meldinger"}. +{"Allow visitors to change nickname","Tillat besøkende å endre kallenavn"}. +{"Allow visitors to send status text in presence updates","Tillat besøkende å sende status tekst i tilgjengelighets oppdateringer"}. +{"All Users","Alle Brukere"}. +{"Announcements","Kunngjøringer"}. +{"anyone","hvem som helst"}. +{"April","april"}. +{"August","august"}. +{"Backup Management","Håndtere Sikkerehetskopiering"}. +{"Backup of ","Sikkerhetskopi av "}. +{"Backup","Sikkerhetskopier"}. +{"Backup to File at ","Sikkerhetskopiere til Fil på "}. +{"Bad format","Feil format"}. +{"Birthday","Fødselsdag"}. +{"Change Password","Endre Passord"}. +{"Change User Password","Endre Brukers Passord"}. +{"Chatroom configuration modified","Samtalerommets konfigurasjon er endret"}. +{"Chatrooms","Samtalerom"}. +{"Choose a username and password to register with this server","Velg et brukernavn og passord for å registrere på denne serveren"}. +{"Choose modules to stop","Velg hvilke moduler som skal stoppes"}. +{"Choose storage type of tables","Velg lagringstype for tabeller"}. +{"Choose whether to approve this entity's subscription.","Velg om du vil godkjenne denne eksistensens abonement"}. +{"City","By"}. +{"Commands","Kommandoer"}. +{"Conference room does not exist","Konferanserommet finnes ikke"}. +{"Configuration for ","Konfigurasjon for "}. +{"Configuration","Konfigurasjon"}. +{"Connected Resources:","Tilkoblede Ressurser:"}. +{"Country","Land"}. +{"CPU Time:","CPU Tid:"}. +{"Database","Database"}. +{"Database Tables at ","Database Tabeller på "}. +{"Database Tables Configuration at ","Database Tabell Konfigurasjon på "}. +{"December","desember"}. +{"Default users as participants","Standard brukere som deltakere"}. +{"Delete message of the day on all hosts","Slett melding for dagen på alle maskiner"}. +{"Delete message of the day","Slett melding for dagen"}. +{"Delete Selected","Slett valgte"}. +{"Delete","Slett"}. +{"Delete User","Slett Bruker"}. +{"Deliver event notifications","Lever begivenhets kunngjøringer"}. +{"Deliver payloads with event notifications","Send innhold sammen med kunngjøringer"}. +{"Description:","Beskrivelse:"}. +{"Disc only copy","Kun diskkopi"}. +{"Displayed Groups:","Viste grupper:"}. +{"Dump Backup to Text File at ","Dump Sikkerhetskopi til Tekstfil på "}. +{"Dump to Text File","Dump til Tekstfil"}. +{"Edit Properties","Redigere Egenskaper"}. +{"ejabberd IRC module","ejabberd IRC modul"}. +{"ejabberd MUC module","ejabberd MUC modul"}. +{"ejabberd Publish-Subscribe module","ejabberd Publish-Subscribe modul"}. +{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestreams modul"}. +{"ejabberd vCard module","ejabberd vCard modul"}. +{"ejabberd virtual hosts","virtuella ejabberd maskiner"}. +{"ejabberd Web Admin","ejabberd Web Admin"}. +{"Email","Epost"}. +{"Enable logging","Slå på logging"}. +{"Encodings","Tekstkodinger"}. +{"End User Session","Avslutt Bruker Sesjon"}. +{"Enter list of {Module, [Options]}","Skriv inn en liste av {Module, [Options]}"}. +{"Enter nickname you want to register","Skriv inn kallenavnet du ønsker å registrere"}. +{"Enter path to backup file","Skriv inn sti til sikkerhetskopi filen"}. +{"Enter path to jabberd1.4 spool dir","Skriv inn sti til jabberd1.4 spoolkatalog"}. +{"Enter path to jabberd1.4 spool file","Skriv inn sti til jabberd1.4 spoolfil"}. +{"Enter path to text file","Skriv inn sti til tekstfil"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Skriv inn brukernavn og tekstkoding du ønsker å bruke for å koble til IRC tjenere"}. +{"Erlang Jabber Server","Erlang Jabber Server"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Eksempel: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","Etternavn"}. +{"February","februar"}. +{"Fill in fields to search for any matching Jabber User","Fyll inn felt for å søke etter Jabber brukere"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Fyll inn skjemaet for å søke etter Jabber bruker (Legg til * på slutten av feltet for å treffe alle som starter slik)"}. +{"Friday","fredag"}. +{"From","Fra"}. +{"From ~s","Fra ~s"}. +{"Full Name","Fullstendig Navn"}. +{"Get Number of Online Users","Vis Antall Tilkoblede Brukere"}. +{"Get Number of Registered Users","Vis Antall Registrerte Brukere"}. +{"Get User Last Login Time","Vis Brukers Siste Påloggings Tidspunkt"}. +{"Get User Password","Hent Brukers Passord"}. +{"Get User Statistics","Vis Bruker Statistikk"}. +{"Group ","Gruppe "}. +{"Groups","Grupper"}. +{"has been banned","har blitt bannlyst"}. +{"has been kicked because of an affiliation change","har blitt kastet ut på grunn av en tilknytnings endring"}. +{"has been kicked because of a system shutdown","har blitt kastet ut på grunn av at systemet avslutter"}. +{"has been kicked because the room has been changed to members-only","har blitt kastet ut på grunn av at rommet er endret til kun-for-medlemmer"}. +{"has been kicked","har blitt kastet ut"}. +{" has set the subject to: "," har satt emnet til: "}. +{"Host","Maskin"}. {"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Om du ønsker å spesifisere tekstkoding for IRC tjenere, fyller du ut en liste med verdier i formatet '{\"irc server\", \"encoding\"}'. Denne tjenesten bruker \"~s\" som standard."}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Eksempel: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"Encodings", "Tekstkodinger"}. - -% web/ejabberd_web_admin.erl -{"ejabberd Web Admin", "ejabberd Web Admin"}. -{"Administration", "Administrasjon"}. -{"(Raw)", "(Rå)"}. -{"Raw", "Rå"}. -{"Users Last Activity", "Brukers Siste Aktivitet"}. -{"Registered Users", "Registrerte Brukere"}. -{"Offline Messages", "Frakoblede Meldinger"}. -{"Registered Users:", "Registrerte Brukere:"}. -{"Online Users:", "Tilkoblede Brukere:"}. -{"Outgoing s2s Connections:", "Utgående s2s Koblinger"}. -{"Outgoing s2s Servers:", "Utgående s2s Tjenere"}. -{"No Data", "Ingen Data"}. -{"Listened Ports", "Lyttende Porter"}. -{"RPC Call Error", "RPC Kall Feil"}. -{"Database Tables at ", "Database Tabeller på "}. -{"Backup of ", "Sikkerhetskopi av "}. +{"Import Directory","Importer Katalog"}. +{"Import File","Importer File"}. +{"Import User from File at ","Importer Bruker fra Fil på "}. +{"Import Users from Dir at ","Importer Brukere fra Katalog på "}. +{"Import Users From jabberd 1.4 Spool Files","Importer Brukere Fra jabberd 1.4 Spoolfiler"}. +{"Improper message type","Feilaktig meldingstype"}. +{"Incorrect password","Feil passord"}. +{"Invalid affiliation: ~s","Ugyldig rang: ~s"}. +{"Invalid role: ~s","Ugyldig rolle: ~s"}. +{"IP addresses","IP adresser"}. +{"IRC Transport","IRC Transport"}. +{"IRC Username","IRC Brukernavn"}. +{"is now known as","er nå kjent som"}. +{"It is not allowed to send private messages","Det er ikke tillatt å sende private meldinger"}. +{"It is not allowed to send private messages of type \"groupchat\"","Det er ikke tillatt å sende private meldinger med typen \"groupchat\""}. +{"It is not allowed to send private messages to the conference","Det er ikke tillatt å sende private meldinger til konferansen"}. +{"Jabber ID","Jabber ID"}. +{"January","januar"}. +{"JID ~s is invalid","Ugyldig JID ~s"}. +{"joins the room","kommer inn i rommet"}. +{"July","juli"}. +{"June","juni"}. +{"Last Activity","Siste Aktivitet"}. +{"Last login","Siste pålogging"}. +{"Last month","Siste måned"}. +{"Last year","Siste året"}. +{"leaves the room","forlater rommet"}. +{"Listened Ports at ","Lyttende Porter på "}. +{"Listened Ports","Lyttende Porter"}. +{"List of modules to start","Liste over moduler som skal startes"}. +{"Low level update script","Lavnivå oppdaterings skript"}. +{"Make participants list public","Gjør deltakerlisten offentlig"}. +{"Make room members-only","Gjør rommet tilgjengelig kun for medlemmer"}. +{"Make room moderated","Gjør rommet redaktørstyrt"}. +{"Make room password protected","Passordbeskytt rommet"}. +{"Make room persistent","Gjør rommet permanent"}. +{"Make room public searchable","Gjør rommet offentlig søkbart"}. +{"March","mars"}. +{"Maximum Number of Occupants","Maksimum Antall Deltakere"}. +{"Max # of items to persist","Høyeste # elementer som skal lagres"}. +{"Max payload size in bytes","Største innholdsstørrelse i byte"}. +{"May","mai"}. +{"Membership required to enter this room","Du må være medlem for å gå inn i dette rommet"}. +{"Members:","Medlemmer:"}. +{"Memory","Minne"}. +{"Message body","Meldingskropp"}. +{"Middle Name","Mellomnavn"}. +{"Moderator privileges required","Redaktørprivilegier kreves"}. +{"moderators only","kun for redaktører"}. +{"Module","Modul"}. +{"Modules at ","Moduler på "}. +{"Modules","Moduler"}. +{"Monday","mandag"}. +{"Name:","Navn:"}. +{"Name","Navn"}. +{"Never","Aldri"}. +{"Nickname is already in use by another occupant","Kallenavnet er allerede i bruk av en annen bruker"}. +{"Nickname is registered by another person","Kallenavnet er reservert av en annen person"}. +{"Nickname","Kallenavn"}. +{"Nickname Registration at ","Registrer Kallenavn på "}. +{"Nickname ~s does not exist in the room","Kallenavn ~s eksisterer ikke i dette rommet"}. +{"No body provided for announce message","Ingen meldingskropp gitt for kunngjørings melding"}. +{"No Data","Ingen Data"}. +{"Node ID","Node ID"}. +{"Node ","Node "}. +{"Node not found","Noden finnes ikke"}. +{"Nodes","Noder"}. +{"No limit","Ingen grense"}. +{"None","Ingen"}. +{"No resource provided","Ingen ressurs angitt"}. +{"Notify subscribers when items are removed from the node","Informer abonnenter når elementer fjernes fra noden"}. +{"Notify subscribers when the node configuration changes","Informer abonnenter når node konfigurasjonen endres"}. +{"Notify subscribers when the node is deleted","Informer abonnenter når noden slettes"}. +{"November","november"}. +{"Number of occupants","Antall deltakere"}. +{"Number of online users","Antall tilkoblede brukere"}. +{"Number of registered users","Antall registrerte brukere"}. +{"October","oktober"}. +{"Offline Messages:","Frakoblede Meldinger:"}. +{"Offline Messages","Frakoblede Meldinger"}. +{"OK","OK"}. +{"Online","Tilkoblet"}. +{"Online Users:","Tilkoblede Brukere:"}. +{"Online Users","Tilkoblede Brukere"}. +{"Only deliver notifications to available users","Send kunngjøringer bare til tilgjengelige brukere"}. +{"Only moderators and participants are allowed to change subject in this room","Bare redaktører og deltakere kan endre emnet i dette rommet"}. +{"Only moderators are allowed to change subject in this room","Bare redaktører kan endre emnet i dette rommet"}. +{"Only occupants are allowed to send messages to the conference","Bare deltakere får sende normale meldinger til konferansen"}. +{"Only occupants are allowed to send queries to the conference","Bare deltakere er tillatt å sende forespørsler til konferansen"}. +{"Only service administrators are allowed to send service messages","Bare tjeneste administratorer er tilatt å sende tjeneste meldinger"}. +{"Options","Alternativer"}. +{"Organization Name","Organisasjonsnavn"}. +{"Organization Unit","Organisasjonsenhet"}. +{"Outgoing s2s Connections:","Utgående s2s Koblinger"}. +{"Outgoing s2s Connections","Utgående s2s Koblinger"}. +{"Outgoing s2s Servers:","Utgående s2s Tjenere"}. +{"Owner privileges required","Eierprivilegier kreves"}. +{"Packet","Pakke"}. +{"Password:","Passord:"}. +{"Password","Passord"}. +{"Password required to enter this room","Passord kreves for å komme inn i dette rommet"}. +{"Password Verification","Passord Bekreftelse"}. +{"Path to Dir","Sti til Katalog"}. +{"Path to File","Sti til Fil"}. +{"Pending","Ventende"}. +{"Period: ","Periode: "}. +{"Persist items to storage","Vedvarende elementer til lagring"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","Port"}. +{"Present real JIDs to","Presenter ekte JIDer til"}. +{"private, ","privat, "}. +{"Publish-Subscribe","Publish-Subscribe"}. +{"PubSub subscriber request","PubSub abonements forespørsel"}. +{"Queries to the conference members are not allowed in this room","Det er ikke tillatt å sende forespørsler til deltakerene i dette rommet"}. +{"RAM and disc copy","RAM og diskkopi"}. +{"RAM copy","RAM kopi"}. +{"(Raw)","(Rå)"}. +{"Raw","Rå"}. +{"Really delete message of the day?","Virkelig slette melding for dagen?"}. +{"Recipient is not in the conference room","Mottakeren er ikke i konferanserommet"}. +{"Registered Users:","Registrerte Brukere:"}. +{"Registered Users","Registrerte Brukere"}. +{"Registration in mod_irc for ","Registrering i mod_irc for "}. {"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Merk at disse valgene vil bare sikkerhetskopiere den innebygde Mnesia databasen. Dersom du bruker ODBC modulen må du også ta backup av din SQL database."}. -{"Store binary backup:", "Lagre binær sikkerhetskopi:"}. -{"Restore binary backup immediately:", "Gjenopprette binær backup umiddelbart:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Gjenopprette binær backup etter neste ejabberd omstart (krever mindre minne):"}. -{"Store plain text backup:", "Lagre rentekst sikkerhetskopi:"}. -{"Restore plain text backup immediately:", "Gjenopprette rentekst sikkerhetskopi umiddelbart:"}. -{"Statistics of ~p", "Statistikk for ~p"}. -{"Uptime:", "Oppetid:"}. -{"CPU Time:", "CPU Tid:"}. -{"Transactions Commited:", "Sendte Transaksjoner:"}. -{"Transactions Aborted:", "Avbrutte Transasksjoner:"}. -{"Transactions Restarted:", "Omstartede Transasksjoner:"}. -{"Transactions Logged:", "Loggede Transasksjoner:"}. -{"Update ", "Oppdater "}. -{"Update plan", "Oppdaterings plan"}. -{"Updated modules", "Oppdater moduler"}. -{"Update script", "Oppdaterings skript"}. -{"Low level update script", "Lavnivå oppdaterings skript"}. -{"Script check", "Skript sjekk"}. -{"Users", "Brukere"}. -{"Nodes", "Noder"}. -{"Statistics", "Statistikk"}. -{"Delete Selected", "Slett valgte"}. -{"Submit", "Send"}. -{"~s access rule configuration", "tilgangsregel konfigurasjon for ~s"}. -{"Node not found", "Noden finnes ikke"}. -{"Add New", "Legg til ny"}. -{"Change Password", "Endre Passord"}. -{"Connected Resources:", "Tilkoblede Ressurser:"}. -{"Password:", "Passord:"}. -{"None", "Ingen"}. -{"Node ", "Node "}. -{"Restart", "Starte på nytt"}. -{"Stop", "Stoppe"}. -{"Name", "Navn"}. -{"Storage Type", "Lagringstype"}. -{"Size", "Størrelse"}. -{"Memory", "Minne"}. -{"OK", "OK"}. -{"Listened Ports at ", "Lyttende Porter på "}. -{"Port", "Port"}. -{"Module", "Modul"}. -{"Options", "Alternativer"}. -{"Update", "Oppdatere"}. -{"Delete", "Slett"}. -{"Add User", "Legg til Bruker"}. -{"Last Activity", "Siste Aktivitet"}. -{"Never", "Aldri"}. -{"Time", "Tid"}. -{"From", "Fra"}. -{"To", "Til"}. -{"Packet", "Pakke"}. -{"Roster", "Kontaktliste"}. -{"Nickname", "Kallenavn"}. -{"Subscription", "Abonnement"}. -{"Pending", "Ventende"}. -{"Groups", "Grupper"}. -{"Remove", "Fjern"}. -{"User ", "Bruker "}. -{"Roster of ", "Kontaktliste for "}. -{"Online", "Tilkoblet"}. -{"Validate", "Bekrefte gyldighet"}. -{"Name:", "Navn:"}. -{"Description:", "Beskrivelse:"}. -{"Members:", "Medlemmer:"}. -{"Displayed Groups:", "Viste grupper:"}. -{"Group ", "Gruppe "}. -{"Virtual Hosts", "Virtuelle Maskiner"}. -{"ejabberd virtual hosts", "virtuella ejabberd maskiner"}. -{"Period: ", "Periode: "}. -{"Last month", "Siste måned"}. -{"Last year", "Siste året"}. -{"All activity", "All aktivitet"}. -{"Show Ordinary Table", "Vis Ordinær Tabell"}. -{"Show Integral Table", "Vis Integral Tabell"}. -{"Host", "Maskin"}. -{"Modules at ", "Moduler på "}. -{"Start", "Start"}. - -% mod_roster.erl -{"Submitted", "Innsendt"}. -{"Bad format", "Feil format"}. -{"Add Jabber ID", "Legg til Jabber ID"}. - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "Kontaktens frakoblede meldingskø er full. Meldingen har blitt kassert."}. -{"~s's Offline Messages Queue", "~ss kø for Frakoblede Meldinger"}. -{"Offline Messages:", "Frakoblede Meldinger:"}. - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "ejabberd SOCKS5 Bytestreams modul"}. - -% mod_shared_roster.erl -{"Shared Roster Groups", "Delte Kontaktgrupper"}. - -% mod_announce.erl -{"Really delete message of the day?", "Virkelig slette melding for dagen?"}. -{"Subject", "Tittel"}. -{"Message body", "Meldingskropp"}. -{"No body provided for announce message", "Ingen meldingskropp gitt for kunngjørings melding"}. -{"Announcements", "Kunngjøringer"}. -{"Send announcement to all users", "Send kunngjøring til alle brukere"}. -{"Send announcement to all users on all hosts", "Send kunngjøring til alle brukere på alle maskiner"}. -{"Send announcement to all online users", "Send kunngjøring alle tilkoblede brukere"}. -{"Send announcement to all online users on all hosts", "Send kunngjøring til alle tilkoblede brukere på alle maskiner"}. -{"Set message of the day and send to online users", "Angi melding for dagen og send til tilkoblede brukere"}. -{"Set message of the day on all hosts and send to online users", "Angi melding for dagen på alle maskiner og send til tilkoblede brukere"}. -{"Update message of the day (don't send)", "Oppdater melding for dagen (ikke send)"}. -{"Update message of the day on all hosts (don't send)", "Oppdater melding for dagen på alle maskiner (ikke send)"}. -{"Delete message of the day", "Slett melding for dagen"}. -{"Delete message of the day on all hosts", "Slett melding for dagen på alle maskiner"}. - -% mod_adhoc.erl -{"Commands", "Kommandoer"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% mod_muc/mod_muc_log.erl -{"Chatroom configuration modified", "Samtalerommets konfigurasjon er endret"}. -{"joins the room", "kommer inn i rommet"}. -{"leaves the room", "forlater rommet"}. -{"has been banned", "har blitt bannlyst"}. -{"has been kicked", "har blitt kastet ut"}. -{"has been kicked because of an affiliation change", "har blitt kastet ut på grunn av en tilknytnings endring"}. -{"has been kicked because the room has been changed to members-only", "har blitt kastet ut på grunn av at rommet er endret til kun-for-medlemmer"}. -{"has been kicked because of a system shutdown", "har blitt kastet ut på grunn av at systemet avslutter"}. -{"is now known as", "er nå kjent som"}. -{"Monday", "mandag"}. -{"Tuesday", "tirsdag"}. -{"Wednesday", "onsdag"}. -{"Thursday", "torsdag"}. -{"Friday", "fredag"}. -{"Saturday", "lørdag"}. -{"Sunday", "søndag"}. -{"January", "januar"}. -{"February", "februar"}. -{"March", "mars"}. -{"April", "april"}. -{"May", "mai"}. -{"June", "juni"}. -{"July", "juli"}. -{"August", "august"}. -{"September", "september"}. -{"October", "oktober"}. -{"November", "november"}. -{"December", "desember"}. -{"Room Configuration", "Rom Konfigurasjon"}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Remote copy","Lagres ikke lokalt"}. +{"Remove","Fjern"}. +{"Remove User","Fjern Bruker"}. +{"Replaced by new connection","Erstattet av en ny tilkobling"}. +{"Resources","Ressurser"}. +{"Restart Service","Start Tjeneste på Nytt"}. +{"Restart","Starte på nytt"}. +{"Restore Backup from File at ","Gjenopprett fra Sikkerhetsopifil på "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Gjenopprette binær backup etter neste ejabberd omstart (krever mindre minne):"}. +{"Restore binary backup immediately:","Gjenopprette binær backup umiddelbart:"}. +{"Restore","Gjenopprett"}. +{"Restore plain text backup immediately:","Gjenopprette rentekst sikkerhetskopi umiddelbart:"}. +{"Room Configuration","Rom Konfigurasjon"}. +{"Room creation is denied by service policy","Oppretting av rom nektes av en tjenste regel"}. +{"Room title","Romtittel"}. +{"Roster groups allowed to subscribe","Kontaktliste grupper som tillates å abonnere"}. +{"Roster","Kontaktliste"}. +{"Roster of ","Kontaktliste for "}. +{"Roster size","Kontaktliste størrelse"}. +{"RPC Call Error","RPC Kall Feil"}. +{"Running Nodes","Kjørende Noder"}. +{"~s access rule configuration","tilgangsregel konfigurasjon for ~s"}. +{"Saturday","lørdag"}. +{"Script check","Skript sjekk"}. +{"Search Results for ","Søke Resultater for "}. +{"Search users in ","Søk etter brukere i "}. +{"Send announcement to all online users on all hosts","Send kunngjøring til alle tilkoblede brukere på alle maskiner"}. +{"Send announcement to all online users","Send kunngjøring alle tilkoblede brukere"}. +{"Send announcement to all users on all hosts","Send kunngjøring til alle brukere på alle maskiner"}. +{"Send announcement to all users","Send kunngjøring til alle brukere"}. +{"September","september"}. +{"Set message of the day and send to online users","Angi melding for dagen og send til tilkoblede brukere"}. +{"Set message of the day on all hosts and send to online users","Angi melding for dagen på alle maskiner og send til tilkoblede brukere"}. +{"Shared Roster Groups","Delte Kontaktgrupper"}. +{"Show Integral Table","Vis Integral Tabell"}. +{"Show Ordinary Table","Vis Ordinær Tabell"}. +{"Shut Down Service","Avslutt Tjeneste"}. +{"~s invites you to the room ~s","~s inviterer deg til rommet ~s"}. +{"Size","Størrelse"}. +{"Specified nickname is already registered","Dette kallenavnet er allerede registrert"}. +{"Specify the access model","Spesifiser aksess modellen"}. +{"Specify the publisher model","Angi publiserings modell"}. +{"~s's Offline Messages Queue","~ss kø for Frakoblede Meldinger"}. +{"Start Modules at ","Start Moduler på "}. +{"Start Modules","Start Moduler"}. +{"Start","Start"}. +{"Statistics of ~p","Statistikk for ~p"}. +{"Statistics","Statistikk"}. +{"Stop Modules at ","Stopp Moduler på "}. +{"Stop Modules","Stop Moduler"}. +{"Stopped Nodes","Stoppede Noder"}. +{"Stop","Stoppe"}. +{"Storage Type","Lagringstype"}. +{"Store binary backup:","Lagre binær sikkerhetskopi:"}. +{"Store plain text backup:","Lagre rentekst sikkerhetskopi:"}. +{"Subject","Tittel"}. +{"Submit","Send"}. +{"Submitted","Innsendt"}. +{"Subscriber Address","Abonnements Adresse"}. +{"Subscription","Abonnement"}. +{"Sunday","søndag"}. +{"the password is","passordet er"}. +{"This participant is kicked from the room because he sent an error message","Denne deltakeren er kastet ut av rommet fordi han sendte en feilmelding"}. +{"This participant is kicked from the room because he sent an error message to another participant","Denne deltakeren er kastet ut av rommet fordi han sendte en feilmelding til en annen deltaker"}. +{"This participant is kicked from the room because he sent an error presence","Denne deltakeren er kastet ut av rommet fordi han sendte feil tilstederværelse"}. +{"This room is not anonymous","Dette rommet er ikke anonymt"}. +{"Thursday","torsdag"}. +{"Time delay","Tids forsinkelse"}. +{"Time","Tid"}. +{"To ~s","Til ~s"}. +{"To","Til"}. +{"Traffic rate limit is exceeded","Trafikkmengde grense overskredet"}. +{"Transactions Aborted:","Avbrutte Transasksjoner:"}. +{"Transactions Commited:","Sendte Transaksjoner:"}. +{"Transactions Logged:","Loggede Transasksjoner:"}. +{"Transactions Restarted:","Omstartede Transasksjoner:"}. +{"Tuesday","tirsdag"}. +{"Updated modules","Oppdater moduler"}. +{"Update message of the day (don't send)","Oppdater melding for dagen (ikke send)"}. +{"Update message of the day on all hosts (don't send)","Oppdater melding for dagen på alle maskiner (ikke send)"}. +{"Update ","Oppdater "}. +{"Update","Oppdatere"}. +{"Update plan","Oppdaterings plan"}. +{"Update script","Oppdaterings skript"}. +{"Uptime:","Oppetid:"}. +{"Use of STARTTLS required","Bruk av STARTTLS kreves"}. +{"User ","Bruker "}. +{"User","Bruker"}. +{"User Management","Bruker Behandling"}. +{"Users are not allowed to register accounts so fast","Brukere får ikke lov til å registrere kontoer så fort"}. +{"Users","Brukere"}. +{"Users Last Activity","Brukers Siste Aktivitet"}. +{"Validate","Bekrefte gyldighet"}. +{"vCard User Search","vCard Bruker Søk"}. +{"Virtual Hosts","Virtuelle Maskiner"}. +{"Visitors are not allowed to change their nicknames in this room","Besøkende får ikke lov å endre kallenavn i dette rommet"}. +{"Visitors are not allowed to send messages to all occupants","Besøkende får ikke sende meldinger til alle deltakere"}. +{"Wednesday","onsdag"}. +{"When to send the last published item","Når skal siste publiserte artikkel sendes"}. +{"Whether to allow subscriptions","Om man skal tillate abonnenter"}. +{"You have been banned from this room","Du har blitt bannlyst i dette rommet."}. +{"You must fill in field \"Nickname\" in the form","Du må fylle inn feltet \"Nickname\" i skjemaet"}. +{"You need an x:data capable client to configure mod_irc settings","Du trenger en klient som støtter x:data for å konfigurere mod_irc instillinger"}. +{"You need an x:data capable client to configure room","Du trenger en klient som støtter x:data for å konfigurere rommet"}. +{"You need an x:data capable client to register nickname","Du trenger en klient som søtter x:data for å registrere kallenavn"}. +{"You need an x:data capable client to search","Du tregner en klient som støtter x:data for å kunne søke"}. +{"Your contact offline message queue is full. The message has been discarded.","Kontaktens frakoblede meldingskø er full. Meldingen har blitt kassert."}. diff --git a/src/msgs/no.po b/src/msgs/no.po new file mode 100644 index 000000000..7a8448eee --- /dev/null +++ b/src/msgs/no.po @@ -0,0 +1,1493 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Stian B. Barmen\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Norwegian (bokmål)\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "Bruk av STARTTLS kreves" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Ingen ressurs angitt" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Erstattet av en ny tilkobling" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Kommandoer" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Virkelig slette melding for dagen?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Tittel" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Meldingskropp" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "Ingen meldingskropp gitt for kunngjørings melding" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Kunngjøringer" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Send kunngjøring til alle brukere" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Send kunngjøring til alle brukere på alle maskiner" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Send kunngjøring alle tilkoblede brukere" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "Send kunngjøring til alle tilkoblede brukere på alle maskiner" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Angi melding for dagen og send til tilkoblede brukere" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "Angi melding for dagen på alle maskiner og send til tilkoblede brukere" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Oppdater melding for dagen (ikke send)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Oppdater melding for dagen på alle maskiner (ikke send)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Slett melding for dagen" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Slett melding for dagen på alle maskiner" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Konfigurasjon" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Database" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Start Moduler" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Stop Moduler" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Sikkerhetskopier" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Gjenopprett" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Dump til Tekstfil" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Importer File" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Importer Katalog" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Start Tjeneste på Nytt" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Avslutt Tjeneste" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Legg til Bruker" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Slett Bruker" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Avslutt Bruker Sesjon" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Hent Brukers Passord" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Endre Brukers Passord" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Vis Brukers Siste Påloggings Tidspunkt" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Vis Bruker Statistikk" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Vis Antall Registrerte Brukere" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Vis Antall Tilkoblede Brukere" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Tilgangskontrollister" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Tilgangsregler" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Bruker Behandling" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Tilkoblede Brukere" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Alle Brukere" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Utgående s2s Koblinger" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Kjørende Noder" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Stoppede Noder" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Moduler" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Håndtere Sikkerehetskopiering" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Importer Brukere Fra jabberd 1.4 Spoolfiler" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "Til ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "Fra ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Database Tabell Konfigurasjon på " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Velg lagringstype for tabeller" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Kun diskkopi" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "RAM og diskkopi" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "RAM kopi" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Lagres ikke lokalt" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Stopp Moduler på " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Velg hvilke moduler som skal stoppes" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Start Moduler på " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Skriv inn en liste av {Module, [Options]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Liste over moduler som skal startes" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Sikkerhetskopiere til Fil på " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Skriv inn sti til sikkerhetskopi filen" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Sti til Fil" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Gjenopprett fra Sikkerhetsopifil på " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Dump Sikkerhetskopi til Tekstfil på " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Skriv inn sti til tekstfil" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Importer Bruker fra Fil på " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Skriv inn sti til jabberd1.4 spoolfil" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Importer Brukere fra Katalog på " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Skriv inn sti til jabberd1.4 spoolkatalog" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Sti til Katalog" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Tids forsinkelse" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Konfigurasjon for Tilgangskontroll lister" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Tilgangskontroll lister" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Tilgangskonfigurasjon" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Tilgangsregler" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Passord" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Passord Bekreftelse" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Antall registrerte brukere" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Antall tilkoblede brukere" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Aldri" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Tilkoblet" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Siste pålogging" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Kontaktliste størrelse" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "IP adresser" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Ressurser" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Administrasjon av " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Handling på bruker" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Redigere Egenskaper" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Fjern Bruker" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Tilgang nektes på grunn av en tjeneste regel" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "IRC Transport" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "ejabberd IRC modul" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "" +"Du trenger en klient som støtter x:data for å konfigurere mod_irc " +"instillinger" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Registrering i mod_irc for " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Skriv inn brukernavn og tekstkoding du ønsker å bruke for å koble til IRC " +"tjenere" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "IRC Brukernavn" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Om du ønsker å spesifisere tekstkoding for IRC tjenere, fyller du ut en " +"liste med verdier i formatet '{\"irc server\", \"encoding\"}'. Denne " +"tjenesten bruker \"~s\" som standard." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Eksempel: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-" +"1\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Tekstkodinger" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "Bare tjeneste administratorer er tilatt å sende tjeneste meldinger" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "Oppretting av rom nektes av en tjenste regel" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "Konferanserommet finnes ikke" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Samtalerom" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "Du trenger en klient som søtter x:data for å registrere kallenavn" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Registrer Kallenavn på " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Skriv inn kallenavnet du ønsker å registrere" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Kallenavn" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "Dette kallenavnet er allerede registrert" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Du må fylle inn feltet \"Nickname\" i skjemaet" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "ejabberd MUC modul" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Samtalerommets konfigurasjon er endret" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "kommer inn i rommet" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "forlater rommet" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "har blitt bannlyst" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "har blitt kastet ut" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "har blitt kastet ut på grunn av en tilknytnings endring" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "" +"har blitt kastet ut på grunn av at rommet er endret til kun-for-medlemmer" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "har blitt kastet ut på grunn av at systemet avslutter" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "er nå kjent som" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " har satt emnet til: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "mandag" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "tirsdag" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "onsdag" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "torsdag" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "fredag" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "lørdag" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "søndag" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "januar" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "februar" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "mars" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "april" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "mai" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "juni" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "juli" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "august" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "september" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "oktober" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "november" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "desember" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Rom Konfigurasjon" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Romtittel" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Trafikkmengde grense overskredet" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" +"Denne deltakeren er kastet ut av rommet fordi han sendte en feilmelding" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Det er ikke tillatt å sende private meldinger til konferansen" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Feilaktig meldingstype" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Denne deltakeren er kastet ut av rommet fordi han sendte en feilmelding til " +"en annen deltaker" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "Det er ikke tillatt å sende private meldinger med typen \"groupchat\"" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "Mottakeren er ikke i konferanserommet" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Bare deltakere får sende normale meldinger til konferansen" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "Det er ikke tillatt å sende private meldinger" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Bare deltakere er tillatt å sende forespørsler til konferansen" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "" +"Det er ikke tillatt å sende forespørsler til deltakerene i dette rommet" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "privat, " + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "Bare redaktører og deltakere kan endre emnet i dette rommet" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Bare redaktører kan endre emnet i dette rommet" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "Besøkende får ikke sende meldinger til alle deltakere" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" +"Denne deltakeren er kastet ut av rommet fordi han sendte feil " +"tilstederværelse" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Besøkende får ikke lov å endre kallenavn i dette rommet" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "Kallenavnet er allerede i bruk av en annen bruker" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "Kallenavnet er reservert av en annen person" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Du har blitt bannlyst i dette rommet." + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "Du må være medlem for å gå inn i dette rommet" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Dette rommet er ikke anonymt" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Passord kreves for å komme inn i dette rommet" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Feil passord" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Administratorprivilegier kreves" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Redaktørprivilegier kreves" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "Ugyldig JID ~s" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "Kallenavn ~s eksisterer ikke i dette rommet" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Ugyldig rang: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Ugyldig rolle: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Eierprivilegier kreves" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Konfigurasjon for " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Beskrivelse:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Gjør rommet permanent" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Gjør rommet offentlig søkbart" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Gjør deltakerlisten offentlig" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Passordbeskytt rommet" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Maksimum Antall Deltakere" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Ingen grense" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Presenter ekte JIDer til" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "kun for redaktører" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "hvem som helst" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Gjør rommet tilgjengelig kun for medlemmer" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Gjør rommet redaktørstyrt" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Standard brukere som deltakere" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Tillat brukere å endre emne" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Tillat brukere å sende private meldinger" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Tillat brukere å sende forespørsel til andre brukere" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Tillat brukere å sende invitasjoner" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "Tillat besøkende å sende status tekst i tilgjengelighets oppdateringer" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Tillat besøkende å endre kallenavn" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Slå på logging" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "Du trenger en klient som støtter x:data for å konfigurere rommet" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Antall deltakere" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s inviterer deg til rommet ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "passordet er" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "Kontaktens frakoblede meldingskø er full. Meldingen har blitt kassert." + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "~ss kø for Frakoblede Meldinger" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Innsendt" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Tid" + +#: mod_offline.erl:507 +msgid "From" +msgstr "Fra" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Til" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Pakke" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Slett valgte" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Frakoblede Meldinger:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "ejabberd SOCKS5 Bytestreams modul" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Publish-Subscribe" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "ejabberd Publish-Subscribe modul" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "PubSub abonements forespørsel" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Velg om du vil godkjenne denne eksistensens abonement" + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "Node ID" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Abonnements Adresse" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Tillat denne JID å abonnere på denne pubsub noden?" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Send innhold sammen med kunngjøringer" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Lever begivenhets kunngjøringer" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Informer abonnenter når node konfigurasjonen endres" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Informer abonnenter når noden slettes" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Informer abonnenter når elementer fjernes fra noden" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Vedvarende elementer til lagring" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "Et vennlig navn for noden" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Høyeste # elementer som skal lagres" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Om man skal tillate abonnenter" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Spesifiser aksess modellen" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Kontaktliste grupper som tillates å abonnere" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Angi publiserings modell" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Største innholdsstørrelse i byte" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Når skal siste publiserte artikkel sendes" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Send kunngjøringer bare til tilgjengelige brukere" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "Velg et brukernavn og passord for å registrere på denne serveren" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "Brukere får ikke lov til å registrere kontoer så fort" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Ingen" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Abonnement" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Ventende" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Grupper" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Bekrefte gyldighet" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Fjern" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Kontaktliste for " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Feil format" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Legg til Jabber ID" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Kontaktliste" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Delte Kontaktgrupper" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Legg til ny" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Navn:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Beskrivelse:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Medlemmer:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Viste grupper:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Gruppe " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Send" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Erlang Jabber Server" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Fødselsdag" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "By" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "Land" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "Epost" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Etternavn" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Fyll inn skjemaet for å søke etter Jabber bruker (Legg til * på slutten av " +"feltet for å treffe alle som starter slik)" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Fullstendig Navn" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Mellomnavn" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Navn" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Organisasjonsnavn" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Organisasjonsenhet" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Søk etter brukere i " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Bruker" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "Du tregner en klient som støtter x:data for å kunne søke" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "vCard Bruker Søk" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "ejabberd vCard modul" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Søke Resultater for " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Fyll inn felt for å søke etter Jabber brukere" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "ejabberd Web Admin" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Administrasjon" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Virtuelle Maskiner" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Noder" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Statistikk" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Brukere" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Siste Aktivitet" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Rå)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Rå" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "tilgangsregel konfigurasjon for ~s" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "virtuella ejabberd maskiner" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Brukers Siste Aktivitet" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Periode: " + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Siste måned" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Siste året" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "All aktivitet" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Vis Ordinær Tabell" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Vis Integral Tabell" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Noden finnes ikke" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Maskin" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Registrerte Brukere" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Frakoblede Meldinger" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Registrerte Brukere:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Tilkoblede Brukere:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Utgående s2s Koblinger" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Utgående s2s Tjenere" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Endre Passord" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Bruker " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Tilkoblede Ressurser:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Passord:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Ingen Data" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Node " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Lyttende Porter" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Oppdatere" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Starte på nytt" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Stoppe" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "RPC Kall Feil" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Database Tabeller på " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Lagringstype" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Størrelse" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Minne" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Sikkerhetskopi av " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Merk at disse valgene vil bare sikkerhetskopiere den innebygde Mnesia " +"databasen. Dersom du bruker ODBC modulen må du også ta backup av din SQL " +"database." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Lagre binær sikkerhetskopi:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "OK" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Gjenopprette binær backup umiddelbart:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"Gjenopprette binær backup etter neste ejabberd omstart (krever mindre minne):" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Lagre rentekst sikkerhetskopi:" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Gjenopprette rentekst sikkerhetskopi umiddelbart:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Lyttende Porter på " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Moduler på " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "Statistikk for ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Oppetid:" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "CPU Tid:" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Sendte Transaksjoner:" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Avbrutte Transasksjoner:" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Omstartede Transasksjoner:" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Loggede Transasksjoner:" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Oppdater " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Oppdaterings plan" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Oppdater moduler" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Oppdaterings skript" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Lavnivå oppdaterings skript" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Skript sjekk" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Port" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Modul" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Alternativer" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Slett" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Start" + +#~ msgid "You must fill in field \"nick\" in the form" +#~ msgstr "Du må fylle inn feltet \"nick\" i skjemaet" diff --git a/src/msgs/pl.msg b/src/msgs/pl.msg index da91ad477..bc849bea3 100644 --- a/src/msgs/pl.msg +++ b/src/msgs/pl.msg @@ -1,421 +1,343 @@ -% $Id$ -% Language: Polish (polski) -% Author: Andrzej Smyk -% Author: Mateusz Gajewski -% Author: Zbyszek Zolkiewski - -% jlib.hrl -{"No resource provided", "Brak dostarczonych zasobów"}. - -% mod_configure.erl -{"Restart Service", "Restart serwisu"}. -{"Shut Down Service", "Wyłączenie serwisu"}. -{"Delete User", "Usuń użytkownika"}. -{"End User Session", "Zakończ sesję uzytkownika"}. -{"Get User Password", "Pobierz hasło użytkownika"}. -{"Change User Password", "Zmień hasło użytkownika"}. -{"Get User Last Login Time", "Pokaż czas ostatniego zalogowania uzytkownika"}. -{"Get User Statistics", "Pobierz statystyki użytkownika"}. -{"Get Number of Registered Users", "Pokaż liczbę zarejestrowanych użytkowników"}. -{"Get Number of Online Users", "Pokaż ilość użytkowników online"}. -{"User Management", "Zarządzanie użytkownikami"}. -{"Time delay", "Opóźnienie czasu"}. -{"Password Verification", "Weryfikacja hasła"}. -{"Number of registered users", "Ilość zarejestrowanych użytkowników"}. -{"Number of online users", "Ilość użytkowników online"}. -{"Last login", "Ostatnie logowanie"}. -{"Roster size", "Rozmiar rostera"}. -{"IP addresses", "Adresy IP"}. -{"Resources", "Zasoby"}. -{"Choose storage type of tables", "Wybierz typ przechowalni tablic"}. -{"RAM copy", "Kopia RAM"}. -{"RAM and disc copy", "Kopia ramu i dysku"}. -{"Disc only copy", "Kopia samego dysku"}. -{"Remote copy", "Zdalna kopia"}. -{"Stop Modules at ", "Zatrzymaj moduł o "}. -{"Choose modules to stop", "Wybierz moduły do zatrzymania"}. -{"Start Modules at ", "Uruchom moduł o "}. -{"Enter list of {Module, [Options]}", "Wprowadź listę {Moduł, [Opcje]}"}. -{"List of modules to start", "Lista modułów do uruchomienia"}. -{"Backup to File at ", "Stwórz kopię do pliku na "}. -{"Enter path to backup file", "Wprowadź scieżkę do pliku kopii zapasowej"}. -{"Path to File", "Scieżka do pliku"}. -{"Restore Backup from File at ", "Przywróć kopię zapasową z pliku na "}. -{"Dump Backup to Text File at ", "Zrzuć kopię zapasową do pliku tekstowego na "}. -{"Enter path to text file", "Wprowadź scieżkę do pliku tekstowego"}. -{"Import User from File at ", "Importuj użytkownika z pliku na "}. -{"Enter path to jabberd1.4 spool file", "Wprowadź ścieżkę do pliku spool dla serwera jabberd1.4"}. -{"Import Users from Dir at ", "Importuj użytkowników z katalogu na "}. -{"Enter path to jabberd1.4 spool dir", "Wprowadź ścieżkę do katalogu spool serwera jabberd1.4"}. -{"Path to Dir", "Ścieżka do katalogu"}. -{"Hostname Configuration", "Konfiguracja hosta"}. -{"Choose host name", "Wybierz nazwę hosta"}. -{"Host name", "Nazwa hosta"}. -{"Access Control List Configuration", "Konfiguracja listy dostępowej"}. -{"Access control lists", "Lista dostępu"}. -{"Access Configuration", "Konfiguracja dostępu"}. -{"Access rules", "Zasady dostępu"}. -{"Remove Users", "Usuń użytkowników"}. -{"Choose users to remove", "Wybierz użytkowników do usunięcia"}. -{"Administration of ", "Administracja "}. -{"Action on user", "Akcja dla użytkownika"}. -{"Edit Properties", "Edytuj właściwości"}. -{"Remove User", "Usuń użytkownika"}. - -% mod_disco.erl -{"Configuration", "Konfiguracja"}. -{"Online Users", "Użytkownicy zalogowani"}. -{"All Users", "Wszyscy użytkownicy"}. -{"To ~s", "Do ~s"}. -{"From ~s", "Z ~s"}. -{"Running Nodes", "Uruchomione gałęzie"}. -{"Stopped Nodes", "Zatrzymane gałęzie"}. -{"Host Name", "Nazwa hosta"}. -{"Access Control Lists", "Lista dostępowa"}. -{"Access Rules", "Zasady dostępu"}. -{"Remove Users", "Usuń użytkowników"}. -{"Modules", "Moduły"}. -{"Start Modules", "Uruchom moduły"}. -{"Stop Modules", "Zatrzymaj moduły"}. -{"Backup Management", "Zarządzanie kopiami zapasowymi"}. -{"Backup", "Tworzenie kopii"}. -{"Restore", "Odtwarzanie kopii"}. -{"Dump to Text File", "Zrzucanie do pliku tekstowego"}. -{"Import File", "Importuj plik"}. -{"Import Directory", "Importuj katalog"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Wybierz nazwę użytkownika i hasło aby zarejestrować się na tym serwerze"}. - -% mod_vcard.erl -{"You need an x:data capable client to search", "Potrzebujesz klienta kompatybilnego z x:data aby wyszukiwać"}. -{"Search users in ", "Wyszukaj użytkowników w "}. -{"Fill in fields to search for any matching Jabber User", "Wypełnij pola aby znaleźdź pasujących użytkowników Jabbera"}. -{"User", "Użytkownik: "}. -{"Full Name", "Pełna nazwa: "}. -{"Name", "Imię: "}. -{"Middle Name", "Nazwisko: "}. -{"Family Name", "Nazwisko rodowe: "}. -{"Nickname", "Nick: "}. -{"Birthday", "Data urodzenia: "}. -{"Country", "Państwo: "}. -{"City", "Miasto: "}. -{"Organization Name", "Nazwa organizacji: "}. -{"Organization Unit", "Dział: "}. - -% mod_muc/mod_muc.erl -{"Chatrooms", "Pokoje rozmów"}. -{"ejabberd MUC module", "Moduł MUC"}. -{"You need an x:data capable client to register nickname", "Potrzebujesz klienta kompatybilnego z x:data aby zarejestrować nick"}. -{"Nickname Registration at ", "Rejestracja nicka na "}. -{"Enter nickname you want to register", "Wprowadz nicka którego chcesz zarejestrować"}. -{"Only service administrators are allowed to send service messages", "Jedynie administrator może wysyłać wiadomości serwisowe"}. -{"Conference room does not exist", "Pokój konferencyjny nie istnieje"}. -{"Access denied by service policy", "Dostęp zabroniony przez zabezpieczenia serwera"}. -{"Specified nickname is already registered", "Podany nick jest już zarejestrowany"}. - -% mod_muc/mod_muc_room.erl -{"Make room moderated", "Moderuj pokój"}. -{"Traffic rate limit is exceeded", "Limit transferu przekroczony"}. -{"Maximum Number of Occupants", "Maksymalna liczba uczestników"}. -{"No limit", "Bez limitu"}. -{"~s invites you to the room ~s", "~s zaprasza Cię do pokoju ~s"}. -{"the password is", "hasło to"}. -{" has set the subject to: ", "zmieł(a) temat na: "}. -{"You need an x:data capable client to configure room", "Potrzebujesz klienta kompatybilnego z x:data aby skonfigurować pokój"}. -{"Configuration for ", "Konfiguracja dla "}. -{"Room title", "Tytuł pokoju"}. -{"Password", "Hasło"}. -{"Only moderators and participants are allowed to change subject in this room", "Tylko moderatorzy i wlasciciele mogą zmienić temat tego pokoju"}. -{"Only moderators are allowed to change subject in this room", "Tylko moderatorzy mogą zmienić temat tego pokoju"}. -{"Visitors are not allowed to send messages to all occupants", "Odwiedzający nie mogą wysyłać wiadomości do wszystkich obecnych"}. -{"Only occupants are allowed to send messages to the conference", "Tylko obecni mogą wysyłać wiadomości na konferencje"}. -{"It is not allowed to send normal messages to the conference", "Nie można wysyłać normalnych wiadomości na konferencje"}. -{"It is not allowed to send private messages to the conference", "Nie wolno wysyłac prywatnych wiadomości na konferencje"}. -{"Improper message type", "Nieprawidłowy typ wiadomości"}. -{"Nickname is already in use by another occupant", "Nick jest używany przez innego użytkownika"}. -{"Nickname is registered by another person", "Nick jest już zarejestrowany przez inną osobę"}. -{"It is not allowed to send private messages of type \"groupchat\"", "Nie mozna wysyłac prywatnych wiadomości typu \"Groupchat\" "}. -{"Recipient is not in the conference room", "Odbiorca nie jest obecny w pokoju"}. -{"Only occupants are allowed to send queries to the conference", "Tylko użytkownicy mogą wysyłać zapytania do pokoju konferencyjnego"}. -{"Queries to the conference members are not allowed in this room", "Zapytania do członków konferencji nie są dozwolone w tym pokoju"}. -{"You have been banned from this room", "Zostałeś zabanowany w tym pokoju"}. -{"Membership required to enter this room", "Aby wejść do pokoju wymagane jest jego członkostwo"}. -{"Password required to enter this room", "Aby wejść do pokoju wymagane jest hasło"}. -{"Incorrect password", "Nieprawidłowe hasło"}. -{"Administrator privileges required", "Wymagane prawa administratora"}. -{"Moderator privileges required", "Wymagane prawa moderatora"}. -{"JID ~s is invalid", "JID ~s jest niepoprawny"}. -{"Nickname ~s does not exist in the room", "Nick ~s nie istnieje w tym pokoju"}. -{"Invalid affiliation: ~s", "Nieprawidłowe powiązanie: ~s"}. -{"Invalid role: ~s", "Nieprawidłowa rola: ~s"}. -{"Owner privileges required", "Wymagane uprawnienia właściciela "}. -{"private, ", "prywatny, "}. -{"Present real JIDs to", "Kto może widzieć prawdziwe JID-y?"}. -{"moderators only", "tylko moderatorzy"}. -{"anyone", "wszyscy"}. - - -% mod_irc/mod_irc.erl -{"IRC Transport", "Transport IRC"}. -{"ejabberd IRC module", "Moduł IRC"}. -{"You need an x:data capable client to configure mod_irc settings", "Potrzebujesz klienta kompatybilnego z x:data aby skonfigurować mod_irc"}. -{"Registration in mod_irc for ", "Rejestracja w mod_irc dla "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Wprowadź nazwę użytkownika i kodowanie których chcesz używać do łączenia z serwerami IRC"}. -{"IRC Username", "Nazwa użytkownika"}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Przykład: [{\"wroclaw.irc.pl\",\"utf-8\"}, {\"warszawa.irc.pl\", \"iso8859-2\"}]."}. -{"Encodings", "Kodowania"}. - -% web/ejabberd_web_admin.erl -{"Low level update script", "Skrypt update-u niskiego poziomu"}. -{"Users", "Użytkownicy"}. -{"Nodes", "Gałęzie"}. -{"Statistics", "Statystyki"}. -{"Delete Selected", "Usuń zaznaczone"}. -{"Submit", "Wprowadź"}. -{"~s access rule configuration", "~s konfiguracja zasad dostępu"}. -{"Node not found", "Gałąź nie znaleziona"}. -{"Add New", "Dodaj nowe"}. -{"Change Password", "Zmień hasło"}. -{"Connected Resources:", "Zasoby podłączone"}. -{"Password:", "Hasło:"}. -{"None", "Brak"}. -{"Node ", "Gałąź "}. -{"Restart", "Restart"}. -{"Stop", "Stop"}. -{"Name", "Nazwa"}. -{"Storage Type", "Typ bazy"}. -{"Size", "Wielkość"}. -{"Memory", "Pamięć"}. -{"OK", "OK"}. -{"Listened Ports at ", "Porty nasłuchujące "}. -{"Port", "Port"}. -{"Module", "Moduł"}. -{"Options", "Opcje"}. -{"Update", "Aktualizacja"}. -{"Delete", "Usuń"}. -{"Add User", "Dodaj użytkownika"}. -{"Last Activity", "Ostatnia aktywność"}. -{"Never", "Nigdy"}. -{"Time", "Czas"}. -{"From", "Od"}. -{"To", "Do"}. -{"Packet", "Pakiet "}. -{"Roster", "Roster "}. -{"Nickname", "Nick "}. -{"Subscription", "Subskrypcja "}. -{"Pending", "Oczekiwanie "}. -{"Groups", "Grupy "}. -{"Remove", "Usuń "}. -{"User ", "Użytkownik "}. -{"Roster of ", "Roster "}. -{"Shared Roster", "Roster współdzielony"}. -{"Online", "Dostępny"}. -{"Validate", "Zatwierdź"}. -{"Name:", "Nazwa:"}. -{"Description:", "Opis:"}. -{"Members:", "Członkowie:"}. -{"Displayed Groups:", "Wyświetlane grupy:"}. -{"Group ", "Grupa "}. -{"Period: ", "Przedział czasu "}. -{"Last month", "Ostatni miesiąc"}. -{"Last year", "Ostatni rok"}. -{"All activity", "Cała aktywność"}. -{"Show Ordinary Table", "Pokaż zwykłą tabelę"}. -{"Show Integral Table", "Pokaż tabelę całkowitą"}. -{"Start", "Start"}. -{"Modules at ", "Moduły na "}. -{"Virtual Hosts", "Wirtualne hosty"}. -{"ejabberd virtual hosts", "wirtualne hosty ejabberda"}. -{"Host", "Host"}. - -% mod_vcard_odbc.erl -{"Email", "Email"}. -{"vCard User Search", "Wyszukiwanie vCard użytkowników"}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Wypełnij formularz aby wyszukać pasujących użytkowników Jabbera (dodaj * na koniec pola aby dopasować)"}. - -% ejabberd_c2s.erl -{"Use of STARTTLS required", "Wymagane użycie STARTTLS"}. - -% mod_pubsub/mod_pubsub.erl -{"ejabberd Publish-Subscribe module", "Moduł Publish-Subscribe"}. -{"PubSub subscriber request", "Rządzanie subskrybenta PubSub"}. -{"Choose whether to approve this entity's subscription.", "Wybierz, czy akceptować subskrypcję tej jednostki"}. -{"Node ID", "ID noda"}. -{"Subscriber Address", "Adres subskrybenta"}. -{"Allow this JID to subscribe to this pubsub node?", "Pozwól temu JID na zapisanie się do tego noda pubsub"}. -{"Deliver event notifications", "Dostarczaj powiadomienia o zdarzeniach"}. -{"Specify the access model", "Oznacz model dostępu"}. -{"Roster groups that may subscribe (if access model is roster)", "Grupy rostera jakie mogą subskrybować (jeśli model dostępu to roster"}. -{"When to send the last published item", "Kiedy wysłać ostatnio opublikowaną rzecz"}. -{"Node Creator", "Tworzenie gałęzi"}. -{"Deliver payloads with event notifications", "Dołącz zawartość publikowanego przedmiotu podczas wysyłania powiadomienia o publikacji"}. -{"Notify subscribers when the node configuration changes", "Informuj subskrybentów gdy konfiguracja gałęzi się zmieni"}. -{"Notify subscribers when the node is deleted", "Informuj subskrybentów gdy gałąż zostanie wykasowana"}. -{"Notify subscribers when items are removed from the node", "Informuj subskrybentów kiedy zostaną z gałęzi usunięte jakieś elementy"}. -{"Persist items to storage", "Przechowuj przedmioty pub/sub w pamięci"}. -{"Max # of items to persist", "Maksymalna ilość przechowywanych przedmiotów"}. -{"Whether to allow subscriptions", "Czy pozwolić na subskrypcje"}. -{"Specify the subscriber model", "Oznacz model subskrybenta"}. -{"Specify the publisher model", "Oznacz model publikującego"}. -{"Max payload size in bytes", "Maksymalna wielkość powiadomienia w bajtach"}. -{"Send items to new subscribers", "Wysyłaj rzeczy do nowych subskrybentów"}. -{"Only deliver notifications to available users", "Dostarczaj notyfikacje tylko do osiągalnych użytkowników"}. -{"Specify the current subscription approver", "Wyznacz aprobującego obecne subskrypcje "}. - -% mod_irc/mod_irc.erl -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Jeśli chcesz ustawić inne kodowanie dla serwerów IRC, wypełnij tą listę wartościami w formacie '{\"irc server\",\"encoding\"}'. Jako domyślne ten serwis używa kodowania \"~s\"."}. - -% mod_muc/mod_muc.erl -{"Room creation is denied by service policy", "Tworzenie pokoju jest zabronione przez polisę"}. - -% mod_vcard_odbc.erl -{"Erlang Jabber Server", "Erlang Jabber Server"}. -{"ejabberd vCard module", "Erlang Jabber Server"}. -{"Search Results for ", "Wyniki wyszukiwania dla "}. -{"Jabber ID", "Jabber ID"}. - -% mod_adhoc.erl -{"Commands", "Polecenia"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% ejabberd_c2s.erl -{"Replaced by new connection", "Podmienione przez nowe połączenie"}. - -% mod_announce.erl -{"Send announcement to all users on all hosts", "Wyślij powiadomienie do wszystkich użytkowników na wszystkich hostach"}. -{"Set message of the day on all hosts and send to online users", "Ustaw wiadomość dnia dla wszystkich hostów i wyślij do uzytkowników online"}. -{"Update message of the day on all hosts (don't send)", "Odśwież wiadomośc dnia na wszystkich hostach (nie wysyłaj)"}. -{"Delete message of the day on all hosts", "Usuń wiadomość dnia ze wszystkich hostów"}. -{"Really delete message of the day?", "Na pewno usunąć wiadomość dnia?"}. -{"Subject", "Temat"}. -{"Message body", "Treść wiadomości"}. -{"No body provided for announce message", "Nikt nie jest uprawniony do rozsyłania oznajmień"}. -{"Announcements", "Oznajmienia"}. -{"Send announcement to all users", "Wyślij oznajmienie do wszystkich użytkowników"}. -{"Send announcement to all online users", "Wyślij oznajmienie do wszystkich użytkowników online"}. -{"Send announcement to all online users on all hosts", "Wyślij oznajmienie do wszystkich użytkowników online na wszystkich hostach"}. -{"Set message of the day and send to online users", "Wyślij wiadomość dnia do wszystkich użytkowników online"}. -{"Update message of the day (don't send)", "Zmień wiadomość dnia (nie wysyłaj)"}. -{"Delete message of the day", "Usuń wiadomość dnia"}. - -% mod_configure.erl -{"Database", "Baza"}. -{"Outgoing s2s Connections", "Wychodzące połączenia s2s"}. -{"Import Users From jabberd 1.4 Spool Files", "Importuj użytkowników z plików spool serwera jabber 1.4"}. -{"Database Tables Configuration at ", "Konfiguracja tabel bazy na "}. - -% web/ejabberd_web_admin.erl -{"ejabberd Web Interface", "Interfejs WWW serwera ejabberd"}. -{"Administration", "Administracja"}. -{"Submitted", "Wprowadzone"}. -{"Bad format", "Zły format"}. -{"Users Last Activity", "Ostatnia aktywność użytkowników"}. -{"Registered Users", "Użytkownicy zarejestrowani"}. -{"Offline Messages", "Wiadomości offline"}. -{"Registered Users:", "Użytkownicy zarejestrowani:"}. -{"Authenticated Users:", "Użytkownicy autoryzowani:"}. -{"Online Users:", "Użytkownicy online:"}. -{"Outgoing s2s Connections:", "Wychodzące połączenia s2s:"}. -{"Outgoing s2s Servers:", "Serwery zewnętrzne s2s:"}. -{"Offline Messages:", "Wiadomości offline"}. -{"~s's Offline Messages Queue", "~s skolejkowanych wiadomości offline"}. -{"Add Jabber ID", "Dodaj JID"}. -{"No Data", "Brak danych"}. -{"Listened Ports", "Porty nasłuchujące"}. -{"RPC Call Error", "Błąd odwołania RPC"}. -{"Database Tables at ", "Tabele bazy na "}. -{"Backup of ", "Kopia zapasowa "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "Te opcje backupują jedynie bazę Mnesia. Jeśli używasz modułu ODBC - musisz wykonać kopię SQL oddzielnie"}. -{"Store binary backup:", "Zachowaj kopię binarną:"}. -{"Restore binary backup immediately:", "Natychmiast odtwórz kopię binarną:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Odtwórz kopię binarną podczas następnego restaru ejabberd-a (wymaga mniej pamięci)"}. -{"Store plain text backup:", "Zachowaj kopię w czystym tekście"}. -{"Restore plain text backup immediately:", "Odtwórz kopię z czystego tekstu"}. -{"Statistics of ~p", "Statystyki ~p"}. -{"Uptime:", "Uptime"}. -{"CPU Time:", "Czas CPU"}. -{"Transactions Commited:", "Transakcje zakończone"}. -{"Transactions Aborted:", "Transakcje anulowane"}. -{"Transactions Restarted:", "Transakcje uruchomione ponownie"}. -{"Transactions Logged:", "Transakcje logowane"}. -{"Update ", "Uaktualnij"}. -{"Update plan", "Uaktualnij plan"}. -{"Updated modules", "Uaktualnione moduły"}. -{"Update script", "Uaktualnij skrypt"}. -{"Script check", "Sprawdź skrypt"}. -{"Not Found", "Nie znaleziono"}. -{"Shared Roster Groups", "Grupy współdzielone"}. - -% mod_muc/mod_muc_log.erl -{"Chatroom configuration modified", "Konfiguracja pokoju zmodyfikowana"}. -{"joins the room", "dołączył(a) się do pokoju"}. -{"leaves the room", "opóścił(a) pokój"}. -{"has been kicked", "został(a) kopnięty(a)"}. -{"has been banned", "został(a) zabanowany(a)"}. -{"is now known as", "jest teraz znany(a) jako"}. -{"Monday", "Poniedziałek"}. -{"Tuesday", "Wtorek"}. -{"Wednesday", "Środa"}. -{"Thursday", "Czwartek"}. -{"Friday", "Piątek"}. -{"Saturday", "Sobota"}. -{"Sunday", "Niedziela"}. -{"January", "Styczeń"}. -{"February", "Luty"}. -{"March", "Marzec"}. -{"April", "Kwiecień"}. -{"May", "Maj"}. -{"June", "Czerwiec"}. -{"July", "Lipiec"}. -{"August", "Sierpień"}. -{"September", "Wrzesień"}. -{"October", "Październik"}. -{"November", "Listopad"}. -{"December", "Grudzień"}. -{"Room Configuration", "Konfiguracja pokoju"}. - -% mod_muc/mod_muc.erl -{"You must fill in field \"Nickname\" in the form", "Musisz wypełnić pole NICKNAME w formularzu"}. - -% mod_muc/mod_muc_room.erl -{"This room is not anonymous", "Pokój nie jest nieznany"}. -{"Make room persistent", "Utwórz pokój na stałe"}. -{"Make room public searchable", "Pozwól wyszukiwać pokój"}. -{"Make participants list public", "Upublicznij listę uczestników"}. -{"Make room password protected", "Zabezpiecz pokój hasłem"}. -{"Make room members-only", "Utwórz pokój tylko dla uczestnikóww"}. -{"Make room moderated", "Moderuj pokój"}. -{"Default users as participants", "Domyślni użytkownicy jako uczestnicy"}. -{"Allow users to change subject", "Pozwól użytkownikom zmienić tytuł pokoju"}. -{"Allow users to send private messages", "Pozwól użytkownikom wysyłać prywatne wiadomości"}. -{"Allow users to query other users", "Pozwól użytkownikom pobierać informacje o innych użytkownikach"}. -{"Allow users to send invites", "Pozwól użytkownikom wysyłać zaproszenia"}. -{"Enable logging", "Włącz logowanie"}. -{"Description", "Opis"}. -{"Number of occupants", "Liczba uczestników"}. - -% mod_vcard_ldap.erl -{"Jabber ID", "Jabber ID"}. - -% mod_presence.erl -{"You need an x:data capable client to register presence", "Potrzebujesz klinta kompatybilnego z x:data aby zarejestrować widoczność "}. -{"Presence registration at ", "Rejestracja widoczności na "}. -{"What presence features do you want to register?", "Jakie usługi widoczności chcesz zarejestrować?"}. -{"Specified presence is already registered", "Określona widoczność już jest zarejestrowana"}. -{"You must fill in field \"Xml\" in the form", "Musisz wypełnić w formularzu pole \"XML\""}. -{"You must fill in field \"Icon\" in the form", "Musisz wypełnić w formularzu pole \"Icon\""}. -{"Raw XML export", "Eksport XML do raw"}. -{"Allow icon export", "Pozwól na eksport ikon"}. - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "Mudł SOCKS5 Bytestreams"}. - -% mod_offline.erl -{"Your contact offline message queue is full. The message has been discarded.", "Twoja kolejka wiadomoci offline jest pełna. Wiadomoć została odrzucona."}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Konfiguracja dostępu"}. +{"Access Control List Configuration","Konfiguracja listy dostępowej"}. +{"Access Control Lists","Lista dostępowa"}. +{"Access control lists","Lista dostępu"}. +{"Access denied by service policy","Dostęp zabroniony przez zabezpieczenia serwera"}. +{"Access rules","Zasady dostępu"}. +{"Access Rules","Zasady dostępu"}. +{"Action on user","Akcja dla użytkownika"}. +{"Add Jabber ID","Dodaj JID"}. +{"Add New","Dodaj nowe"}. +{"Add User","Dodaj użytkownika"}. +{"Administration","Administracja"}. +{"Administration of ","Administracja "}. +{"Administrator privileges required","Wymagane prawa administratora"}. +{"A friendly name for the node","Przyjazna nazwa węzła"}. +{"All activity","Cała aktywność"}. +{"Allow this JID to subscribe to this pubsub node?","Pozwól temu JID na zapisanie się do tego noda pubsub"}. +{"Allow users to change subject","Pozwól użytkownikom zmienić tytuł pokoju"}. +{"Allow users to query other users","Pozwól użytkownikom pobierać informacje o innych użytkownikach"}. +{"Allow users to send invites","Pozwól użytkownikom wysyłać zaproszenia"}. +{"Allow users to send private messages","Pozwól użytkownikom wysyłać prywatne wiadomości"}. +{"Allow visitors to change nickname","Pozwól uczestnikom na zmianę nika"}. +{"Allow visitors to send status text in presence updates","Pozwól uczestnikom na wysyłanie statusów opisowych"}. +{"All Users","Wszyscy użytkownicy"}. +{"Announcements","Oznajmienia"}. +{"anyone","wszyscy"}. +{"April","Kwiecień"}. +{"August","Sierpień"}. +{"Backup Management","Zarządzanie kopiami zapasowymi"}. +{"Backup of ","Kopia zapasowa "}. +{"Backup to File at ","Stwórz kopię do pliku na "}. +{"Backup","Tworzenie kopii"}. +{"Bad format","Zły format"}. +{"Birthday","Data urodzenia: "}. +{"Change Password","Zmień hasło"}. +{"Change User Password","Zmień hasło użytkownika"}. +{"Chatroom configuration modified","Konfiguracja pokoju zmodyfikowana"}. +{"Chatrooms","Pokoje rozmów"}. +{"Choose a username and password to register with this server","Wybierz nazwę użytkownika i hasło aby zarejestrować się na tym serwerze"}. +{"Choose modules to stop","Wybierz moduły do zatrzymania"}. +{"Choose storage type of tables","Wybierz typ przechowalni tablic"}. +{"Choose whether to approve this entity's subscription.","Wybierz, czy akceptować subskrypcję tej jednostki"}. +{"City","Miasto: "}. +{"Commands","Polecenia"}. +{"Conference room does not exist","Pokój konferencyjny nie istnieje"}. +{"Configuration for ","Konfiguracja dla "}. +{"Configuration","Konfiguracja"}. +{"Connected Resources:","Zasoby podłączone"}. +{"Country","Państwo: "}. +{"CPU Time:","Czas CPU"}. +{"Database","Baza"}. +{"Database Tables at ","Tabele bazy na "}. +{"Database Tables Configuration at ","Konfiguracja tabel bazy na "}. +{"December","Grudzień"}. +{"Default users as participants","Domyślni użytkownicy jako uczestnicy"}. +{"Delete message of the day on all hosts","Usuń wiadomość dnia ze wszystkich hostów"}. +{"Delete message of the day","Usuń wiadomość dnia"}. +{"Delete Selected","Usuń zaznaczone"}. +{"Delete User","Usuń użytkownika"}. +{"Delete","Usuń"}. +{"Deliver event notifications","Dostarczaj powiadomienia o zdarzeniach"}. +{"Deliver payloads with event notifications","Dołącz zawartość publikowanego przedmiotu podczas wysyłania powiadomienia o publikacji"}. +{"Description:","Opis:"}. +{"Disc only copy","Kopia samego dysku"}. +{"Displayed Groups:","Wyświetlane grupy:"}. +{"Dump Backup to Text File at ","Zrzuć kopię zapasową do pliku tekstowego na "}. +{"Dump to Text File","Zrzucanie do pliku tekstowego"}. +{"Edit Properties","Edytuj właściwości"}. +{"ejabberd IRC module","Moduł IRC"}. +{"ejabberd MUC module","Moduł MUC"}. +{"ejabberd Publish-Subscribe module","Moduł Publish-Subscribe"}. +{"ejabberd SOCKS5 Bytestreams module","Mudł SOCKS5 Bytestreams"}. +{"ejabberd vCard module","Erlang Jabber Server"}. +{"ejabberd virtual hosts","wirtualne hosty ejabberda"}. +{"ejabberd Web Admin","ejabberd: Panel Administracyjny"}. +{"Email","Email"}. +{"Enable logging","Włącz logowanie"}. +{"Encodings","Kodowania"}. +{"End User Session","Zakończ sesję uzytkownika"}. +{"Enter list of {Module, [Options]}","Wprowadź listę {Moduł, [Opcje]}"}. +{"Enter nickname you want to register","Wprowadz nicka którego chcesz zarejestrować"}. +{"Enter path to backup file","Wprowadź scieżkę do pliku kopii zapasowej"}. +{"Enter path to jabberd1.4 spool dir","Wprowadź ścieżkę do katalogu spool serwera jabberd1.4"}. +{"Enter path to jabberd1.4 spool file","Wprowadź ścieżkę do pliku spool dla serwera jabberd1.4"}. +{"Enter path to text file","Wprowadź scieżkę do pliku tekstowego"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Wprowadź nazwę użytkownika i kodowanie których chcesz używać do łączenia z serwerami IRC"}. +{"Erlang Jabber Server","Erlang Jabber Server"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Przykład: [{\"wroclaw.irc.pl\",\"utf-8\"}, {\"warszawa.irc.pl\", \"iso8859-2\"}]."}. +{"Family Name","Nazwisko rodowe: "}. +{"February","Luty"}. +{"Fill in fields to search for any matching Jabber User","Wypełnij pola aby znaleźdź pasujących użytkowników Jabbera"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Wypełnij formularz aby wyszukać pasujących użytkowników Jabbera (dodaj * na koniec pola aby dopasować)"}. +{"Friday","Piątek"}. +{"From","Od"}. +{"From ~s","Z ~s"}. +{"Full Name","Pełna nazwa: "}. +{"Get Number of Online Users","Pokaż ilość użytkowników online"}. +{"Get Number of Registered Users","Pokaż liczbę zarejestrowanych użytkowników"}. +{"Get User Last Login Time","Pokaż czas ostatniego zalogowania uzytkownika"}. +{"Get User Password","Pobierz hasło użytkownika"}. +{"Get User Statistics","Pobierz statystyki użytkownika"}. +{"Group ","Grupa "}. +{"Groups","Grupy "}. +{"has been banned","został(a) zabanowany(a)"}. +{"has been kicked because of an affiliation change","został wyrzucony z powodu zmiany przynależności"}. +{"has been kicked because of a system shutdown","został wyrzucony z powodu wyłączenia systemu"}. +{"has been kicked because the room has been changed to members-only","został wyrzucony z powodu zmiany parametrów pokoju: Tylko dla Członków"}. +{"has been kicked","został(a) kopnięty(a)"}. +{" has set the subject to: ","zmieł(a) temat na: "}. +{"Host","Host"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Jeśli chcesz ustawić inne kodowanie dla serwerów IRC, wypełnij tą listę wartościami w formacie '{\"irc server\",\"encoding\"}'. Jako domyślne ten serwis używa kodowania \"~s\"."}. +{"Import Directory","Importuj katalog"}. +{"Import File","Importuj plik"}. +{"Import User from File at ","Importuj użytkownika z pliku na "}. +{"Import Users from Dir at ","Importuj użytkowników z katalogu na "}. +{"Import Users From jabberd 1.4 Spool Files","Importuj użytkowników z plików spool serwera jabber 1.4"}. +{"Improper message type","Nieprawidłowy typ wiadomości"}. +{"Incorrect password","Nieprawidłowe hasło"}. +{"Invalid affiliation: ~s","Nieprawidłowe powiązanie: ~s"}. +{"Invalid role: ~s","Nieprawidłowa rola: ~s"}. +{"IP addresses","Adresy IP"}. +{"IRC Transport","Transport IRC"}. +{"IRC Username","Nazwa użytkownika"}. +{"is now known as","jest teraz znany(a) jako"}. +{"It is not allowed to send private messages of type \"groupchat\"","Nie mozna wysyłac prywatnych wiadomości typu \"Groupchat\" "}. +{"It is not allowed to send private messages to the conference","Nie wolno wysyłac prywatnych wiadomości na konferencje"}. +{"It is not allowed to send private messages","Wysyłanie prywatnych wiadomości jest zabronione"}. +{"Jabber ID","Jabber ID"}. +{"January","Styczeń"}. +{"JID ~s is invalid","JID ~s jest niepoprawny"}. +{"joins the room","dołączył(a) się do pokoju"}. +{"July","Lipiec"}. +{"June","Czerwiec"}. +{"Last Activity","Ostatnia aktywność"}. +{"Last login","Ostatnie logowanie"}. +{"Last month","Ostatni miesiąc"}. +{"Last year","Ostatni rok"}. +{"leaves the room","opóścił(a) pokój"}. +{"Listened Ports at ","Porty nasłuchujące "}. +{"Listened Ports","Porty nasłuchujące"}. +{"List of modules to start","Lista modułów do uruchomienia"}. +{"Low level update script","Skrypt update-u niskiego poziomu"}. +{"Make participants list public","Upublicznij listę uczestników"}. +{"Make room members-only","Utwórz pokój tylko dla uczestnikóww"}. +{"Make room moderated","Moderuj pokój"}. +{"Make room password protected","Zabezpiecz pokój hasłem"}. +{"Make room persistent","Utwórz pokój na stałe"}. +{"Make room public searchable","Pozwól wyszukiwać pokój"}. +{"March","Marzec"}. +{"Maximum Number of Occupants","Maksymalna liczba uczestników"}. +{"Max # of items to persist","Maksymalna ilość przechowywanych przedmiotów"}. +{"Max payload size in bytes","Maksymalna wielkość powiadomienia w bajtach"}. +{"May","Maj"}. +{"Members:","Członkowie:"}. +{"Membership required to enter this room","Aby wejść do pokoju wymagane jest jego członkostwo"}. +{"Memory","Pamięć"}. +{"Message body","Treść wiadomości"}. +{"Middle Name","Nazwisko: "}. +{"Moderator privileges required","Wymagane prawa moderatora"}. +{"moderators only","tylko moderatorzy"}. +{"Module","Moduł"}. +{"Modules at ","Moduły na "}. +{"Modules","Moduły"}. +{"Monday","Poniedziałek"}. +{"Name:","Nazwa:"}. +{"Name","Nazwa"}. +{"Never","Nigdy"}. +{"Nickname is already in use by another occupant","Nick jest używany przez innego użytkownika"}. +{"Nickname is registered by another person","Nick jest już zarejestrowany przez inną osobę"}. +{"Nickname","Nick "}. +{"Nickname Registration at ","Rejestracja nicka na "}. +{"Nickname ~s does not exist in the room","Nick ~s nie istnieje w tym pokoju"}. +{"No body provided for announce message","Nikt nie jest uprawniony do rozsyłania oznajmień"}. +{"No Data","Brak danych"}. +{"Node ","Gałąź "}. +{"Node ID","ID noda"}. +{"Node not found","Gałąź nie znaleziona"}. +{"Nodes","Gałęzie"}. +{"No limit","Bez limitu"}. +{"None","Brak"}. +{"No resource provided","Brak dostarczonych zasobów"}. +{"Notify subscribers when items are removed from the node","Informuj subskrybentów kiedy zostaną z gałęzi usunięte jakieś elementy"}. +{"Notify subscribers when the node configuration changes","Informuj subskrybentów gdy konfiguracja gałęzi się zmieni"}. +{"Notify subscribers when the node is deleted","Informuj subskrybentów gdy gałąż zostanie wykasowana"}. +{"November","Listopad"}. +{"Number of occupants","Liczba uczestników"}. +{"Number of online users","Ilość użytkowników online"}. +{"Number of registered users","Ilość zarejestrowanych użytkowników"}. +{"October","Październik"}. +{"Offline Messages:","Wiadomości offline"}. +{"Offline Messages","Wiadomości offline"}. +{"OK","OK"}. +{"Online","Dostępny"}. +{"Online Users:","Użytkownicy online:"}. +{"Online Users","Użytkownicy zalogowani"}. +{"Only deliver notifications to available users","Dostarczaj notyfikacje tylko do osiągalnych użytkowników"}. +{"Only moderators and participants are allowed to change subject in this room","Tylko moderatorzy i wlasciciele mogą zmienić temat tego pokoju"}. +{"Only moderators are allowed to change subject in this room","Tylko moderatorzy mogą zmienić temat tego pokoju"}. +{"Only occupants are allowed to send messages to the conference","Tylko obecni mogą wysyłać wiadomości na konferencje"}. +{"Only occupants are allowed to send queries to the conference","Tylko użytkownicy mogą wysyłać zapytania do pokoju konferencyjnego"}. +{"Only service administrators are allowed to send service messages","Jedynie administrator może wysyłać wiadomości serwisowe"}. +{"Options","Opcje"}. +{"Organization Name","Nazwa organizacji: "}. +{"Organization Unit","Dział: "}. +{"Outgoing s2s Connections:","Wychodzące połączenia s2s:"}. +{"Outgoing s2s Connections","Wychodzące połączenia s2s"}. +{"Outgoing s2s Servers:","Serwery zewnętrzne s2s:"}. +{"Owner privileges required","Wymagane uprawnienia właściciela\t"}. +{"Packet","Pakiet "}. +{"Password:","Hasło:"}. +{"Password","Hasło"}. +{"Password required to enter this room","Aby wejść do pokoju wymagane jest hasło"}. +{"Password Verification","Weryfikacja hasła"}. +{"Path to Dir","Ścieżka do katalogu"}. +{"Path to File","Scieżka do pliku"}. +{"Pending","Oczekiwanie "}. +{"Period: ","Przedział czasu "}. +{"Persist items to storage","Przechowuj przedmioty pub/sub w pamięci"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","Port"}. +{"Present real JIDs to","Kto może widzieć prawdziwe JID-y?"}. +{"private, ","prywatny, "}. +{"Publish-Subscribe","PubSub"}. +{"PubSub subscriber request","Rządzanie subskrybenta PubSub"}. +{"Queries to the conference members are not allowed in this room","Zapytania do członków konferencji nie są dozwolone w tym pokoju"}. +{"RAM and disc copy","Kopia ramu i dysku"}. +{"RAM copy","Kopia RAM"}. +{"(Raw)","(Raw)"}. +{"Raw","Raw"}. +{"Really delete message of the day?","Na pewno usunąć wiadomość dnia?"}. +{"Recipient is not in the conference room","Odbiorca nie jest obecny w pokoju"}. +{"Registered Users:","Użytkownicy zarejestrowani:"}. +{"Registered Users","Użytkownicy zarejestrowani"}. +{"Registration in mod_irc for ","Rejestracja w mod_irc dla "}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Te opcje backupują jedynie bazę Mnesia. Jeśli używasz modułu ODBC - musisz wykonać kopię SQL oddzielnie"}. +{"Remote copy","Zdalna kopia"}. +{"Remove User","Usuń użytkownika"}. +{"Remove","Usuń "}. +{"Replaced by new connection","Podmienione przez nowe połączenie"}. +{"Resources","Zasoby"}. +{"Restart","Restart"}. +{"Restart Service","Restart serwisu"}. +{"Restore Backup from File at ","Przywróć kopię zapasową z pliku na "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Odtwórz kopię binarną podczas następnego restaru ejabberd-a (wymaga mniej pamięci)"}. +{"Restore binary backup immediately:","Natychmiast odtwórz kopię binarną:"}. +{"Restore","Odtwarzanie kopii"}. +{"Restore plain text backup immediately:","Odtwórz kopię z czystego tekstu"}. +{"Room Configuration","Konfiguracja pokoju"}. +{"Room creation is denied by service policy","Tworzenie pokoju jest zabronione przez polisę"}. +{"Room title","Tytuł pokoju"}. +{"Roster groups allowed to subscribe","Grupy kontaktów które mogą się zapisać"}. +{"Roster of ","Roster "}. +{"Roster","Roster "}. +{"Roster size","Rozmiar rostera"}. +{"RPC Call Error","Błąd odwołania RPC"}. +{"Running Nodes","Uruchomione gałęzie"}. +{"~s access rule configuration","~s konfiguracja zasad dostępu"}. +{"Saturday","Sobota"}. +{"Script check","Sprawdź skrypt"}. +{"Search Results for ","Wyniki wyszukiwania dla "}. +{"Search users in ","Wyszukaj użytkowników w "}. +{"Send announcement to all online users on all hosts","Wyślij oznajmienie do wszystkich użytkowników online na wszystkich hostach"}. +{"Send announcement to all online users","Wyślij oznajmienie do wszystkich użytkowników online"}. +{"Send announcement to all users on all hosts","Wyślij powiadomienie do wszystkich użytkowników na wszystkich hostach"}. +{"Send announcement to all users","Wyślij oznajmienie do wszystkich użytkowników"}. +{"September","Wrzesień"}. +{"Set message of the day and send to online users","Wyślij wiadomość dnia do wszystkich użytkowników online"}. +{"Set message of the day on all hosts and send to online users","Ustaw wiadomość dnia dla wszystkich hostów i wyślij do uzytkowników online"}. +{"Shared Roster Groups","Grupy współdzielone"}. +{"Show Integral Table","Pokaż tabelę całkowitą"}. +{"Show Ordinary Table","Pokaż zwykłą tabelę"}. +{"Shut Down Service","Wyłączenie serwisu"}. +{"~s invites you to the room ~s","~s zaprasza Cię do pokoju ~s"}. +{"Size","Wielkość"}. +{"Specified nickname is already registered","Podany nick jest już zarejestrowany"}. +{"Specify the access model","Oznacz model dostępu"}. +{"Specify the publisher model","Oznacz model publikującego"}. +{"~s's Offline Messages Queue","~s skolejkowanych wiadomości offline"}. +{"Start Modules at ","Uruchom moduł o "}. +{"Start Modules","Uruchom moduły"}. +{"Start","Start"}. +{"Statistics of ~p","Statystyki ~p"}. +{"Statistics","Statystyki"}. +{"Stop Modules at ","Zatrzymaj moduł o "}. +{"Stop Modules","Zatrzymaj moduły"}. +{"Stopped Nodes","Zatrzymane gałęzie"}. +{"Stop","Stop"}. +{"Storage Type","Typ bazy"}. +{"Store binary backup:","Zachowaj kopię binarną:"}. +{"Store plain text backup:","Zachowaj kopię w czystym tekście"}. +{"Subject","Temat"}. +{"Submitted","Wprowadzone"}. +{"Submit","Wprowadź"}. +{"Subscriber Address","Adres subskrybenta"}. +{"Subscription","Subskrypcja "}. +{"Sunday","Niedziela"}. +{"the password is","hasło to"}. +{"This participant is kicked from the room because he sent an error message","Ten uczestnik został wyrzucony z pokoju ponieważ wysłał błędną wiadomość"}. +{"This participant is kicked from the room because he sent an error message to another participant","Ten uczestnik został wyrzucony z pokoju ponieważ wysłał błędą wiadomość do innego uczestnika"}. +{"This participant is kicked from the room because he sent an error presence","Ten uczestnik został wyrzucony z pokoju ponieważ informacja o statusie zawierała błędy"}. +{"This room is not anonymous","Pokój nie jest nieznany"}. +{"Thursday","Czwartek"}. +{"Time","Czas"}. +{"Time delay","Opóźnienie czasu"}. +{"To","Do"}. +{"To ~s","Do ~s"}. +{"Traffic rate limit is exceeded","Limit transferu przekroczony"}. +{"Transactions Aborted:","Transakcje anulowane"}. +{"Transactions Commited:","Transakcje zakończone"}. +{"Transactions Logged:","Transakcje logowane"}. +{"Transactions Restarted:","Transakcje uruchomione ponownie"}. +{"Tuesday","Wtorek"}. +{"Update","Aktualizacja"}. +{"Updated modules","Uaktualnione moduły"}. +{"Update message of the day (don't send)","Zmień wiadomość dnia (nie wysyłaj)"}. +{"Update message of the day on all hosts (don't send)","Odśwież wiadomośc dnia na wszystkich hostach (nie wysyłaj)"}. +{"Update plan","Uaktualnij plan"}. +{"Update script","Uaktualnij skrypt"}. +{"Update ","Uaktualnij"}. +{"Uptime:","Uptime"}. +{"Use of STARTTLS required","Wymagane użycie STARTTLS"}. +{"User Management","Zarządzanie użytkownikami"}. +{"Users are not allowed to register accounts so fast","Nie możesz tak szybko rejestrować nowych kont"}. +{"Users Last Activity","Ostatnia aktywność użytkowników"}. +{"Users","Użytkownicy"}. +{"User ","Użytkownik "}. +{"User","Użytkownik: "}. +{"Validate","Zatwierdź"}. +{"vCard User Search","Wyszukiwanie vCard użytkowników"}. +{"Virtual Hosts","Wirtualne hosty"}. +{"Visitors are not allowed to change their nicknames in this room","Uczestnicy tego pokoju nie mogą zmieniać swoich ników"}. +{"Visitors are not allowed to send messages to all occupants","Odwiedzający nie mogą wysyłać wiadomości do wszystkich obecnych"}. +{"Wednesday","Środa"}. +{"When to send the last published item","Kiedy wysłać ostatnio opublikowaną rzecz"}. +{"Whether to allow subscriptions","Czy pozwolić na subskrypcje"}. +{"You have been banned from this room","Zostałeś zabanowany w tym pokoju"}. +{"You must fill in field \"Nickname\" in the form","Musisz wypełnić pole NICKNAME w formularzu"}. +{"You need an x:data capable client to configure mod_irc settings","Potrzebujesz klienta kompatybilnego z x:data aby skonfigurować mod_irc"}. +{"You need an x:data capable client to configure room","Potrzebujesz klienta kompatybilnego z x:data aby skonfigurować pokój"}. +{"You need an x:data capable client to register nickname","Potrzebujesz klienta kompatybilnego z x:data aby zarejestrować nick"}. +{"You need an x:data capable client to search","Potrzebujesz klienta kompatybilnego z x:data aby wyszukiwać"}. +{"Your contact offline message queue is full. The message has been discarded.","Twoja kolejka wiadomoci offline jest pełna. Wiadomoć została odrzucona."}. diff --git a/src/msgs/pl.po b/src/msgs/pl.po new file mode 100644 index 000000000..b960a22db --- /dev/null +++ b/src/msgs/pl.po @@ -0,0 +1,1500 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Zbyszek Żółkiewski\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Polish (polski)\n" +"X-Additional-Translator: Andrzej Smyk\n" +"X-Additional-Translator: Mateusz Gajewski\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "Wymagane użycie STARTTLS" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Brak dostarczonych zasobów" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Podmienione przez nowe połączenie" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Polecenia" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Na pewno usunąć wiadomość dnia?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Temat" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Treść wiadomości" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "Nikt nie jest uprawniony do rozsyłania oznajmień" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Oznajmienia" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Wyślij oznajmienie do wszystkich użytkowników" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Wyślij powiadomienie do wszystkich użytkowników na wszystkich hostach" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Wyślij oznajmienie do wszystkich użytkowników online" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "" +"Wyślij oznajmienie do wszystkich użytkowników online na wszystkich hostach" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Wyślij wiadomość dnia do wszystkich użytkowników online" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Ustaw wiadomość dnia dla wszystkich hostów i wyślij do uzytkowników online" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Zmień wiadomość dnia (nie wysyłaj)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Odśwież wiadomośc dnia na wszystkich hostach (nie wysyłaj)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Usuń wiadomość dnia" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Usuń wiadomość dnia ze wszystkich hostów" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Konfiguracja" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Baza" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Uruchom moduły" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Zatrzymaj moduły" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Tworzenie kopii" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Odtwarzanie kopii" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Zrzucanie do pliku tekstowego" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Importuj plik" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Importuj katalog" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Restart serwisu" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Wyłączenie serwisu" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Dodaj użytkownika" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Usuń użytkownika" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Zakończ sesję uzytkownika" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Pobierz hasło użytkownika" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Zmień hasło użytkownika" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Pokaż czas ostatniego zalogowania uzytkownika" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Pobierz statystyki użytkownika" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Pokaż liczbę zarejestrowanych użytkowników" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Pokaż ilość użytkowników online" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Lista dostępowa" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Zasady dostępu" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Zarządzanie użytkownikami" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Użytkownicy zalogowani" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Wszyscy użytkownicy" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Wychodzące połączenia s2s" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Uruchomione gałęzie" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Zatrzymane gałęzie" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Moduły" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Zarządzanie kopiami zapasowymi" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Importuj użytkowników z plików spool serwera jabber 1.4" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "Do ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "Z ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Konfiguracja tabel bazy na " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Wybierz typ przechowalni tablic" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Kopia samego dysku" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "Kopia ramu i dysku" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "Kopia RAM" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Zdalna kopia" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Zatrzymaj moduł o " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Wybierz moduły do zatrzymania" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Uruchom moduł o " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Wprowadź listę {Moduł, [Opcje]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Lista modułów do uruchomienia" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Stwórz kopię do pliku na " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Wprowadź scieżkę do pliku kopii zapasowej" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Scieżka do pliku" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Przywróć kopię zapasową z pliku na " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Zrzuć kopię zapasową do pliku tekstowego na " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Wprowadź scieżkę do pliku tekstowego" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Importuj użytkownika z pliku na " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Wprowadź ścieżkę do pliku spool dla serwera jabberd1.4" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Importuj użytkowników z katalogu na " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Wprowadź ścieżkę do katalogu spool serwera jabberd1.4" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Ścieżka do katalogu" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Opóźnienie czasu" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Konfiguracja listy dostępowej" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Lista dostępu" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Konfiguracja dostępu" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Zasady dostępu" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Hasło" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Weryfikacja hasła" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Ilość zarejestrowanych użytkowników" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Ilość użytkowników online" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Nigdy" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Dostępny" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Ostatnie logowanie" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Rozmiar rostera" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "Adresy IP" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Zasoby" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Administracja " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Akcja dla użytkownika" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Edytuj właściwości" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Usuń użytkownika" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Dostęp zabroniony przez zabezpieczenia serwera" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "Transport IRC" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "Moduł IRC" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "Potrzebujesz klienta kompatybilnego z x:data aby skonfigurować mod_irc" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Rejestracja w mod_irc dla " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Wprowadź nazwę użytkownika i kodowanie których chcesz używać do łączenia z " +"serwerami IRC" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "Nazwa użytkownika" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Jeśli chcesz ustawić inne kodowanie dla serwerów IRC, wypełnij tą listę " +"wartościami w formacie '{\"irc server\",\"encoding\"}'. Jako domyślne ten " +"serwis używa kodowania \"~s\"." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Przykład: [{\"wroclaw.irc.pl\",\"utf-8\"}, {\"warszawa.irc.pl\", \"iso8859-2" +"\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Kodowania" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "Jedynie administrator może wysyłać wiadomości serwisowe" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "Tworzenie pokoju jest zabronione przez polisę" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "Pokój konferencyjny nie istnieje" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Pokoje rozmów" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "Potrzebujesz klienta kompatybilnego z x:data aby zarejestrować nick" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Rejestracja nicka na " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Wprowadz nicka którego chcesz zarejestrować" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Nick " + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "Podany nick jest już zarejestrowany" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Musisz wypełnić pole NICKNAME w formularzu" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "Moduł MUC" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Konfiguracja pokoju zmodyfikowana" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "dołączył(a) się do pokoju" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "opóścił(a) pokój" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "został(a) zabanowany(a)" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "został(a) kopnięty(a)" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "został wyrzucony z powodu zmiany przynależności" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "został wyrzucony z powodu zmiany parametrów pokoju: Tylko dla Członków" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "został wyrzucony z powodu wyłączenia systemu" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "jest teraz znany(a) jako" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr "zmieł(a) temat na: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "Poniedziałek" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "Wtorek" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "Środa" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "Czwartek" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "Piątek" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "Sobota" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "Niedziela" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "Styczeń" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "Luty" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "Marzec" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "Kwiecień" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "Maj" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "Czerwiec" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "Lipiec" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "Sierpień" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "Wrzesień" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "Październik" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "Listopad" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "Grudzień" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Konfiguracja pokoju" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Tytuł pokoju" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Limit transferu przekroczony" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" +"Ten uczestnik został wyrzucony z pokoju ponieważ wysłał błędną wiadomość" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Nie wolno wysyłac prywatnych wiadomości na konferencje" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Nieprawidłowy typ wiadomości" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Ten uczestnik został wyrzucony z pokoju ponieważ wysłał błędą wiadomość do " +"innego uczestnika" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "Nie mozna wysyłac prywatnych wiadomości typu \"Groupchat\" " + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "Odbiorca nie jest obecny w pokoju" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Tylko obecni mogą wysyłać wiadomości na konferencje" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "Wysyłanie prywatnych wiadomości jest zabronione" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Tylko użytkownicy mogą wysyłać zapytania do pokoju konferencyjnego" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "Zapytania do członków konferencji nie są dozwolone w tym pokoju" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "prywatny, " + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "Tylko moderatorzy i wlasciciele mogą zmienić temat tego pokoju" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Tylko moderatorzy mogą zmienić temat tego pokoju" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "Odwiedzający nie mogą wysyłać wiadomości do wszystkich obecnych" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" +"Ten uczestnik został wyrzucony z pokoju ponieważ informacja o statusie " +"zawierała błędy" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Uczestnicy tego pokoju nie mogą zmieniać swoich ników" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "Nick jest używany przez innego użytkownika" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "Nick jest już zarejestrowany przez inną osobę" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Zostałeś zabanowany w tym pokoju" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "Aby wejść do pokoju wymagane jest jego członkostwo" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Pokój nie jest nieznany" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Aby wejść do pokoju wymagane jest hasło" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Nieprawidłowe hasło" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Wymagane prawa administratora" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Wymagane prawa moderatora" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "JID ~s jest niepoprawny" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "Nick ~s nie istnieje w tym pokoju" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Nieprawidłowe powiązanie: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Nieprawidłowa rola: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Wymagane uprawnienia właściciela\t" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Konfiguracja dla " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Opis:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Utwórz pokój na stałe" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Pozwól wyszukiwać pokój" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Upublicznij listę uczestników" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Zabezpiecz pokój hasłem" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Maksymalna liczba uczestników" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Bez limitu" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Kto może widzieć prawdziwe JID-y?" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "tylko moderatorzy" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "wszyscy" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Utwórz pokój tylko dla uczestnikóww" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Moderuj pokój" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Domyślni użytkownicy jako uczestnicy" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Pozwól użytkownikom zmienić tytuł pokoju" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Pozwól użytkownikom wysyłać prywatne wiadomości" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Pozwól użytkownikom pobierać informacje o innych użytkownikach" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Pozwól użytkownikom wysyłać zaproszenia" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "Pozwól uczestnikom na wysyłanie statusów opisowych" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Pozwól uczestnikom na zmianę nika" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Włącz logowanie" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "Potrzebujesz klienta kompatybilnego z x:data aby skonfigurować pokój" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Liczba uczestników" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s zaprasza Cię do pokoju ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "hasło to" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "" +"Twoja kolejka wiadomoci offline jest pełna. Wiadomoć została odrzucona." + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "~s skolejkowanych wiadomości offline" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Wprowadzone" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Czas" + +#: mod_offline.erl:507 +msgid "From" +msgstr "Od" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Do" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Pakiet " + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Usuń zaznaczone" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Wiadomości offline" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "Mudł SOCKS5 Bytestreams" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "PubSub" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "Moduł Publish-Subscribe" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "Rządzanie subskrybenta PubSub" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Wybierz, czy akceptować subskrypcję tej jednostki" + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "ID noda" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Adres subskrybenta" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Pozwól temu JID na zapisanie się do tego noda pubsub" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "" +"Dołącz zawartość publikowanego przedmiotu podczas wysyłania powiadomienia o " +"publikacji" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Dostarczaj powiadomienia o zdarzeniach" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Informuj subskrybentów gdy konfiguracja gałęzi się zmieni" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Informuj subskrybentów gdy gałąż zostanie wykasowana" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Informuj subskrybentów kiedy zostaną z gałęzi usunięte jakieś elementy" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Przechowuj przedmioty pub/sub w pamięci" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "Przyjazna nazwa węzła" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Maksymalna ilość przechowywanych przedmiotów" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Czy pozwolić na subskrypcje" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Oznacz model dostępu" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Grupy kontaktów które mogą się zapisać" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Oznacz model publikującego" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Maksymalna wielkość powiadomienia w bajtach" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Kiedy wysłać ostatnio opublikowaną rzecz" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Dostarczaj notyfikacje tylko do osiągalnych użytkowników" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "" +"Wybierz nazwę użytkownika i hasło aby zarejestrować się na tym serwerze" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "Nie możesz tak szybko rejestrować nowych kont" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Brak" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Subskrypcja " + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Oczekiwanie " + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Grupy " + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Zatwierdź" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Usuń " + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Roster " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Zły format" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Dodaj JID" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Roster " + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Grupy współdzielone" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Dodaj nowe" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Nazwa:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Opis:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Członkowie:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Wyświetlane grupy:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Grupa " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Wprowadź" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Erlang Jabber Server" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Data urodzenia: " + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Miasto: " + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "Państwo: " + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "Email" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Nazwisko rodowe: " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Wypełnij formularz aby wyszukać pasujących użytkowników Jabbera (dodaj * na " +"koniec pola aby dopasować)" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Pełna nazwa: " + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Nazwisko: " + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Nazwa" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Nazwa organizacji: " + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Dział: " + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Wyszukaj użytkowników w " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Użytkownik: " + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "Potrzebujesz klienta kompatybilnego z x:data aby wyszukiwać" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "Wyszukiwanie vCard użytkowników" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "Erlang Jabber Server" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Wyniki wyszukiwania dla " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Wypełnij pola aby znaleźdź pasujących użytkowników Jabbera" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "ejabberd: Panel Administracyjny" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Administracja" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Wirtualne hosty" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Gałęzie" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Statystyki" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Użytkownicy" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Ostatnia aktywność" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Raw)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Raw" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "~s konfiguracja zasad dostępu" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "wirtualne hosty ejabberda" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Ostatnia aktywność użytkowników" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Przedział czasu " + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Ostatni miesiąc" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Ostatni rok" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Cała aktywność" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Pokaż zwykłą tabelę" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Pokaż tabelę całkowitą" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Gałąź nie znaleziona" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Host" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Użytkownicy zarejestrowani" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Wiadomości offline" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Użytkownicy zarejestrowani:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Użytkownicy online:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Wychodzące połączenia s2s:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Serwery zewnętrzne s2s:" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Zmień hasło" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Użytkownik " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Zasoby podłączone" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Hasło:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Brak danych" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Gałąź " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Porty nasłuchujące" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Aktualizacja" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Restart" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Stop" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "Błąd odwołania RPC" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Tabele bazy na " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Typ bazy" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Wielkość" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Pamięć" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Kopia zapasowa " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Te opcje backupują jedynie bazę Mnesia. Jeśli używasz modułu ODBC - musisz " +"wykonać kopię SQL oddzielnie" + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Zachowaj kopię binarną:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "OK" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Natychmiast odtwórz kopię binarną:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"Odtwórz kopię binarną podczas następnego restaru ejabberd-a (wymaga mniej " +"pamięci)" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Zachowaj kopię w czystym tekście" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Odtwórz kopię z czystego tekstu" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Porty nasłuchujące " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Moduły na " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "Statystyki ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Uptime" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "Czas CPU" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Transakcje zakończone" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Transakcje anulowane" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Transakcje uruchomione ponownie" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Transakcje logowane" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Uaktualnij" + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Uaktualnij plan" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Uaktualnione moduły" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Uaktualnij skrypt" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Skrypt update-u niskiego poziomu" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Sprawdź skrypt" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Port" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Moduł" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Opcje" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Usuń" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Start" + +#~ msgid "You must fill in field \"Icon\" in the form" +#~ msgstr "Musisz wypełnić w formularzu pole \"Icon\"" + +#~ msgid "You must fill in field \"Xml\" in the form" +#~ msgstr "Musisz wypełnić w formularzu pole \"XML\"" diff --git a/src/msgs/pt-br.msg b/src/msgs/pt-br.msg index 9af4f558f..97f2fca49 100644 --- a/src/msgs/pt-br.msg +++ b/src/msgs/pt-br.msg @@ -1,406 +1,343 @@ -% $Id$ -% Language: Portuguese (Brazil) -% Author: Otávio Fernandes -% Author: Renato Botelho -% Author: Lucius Curado -% Author: Felipe Brito Vasconcellos -% Author: Victor Hugo dos Santos - -% jlib.hrl -{"No resource provided", "Recurso não foi fornecido"}. - -% mod_configure.erl -{"Restart Service", "Reiniciar Serviço"}. -{"Shut Down Service", "Parar Serviço"}. -{"Delete User", "Deletar Usuário"}. -{"End User Session", "Terminar Sessão do Usuário"}. -{"Get User Password", "Obter Senha do Usuário"}. -{"Change User Password", "Alterar Senha do Usuário"}. -{"Get User Last Login Time", "Obter a Data do Último Login"}. -{"Get User Statistics", "Obter Estatísticas do Usuário"}. -{"Get Number of Registered Users", "Obter Número de Usuários Registrados"}. -{"Get Number of Online Users", "Obter Número de Usuários Online"}. -{"User Management", "Gerenciamento de Usuários"}. -{"Time delay", "Intervalo de Tempo"}. -{"Password Verification", "Verificação de Senha"}. -{"Number of registered users", "Número de usuários registrados"}. -{"Number of online users", "Número de usuários online"}. -{"Last login", "Último login"}. -{"Roster size", "Tamanho da Lista"}. -{"IP addresses", "Endereços IP"}. -{"Resources", "Recursos"}. -{"Access Configuration", "Configuração de Acesso"}. -{"Access Control List Configuration", "Configuração da Lista de Controle de Acesso"}. -{"Access control lists", "Listas de Controle de Acesso"}. -{"Access rules", "Regras de acesso"}. -{"Action on user", "Ação no usuário"}. -{"Administration of ", "Administração de "}. -{"Backup to File at ", "Salvar cópia de segurança para arquivo em "}. -{"Choose modules to stop", "Selecione módulos a parar"}. -{"Choose storage type of tables", "Selecione o tipo de armazenamento das tabelas"}. -{"Disc only copy", "Copia em disco somente"}. -{"Dump Backup to Text File at ", "Exporta cópia de segurança para arquivo de texto em "}. -{"Edit Properties", "Editar propriedades"}. -{"Enter list of {Module, [Options]}", "Introduza lista de {módulo, [opções]}"}. -{"Enter path to backup file", "Introduza o caminho do arquivo de cópia de segurança"}. -{"Enter path to jabberd1.4 spool dir", "Introduza o caminho para o diretório de spools do jabberd1.4"}. -{"Enter path to jabberd1.4 spool file", "Introduza o caminho para o arquivo de spool do jabberd1.4"}. -{"Enter path to text file", "Introduza caminho para o arquivo de texto"}. -{"Import User from File at ", "Importar usuário a partir do arquivo em "}. -{"Import Users from Dir at ", "Importar usuários a partir do diretório em "}. -{"Path to Dir", "Caminho para o diretório"}. -{"Path to File", "Caminho do arquivo"}. -{"RAM and disc copy", "Copia em RAM y disco"}. -{"RAM copy", "Copia em RAM"}. -{"Remote copy", "Copia remota"}. -{"Remove User", "Remover usuário"}. -{"Restore Backup from File at ", "Restaura cópia de segurança a partir do arquivo em "}. -{"Start Modules at ", "Iniciar módulos em "}. - -% mod_disco.erl -{"Access Control Lists", "Listas de Controle de Acesso"}. -{"Access Rules", "Regras de Aceso"}. -{"All Users", "Todos os usuários"}. -{"Backup", "Salvar cópia de segurança"}. -{"Backup Management", "Gestão de copia de segurança"}. -{"Configuration", "Configuração"}. -{"Dump to Text File", "Exportar para arquivo de texto"}. -{"From ~s", "De ~s"}. -{"Import Directory", "Importar diretório"}. -{"Import File", "Importar arquivo"}. -{"Modules", "Módulos"}. -{"Online Users", "Usuários conectados"}. -{"Restore", "Restaurar"}. -{"Running Nodes", "Nos em execução"}. -{"Start Modules", "Iniciar módulos"}. -{"Stop Modules", "Parar módulos"}. -{"Stopped Nodes", "Nos parados"}. -{"To ~s", "Para ~s"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Escolha um nome de usuário e senha para registrar-se neste servidor"}. - -% mod_vcard.erl +{"Access Configuration","Configuração de Acesso"}. +{"Access Control List Configuration","Configuração da Lista de Controle de Acesso"}. +{"Access control lists","Listas de Controle de Acesso"}. +{"Access Control Lists","Listas de Controle de Acesso"}. +{"Access denied by service policy","Aceso denegado por la política do serviço"}. +{"Access Rules","Regras de Aceso"}. +{"Access rules","Regras de acesso"}. +{"Action on user","Ação no usuário"}. +{"Add Jabber ID","Adicionar ID jabber"}. +{"Add New","Adicionar novo"}. +{"Add User","Adicionar usuário"}. +{"Administration","Administração"}. +{"Administration of ","Administração de "}. +{"Administrator privileges required","Se necessita privilégios de administrador"}. +{"A friendly name for the node","Um nome familiar para o nó"}. +{"All activity","Toda la atividade"}. +{"Allow this JID to subscribe to this pubsub node?","Autorizar este JID para a inscrição neste tópico pubsub ?"}. +{"Allow users to change subject","Permitir a usuários modificar o assunto"}. +{"Allow users to query other users","Permitir a usuários pesquisar informações sobre os demais"}. +{"Allow users to send invites","Permitir a usuários envio de convites"}. +{"Allow users to send private messages","Permitir a usuários enviarem mensagens privadas"}. +{"Allow visitors to change nickname","Permitir mudança de apelido aos visitantes"}. +{"Allow visitors to send status text in presence updates","Permitir atualizações de status aos visitantes"}. +{"All Users","Todos os usuários"}. +{"Announcements","Anúncios"}. +{"anyone","qualquer um"}. +{"April","Abril"}. +{"August","Agosto"}. +{"Backup Management","Gestão de copia de segurança"}. +{"Backup of ","Backup de"}. +{"Backup","Salvar cópia de segurança"}. +{"Backup to File at ","Salvar cópia de segurança para arquivo em "}. +{"Bad format","Formato incorreto"}. {"Birthday","Aniversário"}. -{"City", "Cidade"}. +{"Change Password","Mudar senha"}. +{"Change User Password","Alterar Senha do Usuário"}. +{"Chatroom configuration modified","Configuração da sala de bate-papo modificada"}. +{"Chatrooms","Salas de Chat"}. +{"Choose a username and password to register with this server","Escolha um nome de usuário e senha para registrar-se neste servidor"}. +{"Choose modules to stop","Selecione módulos a parar"}. +{"Choose storage type of tables","Selecione o tipo de armazenamento das tabelas"}. +{"Choose whether to approve this entity's subscription.","Aprovar esta assinatura."}. +{"City","Cidade"}. +{"Commands","Comandos"}. +{"Conference room does not exist","La sala de conferencias não existe"}. +{"Configuration","Configuração"}. +{"Configuration for ","Configuração para "}. +{"Connected Resources:","Recursos conectados:"}. {"Country","País"}. -{"ejabberd vCard module", "Módulo vCard para ejabberd"}. -{"Erlang Jabber Server", "Servidor Jabber em Erlang"}. -{"Family Name", "Nome de família"}. -{"Fill in fields to search for any matching Jabber User", "Preencha os campos para procurar usuários Jabber coincidentes"}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Preencha o formulário para buscar usuários Jabber. Agrega * ao final de um campo para buscar sub-palavras."}. -{"Full Name", "Nome completo"}. -{"Middle Name", "Apelido"}. -{"Name", "Nome"}. -{"Nickname", "Nick"}. -{"Organization Name", "Nome da organização"}. -{"Organization Unit", "Unidade da organização"}. -{"Search users in ", "Procurar usuários em "}. -{"User", "Usuário"}. -{"You need an x:data capable client to search", "Necessitas um cliente com suporte de x:data para poder buscar"}. - -% mod_pubsub/mod_pubsub.erl -{"Publish-Subscribe", "Publicação de Tópico"}. -{"ejabberd Publish-Subscribe module", "Módulo para Publicar Tópicos do ejabberd"}. -{"PubSub subscriber request", "PubSub requisição de assinante"}. -{"Choose whether to approve this entity's subscription.", "Aprovar esta assinatura."}. -{"Node ID", "ID do Tópico"}. -{"Subscriber Address", "Enderço dos Assinantes"}. -{"Allow this JID to subscribe to this pubsub node?", "Autorizar este JID para a inscrição neste tópico pubsub ?"}. -{"Deliver event notifications", "Entregar as notificações de evento"}. -{"Specify the access model", "Especificar os modelos de acesso"}. -{"Roster groups allowed to subscribe", "Listar grupos autorizados"}. -{"When to send the last published item", "Quando enviar o último tópico publicado"}. -{"Deliver payloads with event notifications", "Enviar payloads junto com as notificações de eventos"}. -{"Max # of items to persist", "Máximo # de elementos que persistem"}. -{"Max payload size in bytes", "Máximo tamanho do payload em bytes"}. -{"Notify subscribers when items are removed from the node", "Notificar subscritores quando os elementos se eliminem do nodo"}. -{"Notify subscribers when the node configuration changes", "Notificar subscritores quando cambia la configuração do nodo"}. -{"Notify subscribers when the node is deleted", "Notificar subscritores quando o nodo se elimine"}. -{"Only deliver notifications to available users", "Solo enviar notificações aos usuários disponíveis"}. -{"Persist items to storage", "Persistir elementos ao armazenar"}. -{"Specify the publisher model", "Especificar o modelo do publicante"}. -{"Whether to allow subscriptions", "Permitir subscrições"}. - -% mod_muc/mod_muc.erl -{"Chatrooms", "Salas de Chat"}. -{"Access denied by service policy", "Aceso denegado por la política do serviço"}. -{"Conference room does not exist", "La sala de conferencias não existe"}. -{"ejabberd MUC module", "Módulo de MUC para ejabbed"}. -{"Enter nickname you want to register", "Introduza o apelido que quer registrar"}. -{"Incorrect password", "Senha incorreta"}. -{"Nickname is already in use by another occupant", "O apelido já está em uso por outro ocupante"}. -{"Nickname is registered by another person", "O apelido já está registrado por outra pessoa"}. -{"Nickname Registration at ", "Registro do apelido em "}. -{"Nickname ~s does not exist in the room", "Apelido ~s não existe na sala"}. -{"Password required to enter this room", "É necessária a senha para poder entrar nesta sala"}. -{"Password", "Senha"}. -{"Room creation is denied by service policy", "Se te a denegado criar la sala por política do serviço"}. -{"Specified nickname is already registered", "O apelido especificado já está registrado"}. -{"You need an x:data capable client to register nickname", "Necessitas um cliente com suporte de x:data para poder registrar o nick"}. - -% mod_muc/mod_muc_room.erl -{"Traffic rate limit is exceeded", "Limite de banda excedido"}. -{"This participant is kicked from the room because he sent an error message", "Este participante foi desconectado da sala de chat por ter enviado uma mensagem de erro."}. -{"This participant is kicked from the room because he sent an error message to another participant", "Este participante foi desconectado da sala de chat por ter enviado uma mensagem de erro para outro usuário."}. -{"This participant is kicked from the room because he sent an error presence", "Este participante foi desconectado da sala de chat por ter enviado uma notificação errônea de presença."}. -{"Maximum Number of Occupants", "Número máximo de participantes"}. -{"No limit", "Ilimitado"}. -{"~s invites you to the room ~s", "~s convidou você para a sala ~s"}. -{"the password is", "a senha é"}. -{"Make room moderated", "Tornar a sala moderada"}. -{"Administrator privileges required", "Se necessita privilégios de administrador"}. -{"Configuration for ", "Configuração para "}. -{" has set the subject to: ", " a posto o assunto: "}. -{"Improper message type", "Tipo de mensagem incorreto"}. -{"Incorrect password", "Senha incorreta"}. -{"Invalid affiliation: ~s", "Afiliação não válida: ~s"}. -{"Invalid role: ~s", "Rol não válido: ~s"}. -{"It is not allowed to send private messages of type \"groupchat\"", "No está permitido enviar mensagens privados do tipo \"groupchat\""}. -{"It is not allowed to send private messages to the conference", "Impedir o envio de mensagens privados a la sala"}. -{"JID ~s is invalid", "O JID ~s não es válido"}. -{"Membership required to enter this room", "Necessitas ser membro de esta sala para poder entrar"}. -{"Moderator privileges required", "Se necessita privilégios de moderador"}. -{"Nickname is already in use by another occupant", "O nick já está sendo usado por outro ocupante"}. -{"Nickname is registered by another person", "O nick já está registrado por outra pessoa"}. -{"Nickname ~s does not exist in the room", "O nick ~s não existe em la sala"}. -{"Only moderators and participants are allowed to change subject in this room", "Solo os moderadores y participantes podem cambiar o assunto de esta sala"}. -{"Only moderators are allowed to change subject in this room", "Solo os moderadores podem cambiar o assunto de esta sala"}. -{"Only occupants are allowed to send messages to the conference", "Solo os ocupantes podem enviar mensagens a la sala"}. -{"Only occupants are allowed to send queries to the conference", "Solo os ocupantes podem enviar consultas a la sala"}. -{"Owner privileges required", "Se requere privilégios de proprietário da sala"}. -{"Password", "Senha"}. -{"Password required to enter this room", "Se necessita senha para entrar em esta sala"}. -{"private, ", "privado"}. -{"Queries to the conference members are not allowed in this room", "Nesta sala não se permite consultas aos membros da sala"}. -{"Recipient is not in the conference room", "O receptor não está em la sala de conferencia"}. -{"Room title", "Título da sala"}. -{"Visitors are not allowed to send messages to all occupants", "Os visitantes não podem enviar mensagens a todos os ocupantes"}. -{"You have been banned from this room", "As sido bloqueado em esta sala"}. -{"You need an x:data capable client to configure room", "Necessitas um cliente com suporte de x:data para configurar la sala"}. - -% mod_irc/mod_irc.erl -{"IRC Transport", "IRC Transport"}. -{"ejabberd IRC module", "Módulo de IRC para ejabberd"}. -{"Encodings", "Codificação"}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Introduza o nome de usuário e codificações de caracteres que quer usar ao conectar-se aos servidores de IRC"}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Exemplo: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Se deseja especificar codificações de caracteres diferentes para cada servidor IRC preencha esta lista com valores no formato '{\"servidor irc\", \"codificação\"}'. Este serviço usa por padrão a codificação \"~s\"."}. -{"IRC Username", "Nome de usuário no IRC"}. -{"Registration in mod_irc for ", "Registro em mod_irc para"}. -{"You need an x:data capable client to configure mod_irc settings", "Necessitas um cliente com suporte de x:data para configurar las opções de mod_irc"}. - -% web/ejabberd_web_admin.erl -{"ejabberd Web Admin", "ejabberd Web Admin"}. -{"Add New", "Adicionar novo"}. -{"Add User", "Adicionar usuário"}. -{"All activity", "Toda la atividade"}. -{"Change Password", "Mudar senha"}. -{"Connected Resources:", "Recursos conectados:"}. -{"Delete", "Eliminar"}. -{"Delete Selected", "Remover os selecionados"}. -{"ejabberd virtual hosts", "Maquinas virtuais de ejabberd"}. -{"From", "De"}. -{"Group ", "Grupo "}. -{"Groups", "Grupos"}. -{"Host", "Máquina"}. -{"Last Activity", "Última atividade"}. -{"Last month", "Último mês"}. -{"Last year", "Último ano"}. -{"Listened Ports at ", "Portas de escuta em "}. -{"Members:", "Miembros:"}. -{"Memory", "Memória"}. -{"Module", "Módulo"}. -{"Modules at ", "Módulos em "}. -{"Name:", "Nome:"}. -{"Name", "Nome"}. -{"Never", "Nunca"}. -{"Nickname", "Apelido"}. -{"Online", "Conectado"}. -{"Options", "Opções"}. -{"Packet", "Pacote"}. -{"Password:", "Senha:"}. -{"Pending", "Pendente"}. -{"Period: ", "Período: "}. -{"Port", "Porta"}. -{"Remove", "Borrar"}. -{"Restart", "Reiniciar"}. -{"Roster", "Lista de contatos"}. -{"Roster of ", "Lista de contatos de "}. -{"~s access rule configuration", "Configuração da Regra de Acesso ~s"}. -{"Show Integral Table", "Mostrar Tabela Integral"}. -{"Show Ordinary Table", "Mostrar Tabela Ordinária"}. -{"Size", "Tamanho"}. -{"Start", "Iniciar"}. -{"Statistics", "Estatísticas"}. -{"Stop", "Parar"}. -{"Storage Type", "Tipo de armazenamento"}. -{"Submit", "Enviar"}. -{"Subscription", "Subscrição"}. -{"Time", "Fecha"}. -{"To", "Para"}. - -{"Update", "Atualizar"}. -{"Users", "Usuários"}. -{"User ", "Usuário"}. -{"Validate", "Validar"}. -{"Virtual Hosts", "Maquinas Virtuais"}. - -% ejabberd_c2s.erl -{"Use of STARTTLS required", "É obrigatório usar STARTTLS"}. - -% mod_vcard_ldap.erl -{"Fill in fields to search for any matching Jabber User", "Preencha campos para buscar usuários Jabber que concordem"}. - -% mod_adhoc.erl -{"Commands", "Comandos"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% mod_vcard_odbc.erl -{"vCard User Search", "Busca de Usuário vCard"}. -{"Email", "e-mail"}. -{"Search Results for ", "Resultados de pesquisa para"}. -{"Jabber ID", "ID Jabber"}. - -% ejabberd_c2s.erl -{"Replaced by new connection", "Substituído por nova conexão"}. - -% mod_announce.erl -{"Send announcement to all users on all hosts", "Enviar aviso para todos os usuários em todos os hosts"}. -{"Set message of the day on all hosts and send to online users", "Definir mensagem do dia em todos os hosts e enviar para os usuários online"}. -{"Update message of the day on all hosts (don't send)", "Atualizar a mensagem do dia em todos os host (não enviar)"}. -{"Delete message of the day on all hosts", "Apagar a mensagem do dia em todos os hosts"}. -{"Really delete message of the day?", "Deletar realmente a mensagem do dia?"}. -{"Subject", "Assunto"}. -{"Message body", "Corpo da mensagem"}. -{"No body provided for announce message", "Nenhum corpo de texto fornecido para anunciar mensagem"}. -{"Announcements", "Anúncios"}. -{"Send announcement to all users", "Enviar anúncio a todos os usuários"}. -{"Send announcement to all online users", "Enviar anúncio a todos os usuárions online"}. -{"Send announcement to all online users on all hosts", "Enviar anúncio a todos usuários online em todas as máquinas"}. -{"Set message of the day and send to online users", "Definir mensagem do dia e enviar a todos usuários online"}. -{"Update message of the day (don't send)", "Atualizar mensagem do dia (não enviar)"}. -{"Delete message of the day", "Apagar mensagem do dia"}. - -% mod_configure.erl -{"Database", "Base de dados"}. -{"Outgoing s2s Connections", "Conexões que partam de s2s"}. -{"Import Users From jabberd 1.4 Spool Files", "Importar usuários de arquivos jabberd 1.4"}. -{"Database Tables Configuration at ", "Configuração de Tabelas de Base de dados em "}. -{"Stop Modules at ", "Parar módulos em "}. -{"List of modules to start", "Listas de módulos para inicializar"}. - -% web/ejabberd_web_admin.erl -{"Administration", "Administração"}. -{"Nodes", "Nós"}. -{"(Raw)", "(Intocado)"}. -{"Submitted", "Submetido"}. -{"Bad format", "Formato incorreto"}. -{"Raw", "Intocado"}. -{"Users Last Activity", "Ultimas atividades dos usuários"}. -{"Node not found", "Nó não encontrado"}. -{"Registered Users", "Usuários Registrados"}. -{"Offline Messages", "Mensagens offline"}. -{"Registered Users:", "Usuários registrados"}. -{"Online Users:", "Usuários online"}. -{"Outgoing s2s Connections:", "Conexões que partem de s2s"}. -{"Outgoing s2s Servers:", "Servidores que partem de s2s"}. -{"None", "Nenhum"}. -{"Offline Messages:", "Mensagens offline"}. -{"~s's Offline Messages Queue", "~s's Fila de Mensagens Offline"}. -{"Add Jabber ID", "Adicionar ID jabber"}. -{"No Data", "Nenhum dado"}. -{"Node ", "Nó"}. -{"Listened Ports", "Portas escutadas"}. -{"RPC Call Error", "Erro de chamada RPC"}. -{"Database Tables at ", "Tabelas de base de dados em"}. -{"Backup of ", "Backup de"}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "Observe que tais opções farão backup apenas da base de dados Mnesia. Caso você esteja utilizando o modulo ODBC, você precisará fazer backup de sua base de dados SQL separadamente."}. -{"Store binary backup:", "Armazenar backup binário:"}. -{"OK", "OK"}. -{"Restore binary backup immediately:", "Restaurar backup binário imediatamente"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Restaurar backup binário após próximo reinicialização do ejabberd (requer menos memória):"}. -{"Store plain text backup:", "Armazenar backup plain text"}. -{"Restore plain text backup immediately:", "Restaurar backup plain text imediatamente:"}. -{"Statistics of ~p", "Estatísticas de ~p"}. -{"Uptime:", "Uptime:"}. -{"CPU Time:", "Tempo de CPU"}. -{"Transactions Commited:", "Transações:"}. -{"Transactions Aborted:", "Transações abortadas:"}. -{"Transactions Restarted:", "Transações restauradas:"}. -{"Transactions Logged:", "Transações de log:"}. -{"Update ", "Atualizar"}. -{"Update plan", "Plano de Atualização"}. -{"Updated modules", "Módulos atualizados"}. -{"Update script", "Script de atualização"}. -{"Low level update script", "Script de atualização low level"}. -{"Script check", "Verificação de Script"}. -{"Shared Roster Groups", "Grupos Shared Roster"}. -{"Description:", "Descrição:"}. -{"Displayed Groups:", "Grupos Indicados"}. - -% mod_muc/mod_muc_log.erl -{"has been kicked because of an affiliation change", "foi desconectado porque por afiliação inválida"}. -{"has been kicked because the room has been changed to members-only", "foi desconectado porque a política da sala mudou, só membros são permitidos"}. -{"has been kicked because of a system shutdown", "foi desconectado porque o sistema foi desligado"}. -{"Chatroom configuration modified", "Configuração da sala de bate-papo modificada"}. -{"joins the room", "Entrar na sala"}. -{"leaves the room", "Sair da sala"}. -{"has been kicked", "foi removido"}. -{"has been banned", "foi banido"}. -{"Monday", "Segunda"}. -{"Tuesday", "Terça"}. -{"Wednesday", "Quarta"}. -{"Thursday", "Quinta"}. -{"Friday", "Sexta"}. -{"Saturday", "Sábado"}. -{"Sunday", "Domingo"}. -{"January", "Janeiro"}. -{"February", "Fevereiro"}. -{"March", "Março"}. -{"April", "Abril"}. -{"May", "Maio"}. -{"June", "Junho"}. -{"July", "Julho"}. -{"August", "Agosto"}. -{"September", "Setembro"}. -{"October", "Outubro"}. -{"November", "Novembro"}. -{"December", "Dezembro"}. -{"Room Configuration", "Configuração de salas"}. - -% mod_muc/mod_muc.erl -{"Only service administrators are allowed to send service messages", "Apenas administradores possuem permissão para enviar mensagens de serviço"}. -{"You must fill in field \"Nickname\" in the form", "Você deve completar o campo \"Apelido\" no formulário"}. - -% mod_muc/mod_muc_room.erl -{"This room is not anonymous", "Essa sala não é anônima"}. -{"Make room persistent", "Tornar sala persistente"}. -{"Make room public searchable", "Tornar sala pública possível de ser encontrada"}. -{"Make participants list public", "Tornar pública a lista de participantes"}. -{"Make room password protected", "Tornar protegida a senha da sala"}. -{"Make room members-only", "Tornar sala apenas para membros"}. -{"Make room moderated", "Tornar a sala moderada"}. -{"Default users as participants", "Usuários padrões como participantes"}. -{"Allow users to change subject", "Permitir a usuários modificar o assunto"}. -{"Allow users to send private messages", "Permitir a usuários enviarem mensagens privadas"}. -{"Allow users to query other users", "Permitir a usuários pesquisar informações sobre os demais"}. -{"Allow users to send invites", "Permitir a usuários envio de convites"}. -{"Enable logging", "Permitir criação de logs"}. -{"Number of occupants", "Número de participantes"}. -{"Present real JIDs to", "Tornar o JID real visível por"}. -{"moderators only", "apenas moderadores"}. -{"anyone", "qualquer um"}. -{"is now known as", "é agora conhecido como"}. - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "Sua fila de mensagens offline esta cheia. Sua mensagem foi descartada"}. - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "Modulo ejabberd SOCKS5 Bytestreams"}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"CPU Time:","Tempo de CPU"}. +{"Database","Base de dados"}. +{"Database Tables at ","Tabelas de base de dados em"}. +{"Database Tables Configuration at ","Configuração de Tabelas de Base de dados em "}. +{"December","Dezembro"}. +{"Default users as participants","Usuários padrões como participantes"}. +{"Delete","Eliminar"}. +{"Delete message of the day","Apagar mensagem do dia"}. +{"Delete message of the day on all hosts","Apagar a mensagem do dia em todos os hosts"}. +{"Delete Selected","Remover os selecionados"}. +{"Delete User","Deletar Usuário"}. +{"Deliver event notifications","Entregar as notificações de evento"}. +{"Deliver payloads with event notifications","Enviar payloads junto com as notificações de eventos"}. +{"Description:","Descrição:"}. +{"Disc only copy","Copia em disco somente"}. +{"Displayed Groups:","Grupos Indicados"}. +{"Dump Backup to Text File at ","Exporta cópia de segurança para arquivo de texto em "}. +{"Dump to Text File","Exportar para arquivo de texto"}. +{"Edit Properties","Editar propriedades"}. +{"ejabberd IRC module","Módulo de IRC para ejabberd"}. +{"ejabberd MUC module","Módulo de MUC para ejabberd"}. +{"ejabberd Publish-Subscribe module","Módulo para Publicar Tópicos do ejabberd"}. +{"ejabberd SOCKS5 Bytestreams module","Modulo ejabberd SOCKS5 Bytestreams"}. +{"ejabberd vCard module","Módulo vCard para ejabberd"}. +{"ejabberd virtual hosts","Maquinas virtuais de ejabberd"}. +{"ejabberd Web Admin","ejabberd Web Admin"}. +{"Email","e-mail"}. +{"Enable logging","Permitir criação de logs"}. +{"Encodings","Codificação"}. +{"End User Session","Terminar Sessão do Usuário"}. +{"Enter list of {Module, [Options]}","Introduza lista de {módulo, [opções]}"}. +{"Enter nickname you want to register","Introduza o apelido que quer registrar"}. +{"Enter path to backup file","Introduza o caminho do arquivo de cópia de segurança"}. +{"Enter path to jabberd1.4 spool dir","Introduza o caminho para o diretório de spools do jabberd1.4"}. +{"Enter path to jabberd1.4 spool file","Introduza o caminho para o arquivo de spool do jabberd1.4"}. +{"Enter path to text file","Introduza caminho para o arquivo de texto"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Introduza o nome de usuário e codificações de caracteres que quer usar ao conectar-se aos servidores de IRC"}. +{"Erlang Jabber Server","Servidor Jabber em Erlang"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Exemplo: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","Nome de família"}. +{"February","Fevereiro"}. +{"Fill in fields to search for any matching Jabber User","Preencha campos para buscar usuários Jabber que concordem"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Preencha o formulário para buscar usuários Jabber. Agrega * ao final de um campo para buscar sub-palavras."}. +{"Friday","Sexta"}. +{"From","De"}. +{"From ~s","De ~s"}. +{"Full Name","Nome completo"}. +{"Get Number of Online Users","Obter Número de Usuários Online"}. +{"Get Number of Registered Users","Obter Número de Usuários Registrados"}. +{"Get User Last Login Time","Obter a Data do Último Login"}. +{"Get User Password","Obter Senha do Usuário"}. +{"Get User Statistics","Obter Estatísticas do Usuário"}. +{"Group ","Grupo "}. +{"Groups","Grupos"}. +{"has been banned","foi banido"}. +{"has been kicked because of an affiliation change","foi desconectado porque por afiliação inválida"}. +{"has been kicked because of a system shutdown","foi desconectado porque o sistema foi desligado"}. +{"has been kicked because the room has been changed to members-only","foi desconectado porque a política da sala mudou, só membros são permitidos"}. +{"has been kicked","foi removido"}. +{" has set the subject to: "," a posto o assunto: "}. +{"Host","Máquina"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Se deseja especificar codificações de caracteres diferentes para cada servidor IRC preencha esta lista com valores no formato '{\"servidor irc\", \"codificação\"}'. Este serviço usa por padrão a codificação \"~s\"."}. +{"Import Directory","Importar diretório"}. +{"Import File","Importar arquivo"}. +{"Import User from File at ","Importar usuário a partir do arquivo em "}. +{"Import Users from Dir at ","Importar usuários a partir do diretório em "}. +{"Import Users From jabberd 1.4 Spool Files","Importar usuários de arquivos jabberd 1.4"}. +{"Improper message type","Tipo de mensagem incorreto"}. +{"Incorrect password","Senha incorreta"}. +{"Invalid affiliation: ~s","Afiliação não válida: ~s"}. +{"Invalid role: ~s","Rol não válido: ~s"}. +{"IP addresses","Endereços IP"}. +{"IRC Transport","IRC Transport"}. +{"IRC Username","Nome de usuário no IRC"}. +{"is now known as","é agora conhecido como"}. +{"It is not allowed to send private messages","Não é permitido enviar mensagens privadas"}. +{"It is not allowed to send private messages of type \"groupchat\"","No está permitido enviar mensagens privados do tipo \"groupchat\""}. +{"It is not allowed to send private messages to the conference","Impedir o envio de mensagens privados a la sala"}. +{"Jabber ID","ID Jabber"}. +{"January","Janeiro"}. +{"JID ~s is invalid","O JID ~s não es válido"}. +{"joins the room","Entrar na sala"}. +{"July","Julho"}. +{"June","Junho"}. +{"Last Activity","Última atividade"}. +{"Last login","Último login"}. +{"Last month","Último mês"}. +{"Last year","Último ano"}. +{"leaves the room","Sair da sala"}. +{"Listened Ports at ","Portas de escuta em "}. +{"Listened Ports","Portas escutadas"}. +{"List of modules to start","Listas de módulos para inicializar"}. +{"Low level update script","Script de atualização low level"}. +{"Make participants list public","Tornar pública a lista de participantes"}. +{"Make room members-only","Tornar sala apenas para membros"}. +{"Make room moderated","Tornar a sala moderada"}. +{"Make room password protected","Tornar protegida a senha da sala"}. +{"Make room persistent","Tornar sala persistente"}. +{"Make room public searchable","Tornar sala pública possível de ser encontrada"}. +{"March","Março"}. +{"Maximum Number of Occupants","Número máximo de participantes"}. +{"Max # of items to persist","Máximo # de elementos que persistem"}. +{"Max payload size in bytes","Máximo tamanho do payload em bytes"}. +{"May","Maio"}. +{"Membership required to enter this room","Necessitas ser membro de esta sala para poder entrar"}. +{"Members:","Miembros:"}. +{"Memory","Memória"}. +{"Message body","Corpo da mensagem"}. +{"Middle Name","Apelido"}. +{"Moderator privileges required","Se necessita privilégios de moderador"}. +{"moderators only","apenas moderadores"}. +{"Module","Módulo"}. +{"Modules at ","Módulos em "}. +{"Modules","Módulos"}. +{"Monday","Segunda"}. +{"Name:","Nome:"}. +{"Name","Nome"}. +{"Never","Nunca"}. +{"Nickname","Apelido"}. +{"Nickname is already in use by another occupant","O nick já está sendo usado por outro ocupante"}. +{"Nickname is registered by another person","O nick já está registrado por outra pessoa"}. +{"Nickname Registration at ","Registro do apelido em "}. +{"Nickname ~s does not exist in the room","O nick ~s não existe em la sala"}. +{"No body provided for announce message","Nenhum corpo de texto fornecido para anunciar mensagem"}. +{"No Data","Nenhum dado"}. +{"Node ID","ID do Tópico"}. +{"Node ","Nó"}. +{"Node not found","Nó não encontrado"}. +{"Nodes","Nós"}. +{"No limit","Ilimitado"}. +{"None","Nenhum"}. +{"No resource provided","Recurso não foi fornecido"}. +{"Notify subscribers when items are removed from the node","Notificar subscritores quando os elementos se eliminem do nodo"}. +{"Notify subscribers when the node configuration changes","Notificar subscritores quando cambia la configuração do nodo"}. +{"Notify subscribers when the node is deleted","Notificar subscritores quando o nodo se elimine"}. +{"November","Novembro"}. +{"Number of occupants","Número de participantes"}. +{"Number of online users","Número de usuários online"}. +{"Number of registered users","Número de usuários registrados"}. +{"October","Outubro"}. +{"Offline Messages:","Mensagens offline"}. +{"Offline Messages","Mensagens offline"}. +{"OK","OK"}. +{"Online","Conectado"}. +{"Online Users","Usuários conectados"}. +{"Online Users:","Usuários online"}. +{"Only deliver notifications to available users","Solo enviar notificações aos usuários disponíveis"}. +{"Only moderators and participants are allowed to change subject in this room","Solo os moderadores y participantes podem cambiar o assunto de esta sala"}. +{"Only moderators are allowed to change subject in this room","Solo os moderadores podem cambiar o assunto de esta sala"}. +{"Only occupants are allowed to send messages to the conference","Solo os ocupantes podem enviar mensagens a la sala"}. +{"Only occupants are allowed to send queries to the conference","Solo os ocupantes podem enviar consultas a la sala"}. +{"Only service administrators are allowed to send service messages","Apenas administradores possuem permissão para enviar mensagens de serviço"}. +{"Options","Opções"}. +{"Organization Name","Nome da organização"}. +{"Organization Unit","Unidade da organização"}. +{"Outgoing s2s Connections","Conexões que partam de s2s"}. +{"Outgoing s2s Connections:","Conexões que partem de s2s"}. +{"Outgoing s2s Servers:","Servidores que partem de s2s"}. +{"Owner privileges required","Se requere privilégios de proprietário da sala"}. +{"Packet","Pacote"}. +{"Password required to enter this room","Se necessita senha para entrar em esta sala"}. +{"Password:","Senha:"}. +{"Password","Senha"}. +{"Password Verification","Verificação de Senha"}. +{"Path to Dir","Caminho para o diretório"}. +{"Path to File","Caminho do arquivo"}. +{"Pending","Pendente"}. +{"Period: ","Período: "}. +{"Persist items to storage","Persistir elementos ao armazenar"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","Porta"}. +{"Present real JIDs to","Tornar o JID real visível por"}. +{"private, ","privado"}. +{"Publish-Subscribe","Publicação de Tópico"}. +{"PubSub subscriber request","PubSub requisição de assinante"}. +{"Queries to the conference members are not allowed in this room","Nesta sala não se permite consultas aos membros da sala"}. +{"RAM and disc copy","Copia em RAM y disco"}. +{"RAM copy","Copia em RAM"}. +{"(Raw)","(Intocado)"}. +{"Raw","Intocado"}. +{"Really delete message of the day?","Deletar realmente a mensagem do dia?"}. +{"Recipient is not in the conference room","O receptor não está em la sala de conferencia"}. +{"Registered Users:","Usuários registrados"}. +{"Registered Users","Usuários Registrados"}. +{"Registration in mod_irc for ","Registro em mod_irc para"}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Observe que tais opções farão backup apenas da base de dados Mnesia. Caso você esteja utilizando o modulo ODBC, você precisará fazer backup de sua base de dados SQL separadamente."}. +{"Remote copy","Copia remota"}. +{"Remove","Borrar"}. +{"Remove User","Remover usuário"}. +{"Replaced by new connection","Substituído por nova conexão"}. +{"Resources","Recursos"}. +{"Restart","Reiniciar"}. +{"Restart Service","Reiniciar Serviço"}. +{"Restore Backup from File at ","Restaura cópia de segurança a partir do arquivo em "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Restaurar backup binário após próximo reinicialização do ejabberd (requer menos memória):"}. +{"Restore binary backup immediately:","Restaurar backup binário imediatamente"}. +{"Restore plain text backup immediately:","Restaurar backup plain text imediatamente:"}. +{"Restore","Restaurar"}. +{"Room Configuration","Configuração de salas"}. +{"Room creation is denied by service policy","Se te a denegado criar la sala por política do serviço"}. +{"Room title","Título da sala"}. +{"Roster groups allowed to subscribe","Listar grupos autorizados"}. +{"Roster","Lista de contatos"}. +{"Roster of ","Lista de contatos de "}. +{"Roster size","Tamanho da Lista"}. +{"RPC Call Error","Erro de chamada RPC"}. +{"Running Nodes","Nos em execução"}. +{"~s access rule configuration","Configuração da Regra de Acesso ~s"}. +{"Saturday","Sábado"}. +{"Script check","Verificação de Script"}. +{"Search Results for ","Resultados de pesquisa para"}. +{"Search users in ","Procurar usuários em "}. +{"Send announcement to all online users","Enviar anúncio a todos os usuárions online"}. +{"Send announcement to all online users on all hosts","Enviar anúncio a todos usuários online em todas as máquinas"}. +{"Send announcement to all users","Enviar anúncio a todos os usuários"}. +{"Send announcement to all users on all hosts","Enviar aviso para todos os usuários em todos os hosts"}. +{"September","Setembro"}. +{"Set message of the day and send to online users","Definir mensagem do dia e enviar a todos usuários online"}. +{"Set message of the day on all hosts and send to online users","Definir mensagem do dia em todos os hosts e enviar para os usuários online"}. +{"Shared Roster Groups","Grupos Shared Roster"}. +{"Show Integral Table","Mostrar Tabela Integral"}. +{"Show Ordinary Table","Mostrar Tabela Ordinária"}. +{"Shut Down Service","Parar Serviço"}. +{"~s invites you to the room ~s","~s convidou você para a sala ~s"}. +{"Size","Tamanho"}. +{"Specified nickname is already registered","O apelido especificado já está registrado"}. +{"Specify the access model","Especificar os modelos de acesso"}. +{"Specify the publisher model","Especificar o modelo do publicante"}. +{"~s's Offline Messages Queue","~s's Fila de Mensagens Offline"}. +{"Start","Iniciar"}. +{"Start Modules at ","Iniciar módulos em "}. +{"Start Modules","Iniciar módulos"}. +{"Statistics","Estatísticas"}. +{"Statistics of ~p","Estatísticas de ~p"}. +{"Stop Modules at ","Parar módulos em "}. +{"Stop Modules","Parar módulos"}. +{"Stop","Parar"}. +{"Stopped Nodes","Nos parados"}. +{"Storage Type","Tipo de armazenamento"}. +{"Store binary backup:","Armazenar backup binário:"}. +{"Store plain text backup:","Armazenar backup plain text"}. +{"Subject","Assunto"}. +{"Submit","Enviar"}. +{"Submitted","Submetido"}. +{"Subscriber Address","Enderço dos Assinantes"}. +{"Subscription","Subscrição"}. +{"Sunday","Domingo"}. +{"the password is","a senha é"}. +{"This participant is kicked from the room because he sent an error message","Este participante foi desconectado da sala de chat por ter enviado uma mensagem de erro."}. +{"This participant is kicked from the room because he sent an error message to another participant","Este participante foi desconectado da sala de chat por ter enviado uma mensagem de erro para outro usuário."}. +{"This participant is kicked from the room because he sent an error presence","Este participante foi desconectado da sala de chat por ter enviado uma notificação errônea de presença."}. +{"This room is not anonymous","Essa sala não é anônima"}. +{"Thursday","Quinta"}. +{"Time delay","Intervalo de Tempo"}. +{"Time","Fecha"}. +{"To","Para"}. +{"To ~s","Para ~s"}. +{"Traffic rate limit is exceeded","Limite de banda excedido"}. +{"Transactions Aborted:","Transações abortadas:"}. +{"Transactions Commited:","Transações:"}. +{"Transactions Logged:","Transações de log:"}. +{"Transactions Restarted:","Transações restauradas:"}. +{"Tuesday","Terça"}. +{"Update ","Atualizar"}. +{"Update","Atualizar"}. +{"Updated modules","Módulos atualizados"}. +{"Update message of the day (don't send)","Atualizar mensagem do dia (não enviar)"}. +{"Update message of the day on all hosts (don't send)","Atualizar a mensagem do dia em todos os host (não enviar)"}. +{"Update plan","Plano de Atualização"}. +{"Update script","Script de atualização"}. +{"Uptime:","Uptime:"}. +{"Use of STARTTLS required","É obrigatório usar STARTTLS"}. +{"User Management","Gerenciamento de Usuários"}. +{"Users are not allowed to register accounts so fast","Usuários ainda não podem registrar novas contas"}. +{"Users Last Activity","Ultimas atividades dos usuários"}. +{"Users","Usuários"}. +{"User ","Usuário"}. +{"User","Usuário"}. +{"Validate","Validar"}. +{"vCard User Search","Busca de Usuário vCard"}. +{"Virtual Hosts","Maquinas Virtuais"}. +{"Visitors are not allowed to change their nicknames in this room","Nesta sala, os visitantes não pode mudar seus apelidos"}. +{"Visitors are not allowed to send messages to all occupants","Os visitantes não podem enviar mensagens a todos os ocupantes"}. +{"Wednesday","Quarta"}. +{"When to send the last published item","Quando enviar o último tópico publicado"}. +{"Whether to allow subscriptions","Permitir subscrições"}. +{"You have been banned from this room","As sido bloqueado em esta sala"}. +{"You must fill in field \"Nickname\" in the form","Você deve completar o campo \"Apelido\" no formulário"}. +{"You need an x:data capable client to configure mod_irc settings","Necessitas um cliente com suporte de x:data para configurar las opções de mod_irc"}. +{"You need an x:data capable client to configure room","Necessitas um cliente com suporte de x:data para configurar la sala"}. +{"You need an x:data capable client to register nickname","Necessitas um cliente com suporte de x:data para poder registrar o nick"}. +{"You need an x:data capable client to search","Necessitas um cliente com suporte de x:data para poder buscar"}. +{"Your contact offline message queue is full. The message has been discarded.","Sua fila de mensagens offline esta cheia. Sua mensagem foi descartada"}. diff --git a/src/msgs/pt-br.po b/src/msgs/pt-br.po new file mode 100644 index 000000000..791d2d755 --- /dev/null +++ b/src/msgs/pt-br.po @@ -0,0 +1,1499 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Otávio Fernandes\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Portuguese (Brazil)\n" +"X-Additional-Translator: Renato Botelho\n" +"X-Additional-Translator: Lucius Curado\n" +"X-Additional-Translator: Felipe Brito Vasconcellos\n" +"X-Additional-Translator: Victor Hugo dos Santos\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "É obrigatório usar STARTTLS" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Recurso não foi fornecido" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Substituído por nova conexão" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Comandos" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Deletar realmente a mensagem do dia?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Assunto" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Corpo da mensagem" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "Nenhum corpo de texto fornecido para anunciar mensagem" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Anúncios" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Enviar anúncio a todos os usuários" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Enviar aviso para todos os usuários em todos os hosts" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Enviar anúncio a todos os usuárions online" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "Enviar anúncio a todos usuários online em todas as máquinas" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Definir mensagem do dia e enviar a todos usuários online" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Definir mensagem do dia em todos os hosts e enviar para os usuários online" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Atualizar mensagem do dia (não enviar)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Atualizar a mensagem do dia em todos os host (não enviar)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Apagar mensagem do dia" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Apagar a mensagem do dia em todos os hosts" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Configuração" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Base de dados" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Iniciar módulos" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Parar módulos" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Salvar cópia de segurança" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Restaurar" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Exportar para arquivo de texto" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Importar arquivo" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Importar diretório" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Reiniciar Serviço" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Parar Serviço" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Adicionar usuário" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Deletar Usuário" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Terminar Sessão do Usuário" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Obter Senha do Usuário" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Alterar Senha do Usuário" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Obter a Data do Último Login" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Obter Estatísticas do Usuário" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Obter Número de Usuários Registrados" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Obter Número de Usuários Online" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Listas de Controle de Acesso" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Regras de Aceso" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Gerenciamento de Usuários" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Usuários conectados" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Todos os usuários" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Conexões que partam de s2s" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Nos em execução" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Nos parados" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Módulos" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Gestão de copia de segurança" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Importar usuários de arquivos jabberd 1.4" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "Para ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "De ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Configuração de Tabelas de Base de dados em " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Selecione o tipo de armazenamento das tabelas" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Copia em disco somente" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "Copia em RAM y disco" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "Copia em RAM" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Copia remota" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Parar módulos em " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Selecione módulos a parar" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Iniciar módulos em " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Introduza lista de {módulo, [opções]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Listas de módulos para inicializar" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Salvar cópia de segurança para arquivo em " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Introduza o caminho do arquivo de cópia de segurança" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Caminho do arquivo" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Restaura cópia de segurança a partir do arquivo em " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Exporta cópia de segurança para arquivo de texto em " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Introduza caminho para o arquivo de texto" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Importar usuário a partir do arquivo em " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Introduza o caminho para o arquivo de spool do jabberd1.4" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Importar usuários a partir do diretório em " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Introduza o caminho para o diretório de spools do jabberd1.4" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Caminho para o diretório" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Intervalo de Tempo" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Configuração da Lista de Controle de Acesso" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Listas de Controle de Acesso" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Configuração de Acesso" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Regras de acesso" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "ID Jabber" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Senha" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Verificação de Senha" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Número de usuários registrados" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Número de usuários online" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Nunca" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Conectado" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Último login" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Tamanho da Lista" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "Endereços IP" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Recursos" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Administração de " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Ação no usuário" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Editar propriedades" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Remover usuário" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Aceso denegado por la política do serviço" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "IRC Transport" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "Módulo de IRC para ejabberd" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "" +"Necessitas um cliente com suporte de x:data para configurar las opções de " +"mod_irc" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Registro em mod_irc para" + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Introduza o nome de usuário e codificações de caracteres que quer usar ao " +"conectar-se aos servidores de IRC" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "Nome de usuário no IRC" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Se deseja especificar codificações de caracteres diferentes para cada " +"servidor IRC preencha esta lista com valores no formato '{\"servidor irc\", " +"\"codificação\"}'. Este serviço usa por padrão a codificação \"~s\"." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Exemplo: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Codificação" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "" +"Apenas administradores possuem permissão para enviar mensagens de serviço" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "Se te a denegado criar la sala por política do serviço" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "La sala de conferencias não existe" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Salas de Chat" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "" +"Necessitas um cliente com suporte de x:data para poder registrar o nick" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Registro do apelido em " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Introduza o apelido que quer registrar" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Apelido" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "O apelido especificado já está registrado" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Você deve completar o campo \"Apelido\" no formulário" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "Módulo de MUC para ejabberd" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Configuração da sala de bate-papo modificada" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "Entrar na sala" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "Sair da sala" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "foi banido" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "foi removido" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "foi desconectado porque por afiliação inválida" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "" +"foi desconectado porque a política da sala mudou, só membros são permitidos" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "foi desconectado porque o sistema foi desligado" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "é agora conhecido como" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " a posto o assunto: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "Segunda" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "Terça" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "Quarta" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "Quinta" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "Sexta" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "Sábado" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "Domingo" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "Janeiro" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "Fevereiro" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "Março" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "Abril" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "Maio" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "Junho" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "Julho" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "Agosto" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "Setembro" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "Outubro" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "Novembro" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "Dezembro" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Configuração de salas" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Título da sala" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Limite de banda excedido" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" +"Este participante foi desconectado da sala de chat por ter enviado uma " +"mensagem de erro." + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Impedir o envio de mensagens privados a la sala" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Tipo de mensagem incorreto" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Este participante foi desconectado da sala de chat por ter enviado uma " +"mensagem de erro para outro usuário." + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "No está permitido enviar mensagens privados do tipo \"groupchat\"" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "O receptor não está em la sala de conferencia" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Solo os ocupantes podem enviar mensagens a la sala" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "Não é permitido enviar mensagens privadas" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Solo os ocupantes podem enviar consultas a la sala" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "Nesta sala não se permite consultas aos membros da sala" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "privado" + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "" +"Solo os moderadores y participantes podem cambiar o assunto de esta sala" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Solo os moderadores podem cambiar o assunto de esta sala" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "Os visitantes não podem enviar mensagens a todos os ocupantes" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" +"Este participante foi desconectado da sala de chat por ter enviado uma " +"notificação errônea de presença." + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Nesta sala, os visitantes não pode mudar seus apelidos" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "O nick já está sendo usado por outro ocupante" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "O nick já está registrado por outra pessoa" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "As sido bloqueado em esta sala" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "Necessitas ser membro de esta sala para poder entrar" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Essa sala não é anônima" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Se necessita senha para entrar em esta sala" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Senha incorreta" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Se necessita privilégios de administrador" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Se necessita privilégios de moderador" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "O JID ~s não es válido" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "O nick ~s não existe em la sala" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Afiliação não válida: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Rol não válido: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Se requere privilégios de proprietário da sala" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Configuração para " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Descrição:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Tornar sala persistente" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Tornar sala pública possível de ser encontrada" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Tornar pública a lista de participantes" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Tornar protegida a senha da sala" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Número máximo de participantes" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Ilimitado" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Tornar o JID real visível por" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "apenas moderadores" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "qualquer um" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Tornar sala apenas para membros" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Tornar a sala moderada" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Usuários padrões como participantes" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Permitir a usuários modificar o assunto" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Permitir a usuários enviarem mensagens privadas" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Permitir a usuários pesquisar informações sobre os demais" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Permitir a usuários envio de convites" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "Permitir atualizações de status aos visitantes" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Permitir mudança de apelido aos visitantes" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Permitir criação de logs" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "Necessitas um cliente com suporte de x:data para configurar la sala" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Número de participantes" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s convidou você para a sala ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "a senha é" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "Sua fila de mensagens offline esta cheia. Sua mensagem foi descartada" + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "~s's Fila de Mensagens Offline" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Submetido" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Fecha" + +#: mod_offline.erl:507 +msgid "From" +msgstr "De" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Para" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Pacote" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Remover os selecionados" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Mensagens offline" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "Modulo ejabberd SOCKS5 Bytestreams" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Publicação de Tópico" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "Módulo para Publicar Tópicos do ejabberd" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "PubSub requisição de assinante" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Aprovar esta assinatura." + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "ID do Tópico" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Enderço dos Assinantes" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Autorizar este JID para a inscrição neste tópico pubsub ?" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Enviar payloads junto com as notificações de eventos" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Entregar as notificações de evento" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Notificar subscritores quando cambia la configuração do nodo" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Notificar subscritores quando o nodo se elimine" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Notificar subscritores quando os elementos se eliminem do nodo" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Persistir elementos ao armazenar" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "Um nome familiar para o nó" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Máximo # de elementos que persistem" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Permitir subscrições" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Especificar os modelos de acesso" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Listar grupos autorizados" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Especificar o modelo do publicante" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Máximo tamanho do payload em bytes" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Quando enviar o último tópico publicado" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Solo enviar notificações aos usuários disponíveis" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "Escolha um nome de usuário e senha para registrar-se neste servidor" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "Usuários ainda não podem registrar novas contas" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Nenhum" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Subscrição" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Pendente" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Grupos" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Validar" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Borrar" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Lista de contatos de " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Formato incorreto" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Adicionar ID jabber" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Lista de contatos" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Grupos Shared Roster" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Adicionar novo" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Nome:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Descrição:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Miembros:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Grupos Indicados" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Grupo " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Enviar" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Servidor Jabber em Erlang" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Aniversário" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Cidade" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "País" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "e-mail" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Nome de família" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Preencha o formulário para buscar usuários Jabber. Agrega * ao final de um " +"campo para buscar sub-palavras." + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Nome completo" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Apelido" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Nome" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Nome da organização" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Unidade da organização" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Procurar usuários em " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Usuário" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "Necessitas um cliente com suporte de x:data para poder buscar" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "Busca de Usuário vCard" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "Módulo vCard para ejabberd" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Resultados de pesquisa para" + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Preencha campos para buscar usuários Jabber que concordem" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "ejabberd Web Admin" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Administração" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Maquinas Virtuais" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Nós" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Estatísticas" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Usuários" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Última atividade" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Intocado)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Intocado" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "Configuração da Regra de Acesso ~s" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "Maquinas virtuais de ejabberd" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Ultimas atividades dos usuários" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Período: " + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Último mês" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Último ano" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Toda la atividade" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Mostrar Tabela Ordinária" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Mostrar Tabela Integral" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Nó não encontrado" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Máquina" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Usuários Registrados" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Mensagens offline" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Usuários registrados" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Usuários online" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Conexões que partem de s2s" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Servidores que partem de s2s" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Mudar senha" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Usuário" + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Recursos conectados:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Senha:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Nenhum dado" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Nó" + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Portas escutadas" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Atualizar" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Reiniciar" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Parar" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "Erro de chamada RPC" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Tabelas de base de dados em" + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Tipo de armazenamento" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Tamanho" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Memória" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Backup de" + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Observe que tais opções farão backup apenas da base de dados Mnesia. Caso " +"você esteja utilizando o modulo ODBC, você precisará fazer backup de sua " +"base de dados SQL separadamente." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Armazenar backup binário:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "OK" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Restaurar backup binário imediatamente" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"Restaurar backup binário após próximo reinicialização do ejabberd (requer " +"menos memória):" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Armazenar backup plain text" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Restaurar backup plain text imediatamente:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Portas de escuta em " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Módulos em " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "Estatísticas de ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Uptime:" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "Tempo de CPU" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Transações:" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Transações abortadas:" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Transações restauradas:" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Transações de log:" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Atualizar" + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Plano de Atualização" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Módulos atualizados" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Script de atualização" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Script de atualização low level" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Verificação de Script" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Porta" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Módulo" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Opções" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Eliminar" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Iniciar" diff --git a/src/msgs/pt.msg b/src/msgs/pt.msg index 93fa04063..71cce8fb6 100644 --- a/src/msgs/pt.msg +++ b/src/msgs/pt.msg @@ -1,244 +1,150 @@ -% $Id$ -% Language: Portuguese (português) -% Author: Iceburn - -% jlib.hrl -{"No resource provided", "Não foi passado nenhum recurso"}. - -% mod_configure.erl -{"DB Tables Configuration at ", "Configuração de tabelas da BD em "}. -{"Choose storage type of tables", "Seleccione o tipo de armazenagem das tabelas"}. -{"RAM copy", "Cópia em RAM"}. -{"RAM and disc copy", "Cópia em RAM e em disco"}. -{"Disc only copy", "Cópia apenas em disco"}. -{"Remote copy", "Cópia remota"}. -{"Stop Modules at ", "Parar módulos em "}. -{"Choose modules to stop", "Seleccione os módulos a parar"}. -{"Start Modules at ", "Iniciar os módulos em "}. -{"Enter list of {Module, [Options]}", "Introduza lista de {módulos, [opções]}"}. -{"List of modules to start", "Lista de módulos a iniciar"}. -{"Backup to File at ", "Guardar cópia de segurança para ficheiro em "}. -{"Enter path to backup file", "Introduza o caminho do ficheiro de cópia de segurança"}. -{"Path to File", "Caminho do ficheiro"}. -{"Restore Backup from File at ", "Restaura cópia de segurança a partir do ficheiro em "}. -{"Dump Backup to Text File at ", "Exporta cópia de segurança para ficheiro de texto em "}. -{"Enter path to text file", "Introduza caminho para o ficheiro de texto"}. -{"Import User from File at ", "Importar utilizador a partir do ficheiro em "}. -{"Enter path to jabberd1.4 spool file", "Introduza o caminho para o ficheiro de spool do jabberd1.4"}. -{"Import Users from Dir at ", "Importar utilizadores a partir do directório em "}. -{"Enter path to jabberd1.4 spool dir", "Introduza o caminho para o directório de spools do jabberd1.4"}. -{"Path to Dir", "Caminho para o directório"}. -{"Hostname Configuration", "Configuração do nome do servidor"}. -{"Choose host name", "Introduza o nome do servidor"}. -{"Host name", "Nome do servidor"}. -{"Access Control List Configuration", "Configuração da Lista de Controlo de Acesso"}. -{"Access control lists", "Listas de Controlo de Acesso"}. -{"Access Configuration", "Configuração de acessos"}. -{"Access rules", "Regras de acesso"}. -{"Remove Users", "Eliminar utilizadores"}. -{"Choose users to remove", "Seleccione utilizadores a eliminar"}. -{"Administration of ", "Administração de "}. -{"Action on user", "Acção no utilizador"}. -{"Edit Properties", "Editar propriedades"}. -{"Remove User", "Eliminar utilizador"}. - -% mod_disco.erl -{"Configuration", "Configuração"}. -{"Online Users", "Utilizadores ligados"}. -{"All Users", "Todos os utilizadores"}. -{"Outgoing S2S connections", "Conexões S2S para fora"}. -{"To ~s", "A ~s"}. -{"From ~s", "De ~s"}. -{"Running Nodes", "Nodos a correr"}. -{"Stopped Nodes", "Nodos parados"}. -{"Host Name", "Nome do servidor"}. -{"Access Control Lists", "Listas de Controlo de Acesso"}. -{"Access Rules", "Regras de Acesso"}. -{"Remove Users", "Eliminar utilizadores"}. -{"DB", "BD"}. -{"Modules", "Módulos"}. -{"Start Modules", "Iniciar módulos"}. -{"Stop Modules", "Parar módulos"}. -{"Backup Management", "Gestão de cópias de segurança"}. -{"Import users from jabberd1.4 spool files", "Importar utilizadores a partir de ficheiros da spool do jabberd1.4"}. -{"Backup", "Guardar cópia de segurança"}. -{"Restore", "Restaurar"}. -{"Dump to Text File", "Exportar para ficheiro de texto"}. -{"Import File", "Importar ficheiro"}. -{"Import Directory", "Importar directório"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Escolha um nome de utilizador e palavra-chave para se registar neste servidor"}. - -% mod_vcard.erl -{"Erlang Jabber Server", "Servidor Jabber em Erlang"}. -{"ejabberd vCard module", "Módulo vCard de ejabberd"}. -{"You need an x:data capable client to search", "É necessário um cliente com suporte de x:data para poder procurar"}. -{"Search users in ", "Procurar utilizadores em "}. -{"Fill in fields to search for any matching Jabber User", "Preencha os campos para procurar utilizadores Jabber coincidentes"}. -{"Results of search in ", "Resultados da procura em "}. -{"User", "Utilizador"}. -{"Full Name", "Nome completo"}. -{"Name", "Nome"}. -{"Middle Name", "Segundo nome"}. -{"Family Name", "Apelido"}. -{"Nickname", "Alcunha"}. -{"Birthday", "Data de nascimento"}. -{"Country", "País"}. -{"City", "Cidade"}. -{"email", "email"}. -{"Organization Name", "Nome da organização"}. -{"Organization Unit", "Unidade da organização"}. - -% mod_pubsub/mod_pubsub.erl -{"ejabberd pub/sub module", "Módulo pub/sub de ejabberd"}. - -% mod_muc/mod_muc.erl -{"You need an x:data capable client to register nickname", "É necessário um cliente com suporte de x:data para poder registar a alcunha"}. -{"Nickname Registration at ", "Registo da alcunha em "}. -{"Enter nickname you want to register", "Introduza a alcunha que quer registar"}. -{"ejabberd MUC module", "Módulo MUC de ejabberd"}. -{"Only service administrators are allowed to send service messages", "Só os administradores do serviço têm permissão para enviar mensagens de serviço"}. -{"Conference room does not exist", "A sala não existe"}. -{"Access denied by service policy", "Acesso negado pela política de serviço"}. -{"You must fill in field \"nick\" in the form", "Deve preencher o campo \"alcunha\" no formulário"}. -{"Specified nickname is already registered", "A alcunha especificada já está registada"}. - -% mod_muc/mod_muc_room.erl -{"Make room moderated", "Tornar a sala moderada"}. -{" has set the subject to: ", " colocou o tópico: "}. -{"You need an x:data capable client to configure room", "É necessário um cliente com suporte de x:data para configurar a sala"}. -{"Configuration for ", "Configuração para "}. -{"Room title", "Título da sala"}. -{"Allow users to change subject?", "Permitir aos utilizadores mudar o tópico?"}. -{"Allow users to query other users?", "Permitir aos utilizadores consultar outros utilizadores?"}. -{"Allow users to send private messages?", "Permitir que os utilizadores enviem mensagens privadas?"}. -{"Make room public searchable?", "Tornar a sala publicamente visível?"}. -{"Make participants list public?", "Tornar pública a lista de participantes?"}. -{"Make room persistent?", "Tornar a sala permanente?"}. -{"Make room moderated?", "Tornar a sala moderada?"}. -{"Default users as members?", "Os utilizadores são membros por omissão?"}. -{"Make room members only?", "Tornar a sala exclusiva a membros?"}. -{"Allow users to send invites?", "Permitir que os utilizadores enviem convites?"}. -{"Make room password protected?", "Proteger a sala com palavra-chave?"}. -{"Password", "Palavra-chave"}. -{"Make room anonymous?", "Tornar a sala anónima?"}. -{"Enable logging?", "Guardar históricos?"}. -{"Only moderators and participants are allowed to change subject in this room", "Só os moderadores e os participantes podem mudar o tópico desta sala"}. -{"Only moderators are allowed to change subject in this room", "Só os moderadores podem mudar o tópico desta sala"}. -{"Visitors are not allowed to send messages to all occupants", "Os visitantes não podem enviar mensagens para todos os ocupantes"}. -{"Only occupants are allowed to send messages to the conference", "Só os ocupantes podem enviar mensagens para a sala"}. -{"It is not allowed to send normal messages to the conference", "Impedir o envio de mensagens normais para a sala"}. -{"It is not allowed to send private messages to the conference", "Impedir o envio de mensagens privadas para a sala"}. -{"Improper message type", "Tipo de mensagem incorrecto"}. -{"Nickname is already in use by another occupant", "A alcunha já está a ser usado por outro ocupante"}. -{"Nickname is registered by another person", "A alcunha já está registada por outra pessoa"}. -{"It is not allowed to send private messages of type \"groupchat\"", "Não é permitido enviar mensagens privadas do tipo \"groupchat\""}. -{"Recipient is not in the conference room", "O destinatário não está na sala"}. -{"Only occupants are allowed to send queries to the conference", "Só os ocupantes podem enviar consultas para a sala"}. -{"Queries to the conference members are not allowed in this room", "Nesta sala não são permitidas consultas aos seus membros"}. -{"You have been banned from this room", "Foi banido desta sala"}. -{"Membership required to enter this room", "É necessário ser membro desta sala para poder entrar"}. -{"Password required to enter this room", "É necessária a palavra-chave para poder entrar nesta sala"}. -{"Incorrect password", "Palavra-chave incorrecta"}. -{"Administrator privileges required", "São necessários privilégios de administrador"}. -{"Moderator privileges required", "São necessários privilégios de moderador"}. -{"JID ~s is invalid", "O JID ~s não é válido"}. -{"Nickname ~s does not exist in the room", "A alcunha ~s não existe na sala"}. -{"Invalid affiliation: ~s", "Afiliação inválida: ~s"}. -{"Invalid role: ~s", "Papel inválido: ~s"}. -{"Owner privileges required", "São necessários privilégios de dono"}. -{"private, ", "privado"}. - -% mod_irc/mod_irc.erl -{"ejabberd IRC module", "Módulo de IRC ejabberd"}. -{"You need an x:data capable client to configure mod_irc settings", "É necessário um cliente com suporte de x:data para configurar as opções do mod_irc"}. -{"Registration in mod_irc for ", "Registo no mod_irc para"}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Introduza o nome de utilizador e codificações de caracteres que quer usar ao conectar-se aos servidores de IRC"}. -{"IRC Username", "Nome do utilizador de IRC"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Se deseja especificar codificações de caracteres diferentes para cada servidor IRC preencha esta lista con valores no formato '{\"servidor irc\", \"codificação\"}'. Este serviço usa por omissão a codificação \"~s\"."}. -{"Encodings", "Codificações"}. - -% web/ejabberd_web_admin.erl -{"ejabberd administration", "Administração do ejabberd"}. -{"Users", "Utilizadores"}. -{"Nodes", "Nodos"}. -{"Statistics", "Estatísticas"}. -{"(raw)", "(modo texto)"}. -{"submitted", "enviado"}. -{"bad format", "formato inválido"}. -{"raw", "modo texto"}. -{"ejabberd access control lists configuration", "Configuração das Listas de Controlo de Acesso do ejabberd"}. -{"Delete Selected", "Eliminar os seleccionados"}. -{"Submit", "Enviar"}. -{"ejabberd access rules configuration", "Configuração das Regras de Acesso do ejabberd"}. -{"~s access rule configuration", "Configuração das Regra de Acesso ~s"}. -{"ejabberd users", "Utilizadores do ejabberd"}. -{"ejabberd stats", "Estatísticas do ejabberd"}. -{"Node not found", "Nodo não encontrado"}. -{"Add New", "Adicionar novo"}. -{"Registered users", "Utilizadores registados"}. -{"Online users", "Utilizadores ligados"}. -{"Outgoing S2S servers", "Servidores S2S de saída"}. -{"Change Password", "Mudar palavra-chave"}. -{"Connected Resources:", "Recursos conectados:"}. -{"Password:", "Palavra-chave:"}. -{"None", "Nenhum"}. -{"Node ", "Nodo"}. -{"DB Management", "Gestão da BD"}. -{"Listened Ports Management", "Gestão das portas em escuta"}. -{"Restart", "Reiniciar"}. -{"Stop", "Parar"}. -{"RPC call error", "Erro na chamada RPC"}. -{"DB Tables at ", "Tabelas da BD em "}. -{"Name", "Nome"}. -{"Storage Type", "Tipo de armazenagem"}. -{"Size", "Tamanho"}. -{"Memory", "Memória"}. -{"Backup Management at ", "Gestão da cópia de segurança em "}. -{"Store a backup in a file", "Armazenar uma cópia de segurança no ficheiro"}. -{"OK", "OK"}. -{"Restore a backup from a file", "Recuperar uma cópia de segurança a partir de ficheiro"}. -{"Install a database fallback from a file", "Instalar uma recuperação de BD desde um ficheiro"}. -{"Dump a database in a text file", "Exportar uma Base de Dados para um ficheiro de texto"}. -{"Restore a database from a text file", "Restaurar uma Base de Dados a partir de ficheiro de texto"}. -{"Listened Ports at ", "Portas em escuta em "}. -{"~p statistics", "Estatísticas de ~p"}. -{"Uptime", "Tempo de funcionamento"}. -{"CPU Time", "Tempo de processador consumido"}. -{"Transactions commited", "Transacções realizadas"}. -{"Transactions aborted", "Transacções abortadas"}. -{"Transactions restarted", "Transacções reiniciadas"}. -{"Transactions logged", "Transacções armazenadas"}. -{"Port", "Porta"}. -{"Module", "Módulo"}. -{"Options", "Opções"}. -{"Update", "Actualizar"}. -{"Delete", "Eliminar"}. -{"Add User", "Adicionar utilizador"}. -{"ejabberd (c) 2002-2005 Alexey Shchepin, 2005 Process One", "ejabberd (c) 2002-2005 Alexey Shchepin, 2005 Process One"}. -{"Offline messages", "Mensagens diferidas"}. -{"Last Activity", "Última actividade"}. -{"Online", "Ligado"}. -{"Never", "Nunca"}. -{"~s offline messages queue", "~s fila de mensagens diferidas"}. -{"Time", "Data"}. -{"From", "De"}. -{"To", "Para"}. -{"Packet", "Pacote"}. -{"Offline messages:", "Mensagens diferidas:"}. -{"Roster", "Lista de contactos"}. -{"Nickname", "Alcunha"}. -{"Subscription", "Subscrição"}. -{"Pending", "Pendente"}. -{"Groups", "Grupos"}. -{"Remove", "Remover"}. -{"Add JID", "Adicionar JID"}. -{"User ", "Utilizador"}. -{"Roster of ", "Lista de contactos de "}. -{"Shared Roster", "Lista de contactos partilhada"}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Configuração de acessos"}. +{"Access Control List Configuration","Configuração da Lista de Controlo de Acesso"}. +{"Access control lists","Listas de Controlo de Acesso"}. +{"Access Control Lists","Listas de Controlo de Acesso"}. +{"Access denied by service policy","Acesso negado pela política de serviço"}. +{"Access rules","Regras de acesso"}. +{"Access Rules","Regras de Acesso"}. +{"Action on user","Acção no utilizador"}. +{"Add New","Adicionar novo"}. +{"Add User","Adicionar utilizador"}. +{"Administration of ","Administração de "}. +{"Administrator privileges required","São necessários privilégios de administrador"}. +{"All Users","Todos os utilizadores"}. +{"Backup","Guardar cópia de segurança"}. +{"Backup Management","Gestão de cópias de segurança"}. +{"Backup to File at ","Guardar cópia de segurança para ficheiro em "}. +{"Birthday","Data de nascimento"}. +{"Change Password","Mudar palavra-chave"}. +{"Choose a username and password to register with this server","Escolha um nome de utilizador e palavra-chave para se registar neste servidor"}. +{"Choose modules to stop","Seleccione os módulos a parar"}. +{"Choose storage type of tables","Seleccione o tipo de armazenagem das tabelas"}. +{"City","Cidade"}. +{"Conference room does not exist","A sala não existe"}. +{"Configuration","Configuração"}. +{"Configuration for ","Configuração para "}. +{"Connected Resources:","Recursos conectados:"}. +{"Country","País"}. +{"Delete","Eliminar"}. +{"Delete Selected","Eliminar os seleccionados"}. +{"Disc only copy","Cópia apenas em disco"}. +{"Dump Backup to Text File at ","Exporta cópia de segurança para ficheiro de texto em "}. +{"Dump to Text File","Exportar para ficheiro de texto"}. +{"Edit Properties","Editar propriedades"}. +{"ejabberd IRC module","Módulo de IRC ejabberd"}. +{"ejabberd MUC module","Módulo MUC de ejabberd"}. +{"ejabberd vCard module","Módulo vCard de ejabberd"}. +{"Encodings","Codificações"}. +{"Enter list of {Module, [Options]}","Introduza lista de {módulos, [opções]}"}. +{"Enter nickname you want to register","Introduza a alcunha que quer registar"}. +{"Enter path to backup file","Introduza o caminho do ficheiro de cópia de segurança"}. +{"Enter path to jabberd1.4 spool dir","Introduza o caminho para o directório de spools do jabberd1.4"}. +{"Enter path to jabberd1.4 spool file","Introduza o caminho para o ficheiro de spool do jabberd1.4"}. +{"Enter path to text file","Introduza caminho para o ficheiro de texto"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Introduza o nome de utilizador e codificações de caracteres que quer usar ao conectar-se aos servidores de IRC"}. +{"Erlang Jabber Server","Servidor Jabber em Erlang"}. +{"Family Name","Apelido"}. +{"Fill in fields to search for any matching Jabber User","Preencha os campos para procurar utilizadores Jabber coincidentes"}. +{"From","De"}. +{"From ~s","De ~s"}. +{"Full Name","Nome completo"}. +{"Groups","Grupos"}. +{" has set the subject to: "," colocou o tópico: "}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Se deseja especificar codificações de caracteres diferentes para cada servidor IRC preencha esta lista con valores no formato '{\"servidor irc\", \"codificação\"}'. Este serviço usa por omissão a codificação \"~s\"."}. +{"Import Directory","Importar directório"}. +{"Import File","Importar ficheiro"}. +{"Import User from File at ","Importar utilizador a partir do ficheiro em "}. +{"Import Users from Dir at ","Importar utilizadores a partir do directório em "}. +{"Improper message type","Tipo de mensagem incorrecto"}. +{"Incorrect password","Palavra-chave incorrecta"}. +{"Invalid affiliation: ~s","Afiliação inválida: ~s"}. +{"Invalid role: ~s","Papel inválido: ~s"}. +{"IRC Username","Nome do utilizador de IRC"}. +{"It is not allowed to send private messages of type \"groupchat\"","Não é permitido enviar mensagens privadas do tipo \"groupchat\""}. +{"It is not allowed to send private messages to the conference","Impedir o envio de mensagens privadas para a sala"}. +{"JID ~s is invalid","O JID ~s não é válido"}. +{"Last Activity","Última actividade"}. +{"Listened Ports at ","Portas em escuta em "}. +{"List of modules to start","Lista de módulos a iniciar"}. +{"Make room moderated","Tornar a sala moderada"}. +{"Membership required to enter this room","É necessário ser membro desta sala para poder entrar"}. +{"Memory","Memória"}. +{"Middle Name","Segundo nome"}. +{"Moderator privileges required","São necessários privilégios de moderador"}. +{"Module","Módulo"}. +{"Modules","Módulos"}. +{"Name","Nome"}. +{"Never","Nunca"}. +{"Nickname","Alcunha"}. +{"Nickname is already in use by another occupant","A alcunha já está a ser usado por outro ocupante"}. +{"Nickname is registered by another person","A alcunha já está registada por outra pessoa"}. +{"Nickname Registration at ","Registo da alcunha em "}. +{"Nickname ~s does not exist in the room","A alcunha ~s não existe na sala"}. +{"Node ","Nodo"}. +{"Node not found","Nodo não encontrado"}. +{"Nodes","Nodos"}. +{"None","Nenhum"}. +{"No resource provided","Não foi passado nenhum recurso"}. +{"OK","OK"}. +{"Online","Ligado"}. +{"Online Users","Utilizadores ligados"}. +{"Only moderators and participants are allowed to change subject in this room","Só os moderadores e os participantes podem mudar o tópico desta sala"}. +{"Only moderators are allowed to change subject in this room","Só os moderadores podem mudar o tópico desta sala"}. +{"Only occupants are allowed to send messages to the conference","Só os ocupantes podem enviar mensagens para a sala"}. +{"Only occupants are allowed to send queries to the conference","Só os ocupantes podem enviar consultas para a sala"}. +{"Only service administrators are allowed to send service messages","Só os administradores do serviço têm permissão para enviar mensagens de serviço"}. +{"Options","Opções"}. +{"Organization Name","Nome da organização"}. +{"Organization Unit","Unidade da organização"}. +{"Owner privileges required","São necessários privilégios de dono"}. +{"Packet","Pacote"}. +{"Password:","Palavra-chave:"}. +{"Password","Palavra-chave"}. +{"Password required to enter this room","É necessária a palavra-chave para poder entrar nesta sala"}. +{"Path to Dir","Caminho para o directório"}. +{"Path to File","Caminho do ficheiro"}. +{"Pending","Pendente"}. +{"Port","Porta"}. +{"private, ","privado"}. +{"Queries to the conference members are not allowed in this room","Nesta sala não são permitidas consultas aos seus membros"}. +{"RAM and disc copy","Cópia em RAM e em disco"}. +{"RAM copy","Cópia em RAM"}. +{"Recipient is not in the conference room","O destinatário não está na sala"}. +{"Registration in mod_irc for ","Registo no mod_irc para"}. +{"Remote copy","Cópia remota"}. +{"Remove","Remover"}. +{"Remove User","Eliminar utilizador"}. +{"Restart","Reiniciar"}. +{"Restore Backup from File at ","Restaura cópia de segurança a partir do ficheiro em "}. +{"Restore","Restaurar"}. +{"Room title","Título da sala"}. +{"Roster","Lista de contactos"}. +{"Roster of ","Lista de contactos de "}. +{"Running Nodes","Nodos a correr"}. +{"~s access rule configuration","Configuração das Regra de Acesso ~s"}. +{"Search users in ","Procurar utilizadores em "}. +{"Size","Tamanho"}. +{"Specified nickname is already registered","A alcunha especificada já está registada"}. +{"Start Modules at ","Iniciar os módulos em "}. +{"Start Modules","Iniciar módulos"}. +{"Statistics","Estatísticas"}. +{"Stop Modules at ","Parar módulos em "}. +{"Stop Modules","Parar módulos"}. +{"Stop","Parar"}. +{"Stopped Nodes","Nodos parados"}. +{"Storage Type","Tipo de armazenagem"}. +{"Submit","Enviar"}. +{"Subscription","Subscrição"}. +{"Time","Data"}. +{"To","Para"}. +{"To ~s","A ~s"}. +{"Update","Actualizar"}. +{"Users","Utilizadores"}. +{"User ","Utilizador"}. +{"User","Utilizador"}. +{"Visitors are not allowed to send messages to all occupants","Os visitantes não podem enviar mensagens para todos os ocupantes"}. +{"You have been banned from this room","Foi banido desta sala"}. +{"You need an x:data capable client to configure mod_irc settings","É necessário um cliente com suporte de x:data para configurar as opções do mod_irc"}. +{"You need an x:data capable client to configure room","É necessário um cliente com suporte de x:data para configurar a sala"}. +{"You need an x:data capable client to register nickname","É necessário um cliente com suporte de x:data para poder registar a alcunha"}. +{"You need an x:data capable client to search","É necessário um cliente com suporte de x:data para poder procurar"}. diff --git a/src/msgs/pt.po b/src/msgs/pt.po new file mode 100644 index 000000000..5afcc47e0 --- /dev/null +++ b/src/msgs/pt.po @@ -0,0 +1,1626 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Iceburn\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Portuguese (português)\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Não foi passado nenhum recurso" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +#, fuzzy +msgid "Ping" +msgstr "Pendente" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +#, fuzzy +msgid "Subject" +msgstr "Enviar" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "" + +#: mod_announce.erl:651 +#, fuzzy +msgid "Delete message of the day" +msgstr "Eliminar os seleccionados" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Configuração" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Iniciar módulos" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Parar módulos" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Guardar cópia de segurança" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Restaurar" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Exportar para ficheiro de texto" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Importar ficheiro" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Importar directório" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +#, fuzzy +msgid "Restart Service" +msgstr "Reiniciar" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Adicionar utilizador" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +#, fuzzy +msgid "Delete User" +msgstr "Eliminar" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +#, fuzzy +msgid "Get User Password" +msgstr "Palavra-chave" + +#: mod_configure.erl:153 mod_configure.erl:477 +#, fuzzy +msgid "Change User Password" +msgstr "Mudar palavra-chave" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +#, fuzzy +msgid "Get User Statistics" +msgstr "Estatísticas" + +#: mod_configure.erl:159 mod_configure.erl:480 +#, fuzzy +msgid "Get Number of Registered Users" +msgstr "Utilizadores registados" + +#: mod_configure.erl:161 mod_configure.erl:481 +#, fuzzy +msgid "Get Number of Online Users" +msgstr "Utilizadores ligados" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Listas de Controlo de Acesso" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Regras de Acesso" + +#: mod_configure.erl:281 mod_configure.erl:454 +#, fuzzy +msgid "User Management" +msgstr "Gestão da BD" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Utilizadores ligados" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Todos os utilizadores" + +#: mod_configure.erl:457 +#, fuzzy +msgid "Outgoing s2s Connections" +msgstr "Conexões S2S para fora" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Nodos a correr" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Nodos parados" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Módulos" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Gestão de cópias de segurança" + +#: mod_configure.erl:534 +#, fuzzy +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Importar utilizadores a partir de ficheiros da spool do jabberd1.4" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "A ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "De ~s" + +#: mod_configure.erl:864 +#, fuzzy +msgid "Database Tables Configuration at " +msgstr "Configuração de tabelas da BD em " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Seleccione o tipo de armazenagem das tabelas" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Cópia apenas em disco" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "Cópia em RAM e em disco" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "Cópia em RAM" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Cópia remota" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Parar módulos em " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Seleccione os módulos a parar" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Iniciar os módulos em " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Introduza lista de {módulos, [opções]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Lista de módulos a iniciar" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Guardar cópia de segurança para ficheiro em " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Introduza o caminho do ficheiro de cópia de segurança" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Caminho do ficheiro" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Restaura cópia de segurança a partir do ficheiro em " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Exporta cópia de segurança para ficheiro de texto em " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Introduza caminho para o ficheiro de texto" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Importar utilizador a partir do ficheiro em " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Introduza o caminho para o ficheiro de spool do jabberd1.4" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Importar utilizadores a partir do directório em " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Introduza o caminho para o directório de spools do jabberd1.4" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Caminho para o directório" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Configuração da Lista de Controlo de Acesso" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Listas de Controlo de Acesso" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Configuração de acessos" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Regras de acesso" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Palavra-chave" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "" + +#: mod_configure.erl:1252 +#, fuzzy +msgid "Number of registered users" +msgstr "Utilizadores registados" + +#: mod_configure.erl:1266 +#, fuzzy +msgid "Number of online users" +msgstr "Utilizadores ligados" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Nunca" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Ligado" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "" + +#: mod_configure.erl:1668 +#, fuzzy +msgid "Roster size" +msgstr "Lista de contactos" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "" + +#: mod_configure.erl:1670 +#, fuzzy +msgid "Resources" +msgstr "Restaurar" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Administração de " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Acção no utilizador" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Editar propriedades" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Eliminar utilizador" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Acesso negado pela política de serviço" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "Módulo de IRC ejabberd" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "" +"É necessário um cliente com suporte de x:data para configurar as opções do " +"mod_irc" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Registo no mod_irc para" + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Introduza o nome de utilizador e codificações de caracteres que quer usar ao " +"conectar-se aos servidores de IRC" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "Nome do utilizador de IRC" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Se deseja especificar codificações de caracteres diferentes para cada " +"servidor IRC preencha esta lista con valores no formato '{\"servidor irc\", " +"\"codificação\"}'. Este serviço usa por omissão a codificação \"~s\"." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Codificações" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "" +"Só os administradores do serviço têm permissão para enviar mensagens de " +"serviço" + +#: mod_muc/mod_muc.erl:446 +#, fuzzy +msgid "Room creation is denied by service policy" +msgstr "Acesso negado pela política de serviço" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "A sala não existe" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "" +"É necessário um cliente com suporte de x:data para poder registar a alcunha" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Registo da alcunha em " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Introduza a alcunha que quer registar" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Alcunha" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "A alcunha especificada já está registada" + +#: mod_muc/mod_muc.erl:635 +#, fuzzy +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Deve preencher o campo \"alcunha\" no formulário" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "Módulo MUC de ejabberd" + +#: mod_muc/mod_muc_log.erl:338 +#, fuzzy +msgid "Chatroom configuration modified" +msgstr "Configuração para " + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " colocou o tópico: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "" + +#: mod_muc/mod_muc_log.erl:425 +#, fuzzy +msgid "November" +msgstr "Nunca" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "" + +#: mod_muc/mod_muc_log.erl:675 +#, fuzzy +msgid "Room Configuration" +msgstr "Configuração" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Título da sala" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Impedir o envio de mensagens privadas para a sala" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Tipo de mensagem incorrecto" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "Não é permitido enviar mensagens privadas do tipo \"groupchat\"" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "O destinatário não está na sala" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Só os ocupantes podem enviar mensagens para a sala" + +#: mod_muc/mod_muc_room.erl:528 +#, fuzzy +msgid "It is not allowed to send private messages" +msgstr "Impedir o envio de mensagens privadas para a sala" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Só os ocupantes podem enviar consultas para a sala" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "Nesta sala não são permitidas consultas aos seus membros" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "privado" + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "Só os moderadores e os participantes podem mudar o tópico desta sala" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Só os moderadores podem mudar o tópico desta sala" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "Os visitantes não podem enviar mensagens para todos os ocupantes" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" + +#: mod_muc/mod_muc_room.erl:949 +#, fuzzy +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Só os moderadores podem mudar o tópico desta sala" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "A alcunha já está a ser usado por outro ocupante" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "A alcunha já está registada por outra pessoa" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Foi banido desta sala" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "É necessário ser membro desta sala para poder entrar" + +#: mod_muc/mod_muc_room.erl:1511 +#, fuzzy +msgid "This room is not anonymous" +msgstr "Tornar a sala anónima?" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "É necessária a palavra-chave para poder entrar nesta sala" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Palavra-chave incorrecta" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "São necessários privilégios de administrador" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "São necessários privilégios de moderador" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "O JID ~s não é válido" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "A alcunha ~s não existe na sala" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Afiliação inválida: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Papel inválido: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "São necessários privilégios de dono" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Configuração para " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Subscrição" + +#: mod_muc/mod_muc_room.erl:2688 +#, fuzzy +msgid "Make room persistent" +msgstr "Tornar a sala permanente?" + +#: mod_muc/mod_muc_room.erl:2693 +#, fuzzy +msgid "Make room public searchable" +msgstr "Tornar a sala publicamente visível?" + +#: mod_muc/mod_muc_room.erl:2696 +#, fuzzy +msgid "Make participants list public" +msgstr "Tornar pública a lista de participantes?" + +#: mod_muc/mod_muc_room.erl:2699 +#, fuzzy +msgid "Make room password protected" +msgstr "Proteger a sala com palavra-chave?" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2743 +#, fuzzy +msgid "anyone" +msgstr "Nenhum" + +#: mod_muc/mod_muc_room.erl:2745 +#, fuzzy +msgid "Make room members-only" +msgstr "Tornar a sala exclusiva a membros?" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Tornar a sala moderada" + +#: mod_muc/mod_muc_room.erl:2751 +#, fuzzy +msgid "Default users as participants" +msgstr "Os utilizadores são membros por omissão?" + +#: mod_muc/mod_muc_room.erl:2754 +#, fuzzy +msgid "Allow users to change subject" +msgstr "Permitir aos utilizadores mudar o tópico?" + +#: mod_muc/mod_muc_room.erl:2757 +#, fuzzy +msgid "Allow users to send private messages" +msgstr "Permitir que os utilizadores enviem mensagens privadas?" + +#: mod_muc/mod_muc_room.erl:2760 +#, fuzzy +msgid "Allow users to query other users" +msgstr "Permitir aos utilizadores consultar outros utilizadores?" + +#: mod_muc/mod_muc_room.erl:2763 +#, fuzzy +msgid "Allow users to send invites" +msgstr "Permitir que os utilizadores enviem convites?" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "" + +#: mod_muc/mod_muc_room.erl:2769 +#, fuzzy +msgid "Allow visitors to change nickname" +msgstr "Permitir aos utilizadores mudar o tópico?" + +#: mod_muc/mod_muc_room.erl:2777 +#, fuzzy +msgid "Enable logging" +msgstr "Guardar históricos?" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "É necessário um cliente com suporte de x:data para configurar a sala" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "" + +#: mod_muc/mod_muc_room.erl:3201 +#, fuzzy +msgid "the password is" +msgstr "Mudar palavra-chave" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "" + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +#, fuzzy +msgid "~s's Offline Messages Queue" +msgstr "~s fila de mensagens diferidas" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +#, fuzzy +msgid "Submitted" +msgstr "enviado" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Data" + +#: mod_offline.erl:507 +msgid "From" +msgstr "De" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Para" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Pacote" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Eliminar os seleccionados" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +#, fuzzy +msgid "Offline Messages:" +msgstr "Mensagens diferidas:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +#, fuzzy +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "Módulo vCard de ejabberd" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:846 +#, fuzzy +msgid "ejabberd Publish-Subscribe module" +msgstr "Módulo pub/sub de ejabberd" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:1005 +#, fuzzy +msgid "Node ID" +msgstr "Nodo" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "" +"Escolha um nome de utilizador e palavra-chave para se registar neste servidor" + +#: mod_register.erl:232 +#, fuzzy +msgid "Users are not allowed to register accounts so fast" +msgstr "Os visitantes não podem enviar mensagens para todos os ocupantes" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Nenhum" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Subscrição" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Pendente" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Grupos" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Remover" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Lista de contactos de " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +#, fuzzy +msgid "Bad format" +msgstr "formato inválido" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +#, fuzzy +msgid "Add Jabber ID" +msgstr "Adicionar JID" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Lista de contactos" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +#, fuzzy +msgid "Shared Roster Groups" +msgstr "Lista de contactos partilhada" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Adicionar novo" + +#: mod_shared_roster.erl:716 +#, fuzzy +msgid "Name:" +msgstr "Nome" + +#: mod_shared_roster.erl:721 +#, fuzzy +msgid "Description:" +msgstr "Subscrição" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "" + +#: mod_shared_roster.erl:746 +#, fuzzy +msgid "Group " +msgstr "Grupos" + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Enviar" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Servidor Jabber em Erlang" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Data de nascimento" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Cidade" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "País" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +#, fuzzy +msgid "Email" +msgstr "email" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Apelido" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +#, fuzzy +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "Preencha os campos para procurar utilizadores Jabber coincidentes" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Nome completo" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Segundo nome" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Nome" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Nome da organização" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Unidade da organização" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Procurar utilizadores em " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Utilizador" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "É necessário um cliente com suporte de x:data para poder procurar" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "Módulo vCard de ejabberd" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +#, fuzzy +msgid "Search Results for " +msgstr "Procurar utilizadores em " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Preencha os campos para procurar utilizadores Jabber coincidentes" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +#, fuzzy +msgid "ejabberd Web Admin" +msgstr "Administração do ejabberd" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +#, fuzzy +msgid "Administration" +msgstr "Administração de " + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Nodos" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Estatísticas" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Utilizadores" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Última actividade" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +#, fuzzy +msgid "(Raw)" +msgstr "(modo texto)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +#, fuzzy +msgid "Raw" +msgstr "modo texto" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "Configuração das Regra de Acesso ~s" + +#: web/ejabberd_web_admin.erl:885 +#, fuzzy +msgid "ejabberd virtual hosts" +msgstr "Estatísticas do ejabberd" + +#: web/ejabberd_web_admin.erl:924 +#, fuzzy +msgid "Users Last Activity" +msgstr "Última actividade" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "" + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "" + +#: web/ejabberd_web_admin.erl:938 +#, fuzzy +msgid "All activity" +msgstr "Última actividade" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Nodo não encontrado" + +#: web/ejabberd_web_admin.erl:1273 +#, fuzzy +msgid "Host" +msgstr "Nome do servidor" + +#: web/ejabberd_web_admin.erl:1274 +#, fuzzy +msgid "Registered Users" +msgstr "Utilizadores registados" + +#: web/ejabberd_web_admin.erl:1382 +#, fuzzy +msgid "Offline Messages" +msgstr "Mensagens diferidas" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +#, fuzzy +msgid "Registered Users:" +msgstr "Utilizadores registados" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +#, fuzzy +msgid "Online Users:" +msgstr "Utilizadores ligados" + +#: web/ejabberd_web_admin.erl:1443 +#, fuzzy +msgid "Outgoing s2s Connections:" +msgstr "Conexões S2S para fora" + +#: web/ejabberd_web_admin.erl:1445 +#, fuzzy +msgid "Outgoing s2s Servers:" +msgstr "Servidores S2S de saída" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Mudar palavra-chave" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Utilizador" + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Recursos conectados:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Palavra-chave:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Nodo" + +#: web/ejabberd_web_admin.erl:1675 +#, fuzzy +msgid "Listened Ports" +msgstr "Portas em escuta em " + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Actualizar" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Reiniciar" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Parar" + +#: web/ejabberd_web_admin.erl:1696 +#, fuzzy +msgid "RPC Call Error" +msgstr "Erro na chamada RPC" + +#: web/ejabberd_web_admin.erl:1734 +#, fuzzy +msgid "Database Tables at " +msgstr "Tabelas da BD em " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Tipo de armazenagem" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Tamanho" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Memória" + +#: web/ejabberd_web_admin.erl:1758 +#, fuzzy +msgid "Backup of " +msgstr "Guardar cópia de segurança" + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" + +#: web/ejabberd_web_admin.erl:1764 +#, fuzzy +msgid "Store binary backup:" +msgstr "Armazenar uma cópia de segurança no ficheiro" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "OK" + +#: web/ejabberd_web_admin.erl:1771 +#, fuzzy +msgid "Restore binary backup immediately:" +msgstr "Recuperar uma cópia de segurança a partir de ficheiro" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "" + +#: web/ejabberd_web_admin.erl:1793 +#, fuzzy +msgid "Restore plain text backup immediately:" +msgstr "Recuperar uma cópia de segurança a partir de ficheiro" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Portas em escuta em " + +#: web/ejabberd_web_admin.erl:1837 +#, fuzzy +msgid "Modules at " +msgstr "Parar módulos em " + +#: web/ejabberd_web_admin.erl:1862 +#, fuzzy +msgid "Statistics of ~p" +msgstr "Estatísticas" + +#: web/ejabberd_web_admin.erl:1865 +#, fuzzy +msgid "Uptime:" +msgstr "Tempo de funcionamento" + +#: web/ejabberd_web_admin.erl:1868 +#, fuzzy +msgid "CPU Time:" +msgstr "Tempo de processador consumido" + +#: web/ejabberd_web_admin.erl:1874 +#, fuzzy +msgid "Transactions Commited:" +msgstr "Transacções realizadas" + +#: web/ejabberd_web_admin.erl:1877 +#, fuzzy +msgid "Transactions Aborted:" +msgstr "Transacções abortadas" + +#: web/ejabberd_web_admin.erl:1880 +#, fuzzy +msgid "Transactions Restarted:" +msgstr "Transacções reiniciadas" + +#: web/ejabberd_web_admin.erl:1883 +#, fuzzy +msgid "Transactions Logged:" +msgstr "Transacções armazenadas" + +#: web/ejabberd_web_admin.erl:1906 +#, fuzzy +msgid "Update " +msgstr "Actualizar" + +#: web/ejabberd_web_admin.erl:1914 +#, fuzzy +msgid "Update plan" +msgstr "Actualizar" + +#: web/ejabberd_web_admin.erl:1915 +#, fuzzy +msgid "Updated modules" +msgstr "Iniciar módulos" + +#: web/ejabberd_web_admin.erl:1916 +#, fuzzy +msgid "Update script" +msgstr "Actualizar" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Porta" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Módulo" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Opções" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Eliminar" + +#: web/ejabberd_web_admin.erl:2158 +#, fuzzy +msgid "Start" +msgstr "Reiniciar" + +#~ msgid "Backup Management at " +#~ msgstr "Gestão da cópia de segurança em " + +#~ msgid "Choose host name" +#~ msgstr "Introduza o nome do servidor" + +#~ msgid "Choose users to remove" +#~ msgstr "Seleccione utilizadores a eliminar" + +#~ msgid "DB" +#~ msgstr "BD" + +#~ msgid "Dump a database in a text file" +#~ msgstr "Exportar uma Base de Dados para um ficheiro de texto" + +#~ msgid "Host name" +#~ msgstr "Nome do servidor" + +#~ msgid "Hostname Configuration" +#~ msgstr "Configuração do nome do servidor" + +#~ msgid "Install a database fallback from a file" +#~ msgstr "Instalar uma recuperação de BD desde um ficheiro" + +#~ msgid "It is not allowed to send normal messages to the conference" +#~ msgstr "Impedir o envio de mensagens normais para a sala" + +#~ msgid "Listened Ports Management" +#~ msgstr "Gestão das portas em escuta" + +#~ msgid "Make room moderated?" +#~ msgstr "Tornar a sala moderada?" + +#~ msgid "Remove Users" +#~ msgstr "Eliminar utilizadores" + +#~ msgid "Restore a database from a text file" +#~ msgstr "Restaurar uma Base de Dados a partir de ficheiro de texto" + +#~ msgid "Results of search in " +#~ msgstr "Resultados da procura em " + +#~ msgid "ejabberd (c) 2002-2005 Alexey Shchepin, 2005 Process One" +#~ msgstr "ejabberd (c) 2002-2005 Alexey Shchepin, 2005 Process One" + +#~ msgid "ejabberd access control lists configuration" +#~ msgstr "Configuração das Listas de Controlo de Acesso do ejabberd" + +#~ msgid "ejabberd access rules configuration" +#~ msgstr "Configuração das Regras de Acesso do ejabberd" + +#~ msgid "ejabberd users" +#~ msgstr "Utilizadores do ejabberd" + +#~ msgid "~p statistics" +#~ msgstr "Estatísticas de ~p" diff --git a/src/msgs/ru.msg b/src/msgs/ru.msg index f5176614b..94bc74f42 100644 --- a/src/msgs/ru.msg +++ b/src/msgs/ru.msg @@ -1,387 +1,343 @@ -% $Id$ -% Language: Russian (русский) -% Author: Konstantin Khomoutov -% Author: Sergei Golovan - -% ejabberd_c2s.erl -{"Use of STARTTLS required", "Вы обязаны использовать STARTTLS"}. -{"Replaced by new connection", "Заменено новым соединением"}. - -% jlib.hrl -{"No resource provided", "Не указан ресурс"}. - -% mod_adhoc.erl -{"Commands", "Команды"}. -{"Ping", "Пинг"}. -{"Pong", "Понг"}. - -% mod_announce.erl -{"Really delete message of the day?", "Действительно удалить сообщение дня?"}. -{"Subject", "Тема"}. -{"Message body", "Тело сообщения"}. -{"No body provided for announce message", "Тело объявления не должно быть пустым"}. -{"Announcements", "Объявления"}. -{"Send announcement to all users", "Разослать объявление всем пользователям"}. -{"Send announcement to all online users", "Разослать объявление всем подключённым пользователям"}. -{"Send announcement to all online users on all hosts", "Разослать объявление всем подключённым пользователям на всех виртуальных серверах"}. -{"Set message of the day and send to online users", "Установить сообщение дня и разослать его подключённым пользователям"}. -{"Update message of the day (don't send)", "Обновить сообщение дня (не рассылать)"}. -{"Delete message of the day", "Удалить сообщение дня"}. -{"Send announcement to all users on all hosts", "Разослать объявление всем пользователям на всех виртуальных серверах"}. -{"Set message of the day on all hosts and send to online users", "Установить сообщение дня на всех виртуальных серверах и разослать его подключённым пользователям"}. -{"Update message of the day on all hosts (don't send)", "Обновить сообщение дня на всех виртуальных серверах (не рассылать)"}. -{"Delete message of the day on all hosts", "Удалить сообщение дня со всех виртуальных серверов"}. - -% mod_configure.erl -{"Database Tables Configuration at ", "Конфигурация таблиц базы данных на "}. -{"Choose storage type of tables", "Выберите тип хранения таблиц"}. -{"RAM copy", "ОЗУ"}. -{"RAM and disc copy", "ОЗУ и диск"}. -{"Disc only copy", "только диск"}. -{"Remote copy", "не хранится локально"}. -{"Stop Modules at ", "Остановка модулей на "}. -{"Choose modules to stop", "Выберите модули, которые следует остановить"}. -{"Start Modules at ", "Запуск модулей на "}. -{"Enter list of {Module, [Options]}", "Введите список вида {Module, [Options]}"}. -{"List of modules to start", "Список запускаемых модулей"}. -{"Backup to File at ", "Резервное копирование в файл на "}. -{"Enter path to backup file", "Введите путь к резервному файлу"}. -{"Path to File", "Путь к файлу"}. -{"Restore Backup from File at ", "Восстановление из резервной копии на "}. -{"Dump Backup to Text File at ", "Копирование в текстовый файл на "}. -{"Enter path to text file", "Введите путь к текстовому файлу"}. -{"Import User from File at ", "Импорт пользователя из файла на "}. -{"Enter path to jabberd1.4 spool file", "Введите путь к файлу из спула jabberd1.4"}. -{"Import Users from Dir at ", "Импорт пользователей из директории на "}. -{"Enter path to jabberd1.4 spool dir", "Введите путь к директории спула jabberd1.4"}. -{"Path to Dir", "Путь к директории"}. -{"Access Control List Configuration", "Конфигурация списков управления доступом"}. -{"Access control lists", "Списки управления доступом"}. -{"Access Configuration", "Конфигурация доступа"}. -{"Access rules", "Правила доступа"}. -{"Administration of ", "Администрирование "}. -{"Action on user", "Действие над пользователем"}. -{"Edit Properties", "Изменить параметры"}. -{"Remove User", "Удалить пользователя"}. -{"Restart Service", "Перезапустить службу"}. -{"Shut Down Service", "Остановить службу"}. -{"Delete User", "Удалить пользователя"}. -{"End User Session", "Завершить сеанс пользователя"}. -{"Get User Password", "Получить пароль пользователя"}. -{"Change User Password", "Изменить пароль пользователя"}. -{"Get User Last Login Time", "Получить время последнего подключения пользователя"}. -{"Get User Statistics", "Получить статистику по пользователю"}. -{"Get Number of Registered Users", "Получить количество зарегистрированных пользователей"}. -{"Get Number of Online Users", "Получить количество подключённых пользователей"}. -{"User Management", "Управление пользователями"}. -{"Time delay", "По истечение"}. -{"Password Verification", "Проверка пароля"}. -{"Number of registered users", "Количество зарегистрированных пользователей"}. -{"Number of online users", "Количество подключённых пользователей"}. -{"Last login", "Время последнего подключения"}. -{"Roster size", "Размер списка контактов"}. -{"IP addresses", "IP адреса"}. -{"Resources", "Ресурсы"}. - -% mod_disco.erl -{"Configuration", "Конфигурация"}. -{"Online Users", "Подключённые пользователи"}. -{"All Users", "Все пользователи"}. -{"Outgoing s2s Connections", "Исходящие s2s-соединения"}. -{"To ~s", "К ~s"}. -{"From ~s", "От ~s"}. -{"Running Nodes", "Работающие узлы"}. -{"Stopped Nodes", "Остановленные узлы"}. -{"Access Control Lists", "Списки управления доступом"}. -{"Access Rules", "Правила доступа"}. -{"Database", "База данных"}. -{"Modules", "Модули"}. -{"Start Modules", "Запуск модулей"}. -{"Stop Modules", "Остановка модулей"}. -{"Backup Management", "Управление резервным копированием"}. -{"Import Users From jabberd 1.4 Spool Files", "Импорт пользователей из спула jabberd 1.4"}. -{"Backup", "Резервное копирование"}. -{"Restore", "Восстановление из резервной копии"}. -{"Dump to Text File", "Копирование в текстовый файл"}. -{"Import File", "Импорт из файла"}. -{"Import Directory", "Импорт из директории"}. - -% mod_proxy65.erl - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "ejabberd SOCKS5 Bytestreams модуль"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Выберите имя пользователя и пароль для регистрации на этом сервере"}. - -% mod_vcard.erl -{"Erlang Jabber Server", "Erlang Jabber Server"}. -{"ejabberd vCard module", "ejabberd vCard модуль"}. -{"You need an x:data capable client to search", "Чтобы воспользоваться поиском, требуется x:data-совместимый клиент"}. -{"Search users in ", "Поиск пользователей в "}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Заполните форму для поиска пользователя Jabber (Если добавить * в конец поля, то происходит поиск подстроки)"}. -{"Search Results for ", "Результаты поиска в "}. -{"Jabber ID", "Jabber ID"}. -{"User", "Пользователь"}. -{"Full Name", "Полное имя"}. -{"Name", "Имя"}. -{"Middle Name", "Отчество"}. -{"Family Name", "Фамилия"}. -{"Nickname", "Псевдоним"}. -{"Birthday", "День рождения"}. -{"Country", "Страна"}. -{"City", "Город"}. -{"Email", "Электронная почта"}. -{"Organization Name", "Название организации"}. -{"Organization Unit", "Отдел организации"}. - -% mod_vcard_ldap.erl -{"Fill in fields to search for any matching Jabber User", "Заполните форму для поиска пользователя Jabber"}. - -% mod_pubsub/mod_pubsub.erl -{"Roster groups allowed to subscribe", "Группы списка контактов, которым разрешена подписка"}. -{"Deliver payloads with event notifications", "Доставлять вместе с уведомлениями o публикациях сами публикации"}. -{"Notify subscribers when the node configuration changes", "Уведомлять подписчиков об изменении конфигурации сборника"}. -{"Notify subscribers when the node is deleted", "Уведомлять подписчиков об удалении сборника"}. -{"Notify subscribers when items are removed from the node", "Уведомлять подписчиков об удалении публикаций из сборника"}. -{"Persist items to storage", "Сохранять публикации в хранилище"}. -{"Max # of items to persist", "Максимальное число сохраняемых публикаций"}. -{"Whether to allow subscriptions", "Разрешить подписку"}. -{"Specify the publisher model", "Условия публикации"}. -{"Max payload size in bytes", "Максимальный размер полезной нагрузки в байтах"}. -{"Only deliver notifications to available users", "Доставлять уведомления только доступным пользователям"}. -{"Publish-Subscribe", "Публикация-Подписка"}. -{"ejabberd Publish-Subscribe module", "Модуль ejabberd Публикации-Подписки"}. -{"PubSub subscriber request", "Запрос подписчика PubSub"}. -{"Choose whether to approve this entity's subscription.", "Решите: предоставить ли подписку этому объекту."}. -{"Node ID", "ID узла"}. -{"Subscriber Address", "Адрес подписчика"}. -{"Allow this JID to subscribe to this pubsub node?", "Разрешить этому JID подписаться на данный узел?"}. -{"Deliver event notifications", "Доставлять уведомления о событиях"}. -{"Specify the access model", "Укажите механизм управления доступом"}. -{"When to send the last published item", "Когда посылать последний опубликованный элемент"}. - -% mod_muc/mod_muc.erl -{"You need an x:data capable client to register nickname", "Чтобы зарегистрировать псевдоним, требуется x:data-совместимый клиент"}. -{"Nickname Registration at ", "Регистрация псевдонима на "}. -{"Enter nickname you want to register", "Введите псевдоним, который Вы хотели бы зарегистрировать"}. -{"ejabberd MUC module", "ejabberd MUC модуль"}. -{"Only service administrators are allowed to send service messages", "Только администратор службы может посылать служебные сообщения"}. -{"Room creation is denied by service policy", "Cоздавать конференцию запрещено политикой службы"}. -{"Conference room does not exist", "Конференция не существует"}. -{"Access denied by service policy", "Доступ запрещён политикой службы"}. -{"You must fill in field \"Nickname\" in the form", "Вы должны заполнить поле \"Псевдоним\" в форме"}. -{"Specified nickname is already registered", "Указанный псевдоним уже зарегистрирован"}. -{"Chatrooms", "Комнаты"}. - -% mod_muc/mod_muc_log.erl -{"has been kicked because of an affiliation change", "выгнали из комнаты вследствие смены ранга"}. -{"has been kicked because the room has been changed to members-only", "выгнали из комнаты потому что она стала только для членов"}. -{"has been kicked because of a system shutdown", "выгнали из комнаты из-за останова системы"}. -{"Chatroom configuration modified", "Конфигурация комнаты изменилась"}. -{"joins the room", "вошёл(а) в комнату"}. -{"leaves the room", "вышел(а) из комнаты"}. -{"has been kicked", "выгнали из комнаты"}. -{"has been banned", "запретили входить в комнату"}. -{"is now known as", "изменил(а) имя на"}. -{"Monday", "Понедельник"}. -{"Tuesday", "Вторник"}. -{"Wednesday", "Среда"}. -{"Thursday", "Четверг"}. -{"Friday", "Пятница"}. -{"Saturday", "Суббота"}. -{"Sunday", "Воскресенье"}. -{"January", "января"}. -{"February", "февраля"}. -{"March", "марта"}. -{"April", "апреля"}. -{"May", "мая"}. -{"June", "июня"}. -{"July", "июля"}. -{"August", "августа"}. -{"September", "сентября"}. -{"October", "октября"}. -{"November", "ноября"}. -{"December", "декабря"}. -{"Room Configuration", "Конфигурация комнаты"}. - -% mod_muc/mod_muc_room.erl -{"This participant is kicked from the room because he sent an error message", "Этого участника выгнали из комнаты за то, что он послал сообщение об ошибке"}. -{"This participant is kicked from the room because he sent an error message to another participant", "Этого участника выгнали из комнаты за то, что он послал сообщение об ошибке другому участнику"}. -{"This participant is kicked from the room because he sent an error presence", "Этого участника выгнали из комнаты за то, что он послал присутствие с ошибкой"}. -{"Make room moderated", "Сделать комнату модерируемой"}. -{"This room is not anonymous", "Эта комната не анонимная"}. -{" has set the subject to: ", " установил(а) тему: "}. -{"You need an x:data capable client to configure room", "Чтобы сконфигурировать комнату, требуется x:data-совместимый клиент"}. -{"Configuration for ", "Конфигурация "}. -{"Room title", "Название комнаты"}. -{"Allow users to change subject", "Разрешить пользователям изменять тему"}. -{"Allow users to query other users", "Разрешить iq-запросы к пользователям"}. -{"Allow users to send private messages", "Разрешить приватные сообщения"}. -{"Make room public searchable", "Сделать комнату видимой всем"}. -{"Make participants list public", "Сделать список участников видимым всем"}. -{"Make room persistent", "Сделать комнату постоянной"}. -{"Default users as participants", "Сделать пользователей участниками по умолчанию"}. -{"Make room members-only", "Комната только для зарегистрированных участников"}. -{"Allow users to send invites", "Разрешить пользователям посылать приглашения"}. -{"Make room password protected", "Сделать комнату защищённой паролем"}. -{"Password", "Пароль"}. -{"Present real JIDs to", "Сделать реальные JID участников видимыми"}. -{"moderators only", "только модераторам"}. -{"anyone", "всем участникам"}. -{"Enable logging", "Включить журналирование"}. -{"Only moderators and participants are allowed to change subject in this room", "Только модераторы и участники могут изменять тему в этой комнате"}. -{"Only moderators are allowed to change subject in this room", "Только модераторы могут изменять тему в этой комнате"}. -{"Visitors are not allowed to send messages to all occupants", "Посетителям не разрешается посылать сообщения всем присутствующим"}. -{"Only occupants are allowed to send messages to the conference", "Только присутствующим разрешается посылать сообщения в конференцию"}. -{"It is not allowed to send private messages to the conference", "Не разрешается посылать частные сообщения прямо в конференцию"}. -{"Improper message type", "Неправильный тип сообщения"}. -{"Nickname is already in use by another occupant", "Псевдоним занят кем-то из присутствующих"}. -{"Nickname is registered by another person", "Псевдоним зарегистирован кем-то другим"}. -{"It is not allowed to send private messages of type \"groupchat\"", "Нельзя посылать частные сообщения типа \"groupchat\""}. -{"Recipient is not in the conference room", "Адресата нет в конференции"}. -{"Only occupants are allowed to send queries to the conference", "Только присутствующим разрешается посылать запросы в конференцию"}. -{"Queries to the conference members are not allowed in this room", "Запросы к пользователям в этой конференции запрещены"}. -{"You have been banned from this room", "Вам запрещено входить в эту конференцию"}. -{"Membership required to enter this room", "В эту конференцию могут входить только её члены"}. -{"Password required to enter this room", "Чтобы войти в эту конференцию, нужен пароль"}. -{"Incorrect password", "Неправильный пароль"}. -{"Administrator privileges required", "Требуются права администратора"}. -{"Moderator privileges required", "Требуются права модератора"}. -{"JID ~s is invalid", "JID ~s недопустимый"}. -{"Nickname ~s does not exist in the room", "Псевдоним ~s в комнате отсутствует"}. -{"Invalid affiliation: ~s", "Недопустимый ранг: ~s"}. -{"Invalid role: ~s", "Недопустимая роль: ~s"}. -{"Owner privileges required", "Требуются права владельца"}. -{"private, ", "приватная, "}. -{"Number of occupants", "Число присутствующих"}. -{"Traffic rate limit is exceeded", "Превышен лимит скорости посылки информации"}. -{"Maximum Number of Occupants", "Максимальное количество участников"}. -{"No limit", "Не ограничено"}. -{"~s invites you to the room ~s", "~s приглашает вас в комнату ~s"}. -{"the password is", "пароль:"}. - -% mod_irc/mod_irc.erl -{"ejabberd IRC module", "ejabberd IRC модуль"}. -{"You need an x:data capable client to configure mod_irc settings", "Чтобы настроить параметры mod_irc, требуется x:data-совместимый клиент"}. -{"Registration in mod_irc for ", "Регистрация в mod_irc для "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Введите имя пользователя и кодировки, которые будут использоваться при подключении к IRC-серверам"}. -{"IRC Username", "Имя пользователя IRC"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Чтобы указать различные кодировки для разных серверов IRC, заполните список значениями в формате '{\"irc server\", \"encoding\"}'. По умолчанию эта служба использует кодировку \"~s\"."}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Примеры: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"Encodings", "Кодировки"}. -{"IRC Transport", "IRC Транспорт"}. - -% web/ejabberd_web_admin.erl -{"ejabberd Web Admin", "Web-интерфейс администрирования ejabberd"}. -{"Administration", "Администрирование"}. -{"Users", "Пользователи"}. -{"Nodes", "Узлы"}. -{"Statistics", "Статистика"}. -{"(Raw)", "(Необработанный формат)"}. -{"Submitted", "Отправлено"}. -{"Bad format", "Неправильный формат"}. -{"Raw", "Необработанный формат"}. -{"Delete Selected", "Удалить выделенные"}. -{"Submit", "Отправить"}. -{"~s access rule configuration", "Конфигурация правила доступа ~s"}. -{"Node not found", "Узел не найден"}. -{"Add New", "Добавить"}. -{"Registered Users", "Зарегистрированные пользователи"}. -{"Registered Users:", "Зарегистрированные пользователи:"}. -{"Online Users", "Подключённые пользователи"}. -{"Online Users:", "Подключённые пользователи:"}. -{"Outgoing s2s Connections:", "Исходящие s2s-серверы:"}. -{"Outgoing s2s Servers:", "Исходящие s2s-серверы:"}. -{"Change Password", "Сменить пароль"}. -{"Connected Resources:", "Подключённые ресурсы:"}. -{"Password:", "Пароль:"}. -{"None", "Нет"}. -{"Node ", "Узел "}. -{"Listened Ports", "Прослушиваемые порты"}. -{"Restart", "Перезапустить"}. -{"Stop", "Остановить"}. -{"RPC Call Error", "Ошибка вызова RPC"}. -{"Database Tables at ", "Таблицы базы данных на "}. -{"Name", "Название"}. -{"Storage Type", "Тип таблицы"}. -{"Size", "Размер"}. -{"Memory", "Память"}. -{"Backup of ", "Резервное копирование "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "Заметьте, что здесь производится резервное копирование только встроенной базы данных Mnesia. Если Вы также используете другое хранилище данных (например с помощью модуля ODBC), то его резервное копирование следует осуществлять отдельно."}. -{"Store binary backup:", "Сохранить бинарную резервную копию:"}. -{"OK", "Продолжить"}. -{"Restore binary backup immediately:", "Восстановить из бинарной резервной копии немедленно:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Восстановить из бинарной резервной копии при следующем запуске (требует меньше памяти):"}. -{"Store plain text backup:", "Сохранить текстовую резервную копию:"}. -{"Restore plain text backup immediately:", "Восстановить из текстовой резервной копии немедленно:"}. -{"Listened Ports at ", "Прослушиваемые порты на "}. -{"Statistics of ~p", "статистика узла ~p"}. -{"Uptime:", "Время работы:"}. -{"CPU Time:", "Процессорное время:"}. -{"Transactions Commited:", "Транзакции завершенные:"}. -{"Transactions Aborted:", "Транзакции отмененные:"}. -{"Transactions Restarted:", "Транзакции перезапущенные:"}. -{"Transactions Logged:", "Транзакции запротоколированные:"}. -{"Update ", "Обновление "}. -{"Update plan", "План обновления"}. -{"Updated modules", "Обновлённые модули"}. -{"Update script", "Сценарий обновления"}. -{"Low level update script", "Низкоуровневый сценарий обновления"}. -{"Script check", "Проверка сценария"}. -{"Port", "Порт"}. -{"Module", "Модуль"}. -{"Options", "Параметры"}. -{"Update", "Обновить"}. -{"Delete", "Удалить"}. -{"Add User", "Добавить пользователя"}. -{"Offline Messages", "Офлайновые сообщения"}. -{"Offline Messages:", "Офлайновые сообщения:"}. -{"Last Activity", "Последнее подключение"}. -{"Never", "Никогда"}. -{"~s's Offline Messages Queue", "Oчередь офлайновых сообщений ~s"}. -{"Time", "Время"}. -{"From", "От кого"}. -{"To", "Кому"}. -{"Packet", "Пакет"}. -{"Roster", "Ростер"}. -{"Nickname", "Псевдоним"}. -{"Subscription", "Подписка"}. -{"Pending", "Ожидание"}. -{"Groups", "Группы"}. -{"Remove", "Удалить"}. -{"Add Jabber ID", "Добавить Jabber ID"}. -{"User ", "Пользователь "}. -{"Roster of ", "Ростер пользователя "}. -{"Online", "Подключён"}. -{"Validate", "Утвердить"}. -{"Shared Roster Groups", "Группы общих контактов"}. -{"Name:", "Название:"}. -{"Description:", "Описание:"}. -{"Members:", "Члены:"}. -{"Displayed Groups:", "Видимые группы:"}. -{"Group ", "Группа "}. -{"Users Last Activity", "Статистика последнего подключения пользователей"}. -{"Period: ", "Период"}. -{"Last month", "За последний месяц"}. -{"Last year", "За последний год"}. -{"All activity", "Вся статистика"}. -{"Show Ordinary Table", "Показать обычную таблицу"}. -{"Show Integral Table", "Показать интегральную таблицу"}. -{"Start", "Запустить"}. -{"Modules at ", "Модули на "}. -{"No Data", "Нет данных"}. -{"Virtual Hosts", "Виртуальные хосты"}. -{"ejabberd virtual hosts", "Виртуальные хосты ejabberd"}. -{"Host", "Хост"}. - -% mod_vcard_odbc.erl -{"vCard User Search", "Поиск пользователей по vCard"}. - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "Очередь недоставленных сообщений Вашего адресата переполнена. Сообщение не было сохранено."}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Конфигурация доступа"}. +{"Access Control List Configuration","Конфигурация списков управления доступом"}. +{"Access control lists","Списки управления доступом"}. +{"Access Control Lists","Списки управления доступом"}. +{"Access denied by service policy","Доступ запрещён политикой службы"}. +{"Access rules","Правила доступа"}. +{"Access Rules","Правила доступа"}. +{"Action on user","Действие над пользователем"}. +{"Add Jabber ID","Добавить Jabber ID"}. +{"Add New","Добавить"}. +{"Add User","Добавить пользователя"}. +{"Administration of ","Администрирование "}. +{"Administration","Администрирование"}. +{"Administrator privileges required","Требуются права администратора"}. +{"A friendly name for the node","Легко запоминаемое имя для узла"}. +{"All activity","Вся статистика"}. +{"Allow this JID to subscribe to this pubsub node?","Разрешить этому JID подписаться на данный узел?"}. +{"Allow users to change subject","Разрешить пользователям изменять тему"}. +{"Allow users to query other users","Разрешить iq-запросы к пользователям"}. +{"Allow users to send invites","Разрешить пользователям посылать приглашения"}. +{"Allow users to send private messages","Разрешить приватные сообщения"}. +{"Allow visitors to change nickname","Разрешить посетителям изменять псевдоним"}. +{"Allow visitors to send status text in presence updates","Разрешить посетителям вставлять текcт статуса в сообщения о присутствии"}. +{"All Users","Все пользователи"}. +{"Announcements","Объявления"}. +{"anyone","всем участникам"}. +{"April","апреля"}. +{"August","августа"}. +{"Backup Management","Управление резервным копированием"}. +{"Backup of ","Резервное копирование "}. +{"Backup to File at ","Резервное копирование в файл на "}. +{"Backup","Резервное копирование"}. +{"Bad format","Неправильный формат"}. +{"Birthday","День рождения"}. +{"Change Password","Сменить пароль"}. +{"Change User Password","Изменить пароль пользователя"}. +{"Chatroom configuration modified","Конфигурация комнаты изменилась"}. +{"Chatrooms","Комнаты"}. +{"Choose a username and password to register with this server","Выберите имя пользователя и пароль для регистрации на этом сервере"}. +{"Choose modules to stop","Выберите модули, которые следует остановить"}. +{"Choose storage type of tables","Выберите тип хранения таблиц"}. +{"Choose whether to approve this entity's subscription.","Решите: предоставить ли подписку этому объекту."}. +{"City","Город"}. +{"Commands","Команды"}. +{"Conference room does not exist","Конференция не существует"}. +{"Configuration for ","Конфигурация "}. +{"Configuration","Конфигурация"}. +{"Connected Resources:","Подключённые ресурсы:"}. +{"Country","Страна"}. +{"CPU Time:","Процессорное время:"}. +{"Database Tables at ","Таблицы базы данных на "}. +{"Database Tables Configuration at ","Конфигурация таблиц базы данных на "}. +{"Database","База данных"}. +{"December","декабря"}. +{"Default users as participants","Сделать пользователей участниками по умолчанию"}. +{"Delete message of the day on all hosts","Удалить сообщение дня со всех виртуальных серверов"}. +{"Delete message of the day","Удалить сообщение дня"}. +{"Delete Selected","Удалить выделенные"}. +{"Delete User","Удалить пользователя"}. +{"Delete","Удалить"}. +{"Deliver event notifications","Доставлять уведомления о событиях"}. +{"Deliver payloads with event notifications","Доставлять вместе с уведомлениями o публикациях сами публикации"}. +{"Description:","Описание:"}. +{"Disc only copy","только диск"}. +{"Displayed Groups:","Видимые группы:"}. +{"Dump Backup to Text File at ","Копирование в текстовый файл на "}. +{"Dump to Text File","Копирование в текстовый файл"}. +{"Edit Properties","Изменить параметры"}. +{"ejabberd IRC module","ejabberd IRC модуль"}. +{"ejabberd MUC module","ejabberd MUC модуль"}. +{"ejabberd Publish-Subscribe module","Модуль ejabberd Публикации-Подписки"}. +{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestreams модуль"}. +{"ejabberd vCard module","ejabberd vCard модуль"}. +{"ejabberd virtual hosts","Виртуальные хосты ejabberd"}. +{"ejabberd Web Admin","Web-интерфейс администрирования ejabberd"}. +{"Email","Электронная почта"}. +{"Enable logging","Включить журналирование"}. +{"Encodings","Кодировки"}. +{"End User Session","Завершить сеанс пользователя"}. +{"Enter list of {Module, [Options]}","Введите список вида {Module, [Options]}"}. +{"Enter nickname you want to register","Введите псевдоним, который Вы хотели бы зарегистрировать"}. +{"Enter path to backup file","Введите путь к резервному файлу"}. +{"Enter path to jabberd1.4 spool dir","Введите путь к директории спула jabberd1.4"}. +{"Enter path to jabberd1.4 spool file","Введите путь к файлу из спула jabberd1.4"}. +{"Enter path to text file","Введите путь к текстовому файлу"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Введите имя пользователя и кодировки, которые будут использоваться при подключении к IRC-серверам"}. +{"Erlang Jabber Server","Erlang Jabber Server"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Примеры: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","Фамилия"}. +{"February","февраля"}. +{"Fill in fields to search for any matching Jabber User","Заполните форму для поиска пользователя Jabber"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Заполните форму для поиска пользователя Jabber (Если добавить * в конец поля, то происходит поиск подстроки)"}. +{"Friday","Пятница"}. +{"From ~s","От ~s"}. +{"From","От кого"}. +{"Full Name","Полное имя"}. +{"Get Number of Online Users","Получить количество подключённых пользователей"}. +{"Get Number of Registered Users","Получить количество зарегистрированных пользователей"}. +{"Get User Last Login Time","Получить время последнего подключения пользователя"}. +{"Get User Password","Получить пароль пользователя"}. +{"Get User Statistics","Получить статистику по пользователю"}. +{"Groups","Группы"}. +{"Group ","Группа "}. +{"has been banned","запретили входить в комнату"}. +{"has been kicked because of an affiliation change","выгнали из комнаты вследствие смены ранга"}. +{"has been kicked because of a system shutdown","выгнали из комнаты из-за останова системы"}. +{"has been kicked because the room has been changed to members-only","выгнали из комнаты потому что она стала только для членов"}. +{"has been kicked","выгнали из комнаты"}. +{" has set the subject to: "," установил(а) тему: "}. +{"Host","Хост"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Чтобы указать различные кодировки для разных серверов IRC, заполните список значениями в формате '{\"irc server\", \"encoding\"}'. По умолчанию эта служба использует кодировку \"~s\"."}. +{"Import Directory","Импорт из директории"}. +{"Import File","Импорт из файла"}. +{"Import User from File at ","Импорт пользователя из файла на "}. +{"Import Users from Dir at ","Импорт пользователей из директории на "}. +{"Import Users From jabberd 1.4 Spool Files","Импорт пользователей из спула jabberd 1.4"}. +{"Improper message type","Неправильный тип сообщения"}. +{"Incorrect password","Неправильный пароль"}. +{"Invalid affiliation: ~s","Недопустимый ранг: ~s"}. +{"Invalid role: ~s","Недопустимая роль: ~s"}. +{"IP addresses","IP адреса"}. +{"IRC Transport","IRC Транспорт"}. +{"IRC Username","Имя пользователя IRC"}. +{"is now known as","изменил(а) имя на"}. +{"It is not allowed to send private messages of type \"groupchat\"","Нельзя посылать частные сообщения типа \"groupchat\""}. +{"It is not allowed to send private messages to the conference","Не разрешается посылать частные сообщения прямо в конференцию"}. +{"It is not allowed to send private messages","Запрещено посылать приватные сообщения"}. +{"Jabber ID","Jabber ID"}. +{"January","января"}. +{"JID ~s is invalid","JID ~s недопустимый"}. +{"joins the room","вошёл(а) в комнату"}. +{"July","июля"}. +{"June","июня"}. +{"Last Activity","Последнее подключение"}. +{"Last login","Время последнего подключения"}. +{"Last month","За последний месяц"}. +{"Last year","За последний год"}. +{"leaves the room","вышел(а) из комнаты"}. +{"Listened Ports at ","Прослушиваемые порты на "}. +{"Listened Ports","Прослушиваемые порты"}. +{"List of modules to start","Список запускаемых модулей"}. +{"Low level update script","Низкоуровневый сценарий обновления"}. +{"Make participants list public","Сделать список участников видимым всем"}. +{"Make room members-only","Комната только для зарегистрированных участников"}. +{"Make room moderated","Сделать комнату модерируемой"}. +{"Make room password protected","Сделать комнату защищённой паролем"}. +{"Make room persistent","Сделать комнату постоянной"}. +{"Make room public searchable","Сделать комнату видимой всем"}. +{"March","марта"}. +{"Maximum Number of Occupants","Максимальное количество участников"}. +{"Max # of items to persist","Максимальное число сохраняемых публикаций"}. +{"Max payload size in bytes","Максимальный размер полезной нагрузки в байтах"}. +{"May","мая"}. +{"Membership required to enter this room","В эту конференцию могут входить только её члены"}. +{"Members:","Члены:"}. +{"Memory","Память"}. +{"Message body","Тело сообщения"}. +{"Middle Name","Отчество"}. +{"Moderator privileges required","Требуются права модератора"}. +{"moderators only","только модераторам"}. +{"Modules at ","Модули на "}. +{"Modules","Модули"}. +{"Module","Модуль"}. +{"Monday","Понедельник"}. +{"Name:","Название:"}. +{"Name","Название"}. +{"Never","Никогда"}. +{"Nickname is already in use by another occupant","Псевдоним занят кем-то из присутствующих"}. +{"Nickname is registered by another person","Псевдоним зарегистирован кем-то другим"}. +{"Nickname Registration at ","Регистрация псевдонима на "}. +{"Nickname ~s does not exist in the room","Псевдоним ~s в комнате отсутствует"}. +{"Nickname","Псевдоним"}. +{"No body provided for announce message","Тело объявления не должно быть пустым"}. +{"No Data","Нет данных"}. +{"Node ID","ID узла"}. +{"Node not found","Узел не найден"}. +{"Nodes","Узлы"}. +{"Node ","Узел "}. +{"No limit","Не ограничено"}. +{"None","Нет"}. +{"No resource provided","Не указан ресурс"}. +{"Notify subscribers when items are removed from the node","Уведомлять подписчиков об удалении публикаций из сборника"}. +{"Notify subscribers when the node configuration changes","Уведомлять подписчиков об изменении конфигурации сборника"}. +{"Notify subscribers when the node is deleted","Уведомлять подписчиков об удалении сборника"}. +{"November","ноября"}. +{"Number of occupants","Число присутствующих"}. +{"Number of online users","Количество подключённых пользователей"}. +{"Number of registered users","Количество зарегистрированных пользователей"}. +{"October","октября"}. +{"Offline Messages:","Офлайновые сообщения:"}. +{"Offline Messages","Офлайновые сообщения"}. +{"OK","Продолжить"}. +{"Online Users:","Подключённые пользователи:"}. +{"Online Users","Подключённые пользователи"}. +{"Online","Подключён"}. +{"Only deliver notifications to available users","Доставлять уведомления только доступным пользователям"}. +{"Only moderators and participants are allowed to change subject in this room","Только модераторы и участники могут изменять тему в этой комнате"}. +{"Only moderators are allowed to change subject in this room","Только модераторы могут изменять тему в этой комнате"}. +{"Only occupants are allowed to send messages to the conference","Только присутствующим разрешается посылать сообщения в конференцию"}. +{"Only occupants are allowed to send queries to the conference","Только присутствующим разрешается посылать запросы в конференцию"}. +{"Only service administrators are allowed to send service messages","Только администратор службы может посылать служебные сообщения"}. +{"Options","Параметры"}. +{"Organization Name","Название организации"}. +{"Organization Unit","Отдел организации"}. +{"Outgoing s2s Connections:","Исходящие s2s-серверы:"}. +{"Outgoing s2s Connections","Исходящие s2s-соединения"}. +{"Outgoing s2s Servers:","Исходящие s2s-серверы:"}. +{"Owner privileges required","Требуются права владельца"}. +{"Packet","Пакет"}. +{"Password required to enter this room","Чтобы войти в эту конференцию, нужен пароль"}. +{"Password Verification","Проверка пароля"}. +{"Password:","Пароль:"}. +{"Password","Пароль"}. +{"Path to Dir","Путь к директории"}. +{"Path to File","Путь к файлу"}. +{"Pending","Ожидание"}. +{"Period: ","Период"}. +{"Persist items to storage","Сохранять публикации в хранилище"}. +{"Ping","Пинг"}. +{"Pong","Понг"}. +{"Port","Порт"}. +{"Present real JIDs to","Сделать реальные JID участников видимыми"}. +{"private, ","приватная, "}. +{"Publish-Subscribe","Публикация-Подписка"}. +{"PubSub subscriber request","Запрос подписчика PubSub"}. +{"Queries to the conference members are not allowed in this room","Запросы к пользователям в этой конференции запрещены"}. +{"RAM and disc copy","ОЗУ и диск"}. +{"RAM copy","ОЗУ"}. +{"(Raw)","(Необработанный формат)"}. +{"Raw","Необработанный формат"}. +{"Really delete message of the day?","Действительно удалить сообщение дня?"}. +{"Recipient is not in the conference room","Адресата нет в конференции"}. +{"Registered Users:","Зарегистрированные пользователи:"}. +{"Registered Users","Зарегистрированные пользователи"}. +{"Registration in mod_irc for ","Регистрация в mod_irc для "}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Заметьте, что здесь производится резервное копирование только встроенной базы данных Mnesia. Если Вы также используете другое хранилище данных (например с помощью модуля ODBC), то его резервное копирование следует осуществлять отдельно."}. +{"Remote copy","не хранится локально"}. +{"Remove User","Удалить пользователя"}. +{"Remove","Удалить"}. +{"Replaced by new connection","Заменено новым соединением"}. +{"Resources","Ресурсы"}. +{"Restart Service","Перезапустить службу"}. +{"Restart","Перезапустить"}. +{"Restore Backup from File at ","Восстановление из резервной копии на "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Восстановить из бинарной резервной копии при следующем запуске (требует меньше памяти):"}. +{"Restore binary backup immediately:","Восстановить из бинарной резервной копии немедленно:"}. +{"Restore plain text backup immediately:","Восстановить из текстовой резервной копии немедленно:"}. +{"Restore","Восстановление из резервной копии"}. +{"Room Configuration","Конфигурация комнаты"}. +{"Room creation is denied by service policy","Cоздавать конференцию запрещено политикой службы"}. +{"Room title","Название комнаты"}. +{"Roster groups allowed to subscribe","Группы списка контактов, которым разрешена подписка"}. +{"Roster of ","Ростер пользователя "}. +{"Roster size","Размер списка контактов"}. +{"Roster","Ростер"}. +{"RPC Call Error","Ошибка вызова RPC"}. +{"Running Nodes","Работающие узлы"}. +{"~s access rule configuration","Конфигурация правила доступа ~s"}. +{"Saturday","Суббота"}. +{"Script check","Проверка сценария"}. +{"Search Results for ","Результаты поиска в "}. +{"Search users in ","Поиск пользователей в "}. +{"Send announcement to all online users on all hosts","Разослать объявление всем подключённым пользователям на всех виртуальных серверах"}. +{"Send announcement to all online users","Разослать объявление всем подключённым пользователям"}. +{"Send announcement to all users on all hosts","Разослать объявление всем пользователям на всех виртуальных серверах"}. +{"Send announcement to all users","Разослать объявление всем пользователям"}. +{"September","сентября"}. +{"Set message of the day and send to online users","Установить сообщение дня и разослать его подключённым пользователям"}. +{"Set message of the day on all hosts and send to online users","Установить сообщение дня на всех виртуальных серверах и разослать его подключённым пользователям"}. +{"Shared Roster Groups","Группы общих контактов"}. +{"Show Integral Table","Показать интегральную таблицу"}. +{"Show Ordinary Table","Показать обычную таблицу"}. +{"Shut Down Service","Остановить службу"}. +{"~s invites you to the room ~s","~s приглашает вас в комнату ~s"}. +{"Size","Размер"}. +{"Specified nickname is already registered","Указанный псевдоним уже зарегистрирован"}. +{"Specify the access model","Укажите механизм управления доступом"}. +{"Specify the publisher model","Условия публикации"}. +{"~s's Offline Messages Queue","Oчередь офлайновых сообщений ~s"}. +{"Start Modules at ","Запуск модулей на "}. +{"Start Modules","Запуск модулей"}. +{"Start","Запустить"}. +{"Statistics of ~p","статистика узла ~p"}. +{"Statistics","Статистика"}. +{"Stop Modules at ","Остановка модулей на "}. +{"Stop Modules","Остановка модулей"}. +{"Stopped Nodes","Остановленные узлы"}. +{"Stop","Остановить"}. +{"Storage Type","Тип таблицы"}. +{"Store binary backup:","Сохранить бинарную резервную копию:"}. +{"Store plain text backup:","Сохранить текстовую резервную копию:"}. +{"Subject","Тема"}. +{"Submitted","Отправлено"}. +{"Submit","Отправить"}. +{"Subscriber Address","Адрес подписчика"}. +{"Subscription","Подписка"}. +{"Sunday","Воскресенье"}. +{"the password is","пароль:"}. +{"This participant is kicked from the room because he sent an error message to another participant","Этого участника выгнали из комнаты за то, что он послал сообщение об ошибке другому участнику"}. +{"This participant is kicked from the room because he sent an error message","Этого участника выгнали из комнаты за то, что он послал сообщение об ошибке"}. +{"This participant is kicked from the room because he sent an error presence","Этого участника выгнали из комнаты за то, что он послал присутствие с ошибкой"}. +{"This room is not anonymous","Эта комната не анонимная"}. +{"Thursday","Четверг"}. +{"Time delay","По истечение"}. +{"Time","Время"}. +{"To ~s","К ~s"}. +{"To","Кому"}. +{"Traffic rate limit is exceeded","Превышен лимит скорости посылки информации"}. +{"Transactions Aborted:","Транзакции отмененные:"}. +{"Transactions Commited:","Транзакции завершенные:"}. +{"Transactions Logged:","Транзакции запротоколированные:"}. +{"Transactions Restarted:","Транзакции перезапущенные:"}. +{"Tuesday","Вторник"}. +{"Updated modules","Обновлённые модули"}. +{"Update message of the day (don't send)","Обновить сообщение дня (не рассылать)"}. +{"Update message of the day on all hosts (don't send)","Обновить сообщение дня на всех виртуальных серверах (не рассылать)"}. +{"Update plan","План обновления"}. +{"Update script","Сценарий обновления"}. +{"Update","Обновить"}. +{"Update ","Обновление "}. +{"Uptime:","Время работы:"}. +{"Use of STARTTLS required","Вы обязаны использовать STARTTLS"}. +{"User Management","Управление пользователями"}. +{"Users are not allowed to register accounts so fast","Пользователи не могут регистрировать учётные записи так быстро"}. +{"Users Last Activity","Статистика последнего подключения пользователей"}. +{"Users","Пользователи"}. +{"User ","Пользователь "}. +{"User","Пользователь"}. +{"Validate","Утвердить"}. +{"vCard User Search","Поиск пользователей по vCard"}. +{"Virtual Hosts","Виртуальные хосты"}. +{"Visitors are not allowed to change their nicknames in this room","Посетителям запрещено изменять свои псевдонимы в этой комнате"}. +{"Visitors are not allowed to send messages to all occupants","Посетителям не разрешается посылать сообщения всем присутствующим"}. +{"Wednesday","Среда"}. +{"When to send the last published item","Когда посылать последний опубликованный элемент"}. +{"Whether to allow subscriptions","Разрешить подписку"}. +{"You have been banned from this room","Вам запрещено входить в эту конференцию"}. +{"You must fill in field \"Nickname\" in the form","Вы должны заполнить поле \"Псевдоним\" в форме"}. +{"You need an x:data capable client to configure mod_irc settings","Чтобы настроить параметры mod_irc, требуется x:data-совместимый клиент"}. +{"You need an x:data capable client to configure room","Чтобы сконфигурировать комнату, требуется x:data-совместимый клиент"}. +{"You need an x:data capable client to register nickname","Чтобы зарегистрировать псевдоним, требуется x:data-совместимый клиент"}. +{"You need an x:data capable client to search","Чтобы воспользоваться поиском, требуется x:data-совместимый клиент"}. +{"Your contact offline message queue is full. The message has been discarded.","Очередь недоставленных сообщений Вашего адресата переполнена. Сообщение не было сохранено."}. diff --git a/src/msgs/ru.po b/src/msgs/ru.po new file mode 100644 index 000000000..347eafa40 --- /dev/null +++ b/src/msgs/ru.po @@ -0,0 +1,1496 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Evgeniy Khramtsov\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Russian (русский)\n" +"X-Additional-Translator: Konstantin Khomoutov\n" +"X-Additional-Translator: Sergei Golovan\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "Вы обязаны использовать STARTTLS" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Не указан ресурс" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Заменено новым соединением" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Команды" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Пинг" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Понг" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Действительно удалить сообщение дня?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Тема" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Тело сообщения" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "Тело объявления не должно быть пустым" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Объявления" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Разослать объявление всем пользователям" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Разослать объявление всем пользователям на всех виртуальных серверах" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Разослать объявление всем подключённым пользователям" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "" +"Разослать объявление всем подключённым пользователям на всех виртуальных " +"серверах" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Установить сообщение дня и разослать его подключённым пользователям" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Установить сообщение дня на всех виртуальных серверах и разослать его " +"подключённым пользователям" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Обновить сообщение дня (не рассылать)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Обновить сообщение дня на всех виртуальных серверах (не рассылать)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Удалить сообщение дня" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Удалить сообщение дня со всех виртуальных серверов" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Конфигурация" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "База данных" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Запуск модулей" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Остановка модулей" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Резервное копирование" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Восстановление из резервной копии" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Копирование в текстовый файл" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Импорт из файла" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Импорт из директории" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Перезапустить службу" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Остановить службу" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Добавить пользователя" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Удалить пользователя" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Завершить сеанс пользователя" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Получить пароль пользователя" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Изменить пароль пользователя" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Получить время последнего подключения пользователя" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Получить статистику по пользователю" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Получить количество зарегистрированных пользователей" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Получить количество подключённых пользователей" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Списки управления доступом" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Правила доступа" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Управление пользователями" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Подключённые пользователи" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Все пользователи" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Исходящие s2s-соединения" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Работающие узлы" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Остановленные узлы" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Модули" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Управление резервным копированием" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Импорт пользователей из спула jabberd 1.4" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "К ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "От ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Конфигурация таблиц базы данных на " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Выберите тип хранения таблиц" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "только диск" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "ОЗУ и диск" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "ОЗУ" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "не хранится локально" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Остановка модулей на " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Выберите модули, которые следует остановить" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Запуск модулей на " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Введите список вида {Module, [Options]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Список запускаемых модулей" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Резервное копирование в файл на " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Введите путь к резервному файлу" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Путь к файлу" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Восстановление из резервной копии на " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Копирование в текстовый файл на " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Введите путь к текстовому файлу" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Импорт пользователя из файла на " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Введите путь к файлу из спула jabberd1.4" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Импорт пользователей из директории на " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Введите путь к директории спула jabberd1.4" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Путь к директории" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "По истечение" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Конфигурация списков управления доступом" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Списки управления доступом" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Конфигурация доступа" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Правила доступа" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Пароль" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Проверка пароля" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Количество зарегистрированных пользователей" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Количество подключённых пользователей" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Никогда" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Подключён" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Время последнего подключения" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Размер списка контактов" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "IP адреса" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Ресурсы" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Администрирование " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Действие над пользователем" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Изменить параметры" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Удалить пользователя" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Доступ запрещён политикой службы" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "IRC Транспорт" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "ejabberd IRC модуль" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "Чтобы настроить параметры mod_irc, требуется x:data-совместимый клиент" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Регистрация в mod_irc для " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Введите имя пользователя и кодировки, которые будут использоваться при " +"подключении к IRC-серверам" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "Имя пользователя IRC" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Чтобы указать различные кодировки для разных серверов IRC, заполните список " +"значениями в формате '{\"irc server\", \"encoding\"}'. По умолчанию эта " +"служба использует кодировку \"~s\"." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Примеры: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Кодировки" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "Только администратор службы может посылать служебные сообщения" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "Cоздавать конференцию запрещено политикой службы" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "Конференция не существует" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Комнаты" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "Чтобы зарегистрировать псевдоним, требуется x:data-совместимый клиент" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Регистрация псевдонима на " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Введите псевдоним, который Вы хотели бы зарегистрировать" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Псевдоним" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "Указанный псевдоним уже зарегистрирован" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Вы должны заполнить поле \"Псевдоним\" в форме" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "ejabberd MUC модуль" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Конфигурация комнаты изменилась" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "вошёл(а) в комнату" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "вышел(а) из комнаты" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "запретили входить в комнату" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "выгнали из комнаты" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "выгнали из комнаты вследствие смены ранга" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "выгнали из комнаты потому что она стала только для членов" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "выгнали из комнаты из-за останова системы" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "изменил(а) имя на" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " установил(а) тему: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "Понедельник" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "Вторник" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "Среда" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "Четверг" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "Пятница" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "Суббота" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "Воскресенье" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "января" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "февраля" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "марта" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "апреля" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "мая" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "июня" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "июля" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "августа" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "сентября" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "октября" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "ноября" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "декабря" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Конфигурация комнаты" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Название комнаты" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Превышен лимит скорости посылки информации" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" +"Этого участника выгнали из комнаты за то, что он послал сообщение об ошибке" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Не разрешается посылать частные сообщения прямо в конференцию" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Неправильный тип сообщения" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Этого участника выгнали из комнаты за то, что он послал сообщение об ошибке " +"другому участнику" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "Нельзя посылать частные сообщения типа \"groupchat\"" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "Адресата нет в конференции" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Только присутствующим разрешается посылать сообщения в конференцию" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "Запрещено посылать приватные сообщения" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Только присутствующим разрешается посылать запросы в конференцию" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "Запросы к пользователям в этой конференции запрещены" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "приватная, " + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "Только модераторы и участники могут изменять тему в этой комнате" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Только модераторы могут изменять тему в этой комнате" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "Посетителям не разрешается посылать сообщения всем присутствующим" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" +"Этого участника выгнали из комнаты за то, что он послал присутствие с ошибкой" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Посетителям запрещено изменять свои псевдонимы в этой комнате" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "Псевдоним занят кем-то из присутствующих" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "Псевдоним зарегистирован кем-то другим" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Вам запрещено входить в эту конференцию" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "В эту конференцию могут входить только её члены" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Эта комната не анонимная" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Чтобы войти в эту конференцию, нужен пароль" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Неправильный пароль" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Требуются права администратора" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Требуются права модератора" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "JID ~s недопустимый" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "Псевдоним ~s в комнате отсутствует" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Недопустимый ранг: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Недопустимая роль: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Требуются права владельца" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Конфигурация " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Описание:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Сделать комнату постоянной" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Сделать комнату видимой всем" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Сделать список участников видимым всем" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Сделать комнату защищённой паролем" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Максимальное количество участников" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Не ограничено" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Сделать реальные JID участников видимыми" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "только модераторам" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "всем участникам" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Комната только для зарегистрированных участников" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Сделать комнату модерируемой" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Сделать пользователей участниками по умолчанию" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Разрешить пользователям изменять тему" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Разрешить приватные сообщения" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Разрешить iq-запросы к пользователям" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Разрешить пользователям посылать приглашения" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "" +"Разрешить посетителям вставлять текcт статуса в сообщения о присутствии" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Разрешить посетителям изменять псевдоним" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Включить журналирование" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "Чтобы сконфигурировать комнату, требуется x:data-совместимый клиент" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Число присутствующих" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s приглашает вас в комнату ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "пароль:" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "" +"Очередь недоставленных сообщений Вашего адресата переполнена. Сообщение не " +"было сохранено." + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "Oчередь офлайновых сообщений ~s" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Отправлено" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Время" + +#: mod_offline.erl:507 +msgid "From" +msgstr "От кого" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Кому" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Пакет" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Удалить выделенные" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Офлайновые сообщения:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "ejabberd SOCKS5 Bytestreams модуль" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Публикация-Подписка" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "Модуль ejabberd Публикации-Подписки" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "Запрос подписчика PubSub" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Решите: предоставить ли подписку этому объекту." + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "ID узла" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Адрес подписчика" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Разрешить этому JID подписаться на данный узел?" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Доставлять вместе с уведомлениями o публикациях сами публикации" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Доставлять уведомления о событиях" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Уведомлять подписчиков об изменении конфигурации сборника" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Уведомлять подписчиков об удалении сборника" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Уведомлять подписчиков об удалении публикаций из сборника" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Сохранять публикации в хранилище" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "Легко запоминаемое имя для узла" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Максимальное число сохраняемых публикаций" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Разрешить подписку" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Укажите механизм управления доступом" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Группы списка контактов, которым разрешена подписка" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Условия публикации" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Максимальный размер полезной нагрузки в байтах" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Когда посылать последний опубликованный элемент" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Доставлять уведомления только доступным пользователям" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "Выберите имя пользователя и пароль для регистрации на этом сервере" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "Пользователи не могут регистрировать учётные записи так быстро" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Нет" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Подписка" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Ожидание" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Группы" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Утвердить" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Удалить" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Ростер пользователя " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Неправильный формат" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Добавить Jabber ID" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Ростер" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Группы общих контактов" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Добавить" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Название:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Описание:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Члены:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Видимые группы:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Группа " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Отправить" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Erlang Jabber Server" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "День рождения" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Город" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "Страна" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "Электронная почта" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Фамилия" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Заполните форму для поиска пользователя Jabber (Если добавить * в конец " +"поля, то происходит поиск подстроки)" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Полное имя" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Отчество" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Название" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Название организации" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Отдел организации" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Поиск пользователей в " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Пользователь" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "Чтобы воспользоваться поиском, требуется x:data-совместимый клиент" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "Поиск пользователей по vCard" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "ejabberd vCard модуль" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Результаты поиска в " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Заполните форму для поиска пользователя Jabber" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "Web-интерфейс администрирования ejabberd" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Администрирование" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Виртуальные хосты" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Узлы" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Статистика" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Пользователи" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Последнее подключение" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Необработанный формат)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Необработанный формат" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "Конфигурация правила доступа ~s" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "Виртуальные хосты ejabberd" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Статистика последнего подключения пользователей" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Период" + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "За последний месяц" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "За последний год" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Вся статистика" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Показать обычную таблицу" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Показать интегральную таблицу" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Узел не найден" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Хост" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Зарегистрированные пользователи" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Офлайновые сообщения" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Зарегистрированные пользователи:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Подключённые пользователи:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Исходящие s2s-серверы:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Исходящие s2s-серверы:" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Сменить пароль" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Пользователь " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Подключённые ресурсы:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Пароль:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Нет данных" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Узел " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Прослушиваемые порты" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Обновить" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Перезапустить" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Остановить" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "Ошибка вызова RPC" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Таблицы базы данных на " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Тип таблицы" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Размер" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Память" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Резервное копирование " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Заметьте, что здесь производится резервное копирование только встроенной " +"базы данных Mnesia. Если Вы также используете другое хранилище данных " +"(например с помощью модуля ODBC), то его резервное копирование следует " +"осуществлять отдельно." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Сохранить бинарную резервную копию:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "Продолжить" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Восстановить из бинарной резервной копии немедленно:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"Восстановить из бинарной резервной копии при следующем запуске (требует " +"меньше памяти):" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Сохранить текстовую резервную копию:" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Восстановить из текстовой резервной копии немедленно:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Прослушиваемые порты на " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Модули на " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "статистика узла ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Время работы:" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "Процессорное время:" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Транзакции завершенные:" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Транзакции отмененные:" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Транзакции перезапущенные:" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Транзакции запротоколированные:" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Обновление " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "План обновления" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Обновлённые модули" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Сценарий обновления" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Низкоуровневый сценарий обновления" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Проверка сценария" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Порт" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Модуль" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Параметры" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Удалить" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Запустить" diff --git a/src/msgs/sk.msg b/src/msgs/sk.msg index ef61d300b..25b1f9b03 100644 --- a/src/msgs/sk.msg +++ b/src/msgs/sk.msg @@ -1,420 +1,343 @@ -% $Id$ -% Language: Slovak (slovenčina) -% Author: Juraj Michalek -% Author: SkLUG - -% jlib.hrl -{"No resource provided", "Nebol poskytnutý žiadny zdroj"}. - -% mod_configure.erl -{"Choose storage type of tables", "Vyberte typ úložiska pre tabuľky"}. -{"RAM copy", "Kópia RAM"}. -{"RAM and disc copy", "Kópia RAM a disku"}. -{"Disc only copy", "Len kópia disku"}. -{"Remote copy", "Vzdialená kópia"}. -{"Stop Modules at ", "Zastaviť moduly na "}. -{"Choose modules to stop", "Vyberte moduly, ktoré majú byť zastavené"}. -{"Start Modules at ", "Spustiť moduly na "}. -{"Enter list of {Module, [Options]}", "Vložte zoznam modulov {Modul, [Parametre]}"}. -{"List of modules to start", "Zoznam modulov, ktoré majú byť spustené"}. -{"Backup to File at ", "Záloha do súboru na "}. -{"Enter path to backup file", "Zadajte cestu k súboru so zálohou"}. -{"Path to File", "Cesta k súboru"}. -{"Restore Backup from File at ", "Obnoviť zálohu zo súboru na "}. -{"Dump Backup to Text File at ", "Uložiť zálohu do textového súboru na "}. -{"Enter path to text file", "Zadajte cestu k textovému súboru"}. -{"Import User from File at ", "Importovať používateľa zo súboru na "}. -{"Enter path to jabberd1.4 spool file", "Zadajte cestu k spool súboru jabberd1.4"}. -{"Import Users from Dir at ", "Importovať používateľov z adresára na "}. -{"Enter path to jabberd1.4 spool dir", "Zadajte cestu k jabberd1.4 spool adresáru"}. -{"Path to Dir", "Cesta k adresáru"}. -{"Hostname Configuration", "Konfigurácia mena servera"}. -{"Choose host name", "Vyberte meno servera"}. -{"Host name", "Host name"}. -{"Access Control List Configuration", "Konfigurácia zoznamu prístupových oprávnení (ACL)"}. -{"Access control lists", "Zoznamy prístupových oprávnení (ACL)"}. -{"Access Configuration", "Konfigurácia prístupu"}. -{"Access rules", "Prístupové pravidlá"}. -{"Remove Users", "Odstrániť používateľov"}. -{"Choose users to remove", "Zvoliť používateľov, ktorí budú odstránení"}. -{"Administration of ", "Administrácia "}. -{"Action on user", "Operácia aplikovaná na používateľa"}. -{"Edit Properties", "Editovať vlastnosti"}. -{"Remove User", "Odstrániť používateľa"}. -{"DB Tables Configuration at ", "Databázové tabuľky s konfiguráciou na "}. -{"Database", "Databáza"}. -{"Outgoing s2s Connections", "Odchdazájuce s2s spojenie"}. -{"Import Users From jabberd 1.4 Spool Files", "Importovať používateľov z jabber 1.4 spool súborov"}. -{"Database Tables Configuration at ", "Konfigurácia databázových tabuliek "}. - -% mod_disco.erl -{"Configuration", "Konfigurácia"}. -{"Online Users", "Online používatelia"}. -{"All Users", "Všetci používatelia"}. -{"Outgoing S2S connections", "Odchádzajúce spojenie S2S"}. -{"To ~s", "Pre ~s"}. -{"From ~s", "Od ~s"}. -{"Running Nodes", "Bežiace uzly"}. -{"Stopped Nodes", "Zastavené uzly"}. -{"Host Name", "Host name"}. -{"Access Control Lists", "Zoznamy prístupových oprávnení (ACL)"}. -{"Access Rules", "Prístupové pravidlá"}. -{"Remove Users", "Odstrániť používateľov"}. -{"DB", "DB"}. -{"Modules", "Moduly"}. -{"Start Modules", "Spustiť moduly"}. -{"Stop Modules", "Zastaviť moduly"}. -{"Backup Management", "Správa zálohovania"}. -{"Import users from jabberd1.4 spool files", "Importovať používateľov z jabberd1.4 spool súborov"}. -{"Backup", "Zálohovať"}. -{"Restore", "Obnoviť"}. -{"Dump to Text File", "Uložiť do textového súboru"}. -{"Import File", "Import súboru"}. -{"Import Directory", "Import adresára"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Vybrať meno používateľa a heslo pre registráciu na tomto serveri"}. - -% mod_vcard.erl -{"You need an x:data capable client to search", "Na vyhľadávanie potrebujete klienta podporujúceho x:data"}. -{"Search users in ", "Hľadať používateľov v "}. -{"Fill in fields to search for any matching Jabber User", "Vyplnte políčka pre vyhľadávanie Jabber používateľa"}. -{"Results of search in ", "Výsledky vyhľadávania v "}. -{"User", "Používateľ: "}. -{"Full Name", "Celé meno: "}. -{"Name", "Meno: "}. -{"Middle Name", "Prostredné meno: "}. -{"Family Name", "Priezvisko: "}. -{"Nickname", "Prezývka: "}. -{"Birthday", "Dátum narodenia: "}. -{"Country", "Krajina: "}. -{"City", "Mesto: "}. -{"email", "E-mail: "}. -{"Organization Name", "Meno organizácie: "}. -{"Organization Unit", "Organizačná jednotka: "}. - -% mod_muc/mod_muc.erl -{"You need an x:data capable client to register nickname", "Na registráciu prezývky potrebujete klienta podporujúceho z x:data"}. -{"Nickname Registration at ", "Registrácia prezývky na "}. -{"Enter nickname you want to register", "Zadajte prezývku, ktorú chete registrovať"}. -{"Only service administrators are allowed to send service messages", "Iba správcovia služby majú povolené odosielanie servisných správ"}. -{"Conference room does not exist", "Konferenčná miestnosť neexistuje"}. -{"Access denied by service policy", "Prístup bol zamiestnutý nastavení služby"}. -{"You must fill in field \"nick\" in the form", "Musíte vyplniť políčko \"prezývka\" vo formulári"}. -{"Specified nickname is already registered", "Zadaná prezývka je už registrovaná"}. -{"You must fill in field \"Nickname\" in the form", "Musíte vyplniť políčko \"Prezývka\" vo formulári"}. -{"ejabberd MUC module", "Ejabberd MUC modul"}. - -% mod_muc/mod_muc_room.erl -{"Make room moderated", "Nastaviť miestnosť ako moderovanú"}. -{"This room is not anonymous", "Táto miestnosť nie je anonymná"}. -{"Make room persistent", "Nastaviť miestnosť ako trvalú"}. -{"Make room public searchable", "Nastaviť miestnosť ako verejne prehľadávateľnú"}. -{"Make participants list public", "Nastaviť zoznam zúčastnených ako verejný"}. -{"Make room password protected", "Chrániť miestnosť heslom"}. -{"Make room semianonymous", "Nastaviť miestnosť ako čiastočne anonymnú"}. -{"Make room members-only", "Nastaviť miestnosť len pre členov"}. -{"Make room moderated", "Nastaviť miestnosť ako moderovanú"}. -{"Default users as participants", "Používatelia sú implicitne členmi"}. -{"Allow users to change subject", "Povoliť používateľom zmeniť tému tejto miestnosti"}. -{"Allow users to send private messages", "Povoliť používateľom odosielať súkromné správy"}. -{"Allow users to query other users", "Povoliť používateľom odosielať požiadavky (query) ostatným používateľom"}. -{"Allow users to send invites", "povoliť používateľom posielanie pozvánok"}. -{"Enable logging", "Zapnúť zaznamenávanie histórie"}. -{"Description", "Popis"}. -{"Number of occupants", "Počet zúčastnených"}. -{" has set the subject to: ", "zmiel(a) tému na: "}. -{"You need an x:data capable client to configure room", "Na konfiguráciu miestnosti potrebujete klienta podporujúceho x:data"}. -{"Configuration for ", "Konfigurácia pre "}. -{"Room title", "Názov miestnosti"}. -{"Allow users to change subject?", "Povoliť používateľom meniť tému?"}. -{"Allow users to query other users?", "Povoliť používateľom odosielať požiadavky (query) ostatným používateľom?"}. -{"Allow users to send private messages?", "Povoliť používateľom odosielať súkromné správy?"}. -{"Make room public searchable?", "Nastaviť miestnosť ako verejne prehľadávateľnú?"}. -{"Make participants list public?", "Nastaviť zoznam zúčastnených ako verejný?"}. -{"Make room persistent?", "Nastaviť miestnosť ako trvalú (persistent)?"}. -{"Make room moderated?", "Nastaviť miestnosť ako moderovanú?"}. -{"Default users as members?", "Používatelia sú implicitne členmi?"}. -{"Make room members only?", "Nastaviť miestnosť len pre členov?"}. -{"Allow users to send invites?", "Povoliť používateľom odosielať pozvánky?"}. -{"Make room password protected?", "Chrániť miestnosť heslom?"}. -{"Password", "Heslo"}. -{"Make room anonymous?", "Nastaviť miestnosť ako anonymnú?"}. -{"Enable logging?", "Zapnúť zaznamenávanie histórie?"}. -{"Only moderators and participants are allowed to change subject in this room", "Len moderátori a zúčastnený majú povolené meniť tému tejto miestnosti"}. -{"Only moderators are allowed to change subject in this room", "Len moderátori majú povolené meniť tému miestnosti"}. -{"Visitors are not allowed to send messages to all occupants", "Návštevníci nemajú povolené zasielať správy všetkým prihláseným do konferencie"}. -{"Only occupants are allowed to send messages to the conference", "Len členovia majú povolené zasielať správy do konferencie"}. -{"It is not allowed to send normal messages to the conference", "Nie je povolené odosielať normálne správy do konferencie"}. -{"It is not allowed to send private messages to the conference", "Nie je povolené odosielať súkromné správy do konferencie"}. -{"Improper message type", "Nesprávny typ správy"}. -{"Nickname is already in use by another occupant", "Prezývka je už používaná iným členom"}. -{"Nickname is registered by another person", "Prezývka je registrovaná inou osobou"}. -{"It is not allowed to send private messages of type \"groupchat\"", "Nie je dovolené odoslanie súkromnej správy typu \"Skupinová správa\" "}. -{"Recipient is not in the conference room", "Príjemca sa nenachádza v konferenčnej miestnosti"}. -{"Only occupants are allowed to send queries to the conference", "Len členovia majú povolené odosielať požiadavky (query) do konferencie"}. -{"Queries to the conference members are not allowed in this room", "Požiadavky (queries) na členov konferencie nie sú povolené v tejto miestnosti"}. -{"You have been banned from this room", "Boli ste vylúčený z tejto miestnosti"}. -{"Membership required to enter this room", "Pre vstup do miestnosti je potrebné byť členom"}. -{"Password required to enter this room", "Pre vstup do miestnosti je potrebné heslo"}. -{"Incorrect password", "Nesprávne heslo"}. -{"Administrator privileges required", "Sú potrebné práva administrátora"}. -{"Moderator privileges required", "Sú potrebné práva moderátora"}. -{"JID ~s is invalid", "JID ~s je neplatné"}. -{"Nickname ~s does not exist in the room", "Prezývka ~s v miestnosti neexistuje"}. -{"Invalid affiliation: ~s", "Neplatné priradenie: ~s"}. -{"Invalid role: ~s", "Neplatná rola: ~s"}. -{"Owner privileges required", "Sú vyžadované práva vlastníka"}. -{"private, ", "súkromná, "}. - -% mod_irc/mod_irc.erl -{"You need an x:data capable client to configure mod_irc settings", "Pre konfiguráciu mod_irc potrebujete klienta podporujúceho x:data"}. -{"Registration in mod_irc for ", "Registrácia do mod_irc na "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Vložte meno používateľa a kódovanie, ktoré chcete používať pri pripojení na IRC server"}. -{"IRC Username", "IRC prezývka"}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Príklad: [{\"irc.freenode.net\",\"utf-8\"}, {\"irc.freenode.net\", \"iso8859-2\"}]."}. -{"Encodings", "Kódovania"}. - -% web/ejabberd_web_admin.erl -{"ejabberd administration", "Administrácia Ejabberd"}. -{"Users", "Používatelia"}. -{"Nodes", "Uzly"}. -{"Statistics", "Štatistiky"}. -{"(raw)", "(raw)"}. -{"submitted", "odoslané"}. -{"bad format", "zlý formát"}. -{"raw", "raw"}. -{"ejabberd access control lists configuration", "Konfigurácia zoznamu prístupových oprávnení (ACL) Ejabberd"}. -{"Delete Selected", "Zmazať vybrané"}. -{"Submit", "Odoslať"}. -{"ejabberd access rules configuration", "Konfigurácia prístupových pravidiel Ejabberd"}. -{"~s access rule configuration", "~s konfigurácia prístupového pravidla"}. -{"ejabberd users", "Používatelia Ejabberd"}. -{"ejabberd stats", "Štatistiky Ejabberd"}. -{"Node not found", "Uzol nenájdený"}. -{"Add New", "Pridať nový"}. -{"Registered users", "Registrovaní používatelia"}. -{"Online users", "Online používatelia"}. -{"Outgoing S2S servers", "Servery S2S pre odchádzajúcu komunikáciu"}. -{"Change Password", "Zmeniť heslo"}. -{"Connected Resources:", "Pripojené zdroje:"}. -{"Password:", "Heslo:"}. -{"None", "Nič"}. -{"Node ", "Uzol "}. -{"DB Management", "Správa databázy"}. -{"Listened Ports Management", "Správa otvorených portov"}. -{"Restart", "Reštart"}. -{"Stop", "Stop"}. -{"RPC call error", "Chyba RPC volania"}. -{"DB Tables at ", "Databázové tabuľky na "}. -{"Name", "Meno"}. -{"Storage Type", "Typ úložiska"}. -{"Size", "Veľkosť"}. -{"Memory", "Pamäť"}. -{"Backup Management at ", "Správa záloh na "}. -{"Store a backup in a file", "Uložiť zálohu do súboru "}. -{"OK", "OK"}. -{"Restore a backup from a file", "Obnoviť zálohu zo súboru"}. -{"Install a database fallback from a file", "Inštalovať fallback pre databázu zo súboru"}. -{"Dump a database in a text file", "Uložiť databázu do textového súboru"}. -{"Restore a database from a text file", "Obnoviť databázu z textového súboru"}. -{"Listened Ports at ", "Otvorené porty na "}. -{"~p statistics", "~p štatistiky"}. -{"Uptime", "Uptime"}. -{"CPU Time", "Čas procesoru"}. -{"Transactions commited", "Transakcie potvrdená"}. -{"Transactions aborted", "Transakcie zrušená"}. -{"Transactions restarted", "Transakcie reštartovaná"}. -{"Transactions logged", "Transakcie zaznamenaná"}. -{"Port", "Port"}. -{"Module", "Modul"}. -{"Options", "Nastavenia"}. -{"Update", "Aktualizovať"}. -{"Delete", "Zmazať"}. -{"Add User", "Pridať používateľa"}. -{"Offline messages", "Offline správy"}. -{"Last Activity", "Posledná aktivita"}. -{"Never", "Nikdy"}. -{"~s offline messages queue", "~s offline správy"}. -{"Time", "Čas"}. -{"From", "Od"}. -{"To", "Pre"}. -{"Packet", "Paket"}. -{"Offline messages:", "Offline správy:"}. -{"Roster", "Zoznam kontaktov"}. -{"Nickname", "Prezývka"}. -{"Subscription", "Prihlásenie"}. -{"Pending", "Čakajúce"}. -{"Groups", "Skupiny"}. -{"Remove", "Odstrániť"}. -{"Add JID", "Pridať JID"}. -{"User ", "Používateľ "}. -{"Roster of ", "Zoznam kontaktov "}. -{"Shared Roster", "Zdieľaný zoznam kontaktov"}. -{"Online", "Online"}. -{"Validate", "Overiť"}. -{"Not found", "Nenájdené"}. -{"Shared roster groups", "Skupiny pre zdieľaný zoznam kontaktov"}. -{"Name:", "Meno:"}. -{"Description:", "Popis:"}. -{"Members:", "Členovia:"}. -{"Displayed Groups:", "Zobrazené skupiny:"}. -{"Group ", "Skupina "}. -{"Users last activity", "Posledná aktivita používateľa"}. -{"Period: ", "Čas:"}. -{"Last month", "Posledný mesiac"}. -{"Last year", "Posledný rok"}. -{"All activity", "Všetky aktivity"}. -{"Show Ordinary Table", "Zobraziť bežnú tabuľku"}. -{"Show Integral Table", "Zobraziť kompletnú tabuľku"}. -{"Start", "Štart"}. -{"Modules Management", "Správa modulov"}. -{"Modules at ", "Moduly na "}. -{"No data", "Žiadne dáta"}. -{"Virtual Hosts", "Virtuálne servery"}. -{"ejabberd virtual hosts", "Ejabberd virtuálne servery"}. -{"Host", "Server"}. -{"ejabberd Web Interface", "Ejabberd Web rozhranie"}. -{"(raw)", "(raw)"}. -{"raw", "raw"}. -{"Authenticated users", "Autentifikovaný používatelia"}. -{"ejabberd Web Interface", "Ejabberd Web rozhranie"}. -{"Administration", "Administrácia"}. -{"ejabberd (c) 2002-2008 Alexey Shchepin, 2004-2008 Process One", "Ejabberd (c) 2002-2008 Alexey Shchepin, 2004-2008 Process One"}. -{"(Raw)", "(Raw)"}. -{"Submitted", "Odoslané"}. -{"Bad format", "Zlý formát"}. -{"Raw", "Raw"}. -{"Users Last Activity", "Posledná aktivita používateľa"}. -{"Registered Users", "Registrovaní používatelia"}. -{"Offline Messages", "Offline správy"}. -{"Registered Users:", "Registrovaní používatelia:"}. -{"Authenticated Users:", "Autentifikovaný používatelia:"}. -{"Online Users:", "Online používatelia:"}. -{"Outgoing s2s Connections:", "Odchádzajúce s2s spojenia:"}. -{"Outgoing s2s Servers:", "Odchádzajúce s2s servery:"}. -{"Offline Messages:", "Offline správy"}. -{"~s's Offline Messages Queue", "~s Offline správy"}. -{"Add Jabber ID", "Pridať JID"}. -{"No Data", "Žiadne dáta"}. -{"Listened Ports", "Otvorené portov"}. -{"RPC Call Error", "Chyba RPC volania"}. -{"Database Tables at ", "Databázové tabuľky na "}. -{"Backup of ", "Záloha na "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "Podotýkame, že tieto nastavenia budú zálohované do zabudovanej Mnesia databázy. Ak používate ODBC modul, musíte zálohovať vašu SQL databázu separátne."}. -{"Store binary backup:", "Uložiť binárnu zálohu:"}. -{"Restore binary backup immediately:", "Okamžite obnoviť binárnu zálohu:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Obnoviť binárnu zálohu pri nasledujúcom reštarte Ejabberd (vyžaduje menej pamäte)"}. -{"Store plain text backup:", "Uložiť zálohu do textového súboru:"}. -{"Restore plain text backup immediately:", "Okamžite obnoviť zálohu z textového súboru:"}. -{"Statistics of ~p", "Štatistiky ~p"}. -{"Uptime:", "Uptime"}. -{"CPU Time:", "Čas procesoru"}. -{"Transactions Commited:", "Transakcie potvrdená"}. -{"Transactions Aborted:", "Transakcie zrušená"}. -{"Transactions Restarted:", "Transakcie reštartovaná"}. -{"Transactions Logged:", "Transakcie zaznamenaná"}. -{"Update ", "Aktualizovať "}. -{"Update plan", "Aktualizovať plán"}. -{"Updated modules", "Aktualizované moduly"}. -{"Update script", "Aktualizované skripty"}. -{"Low level update script", "Nízkoúrovňový aktualizačný skript"}. -{"Script check", "Kontrola skriptu"}. -{"Not Found", "Nenájdené"}. -{"Shared Roster Groups", "Skupiny pre zdieľaný zoznam kontaktov"}. - -% mod_vcard_odbc.erl -{"Erlang Jabber Server", "Erlang Jabber Server"}. -{"Email", "E-mail"}. -{"ejabberd vCard module", "Ejabberd vCard modul"}. -{"Search Results for ", "Hľadať výsledky pre "}. -{"Jabber ID", "Jabber ID"}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Pre vyhľadanie Jabber používateľa vyplňte formulár (pridajte znak * na koniec, pre vyhľadanie podreťazca)"}. -{"JID", "JID"}. - -% ejabberd_c2s.erl -{"Replaced by new connection", "Nahradené novým spojením"}. -{"Use of STARTTLS required", "Použitie STARTTLS je vyžadované"}. -{"Replaced by new connection", "Nahradené novým spojením"}. - -% mod_vcard_ldap.erl -{"Given Name", "Meno"}. - -% mod_pubsub/mod_pubsub.erl -{"ejabberd pub/sub module", "ejabberd pub/sub modul"}. -{"Node Creator", "Tvorca uzlu"}. -{"Deliver payloads with event notifications", "Doručovanie payload s upozorňovaním na udalosti"}. -{"Notify subscribers when the node configuration changes", "Upozorniť prihlásených používateľov na zmenu nastavenia uzlu"}. -{"Notify subscribers when the node is deleted", "Upozorniť prihlásených používateľov na zmazanie uzlu"}. -{"Notify subscribers when items are removed from the node", "Upozorniť prihlásených používateľov na odstránenie položiek z uzlu"}. -{"Persist items to storage", "Uložiť položky natrvalo do úložiska"}. -{"Max # of items to persist", "Maximálny počet položiek, ktoré je možné natrvalo uložiť"}. -{"Whether to allow subscriptions", "Povoliť prihlasovanie"}. -{"Specify the subscriber model", "Špecifikovať prihlasovací model"}. -{"Specify the publisher model", "Špecifikovať model publikovania"}. -{"Max payload size in bytes", "Maximálny payload v bajtoch"}. -{"Send items to new subscribers", "Odoslať položky novým používateľom"}. -{"Only deliver notifications to available users", "Doručovať upozornenia len aktuálne prihláseným používateľom"}. -{"Specify the current subscription approver", "Zadať súčasného schvaľovateľa prihlásení "}. - -% mod_irc/mod_irc.erl -{"ejabberd IRC module", "Ejabberd IRC module"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Ak chcete zadať iné kódovania pre IRC servery, vyplnte zoznam s hodnotami vo formáte '{\"irc server\",\"encoding\"}'. Predvolené kódovanie pre túto službu je \"~s\"."}. - -% mod_muc/mod_muc.erl -{"Room creation is denied by service policy", "Vytváranie miestnosti nie je povolené"}. -{"ejabberd MUC module", "Ejabberd MUC modul"}. - -% mod_adhoc.erl -{"Commands", "Príkazy"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% mod_announce.erl -{"Really delete message of the day?", "Skutočne zmazať správu dňa?"}. -{"Subject", "Predmet"}. -{"Message body", "Telo správy"}. -{"No body provided for announce message", "Správa neobsahuje text"}. -{"Announcements", "Oznámenia"}. -{"Send announcement to all users", "Odoslať oznam všetkým používateľom"}. -{"Send announcement to all online users", "Odoslať zoznam všetkým online používateľom"}. -{"Send announcement to all online users on all hosts", "Odoslať oznam všetkým online používateľom na všetkých serveroch"}. -{"Set message of the day and send to online users", "Nastaviť správu dňa a odoslať ju online používateľom"}. -{"Update message of the day (don't send)", "Aktualizovať správu dňa (neodosielať)"}. -{"Delete message of the day", "Zmazať správu dňa"}. - -% mod_irc/mod_irc.erl -{"ejabberd IRC module", "Ejabberd IRC modul"}. - -% mod_muc/mod_muc_log.erl -{"Chatroom configuration modified", "Nastavenie diskusnej miestnosti bolo zmenené"}. -{"joins the room", "vstúpil(a) do miestnosti"}. -{"leaves the room", "odišiel(a) z miestnosti"}. -{"has been kicked", "bol(a) vyhodený(á) z miestnosti"}. -{"has been banned", "bol(a) zablokovaný(á)"}. -{"is now known as", "sa premenoval(a) na"}. -{"Monday", "Pondelok"}. -{"Tuesday", "Utorok"}. -{"Wednesday", "Streda"}. -{"Thursday", "Štvrtok"}. -{"Friday", "Piatok"}. -{"Saturday", "Sobota"}. -{"Sunday", "Nedeľa"}. -{"January", "Január"}. -{"February", "Február"}. -{"March", "Marec"}. -{"April", "Apríl"}. -{"May", "Máj"}. -{"June", "Jún"}. -{"July", "Júl"}. -{"August", "August"}. -{"September", "September"}. -{"October", "Október"}. -{"November", "November"}. -{"December", "December"}. -{"Room Configuration", "Nastavenia miestnosti"}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Konfigurácia prístupu"}. +{"Access Control List Configuration","Konfigurácia zoznamu prístupových oprávnení (ACL)"}. +{"Access control lists","Zoznamy prístupových oprávnení (ACL)"}. +{"Access Control Lists","Zoznamy prístupových oprávnení (ACL)"}. +{"Access denied by service policy","Prístup bol zamietnutý nastavením služby"}. +{"Access rules","Prístupové pravidlá"}. +{"Access Rules","Prístupové pravidlá"}. +{"Action on user","Operácia aplikovaná na užívateľa"}. +{"Add Jabber ID","Pridať JID"}. +{"Add New","Pridať nový"}. +{"Add User","Pridať používateľa"}. +{"Administration","Administrácia"}. +{"Administration of ","Administrácia "}. +{"Administrator privileges required","Sú potrebné práva administrátora"}. +{"A friendly name for the node","Prístupný názov pre uzol"}. +{"All activity","Všetky aktivity"}. +{"Allow this JID to subscribe to this pubsub node?","Dovoliť tomuto JID odoberať PubSub uzol?"}. +{"Allow users to change subject","Povoliť užívateľom zmeniť tému tejto miestnosti"}. +{"Allow users to query other users","Povoliť užívateľom dotazovať sa informácie o iných užívateľoch"}. +{"Allow users to send invites","Povoliť používateľom posielanie pozvánok"}. +{"Allow users to send private messages","Povoliť užívateľom odosielať súkromné správy"}. +{"Allow visitors to change nickname","Návštevníci môžu meniť prezývky"}. +{"Allow visitors to send status text in presence updates","Návštevníci môžu posielať textové informácie v stavových správach"}. +{"All Users","Všetci užívatelia"}. +{"Announcements","Oznámenia"}. +{"anyone","všetkým"}. +{"April","Apríl"}. +{"August","August"}. +{"Backup Management","Správa zálohovania"}. +{"Backup of ","Záloha na "}. +{"Backup to File at ","Záloha do súboru na "}. +{"Backup","Zálohovať"}. +{"Bad format","Zlý formát"}. +{"Birthday","Dátum narodenia: "}. +{"Change Password","Zmeniť heslo"}. +{"Change User Password","Zmeniť heslo užívateľa"}. +{"Chatroom configuration modified","Nastavenie diskusnej miestnosti bolo zmenené"}. +{"Chatrooms","Diskusné miestnosti"}. +{"Choose a username and password to register with this server","Zvolte meno užívateľa a heslo pre registráciu na tomto servere"}. +{"Choose modules to stop","Vyberte moduly, ktoré majú byť zastavené"}. +{"Choose storage type of tables","Vyberte typ úložiska pre tabuľky"}. +{"Choose whether to approve this entity's subscription.","Zvolte, či chcete povoliť toto odoberanie"}. +{"City","Mesto: "}. +{"Commands","Príkazy"}. +{"Conference room does not exist","Diskusná miestnosť neexistuje"}. +{"Configuration for ","Konfigurácia pre "}. +{"Configuration","Konfigurácia"}. +{"Connected Resources:","Pripojené zdroje:"}. +{"Country","Krajina: "}. +{"CPU Time:","Čas procesoru"}. +{"Database","Databáza"}. +{"Database Tables at ","Databázové tabuľky na "}. +{"Database Tables Configuration at ","Konfigurácia databázových tabuliek "}. +{"December","December"}. +{"Default users as participants","Užívatelia sú implicitne členmi"}. +{"Delete message of the day on all hosts","Zmazať správu dňa na všetkých serveroch"}. +{"Delete message of the day","Zmazať správu dňa"}. +{"Delete Selected","Zmazať vybrané"}. +{"Delete User","Vymazať užívateľa"}. +{"Delete","Zmazať"}. +{"Deliver event notifications","Doručiť oznamy o udalosti"}. +{"Deliver payloads with event notifications","Doručiť náklad s upozornením na udalosť"}. +{"Description:","Popis:"}. +{"Disc only copy","Len kópia disku"}. +{"Displayed Groups:","Zobrazené skupiny:"}. +{"Dump Backup to Text File at ","Uložiť zálohu do textového súboru na "}. +{"Dump to Text File","Uložiť do textového súboru"}. +{"Edit Properties","Editovať vlastnosti"}. +{"ejabberd IRC module","ejabberd IRC modul"}. +{"ejabberd MUC module","ejabberd MUC modul"}. +{"ejabberd Publish-Subscribe module","ejabberd Publish-Subscribe modul"}. +{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestreams modul"}. +{"ejabberd vCard module","ejabberd vCard modul"}. +{"ejabberd virtual hosts","ejabberd virtuálne servery"}. +{"ejabberd Web Admin","ejabberd Web Admin"}. +{"Email","E-mail"}. +{"Enable logging","Zapnúť zaznamenávanie histórie"}. +{"Encodings","Kódovania"}. +{"End User Session","Ukončiť reláciu užívateľa"}. +{"Enter list of {Module, [Options]}","Vložte zoznam modulov {Modul, [Parametre]}"}. +{"Enter nickname you want to register","Zadajte prezývku, ktorú chcete registrovať"}. +{"Enter path to backup file","Zadajte cestu k súboru so zálohou"}. +{"Enter path to jabberd1.4 spool dir","Zadajte cestu k jabberd1.4 spool adresáru"}. +{"Enter path to jabberd1.4 spool file","Zadajte cestu k spool súboru jabberd1.4"}. +{"Enter path to text file","Zadajte cestu k textovému súboru"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Vložte meno používateľa a kódovanie, ktoré chcete používať pri pripojení na IRC server"}. +{"Erlang Jabber Server","Erlang Jabber Server"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Príklad: [{\"irc.freenode.net\",\"utf-8\"}, {\"irc.freenode.net\", \"iso8859-2\"}]."}. +{"Family Name","Priezvisko: "}. +{"February","Február"}. +{"Fill in fields to search for any matching Jabber User","Vyplnte políčka pre vyhľadávanie Jabber užívateľa"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Pre vyhľadanie Jabber používateľa vyplňte formulár (pridajte znak * na koniec, pre vyhľadanie podreťazca)"}. +{"Friday","Piatok"}. +{"From","Od"}. +{"From ~s","Od ~s"}. +{"Full Name","Celé meno: "}. +{"Get Number of Online Users","Zobraziť počet pripojených užívateľov"}. +{"Get Number of Registered Users","Zobraziť počet registrovaných užívateľov"}. +{"Get User Last Login Time","Zobraziť čas posledného prihlásenia"}. +{"Get User Password","Zobraziť heslo užívateľa"}. +{"Get User Statistics","Zobraziť štatistiku užívateľa"}. +{"Group ","Skupina "}. +{"Groups","Skupiny"}. +{"has been banned","bol(a) zablokovaný(á)"}. +{"has been kicked because of an affiliation change","bol vyhodený(á) kvôli zmene priradenia"}. +{"has been kicked because of a system shutdown","bol vyhodený(á) kvôli reštartu systému"}. +{"has been kicked because the room has been changed to members-only","bol vyhodený(á), pretože miestnosť bola vyhradená len pre členov"}. +{"has been kicked","bol(a) vyhodený(á) z miestnosti"}. +{" has set the subject to: ","zmenil(a) tému na: "}. +{"Host","Server"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Ak chcete zadať iné kódovania pre IRC servery, vyplnte zoznam s hodnotami vo formáte '{\"irc server\",\"encoding\"}'. Predvolené kódovanie pre túto službu je \"~s\"."}. +{"Import Directory","Import adresára"}. +{"Import File","Import súboru"}. +{"Import User from File at ","Importovať užívateľa zo súboru na "}. +{"Import Users from Dir at ","Importovať užívateľov z adresára na "}. +{"Import Users From jabberd 1.4 Spool Files","Importovať užívateľov z jabberd 1.4 spool súborov"}. +{"Improper message type","Nesprávny typ správy"}. +{"Incorrect password","Nesprávne heslo"}. +{"Invalid affiliation: ~s","Neplatné priradenie: ~s"}. +{"Invalid role: ~s","Neplatná rola: ~s"}. +{"IP addresses","IP adresa"}. +{"IRC Transport","IRC Transport"}. +{"IRC Username","IRC prezývka"}. +{"is now known as","sa premenoval(a) na"}. +{"It is not allowed to send private messages","Nieje povolené posielať súkromné správy"}. +{"It is not allowed to send private messages of type \"groupchat\"","Nie je dovolené odoslanie súkromnej správy typu \"Skupinová správa\" "}. +{"It is not allowed to send private messages to the conference","Nie je povolené odosielať súkromné správy do konferencie"}. +{"Jabber ID","Jabber ID"}. +{"January","Január"}. +{"JID ~s is invalid","JID ~s je neplatné"}. +{"joins the room","vstúpil(a) do miestnosti"}. +{"July","Júl"}. +{"June","Jún"}. +{"Last Activity","Posledná aktivita"}. +{"Last login","Posledné prihlásenie"}. +{"Last month","Posledný mesiac"}. +{"Last year","Posledný rok"}. +{"leaves the room","odišiel(a) z miestnosti"}. +{"Listened Ports at ","Otvorené porty na "}. +{"Listened Ports","Otvorené portov"}. +{"List of modules to start","Zoznam modulov, ktoré majú byť spustené"}. +{"Low level update script","Nízkoúrovňový aktualizačný skript"}. +{"Make participants list public","Nastaviť zoznam zúčastnených ako verejný"}. +{"Make room members-only","Nastaviť miestnosť len pre členov"}. +{"Make room moderated","Nastaviť miestnosť ako moderovanú"}. +{"Make room password protected","Chrániť miestnosť heslom"}. +{"Make room persistent","Nastaviť miestnosť ako trvalú"}. +{"Make room public searchable","Nastaviť miestnosť ako verejne prehľadávateľnú"}. +{"March","Marec"}. +{"Maximum Number of Occupants","Počet účastníkov"}. +{"Max # of items to persist","Maximálny počet položiek, ktoré je možné natrvalo uložiť"}. +{"Max payload size in bytes","Maximálny náklad v bajtoch"}. +{"May","Máj"}. +{"Members:","Členovia:"}. +{"Membership required to enter this room","Pre vstup do miestnosti je potrebné byť členom"}. +{"Memory","Pamäť"}. +{"Message body","Telo správy"}. +{"Middle Name","Prostredné meno: "}. +{"Moderator privileges required","Sú potrebné práva moderátora"}. +{"moderators only","moderátorom"}. +{"Module","Modul"}. +{"Modules at ","Moduly na "}. +{"Modules","Moduly"}. +{"Monday","Pondelok"}. +{"Name:","Meno:"}. +{"Name","Meno"}. +{"Never","Nikdy"}. +{"Nickname is already in use by another occupant","Prezývka je už používaná iným členom"}. +{"Nickname is registered by another person","Prezývka je registrovaná inou osobou"}. +{"Nickname","Prezývka"}. +{"Nickname Registration at ","Registrácia prezývky na "}. +{"Nickname ~s does not exist in the room","Prezývka ~s v miestnosti neexistuje"}. +{"No body provided for announce message","Správa neobsahuje text"}. +{"No Data","Žiadne dáta"}. +{"Node ID","ID uzlu"}. +{"Node not found","Uzol nenájdený"}. +{"Nodes","Uzly"}. +{"Node ","Uzol "}. +{"No limit","Bez limitu"}. +{"None","Nič"}. +{"No resource provided","Nebol poskytnutý žiadny zdroj"}. +{"Notify subscribers when items are removed from the node","Upozorniť prihlásených používateľov na odstránenie položiek z uzlu"}. +{"Notify subscribers when the node configuration changes","Upozorniť prihlásených používateľov na zmenu nastavenia uzlu"}. +{"Notify subscribers when the node is deleted","Upozorniť prihlásených používateľov na zmazanie uzlu"}. +{"November","November"}. +{"Number of occupants","Počet zúčastnených"}. +{"Number of online users","Počet online užívateľov"}. +{"Number of registered users","Počet registrovaných užívateľov"}. +{"October","Október"}. +{"Offline Messages:","Offline správy"}. +{"Offline Messages","Offline správy"}. +{"OK","OK"}. +{"Online","Online"}. +{"Online Users:","Online používatelia:"}. +{"Online Users","Online užívatelia"}. +{"Only deliver notifications to available users","Doručovať upozornenia len aktuálne prihláseným používateľom"}. +{"Only moderators and participants are allowed to change subject in this room","Len moderátori a zúčastnený majú povolené meniť tému tejto miestnosti"}. +{"Only moderators are allowed to change subject in this room","Len moderátori majú povolené meniť tému miestnosti"}. +{"Only occupants are allowed to send messages to the conference","Len členovia majú povolené zasielať správy do konferencie"}. +{"Only occupants are allowed to send queries to the conference","Len členovia majú povolené dotazovať sa o konferencii"}. +{"Only service administrators are allowed to send service messages","Iba správcovia služby majú povolené odosielanie servisných správ"}. +{"Options","Nastavenia"}. +{"Organization Name","Meno organizácie: "}. +{"Organization Unit","Organizačná jednotka: "}. +{"Outgoing s2s Connections:","Odchádzajúce s2s spojenia:"}. +{"Outgoing s2s Connections","Odchádzajúce s2s spojenia"}. +{"Outgoing s2s Servers:","Odchádzajúce s2s servery:"}. +{"Owner privileges required","Sú vyžadované práva vlastníka"}. +{"Packet","Paket"}. +{"Password:","Heslo:"}. +{"Password","Heslo"}. +{"Password required to enter this room","Pre vstup do miestnosti je potrebné heslo"}. +{"Password Verification","Overenie hesla"}. +{"Path to Dir","Cesta k adresáru"}. +{"Path to File","Cesta k súboru"}. +{"Pending","Čakajúce"}. +{"Period: ","Čas:"}. +{"Persist items to storage","Uložiť položky natrvalo do úložiska"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","Port"}. +{"Present real JIDs to","Zobrazovať skutočné JID"}. +{"private, ","súkromná, "}. +{"Publish-Subscribe","Publish-Subscribe"}. +{"PubSub subscriber request","Žiadosť odberateľa PubSub"}. +{"Queries to the conference members are not allowed in this room","Dotazovať sa o členoch nie je v tejto miestnosti povolené"}. +{"RAM and disc copy","Kópia RAM a disku"}. +{"RAM copy","Kópia RAM"}. +{"(Raw)","(Raw)"}. +{"Raw","Raw"}. +{"Really delete message of the day?","Skutočne zmazať správu dňa?"}. +{"Recipient is not in the conference room","Príjemca sa nenachádza v konferenčnej miestnosti"}. +{"Registered Users:","Registrovaní používatelia:"}. +{"Registered Users","Registrovaní používatelia"}. +{"Registration in mod_irc for ","Registrácia do mod_irc na "}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Podotýkame, že tieto nastavenia budú zálohované do zabudovanej Mnesia databázy. Ak používate ODBC modul, musíte zálohovať vašu SQL databázu separátne."}. +{"Remote copy","Vzdialená kópia"}. +{"Remove","Odstrániť"}. +{"Remove User","Odstrániť užívateľa"}. +{"Replaced by new connection","Nahradené novým spojením"}. +{"Resources","Zdroje"}. +{"Restart","Reštart"}. +{"Restart Service","Reštartovať službu"}. +{"Restore Backup from File at ","Obnoviť zálohu zo súboru na "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Obnoviť binárnu zálohu pri nasledujúcom reštarte ejabberd (vyžaduje menej pamäte)"}. +{"Restore binary backup immediately:","Okamžite obnoviť binárnu zálohu:"}. +{"Restore","Obnoviť"}. +{"Restore plain text backup immediately:","Okamžite obnoviť zálohu z textového súboru:"}. +{"Room Configuration","Nastavenia miestnosti"}. +{"Room creation is denied by service policy","Vytváranie miestnosti nie je povolené"}. +{"Room title","Názov miestnosti"}. +{"Roster groups allowed to subscribe","Skupiny kontaktov, ktoré môžu odoberať"}. +{"Roster of ","Zoznam kontaktov "}. +{"Roster size","Počet kontaktov v zozname"}. +{"Roster","Zoznam kontaktov"}. +{"RPC Call Error","Chyba RPC volania"}. +{"Running Nodes","Bežiace uzly"}. +{"~s access rule configuration","~s konfigurácia prístupového pravidla"}. +{"Saturday","Sobota"}. +{"Script check","Kontrola skriptu"}. +{"Search Results for ","Hľadať výsledky pre "}. +{"Search users in ","Hľadať užívateľov v "}. +{"Send announcement to all online users","Odoslať zoznam všetkým online používateľom"}. +{"Send announcement to all online users on all hosts","Odoslať oznam všetkým online používateľom na všetkých serveroch"}. +{"Send announcement to all users","Odoslať oznam všetkým používateľom"}. +{"Send announcement to all users on all hosts","Poslať oznámenie všetkým užívateľom na všetkých serveroch"}. +{"September","September"}. +{"Set message of the day and send to online users","Nastaviť správu dňa a odoslať ju online používateľom"}. +{"Set message of the day on all hosts and send to online users","Nastaviť správu dňa na všetkých serveroch a poslať ju online užívateľom"}. +{"Shared Roster Groups","Skupiny pre zdieľaný zoznam kontaktov"}. +{"Show Integral Table","Zobraziť kompletnú tabuľku"}. +{"Show Ordinary Table","Zobraziť bežnú tabuľku"}. +{"Shut Down Service","Vypnúť službu"}. +{"~s invites you to the room ~s","~s Vás pozýva do miestnosti ~s"}. +{"Size","Veľkosť"}. +{"Specified nickname is already registered","Zadaná prezývka je už registrovaná"}. +{"Specify the access model","Uveďte model prístupu"}. +{"Specify the publisher model","Špecifikovať model publikovania"}. +{"~s's Offline Messages Queue","~s Offline správy"}. +{"Start Modules at ","Spustiť moduly na "}. +{"Start Modules","Spustiť moduly"}. +{"Start","Štart"}. +{"Statistics of ~p","Štatistiky ~p"}. +{"Statistics","Štatistiky"}. +{"Stop Modules at ","Zastaviť moduly na "}. +{"Stop Modules","Zastaviť moduly"}. +{"Stopped Nodes","Zastavené uzly"}. +{"Stop","Stop"}. +{"Storage Type","Typ úložiska"}. +{"Store binary backup:","Uložiť binárnu zálohu:"}. +{"Store plain text backup:","Uložiť zálohu do textového súboru:"}. +{"Subject","Predmet"}. +{"Submit","Odoslať"}. +{"Submitted","Odoslané"}. +{"Subscriber Address","Adresa odberateľa"}. +{"Subscription","Prihlásenie"}. +{"Sunday","Nedeľa"}. +{"the password is","heslo je"}. +{"This participant is kicked from the room because he sent an error message to another participant","Účastník bol vyhodený z miestnosti, pretože poslal chybovú správu inému účastníkovi"}. +{"This participant is kicked from the room because he sent an error message","Účastník bol vyhodený z miestnosti, pretože poslal chybovú správu"}. +{"This participant is kicked from the room because he sent an error presence","Účastník bol vyhodený z miestnosti, pretože poslal chybovú správu o stave"}. +{"This room is not anonymous","Táto miestnosť nie je anonymná"}. +{"Thursday","Štvrtok"}. +{"Time","Čas"}. +{"Time delay","Časový posun"}. +{"To","Pre"}. +{"To ~s","Pre ~s"}. +{"Traffic rate limit is exceeded","Bol prekročený prenosový limit"}. +{"Transactions Aborted:","Transakcie zrušená"}. +{"Transactions Commited:","Transakcie potvrdená"}. +{"Transactions Logged:","Transakcie zaznamenaná"}. +{"Transactions Restarted:","Transakcie reštartovaná"}. +{"Tuesday","Utorok"}. +{"Update ","Aktualizovať "}. +{"Update","Aktualizovať"}. +{"Updated modules","Aktualizované moduly"}. +{"Update message of the day (don't send)","Aktualizovať správu dňa (neodosielať)"}. +{"Update message of the day on all hosts (don't send)","Upraviť správu dňa na všetkých serveroch"}. +{"Update plan","Aktualizovať plán"}. +{"Update script","Aktualizované skripty"}. +{"Uptime:","Uptime:"}. +{"Use of STARTTLS required","Použitie STARTTLS je vyžadované"}. +{"User Management","Správa užívateľov"}. +{"User ","Používateľ "}. +{"Users are not allowed to register accounts so fast","Nieje možné vytvárať účty tak rýchlo po sebe"}. +{"Users Last Activity","Posledná aktivita používateľa"}. +{"Users","Používatelia"}. +{"User","Užívateľ: "}. +{"Validate","Overiť"}. +{"vCard User Search","Hľadať užívateľov vo vCard"}. +{"Virtual Hosts","Virtuálne servery"}. +{"Visitors are not allowed to change their nicknames in this room","V tejto miestnosti nieje povolené meniť prezývky"}. +{"Visitors are not allowed to send messages to all occupants","Návštevníci nemajú povolené zasielať správy všetkým prihláseným do konferencie"}. +{"Wednesday","Streda"}. +{"When to send the last published item","Kedy odoslať posledne publikovanú položku"}. +{"Whether to allow subscriptions","Povoliť prihlasovanie"}. +{"You have been banned from this room","Boli ste vylúčený z tejto miestnosti"}. +{"You must fill in field \"Nickname\" in the form","Musíte vyplniť políčko \"Prezývka\" vo formulári"}. +{"You need an x:data capable client to configure mod_irc settings","Pre konfiguráciu mod_irc potrebujete klienta podporujúceho x:data"}. +{"You need an x:data capable client to configure room","Na konfiguráciu miestnosti potrebujete klienta podporujúceho x:data"}. +{"You need an x:data capable client to register nickname","Na registráciu prezývky potrebujete klienta podporujúceho z x:data"}. +{"You need an x:data capable client to search","Na vyhľadávanie potrebujete klienta podporujúceho x:data"}. +{"Your contact offline message queue is full. The message has been discarded.","Fronta offline správ tohoto kontaktu je plná. Správa bola zahodená."}. diff --git a/src/msgs/sk.po b/src/msgs/sk.po new file mode 100644 index 000000000..faa0edd18 --- /dev/null +++ b/src/msgs/sk.po @@ -0,0 +1,1493 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Marek Becka\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Slovak (slovenčina)\n" +"X-Additional-Translator: Juraj Michalek\n" +"X-Additional-Translator: SkLUG\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "Použitie STARTTLS je vyžadované" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Nebol poskytnutý žiadny zdroj" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Nahradené novým spojením" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Príkazy" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Skutočne zmazať správu dňa?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Predmet" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Telo správy" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "Správa neobsahuje text" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Oznámenia" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Odoslať oznam všetkým používateľom" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Poslať oznámenie všetkým užívateľom na všetkých serveroch" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Odoslať zoznam všetkým online používateľom" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "Odoslať oznam všetkým online používateľom na všetkých serveroch" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Nastaviť správu dňa a odoslať ju online používateľom" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Nastaviť správu dňa na všetkých serveroch a poslať ju online užívateľom" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Aktualizovať správu dňa (neodosielať)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Upraviť správu dňa na všetkých serveroch" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Zmazať správu dňa" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Zmazať správu dňa na všetkých serveroch" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Konfigurácia" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Databáza" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Spustiť moduly" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Zastaviť moduly" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Zálohovať" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Obnoviť" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Uložiť do textového súboru" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Import súboru" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Import adresára" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Reštartovať službu" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Vypnúť službu" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Pridať používateľa" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Vymazať užívateľa" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Ukončiť reláciu užívateľa" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Zobraziť heslo užívateľa" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Zmeniť heslo užívateľa" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Zobraziť čas posledného prihlásenia" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Zobraziť štatistiku užívateľa" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Zobraziť počet registrovaných užívateľov" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Zobraziť počet pripojených užívateľov" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Zoznamy prístupových oprávnení (ACL)" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Prístupové pravidlá" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Správa užívateľov" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Online užívatelia" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Všetci užívatelia" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Odchádzajúce s2s spojenia" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Bežiace uzly" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Zastavené uzly" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Moduly" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Správa zálohovania" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Importovať užívateľov z jabberd 1.4 spool súborov" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "Pre ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "Od ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Konfigurácia databázových tabuliek " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Vyberte typ úložiska pre tabuľky" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Len kópia disku" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "Kópia RAM a disku" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "Kópia RAM" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Vzdialená kópia" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Zastaviť moduly na " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Vyberte moduly, ktoré majú byť zastavené" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Spustiť moduly na " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Vložte zoznam modulov {Modul, [Parametre]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Zoznam modulov, ktoré majú byť spustené" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Záloha do súboru na " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Zadajte cestu k súboru so zálohou" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Cesta k súboru" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Obnoviť zálohu zo súboru na " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Uložiť zálohu do textového súboru na " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Zadajte cestu k textovému súboru" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Importovať užívateľa zo súboru na " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Zadajte cestu k spool súboru jabberd1.4" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Importovať užívateľov z adresára na " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Zadajte cestu k jabberd1.4 spool adresáru" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Cesta k adresáru" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Časový posun" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Konfigurácia zoznamu prístupových oprávnení (ACL)" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Zoznamy prístupových oprávnení (ACL)" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Konfigurácia prístupu" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Prístupové pravidlá" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Heslo" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Overenie hesla" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Počet registrovaných užívateľov" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Počet online užívateľov" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Nikdy" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Online" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Posledné prihlásenie" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Počet kontaktov v zozname" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "IP adresa" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Zdroje" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Administrácia " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Operácia aplikovaná na užívateľa" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Editovať vlastnosti" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Odstrániť užívateľa" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Prístup bol zamietnutý nastavením služby" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "IRC Transport" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "ejabberd IRC modul" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "Pre konfiguráciu mod_irc potrebujete klienta podporujúceho x:data" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Registrácia do mod_irc na " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Vložte meno používateľa a kódovanie, ktoré chcete používať pri pripojení na " +"IRC server" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "IRC prezývka" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Ak chcete zadať iné kódovania pre IRC servery, vyplnte zoznam s hodnotami vo " +"formáte '{\"irc server\",\"encoding\"}'. Predvolené kódovanie pre túto " +"službu je \"~s\"." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Príklad: [{\"irc.freenode.net\",\"utf-8\"}, {\"irc.freenode.net\", \"iso8859-" +"2\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Kódovania" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "Iba správcovia služby majú povolené odosielanie servisných správ" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "Vytváranie miestnosti nie je povolené" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "Diskusná miestnosť neexistuje" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Diskusné miestnosti" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "Na registráciu prezývky potrebujete klienta podporujúceho z x:data" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Registrácia prezývky na " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Zadajte prezývku, ktorú chcete registrovať" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Prezývka" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "Zadaná prezývka je už registrovaná" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Musíte vyplniť políčko \"Prezývka\" vo formulári" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "ejabberd MUC modul" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Nastavenie diskusnej miestnosti bolo zmenené" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "vstúpil(a) do miestnosti" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "odišiel(a) z miestnosti" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "bol(a) zablokovaný(á)" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "bol(a) vyhodený(á) z miestnosti" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "bol vyhodený(á) kvôli zmene priradenia" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "bol vyhodený(á), pretože miestnosť bola vyhradená len pre členov" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "bol vyhodený(á) kvôli reštartu systému" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "sa premenoval(a) na" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr "zmenil(a) tému na: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "Pondelok" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "Utorok" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "Streda" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "Štvrtok" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "Piatok" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "Sobota" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "Nedeľa" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "Január" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "Február" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "Marec" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "Apríl" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "Máj" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "Jún" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "Júl" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "August" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "September" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "Október" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "November" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "December" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Nastavenia miestnosti" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Názov miestnosti" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Bol prekročený prenosový limit" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "Účastník bol vyhodený z miestnosti, pretože poslal chybovú správu" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Nie je povolené odosielať súkromné správy do konferencie" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Nesprávny typ správy" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Účastník bol vyhodený z miestnosti, pretože poslal chybovú správu inému " +"účastníkovi" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "Nie je dovolené odoslanie súkromnej správy typu \"Skupinová správa\" " + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "Príjemca sa nenachádza v konferenčnej miestnosti" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Len členovia majú povolené zasielať správy do konferencie" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "Nieje povolené posielať súkromné správy" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Len členovia majú povolené dotazovať sa o konferencii" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "Dotazovať sa o členoch nie je v tejto miestnosti povolené" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "súkromná, " + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "Len moderátori a zúčastnený majú povolené meniť tému tejto miestnosti" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Len moderátori majú povolené meniť tému miestnosti" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "" +"Návštevníci nemajú povolené zasielať správy všetkým prihláseným do " +"konferencie" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" +"Účastník bol vyhodený z miestnosti, pretože poslal chybovú správu o stave" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "V tejto miestnosti nieje povolené meniť prezývky" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "Prezývka je už používaná iným členom" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "Prezývka je registrovaná inou osobou" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Boli ste vylúčený z tejto miestnosti" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "Pre vstup do miestnosti je potrebné byť členom" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Táto miestnosť nie je anonymná" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Pre vstup do miestnosti je potrebné heslo" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Nesprávne heslo" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Sú potrebné práva administrátora" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Sú potrebné práva moderátora" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "JID ~s je neplatné" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "Prezývka ~s v miestnosti neexistuje" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Neplatné priradenie: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Neplatná rola: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Sú vyžadované práva vlastníka" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Konfigurácia pre " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Popis:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Nastaviť miestnosť ako trvalú" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Nastaviť miestnosť ako verejne prehľadávateľnú" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Nastaviť zoznam zúčastnených ako verejný" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Chrániť miestnosť heslom" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Počet účastníkov" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Bez limitu" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Zobrazovať skutočné JID" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "moderátorom" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "všetkým" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Nastaviť miestnosť len pre členov" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Nastaviť miestnosť ako moderovanú" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Užívatelia sú implicitne členmi" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Povoliť užívateľom zmeniť tému tejto miestnosti" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Povoliť užívateľom odosielať súkromné správy" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Povoliť užívateľom dotazovať sa informácie o iných užívateľoch" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Povoliť používateľom posielanie pozvánok" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "Návštevníci môžu posielať textové informácie v stavových správach" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Návštevníci môžu meniť prezývky" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Zapnúť zaznamenávanie histórie" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "Na konfiguráciu miestnosti potrebujete klienta podporujúceho x:data" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Počet zúčastnených" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s Vás pozýva do miestnosti ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "heslo je" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "Fronta offline správ tohoto kontaktu je plná. Správa bola zahodená." + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "~s Offline správy" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Odoslané" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Čas" + +#: mod_offline.erl:507 +msgid "From" +msgstr "Od" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Pre" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Paket" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Zmazať vybrané" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Offline správy" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "ejabberd SOCKS5 Bytestreams modul" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Publish-Subscribe" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "ejabberd Publish-Subscribe modul" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "Žiadosť odberateľa PubSub" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Zvolte, či chcete povoliť toto odoberanie" + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "ID uzlu" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Adresa odberateľa" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Dovoliť tomuto JID odoberať PubSub uzol?" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Doručiť náklad s upozornením na udalosť" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Doručiť oznamy o udalosti" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Upozorniť prihlásených používateľov na zmenu nastavenia uzlu" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Upozorniť prihlásených používateľov na zmazanie uzlu" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Upozorniť prihlásených používateľov na odstránenie položiek z uzlu" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Uložiť položky natrvalo do úložiska" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "Prístupný názov pre uzol" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Maximálny počet položiek, ktoré je možné natrvalo uložiť" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Povoliť prihlasovanie" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Uveďte model prístupu" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Skupiny kontaktov, ktoré môžu odoberať" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Špecifikovať model publikovania" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Maximálny náklad v bajtoch" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Kedy odoslať posledne publikovanú položku" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Doručovať upozornenia len aktuálne prihláseným používateľom" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "Zvolte meno užívateľa a heslo pre registráciu na tomto servere" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "Nieje možné vytvárať účty tak rýchlo po sebe" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Nič" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Prihlásenie" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Čakajúce" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Skupiny" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Overiť" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Odstrániť" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Zoznam kontaktov " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Zlý formát" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Pridať JID" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Zoznam kontaktov" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Skupiny pre zdieľaný zoznam kontaktov" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Pridať nový" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Meno:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Popis:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Členovia:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Zobrazené skupiny:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Skupina " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Odoslať" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Erlang Jabber Server" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Dátum narodenia: " + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Mesto: " + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "Krajina: " + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "E-mail" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Priezvisko: " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Pre vyhľadanie Jabber používateľa vyplňte formulár (pridajte znak * na " +"koniec, pre vyhľadanie podreťazca)" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Celé meno: " + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Prostredné meno: " + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Meno" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Meno organizácie: " + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Organizačná jednotka: " + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Hľadať užívateľov v " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Užívateľ: " + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "Na vyhľadávanie potrebujete klienta podporujúceho x:data" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "Hľadať užívateľov vo vCard" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "ejabberd vCard modul" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Hľadať výsledky pre " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Vyplnte políčka pre vyhľadávanie Jabber užívateľa" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "ejabberd Web Admin" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Administrácia" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Virtuálne servery" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Uzly" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Štatistiky" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Používatelia" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Posledná aktivita" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Raw)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Raw" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "~s konfigurácia prístupového pravidla" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "ejabberd virtuálne servery" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Posledná aktivita používateľa" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Čas:" + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Posledný mesiac" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Posledný rok" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Všetky aktivity" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Zobraziť bežnú tabuľku" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Zobraziť kompletnú tabuľku" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Uzol nenájdený" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Server" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Registrovaní používatelia" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Offline správy" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Registrovaní používatelia:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Online používatelia:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Odchádzajúce s2s spojenia:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Odchádzajúce s2s servery:" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Zmeniť heslo" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Používateľ " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Pripojené zdroje:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Heslo:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Žiadne dáta" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Uzol " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Otvorené portov" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Aktualizovať" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Reštart" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Stop" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "Chyba RPC volania" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Databázové tabuľky na " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Typ úložiska" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Veľkosť" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Pamäť" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Záloha na " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Podotýkame, že tieto nastavenia budú zálohované do zabudovanej Mnesia " +"databázy. Ak používate ODBC modul, musíte zálohovať vašu SQL databázu " +"separátne." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Uložiť binárnu zálohu:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "OK" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Okamžite obnoviť binárnu zálohu:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"Obnoviť binárnu zálohu pri nasledujúcom reštarte ejabberd (vyžaduje menej " +"pamäte)" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Uložiť zálohu do textového súboru:" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Okamžite obnoviť zálohu z textového súboru:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Otvorené porty na " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Moduly na " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "Štatistiky ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Uptime:" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "Čas procesoru" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Transakcie potvrdená" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Transakcie zrušená" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Transakcie reštartovaná" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Transakcie zaznamenaná" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Aktualizovať " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Aktualizovať plán" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Aktualizované moduly" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Aktualizované skripty" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Nízkoúrovňový aktualizačný skript" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Kontrola skriptu" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Port" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Modul" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Nastavenia" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Zmazať" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Štart" + +#~ msgid "You must fill in field \"nick\" in the form" +#~ msgstr "Musíte vyplniť políčko \"prezývka\" vo formulári" diff --git a/src/msgs/sv.msg b/src/msgs/sv.msg index 498595cfc..833839131 100644 --- a/src/msgs/sv.msg +++ b/src/msgs/sv.msg @@ -1,296 +1,343 @@ -% $Id$ -% Language: Swedish (svenska) -% Author: Magnus Henoch -% Author: Jonas Ådahl - -% ejabberd_c2s.erl -{"Use of STARTTLS required", "Du måste använda STARTTLS"}. -{"Replaced by new connection", "Ersatt av ny anslutning"}. - -% jlib.hrl -{"No resource provided", "Ingen resurs angiven"}. - -% mod_configure.erl -{"DB Tables Configuration at ", "Konfigurera DB-tabeller på "}. -{"Choose storage type of tables", "Välj lagringstyp för tabeller"}. -{"RAM copy", "RAM-kopia"}. -{"RAM and disc copy", "RAM- och diskkopia"}. -{"Disc only copy", "Endast diskkopia"}. -{"Remote copy", "Sparas inte lokalt"}. -{"Stop Modules at ", "Stoppa moduler på "}. -{"Choose modules to stop", "Välj vilka moduler som skall stoppas"}. -{"Start Modules at ", "Starta moduler på "}. -{"Enter list of {Module, [Options]}", "Skriv in en lista av {Module, [Options]}"}. -{"List of modules to start", "Lista av moduler som skall startas"}. -{"Backup to File at ", "Säkerhetskopiera till fil på "}. -{"Enter path to backup file", "Skriv in sökväg till fil för säkerhetskopia"}. -{"Path to File", "Sökväg till fil"}. -{"Restore Backup from File at ", "Återställ säkerhetskopia från fil på "}. -{"Dump Backup to Text File at ", "Dumpa säkerhetskopia till textfil på "}. -{"Enter path to text file", "Skriv in sökväg till textfil"}. -{"Import User from File at ", "Importera användare från fil på "}. -{"Enter path to jabberd1.4 spool file", "Skriv in sökväg till spoolfil från jabberd1.4"}. -{"Import Users from Dir at ", "Importera användare från katalog på "}. -{"Enter path to jabberd1.4 spool dir", "Skriv in sökväg till spoolkatalog från jabberd1.4"}. -{"Path to Dir", "Sökväg till katalog"}. -{"Hostname Configuration", "Värdnamnkonfiguration"}. -{"Choose host name", "Välj värdnamn"}. -{"Host name", "Värdnamn"}. -{"Access Control List Configuration", "Konfiguera ACL"}. -{"Access control lists", "ACL"}. -{"Access Configuration", "Åtkomstkonfiguration"}. -{"Access rules", "Åtkomstregler"}. -{"Remove Users", "Ta bort användare"}. -{"Choose users to remove", "Välj användare att ta bort"}. -{"Administration of ", "Administration av "}. -{"Action on user", "Handling mot användare"}. -{"Edit Properties", "Redigera egenskaper"}. -{"Remove User", "Ta bort användare"}. - -% mod_disco.erl -{"Configuration", "Konfiguration"}. -{"Online Users", "Anslutna användare"}. -{"All Users", "Alla användare"}. -{"Outgoing S2S connections", "Utgående S2S-anslutningar"}. -{"To ~s", "Till ~s"}. -{"From ~s", "Från ~s"}. -{"Running Nodes", "Körande noder"}. -{"Stopped Nodes", "Stannade noder"}. -{"Host Name", "Värdnamn"}. -{"Access Control Lists", "ACL"}. -{"Access Rules", "Åtkomstregler"}. -{"Remove Users", "Ta bort användare"}. -{"DB", "DB"}. -{"Modules", "Moduler"}. -{"Start Modules", "Starta moduler"}. -{"Stop Modules", "Stanna moduler"}. -{"Backup Management", "Hantera säkerhetskopior"}. -{"Import users from jabberd1.4 spool files", "Importera användare från spoolfiler från jabberd1.4"}. -{"Backup", "Säkerhetskopiera"}. -{"Restore", "Återställ"}. -{"Dump to Text File", "Dumpa till textfil"}. -{"Import File", "Importera fil"}. -{"Import Directory", "Importera katalog"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Välj ett användarnamn och lösenord för att registrera mot denna server"}. - -% mod_vcard.erl -{"Erlang Jabber Server", "Erlang Jabber Server"}. -{"ejabberd vCard module", "ejabberd vCard-modul"}. -{"You need an x:data capable client to search", "Du behöver en klient som stödjer x:data, för att kunna söka"}. -{"Search users in ", "Sök efter användare på "}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Fyll i formuläret för att söka efter en användare (lägg till * på slutet av fältet för att hitta alla som börjar så)"}. -{"Results of search in ", "Sökresultat på "}. -{"User", "Användarnamn"}. -{"Full Name", "Fullständigt namn"}. -{"Name", "Förnamn"}. -{"Middle Name", "Mellannamn"}. -{"Family Name", "Efternamn"}. -{"Nickname", "Smeknamn"}. -{"Birthday", "Födelsedag"}. -{"Country", "Land"}. -{"City", "Stad"}. -{"email", "email"}. -{"Organization Name", "Organisationsnamn"}. -{"Organization Unit", "Organisationsenhet"}. - -% mod_vcard_ldap.erl -{"Fill in fields to search for any matching Jabber User", "Fyll i fält för att söka efter jabberanvändare"}. -{"Given Name", "Förnamn"}. - -% mod_vcard_odbc.erl -{"JID", "JID"}. - -% mod_pubsub/mod_pubsub.erl -{"ejabberd pub/sub module", "ejabberd pub/sub-modul"}. -{"Node Creator", "Nodskapare"}. -{"Deliver payloads with event notifications", "Skicka innehåll tillsammans med notifikationer"}. -{"Notify subscribers when the node configuration changes", "Meddela prenumeranter när nodens konfiguration ändras"}. -{"Notify subscribers when the node is deleted", "Meddela prenumeranter när noden tas bort"}. -{"Notify subscribers when items are removed from the node", "Meddela prenumeranter när dataposter tas bort från noden"}. -{"Persist items to storage", "Spara dataposter permanent"}. -{"Max # of items to persist", "Högsta antal dataposter som sparas"}. -{"Whether to allow subscriptions", "Tillåta prenumerationer?"}. -{"Specify the subscriber model", "Ange prenumerationsmodell"}. -{"Specify the publisher model", "Ange publiceringsmodell"}. -{"Max payload size in bytes", "Högsta innehållsstorlek i bytes"}. -{"Send items to new subscribers", "Skicka dataposter till nya prenumeranter"}. -{"Only deliver notifications to available users", "Skicka notifikationer bara till uppkopplade användare"}. -{"Specify the current subscription approver", "Ange prenumerationsgodkännare"}. - -% mod_muc/mod_muc.erl -{"You need an x:data capable client to register nickname", "Du behöver en klient som stödjer x:data för att registrera smeknamn"}. -{"Nickname Registration at ", "Registrera smeknamn på "}. -{"Enter nickname you want to register", "Skriv in smeknamnet du vill registrera"}. -{"ejabberd MUC module", "ejabberd MUC modul"}. -{"Only service administrators are allowed to send service messages", "Endast administratörer får skicka tjänstmeddelanden"}. -{"Room creation is denied by service policy", "Skapandet av rum är förbjudet enligt lokal policy"}. -{"Conference room does not exist", "Rummet finns inte"}. -{"Access denied by service policy", "Åtkomst nekad enligt lokal policy"}. -{"You must fill in field \"nick\" in the form", "Du måste fylla i fältet \"nick\" i formuläret"}. -{"Specified nickname is already registered", "Detta smeknamnet är redan registrerat"}. - -% mod_muc/mod_muc_room.erl -{"Make room moderated", "Gör rummet modererat"}. -{" has set the subject to: ", " har satt ämnet till: "}. -{"You need an x:data capable client to configure room", "Du behöver en klient som stödjer x:data för att konfiguera detta rum"}. -{"Configuration for ", "Konfiguration för "}. -{"Room title", "Rumstitel"}. -{"Allow users to change subject?", "Tillåt användare att ändra ämnet?"}. -{"Allow users to query other users?", "Tillåt användare att skicka iq-queries"}. -{"Allow users to send private messages?", "Tillåt användare att skicka privata meddelanden"}. -{"Make room public searchable?", "Gör rummet synligt för alla?"}. -{"Make participants list public?", "Gör användarlistan publik?"}. -{"Make room persistent?", "Gör rummet permanent?"}. -{"Make room moderated?", "Gör rummet modererat?"}. -{"Default users as members?", "Gör användare deltagare som standard?"}. -{"Make room members only?", "Stäng ute icke medlemmar?"}. -{"Allow users to send invites?", "Tillåt användare att skicka inbjudningar?"}. -{"Make room password protected?", "Lösenordsskydda rummet?"}. -{"Password", "Lösenord"}. -{"Make room anonymous?", "Anonymt rum?"}. -{"Enable logging?", "Aktivera loggning?"}. -{"Only moderators and participants are allowed to change subject in this room", "Endast moderatorer och deltagare har tillåtelse att ändra ämnet i det här rummet"}. -{"Only moderators are allowed to change subject in this room", "Endast moderatorer får ändra ämnet i det här rummet"}. -{"Visitors are not allowed to send messages to all occupants", "Besökare får inte skicka medelande till alla"}. -{"Only occupants are allowed to send messages to the conference", "Utomstående får inte skicka medelanden till den här konferensen"}. -{"It is not allowed to send normal messages to the conference", "Det är inte tillåtet att skicka normala medelanden till den här konferensen"}. -{"It is not allowed to send private messages to the conference", "Det är inte tillåtet att skicka privata medelanden till den här konferensen"}. -{"Improper message type", "Felaktig medelandetyp"}. -{"Nickname is already in use by another occupant", "Smeknamnet används redan"}. -{"Nickname is registered by another person", "Smeknamnet är reserverat"}. -{"It is not allowed to send private messages of type \"groupchat\"", "Det är inte tillåtet att skicka privata medelanden med typen \"groupchat\""}. -{"Recipient is not in the conference room", "Mottagaren finns inte i rummet"}. -{"Only occupants are allowed to send queries to the conference", "Utomstående får inte skicka iq-queries till den här konferensen"}. -{"Queries to the conference members are not allowed in this room", "Det är förbjudet att skicka iq-queries till konferensdeltagare"}. -{"You have been banned from this room", "Du har blivit bannlyst från det här rummet"}. -{"Membership required to enter this room", "Du måste vara medlem för att komma in i det här rummet"}. -{"Password required to enter this room", "Lösenord erfordras"}. -{"Incorrect password", "Fel lösenord"}. -{"Administrator privileges required", "Administrationsprivilegier krävs"}. -{"Moderator privileges required", "Moderatorprivilegier krävs"}. -{"JID ~s is invalid", "Otillåtet JID ~s"}. -{"Nickname ~s does not exist in the room", "Smeknamnet ~s existerar inte i det här rummet"}. -{"Invalid affiliation: ~s", "Ogiltlig rang: ~s"}. -{"Invalid role: ~s", "Ogiltlig roll: ~s"}. -{"Owner privileges required", "Ägarprivilegier krävs"}. -{"private, ", "privat, "}. - -% mod_irc/mod_irc.erl -{"ejabberd IRC module", "ejabberd IRC-modul"}. -{"You need an x:data capable client to configure mod_irc settings", "Du behöer en klient som stöjer x:data för att konfigurera mod_irc"}. -{"Registration in mod_irc for ", "mod_irc-registrering för "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Skriv in användarnamn och textkodning du vill använda för att ansluta till IRC-servrar"}. -{"IRC Username", "IRC-användarnamn"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Om du vill specifiera textkodning för IRC-servrar, fyll i listan med värden i formatet '{\"irc server\", \"encoding\"}'. Som standard används \"~s\"."}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Exempel: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"Encodings", "Textkodningar"}. - -% web/ejabberd_web_admin.erl -{"ejabberd administration", "ejabberd-administration"}. -{"Users", "Användare"}. -{"Nodes", "Noder"}. -{"Statistics", "Statistik"}. -{"(raw)", "(obehandlat format)"}. -{"submitted", "inskickat"}. -{"bad format", "otillåtet format"}. -{"raw", "obehandlat format"}. -{"ejabberd access control lists configuration", "ejabberd ACL-konfiguration"}. -{"Delete Selected", "Tabort valda"}. -{"Submit", "Skicka"}. -{"ejabberd access rules configuration", "ejabberd åtkomstregler-konfiguration"}. -{"~s access rule configuration", "Åtkomstregelkonfiguration för ~s"}. -{"ejabberd users", "ejabberd-användare"}. -{"ejabberd stats", "ejabberd-statistik"}. -{"Node not found", "Noden finns inte"}. -{"Add New", "Lägg till ny"}. -{"Registered users", "Registrerade användare"}. -{"Authenticated users", "Inloggade användare"}. -{"Online users", "Anslutna användare"}. -{"Outgoing S2S servers", "Utgående S2S-servrar"}. -{"Change Password", "Ändra lösenord"}. -{"Connected Resources:", "Anslutna resurser:"}. -{"Password:", "Lösenord:"}. -{"None", "Inga"}. -{"Node ", "Nod "}. -{"DB Management", "DB-hantering"}. -{"Listened Ports Management", "Hantering av lyssnande portar"}. -{"Restart", "Omstart"}. -{"Stop", "Stoppa"}. -{"RPC call error", "RPC-fel"}. -{"DB Tables at ", "DB-tabeller på "}. -{"Name", "Namn"}. -{"Storage Type", "Lagringstyp"}. -{"Size", "Storlek"}. -{"Memory", "Minne"}. -{"Backup Management at ", "Hantering av säkerhetskopiering på "}. -{"Store a backup in a file", "Lagra en säkerhetskopiering i en fil"}. -{"OK", "OK"}. -{"Restore a backup from a file", "Återställ en säkerhetskopia från en fil"}. -{"Install a database fallback from a file", "Installera en databasfallback från en fil"}. -{"Dump a database in a text file", "Dumpa en databas i en textfil"}. -{"Restore a database from a text file", "Återställ en databas från en textfil"}. -{"Listened Ports at ", "Lyssnande portar på "}. -{"~p statistics", "~p-statistik"}. -{"Uptime", "Driftstid"}. -{"CPU Time", "CPU-tid"}. -{"Transactions commited", "Skickade transaktioner"}. -{"Transactions aborted", "Avbrutna transaktioner"}. -{"Transactions restarted", "Omstartade transaktioner"}. -{"Transactions logged", "Loggade transaktioner"}. -{"Port", "Port"}. -{"Module", "Modul"}. -{"Options", "Parametrar"}. -{"Update", "Uppdatera"}. -{"Delete", "Ta bort"}. -{"Add User", "Lägg till användare"}. -{"ejabberd (c) 2002-2005 Alexey Shchepin, 2004-2005 Process One", "ejabberd (c) 2002-2005 Alexej Sjtjepin, 2004-2005 Process One"}. -{"Offline messages", "Offline-medelanden"}. -{"Last Activity", "Senast aktivitet"}. -{"Never", "Aldrig"}. -{"~s offline messages queue", "~s offlinemedelande i kö"}. -{"Time", "Tid"}. -{"From", "Från"}. -{"To", "Till"}. -{"Packet", "Paket"}. -{"Offline messages:", "Offlinemedelande:"}. -{"Roster", "Kontaktlista"}. -{"Nickname", "Smeknamn"}. -{"Subscription", "Prenumeration"}. -{"Pending", "Ännu inte godkända"}. -{"Groups", "Grupper"}. -{"Remove", "Ta bort"}. -{"Add JID", "Lägg till JID"}. -{"User ", "Användare "}. -{"Roster of ", "Kontaktlista för "}. -{"Shared Roster", "Gemensam kontaktlista"}. -{"Online", "Ansluten"}. -{"Validate", "Validera"}. -{"Not found", "Finns inte"}. -{"Shared roster groups", "Gemensamma kontaktlistagrupper"}. -{"Name:", "Namn:"}. -{"Description:", "Beskrivning:"}. -{"Members:", "Medlemmar:"}. -{"Displayed Groups:", "Visade grupper:"}. -{"Group ", "Grupp "}. -{"Virtual Hosts", "Virtuella servrar"}. -{"ejabberd virtual hosts", "Virtuella ejabberd-servrar"}. -{"Users last activity", "Senaste aktivitet från användare"}. -{"Period: ", "Period: "}. -{"Last month", "Senaste månaden"}. -{"Last year", "Senaste året"}. -{"All activity", "All aktivitet"}. -{"Show Ordinary Table", "Visa normal tabell"}. -{"Show Integral Table", "Visa kumulativ tabell"}. -{"Host", "Server"}. -{"No data", "Inga data"}. -{"Modules Management", "Modulhantering"}. -{"Modules at ", "Moduler på"}. -{"Start", "Starta"}. -{"ejabberd Web Interface", "Webbgränssnitt till ejabberd"}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Åtkomstkonfiguration"}. +{"Access Control List Configuration","Konfiguera ACL"}. +{"Access control lists","ACL"}. +{"Access Control Lists","ACL"}. +{"Access denied by service policy","Åtkomst nekad enligt lokal policy"}. +{"Access rules","Åtkomstregler"}. +{"Access Rules","Åtkomstregler"}. +{"Action on user","Handling mot användare"}. +{"Add Jabber ID","Lägg till Jabber ID"}. +{"Add New","Lägg till ny"}. +{"Add User","Lägg till användare"}. +{"Administration","Administration"}. +{"Administration of ","Administration av "}. +{"Administrator privileges required","Administrationsprivilegier krävs"}. +{"A friendly name for the node","Ett vänligt namn for noden"}. +{"All activity","All aktivitet"}. +{"Allow this JID to subscribe to this pubsub node?","Tillåt denna JID att prenumerera på denna pubsub node"}. +{"Allow users to change subject","Tillåt användare att byta ämne"}. +{"Allow users to query other users","Tillåt användare att söka efter andra användare"}. +{"Allow users to send invites","Tillåt användare att skicka inbjudningar"}. +{"Allow users to send private messages","Tillåt användare att skicka privata meddelanden"}. +{"Allow visitors to change nickname","Tillåt gäster att kunna ändra smeknamn"}. +{"Allow visitors to send status text in presence updates","Tillåt gäster att skicka statustext som uppdatering"}. +{"All Users","Alla användare"}. +{"Announcements","Meddelanden"}. +{"anyone","Vemsomhelst"}. +{"April","April"}. +{"August","Augusti"}. +{"Backup Management","Hantera säkerhetskopior"}. +{"Backup of ","Backup av"}. +{"Backup","Säkerhetskopiera"}. +{"Backup to File at ","Säkerhetskopiera till fil på "}. +{"Bad format","Dåligt format"}. +{"Birthday","Födelsedag"}. +{"Change Password","Ändra lösenord"}. +{"Change User Password","Andra användarlösenord"}. +{"Chatroom configuration modified","Chattrum konfiguration modifierad"}. +{"Chatrooms","Chattrum"}. +{"Choose a username and password to register with this server","Välj ett användarnamn och lösenord för att registrera mot denna server"}. +{"Choose modules to stop","Välj vilka moduler som skall stoppas"}. +{"Choose storage type of tables","Välj lagringstyp för tabeller"}. +{"Choose whether to approve this entity's subscription.","Välj om du vill godkänna hela denna prenumertion."}. +{"City","Stad"}. +{"Commands","Kommandon"}. +{"Conference room does not exist","Rummet finns inte"}. +{"Configuration for ","Konfiguration för "}. +{"Configuration","Konfiguration"}. +{"Connected Resources:","Anslutna resurser:"}. +{"Country","Land"}. +{"CPU Time:","CPU tid"}. +{"Database","Databas"}. +{"Database Tables at ","Databas tabell pa"}. +{"Database Tables Configuration at ","Databastabellers konfiguration"}. +{"December","December"}. +{"Default users as participants","Gör om användare till deltagare"}. +{"Delete message of the day on all hosts","Ta bort dagens meddelande på alla värdar"}. +{"Delete message of the day","Ta bort dagens meddelande"}. +{"Delete Selected","Tabort valda"}. +{"Delete","Ta bort"}. +{"Delete User","Ta bort användare"}. +{"Deliver event notifications","Skicka eventnotifikation"}. +{"Deliver payloads with event notifications","Skicka innehåll tillsammans med notifikationer"}. +{"Description:","Beskrivning:"}. +{"Disc only copy","Endast diskkopia"}. +{"Displayed Groups:","Visade grupper:"}. +{"Dump Backup to Text File at ","Dumpa säkerhetskopia till textfil på "}. +{"Dump to Text File","Dumpa till textfil"}. +{"Edit Properties","Redigera egenskaper"}. +{"ejabberd IRC module","ejabberd IRC-modul"}. +{"ejabberd MUC module","ejabberd MUC modul"}. +{"ejabberd Publish-Subscribe module","ejabberd publikprenumerations modul"}. +{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestrem modul"}. +{"ejabberd vCard module","ejabberd vCard-modul"}. +{"ejabberd virtual hosts","Virtuella ejabberd-servrar"}. +{"ejabberd Web Admin","ejabberd Web Admin"}. +{"Email","Email"}. +{"Enable logging","Möjliggör login"}. +{"Encodings","Textkodningar"}. +{"End User Session","Avsluta användarsession"}. +{"Enter list of {Module, [Options]}","Skriv in en lista av {Module, [Options]}"}. +{"Enter nickname you want to register","Skriv in smeknamnet du vill registrera"}. +{"Enter path to backup file","Skriv in sökväg till fil för säkerhetskopia"}. +{"Enter path to jabberd1.4 spool dir","Skriv in sökväg till spoolkatalog från jabberd1.4"}. +{"Enter path to jabberd1.4 spool file","Skriv in sökväg till spoolfil från jabberd1.4"}. +{"Enter path to text file","Skriv in sökväg till textfil"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Skriv in användarnamn och textkodning du vill använda för att ansluta till IRC-servrar"}. +{"Erlang Jabber Server","Erlang Jabber Server"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Exempel: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","Efternamn"}. +{"February","Februari"}. +{"Fill in fields to search for any matching Jabber User","Fyll i fält för att söka efter jabberanvändare"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Fyll i formuläret för att söka efter en användare (lägg till * på slutet av fältet för att hitta alla som börjar så)"}. +{"Friday","Fredag"}. +{"From","Från"}. +{"From ~s","Från ~s"}. +{"Full Name","Fullständigt namn"}. +{"Get Number of Online Users","Hämta antal inloggade användare"}. +{"Get Number of Registered Users","Hämta antal registrerade användare"}. +{"Get User Last Login Time","Hämta användarens senast inloggade tid"}. +{"Get User Password","Hämta användarlösenord"}. +{"Get User Statistics","Hämta användarstatistik"}. +{"Group ","Grupp "}. +{"Groups","Grupper"}. +{"has been banned","har blivit bannad"}. +{"has been kicked because of an affiliation change","har blivit kickad p.g.a en ändring av tillhörighet"}. +{"has been kicked because of a system shutdown","har blivit kickad p.g.a en systemnerstängning"}. +{"has been kicked because the room has been changed to members-only","har blivit kickad p.g.a att rummet har ändrats till endast användare"}. +{"has been kicked","har blivit kickad"}. +{" has set the subject to: "," har satt ämnet till: "}. +{"Host","Server"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Om du vill specifiera textkodning för IRC-servrar, fyll i listan med värden i formatet '{\"irc server\", \"encoding\"}'. Som standard används \"~s\"."}. +{"Import Directory","Importera katalog"}. +{"Import File","Importera fil"}. +{"Import User from File at ","Importera användare från fil på "}. +{"Import Users from Dir at ","Importera användare från katalog på "}. +{"Import Users From jabberd 1.4 Spool Files","Importera användare från jabberd 1.4 Spool filer"}. +{"Improper message type","Felaktig medelandetyp"}. +{"Incorrect password","Fel lösenord"}. +{"Invalid affiliation: ~s","Ogiltlig rang: ~s"}. +{"Invalid role: ~s","Ogiltlig roll: ~s"}. +{"IP addresses","IP adresser"}. +{"IRC Transport","IRC transport"}. +{"IRC Username","IRC-användarnamn"}. +{"is now known as","är känd som"}. +{"It is not allowed to send private messages","Det ar inte tillåtet att skicka privata meddelanden"}. +{"It is not allowed to send private messages of type \"groupchat\"","Det är inte tillåtet att skicka privata medelanden med typen \"groupchat\""}. +{"It is not allowed to send private messages to the conference","Det är inte tillåtet att skicka privata medelanden till den här konferensen"}. +{"Jabber ID","Jabber ID"}. +{"January","Januari"}. +{"JID ~s is invalid","Otillåtet JID ~s"}. +{"joins the room","joinar rummet"}. +{"July","Juli"}. +{"June","Juni"}. +{"Last Activity","Senast aktivitet"}. +{"Last login","Senaste login"}. +{"Last month","Senaste månaden"}. +{"Last year","Senaste året"}. +{"leaves the room","lämnar rummet"}. +{"Listened Ports at ","Lyssnande portar på "}. +{"Listened Ports","Lyssnarport"}. +{"List of modules to start","Lista av moduler som skall startas"}. +{"Low level update script","Uppdaterade laglevel skript"}. +{"Make participants list public","Gör deltagarlistan publik"}. +{"Make room members-only","Gör om rummet till endast medlemmar"}. +{"Make room moderated","Gör rummet modererat"}. +{"Make room password protected","Gör losenorden i rummet publika"}. +{"Make room persistent","Gör rummet permanent"}. +{"Make room public searchable","Gör rummet publikt sökbart"}. +{"March","Mars"}. +{"Maximum Number of Occupants","Maximalt antal av användare"}. +{"Max # of items to persist","Högsta antal dataposter som sparas"}. +{"Max payload size in bytes","Högsta innehållsstorlek i bytes"}. +{"May","Maj"}. +{"Membership required to enter this room","Du måste vara medlem för att komma in i det här rummet"}. +{"Members:","Medlemmar:"}. +{"Memory","Minne"}. +{"Message body","Meddelande kropp"}. +{"Middle Name","Mellannamn"}. +{"Moderator privileges required","Moderatorprivilegier krävs"}. +{"moderators only","endast moderatorer"}. +{"Module","Modul"}. +{"Modules at ","Moduler på"}. +{"Modules","Moduler"}. +{"Monday","Måndag"}. +{"Name:","Namn:"}. +{"Name","Namn"}. +{"Never","Aldrig"}. +{"Nickname is already in use by another occupant","Smeknamnet används redan"}. +{"Nickname is registered by another person","Smeknamnet är reserverat"}. +{"Nickname Registration at ","Registrera smeknamn på "}. +{"Nickname ~s does not exist in the room","Smeknamnet ~s existerar inte i det här rummet"}. +{"Nickname","Smeknamn"}. +{"No body provided for announce message","Ingen kropp behövs för dessa meddelanden"}. +{"No Data","Ingen data"}. +{"Node ID","Node ID"}. +{"Node ","Nod "}. +{"Node not found","Noden finns inte"}. +{"Nodes","Noder"}. +{"No limit","Ingen gräns"}. +{"None","Inga"}. +{"No resource provided","Ingen resurs angiven"}. +{"Notify subscribers when items are removed from the node","Meddela prenumeranter när dataposter tas bort från noden"}. +{"Notify subscribers when the node configuration changes","Meddela prenumeranter när nodens konfiguration ändras"}. +{"Notify subscribers when the node is deleted","Meddela prenumeranter när noden tas bort"}. +{"November","November"}. +{"Number of occupants","Antal besökare"}. +{"Number of online users","Antal inloggade användare"}. +{"Number of registered users","Antal registrerade användare"}. +{"October","Oktober"}. +{"Offline Messages:","Offline meddelanden:"}. +{"Offline Messages","Offline meddelanden"}. +{"OK","OK"}. +{"Online","Ansluten"}. +{"Online Users","Anslutna användare"}. +{"Online Users:","Inloggade användare"}. +{"Only deliver notifications to available users","Skicka notifikationer bara till uppkopplade användare"}. +{"Only moderators and participants are allowed to change subject in this room","Endast moderatorer och deltagare har tillåtelse att ändra ämnet i det här rummet"}. +{"Only moderators are allowed to change subject in this room","Endast moderatorer får ändra ämnet i det här rummet"}. +{"Only occupants are allowed to send messages to the conference","Utomstående får inte skicka medelanden till den här konferensen"}. +{"Only occupants are allowed to send queries to the conference","Utomstående får inte skicka iq-queries till den här konferensen"}. +{"Only service administrators are allowed to send service messages","Endast administratörer får skicka tjänstmeddelanden"}. +{"Options","Parametrar"}. +{"Organization Name","Organisationsnamn"}. +{"Organization Unit","Organisationsenhet"}. +{"Outgoing s2s Connections","Utgaende s2s anslutning"}. +{"Outgoing s2s Connections:","Utgående s2s anslutning"}. +{"Outgoing s2s Servers:","Utgående s2s server"}. +{"Owner privileges required","Ägarprivilegier krävs"}. +{"Packet","Paket"}. +{"Password:","Lösenord:"}. +{"Password","Lösenord"}. +{"Password required to enter this room","Lösenord erfordras"}. +{"Password Verification","Lösenordsverifikation"}. +{"Path to Dir","Sökväg till katalog"}. +{"Path to File","Sökväg till fil"}. +{"Pending","Ännu inte godkända"}. +{"Period: ","Period: "}. +{"Persist items to storage","Spara dataposter permanent"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","Port"}. +{"Present real JIDs to","Nuvarande äkta JIDs till"}. +{"private, ","privat, "}. +{"Publish-Subscribe","Publikprenumeration"}. +{"PubSub subscriber request","Pubsub prenumerationsforfrågan"}. +{"Queries to the conference members are not allowed in this room","Det är förbjudet att skicka iq-queries till konferensdeltagare"}. +{"RAM and disc copy","RAM- och diskkopia"}. +{"RAM copy","RAM-kopia"}. +{"(Raw)","(Ra)"}. +{"Raw","Ra"}. +{"Really delete message of the day?","Verkligen ta bort dagens meddelanden?"}. +{"Recipient is not in the conference room","Mottagaren finns inte i rummet"}. +{"Registered Users:","Registrerade användare"}. +{"Registered Users","Registrerade användare"}. +{"Registration in mod_irc for ","mod_irc-registrering för "}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Kom ihåg att dessa inställningar endast tar backup pa builtin Mnesias databas. Om du använder ODBC modul så måste du ta backup på SQLs databas enskilt"}. +{"Remote copy","Sparas inte lokalt"}. +{"Remove","Ta bort"}. +{"Remove User","Ta bort användare"}. +{"Replaced by new connection","Ersatt av ny anslutning"}. +{"Resources","Resurser"}. +{"Restart","Omstart"}. +{"Restart Service","Starta om servicen"}. +{"Restore","Återställ"}. +{"Restore Backup from File at ","Återställ säkerhetskopia från fil på "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","återställ den binära backupen efter nästa ejabberd omstart"}. +{"Restore binary backup immediately:","återställ den binära backupen omedelbart"}. +{"Restore plain text backup immediately:","återställ textbackup omedelbart"}. +{"Room Configuration","Rumkonfiguration"}. +{"Room creation is denied by service policy","Skapandet av rum är förbjudet enligt lokal policy"}. +{"Room title","Rumstitel"}. +{"Roster groups allowed to subscribe","Rostergrupper tillåts att prenumerera"}. +{"Roster","Kontaktlista"}. +{"Roster of ","Kontaktlista för "}. +{"Roster size","Roster storlek"}. +{"RPC Call Error","RPC Uppringningserror"}. +{"Running Nodes","Körande noder"}. +{"~s access rule configuration","Åtkomstregelkonfiguration för ~s"}. +{"Saturday","Lördag"}. +{"Script check","Skript kollat"}. +{"Search Results for ","Sökresultat för"}. +{"Search users in ","Sök efter användare på "}. +{"Send announcement to all online users on all hosts","Sänd meddelanden till alla inloggade användare på alla värdar"}. +{"Send announcement to all online users","Sänd meddelanden till alla inloggade användare"}. +{"Send announcement to all users on all hosts","Sänd meddelanden till alla användare på alla värdar"}. +{"Send announcement to all users","Sänd meddelanden till alla användare"}. +{"September","September"}. +{"Set message of the day and send to online users","Sätt dagens status meddelande och skicka till alla användare"}. +{"Set message of the day on all hosts and send to online users","Sätt dagens status meddelande pa alla värdar och skicka till alla användare"}. +{"Shared Roster Groups","Delade Rostergrupper"}. +{"Show Integral Table","Visa kumulativ tabell"}. +{"Show Ordinary Table","Visa normal tabell"}. +{"Shut Down Service","Stäng ner servicen"}. +{"~s invites you to the room ~s","~s bjöd in dig till rummet ~s"}. +{"Size","Storlek"}. +{"Specified nickname is already registered","Detta smeknamnet är redan registrerat"}. +{"Specify the access model","Specificera accessmodellen"}. +{"Specify the publisher model","Ange publiceringsmodell"}. +{"~s's Offline Messages Queue","~s's offline meddelandekö"}. +{"Start Modules at ","Starta moduler på "}. +{"Start Modules","Starta moduler"}. +{"Start","Starta"}. +{"Statistics of ~p","Statistik på ~p"}. +{"Statistics","Statistik"}. +{"Stop Modules at ","Stoppa moduler på "}. +{"Stop Modules","Stanna moduler"}. +{"Stopped Nodes","Stannade noder"}. +{"Stop","Stoppa"}. +{"Storage Type","Lagringstyp"}. +{"Store binary backup:","Lagra den binära backupen"}. +{"Store plain text backup:","Lagra textbackup"}. +{"Subject","Ämne"}. +{"Submit","Skicka"}. +{"Submitted","Skicka in"}. +{"Subscriber Address","Prenumerationsadress"}. +{"Subscription","Prenumeration"}. +{"Sunday","Söndag"}. +{"the password is","Lösenordet är"}. +{"This participant is kicked from the room because he sent an error message","Deltagaren har blivit kickad fran rummet p.g.a att han skickade ett errormeddelande"}. +{"This participant is kicked from the room because he sent an error message to another participant","Deltagaren har blivit kickad från rummet p.g.a att han skickade ett errormeddelande till en annan deltagare"}. +{"This participant is kicked from the room because he sent an error presence","Denna deltagaren är kickad från rummet p.g.a att han skickade en errorstatus"}. +{"This room is not anonymous","Detta rum är inte anonymt"}. +{"Thursday","Torsdag"}. +{"Time delay","Tidsförsening"}. +{"Time","Tid"}. +{"To ~s","Till ~s"}. +{"To","Till"}. +{"Traffic rate limit is exceeded","Trafikgränsen har överstigits"}. +{"Transactions Aborted:","Transaktioner borttagna"}. +{"Transactions Commited:","Transaktioner kommittade"}. +{"Transactions Logged:","Transaktioner loggade "}. +{"Transactions Restarted:","Transaktioner omstartade"}. +{"Tuesday","Tisdag"}. +{"Updated modules","Uppdaterade moduler"}. +{"Update message of the day (don't send)","Uppdatera dagens status meddelande (skicka inte)"}. +{"Update message of the day on all hosts (don't send)","Uppdatera dagens status meddelande på alla värdar (skicka inte)"}. +{"Update plan","Uppdateringsplan"}. +{"Update script","Uppdatera skript"}. +{"Update ","Uppdatera"}. +{"Update","Uppdatera"}. +{"Uptime:","Tid upp"}. +{"Use of STARTTLS required","Du måste använda STARTTLS"}. +{"User ","Användare "}. +{"User","Användarnamn"}. +{"User Management","Användarmanagement"}. +{"Users","Användare"}. +{"Users are not allowed to register accounts so fast","Det är inte tillåtet för användare att skapa konton så fort"}. +{"Users Last Activity","Användarens senaste aktivitet"}. +{"Validate","Validera"}. +{"vCard User Search","vCard användare sök"}. +{"Virtual Hosts","Virtuella servrar"}. +{"Visitors are not allowed to change their nicknames in this room","Det är inte tillåtet for gäster att ändra sina smeknamn i detta rummet"}. +{"Visitors are not allowed to send messages to all occupants","Besökare får inte skicka medelande till alla"}. +{"Wednesday","Onsdag"}. +{"When to send the last published item","När att skicka senast publicerade ämne"}. +{"Whether to allow subscriptions","Tillåta prenumerationer?"}. +{"You have been banned from this room","Du har blivit bannlyst från det här rummet"}. +{"You must fill in field \"Nickname\" in the form","Du måste fylla i fält \"smeknamn\" i formen"}. +{"You need an x:data capable client to configure mod_irc settings","Du behöer en klient som stöjer x:data för att konfigurera mod_irc"}. +{"You need an x:data capable client to configure room","Du behöver en klient som stödjer x:data för att konfiguera detta rum"}. +{"You need an x:data capable client to register nickname","Du behöver en klient som stödjer x:data för att registrera smeknamn"}. +{"You need an x:data capable client to search","Du behöver en klient som stödjer x:data, för att kunna söka"}. +{"Your contact offline message queue is full. The message has been discarded.","Din kontaktkö for offlinekontakter ar full"}. diff --git a/src/msgs/sv.po b/src/msgs/sv.po new file mode 100644 index 000000000..06b5ebec1 --- /dev/null +++ b/src/msgs/sv.po @@ -0,0 +1,1495 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Thore Alstromer\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Swedish (svenska)\n" +"X-Additional-Translator: Heysan\n" +"X-Additional-Translator: Magnus Henoch\n" +"X-Additional-Translator: Jonas Ådahl\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "Du måste använda STARTTLS" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Ingen resurs angiven" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Ersatt av ny anslutning" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Kommandon" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Verkligen ta bort dagens meddelanden?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Ämne" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Meddelande kropp" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "Ingen kropp behövs för dessa meddelanden" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Meddelanden" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Sänd meddelanden till alla användare" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Sänd meddelanden till alla användare på alla värdar" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Sänd meddelanden till alla inloggade användare" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "Sänd meddelanden till alla inloggade användare på alla värdar" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Sätt dagens status meddelande och skicka till alla användare" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Sätt dagens status meddelande pa alla värdar och skicka till alla användare" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Uppdatera dagens status meddelande (skicka inte)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Uppdatera dagens status meddelande på alla värdar (skicka inte)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Ta bort dagens meddelande" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Ta bort dagens meddelande på alla värdar" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Konfiguration" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Databas" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Starta moduler" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Stanna moduler" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Säkerhetskopiera" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Återställ" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Dumpa till textfil" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Importera fil" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Importera katalog" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Starta om servicen" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Stäng ner servicen" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Lägg till användare" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Ta bort användare" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Avsluta användarsession" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Hämta användarlösenord" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Andra användarlösenord" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Hämta användarens senast inloggade tid" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Hämta användarstatistik" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Hämta antal registrerade användare" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Hämta antal inloggade användare" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "ACL" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Åtkomstregler" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Användarmanagement" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Anslutna användare" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Alla användare" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Utgaende s2s anslutning" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Körande noder" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Stannade noder" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Moduler" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Hantera säkerhetskopior" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Importera användare från jabberd 1.4 Spool filer" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "Till ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "Från ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Databastabellers konfiguration" + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Välj lagringstyp för tabeller" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Endast diskkopia" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "RAM- och diskkopia" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "RAM-kopia" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Sparas inte lokalt" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Stoppa moduler på " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Välj vilka moduler som skall stoppas" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Starta moduler på " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Skriv in en lista av {Module, [Options]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Lista av moduler som skall startas" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Säkerhetskopiera till fil på " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Skriv in sökväg till fil för säkerhetskopia" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Sökväg till fil" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Återställ säkerhetskopia från fil på " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Dumpa säkerhetskopia till textfil på " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Skriv in sökväg till textfil" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Importera användare från fil på " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Skriv in sökväg till spoolfil från jabberd1.4" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Importera användare från katalog på " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Skriv in sökväg till spoolkatalog från jabberd1.4" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Sökväg till katalog" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Tidsförsening" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Konfiguera ACL" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "ACL" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Åtkomstkonfiguration" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Åtkomstregler" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Lösenord" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Lösenordsverifikation" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Antal registrerade användare" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Antal inloggade användare" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Aldrig" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Ansluten" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Senaste login" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Roster storlek" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "IP adresser" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Resurser" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Administration av " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Handling mot användare" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Redigera egenskaper" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Ta bort användare" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Åtkomst nekad enligt lokal policy" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "IRC transport" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "ejabberd IRC-modul" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "Du behöer en klient som stöjer x:data för att konfigurera mod_irc" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "mod_irc-registrering för " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Skriv in användarnamn och textkodning du vill använda för att ansluta till " +"IRC-servrar" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "IRC-användarnamn" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Om du vill specifiera textkodning för IRC-servrar, fyll i listan med värden " +"i formatet '{\"irc server\", \"encoding\"}'. Som standard används \"~s\"." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Exempel: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Textkodningar" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "Endast administratörer får skicka tjänstmeddelanden" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "Skapandet av rum är förbjudet enligt lokal policy" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "Rummet finns inte" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Chattrum" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "Du behöver en klient som stödjer x:data för att registrera smeknamn" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Registrera smeknamn på " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Skriv in smeknamnet du vill registrera" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Smeknamn" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "Detta smeknamnet är redan registrerat" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Du måste fylla i fält \"smeknamn\" i formen" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "ejabberd MUC modul" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Chattrum konfiguration modifierad" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "joinar rummet" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "lämnar rummet" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "har blivit bannad" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "har blivit kickad" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "har blivit kickad p.g.a en ändring av tillhörighet" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "har blivit kickad p.g.a att rummet har ändrats till endast användare" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "har blivit kickad p.g.a en systemnerstängning" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "är känd som" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " har satt ämnet till: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "Måndag" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "Tisdag" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "Onsdag" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "Torsdag" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "Fredag" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "Lördag" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "Söndag" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "Januari" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "Februari" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "Mars" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "April" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "Maj" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "Juni" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "Juli" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "Augusti" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "September" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "Oktober" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "November" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "December" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Rumkonfiguration" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Rumstitel" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Trafikgränsen har överstigits" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" +"Deltagaren har blivit kickad fran rummet p.g.a att han skickade ett " +"errormeddelande" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "" +"Det är inte tillåtet att skicka privata medelanden till den här konferensen" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Felaktig medelandetyp" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Deltagaren har blivit kickad från rummet p.g.a att han skickade ett " +"errormeddelande till en annan deltagare" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "" +"Det är inte tillåtet att skicka privata medelanden med typen \"groupchat\"" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "Mottagaren finns inte i rummet" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Utomstående får inte skicka medelanden till den här konferensen" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "Det ar inte tillåtet att skicka privata meddelanden" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Utomstående får inte skicka iq-queries till den här konferensen" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "Det är förbjudet att skicka iq-queries till konferensdeltagare" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "privat, " + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "" +"Endast moderatorer och deltagare har tillåtelse att ändra ämnet i det här " +"rummet" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Endast moderatorer får ändra ämnet i det här rummet" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "Besökare får inte skicka medelande till alla" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" +"Denna deltagaren är kickad från rummet p.g.a att han skickade en errorstatus" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Det är inte tillåtet for gäster att ändra sina smeknamn i detta rummet" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "Smeknamnet används redan" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "Smeknamnet är reserverat" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Du har blivit bannlyst från det här rummet" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "Du måste vara medlem för att komma in i det här rummet" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Detta rum är inte anonymt" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Lösenord erfordras" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Fel lösenord" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Administrationsprivilegier krävs" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Moderatorprivilegier krävs" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "Otillåtet JID ~s" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "Smeknamnet ~s existerar inte i det här rummet" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Ogiltlig rang: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Ogiltlig roll: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Ägarprivilegier krävs" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Konfiguration för " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Beskrivning:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Gör rummet permanent" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Gör rummet publikt sökbart" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Gör deltagarlistan publik" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Gör losenorden i rummet publika" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Maximalt antal av användare" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Ingen gräns" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Nuvarande äkta JIDs till" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "endast moderatorer" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "Vemsomhelst" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Gör om rummet till endast medlemmar" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Gör rummet modererat" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Gör om användare till deltagare" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Tillåt användare att byta ämne" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Tillåt användare att skicka privata meddelanden" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Tillåt användare att söka efter andra användare" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Tillåt användare att skicka inbjudningar" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "Tillåt gäster att skicka statustext som uppdatering" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Tillåt gäster att kunna ändra smeknamn" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Möjliggör login" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "Du behöver en klient som stödjer x:data för att konfiguera detta rum" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Antal besökare" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s bjöd in dig till rummet ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "Lösenordet är" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "Din kontaktkö for offlinekontakter ar full" + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "~s's offline meddelandekö" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Skicka in" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Tid" + +#: mod_offline.erl:507 +msgid "From" +msgstr "Från" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Till" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Paket" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Tabort valda" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Offline meddelanden:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "ejabberd SOCKS5 Bytestrem modul" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Publikprenumeration" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "ejabberd publikprenumerations modul" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "Pubsub prenumerationsforfrågan" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Välj om du vill godkänna hela denna prenumertion." + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "Node ID" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Prenumerationsadress" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Tillåt denna JID att prenumerera på denna pubsub node" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Skicka innehåll tillsammans med notifikationer" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Skicka eventnotifikation" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Meddela prenumeranter när nodens konfiguration ändras" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Meddela prenumeranter när noden tas bort" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Meddela prenumeranter när dataposter tas bort från noden" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Spara dataposter permanent" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "Ett vänligt namn for noden" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Högsta antal dataposter som sparas" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Tillåta prenumerationer?" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Specificera accessmodellen" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Rostergrupper tillåts att prenumerera" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Ange publiceringsmodell" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Högsta innehållsstorlek i bytes" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "När att skicka senast publicerade ämne" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Skicka notifikationer bara till uppkopplade användare" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "Välj ett användarnamn och lösenord för att registrera mot denna server" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "Det är inte tillåtet för användare att skapa konton så fort" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Inga" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Prenumeration" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Ännu inte godkända" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Grupper" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Validera" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Ta bort" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Kontaktlista för " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Dåligt format" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Lägg till Jabber ID" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Kontaktlista" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Delade Rostergrupper" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Lägg till ny" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Namn:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Beskrivning:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Medlemmar:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Visade grupper:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Grupp " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Skicka" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Erlang Jabber Server" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Födelsedag" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Stad" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "Land" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "Email" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Efternamn" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Fyll i formuläret för att söka efter en användare (lägg till * på slutet av " +"fältet för att hitta alla som börjar så)" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Fullständigt namn" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Mellannamn" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Namn" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Organisationsnamn" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Organisationsenhet" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Sök efter användare på " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Användarnamn" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "Du behöver en klient som stödjer x:data, för att kunna söka" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "vCard användare sök" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "ejabberd vCard-modul" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Sökresultat för" + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Fyll i fält för att söka efter jabberanvändare" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "ejabberd Web Admin" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Administration" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Virtuella servrar" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Noder" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Statistik" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Användare" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Senast aktivitet" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Ra)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Ra" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "Åtkomstregelkonfiguration för ~s" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "Virtuella ejabberd-servrar" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Användarens senaste aktivitet" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Period: " + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Senaste månaden" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Senaste året" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "All aktivitet" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Visa normal tabell" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Visa kumulativ tabell" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Noden finns inte" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Server" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Registrerade användare" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Offline meddelanden" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Registrerade användare" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Inloggade användare" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Utgående s2s anslutning" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Utgående s2s server" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Ändra lösenord" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Användare " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Anslutna resurser:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Lösenord:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Ingen data" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Nod " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Lyssnarport" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Uppdatera" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Omstart" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Stoppa" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "RPC Uppringningserror" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Databas tabell pa" + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Lagringstyp" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Storlek" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Minne" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Backup av" + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Kom ihåg att dessa inställningar endast tar backup pa builtin Mnesias " +"databas. Om du använder ODBC modul så måste du ta backup på SQLs databas " +"enskilt" + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Lagra den binära backupen" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "OK" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "återställ den binära backupen omedelbart" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "återställ den binära backupen efter nästa ejabberd omstart" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Lagra textbackup" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "återställ textbackup omedelbart" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Lyssnande portar på " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Moduler på" + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "Statistik på ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Tid upp" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "CPU tid" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Transaktioner kommittade" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Transaktioner borttagna" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Transaktioner omstartade" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Transaktioner loggade " + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Uppdatera" + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Uppdateringsplan" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Uppdaterade moduler" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Uppdatera skript" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Uppdaterade laglevel skript" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Skript kollat" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Port" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Modul" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Parametrar" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Ta bort" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Starta" + +#~ msgid "You must fill in field \"nick\" in the form" +#~ msgstr "Du måste fylla i fältet \"nick\" i formuläret" diff --git a/src/msgs/th.msg b/src/msgs/th.msg index baeefc939..4f26865ff 100644 --- a/src/msgs/th.msg +++ b/src/msgs/th.msg @@ -1,374 +1,328 @@ -% $Id$ -% Language: Thai (ภาษาไทย) -% Author: EQHO Communications (Thailand) Ltd. - http://www.eqho.com - -% mod_vcard_odbc.erl -{"Erlang Jabber Server", "Erlang Jabber Server"}. -{"You need an x:data capable client to search", "คุณต้องใช้ไคลเอ็นต์ที่รองรับ x:data เพื่อค้นหา"}. -{"Search users in ", "ค้นหาผู้ใช้ใน "}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "กรอกข้อมูลในแบบฟอร์มเพื่อค้นหาผู้ใช้ Jabber ที่ตรงกัน (ใส่เครื่องหมาย * ที่ท้ายสุดของฟิลด์เพื่อจับคู่กับสตริงย่อย)"}. -{"User", "ผู้ใช้"}. -{"Full Name", "ชื่อเต็ม"}. -{"Name", "ชื่อ"}. -{"Middle Name", "ชื่อกลาง"}. -{"Family Name", "นามสกุล"}. -{"Nickname", "ชื่อเล่น"}. -{"Birthday", "วันเกิด"}. -{"Country", "ประเทศ"}. -{"City", "เมือง"}. -{"Email", "อีเมล"}. -{"Organization Name", "ชื่อองค์กร"}. -{"Organization Unit", "หน่วยขององค์กร"}. -{"vCard User Search", "ค้นหาผู้ใช้ vCard "}. -{"ejabberd vCard module", "ejabberd vCard module"}. -{"Search Results for ", "ผลการค้นหาสำหรับ "}. -{"Jabber ID", "Jabber ID"}. - -% mod_roster.erl -{"None", "ไม่มี"}. -{"Subscription", "การสมัครสมาชิก"}. -{"Pending", "ค้างอยู่"}. -{"Groups", "กลุ่ม"}. -{"Validate", "ตรวจสอบ"}. -{"Remove", "ลบ"}. -{"Roster of ", "บัญชีรายชื่อของ "}. -{"Submitted", "ส่งแล้ว"}. -{"Bad format", "รูปแบบที่ไม่ถูกต้อง"}. -{"Add Jabber ID", "เพิ่ม Jabber ID"}. -{"Roster", "บัญชีรายชื่อ"}. - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "ลำดับข้อความออฟไลน์ของผู้ที่ติดต่อของคุณเต็มแล้ว ข้อความถูกลบทิ้งแล้ว"}. -{"~s's Offline Messages Queue", "~s's ลำดับข้อความออฟไลน์"}. -{"Packet", "แพ็กเก็ต"}. -{"Delete Selected", "ลบข้อความที่เลือก"}. -{"Offline Messages:", "ข้อความออฟไลน์:"}. - -% ejabberd_c2s.erl -{"Use of STARTTLS required", "ต้องใช้ STARTTLS"}. -{"No resource provided", "ไม่ได้ระบุข้อมูล"}. -{"Replaced by new connection", "แทนที่ด้วยการเชื่อมต่อใหม่"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "เลือกชื่อผู้ใช้และรหัสผ่านเพื่อลงทะเบียนกับเซิร์ฟเวอร์นี้"}. - -% mod_vcard_ldap.erl -{"Fill in fields to search for any matching Jabber User", "กรอกข้อมูลลงในฟิลด์เพื่อค้นหาผู้ใช้ Jabber ที่ตรงกัน"}. - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "ejabberd SOCKS5 Bytestreams module"}. - -% mod_shared_roster.erl -{"Add New", "เพิ่มผู้ใช้ใหม่"}. -{"Shared Roster Groups", "กลุ่มบัญชีรายชื่อที่ใช้งานร่วมกัน"}. -{"Name:", "ชื่อ:"}. -{"Description:", "รายละเอียด:"}. -{"Members:", "สมาชิก:"}. -{"Displayed Groups:", "กลุ่มที่แสดง:"}. -{"Group ", "กลุ่ม"}. -{"Submit", "ส่ง"}. - -% mod_announce.erl -{"Really delete message of the day?", "แน่ใจว่าต้องการลบข้อความของวันหรือไม่"}. -{"Subject", "หัวเรื่อง"}. -{"Message body", "เนื้อหาของข้อความ"}. -{"No body provided for announce message", "ไม่ได้ป้อนเนื้อหาสำหรับข้อความที่ประกาศ"}. -{"Announcements", "ประกาศ"}. -{"Send announcement to all users", "ส่งประกาศถึงผู้ใช้ทั้งหมด"}. -{"Send announcement to all users on all hosts", "ส่งประกาศถึงผู้ใช้ทั้งหมดบนโฮสต์ทั้งหมด"}. -{"Send announcement to all online users", "ส่งประกาศถึงผู้ใช้ออนไลน์ทั้งหมด"}. -{"Send announcement to all online users on all hosts", "ส่งประกาศถึงผู้ใช้ออนไลน์ทั้งหมดบนโฮสต์ทั้งหมด"}. -{"Set message of the day and send to online users", "ตั้งค่าข้อความของวันและส่งถึงผู้ใช้ออนไลน์"}. -{"Set message of the day on all hosts and send to online users", "ตั้งค่าข้อความของวันบนโฮสต์ทั้งหมดและส่งถึงผู้ใช้ออนไลน์"}. -{"Update message of the day (don't send)", "อัพเดตข้อความของวัน (ไม่ต้องส่ง)"}. -{"Update message of the day on all hosts (don't send)", "อัพเดตข้อความของวันบนโฮสต์ทั้งหมด (ไม่ต้องส่ง) "}. -{"Delete message of the day", "ลบข้อความของวัน"}. -{"Delete message of the day on all hosts", "ลบข้อความของวันบนโฮสต์ทั้งหมด"}. - -% mod_adhoc.erl -{"Commands", "คำสั่ง"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% mod_irc/mod_irc.erl -{"Access denied by service policy", "การเข้าถึงถูกปฏิเสธโดยนโยบายการบริการ"}. -{"IRC Transport", "การส่ง IRC"}. -{"ejabberd IRC module", "ejabberd IRC module"}. -{"You need an x:data capable client to configure mod_irc settings", "คุณต้องใช้ไคลเอ็นต์ที่รองรับ x:data เพื่อกำหนดการตั้งค่า mod_irc"}. -{"Registration in mod_irc for ", "การลงทะเบียนใน mod_irc สำหรับ"}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "ป้อนชื่อผู้ใช้และการเข้ารหัสที่คุณต้องการใช้สำหรับเชื่อมต่อกับเซิร์ฟเวอร์ IRC"}. -{"IRC Username", "ชื่อผู้ใช้ IRC"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "ถ้าคุณต้องการระบุการเข้ารหัสที่ต่างกันสำหรับเซิร์ฟเวอร์ IRC ให้กรอกค่าโดยใช้รูปแบบ '{\"irc server\", \"encoding\"}' ลงในรายการ การบริการนี้ใช้การเข้ารหัสในรูปแบบ \"~s\" โดยค่าดีฟอลต์ "}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "ตัวอย่าง: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"Encodings", "การเข้ารหัส"}. - -% mod_configure.erl -{"Configuration", "การกำหนดค่า"}. -{"Database", "ฐานข้อมูล"}. -{"Start Modules", "เริ่มโมดูล"}. -{"Stop Modules", "หยุดโมดูล"}. -{"Backup", "การสำรองข้อมูล "}. -{"Restore", "การคืนค่า"}. -{"Dump to Text File", "ถ่ายโอนข้อมูลไปยังไฟล์ข้อความ"}. -{"Import File", "อิมพอร์ตไฟล์"}. -{"Import Directory", "อิมพอร์ตไดเร็กทอรี"}. -{"Restart Service", "เริ่มต้นการบริการใหม่อีกครั้ง"}. -{"Shut Down Service", "ปิดการบริการ"}. -{"Add User", "เพิ่มผู้ใช้"}. -{"Delete User", "ลบผู้ใช้"}. -{"End User Session", "สิ้นสุดเซสชันของผู้ใช้"}. -{"Get User Password", "ขอรับรหัสผ่านของผู้ใช้"}. -{"Change User Password", "เปลี่ยนรหัสผ่านของผู้ใช้"}. -{"Get User Last Login Time", "แสดงเวลาเข้าสู่ระบบครั้งล่าสุดของผู้ใช้"}. -{"Get User Statistics", "แสดงสถิติของผู้ใช้"}. -{"Get Number of Registered Users", "แสดงจำนวนผู้ใช้ที่ลงทะเบียน"}. -{"Get Number of Online Users", "แสดงจำนวนผู้ใช้ออนไลน์"}. -{"Access Control Lists", "รายการควบคุมการเข้าถึง"}. -{"Access Rules", "กฎการเข้าถึง"}. -{"User Management", "การจัดการผู้ใช้"}. -{"Online Users", "ผู้ใช้ออนไลน์"}. -{"All Users", "ผู้ใช้ทั้งหมด"}. -{"Outgoing s2s Connections", "การเชื่อมต่อ s2s ขาออก"}. -{"Running Nodes", "โหนดที่ทำงาน"}. -{"Stopped Nodes", "โหนดที่หยุด"}. -{"Modules", "โมดูล"}. -{"Backup Management", "การจัดการข้อมูลสำรอง"}. -{"Import Users From jabberd 1.4 Spool Files", "อิมพอร์ตผู้ใช้จากไฟล์เก็บพักข้อมูล jabberd 1.4"}. -{"To ~s", "ถึง ~s"}. -{"From ~s", "จาก ~s"}. -{"Database Tables Configuration at ", "การกำหนดค่าตารางฐานข้อมูลที่"}. -{"Choose storage type of tables", "เลือกชนิดการจัดเก็บของตาราง"}. -{"RAM copy", "คัดลอก RAM"}. -{"RAM and disc copy", "คัดลอก RAM และดิสก์"}. -{"Disc only copy", "คัดลอกเฉพาะดิสก์"}. -{"Remote copy", "คัดลอกระยะไกล"}. -{"Stop Modules at ", "หยุดโมดูลที่"}. -{"Choose modules to stop", "เลือกโมดูลเพื่อหยุดการทำงาน"}. -{"Start Modules at ", "เริ่มโมดูลที่"}. -{"Enter list of {Module, [Options]}", "ป้อนรายการของ {โมดูล, [ตัวเลือก]}"}. -{"List of modules to start", "รายการของโมดูลที่จะเริ่มการทำงาน"}. -{"Backup to File at ", "สำรองไฟล์ข้อมูลที่"}. -{"Enter path to backup file", "ป้อนพาธเพื่อสำรองไฟล์ข้อมูล"}. -{"Path to File", "พาธของไฟล์ข้อมูล"}. -{"Restore Backup from File at ", "คืนค่าการสำรองข้อมูลจากไฟล์ที่"}. -{"Dump Backup to Text File at ", "ถ่ายโอนการสำรองข้อมูลไปยังไฟล์ข้อความที่"}. -{"Enter path to text file", "ป้อนพาธของไฟล์ข้อความ"}. -{"Import User from File at ", "อิมพอร์ตผู้ใช้จากไฟล์ที่"}. -{"Enter path to jabberd1.4 spool file", "ป้อนพาธไปยังไฟล์เก็บพักข้อมูล jabberd 1.4"}. -{"Import Users from Dir at ", "อิมพอร์ตผู้ใช้จาก Dir ที่"}. -{"Enter path to jabberd1.4 spool dir", "ป้อนพาธไปยัง jabberd 1.4 spool dir"}. -{"Path to Dir", "พาธไปยัง Dir"}. -{"Time delay", "การหน่วงเวลา"}. -{"Access Control List Configuration", "การกำหนดค่ารายการควบคุมการเข้าถึง"}. -{"Access control lists", "รายการควบคุมการเข้าถึง"}. -{"Access Configuration", "การกำหนดค่าการเข้าถึง"}. -{"Access rules", "กฎการเข้าถึง"}. -{"Password", "รหัสผ่าน"}. -{"Password Verification", "การตรวจสอบรหัสผ่าน"}. -{"Number of registered users", "จำนวนผู้ใช้ที่ลงทะเบียน"}. -{"Number of online users", "จำนวนผู้ใช้ออนไลน์"}. -{"Never", "ไม่เคย"}. -{"Online", "ออนไลน์"}. -{"Last login", "การเข้าสู่ระบบครั้งล่าสุด"}. -{"Roster size", "ขนาดของบัญชีรายชื่อ"}. -{"IP addresses", "ที่อยู่ IP"}. -{"Resources", "ทรัพยากร"}. -{"Administration of ", "การดูแล "}. -{"Action on user", "การดำเนินการกับผู้ใช้"}. -{"Edit Properties", "แก้ไขคุณสมบัติ"}. -{"Remove User", "ลบผู้ใช้"}. - -% mod_pubsub/mod_pubsub.erl -{"Publish-Subscribe", "เผยแพร่-สมัครเข้าใช้งาน"}. -{"ejabberd Publish-Subscribe module", "ejabberd Publish-Subscribe module"}. -{"PubSub subscriber request", "คำร้องขอของผู้สมัครเข้าใช้งาน PubSub"}. -{"Choose whether to approve this entity's subscription.", "เลือกว่าจะอนุมัติการสมัครเข้าใช้งานของเอนทิตี้นี้หรือไม่"}. -{"Node ID", "ID โหนด"}. -{"Subscriber Address", "ที่อยู่ของผู้สมัคร"}. -{"Allow this JID to subscribe to this pubsub node?", "อนุญาตให้ JID นี้เข้าร่วมเป็นสมาชิกของโหนด pubsub หรือไม่"}. -{"Deliver payloads with event notifications", "ส่งส่วนของข้อมูล (payload) พร้อมกับการแจ้งเตือนเหตุการณ์"}. -{"Deliver event notifications", "ส่งการแจ้งเตือนเหตุการณ์"}. -{"Notify subscribers when the node configuration changes", "แจ้งเตือนผู้สมัครสมาชิกเมื่อการกำหนดค่าโหนดเปลี่ยนแปลง"}. -{"Notify subscribers when the node is deleted", "แจ้งเตือนผู้สมัครสมาชิกเมื่อโหนดถูกลบ"}. -{"Notify subscribers when items are removed from the node", "แจ้งเตือนผู้สมัครสมาชิกเมื่อรายการถูกลบออกจากโหนด"}. -{"Persist items to storage", "ยืนยันรายการที่จะจัดเก็บ"}. -{"Max # of items to persist", "จำนวนสูงสุดของรายการที่ยืนยัน"}. -{"Whether to allow subscriptions", "อนุญาตให้เข้าร่วมเป็นสมาชิกหรือไม่"}. -{"Specify the access model", "ระบุโมเดลการเข้าถึง"}. -{"Roster groups that may subscribe (if access model is roster)", "กลุ่มบัญชีรายชื่อที่อาจจะสมัครเป็นสมาชิก (ถ้าโมเดลการเข้าถึงคือบัญชีรายชื่อ)"}. -{"Specify the publisher model", "ระบุโมเดลผู้เผยแพร่"}. -{"Max payload size in bytes", "ขนาดสูงสุดของส่วนของข้อมูล (payload) มีหน่วยเป็นไบต์"}. -{"When to send the last published item", "เวลาที่ส่งรายการที่เผยแพร่ครั้งล่าสุด"}. -{"Only deliver notifications to available users", "ส่งการแจ้งเตือนถึงผู้ใช้ที่สามารถติดต่อได้เท่านั้น"}. - -% web/ejabberd_web_admin.erl -{"ejabberd Web Interface", "เว็บอินเทอร์เฟซของ ejabberd"}. -{"Administration", "การดูแล"}. -{"Virtual Hosts", "โฮสต์เสมือน"}. -{"Nodes", "โหนด"}. -{"Statistics", "สถิติ"}. -{"Users", "ผู้ใช้"}. -{"Last Activity", "กิจกรรมล่าสุด"}. -{"(Raw)", "(ข้อมูลดิบ)"}. -{"Raw", "ข้อมูลดิบ"}. -{"~s access rule configuration", "~s การกำหนดค่ากฎการเข้าถึง"}. -{"ejabberd virtual hosts", "โฮสต์เสมือน ejabberd"}. -{"Users Last Activity", "กิจกรรมล่าสุดของผู้ใช้"}. -{"Period: ", "ระยะเวลา:"}. -{"Last month", "เดือนที่แล้ว"}. -{"Last year", "ปีที่แล้ว"}. -{"All activity", "กิจกรรมทั้งหมด"}. -{"Show Ordinary Table", "แสดงตารางทั่วไป"}. -{"Show Integral Table", "แสดงตารางรวม"}. -{"Node not found", "ไม่พบโหนด"}. -{"Host", "โฮสต์"}. -{"Registered Users", "ผู้ใช้ที่ลงทะเบียน"}. -{"Offline Messages", "ข้อความออฟไลน์"}. -{"Registered Users:", "ผู้ใช้ที่ลงทะเบียน:"}. -{"Online Users:", "ผู้ใช้ออนไลน์:"}. -{"Outgoing s2s Connections:", "การเชื่อมต่อ s2s ขาออก:"}. -{"Outgoing s2s Servers:", "เซิร์ฟเวอร์ s2s ขาออก:"}. -{"Change Password", "เปลี่ยนรหัสผ่าน"}. -{"User ", "ผู้ใช้"}. -{"Connected Resources:", "ทรัพยากรที่เชื่อมต่อ:"}. -{"Password:", "รหัสผ่าน:"}. -{"No Data", "ไม่มีข้อมูล"}. -{"Node ", "โหนด "}. -{"Listened Ports", "พอร์ทฟัง"}. -{"Update", "อัพเดต"}. -{"Restart", "เริ่มต้นใหม่"}. -{"Stop", "หยุด"}. -{"RPC Call Error", "ข้อผิดพลาดจากการเรียกใช้ RPC"}. -{"Database Tables at ", "ตารางฐานข้อมูลที่"}. -{"Storage Type", "ชนิดที่เก็บข้อมูล"}. -{"Size", "ขนาด"}. -{"Memory", "หน่วยความจำ"}. -{"Backup of ", "การสำรองข้อมูล"}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "โปรดทราบว่าตัวเลือกเหล่านี้จะสำรองข้อมูลในฐานข้อมูล builtin Mnesia เท่านั้น หากคุณใช้โมดูล ODBC คุณต้องสำรองข้อมูลของฐานข้อมูล SQL แยกต่างหากด้วย"}. -{"Store binary backup:", "จัดเก็บข้อมูลสำรองแบบไบนารี:"}. -{"OK", "ตกลง"}. -{"Restore binary backup immediately:", "คืนค่าข้อมูลสำรองแบบไบนารีโดยทันที:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "คืนค่าข้อมูลสำรองแบบไบนารีหลังจากที่ ejabberd ถัดไปเริ่มการทำงานใหม่ (ใช้หน่วยความจำน้อยลง):"}. -{"Store plain text backup:", "จัดเก็บข้อมูลสำรองที่เป็นข้อความธรรมดา:"}. -{"Restore plain text backup immediately:", "คืนค่าข้อมูลสำรองที่เป็นข้อความธรรมดาโดยทันที:"}. -{"Listened Ports at ", "พอร์ทฟังที่"}. -{"Modules at ", "โมดูลที่ "}. -{"Statistics of ~p", "สถิติของ ~p"}. -{"Uptime:", "เวลาการทำงานต่อเนื่อง:"}. -{"CPU Time:", "เวลาการทำงานของ CPU:"}. -{"Transactions Commited:", "ทรานแซกชันที่ได้รับมอบหมาย:"}. -{"Transactions Aborted:", "ทรานแซกชันที่ถูกยกเลิก:"}. -{"Transactions Restarted:", "ทรานแซกชันที่เริ่มทำงานใหม่อีกครั้ง:"}. -{"Transactions Logged:", "ทรานแซกชันที่บันทึก:"}. -{"Update ", "อัพเดต "}. -{"Update plan", "แผนการอัพเดต"}. -{"Updated modules", "โมดูลที่อัพเดต"}. -{"Update script", "อัพเดตสคริปต์"}. -{"Low level update script", "อัพเดตสคริปต์ระดับต่ำ"}. -{"Script check", "ตรวจสอบคริปต์"}. -{"Port", "พอร์ท"}. -{"Module", "โมดูล"}. -{"Options", "ตัวเลือก"}. -{"Delete", "ลบ"}. -{"Start", "เริ่ม"}. - -% mod_muc/mod_muc.erl -{"Only service administrators are allowed to send service messages", "ผู้ดูแลด้านการบริการเท่านั้นที่ได้รับอนุญาตให้ส่งข้อความการบริการ"}. -{"Room creation is denied by service policy", "การสร้างห้องสนทนาถูกปฏิเสธโดยนโยบายการบริการ"}. -{"Conference room does not exist", "ไม่มีห้องประชุม"}. -{"Chatrooms", "ห้องสนทนา"}. -{"You need an x:data capable client to register nickname", "คุณต้องใช้ไคลเอ็นต์ที่รองรับ x:data เพื่อลงทะเบียนชื่อเล่น"}. -{"Nickname Registration at ", "การลงทะเบียนชื่อเล่นที่ "}. -{"Enter nickname you want to register", "ป้อนชื่อเล่นที่คุณต้องการลงทะเบียน"}. -{"Specified nickname is already registered", "ชื่อเล่นที่ระบุได้รับการลงได้ทะเบียนแล้ว"}. -{"You must fill in field \"Nickname\" in the form", "คุณต้องกรอกฟิลด์ \"Nickname\" ในแบบฟอร์ม"}. -{"ejabberd MUC module", "ejabberd MUC module"}. - -% mod_muc/mod_muc_room.erl -{"Traffic rate limit is exceeded", "อัตราของปริมาณการเข้าใช้เกินขีดจำกัด"}. -{"It is not allowed to send private messages to the conference", "ไม่อนุญาตให้ส่งข้อความส่วนตัวไปยังห้องประชุม"}. -{"Improper message type", "ประเภทข้อความไม่เหมาะสม"}. -{"Only occupants are allowed to send messages to the conference", "ผู้ครอบครองห้องเท่านั้นที่ได้รับอนุญาตให้ส่งข้อความไปยังห้องประชุม"}. -{"It is not allowed to send private messages of type \"groupchat\"", "ไม่อนุญาตให้ส่งข้อความส่วนตัวไปยัง \"กลุ่มสนทนา\""}. -{"Recipient is not in the conference room", "ผู้รับไม่ได้อยู่ในห้องประชุม"}. -{"Only occupants are allowed to send queries to the conference", "ผู้ครอบครองห้องเท่านั้นที่ได้รับอนุญาตให้ส่งกระทู้ถามไปยังห้องประชุม"}. -{"Queries to the conference members are not allowed in this room", "ห้องนี้ไม่อนุญาตให้ส่งกระทู้ถามถึงสมาชิกในห้องประชุม"}. -{"private, ", "ส่วนตัว, "}. -{"Only moderators and participants are allowed to change subject in this room", "ผู้ดูแลการสนทนาและผู้เข้าร่วมเท่านั้นที่ได้รับอนุญาตให้เปลี่ยนหัวข้อในห้องนี้"}. -{"Only moderators are allowed to change subject in this room", "ผู้ดูแลการสนทนาเท่านั้นที่ได้รับอนุญาตให้เปลี่ยนหัวข้อในห้องนี้"}. -{"Visitors are not allowed to send messages to all occupants", "ผู้เยี่ยมเยือนไม่ได้รับอนุญาตให้ส่งข้อความถึงผู้ครอบครองห้องทั้งหมด"}. -{"Nickname is already in use by another occupant", "ชื่อเล่นถูกใช้งานอยู่โดยผู้ครอบครองห้อง"}. -{"Nickname is registered by another person", "ชื่อเล่นถูกลงทะเบียนใช้งานโดยบุคคลอื่น"}. -{"You have been banned from this room", "คุณถูกสั่งห้ามไมให้เข้าห้องนี้"}. -{"Membership required to enter this room", "ต้องเป็นสมาชิกจึงจะสามารถเข้าห้องนี้ได้"}. -{"This room is not anonymous", "ห้องนี้ไม่ปิดบังชื่อ"}. -{"Password required to enter this room", "ต้องใส่รหัสผ่านเพื่อเข้าห้องนี้"}. -{"Incorrect password", "รหัสผ่านไม่ถูกต้อง"}. -{" has set the subject to: ", " ตั้งหัวข้อว่า: "}. -{"Administrator privileges required", "ต้องมีสิทธิพิเศษของผู้ดูแลระบบ"}. -{"Moderator privileges required", "ต้องมีสิทธิพิเศษของผู้ดูแลการสนทนา"}. -{"JID ~s is invalid", "JID ~s ไม่ถูกต้อง"}. -{"Nickname ~s does not exist in the room", "ไม่มีชื่อเล่น ~s อยู่ในห้องนี้"}. -{"Invalid affiliation: ~s", "การเข้าร่วมที่ไม่ถูกต้อง: ~s"}. -{"Invalid role: ~s", "บทบาทไม่ถูกต้อง: ~s"}. -{"Owner privileges required", "ต้องมีสิทธิพิเศษของเจ้าของ"}. -{"Configuration for ", "การกำหนดค่าสำหรับ "}. -{"Room title", "ชื่อห้อง"}. -{"Make room persistent", "สร้างเป็นห้องถาวร"}. -{"Make room public searchable", "สร้างเป็นห้องที่บุคคลทั่วไปสามารถค้นหาได้"}. -{"Make participants list public", "สร้างรายการผู้เข้าร่วมสำหรับใช้งานโดยบุคคลทั่วไป"}. -{"Make room password protected", "สร้างห้องที่มีการป้องกันด้วยรหัสผ่าน"}. -{"Maximum Number of Occupants", "จำนวนผู้ครอบครองห้องสูงสุด"}. -{"No limit", "ไม่จำกัด"}. -{"Present real JIDs to", "แสดง JIDs ที่ถูกต้องแก่"}. -{"moderators only", "สำหรับผู้ดูแลการสนทนาเท่านั้น"}. -{"anyone", "ทุกคน"}. -{"Make room members-only", "สร้างห้องสำหรับสมาชิกเท่านั้น"}. -{"Default users as participants", "ผู้ใช้เริ่มต้นเป็นผู้เข้าร่วม"}. -{"Allow users to change subject", "อนุญาตให้ผู้ใช้เปลี่ยนหัวข้อได้"}. -{"Allow users to send private messages", "อนุญาตให้ผู้ใช้ส่งข้อความส่วนตัว"}. -{"Allow users to query other users", "อนุญาตให้ผู้ใช้ถามคำถามกับผู้ใช้คนอื่นๆ ได้"}. -{"Allow users to send invites", "อนุญาตให้ผู้ใช้ส่งคำเชิญถึงกันได้"}. -{"Enable logging", "เปิดใช้งานการบันทึก"}. -{"You need an x:data capable client to configure room", "คุณต้องใช้ไคลเอ็นต์ที่รองรับ x:data เพื่อกำหนดค่าห้องสนทนา "}. -{"Number of occupants", "จำนวนผู้ครอบครองห้อง"}. -{"~s invites you to the room ~s", "~s เชิญคุณเข้าร่วมสนทนาในห้อง ~s"}. -{"the password is", "รหัสผ่านคือ"}. - -% mod_muc/mod_muc_log.erl -{"Chatroom configuration modified", "มีการปรับเปลี่ยนการกำหนดค่าของห้องสนทนา"}. -{"joins the room", "เข้าห้องสนทนานี้"}. -{"leaves the room", "ออกจากห้อง"}. -{"has been kicked", "ถูกไล่ออก"}. -{"has been banned", "ถูกสั่งห้าม"}. -{"is now known as", "ซึ่งรู้จักกันในชื่อ"}. -{"Monday", "วันจันทร์"}. -{"Tuesday", "วันอังคาร"}. -{"Wednesday", "วันพุธ"}. -{"Thursday", "วันพฤหัสบดี"}. -{"Friday", "วันศุกร์"}. -{"Saturday", "วันเสาร์"}. -{"Sunday", "วันอาทิตย์"}. -{"January", "มกราคม"}. -{"February", "กุมภาพันธ์"}. -{"March", "มีนาคม"}. -{"April", "เมษายน"}. -{"May", "พฤษภาคม"}. -{"June", "มิถุนายน"}. -{"July", "กรกฎาคม"}. -{"August", "สิงหาคม"}. -{"September", "กันยายน"}. -{"October", "ตุลาคม"}. -{"November", "พฤศจิกายน"}. -{"December", "ธันวาคม"}. -{"Room Configuration", "การกำหนดค่าห้องสนทนา"}. - -% mod_offline.erl -{"Time", "เวลา"}. -{"From", "จาก"}. -{"To", "ถึง"}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","การกำหนดค่าการเข้าถึง"}. +{"Access Control List Configuration","การกำหนดค่ารายการควบคุมการเข้าถึง"}. +{"Access control lists","รายการควบคุมการเข้าถึง"}. +{"Access Control Lists","รายการควบคุมการเข้าถึง"}. +{"Access denied by service policy","การเข้าถึงถูกปฏิเสธโดยนโยบายการบริการ"}. +{"Access rules","กฎการเข้าถึง"}. +{"Access Rules","กฎการเข้าถึง"}. +{"Action on user","การดำเนินการกับผู้ใช้"}. +{"Add Jabber ID","เพิ่ม Jabber ID"}. +{"Add New","เพิ่มผู้ใช้ใหม่"}. +{"Add User","เพิ่มผู้ใช้"}. +{"Administration","การดูแล"}. +{"Administration of ","การดูแล "}. +{"Administrator privileges required","ต้องมีสิทธิพิเศษของผู้ดูแลระบบ"}. +{"All activity","กิจกรรมทั้งหมด"}. +{"Allow this JID to subscribe to this pubsub node?","อนุญาตให้ JID นี้เข้าร่วมเป็นสมาชิกของโหนด pubsub หรือไม่"}. +{"Allow users to change subject","อนุญาตให้ผู้ใช้เปลี่ยนหัวข้อได้"}. +{"Allow users to query other users","อนุญาตให้ผู้ใช้ถามคำถามกับผู้ใช้คนอื่นๆ ได้"}. +{"Allow users to send invites","อนุญาตให้ผู้ใช้ส่งคำเชิญถึงกันได้"}. +{"Allow users to send private messages","อนุญาตให้ผู้ใช้ส่งข้อความส่วนตัว"}. +{"All Users","ผู้ใช้ทั้งหมด"}. +{"Announcements","ประกาศ"}. +{"anyone","ทุกคน"}. +{"April","เมษายน"}. +{"August","สิงหาคม"}. +{"Backup","การสำรองข้อมูล "}. +{"Backup Management","การจัดการข้อมูลสำรอง"}. +{"Backup of ","การสำรองข้อมูล"}. +{"Backup to File at ","สำรองไฟล์ข้อมูลที่"}. +{"Bad format","รูปแบบที่ไม่ถูกต้อง"}. +{"Birthday","วันเกิด"}. +{"Change Password","เปลี่ยนรหัสผ่าน"}. +{"Change User Password","เปลี่ยนรหัสผ่านของผู้ใช้"}. +{"Chatroom configuration modified","มีการปรับเปลี่ยนการกำหนดค่าของห้องสนทนา"}. +{"Chatrooms","ห้องสนทนา"}. +{"Choose a username and password to register with this server","เลือกชื่อผู้ใช้และรหัสผ่านเพื่อลงทะเบียนกับเซิร์ฟเวอร์นี้"}. +{"Choose modules to stop","เลือกโมดูลเพื่อหยุดการทำงาน"}. +{"Choose storage type of tables","เลือกชนิดการจัดเก็บของตาราง"}. +{"Choose whether to approve this entity's subscription.","เลือกว่าจะอนุมัติการสมัครเข้าใช้งานของเอนทิตี้นี้หรือไม่"}. +{"City","เมือง"}. +{"Commands","คำสั่ง"}. +{"Conference room does not exist","ไม่มีห้องประชุม"}. +{"Configuration","การกำหนดค่า"}. +{"Configuration for ","การกำหนดค่าสำหรับ "}. +{"Connected Resources:","ทรัพยากรที่เชื่อมต่อ:"}. +{"Country","ประเทศ"}. +{"CPU Time:","เวลาการทำงานของ CPU:"}. +{"Database","ฐานข้อมูล"}. +{"Database Tables at ","ตารางฐานข้อมูลที่"}. +{"Database Tables Configuration at ","การกำหนดค่าตารางฐานข้อมูลที่"}. +{"December","ธันวาคม"}. +{"Default users as participants","ผู้ใช้เริ่มต้นเป็นผู้เข้าร่วม"}. +{"Delete","ลบ"}. +{"Delete message of the day","ลบข้อความของวัน"}. +{"Delete message of the day on all hosts","ลบข้อความของวันบนโฮสต์ทั้งหมด"}. +{"Delete Selected","ลบข้อความที่เลือก"}. +{"Delete User","ลบผู้ใช้"}. +{"Deliver event notifications","ส่งการแจ้งเตือนเหตุการณ์"}. +{"Deliver payloads with event notifications","ส่งส่วนของข้อมูล (payload) พร้อมกับการแจ้งเตือนเหตุการณ์"}. +{"Description:","รายละเอียด:"}. +{"Disc only copy","คัดลอกเฉพาะดิสก์"}. +{"Displayed Groups:","กลุ่มที่แสดง:"}. +{"Dump Backup to Text File at ","ถ่ายโอนการสำรองข้อมูลไปยังไฟล์ข้อความที่"}. +{"Dump to Text File","ถ่ายโอนข้อมูลไปยังไฟล์ข้อความ"}. +{"Edit Properties","แก้ไขคุณสมบัติ"}. +{"ejabberd IRC module","ejabberd IRC module"}. +{"ejabberd MUC module","ejabberd MUC module"}. +{"ejabberd Publish-Subscribe module","ejabberd Publish-Subscribe module"}. +{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestreams module"}. +{"ejabberd vCard module","ejabberd vCard module"}. +{"ejabberd virtual hosts","โฮสต์เสมือน ejabberd"}. +{"Email","อีเมล"}. +{"Enable logging","เปิดใช้งานการบันทึก"}. +{"Encodings","การเข้ารหัส"}. +{"End User Session","สิ้นสุดเซสชันของผู้ใช้"}. +{"Enter list of {Module, [Options]}","ป้อนรายการของ {โมดูล, [ตัวเลือก]}"}. +{"Enter nickname you want to register","ป้อนชื่อเล่นที่คุณต้องการลงทะเบียน"}. +{"Enter path to backup file","ป้อนพาธเพื่อสำรองไฟล์ข้อมูล"}. +{"Enter path to jabberd1.4 spool dir","ป้อนพาธไปยัง jabberd 1.4 spool dir"}. +{"Enter path to jabberd1.4 spool file","ป้อนพาธไปยังไฟล์เก็บพักข้อมูล jabberd 1.4"}. +{"Enter path to text file","ป้อนพาธของไฟล์ข้อความ"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","ป้อนชื่อผู้ใช้และการเข้ารหัสที่คุณต้องการใช้สำหรับเชื่อมต่อกับเซิร์ฟเวอร์ IRC"}. +{"Erlang Jabber Server","Erlang Jabber Server"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","ตัวอย่าง: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","นามสกุล"}. +{"February","กุมภาพันธ์"}. +{"Fill in fields to search for any matching Jabber User","กรอกข้อมูลลงในฟิลด์เพื่อค้นหาผู้ใช้ Jabber ที่ตรงกัน"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","กรอกข้อมูลในแบบฟอร์มเพื่อค้นหาผู้ใช้ Jabber ที่ตรงกัน (ใส่เครื่องหมาย * ที่ท้ายสุดของฟิลด์เพื่อจับคู่กับสตริงย่อย)"}. +{"Friday","วันศุกร์"}. +{"From","จาก"}. +{"From ~s","จาก ~s"}. +{"Full Name","ชื่อเต็ม"}. +{"Get Number of Online Users","แสดงจำนวนผู้ใช้ออนไลน์"}. +{"Get Number of Registered Users","แสดงจำนวนผู้ใช้ที่ลงทะเบียน"}. +{"Get User Last Login Time","แสดงเวลาเข้าสู่ระบบครั้งล่าสุดของผู้ใช้"}. +{"Get User Password","ขอรับรหัสผ่านของผู้ใช้"}. +{"Get User Statistics","แสดงสถิติของผู้ใช้"}. +{"Group ","กลุ่ม"}. +{"Groups","กลุ่ม"}. +{"has been banned","ถูกสั่งห้าม"}. +{"has been kicked","ถูกไล่ออก"}. +{" has set the subject to: "," ตั้งหัวข้อว่า: "}. +{"Host","โฮสต์"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","ถ้าคุณต้องการระบุการเข้ารหัสที่ต่างกันสำหรับเซิร์ฟเวอร์ IRC ให้กรอกค่าโดยใช้รูปแบบ '{\"irc server\", \"encoding\"}' ลงในรายการ การบริการนี้ใช้การเข้ารหัสในรูปแบบ \"~s\" โดยค่าดีฟอลต์ "}. +{"Import Directory","อิมพอร์ตไดเร็กทอรี"}. +{"Import File","อิมพอร์ตไฟล์"}. +{"Import User from File at ","อิมพอร์ตผู้ใช้จากไฟล์ที่"}. +{"Import Users from Dir at ","อิมพอร์ตผู้ใช้จาก Dir ที่"}. +{"Import Users From jabberd 1.4 Spool Files","อิมพอร์ตผู้ใช้จากไฟล์เก็บพักข้อมูล jabberd 1.4"}. +{"Improper message type","ประเภทข้อความไม่เหมาะสม"}. +{"Incorrect password","รหัสผ่านไม่ถูกต้อง"}. +{"Invalid affiliation: ~s","การเข้าร่วมที่ไม่ถูกต้อง: ~s"}. +{"Invalid role: ~s","บทบาทไม่ถูกต้อง: ~s"}. +{"IP addresses","ที่อยู่ IP"}. +{"IRC Transport","การส่ง IRC"}. +{"IRC Username","ชื่อผู้ใช้ IRC"}. +{"is now known as","ซึ่งรู้จักกันในชื่อ"}. +{"It is not allowed to send private messages of type \"groupchat\"","ไม่อนุญาตให้ส่งข้อความส่วนตัวไปยัง \"กลุ่มสนทนา\""}. +{"It is not allowed to send private messages to the conference","ไม่อนุญาตให้ส่งข้อความส่วนตัวไปยังห้องประชุม"}. +{"Jabber ID","Jabber ID"}. +{"January","มกราคม"}. +{"JID ~s is invalid","JID ~s ไม่ถูกต้อง"}. +{"joins the room","เข้าห้องสนทนานี้"}. +{"July","กรกฎาคม"}. +{"June","มิถุนายน"}. +{"Last Activity","กิจกรรมล่าสุด"}. +{"Last login","การเข้าสู่ระบบครั้งล่าสุด"}. +{"Last month","เดือนที่แล้ว"}. +{"Last year","ปีที่แล้ว"}. +{"leaves the room","ออกจากห้อง"}. +{"Listened Ports","พอร์ทฟัง"}. +{"Listened Ports at ","พอร์ทฟังที่"}. +{"List of modules to start","รายการของโมดูลที่จะเริ่มการทำงาน"}. +{"Low level update script","อัพเดตสคริปต์ระดับต่ำ"}. +{"Make participants list public","สร้างรายการผู้เข้าร่วมสำหรับใช้งานโดยบุคคลทั่วไป"}. +{"Make room members-only","สร้างห้องสำหรับสมาชิกเท่านั้น"}. +{"Make room password protected","สร้างห้องที่มีการป้องกันด้วยรหัสผ่าน"}. +{"Make room persistent","สร้างเป็นห้องถาวร"}. +{"Make room public searchable","สร้างเป็นห้องที่บุคคลทั่วไปสามารถค้นหาได้"}. +{"March","มีนาคม"}. +{"Maximum Number of Occupants","จำนวนผู้ครอบครองห้องสูงสุด"}. +{"Max # of items to persist","จำนวนสูงสุดของรายการที่ยืนยัน"}. +{"Max payload size in bytes","ขนาดสูงสุดของส่วนของข้อมูล (payload) มีหน่วยเป็นไบต์"}. +{"May","พฤษภาคม"}. +{"Members:","สมาชิก:"}. +{"Membership required to enter this room","ต้องเป็นสมาชิกจึงจะสามารถเข้าห้องนี้ได้"}. +{"Memory","หน่วยความจำ"}. +{"Message body","เนื้อหาของข้อความ"}. +{"Middle Name","ชื่อกลาง"}. +{"Moderator privileges required","ต้องมีสิทธิพิเศษของผู้ดูแลการสนทนา"}. +{"moderators only","สำหรับผู้ดูแลการสนทนาเท่านั้น"}. +{"Module","โมดูล"}. +{"Modules","โมดูล"}. +{"Modules at ","โมดูลที่ "}. +{"Monday","วันจันทร์"}. +{"Name:","ชื่อ:"}. +{"Name","ชื่อ"}. +{"Never","ไม่เคย"}. +{"Nickname","ชื่อเล่น"}. +{"Nickname is already in use by another occupant","ชื่อเล่นถูกใช้งานอยู่โดยผู้ครอบครองห้อง"}. +{"Nickname is registered by another person","ชื่อเล่นถูกลงทะเบียนใช้งานโดยบุคคลอื่น"}. +{"Nickname Registration at ","การลงทะเบียนชื่อเล่นที่ "}. +{"Nickname ~s does not exist in the room","ไม่มีชื่อเล่น ~s อยู่ในห้องนี้"}. +{"No body provided for announce message","ไม่ได้ป้อนเนื้อหาสำหรับข้อความที่ประกาศ"}. +{"No Data","ไม่มีข้อมูล"}. +{"Node ","โหนด "}. +{"Node ID","ID โหนด"}. +{"Node not found","ไม่พบโหนด"}. +{"Nodes","โหนด"}. +{"No limit","ไม่จำกัด"}. +{"None","ไม่มี"}. +{"No resource provided","ไม่ได้ระบุข้อมูล"}. +{"Notify subscribers when items are removed from the node","แจ้งเตือนผู้สมัครสมาชิกเมื่อรายการถูกลบออกจากโหนด"}. +{"Notify subscribers when the node configuration changes","แจ้งเตือนผู้สมัครสมาชิกเมื่อการกำหนดค่าโหนดเปลี่ยนแปลง"}. +{"Notify subscribers when the node is deleted","แจ้งเตือนผู้สมัครสมาชิกเมื่อโหนดถูกลบ"}. +{"November","พฤศจิกายน"}. +{"Number of occupants","จำนวนผู้ครอบครองห้อง"}. +{"Number of online users","จำนวนผู้ใช้ออนไลน์"}. +{"Number of registered users","จำนวนผู้ใช้ที่ลงทะเบียน"}. +{"October","ตุลาคม"}. +{"Offline Messages:","ข้อความออฟไลน์:"}. +{"Offline Messages","ข้อความออฟไลน์"}. +{"OK","ตกลง"}. +{"Online","ออนไลน์"}. +{"Online Users:","ผู้ใช้ออนไลน์:"}. +{"Online Users","ผู้ใช้ออนไลน์"}. +{"Only deliver notifications to available users","ส่งการแจ้งเตือนถึงผู้ใช้ที่สามารถติดต่อได้เท่านั้น"}. +{"Only moderators and participants are allowed to change subject in this room","ผู้ดูแลการสนทนาและผู้เข้าร่วมเท่านั้นที่ได้รับอนุญาตให้เปลี่ยนหัวข้อในห้องนี้"}. +{"Only moderators are allowed to change subject in this room","ผู้ดูแลการสนทนาเท่านั้นที่ได้รับอนุญาตให้เปลี่ยนหัวข้อในห้องนี้"}. +{"Only occupants are allowed to send messages to the conference","ผู้ครอบครองห้องเท่านั้นที่ได้รับอนุญาตให้ส่งข้อความไปยังห้องประชุม"}. +{"Only occupants are allowed to send queries to the conference","ผู้ครอบครองห้องเท่านั้นที่ได้รับอนุญาตให้ส่งกระทู้ถามไปยังห้องประชุม"}. +{"Only service administrators are allowed to send service messages","ผู้ดูแลด้านการบริการเท่านั้นที่ได้รับอนุญาตให้ส่งข้อความการบริการ"}. +{"Options","ตัวเลือก"}. +{"Organization Name","ชื่อองค์กร"}. +{"Organization Unit","หน่วยขององค์กร"}. +{"Outgoing s2s Connections:","การเชื่อมต่อ s2s ขาออก:"}. +{"Outgoing s2s Connections","การเชื่อมต่อ s2s ขาออก"}. +{"Outgoing s2s Servers:","เซิร์ฟเวอร์ s2s ขาออก:"}. +{"Owner privileges required","ต้องมีสิทธิพิเศษของเจ้าของ"}. +{"Packet","แพ็กเก็ต"}. +{"Password:","รหัสผ่าน:"}. +{"Password","รหัสผ่าน"}. +{"Password required to enter this room","ต้องใส่รหัสผ่านเพื่อเข้าห้องนี้"}. +{"Password Verification","การตรวจสอบรหัสผ่าน"}. +{"Path to Dir","พาธไปยัง Dir"}. +{"Path to File","พาธของไฟล์ข้อมูล"}. +{"Pending","ค้างอยู่"}. +{"Period: ","ระยะเวลา:"}. +{"Persist items to storage","ยืนยันรายการที่จะจัดเก็บ"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","พอร์ท"}. +{"Present real JIDs to","แสดง JIDs ที่ถูกต้องแก่"}. +{"private, ","ส่วนตัว, "}. +{"Publish-Subscribe","เผยแพร่-สมัครเข้าใช้งาน"}. +{"PubSub subscriber request","คำร้องขอของผู้สมัครเข้าใช้งาน PubSub"}. +{"Queries to the conference members are not allowed in this room","ห้องนี้ไม่อนุญาตให้ส่งกระทู้ถามถึงสมาชิกในห้องประชุม"}. +{"RAM and disc copy","คัดลอก RAM และดิสก์"}. +{"RAM copy","คัดลอก RAM"}. +{"(Raw)","(ข้อมูลดิบ)"}. +{"Raw","ข้อมูลดิบ"}. +{"Really delete message of the day?","แน่ใจว่าต้องการลบข้อความของวันหรือไม่"}. +{"Recipient is not in the conference room","ผู้รับไม่ได้อยู่ในห้องประชุม"}. +{"Registered Users:","ผู้ใช้ที่ลงทะเบียน:"}. +{"Registered Users","ผู้ใช้ที่ลงทะเบียน"}. +{"Registration in mod_irc for ","การลงทะเบียนใน mod_irc สำหรับ"}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","โปรดทราบว่าตัวเลือกเหล่านี้จะสำรองข้อมูลในฐานข้อมูล builtin Mnesia เท่านั้น หากคุณใช้โมดูล ODBC คุณต้องสำรองข้อมูลของฐานข้อมูล SQL แยกต่างหากด้วย"}. +{"Remote copy","คัดลอกระยะไกล"}. +{"Remove","ลบ"}. +{"Remove User","ลบผู้ใช้"}. +{"Replaced by new connection","แทนที่ด้วยการเชื่อมต่อใหม่"}. +{"Resources","ทรัพยากร"}. +{"Restart","เริ่มต้นใหม่"}. +{"Restart Service","เริ่มต้นการบริการใหม่อีกครั้ง"}. +{"Restore","การคืนค่า"}. +{"Restore Backup from File at ","คืนค่าการสำรองข้อมูลจากไฟล์ที่"}. +{"Restore binary backup after next ejabberd restart (requires less memory):","คืนค่าข้อมูลสำรองแบบไบนารีหลังจากที่ ejabberd ถัดไปเริ่มการทำงานใหม่ (ใช้หน่วยความจำน้อยลง):"}. +{"Restore binary backup immediately:","คืนค่าข้อมูลสำรองแบบไบนารีโดยทันที:"}. +{"Restore plain text backup immediately:","คืนค่าข้อมูลสำรองที่เป็นข้อความธรรมดาโดยทันที:"}. +{"Room Configuration","การกำหนดค่าห้องสนทนา"}. +{"Room creation is denied by service policy","การสร้างห้องสนทนาถูกปฏิเสธโดยนโยบายการบริการ"}. +{"Room title","ชื่อห้อง"}. +{"Roster","บัญชีรายชื่อ"}. +{"Roster of ","บัญชีรายชื่อของ "}. +{"Roster size","ขนาดของบัญชีรายชื่อ"}. +{"RPC Call Error","ข้อผิดพลาดจากการเรียกใช้ RPC"}. +{"Running Nodes","โหนดที่ทำงาน"}. +{"~s access rule configuration","~s การกำหนดค่ากฎการเข้าถึง"}. +{"Saturday","วันเสาร์"}. +{"Script check","ตรวจสอบคริปต์"}. +{"Search Results for ","ผลการค้นหาสำหรับ "}. +{"Search users in ","ค้นหาผู้ใช้ใน "}. +{"Send announcement to all online users","ส่งประกาศถึงผู้ใช้ออนไลน์ทั้งหมด"}. +{"Send announcement to all online users on all hosts","ส่งประกาศถึงผู้ใช้ออนไลน์ทั้งหมดบนโฮสต์ทั้งหมด"}. +{"Send announcement to all users","ส่งประกาศถึงผู้ใช้ทั้งหมด"}. +{"Send announcement to all users on all hosts","ส่งประกาศถึงผู้ใช้ทั้งหมดบนโฮสต์ทั้งหมด"}. +{"September","กันยายน"}. +{"Set message of the day and send to online users","ตั้งค่าข้อความของวันและส่งถึงผู้ใช้ออนไลน์"}. +{"Set message of the day on all hosts and send to online users","ตั้งค่าข้อความของวันบนโฮสต์ทั้งหมดและส่งถึงผู้ใช้ออนไลน์"}. +{"Shared Roster Groups","กลุ่มบัญชีรายชื่อที่ใช้งานร่วมกัน"}. +{"Show Integral Table","แสดงตารางรวม"}. +{"Show Ordinary Table","แสดงตารางทั่วไป"}. +{"Shut Down Service","ปิดการบริการ"}. +{"~s invites you to the room ~s","~s เชิญคุณเข้าร่วมสนทนาในห้อง ~s"}. +{"Size","ขนาด"}. +{"Specified nickname is already registered","ชื่อเล่นที่ระบุได้รับการลงได้ทะเบียนแล้ว"}. +{"Specify the access model","ระบุโมเดลการเข้าถึง"}. +{"Specify the publisher model","ระบุโมเดลผู้เผยแพร่"}. +{"~s's Offline Messages Queue","~s's ลำดับข้อความออฟไลน์"}. +{"Start","เริ่ม"}. +{"Start Modules","เริ่มโมดูล"}. +{"Start Modules at ","เริ่มโมดูลที่"}. +{"Statistics","สถิติ"}. +{"Statistics of ~p","สถิติของ ~p"}. +{"Stop","หยุด"}. +{"Stop Modules","หยุดโมดูล"}. +{"Stop Modules at ","หยุดโมดูลที่"}. +{"Stopped Nodes","โหนดที่หยุด"}. +{"Storage Type","ชนิดที่เก็บข้อมูล"}. +{"Store binary backup:","จัดเก็บข้อมูลสำรองแบบไบนารี:"}. +{"Store plain text backup:","จัดเก็บข้อมูลสำรองที่เป็นข้อความธรรมดา:"}. +{"Subject","หัวเรื่อง"}. +{"Submit","ส่ง"}. +{"Submitted","ส่งแล้ว"}. +{"Subscriber Address","ที่อยู่ของผู้สมัคร"}. +{"Subscription","การสมัครสมาชิก"}. +{"Sunday","วันอาทิตย์"}. +{"the password is","รหัสผ่านคือ"}. +{"This room is not anonymous","ห้องนี้ไม่ปิดบังชื่อ"}. +{"Thursday","วันพฤหัสบดี"}. +{"Time","เวลา"}. +{"Time delay","การหน่วงเวลา"}. +{"To","ถึง"}. +{"To ~s","ถึง ~s"}. +{"Traffic rate limit is exceeded","อัตราของปริมาณการเข้าใช้เกินขีดจำกัด"}. +{"Transactions Aborted:","ทรานแซกชันที่ถูกยกเลิก:"}. +{"Transactions Commited:","ทรานแซกชันที่ได้รับมอบหมาย:"}. +{"Transactions Logged:","ทรานแซกชันที่บันทึก:"}. +{"Transactions Restarted:","ทรานแซกชันที่เริ่มทำงานใหม่อีกครั้ง:"}. +{"Tuesday","วันอังคาร"}. +{"Update ","อัพเดต "}. +{"Update","อัพเดต"}. +{"Updated modules","โมดูลที่อัพเดต"}. +{"Update message of the day (don't send)","อัพเดตข้อความของวัน (ไม่ต้องส่ง)"}. +{"Update message of the day on all hosts (don't send)","อัพเดตข้อความของวันบนโฮสต์ทั้งหมด (ไม่ต้องส่ง) "}. +{"Update plan","แผนการอัพเดต"}. +{"Update script","อัพเดตสคริปต์"}. +{"Uptime:","เวลาการทำงานต่อเนื่อง:"}. +{"Use of STARTTLS required","ต้องใช้ STARTTLS"}. +{"User ","ผู้ใช้"}. +{"User","ผู้ใช้"}. +{"User Management","การจัดการผู้ใช้"}. +{"Users","ผู้ใช้"}. +{"Users Last Activity","กิจกรรมล่าสุดของผู้ใช้"}. +{"Validate","ตรวจสอบ"}. +{"vCard User Search","ค้นหาผู้ใช้ vCard "}. +{"Virtual Hosts","โฮสต์เสมือน"}. +{"Visitors are not allowed to send messages to all occupants","ผู้เยี่ยมเยือนไม่ได้รับอนุญาตให้ส่งข้อความถึงผู้ครอบครองห้องทั้งหมด"}. +{"Wednesday","วันพุธ"}. +{"When to send the last published item","เวลาที่ส่งรายการที่เผยแพร่ครั้งล่าสุด"}. +{"Whether to allow subscriptions","อนุญาตให้เข้าร่วมเป็นสมาชิกหรือไม่"}. +{"You have been banned from this room","คุณถูกสั่งห้ามไมให้เข้าห้องนี้"}. +{"You must fill in field \"Nickname\" in the form","คุณต้องกรอกฟิลด์ \"Nickname\" ในแบบฟอร์ม"}. +{"You need an x:data capable client to configure mod_irc settings","คุณต้องใช้ไคลเอ็นต์ที่รองรับ x:data เพื่อกำหนดการตั้งค่า mod_irc"}. +{"You need an x:data capable client to configure room","คุณต้องใช้ไคลเอ็นต์ที่รองรับ x:data เพื่อกำหนดค่าห้องสนทนา "}. +{"You need an x:data capable client to register nickname","คุณต้องใช้ไคลเอ็นต์ที่รองรับ x:data เพื่อลงทะเบียนชื่อเล่น"}. +{"You need an x:data capable client to search","คุณต้องใช้ไคลเอ็นต์ที่รองรับ x:data เพื่อค้นหา"}. +{"Your contact offline message queue is full. The message has been discarded.","ลำดับข้อความออฟไลน์ของผู้ที่ติดต่อของคุณเต็มแล้ว ข้อความถูกลบทิ้งแล้ว"}. diff --git a/src/msgs/th.po b/src/msgs/th.po new file mode 100644 index 000000000..de3beb8ce --- /dev/null +++ b/src/msgs/th.po @@ -0,0 +1,1488 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: EQHO Communications (Thailand) Ltd. - http://www.eqho.com\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Thai (ภาษาไทย)\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "ต้องใช้ STARTTLS" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "ไม่ได้ระบุข้อมูล" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "แทนที่ด้วยการเชื่อมต่อใหม่" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "คำสั่ง" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "แน่ใจว่าต้องการลบข้อความของวันหรือไม่" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "หัวเรื่อง" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "เนื้อหาของข้อความ" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "ไม่ได้ป้อนเนื้อหาสำหรับข้อความที่ประกาศ" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "ประกาศ" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "ส่งประกาศถึงผู้ใช้ทั้งหมด" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "ส่งประกาศถึงผู้ใช้ทั้งหมดบนโฮสต์ทั้งหมด" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "ส่งประกาศถึงผู้ใช้ออนไลน์ทั้งหมด" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "ส่งประกาศถึงผู้ใช้ออนไลน์ทั้งหมดบนโฮสต์ทั้งหมด" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "ตั้งค่าข้อความของวันและส่งถึงผู้ใช้ออนไลน์" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "ตั้งค่าข้อความของวันบนโฮสต์ทั้งหมดและส่งถึงผู้ใช้ออนไลน์" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "อัพเดตข้อความของวัน (ไม่ต้องส่ง)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "อัพเดตข้อความของวันบนโฮสต์ทั้งหมด (ไม่ต้องส่ง) " + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "ลบข้อความของวัน" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "ลบข้อความของวันบนโฮสต์ทั้งหมด" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "การกำหนดค่า" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "ฐานข้อมูล" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "เริ่มโมดูล" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "หยุดโมดูล" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "การสำรองข้อมูล " + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "การคืนค่า" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "ถ่ายโอนข้อมูลไปยังไฟล์ข้อความ" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "อิมพอร์ตไฟล์" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "อิมพอร์ตไดเร็กทอรี" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "เริ่มต้นการบริการใหม่อีกครั้ง" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "ปิดการบริการ" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "เพิ่มผู้ใช้" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "ลบผู้ใช้" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "สิ้นสุดเซสชันของผู้ใช้" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "ขอรับรหัสผ่านของผู้ใช้" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "เปลี่ยนรหัสผ่านของผู้ใช้" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "แสดงเวลาเข้าสู่ระบบครั้งล่าสุดของผู้ใช้" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "แสดงสถิติของผู้ใช้" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "แสดงจำนวนผู้ใช้ที่ลงทะเบียน" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "แสดงจำนวนผู้ใช้ออนไลน์" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "รายการควบคุมการเข้าถึง" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "กฎการเข้าถึง" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "การจัดการผู้ใช้" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "ผู้ใช้ออนไลน์" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "ผู้ใช้ทั้งหมด" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "การเชื่อมต่อ s2s ขาออก" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "โหนดที่ทำงาน" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "โหนดที่หยุด" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "โมดูล" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "การจัดการข้อมูลสำรอง" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "อิมพอร์ตผู้ใช้จากไฟล์เก็บพักข้อมูล jabberd 1.4" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "ถึง ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "จาก ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "การกำหนดค่าตารางฐานข้อมูลที่" + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "เลือกชนิดการจัดเก็บของตาราง" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "คัดลอกเฉพาะดิสก์" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "คัดลอก RAM และดิสก์" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "คัดลอก RAM" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "คัดลอกระยะไกล" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "หยุดโมดูลที่" + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "เลือกโมดูลเพื่อหยุดการทำงาน" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "เริ่มโมดูลที่" + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "ป้อนรายการของ {โมดูล, [ตัวเลือก]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "รายการของโมดูลที่จะเริ่มการทำงาน" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "สำรองไฟล์ข้อมูลที่" + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "ป้อนพาธเพื่อสำรองไฟล์ข้อมูล" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "พาธของไฟล์ข้อมูล" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "คืนค่าการสำรองข้อมูลจากไฟล์ที่" + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "ถ่ายโอนการสำรองข้อมูลไปยังไฟล์ข้อความที่" + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "ป้อนพาธของไฟล์ข้อความ" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "อิมพอร์ตผู้ใช้จากไฟล์ที่" + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "ป้อนพาธไปยังไฟล์เก็บพักข้อมูล jabberd 1.4" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "อิมพอร์ตผู้ใช้จาก Dir ที่" + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "ป้อนพาธไปยัง jabberd 1.4 spool dir" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "พาธไปยัง Dir" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "การหน่วงเวลา" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "การกำหนดค่ารายการควบคุมการเข้าถึง" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "รายการควบคุมการเข้าถึง" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "การกำหนดค่าการเข้าถึง" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "กฎการเข้าถึง" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "รหัสผ่าน" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "การตรวจสอบรหัสผ่าน" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "จำนวนผู้ใช้ที่ลงทะเบียน" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "จำนวนผู้ใช้ออนไลน์" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "ไม่เคย" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "ออนไลน์" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "การเข้าสู่ระบบครั้งล่าสุด" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "ขนาดของบัญชีรายชื่อ" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "ที่อยู่ IP" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "ทรัพยากร" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "การดูแล " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "การดำเนินการกับผู้ใช้" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "แก้ไขคุณสมบัติ" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "ลบผู้ใช้" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "การเข้าถึงถูกปฏิเสธโดยนโยบายการบริการ" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "การส่ง IRC" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "ejabberd IRC module" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "คุณต้องใช้ไคลเอ็นต์ที่รองรับ x:data เพื่อกำหนดการตั้งค่า mod_irc" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "การลงทะเบียนใน mod_irc สำหรับ" + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "ป้อนชื่อผู้ใช้และการเข้ารหัสที่คุณต้องการใช้สำหรับเชื่อมต่อกับเซิร์ฟเวอร์ IRC" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "ชื่อผู้ใช้ IRC" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"ถ้าคุณต้องการระบุการเข้ารหัสที่ต่างกันสำหรับเซิร์ฟเวอร์ IRC ให้กรอกค่าโดยใช้รูปแบบ '{\"irc " +"server\", \"encoding\"}' ลงในรายการ การบริการนี้ใช้การเข้ารหัสในรูปแบบ \"~s\" " +"โดยค่าดีฟอลต์ " + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"ตัวอย่าง: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "การเข้ารหัส" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "ผู้ดูแลด้านการบริการเท่านั้นที่ได้รับอนุญาตให้ส่งข้อความการบริการ" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "การสร้างห้องสนทนาถูกปฏิเสธโดยนโยบายการบริการ" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "ไม่มีห้องประชุม" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "ห้องสนทนา" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "คุณต้องใช้ไคลเอ็นต์ที่รองรับ x:data เพื่อลงทะเบียนชื่อเล่น" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "การลงทะเบียนชื่อเล่นที่ " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "ป้อนชื่อเล่นที่คุณต้องการลงทะเบียน" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "ชื่อเล่น" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "ชื่อเล่นที่ระบุได้รับการลงได้ทะเบียนแล้ว" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "คุณต้องกรอกฟิลด์ \"Nickname\" ในแบบฟอร์ม" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "ejabberd MUC module" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "มีการปรับเปลี่ยนการกำหนดค่าของห้องสนทนา" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "เข้าห้องสนทนานี้" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "ออกจากห้อง" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "ถูกสั่งห้าม" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "ถูกไล่ออก" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "ซึ่งรู้จักกันในชื่อ" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " ตั้งหัวข้อว่า: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "วันจันทร์" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "วันอังคาร" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "วันพุธ" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "วันพฤหัสบดี" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "วันศุกร์" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "วันเสาร์" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "วันอาทิตย์" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "มกราคม" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "กุมภาพันธ์" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "มีนาคม" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "เมษายน" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "พฤษภาคม" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "มิถุนายน" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "กรกฎาคม" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "สิงหาคม" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "กันยายน" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "ตุลาคม" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "พฤศจิกายน" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "ธันวาคม" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "การกำหนดค่าห้องสนทนา" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "ชื่อห้อง" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "อัตราของปริมาณการเข้าใช้เกินขีดจำกัด" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "ไม่อนุญาตให้ส่งข้อความส่วนตัวไปยังห้องประชุม" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "ประเภทข้อความไม่เหมาะสม" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "ไม่อนุญาตให้ส่งข้อความส่วนตัวไปยัง \"กลุ่มสนทนา\"" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "ผู้รับไม่ได้อยู่ในห้องประชุม" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "ผู้ครอบครองห้องเท่านั้นที่ได้รับอนุญาตให้ส่งข้อความไปยังห้องประชุม" + +#: mod_muc/mod_muc_room.erl:528 +#, fuzzy +msgid "It is not allowed to send private messages" +msgstr "ไม่อนุญาตให้ส่งข้อความส่วนตัวไปยังห้องประชุม" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "ผู้ครอบครองห้องเท่านั้นที่ได้รับอนุญาตให้ส่งกระทู้ถามไปยังห้องประชุม" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "ห้องนี้ไม่อนุญาตให้ส่งกระทู้ถามถึงสมาชิกในห้องประชุม" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "ส่วนตัว, " + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "ผู้ดูแลการสนทนาและผู้เข้าร่วมเท่านั้นที่ได้รับอนุญาตให้เปลี่ยนหัวข้อในห้องนี้" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "ผู้ดูแลการสนทนาเท่านั้นที่ได้รับอนุญาตให้เปลี่ยนหัวข้อในห้องนี้" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "ผู้เยี่ยมเยือนไม่ได้รับอนุญาตให้ส่งข้อความถึงผู้ครอบครองห้องทั้งหมด" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" + +#: mod_muc/mod_muc_room.erl:949 +#, fuzzy +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "ผู้ดูแลการสนทนาเท่านั้นที่ได้รับอนุญาตให้เปลี่ยนหัวข้อในห้องนี้" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "ชื่อเล่นถูกใช้งานอยู่โดยผู้ครอบครองห้อง" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "ชื่อเล่นถูกลงทะเบียนใช้งานโดยบุคคลอื่น" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "คุณถูกสั่งห้ามไมให้เข้าห้องนี้" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "ต้องเป็นสมาชิกจึงจะสามารถเข้าห้องนี้ได้" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "ห้องนี้ไม่ปิดบังชื่อ" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "ต้องใส่รหัสผ่านเพื่อเข้าห้องนี้" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "รหัสผ่านไม่ถูกต้อง" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "ต้องมีสิทธิพิเศษของผู้ดูแลระบบ" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "ต้องมีสิทธิพิเศษของผู้ดูแลการสนทนา" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "JID ~s ไม่ถูกต้อง" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "ไม่มีชื่อเล่น ~s อยู่ในห้องนี้" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "การเข้าร่วมที่ไม่ถูกต้อง: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "บทบาทไม่ถูกต้อง: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "ต้องมีสิทธิพิเศษของเจ้าของ" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "การกำหนดค่าสำหรับ " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "รายละเอียด:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "สร้างเป็นห้องถาวร" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "สร้างเป็นห้องที่บุคคลทั่วไปสามารถค้นหาได้" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "สร้างรายการผู้เข้าร่วมสำหรับใช้งานโดยบุคคลทั่วไป" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "สร้างห้องที่มีการป้องกันด้วยรหัสผ่าน" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "จำนวนผู้ครอบครองห้องสูงสุด" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "ไม่จำกัด" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "แสดง JIDs ที่ถูกต้องแก่" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "สำหรับผู้ดูแลการสนทนาเท่านั้น" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "ทุกคน" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "สร้างห้องสำหรับสมาชิกเท่านั้น" + +#: mod_muc/mod_muc_room.erl:2748 +#, fuzzy +msgid "Make room moderated" +msgstr "สร้างเป็นห้องถาวร" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "ผู้ใช้เริ่มต้นเป็นผู้เข้าร่วม" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "อนุญาตให้ผู้ใช้เปลี่ยนหัวข้อได้" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "อนุญาตให้ผู้ใช้ส่งข้อความส่วนตัว" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "อนุญาตให้ผู้ใช้ถามคำถามกับผู้ใช้คนอื่นๆ ได้" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "อนุญาตให้ผู้ใช้ส่งคำเชิญถึงกันได้" + +#: mod_muc/mod_muc_room.erl:2766 +#, fuzzy +msgid "Allow visitors to send status text in presence updates" +msgstr "อนุญาตให้ผู้ใช้ส่งข้อความส่วนตัว" + +#: mod_muc/mod_muc_room.erl:2769 +#, fuzzy +msgid "Allow visitors to change nickname" +msgstr "อนุญาตให้ผู้ใช้เปลี่ยนหัวข้อได้" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "เปิดใช้งานการบันทึก" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "คุณต้องใช้ไคลเอ็นต์ที่รองรับ x:data เพื่อกำหนดค่าห้องสนทนา " + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "จำนวนผู้ครอบครองห้อง" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s เชิญคุณเข้าร่วมสนทนาในห้อง ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "รหัสผ่านคือ" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "ลำดับข้อความออฟไลน์ของผู้ที่ติดต่อของคุณเต็มแล้ว ข้อความถูกลบทิ้งแล้ว" + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "~s's ลำดับข้อความออฟไลน์" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "ส่งแล้ว" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "เวลา" + +#: mod_offline.erl:507 +msgid "From" +msgstr "จาก" + +#: mod_offline.erl:508 +msgid "To" +msgstr "ถึง" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "แพ็กเก็ต" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "ลบข้อความที่เลือก" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "ข้อความออฟไลน์:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "ejabberd SOCKS5 Bytestreams module" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "เผยแพร่-สมัครเข้าใช้งาน" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "ejabberd Publish-Subscribe module" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "คำร้องขอของผู้สมัครเข้าใช้งาน PubSub" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "เลือกว่าจะอนุมัติการสมัครเข้าใช้งานของเอนทิตี้นี้หรือไม่" + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "ID โหนด" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "ที่อยู่ของผู้สมัคร" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "อนุญาตให้ JID นี้เข้าร่วมเป็นสมาชิกของโหนด pubsub หรือไม่" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "ส่งส่วนของข้อมูล (payload) พร้อมกับการแจ้งเตือนเหตุการณ์" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "ส่งการแจ้งเตือนเหตุการณ์" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "แจ้งเตือนผู้สมัครสมาชิกเมื่อการกำหนดค่าโหนดเปลี่ยนแปลง" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "แจ้งเตือนผู้สมัครสมาชิกเมื่อโหนดถูกลบ" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "แจ้งเตือนผู้สมัครสมาชิกเมื่อรายการถูกลบออกจากโหนด" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "ยืนยันรายการที่จะจัดเก็บ" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "จำนวนสูงสุดของรายการที่ยืนยัน" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "อนุญาตให้เข้าร่วมเป็นสมาชิกหรือไม่" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "ระบุโมเดลการเข้าถึง" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "ระบุโมเดลผู้เผยแพร่" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "ขนาดสูงสุดของส่วนของข้อมูล (payload) มีหน่วยเป็นไบต์" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "เวลาที่ส่งรายการที่เผยแพร่ครั้งล่าสุด" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "ส่งการแจ้งเตือนถึงผู้ใช้ที่สามารถติดต่อได้เท่านั้น" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "เลือกชื่อผู้ใช้และรหัสผ่านเพื่อลงทะเบียนกับเซิร์ฟเวอร์นี้" + +#: mod_register.erl:232 +#, fuzzy +msgid "Users are not allowed to register accounts so fast" +msgstr "ผู้เยี่ยมเยือนไม่ได้รับอนุญาตให้ส่งข้อความถึงผู้ครอบครองห้องทั้งหมด" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "ไม่มี" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "การสมัครสมาชิก" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "ค้างอยู่" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "กลุ่ม" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "ตรวจสอบ" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "ลบ" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "บัญชีรายชื่อของ " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "รูปแบบที่ไม่ถูกต้อง" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "เพิ่ม Jabber ID" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "บัญชีรายชื่อ" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "กลุ่มบัญชีรายชื่อที่ใช้งานร่วมกัน" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "เพิ่มผู้ใช้ใหม่" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "ชื่อ:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "รายละเอียด:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "สมาชิก:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "กลุ่มที่แสดง:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "กลุ่ม" + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "ส่ง" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Erlang Jabber Server" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "วันเกิด" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "เมือง" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "ประเทศ" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "อีเมล" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "นามสกุล" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"กรอกข้อมูลในแบบฟอร์มเพื่อค้นหาผู้ใช้ Jabber ที่ตรงกัน (ใส่เครื่องหมาย * " +"ที่ท้ายสุดของฟิลด์เพื่อจับคู่กับสตริงย่อย)" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "ชื่อเต็ม" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "ชื่อกลาง" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "ชื่อ" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "ชื่อองค์กร" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "หน่วยขององค์กร" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "ค้นหาผู้ใช้ใน " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "ผู้ใช้" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "คุณต้องใช้ไคลเอ็นต์ที่รองรับ x:data เพื่อค้นหา" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "ค้นหาผู้ใช้ vCard " + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "ejabberd vCard module" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "ผลการค้นหาสำหรับ " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "กรอกข้อมูลลงในฟิลด์เพื่อค้นหาผู้ใช้ Jabber ที่ตรงกัน" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +#, fuzzy +msgid "ejabberd Web Admin" +msgstr "เว็บอินเทอร์เฟซของ ejabberd" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "การดูแล" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "โฮสต์เสมือน" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "โหนด" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "สถิติ" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "ผู้ใช้" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "กิจกรรมล่าสุด" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(ข้อมูลดิบ)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "ข้อมูลดิบ" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "~s การกำหนดค่ากฎการเข้าถึง" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "โฮสต์เสมือน ejabberd" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "กิจกรรมล่าสุดของผู้ใช้" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "ระยะเวลา:" + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "เดือนที่แล้ว" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "ปีที่แล้ว" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "กิจกรรมทั้งหมด" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "แสดงตารางทั่วไป" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "แสดงตารางรวม" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "ไม่พบโหนด" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "โฮสต์" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "ผู้ใช้ที่ลงทะเบียน" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "ข้อความออฟไลน์" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "ผู้ใช้ที่ลงทะเบียน:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "ผู้ใช้ออนไลน์:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "การเชื่อมต่อ s2s ขาออก:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "เซิร์ฟเวอร์ s2s ขาออก:" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "เปลี่ยนรหัสผ่าน" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "ผู้ใช้" + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "ทรัพยากรที่เชื่อมต่อ:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "รหัสผ่าน:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "ไม่มีข้อมูล" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "โหนด " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "พอร์ทฟัง" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "อัพเดต" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "เริ่มต้นใหม่" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "หยุด" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "ข้อผิดพลาดจากการเรียกใช้ RPC" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "ตารางฐานข้อมูลที่" + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "ชนิดที่เก็บข้อมูล" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "ขนาด" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "หน่วยความจำ" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "การสำรองข้อมูล" + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"โปรดทราบว่าตัวเลือกเหล่านี้จะสำรองข้อมูลในฐานข้อมูล builtin Mnesia เท่านั้น หากคุณใช้โมดูล " +"ODBC คุณต้องสำรองข้อมูลของฐานข้อมูล SQL แยกต่างหากด้วย" + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "จัดเก็บข้อมูลสำรองแบบไบนารี:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "ตกลง" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "คืนค่าข้อมูลสำรองแบบไบนารีโดยทันที:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"คืนค่าข้อมูลสำรองแบบไบนารีหลังจากที่ ejabberd ถัดไปเริ่มการทำงานใหม่ (ใช้หน่วยความจำน้อยลง):" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "จัดเก็บข้อมูลสำรองที่เป็นข้อความธรรมดา:" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "คืนค่าข้อมูลสำรองที่เป็นข้อความธรรมดาโดยทันที:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "พอร์ทฟังที่" + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "โมดูลที่ " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "สถิติของ ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "เวลาการทำงานต่อเนื่อง:" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "เวลาการทำงานของ CPU:" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "ทรานแซกชันที่ได้รับมอบหมาย:" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "ทรานแซกชันที่ถูกยกเลิก:" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "ทรานแซกชันที่เริ่มทำงานใหม่อีกครั้ง:" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "ทรานแซกชันที่บันทึก:" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "อัพเดต " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "แผนการอัพเดต" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "โมดูลที่อัพเดต" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "อัพเดตสคริปต์" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "อัพเดตสคริปต์ระดับต่ำ" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "ตรวจสอบคริปต์" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "พอร์ท" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "โมดูล" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "ตัวเลือก" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "ลบ" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "เริ่ม" + +#~ msgid "Roster groups that may subscribe (if access model is roster)" +#~ msgstr "กลุ่มบัญชีรายชื่อที่อาจจะสมัครเป็นสมาชิก (ถ้าโมเดลการเข้าถึงคือบัญชีรายชื่อ)" diff --git a/src/msgs/tr.msg b/src/msgs/tr.msg index d1b05d3a7..26bdf85f8 100644 --- a/src/msgs/tr.msg +++ b/src/msgs/tr.msg @@ -1,391 +1,343 @@ -% $Id$ -% Language: Turkish (türkçe) -% Author: Doruk Fisek - -% jlib.hrl -{"No resource provided", "Hiç kaynak sağlanmadı"}. - -% mod_configure.erl -{"Restart Service", "Servisi Tekrar Başlat"}. -{"Shut Down Service", "Servisi Kapat"}. -{"Delete User", "Kullanıcıyı Sil"}. -{"End User Session", "Kullanıcı Oturumunu Kapat"}. -{"Get User Password", "Kullanıcı Parolasını Al"}. -{"Change User Password", "Kullanıcı Parolasını Değiştir"}. -{"Get User Last Login Time", "Kullanıcı Son Giriş Zamanınlarını Al"}. -{"Get User Statistics", "Kullanıcı İstatistiklerini Al"}. -{"Get Number of Registered Users", "Kayıtlı Kullanıcı Sayısını Al"}. -{"Get Number of Online Users", "Bağlı Kullanıcı Sayısını Al"}. -{"User Management", "Kullanıcı Yönetimi"}. -{"Time delay", "Zaman gecikmesi"}. -{"Password Verification", "Parola Doğrulaması"}. -{"Number of registered users", "Kayıtlı kullanıcı sayısı"}. -{"Number of online users", "Bağlı kullanıcı sayısı"}. -{"Last login", "Son giriş"}. -{"Roster size", "İsim listesi boyutu"}. -{"IP addresses", "IP adresleri"}. -{"Resources", "Kaynaklar"}. -{"Choose storage type of tables", "Tabloların veri depolama tipini seçiniz"}. -{"RAM copy", "RAM kopyala"}. -{"RAM and disc copy", "RAM ve disk kopyala"}. -{"Disc only copy", "Sadece disk kopyala"}. -{"Remote copy", "Uzak kopyala"}. -{"Stop Modules at ", "Modülleri Durdur : "}. -{"Choose modules to stop", "Durdurulacak modülleri seçiniz"}. -{"Start Modules at ", "Modülleri Başlat : "}. -{"Enter list of {Module, [Options]}", "{Module, [Options]} listesi giriniz"}. -{"List of modules to start", "Başlatılacak modüllerin listesi"}. -{"Backup to File at ", "Dosyaya Yedekle : "}. -{"Enter path to backup file", "Yedek dosyasının yolunu giriniz"}. -{"Path to File", "Dosyanın Yolu"}. -{"Restore Backup from File at ", "Dosyadaki Yedekten Geri Al : "}. -{"Dump Backup to Text File at ", "Metin Dosyasına Döküm Alarak Yedekle : "}. -{"Enter path to text file", "Metin dosyasının yolunu giriniz"}. -{"Import User from File at ", "Dosyadan Kullanıcıları İçe Aktar : "}. -{"Enter path to jabberd1.4 spool file", "jabberd1.4 spool dosyası için yol giriniz"}. -{"Import Users from Dir at ", "Dizinden Kullanıcıları İçe Aktar : "}. -{"Enter path to jabberd1.4 spool dir", "jabberd1.4 spool dosyası için yol giriniz"}. -{"Path to Dir", "Dizinin Yolu"}. -{"Hostname Configuration", "Makina İsmi Ayarı"}. -{"Choose host name", "Makina ismi seçiniz"}. -{"Host name", "Makina ismi"}. -{"Access Control List Configuration", "Erişim Kontrol Listelerinin Ayarlanması (ACL)"}. -{"Access control lists", "Erişim kontrol listeleri (ACL)"}. -{"Access Configuration", "Erişim Ayarları"}. -{"Access rules", "Erişim kuralları"}. -{"Remove Users", "Kullanıcıları Kaldır"}. -{"Choose users to remove", "Kaldırılacak kullanıcıları seçin"}. -{"Administration of ", "Yönetim : "}. -{"Action on user", "Kullanıcıya uygulanacak eylem"}. -{"Edit Properties", "Özellikleri Düzenle"}. -{"Remove User", "Kullanıcıyı Kaldır"}. -{"Database", "Veritabanı"}. -{"Outgoing s2s Connections", "Giden s2s Bağlantıları"}. -{"Import Users From jabberd 1.4 Spool Files", "Jabberd 1.4 Spool Dosyalarından Kullanıcıları İçeri Aktar"}. -{"Database Tables Configuration at ", "Veritabanı Tablo Ayarları : "}. - -% src/ejabberd_c2s.erl -{"Use of STARTTLS required", "STARTTLS kullanımı gereklidir"}. -{"Replaced by new connection", "Eski bağlantı yenisi ile değiştirildi"}. - -% mod_disco.erl -{"Configuration", "Ayarlar"}. -{"Online Users", "Bağlı Kullanıcılar"}. -{"All Users", "Tüm Kullanıcılar"}. -{"To ~s", "Kime ~s"}. -{"From ~s", "Kimden ~s"}. -{"Running Nodes", "Çalışan Düğümler"}. -{"Stopped Nodes", "Durdurulmuş Düğümler"}. -{"Host Name", "Sunucu Adı"}. -{"Access Control Lists", "Erişim Kontrol Listeleri (ACL)"}. -{"Access Rules", "Erişim Kuralları"}. -{"Remove Users", "Kullanıcıları Kaldır"}. -{"Modules", "Modüller"}. -{"Start Modules", "Modülleri Başlat"}. -{"Stop Modules", "Modülleri Durdur"}. -{"Backup Management", "Yedek Yönetimi"}. -{"Backup", "Yedekle"}. -{"Restore", "Yedekten Geri Al"}. -{"Dump to Text File", "Metin Dosyasına Döküm Al"}. -{"Import File", "Dosyayı İçe Aktar"}. -{"Import Directory", "Dizini İçe Aktar"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Bu sunucuya kayıt olmak için bir kullanıcı ismi ve parola seçiniz"}. - -% src/mod_vcard_ldap.erl -{"Erlang Jabber Server", "Erlang Jabber Sunucusu"}. -{"ejabberd vCard module", "ejabberd vCard modülü"}. -{"Email", "E-posta"}. -{"Search Results for ", "Arama sonuçları : "}. -{"Jabber ID", "Jabber ID"}. - -% mod_vcard.erl -{"You need an x:data capable client to search", "Arama yapabilmek için x:data becerisine sahip bir istemciye gereksinimiz var"}. -{"Search users in ", "Kullanıcılarda arama yap : "}. -{"vCard User Search", "vCard Kullanıcı Araması"}. -{"Fill in fields to search for any matching Jabber User", "Eşleşen jabber kullanıcılarını aramak için alanları doldurunuz"}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Eşleşen jabber kullanıcılarını aramak için formu doldurunuz (Alt dizgi eşlemek için alanın sonuna * ekleyin)"}. - -{"User", "Kullanıcı"}. -{"Full Name", "Tam İsim"}. -{"Name", "İsim"}. -{"Middle Name", "Ortanca İsim"}. -{"Family Name", "Soyisim"}. -{"Nickname", "Takma isim"}. -{"Birthday", "Doğumgünü"}. -{"Country", "Ülke"}. -{"City", "İl"}. -{"Organization Name", "Kurum İsmi"}. -{"Organization Unit", "Kurumun İlgili Birimi"}. - -% mod_adhoc.erl -{"Commands", "Komutlar"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% mod_announce.erl -{"Send announcement to all users on all hosts", "Tüm sunuculardaki tüm kullanıcılara duyuru yolla"}. -{"Set message of the day on all hosts and send to online users", "Tüm sunucularda günün mesajını belirle ve bağlı tüm kullanıcılara gönder"}. -{"Update message of the day on all hosts (don't send)", "Tüm sunuculardaki günün mesajını güncelle (gönderme)"}. -{"Delete message of the day on all hosts", "Tüm sunuculardaki günün mesajını sil"}. -{"Really delete message of the day?", "Günün mesajını silmek istediğinize emin misiniz?"}. -{"Subject", "Konu"}. -{"Message body", "Mesajın gövdesi"}. -{"No body provided for announce message", "Duyuru mesajının gövdesi yok"}. -{"Announcements", "Duyurular"}. -{"Send announcement to all users", "Duyuruyu tüm kullanıcılara yolla"}. -{"Send announcement to all online users", "Duyuruyu tüm bağlı kullanıcılara yolla"}. -{"Send announcement to all online users on all hosts", "Duyuruyu tüm sunuculardaki tüm bağlı kullanıcılara yolla"}. -{"Set message of the day and send to online users", "Günün mesajını belirle"}. -{"Update message of the day (don't send)", "Günün mesajını güncelle (gönderme)"}. -{"Delete message of the day", "Günün mesajını sil"}. - -% mod_pubsub/mod_pubsub.erl -{"ejabberd Publish-Subscribe module", "ejabberd Publish-Subscribe modülü"}. -{"PubSub subscriber request", "PubSub üye isteği"}. -{"Choose whether to approve this entity's subscription.", "Bu varlığın üyeliğini onaylayıp onaylamamayı seçiniz."}. -{"Node ID", "Düğüm ID"}. -{"Subscriber Address", "Üye Olanın Adresi"}. -{"Allow this JID to subscribe to this pubsub node?", "Bu JID bu pubsub düğümüne üye olmasına izin verilsin mi?"}. -{"Deliver event notifications", "Olay uyarıları gönderilsin"}. -{"Specify the access model", "Erişim modelini belirtiniz"}. -{"Roster groups that may subscribe (if access model is roster)", "Üye olabilecek kontak listesi grupları (eğer erişim modeli 'kontak listesi' ise)"}. -{"When to send the last published item", "Son yayınlanan öğe ne zaman gönderilsin"}. -{"ejabberd pub/sub module", "pub/sub ejabberd modülü"}. -{"Node Creator", "Düğüm Oluşturucu"}. -{"Notify subscribers when the node configuration changes", "Düğüm ayarları değiştiğinde üyeleri uyar"}. -{"Notify subscribers when the node is deleted", "Bir düğüm silindiğinde üyeleri uyar"}. -{"Notify subscribers when items are removed from the node", "Düğümden öğeler kaldırıldığında üyeleri uyar"}. -{"Whether to allow subscriptions", "Üyeliklere izin verilsin mi"}. -{"Specify the subscriber model", "Üye olma modelini belirtiniz"}. -{"Specify the publisher model", "Yayıncı modelini belirtiniz"}. -{"Max payload size in bytes", "En fazla yük (payload) boyutu (bayt olarak)"}. -{"Send items to new subscribers", "Yeni üyelere öğeleri yolla"}. -{"Only deliver notifications to available users", "Uyarıları sadece durumu uygun kullanıcılara ulaştır"}. -{"Specify the current subscription approver", "Mevcut üyelik onaylayıcısını belirtiniz"}. -{"Publish-Subscribe", "Yayınla-Üye Ol"}. - -% mod_muc/mod_muc_log.erl -{"Chatroom configuration modified", "Sohbet odası ayarı değiştirildi"}. -{"joins the room", "odaya katıldı"}. -{"leaves the room", "odadan ayrıldı"}. -{"has been kicked", "odadan atıldı"}. -{"has been banned", "odaya girmesi yasaklandı"}. -{"is now known as", "isim değiştirdi :"}. -{"Monday", "Pazartesi"}. -{"Tuesday", "Salı"}. -{"Wednesday", "Çarşamba"}. -{"Thursday", "Perşembe"}. -{"Friday", "Cuma"}. -{"Saturday", "Cumartesi"}. -{"Sunday", "Pazar"}. -{"January", "Ocak"}. -{"February", "Şubat"}. -{"March", "Mart"}. -{"April", "Nisan"}. -{"May", "Mayıs"}. -{"June", "Haziran"}. -{"July", "Temmuz"}. -{"August", "Ağustos"}. -{"September", "Eylül"}. -{"October", "Ekim"}. -{"November", "Kasım"}. -{"December", "Aralık"}. -{"Room Configuration", "Oda Ayarları"}. - -% mod_muc/mod_muc.erl -{"You need an x:data capable client to register nickname", "Takma isminizi kaydettirmek için x:data becerisine sahip bir istemciye gereksinimiz var"}. -{"Nickname Registration at ", "Takma İsim Kaydı : "}. -{"Enter nickname you want to register", "Kaydettirmek istediğiniz takma ismi giriniz"}. -{"ejabberd MUC module", "ejabberd MUC modülü"}. -{"Only service administrators are allowed to send service messages", "Sadece servis yöneticileri servis mesajı gönderebilirler"}. -{"Room creation is denied by service policy", "Odanın oluşturulması servis politikası gereği reddedildi"}. -{"Conference room does not exist", "Konferans odası bulunamadı"}. -{"Access denied by service policy", "Servis politikası gereği erişim engellendi"}. -{"Specified nickname is already registered", "Belirtilen takma isim daha önce bir başkası tarafından kaydettirilmiş"}. -{"You must fill in field \"Nickname\" in the form", "Formda \"Takma isim\" alanını doldurmanız gerekiyor"}. -{"Chatrooms", "Sohbet Odaları"}. - -% mod_muc/mod_muc_room.erl -{"Traffic rate limit is exceeded", "Trafik oran sınırı aşıldı"}. -{"Maximum Number of Occupants", "Odada En Fazla Bulunabilecek Kişi Sayısı"}. -{"No limit", "Sınırsız"}. -{"~s invites you to the room ~s", "~s sizi ~s odasına davet ediyor"}. -{"the password is", "parola :"}. -{" has set the subject to: ", " konuyu değiştirdi: "}. -{"You need an x:data capable client to configure room", "Odayı ayarlamak için x:data becerisine sahip bir istemciye gereksinimiz var"}. -{"Configuration for ", "Ayarlar : "}. -{"Room title", "Oda başlığı"}. -{"Password", "Parola"}. -{"Only moderators and participants are allowed to change subject in this room", "Sadece moderatörlerin ve katılımcıların bu odanın konusunu değiştirmesine izin veriliyor"}. -{"Only moderators are allowed to change subject in this room", "Sadece moderatörlerin bu odanın konusunu değiştirmesine izin veriliyor"}. -{"Visitors are not allowed to send messages to all occupants", "Ziyaretçilerin odadaki tüm sakinlere mesaj göndermesine izin verilmiyor"}. -{"Only occupants are allowed to send messages to the conference", "Sadece oda sakinlerinin konferansa mesaj göndermesine izin veriliyor"}. -{"It is not allowed to send normal messages to the conference", "Konferansa normal mesajlar gönderilmesine izin verilmiyor"}. -{"It is not allowed to send private messages to the conference", "Konferansa özel mesajlar gönderilmesine izin verilmiyor"}. -{"Improper message type", "Uygunsuz mesaj tipi"}. -{"Nickname is already in use by another occupant", "Takma isim odanın başka bir sakini tarafından halihazırda kullanımda"}. -{"Nickname is registered by another person", "Takma isim başka biri tarafından kaydettirilmiş"}. -{"It is not allowed to send private messages of type \"groupchat\"", "\"groupchat\" tipinde özel mesajlar gönderilmesine izin verilmiyor"}. -{"Recipient is not in the conference room", "Alıcı konferans odasında değil"}. -{"Only occupants are allowed to send queries to the conference", "Sadece oda sakinlerinin konferansa sorgu göndermesine izin veriliyor"}. -{"Queries to the conference members are not allowed in this room", "Bu odada konferans üyelerine sorgu yapılmasına izin verilmiyor"}. -{"You have been banned from this room", "Bu odaya girmeniz yasaklandı"}. -{"Membership required to enter this room", "Bu odaya girmek için üyelik gerekiyor"}. -{"Password required to enter this room", "Bu odaya girmek için parola gerekiyor"}. -{"Incorrect password", "Yanlış parola"}. -{"Administrator privileges required", "Yönetim yetkileri gerekli"}. -{"Moderator privileges required", "Moderatör yetkileri gerekli"}. -{"JID ~s is invalid", "JID ~s geçersiz"}. -{"Nickname ~s does not exist in the room", "~s takma ismi odada yok"}. -{"Invalid affiliation: ~s", "Geçersiz ilişki: ~s"}. -{"Invalid role: ~s", "Geçersiz rol: ~s"}. -{"Owner privileges required", "Sahip yetkileri gerekli"}. -{"private, ", "özel"}. -{"This room is not anonymous", "Bu oda anonim değil"}. -{"Make room persistent", "Odayı kalıcı hale getir"}. -{"Make room public searchable", "Odayı herkes tarafından aranabilir hale getir"}. -{"Make participants list public", "Katılımcı listesini herkese açık hale getir"}. -{"Make room password protected", "Odayı parola korumalı hale getir"}. -{"Make room members-only", "Odayı sadece üyelere açık hale getir"}. -{"Make room moderated", "Odayı moderasyonlu hale getir"}. -{"Default users as participants", "Kullanıcılar öntanımlı olarak katılımcı olsun"}. -{"Allow users to change subject", "Kullanıcıların konu değiştirmesine izin ver"}. -{"Allow users to send private messages", "Kullanıcıların özel mesaj göndermelerine izin ver"}. -{"Allow users to query other users", "Kullanıcıların diğer kullanıcıları sorgulamalarına izin ver"}. -{"Allow users to send invites", "Kullanıcıların davetiye göndermelerine izin ver"}. -{"Enable logging", "Kayıt tutma özelliğini aç"}. -{"Description", "Tanım"}. -{"Number of occupants", "Oda sakini sayısı"}. -{"Present real JIDs to", "Gerçek JID'lerini göster :"}. -{"moderators only", "sadece moderatörler"}. -{"anyone", "herkes"}. - -% mod_irc/mod_irc.erl -{"ejabberd IRC module", "ejabberd IRC modülü"}. -{"You need an x:data capable client to configure mod_irc settings", "mod_irc ayarlarını düzenlemek için x:data becerisine sahip bir istemciye gereksinimiz var"}. -{"Registration in mod_irc for ", "mod_irc'ye kayıt : "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "IRC sunuculara bağlanmak için kullanmak istediğiniz kullanıcı isimleri ve kodlamaları giriniz"}. -{"IRC Username", "IRC Kullanıcı İsmi"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "IRC sunucuları için farklı kodlamalar belirtmek istiyorsanız, '{\"irc sunucusu\", \"kodlama\"}' biçeminde değerlerle bu listeyi doldurunuz. Öntanımlı olarak bu servis \"~s\" kodlamasını kullanıyor."}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Örnek: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"Encodings", "Kodlamalar"}. -{"IRC Transport", "IRC Nakli (Transport)"}. - -% web/ejabberd_web_admin.erl -{"Administration", "Yönetim"}. -{"Users", "Kullanıcılar"}. -{"Nodes", "Düğümler"}. -{"Shared Roster", "Paylaşılmış Kontak Listesi"}. -{"Statistics", "İstatistikler"}. -{"ejabberd (c) 2002-2008 Alexey Shchepin, 2004-2008 Process One", "ejabberd (c) 2002-2008 Alexey Shchepin, 2004-2008 Process One"}. -{"(Raw)", "(Ham)"}. -{"Submitted", "Gönderilenler"}. -{"Bad format", "Kötü biçem"}. -{"Raw", "Ham"}. -{"Delete Selected", "Seçilenleri Sil"}. -{"Submit", "Gönder"}. -{"~s access rule configuration", "~s erişim kuralları ayarları"}. -{"Node not found", "Düğüm bulunamadı"}. -{"Add New", "Yeni Ekle"}. -{"Registered Users", "Kayıtlı Kullanıcılar"}. -{"Registered Users:", "Kayıtlı Kullanıcılar:"}. -{"Change Password", "Parola Değiştir"}. -{"Connected Resources:", "Bağlı Kaynaklar:"}. -{"Password:", "Parola:"}. -{"None", "Hiçbiri"}. -{"Node ", "Düğüm "}. -{"Listened Ports", "Dinlenen Kapılar (Portlar)"}. -{"Restart", "Tekrar Başlat"}. -{"Stop", "Durdur"}. -{"RPC Call Error", "RPC Çağrı Hatası"}. -{"Name", "İsim"}. -{"Storage Type", "Depolama Tipi"}. -{"Size", "Boyut"}. -{"Memory", "Bellek"}. -{"OK", "Tamam"}. -{"Listened Ports at ", "Dinlenen Kapılar (Portlar) : "}. -{"Uptime:", "Hizmet Süresi:"}. -{"CPU Time:", "İşlemci Zamanı:"}. -{"Transactions Commited:", "Tamamlanan Hareketler (Transactions Commited):"}. -{"Transactions Aborted:", "İptal Edilen Hareketler (Transactions):"}. -{"Transactions Restarted:", "Tekrar Başlatılan Hareketler (Transactions):"}. -{"Transactions Logged:", "Kaydı Tutulan Hareketler (Transactions):"}. -{"Port", "Kapı (Port)"}. -{"Module", "Modül"}. -{"Options", "Seçenekler"}. -{"Update", "GÜncelle"}. -{"Delete", "Sil"}. -{"Add User", "Kullanıcı Ekle"}. -{"Offline Messages", "Çevirim-dışı Mesajlar"}. -{"Users Last Activity", "Kullanıcıların Son Aktiviteleri"}. -{"Never", "Asla"}. -{"~s's Offline Messages Queue", "~s Kullanıcısının Mesaj Kuyruğu"}. -{"Time", "Zaman"}. -{"From", "Kimden"}. -{"To", "Kime"}. -{"Packet", "Paket"}. -{"Offline Messages:", "Çevirim-dışı Mesajlar:"}. -{"Roster", "Kontak Listesi"}. -{"Nickname", "Takma isim"}. -{"Subscription", "Üyelik"}. -{"Pending", "Sıra Bekleyen"}. -{"Groups", "Gruplar"}. -{"Remove", "Kaldır"}. -{"Add Jabber ID", "Jabber ID'si Ekle"}. -{"User ", "Kullanıcı "}. -{"Roster of ", "Kontak Listesi : "}. -{"Online", "Bağlı"}. -{"Validate", "Geçerli"}. -{"Name:", "İsim:"}. -{"Description:", "Tanım:"}. -{"Members:", "Üyeler:"}. -{"Displayed Groups:", "Gösterilen Gruplar:"}. -{"Group ", "Group "}. -{"Period: ", "Periyot:"}. -{"Last month", "Geçen ay"}. -{"Last year", "Geçen yıl"}. -{"All activity", "Tüm aktivite"}. -{"Show Ordinary Table", "Sıradan Tabloyu Göster"}. -{"Show Integral Table", "Önemli Tabloyu Göster"}. -{"Modules at ", "Modüller : "}. -{"Start", "Başlat"}. -{"Virtual Hosts", "Sanal Sunucular"}. -{"ejabberd virtual hosts", "ejabberd sanal sunucuları"}. -{"Host", "Sunucu"}. -{"Authenticated Users:", "Doğrulanmış Kullanıcılar:"}. -{"No Data", "Veri Yok"}. -{"ejabberd Web Interface", "ejabberd Web Arayüzü"}. -{"Online Users:", "Bağlı Kullanıcılar:"}. -{"Outgoing s2s Connections:", "Giden s2s Bağlantıları:"}. -{"Outgoing s2s Servers:", "Giden s2s Sunucuları"}. -{"Database Tables at ", "Veritabanı Tabloları : "}. -{"Backup of ", "Yedek : "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database seperately.", "Bu seçeneklerin sadece gömülü Mnesia veritabanını yedekleyeceğine dikkat edin. Eğer ODBC modülünü kullanıyorsanız, SQL veritabanınızı ayrıca yedeklemelisiniz."}. -{"Store binary backup:", "İkili yedeği sakla:"}. -{"Restore binary backup immediately:", "Hemen ikili yedekten geri al:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "ejabberd'nin bir sonraki tekrar başlatılışında ikili yedekten geri al (daha az bellek gerektirir)"}. -{"Store plain text backup:", "Düz metin yedeği sakla:"}. -{"Restore plain text backup immediately:", "Hemen düz metin yedekten geri al"}. -{"Statistics of ~p", "~p istatistikleri"}. -{"Update ", "Güncelle "}. -{"Update plan", "Planı güncelle"}. -{"Updated modules", "Güncellenen modüller"}. -{"Update script", "Betiği Güncelle"}. -{"Low level update script", "Düşük seviye güncelleme betiği"}. -{"Script check", "Betik kontrolü"}. -{"Not Found", "Bulunamadı"}. -{"Shared Roster Groups", "Paylaşımlı Kontak Listesi Grupları"}. -{"Last Activity", "Son Aktivite"}. - -% mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "ejabberd SOCKS5 Bytestreams modülü"}. - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "Çevirim-dışı mesaj kuyruğunuz dolu. Mesajını dikkate alınmadı."}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Erişim Ayarları"}. +{"Access Control List Configuration","Erişim Kontrol Listelerinin Ayarlanması (ACL)"}. +{"Access control lists","Erişim kontrol listeleri (ACL)"}. +{"Access Control Lists","Erişim Kontrol Listeleri (ACL)"}. +{"Access denied by service policy","Servis politikası gereği erişim engellendi"}. +{"Access rules","Erişim kuralları"}. +{"Access Rules","Erişim Kuralları"}. +{"Action on user","Kullanıcıya uygulanacak eylem"}. +{"Add Jabber ID","Jabber ID'si Ekle"}. +{"Add New","Yeni Ekle"}. +{"Add User","Kullanıcı Ekle"}. +{"Administration of ","Yönetim : "}. +{"Administration","Yönetim"}. +{"Administrator privileges required","Yönetim yetkileri gerekli"}. +{"A friendly name for the node","Düğüm için dostane bir isim"}. +{"All activity","Tüm aktivite"}. +{"Allow this JID to subscribe to this pubsub node?","Bu JID bu pubsub düğümüne üye olmasına izin verilsin mi?"}. +{"Allow users to change subject","Kullanıcıların konu değiştirmesine izin ver"}. +{"Allow users to query other users","Kullanıcıların diğer kullanıcıları sorgulamalarına izin ver"}. +{"Allow users to send invites","Kullanıcıların davetiye göndermelerine izin ver"}. +{"Allow users to send private messages","Kullanıcıların özel mesaj göndermelerine izin ver"}. +{"Allow visitors to change nickname","Ziyaretçilerin takma isim değiştirmelerine izin ver"}. +{"Allow visitors to send status text in presence updates","Ziyaretçilerin varlık (presence) güncellemelerinde durum metni göndermelerine izin ver"}. +{"All Users","Tüm Kullanıcılar"}. +{"Announcements","Duyurular"}. +{"anyone","herkes"}. +{"April","Nisan"}. +{"August","Ağustos"}. +{"Backup Management","Yedek Yönetimi"}. +{"Backup of ","Yedek : "}. +{"Backup to File at ","Dosyaya Yedekle : "}. +{"Backup","Yedekle"}. +{"Bad format","Kötü biçem"}. +{"Birthday","Doğumgünü"}. +{"Change Password","Parola Değiştir"}. +{"Change User Password","Kullanıcı Parolasını Değiştir"}. +{"Chatroom configuration modified","Sohbet odası ayarı değiştirildi"}. +{"Chatrooms","Sohbet Odaları"}. +{"Choose a username and password to register with this server","Bu sunucuya kayıt olmak için bir kullanıcı ismi ve parola seçiniz"}. +{"Choose modules to stop","Durdurulacak modülleri seçiniz"}. +{"Choose storage type of tables","Tabloların veri depolama tipini seçiniz"}. +{"Choose whether to approve this entity's subscription.","Bu varlığın üyeliğini onaylayıp onaylamamayı seçiniz."}. +{"City","İl"}. +{"Commands","Komutlar"}. +{"Conference room does not exist","Konferans odası bulunamadı"}. +{"Configuration","Ayarlar"}. +{"Configuration for ","Ayarlar : "}. +{"Connected Resources:","Bağlı Kaynaklar:"}. +{"Country","Ülke"}. +{"CPU Time:","İşlemci Zamanı:"}. +{"Database Tables at ","Veritabanı Tabloları : "}. +{"Database Tables Configuration at ","Veritabanı Tablo Ayarları : "}. +{"Database","Veritabanı"}. +{"December","Aralık"}. +{"Default users as participants","Kullanıcılar öntanımlı olarak katılımcı olsun"}. +{"Delete message of the day","Günün mesajını sil"}. +{"Delete message of the day on all hosts","Tüm sunuculardaki günün mesajını sil"}. +{"Delete Selected","Seçilenleri Sil"}. +{"Delete","Sil"}. +{"Delete User","Kullanıcıyı Sil"}. +{"Deliver event notifications","Olay uyarıları gönderilsin"}. +{"Deliver payloads with event notifications","Yükleri (payload) olay uyarıları ile beraber gönder"}. +{"Description:","Tanım:"}. +{"Disc only copy","Sadece disk kopyala"}. +{"Displayed Groups:","Gösterilen Gruplar:"}. +{"Dump Backup to Text File at ","Metin Dosyasına Döküm Alarak Yedekle : "}. +{"Dump to Text File","Metin Dosyasına Döküm Al"}. +{"Edit Properties","Özellikleri Düzenle"}. +{"ejabberd IRC module","ejabberd IRC modülü"}. +{"ejabberd MUC module","ejabberd MUC modülü"}. +{"ejabberd Publish-Subscribe module","ejabberd Publish-Subscribe modülü"}. +{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestreams modülü"}. +{"ejabberd vCard module","ejabberd vCard modülü"}. +{"ejabberd virtual hosts","ejabberd sanal sunucuları"}. +{"ejabberd Web Admin","ejabberd Web Yöneticisi"}. +{"Email","E-posta"}. +{"Enable logging","Kayıt tutma özelliğini aç"}. +{"Encodings","Kodlamalar"}. +{"End User Session","Kullanıcı Oturumunu Kapat"}. +{"Enter list of {Module, [Options]}","{Module, [Options]} listesi giriniz"}. +{"Enter nickname you want to register","Kaydettirmek istediğiniz takma ismi giriniz"}. +{"Enter path to backup file","Yedek dosyasının yolunu giriniz"}. +{"Enter path to jabberd1.4 spool dir","jabberd1.4 spool dosyası için yol giriniz"}. +{"Enter path to jabberd1.4 spool file","jabberd1.4 spool dosyası için yol giriniz"}. +{"Enter path to text file","Metin dosyasının yolunu giriniz"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","IRC sunuculara bağlanmak için kullanmak istediğiniz kullanıcı isimleri ve kodlamaları giriniz"}. +{"Erlang Jabber Server","Erlang Jabber Sunucusu"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Örnek: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","Soyisim"}. +{"February","Şubat"}. +{"Fill in fields to search for any matching Jabber User","Eşleşen jabber kullanıcılarını aramak için alanları doldurunuz"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Eşleşen jabber kullanıcılarını aramak için formu doldurunuz (Alt dizgi eşlemek için alanın sonuna * ekleyin)"}. +{"Friday","Cuma"}. +{"From","Kimden"}. +{"From ~s","Kimden ~s"}. +{"Full Name","Tam İsim"}. +{"Get Number of Online Users","Bağlı Kullanıcı Sayısını Al"}. +{"Get Number of Registered Users","Kayıtlı Kullanıcı Sayısını Al"}. +{"Get User Last Login Time","Kullanıcı Son Giriş Zamanınlarını Al"}. +{"Get User Password","Kullanıcı Parolasını Al"}. +{"Get User Statistics","Kullanıcı İstatistiklerini Al"}. +{"Group ","Group "}. +{"Groups","Gruplar"}. +{"has been banned","odaya girmesi yasaklandı"}. +{"has been kicked because of an affiliation change","ilişki değişikliğinden dolayı atıldı"}. +{"has been kicked because of a system shutdown","sistem kapandığından dolayı atıldı"}. +{"has been kicked because the room has been changed to members-only","oda üyelere-özel hale getirildiğinden dolayı atıldı"}. +{"has been kicked","odadan atıldı"}. +{" has set the subject to: "," konuyu değiştirdi: "}. +{"Host","Sunucu"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","IRC sunucuları için farklı kodlamalar belirtmek istiyorsanız, '{\"irc sunucusu\", \"kodlama\"}' biçeminde değerlerle bu listeyi doldurunuz. Öntanımlı olarak bu servis \"~s\" kodlamasını kullanıyor."}. +{"Import Directory","Dizini İçe Aktar"}. +{"Import File","Dosyayı İçe Aktar"}. +{"Import User from File at ","Dosyadan Kullanıcıları İçe Aktar : "}. +{"Import Users from Dir at ","Dizinden Kullanıcıları İçe Aktar : "}. +{"Import Users From jabberd 1.4 Spool Files","Jabberd 1.4 Spool Dosyalarından Kullanıcıları İçeri Aktar"}. +{"Improper message type","Uygunsuz mesaj tipi"}. +{"Incorrect password","Yanlış parola"}. +{"Invalid affiliation: ~s","Geçersiz ilişki: ~s"}. +{"Invalid role: ~s","Geçersiz rol: ~s"}. +{"IP addresses","IP adresleri"}. +{"IRC Transport","IRC Nakli (Transport)"}. +{"IRC Username","IRC Kullanıcı İsmi"}. +{"is now known as","isim değiştirdi :"}. +{"It is not allowed to send private messages of type \"groupchat\"","\"groupchat\" tipinde özel mesajlar gönderilmesine izin verilmiyor"}. +{"It is not allowed to send private messages","Özel mesaj gönderilmesine izin verilmiyor"}. +{"It is not allowed to send private messages to the conference","Konferansa özel mesajlar gönderilmesine izin verilmiyor"}. +{"Jabber ID","Jabber ID"}. +{"January","Ocak"}. +{"JID ~s is invalid","JID ~s geçersiz"}. +{"joins the room","odaya katıldı"}. +{"July","Temmuz"}. +{"June","Haziran"}. +{"Last Activity","Son Aktivite"}. +{"Last login","Son giriş"}. +{"Last month","Geçen ay"}. +{"Last year","Geçen yıl"}. +{"leaves the room","odadan ayrıldı"}. +{"Listened Ports at ","Dinlenen Kapılar (Portlar) : "}. +{"Listened Ports","Dinlenen Kapılar (Portlar)"}. +{"List of modules to start","Başlatılacak modüllerin listesi"}. +{"Low level update script","Düşük seviye güncelleme betiği"}. +{"Make participants list public","Katılımcı listesini herkese açık hale getir"}. +{"Make room members-only","Odayı sadece üyelere açık hale getir"}. +{"Make room moderated","Odayı moderasyonlu hale getir"}. +{"Make room password protected","Odayı parola korumalı hale getir"}. +{"Make room persistent","Odayı kalıcı hale getir"}. +{"Make room public searchable","Odayı herkes tarafından aranabilir hale getir"}. +{"March","Mart"}. +{"Maximum Number of Occupants","Odada En Fazla Bulunabilecek Kişi Sayısı"}. +{"Max # of items to persist","Kalıcı hale getirilecek en fazla öğe sayısı"}. +{"Max payload size in bytes","En fazla yük (payload) boyutu (bayt olarak)"}. +{"May","Mayıs"}. +{"Membership required to enter this room","Bu odaya girmek için üyelik gerekiyor"}. +{"Members:","Üyeler:"}. +{"Memory","Bellek"}. +{"Message body","Mesajın gövdesi"}. +{"Middle Name","Ortanca İsim"}. +{"Moderator privileges required","Moderatör yetkileri gerekli"}. +{"moderators only","sadece moderatörler"}. +{"Module","Modül"}. +{"Modules at ","Modüller : "}. +{"Modules","Modüller"}. +{"Monday","Pazartesi"}. +{"Name:","İsim:"}. +{"Name","İsim"}. +{"Never","Asla"}. +{"Nickname is already in use by another occupant","Takma isim odanın başka bir sakini tarafından halihazırda kullanımda"}. +{"Nickname is registered by another person","Takma isim başka biri tarafından kaydettirilmiş"}. +{"Nickname Registration at ","Takma İsim Kaydı : "}. +{"Nickname ~s does not exist in the room","~s takma ismi odada yok"}. +{"Nickname","Takma isim"}. +{"No body provided for announce message","Duyuru mesajının gövdesi yok"}. +{"No Data","Veri Yok"}. +{"Node ","Düğüm "}. +{"Node ID","Düğüm ID"}. +{"Node not found","Düğüm bulunamadı"}. +{"Nodes","Düğümler"}. +{"No limit","Sınırsız"}. +{"None","Hiçbiri"}. +{"No resource provided","Hiç kaynak sağlanmadı"}. +{"Notify subscribers when items are removed from the node","Düğümden öğeler kaldırıldığında üyeleri uyar"}. +{"Notify subscribers when the node configuration changes","Düğüm ayarları değiştiğinde üyeleri uyar"}. +{"Notify subscribers when the node is deleted","Bir düğüm silindiğinde üyeleri uyar"}. +{"November","Kasım"}. +{"Number of occupants","Oda sakini sayısı"}. +{"Number of online users","Bağlı kullanıcı sayısı"}. +{"Number of registered users","Kayıtlı kullanıcı sayısı"}. +{"October","Ekim"}. +{"Offline Messages:","Çevirim-dışı Mesajlar:"}. +{"Offline Messages","Çevirim-dışı Mesajlar"}. +{"OK","Tamam"}. +{"Online","Bağlı"}. +{"Online Users:","Bağlı Kullanıcılar:"}. +{"Online Users","Bağlı Kullanıcılar"}. +{"Only deliver notifications to available users","Uyarıları sadece durumu uygun kullanıcılara ulaştır"}. +{"Only moderators and participants are allowed to change subject in this room","Sadece moderatörlerin ve katılımcıların bu odanın konusunu değiştirmesine izin veriliyor"}. +{"Only moderators are allowed to change subject in this room","Sadece moderatörlerin bu odanın konusunu değiştirmesine izin veriliyor"}. +{"Only occupants are allowed to send messages to the conference","Sadece oda sakinlerinin konferansa mesaj göndermesine izin veriliyor"}. +{"Only occupants are allowed to send queries to the conference","Sadece oda sakinlerinin konferansa sorgu göndermesine izin veriliyor"}. +{"Only service administrators are allowed to send service messages","Sadece servis yöneticileri servis mesajı gönderebilirler"}. +{"Options","Seçenekler"}. +{"Organization Name","Kurum İsmi"}. +{"Organization Unit","Kurumun İlgili Birimi"}. +{"Outgoing s2s Connections:","Giden s2s Bağlantıları:"}. +{"Outgoing s2s Connections","Giden s2s Bağlantıları"}. +{"Outgoing s2s Servers:","Giden s2s Sunucuları"}. +{"Owner privileges required","Sahip yetkileri gerekli"}. +{"Packet","Paket"}. +{"Password:","Parola:"}. +{"Password","Parola"}. +{"Password required to enter this room","Bu odaya girmek için parola gerekiyor"}. +{"Password Verification","Parola Doğrulaması"}. +{"Path to Dir","Dizinin Yolu"}. +{"Path to File","Dosyanın Yolu"}. +{"Pending","Sıra Bekleyen"}. +{"Period: ","Periyot:"}. +{"Persist items to storage","Öğeleri depoda kalıcı hale getir"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","Kapı (Port)"}. +{"Present real JIDs to","Gerçek JID'lerini göster :"}. +{"private, ","özel"}. +{"Publish-Subscribe","Yayınla-Üye Ol"}. +{"PubSub subscriber request","PubSub üye isteği"}. +{"Queries to the conference members are not allowed in this room","Bu odada konferans üyelerine sorgu yapılmasına izin verilmiyor"}. +{"RAM and disc copy","RAM ve disk kopyala"}. +{"RAM copy","RAM kopyala"}. +{"(Raw)","(Ham)"}. +{"Raw","Ham"}. +{"Really delete message of the day?","Günün mesajını silmek istediğinize emin misiniz?"}. +{"Recipient is not in the conference room","Alıcı konferans odasında değil"}. +{"Registered Users:","Kayıtlı Kullanıcılar:"}. +{"Registered Users","Kayıtlı Kullanıcılar"}. +{"Registration in mod_irc for ","mod_irc'ye kayıt : "}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Bu seçeneklerin sadece gömülü Mnesia veritabanını yedekleyeceğine dikkat edin. Eğer ODBC modülünü kullanıyorsanız, SQL veritabanınızı da ayrıca yedeklemeniz gerekiyor."}. +{"Remote copy","Uzak kopyala"}. +{"Remove","Kaldır"}. +{"Remove User","Kullanıcıyı Kaldır"}. +{"Replaced by new connection","Eski bağlantı yenisi ile değiştirildi"}. +{"Resources","Kaynaklar"}. +{"Restart Service","Servisi Tekrar Başlat"}. +{"Restart","Tekrar Başlat"}. +{"Restore Backup from File at ","Dosyadaki Yedekten Geri Al : "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","ejabberd'nin bir sonraki tekrar başlatılışında ikili yedekten geri al (daha az bellek gerektirir)"}. +{"Restore binary backup immediately:","Hemen ikili yedekten geri al:"}. +{"Restore plain text backup immediately:","Hemen düz metin yedekten geri al"}. +{"Restore","Yedekten Geri Al"}. +{"Room Configuration","Oda Ayarları"}. +{"Room creation is denied by service policy","Odanın oluşturulması servis politikası gereği reddedildi"}. +{"Room title","Oda başlığı"}. +{"Roster groups allowed to subscribe","Üye olunmasına izin verilen kontak listesi grupları"}. +{"Roster","Kontak Listesi"}. +{"Roster of ","Kontak Listesi : "}. +{"Roster size","İsim listesi boyutu"}. +{"RPC Call Error","RPC Çağrı Hatası"}. +{"Running Nodes","Çalışan Düğümler"}. +{"~s access rule configuration","~s erişim kuralları ayarları"}. +{"Saturday","Cumartesi"}. +{"Script check","Betik kontrolü"}. +{"Search Results for ","Arama sonuçları : "}. +{"Search users in ","Kullanıcılarda arama yap : "}. +{"Send announcement to all online users","Duyuruyu tüm bağlı kullanıcılara yolla"}. +{"Send announcement to all online users on all hosts","Duyuruyu tüm sunuculardaki tüm bağlı kullanıcılara yolla"}. +{"Send announcement to all users","Duyuruyu tüm kullanıcılara yolla"}. +{"Send announcement to all users on all hosts","Tüm sunuculardaki tüm kullanıcılara duyuru yolla"}. +{"September","Eylül"}. +{"Set message of the day and send to online users","Günün mesajını belirle"}. +{"Set message of the day on all hosts and send to online users","Tüm sunucularda günün mesajını belirle ve bağlı tüm kullanıcılara gönder"}. +{"Shared Roster Groups","Paylaşımlı Kontak Listesi Grupları"}. +{"Show Integral Table","Önemli Tabloyu Göster"}. +{"Show Ordinary Table","Sıradan Tabloyu Göster"}. +{"Shut Down Service","Servisi Kapat"}. +{"~s invites you to the room ~s","~s sizi ~s odasına davet ediyor"}. +{"Size","Boyut"}. +{"Specified nickname is already registered","Belirtilen takma isim daha önce bir başkası tarafından kaydettirilmiş"}. +{"Specify the access model","Erişim modelini belirtiniz"}. +{"Specify the publisher model","Yayıncı modelini belirtiniz"}. +{"~s's Offline Messages Queue","~s Kullanıcısının Mesaj Kuyruğu"}. +{"Start","Başlat"}. +{"Start Modules at ","Modülleri Başlat : "}. +{"Start Modules","Modülleri Başlat"}. +{"Statistics","İstatistikler"}. +{"Statistics of ~p","~p istatistikleri"}. +{"Stop","Durdur"}. +{"Stop Modules at ","Modülleri Durdur : "}. +{"Stop Modules","Modülleri Durdur"}. +{"Stopped Nodes","Durdurulmuş Düğümler"}. +{"Storage Type","Depolama Tipi"}. +{"Store binary backup:","İkili yedeği sakla:"}. +{"Store plain text backup:","Düz metin yedeği sakla:"}. +{"Subject","Konu"}. +{"Submit","Gönder"}. +{"Submitted","Gönderilenler"}. +{"Subscriber Address","Üye Olanın Adresi"}. +{"Subscription","Üyelik"}. +{"Sunday","Pazar"}. +{"the password is","parola :"}. +{"This participant is kicked from the room because he sent an error message","Bu katılımcı bir hata mesajı gönderdiği için odadan atıldı"}. +{"This participant is kicked from the room because he sent an error message to another participant","Bu katılımcı başka bir katılımcıya bir hata mesajı gönderdiği için odadan atıldı"}. +{"This participant is kicked from the room because he sent an error presence","Bu katılımcı bir hata varlığı (presence) gönderdiği için odadan atıldı"}. +{"This room is not anonymous","Bu oda anonim değil"}. +{"Thursday","Perşembe"}. +{"Time delay","Zaman gecikmesi"}. +{"Time","Zaman"}. +{"To","Kime"}. +{"To ~s","Kime ~s"}. +{"Traffic rate limit is exceeded","Trafik oran sınırı aşıldı"}. +{"Transactions Aborted:","İptal Edilen Hareketler (Transactions):"}. +{"Transactions Commited:","Tamamlanan Hareketler (Transactions Commited):"}. +{"Transactions Logged:","Kaydı Tutulan Hareketler (Transactions):"}. +{"Transactions Restarted:","Tekrar Başlatılan Hareketler (Transactions):"}. +{"Tuesday","Salı"}. +{"Updated modules","Güncellenen modüller"}. +{"Update ","Güncelle "}. +{"Update","GÜncelle"}. +{"Update message of the day (don't send)","Günün mesajını güncelle (gönderme)"}. +{"Update message of the day on all hosts (don't send)","Tüm sunuculardaki günün mesajını güncelle (gönderme)"}. +{"Update plan","Planı güncelle"}. +{"Update script","Betiği Güncelle"}. +{"Uptime:","Hizmet Süresi:"}. +{"Use of STARTTLS required","STARTTLS kullanımı gereklidir"}. +{"User ","Kullanıcı "}. +{"User","Kullanıcı"}. +{"User Management","Kullanıcı Yönetimi"}. +{"Users are not allowed to register accounts so fast","Kullanıcıların bu kadar hızlı hesap açmalarına izin verilmiyor"}. +{"Users","Kullanıcılar"}. +{"Users Last Activity","Kullanıcıların Son Aktiviteleri"}. +{"Validate","Geçerli"}. +{"vCard User Search","vCard Kullanıcı Araması"}. +{"Virtual Hosts","Sanal Sunucular"}. +{"Visitors are not allowed to change their nicknames in this room","Bu odada ziyaretçilerin takma isimlerini değiştirmesine izin verilmiyor"}. +{"Visitors are not allowed to send messages to all occupants","Ziyaretçilerin odadaki tüm sakinlere mesaj göndermesine izin verilmiyor"}. +{"Wednesday","Çarşamba"}. +{"When to send the last published item","Son yayınlanan öğe ne zaman gönderilsin"}. +{"Whether to allow subscriptions","Üyeliklere izin verilsin mi"}. +{"You have been banned from this room","Bu odaya girmeniz yasaklandı"}. +{"You must fill in field \"Nickname\" in the form","Formda \"Takma isim\" alanını doldurmanız gerekiyor"}. +{"You need an x:data capable client to configure mod_irc settings","mod_irc ayarlarını düzenlemek için x:data becerisine sahip bir istemciye gereksinimiz var"}. +{"You need an x:data capable client to configure room","Odayı ayarlamak için x:data becerisine sahip bir istemciye gereksinimiz var"}. +{"You need an x:data capable client to register nickname","Takma isminizi kaydettirmek için x:data becerisine sahip bir istemciye gereksinimiz var"}. +{"You need an x:data capable client to search","Arama yapabilmek için x:data becerisine sahip bir istemciye gereksinimiz var"}. +{"Your contact offline message queue is full. The message has been discarded.","Çevirim-dışı mesaj kuyruğunuz dolu. Mesajını dikkate alınmadı."}. diff --git a/src/msgs/tr.po b/src/msgs/tr.po new file mode 100644 index 000000000..f8baf6615 --- /dev/null +++ b/src/msgs/tr.po @@ -0,0 +1,1497 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Doruk Fisek \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Turkish (türkçe)\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "STARTTLS kullanımı gereklidir" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Hiç kaynak sağlanmadı" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Eski bağlantı yenisi ile değiştirildi" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Komutlar" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Günün mesajını silmek istediğinize emin misiniz?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Konu" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Mesajın gövdesi" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "Duyuru mesajının gövdesi yok" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Duyurular" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Duyuruyu tüm kullanıcılara yolla" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Tüm sunuculardaki tüm kullanıcılara duyuru yolla" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Duyuruyu tüm bağlı kullanıcılara yolla" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "Duyuruyu tüm sunuculardaki tüm bağlı kullanıcılara yolla" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Günün mesajını belirle" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Tüm sunucularda günün mesajını belirle ve bağlı tüm kullanıcılara gönder" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Günün mesajını güncelle (gönderme)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Tüm sunuculardaki günün mesajını güncelle (gönderme)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Günün mesajını sil" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Tüm sunuculardaki günün mesajını sil" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Ayarlar" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Veritabanı" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Modülleri Başlat" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Modülleri Durdur" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Yedekle" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Yedekten Geri Al" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Metin Dosyasına Döküm Al" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Dosyayı İçe Aktar" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Dizini İçe Aktar" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Servisi Tekrar Başlat" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Servisi Kapat" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Kullanıcı Ekle" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Kullanıcıyı Sil" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Kullanıcı Oturumunu Kapat" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Kullanıcı Parolasını Al" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Kullanıcı Parolasını Değiştir" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Kullanıcı Son Giriş Zamanınlarını Al" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Kullanıcı İstatistiklerini Al" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Kayıtlı Kullanıcı Sayısını Al" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Bağlı Kullanıcı Sayısını Al" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Erişim Kontrol Listeleri (ACL)" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Erişim Kuralları" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Kullanıcı Yönetimi" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Bağlı Kullanıcılar" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Tüm Kullanıcılar" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Giden s2s Bağlantıları" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Çalışan Düğümler" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Durdurulmuş Düğümler" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Modüller" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Yedek Yönetimi" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Jabberd 1.4 Spool Dosyalarından Kullanıcıları İçeri Aktar" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "Kime ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "Kimden ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Veritabanı Tablo Ayarları : " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Tabloların veri depolama tipini seçiniz" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Sadece disk kopyala" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "RAM ve disk kopyala" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "RAM kopyala" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Uzak kopyala" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Modülleri Durdur : " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Durdurulacak modülleri seçiniz" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Modülleri Başlat : " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "{Module, [Options]} listesi giriniz" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Başlatılacak modüllerin listesi" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Dosyaya Yedekle : " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Yedek dosyasının yolunu giriniz" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Dosyanın Yolu" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Dosyadaki Yedekten Geri Al : " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Metin Dosyasına Döküm Alarak Yedekle : " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Metin dosyasının yolunu giriniz" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Dosyadan Kullanıcıları İçe Aktar : " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "jabberd1.4 spool dosyası için yol giriniz" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Dizinden Kullanıcıları İçe Aktar : " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "jabberd1.4 spool dosyası için yol giriniz" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Dizinin Yolu" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Zaman gecikmesi" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Erişim Kontrol Listelerinin Ayarlanması (ACL)" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Erişim kontrol listeleri (ACL)" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Erişim Ayarları" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Erişim kuralları" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Parola" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Parola Doğrulaması" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Kayıtlı kullanıcı sayısı" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Bağlı kullanıcı sayısı" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Asla" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Bağlı" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Son giriş" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "İsim listesi boyutu" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "IP adresleri" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Kaynaklar" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Yönetim : " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Kullanıcıya uygulanacak eylem" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Özellikleri Düzenle" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Kullanıcıyı Kaldır" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Servis politikası gereği erişim engellendi" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "IRC Nakli (Transport)" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "ejabberd IRC modülü" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "" +"mod_irc ayarlarını düzenlemek için x:data becerisine sahip bir istemciye " +"gereksinimiz var" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "mod_irc'ye kayıt : " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"IRC sunuculara bağlanmak için kullanmak istediğiniz kullanıcı isimleri ve " +"kodlamaları giriniz" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "IRC Kullanıcı İsmi" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"IRC sunucuları için farklı kodlamalar belirtmek istiyorsanız, '{\"irc " +"sunucusu\", \"kodlama\"}' biçeminde değerlerle bu listeyi doldurunuz. " +"Öntanımlı olarak bu servis \"~s\" kodlamasını kullanıyor." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Örnek: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Kodlamalar" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "Sadece servis yöneticileri servis mesajı gönderebilirler" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "Odanın oluşturulması servis politikası gereği reddedildi" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "Konferans odası bulunamadı" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Sohbet Odaları" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "" +"Takma isminizi kaydettirmek için x:data becerisine sahip bir istemciye " +"gereksinimiz var" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Takma İsim Kaydı : " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Kaydettirmek istediğiniz takma ismi giriniz" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Takma isim" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "Belirtilen takma isim daha önce bir başkası tarafından kaydettirilmiş" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Formda \"Takma isim\" alanını doldurmanız gerekiyor" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "ejabberd MUC modülü" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Sohbet odası ayarı değiştirildi" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "odaya katıldı" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "odadan ayrıldı" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "odaya girmesi yasaklandı" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "odadan atıldı" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "ilişki değişikliğinden dolayı atıldı" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "oda üyelere-özel hale getirildiğinden dolayı atıldı" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "sistem kapandığından dolayı atıldı" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "isim değiştirdi :" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " konuyu değiştirdi: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "Pazartesi" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "Salı" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "Çarşamba" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "Perşembe" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "Cuma" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "Cumartesi" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "Pazar" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "Ocak" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "Şubat" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "Mart" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "Nisan" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "Mayıs" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "Haziran" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "Temmuz" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "Ağustos" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "Eylül" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "Ekim" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "Kasım" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "Aralık" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Oda Ayarları" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Oda başlığı" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Trafik oran sınırı aşıldı" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "Bu katılımcı bir hata mesajı gönderdiği için odadan atıldı" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Konferansa özel mesajlar gönderilmesine izin verilmiyor" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Uygunsuz mesaj tipi" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Bu katılımcı başka bir katılımcıya bir hata mesajı gönderdiği için odadan " +"atıldı" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "\"groupchat\" tipinde özel mesajlar gönderilmesine izin verilmiyor" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "Alıcı konferans odasında değil" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Sadece oda sakinlerinin konferansa mesaj göndermesine izin veriliyor" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "Özel mesaj gönderilmesine izin verilmiyor" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Sadece oda sakinlerinin konferansa sorgu göndermesine izin veriliyor" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "Bu odada konferans üyelerine sorgu yapılmasına izin verilmiyor" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "özel" + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "" +"Sadece moderatörlerin ve katılımcıların bu odanın konusunu değiştirmesine " +"izin veriliyor" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Sadece moderatörlerin bu odanın konusunu değiştirmesine izin veriliyor" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "" +"Ziyaretçilerin odadaki tüm sakinlere mesaj göndermesine izin verilmiyor" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "Bu katılımcı bir hata varlığı (presence) gönderdiği için odadan atıldı" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "" +"Bu odada ziyaretçilerin takma isimlerini değiştirmesine izin verilmiyor" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "Takma isim odanın başka bir sakini tarafından halihazırda kullanımda" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "Takma isim başka biri tarafından kaydettirilmiş" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Bu odaya girmeniz yasaklandı" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "Bu odaya girmek için üyelik gerekiyor" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Bu oda anonim değil" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Bu odaya girmek için parola gerekiyor" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Yanlış parola" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Yönetim yetkileri gerekli" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Moderatör yetkileri gerekli" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "JID ~s geçersiz" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "~s takma ismi odada yok" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Geçersiz ilişki: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Geçersiz rol: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Sahip yetkileri gerekli" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Ayarlar : " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Tanım:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Odayı kalıcı hale getir" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Odayı herkes tarafından aranabilir hale getir" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Katılımcı listesini herkese açık hale getir" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Odayı parola korumalı hale getir" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Odada En Fazla Bulunabilecek Kişi Sayısı" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Sınırsız" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Gerçek JID'lerini göster :" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "sadece moderatörler" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "herkes" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Odayı sadece üyelere açık hale getir" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Odayı moderasyonlu hale getir" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Kullanıcılar öntanımlı olarak katılımcı olsun" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Kullanıcıların konu değiştirmesine izin ver" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Kullanıcıların özel mesaj göndermelerine izin ver" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Kullanıcıların diğer kullanıcıları sorgulamalarına izin ver" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Kullanıcıların davetiye göndermelerine izin ver" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "" +"Ziyaretçilerin varlık (presence) güncellemelerinde durum metni " +"göndermelerine izin ver" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Ziyaretçilerin takma isim değiştirmelerine izin ver" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Kayıt tutma özelliğini aç" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "" +"Odayı ayarlamak için x:data becerisine sahip bir istemciye gereksinimiz var" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Oda sakini sayısı" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s sizi ~s odasına davet ediyor" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "parola :" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "Çevirim-dışı mesaj kuyruğunuz dolu. Mesajını dikkate alınmadı." + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "~s Kullanıcısının Mesaj Kuyruğu" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Gönderilenler" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Zaman" + +#: mod_offline.erl:507 +msgid "From" +msgstr "Kimden" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Kime" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Paket" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Seçilenleri Sil" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Çevirim-dışı Mesajlar:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "ejabberd SOCKS5 Bytestreams modülü" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Yayınla-Üye Ol" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "ejabberd Publish-Subscribe modülü" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "PubSub üye isteği" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Bu varlığın üyeliğini onaylayıp onaylamamayı seçiniz." + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "Düğüm ID" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Üye Olanın Adresi" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Bu JID bu pubsub düğümüne üye olmasına izin verilsin mi?" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Yükleri (payload) olay uyarıları ile beraber gönder" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Olay uyarıları gönderilsin" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Düğüm ayarları değiştiğinde üyeleri uyar" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Bir düğüm silindiğinde üyeleri uyar" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Düğümden öğeler kaldırıldığında üyeleri uyar" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Öğeleri depoda kalıcı hale getir" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "Düğüm için dostane bir isim" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Kalıcı hale getirilecek en fazla öğe sayısı" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Üyeliklere izin verilsin mi" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Erişim modelini belirtiniz" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Üye olunmasına izin verilen kontak listesi grupları" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Yayıncı modelini belirtiniz" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "En fazla yük (payload) boyutu (bayt olarak)" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Son yayınlanan öğe ne zaman gönderilsin" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Uyarıları sadece durumu uygun kullanıcılara ulaştır" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "Bu sunucuya kayıt olmak için bir kullanıcı ismi ve parola seçiniz" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "Kullanıcıların bu kadar hızlı hesap açmalarına izin verilmiyor" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Hiçbiri" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Üyelik" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Sıra Bekleyen" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Gruplar" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Geçerli" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Kaldır" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Kontak Listesi : " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Kötü biçem" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Jabber ID'si Ekle" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Kontak Listesi" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Paylaşımlı Kontak Listesi Grupları" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Yeni Ekle" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "İsim:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Tanım:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Üyeler:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Gösterilen Gruplar:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Group " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Gönder" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Erlang Jabber Sunucusu" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Doğumgünü" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "İl" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "Ülke" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "E-posta" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Soyisim" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Eşleşen jabber kullanıcılarını aramak için formu doldurunuz (Alt dizgi " +"eşlemek için alanın sonuna * ekleyin)" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Tam İsim" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Ortanca İsim" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "İsim" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Kurum İsmi" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Kurumun İlgili Birimi" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Kullanıcılarda arama yap : " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Kullanıcı" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "" +"Arama yapabilmek için x:data becerisine sahip bir istemciye gereksinimiz var" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "vCard Kullanıcı Araması" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "ejabberd vCard modülü" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Arama sonuçları : " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Eşleşen jabber kullanıcılarını aramak için alanları doldurunuz" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "ejabberd Web Yöneticisi" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Yönetim" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Sanal Sunucular" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Düğümler" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "İstatistikler" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Kullanıcılar" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Son Aktivite" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Ham)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Ham" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "~s erişim kuralları ayarları" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "ejabberd sanal sunucuları" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Kullanıcıların Son Aktiviteleri" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Periyot:" + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Geçen ay" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Geçen yıl" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Tüm aktivite" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Sıradan Tabloyu Göster" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Önemli Tabloyu Göster" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Düğüm bulunamadı" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Sunucu" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Kayıtlı Kullanıcılar" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Çevirim-dışı Mesajlar" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Kayıtlı Kullanıcılar:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Bağlı Kullanıcılar:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Giden s2s Bağlantıları:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Giden s2s Sunucuları" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Parola Değiştir" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Kullanıcı " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Bağlı Kaynaklar:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Parola:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Veri Yok" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Düğüm " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Dinlenen Kapılar (Portlar)" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "GÜncelle" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Tekrar Başlat" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Durdur" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "RPC Çağrı Hatası" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Veritabanı Tabloları : " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Depolama Tipi" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Boyut" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Bellek" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Yedek : " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Bu seçeneklerin sadece gömülü Mnesia veritabanını yedekleyeceğine dikkat " +"edin. Eğer ODBC modülünü kullanıyorsanız, SQL veritabanınızı da ayrıca " +"yedeklemeniz gerekiyor." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "İkili yedeği sakla:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "Tamam" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Hemen ikili yedekten geri al:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"ejabberd'nin bir sonraki tekrar başlatılışında ikili yedekten geri al (daha " +"az bellek gerektirir)" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Düz metin yedeği sakla:" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Hemen düz metin yedekten geri al" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Dinlenen Kapılar (Portlar) : " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Modüller : " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "~p istatistikleri" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Hizmet Süresi:" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "İşlemci Zamanı:" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Tamamlanan Hareketler (Transactions Commited):" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "İptal Edilen Hareketler (Transactions):" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Tekrar Başlatılan Hareketler (Transactions):" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Kaydı Tutulan Hareketler (Transactions):" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Güncelle " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Planı güncelle" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Güncellenen modüller" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Betiği Güncelle" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Düşük seviye güncelleme betiği" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Betik kontrolü" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Kapı (Port)" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Modül" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Seçenekler" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Sil" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Başlat" diff --git a/src/msgs/uk.msg b/src/msgs/uk.msg index c6eed76df..a35bc83ef 100644 --- a/src/msgs/uk.msg +++ b/src/msgs/uk.msg @@ -1,390 +1,343 @@ -% $Id$ -% Language: Ukrainian (українська) -% Author: Stoune -% Author: Ruslan Rakhmanin -% Author: Sergei Golovan - -% ejabberd_c2s.erl -{"Use of STARTTLS required", "Ви мусите використовувати STARTTLS"}. -{"Replaced by new connection", "Замінено новим з'єднанням"}. - -% jlib.hrl -{"No resource provided", "Не вказаний ресурс"}. - -% mod_adhoc.erl -{"Commands", "Команди"}. -{"Ping", "Пінг"}. -{"Pong", "Понг"}. - -% mod_announce.erl -{"Send announcement to all users on all hosts", "Надіслати сповіщення до усіх користувачів на усіх хостах"}. -{"Set message of the day on all hosts and send to online users", "Встановити повідомлення дня на всіх хостах та надійслати його підключеним користувачам"}. -{"Update message of the day on all hosts (don't send)", "Оновити повідомлення дня на всіх хостах (не надсилати)"}. -{"Delete message of the day on all hosts", "Видалити повідомлення дня на усіх хостах"}. -{"Really delete message of the day?", "Дійсно видалити повідомлення дня"}. -{"Subject", "Тема"}. -{"Message body", "Тіло повідомлення"}. -{"No body provided for announce message", "Тіло оголошення має бути непустим"}. -{"Announcements", "Оголошення"}. -{"Send announcement to all users", "Надіслати оголошення всім користувачам"}. -{"Send announcement to all online users", "Надіслати оголошення всім підключеним користувачам"}. -{"Send announcement to all online users on all hosts", "Надіслати оголошення всім підключеним користувачам на всіх віртуальних серверах"}. -{"Set message of the day and send to online users", "Встановити повідомлення дня та надіслати його підключеним користувачам"}. -{"Update message of the day (don't send)", "Поновити повідомлення дня (не надсилати)"}. -{"Delete message of the day", "Видалити повідомлення дня"}. - -% mod_configure.erl -{"Restart Service", "Перезапустити Сервіс"}. -{"Shut Down Service", "Відключити Сервіс"}. -{"Delete User", "Видалити Користувача"}. -{"End User Session", "Закінчити Сеанс Користувача"}. -{"Get User Password", "Отримати Пароль Користувача"}. -{"Change User Password", "Змінити Пароль Користувача"}. -{"Get User Last Login Time", "Отримати Час Останнього Підключення Користувача"}. -{"Get User Statistics", "Отримати Статистику по Користувачу"}. -{"Get Number of Registered Users", "Отримати Кількість Зареєстрованих Користувачів"}. -{"Get Number of Online Users", "Отримати Кількість Підключених Користувачів"}. -{"User Management", "Управління Користувачами"}. -{"Time delay", "Час затримки"}. -{"Password Verification", "Перевірка Пароля"}. -{"Number of registered users", "Кількість Зареєстрованих Користувачів"}. -{"Number of online users", "Кількість Підключених Користувачів"}. -{"Last login", "Останнє підключення"}. -{"Roster size", "Кількість контактів"}. -{"IP addresses", "IP адреси"}. -{"Resources", "Ресурси"}. -{"Database Tables Configuration at ", "Конфігурація таблиць бази даних на "}. -{"Choose storage type of tables", "Оберіть тип збереження таблиць"}. -{"RAM copy", "ОЗП"}. -{"RAM and disc copy", "ОЗП та диск"}. -{"Disc only copy", "тільки диск"}. -{"Remote copy", "не зберігаеться локально"}. -{"Stop Modules at ", "Зупинка модулів на "}. -{"Choose modules to stop", "Виберіть модулі, які необхідно зупинити"}. -{"Start Modules at ", "Запуск модулів на "}. -{"Enter list of {Module, [Options]}", "Введіть перелік такого виду {Module, [Options]}"}. -{"List of modules to start", "Список завантажуваних модулів"}. -{"Backup to File at ", "Резервне копіювання в файл на "}. -{"Enter path to backup file", "Введіть шлях до резервного файла"}. -{"Path to File", "Шлях до файла"}. -{"Restore Backup from File at ", "Відновлення з резервної копії на "}. -{"Dump Backup to Text File at ", "Копіювання в текстовий файл на "}. -{"Enter path to text file", "Введіть шлях до текстового файла"}. -{"Import User from File at ", "Імпортування користувача з файла на "}. -{"Enter path to jabberd1.4 spool file", "Введіть шлях до файла зі спула jabberd1.4"}. -{"Import Users from Dir at ", "Імпортування користувача з директорії на "}. -{"Enter path to jabberd1.4 spool dir", "Введіть шлях до директорії спула jabberd1.4"}. -{"Path to Dir", "шлях до директорії"}. -{"Access Control List Configuration", "Конфігурація списків керування доступом"}. -{"Access control lists", "Списки керування доступом"}. -{"Access Configuration", "Конфігурація доступа"}. -{"Access rules", "Правила доступу"}. -{"Administration of ", "Адміністрування "}. -{"Action on user", "Дія над користувачем"}. -{"Edit Properties", "Змінити параметри"}. -{"Remove User", "Видалити користувача"}. - -% mod_disco.erl -{"Configuration", "Конфігурація"}. -{"Online Users", "Підключені користувачі"}. -{"All Users", "Всі користувачі"}. -{"Outgoing s2s Connections", "Вихідні s2s-з'єднання"}. -{"To ~s", "До ~s"}. -{"From ~s", "Від ~s"}. -{"Running Nodes", "Працюючі вузли"}. -{"Stopped Nodes", "Зупинені вузли"}. -{"Access Control Lists", "Списки керування доступом"}. -{"Access Rules", "Правила доступу"}. -{"Database", "База даних"}. -{"Modules", "Модулі"}. -{"Start Modules", "Запуск модулів"}. -{"Stop Modules", "Зупинка модулів"}. -{"Backup Management", "Керування резервним копіюванням"}. -{"Import Users From jabberd 1.4 Spool Files", "Імпорт користувачів зі спулу jabberd 1.4"}. -{"Backup", "Резервне копіювання"}. -{"Restore", "Відновлення з резервної копії"}. -{"Dump to Text File", "Копіювання в текстовий файл"}. -{"Import File", "Імпорт з файла"}. -{"Import Directory", "Імпорт з директорії"}. - -% mod_proxy65.erl - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "ejabberd SOCKS5 Bytestreams модуль"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Виберіть назву користувача та пароль для реєстрації на цьому сервері"}. - -% mod_vcard.erl -{"Erlang Jabber Server", "Erlang Jabber Server"}. -{"ejabberd vCard module", "ejabberd vCard модуль"}. -{"You need an x:data capable client to search", "Для пошуку необхідний x:data-придатний клієнт"}. -{"Search users in ", "Пошук користувачів в "}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Заповніть поля для пошуку користувача Jabber (Додайте * в кінець поля для пошуку підрядка)"}. -{"Search Results for ", "Результати пошуку в "}. -{"Jabber ID", "Jabber ID"}. -{"User", "Користувач"}. -{"Full Name", "Повне ім'я"}. -{"Name", "Ім'я"}. -{"Middle Name", "По-батькові"}. -{"Family Name", "Прізвище"}. -{"Nickname", "Псевдонім"}. -{"Birthday", "День народження"}. -{"Country", "Країна"}. -{"City", "Місто"}. -{"Email", "Електронна пошта"}. -{"Organization Name", "Назва організації"}. -{"Organization Unit", "Відділ організації"}. - -% mod_vcard_ldap.erl -{"Fill in fields to search for any matching Jabber User", "Заповніть поля для пошуку користувача Jabber"}. - -% mod_pubsub/mod_pubsub.erl -{"Roster groups allowed to subscribe", "Дозволені для абонування групи ростера"}. -{"Publish-Subscribe", "Опублікувати-Абонувати"}. -{"ejabberd Publish-Subscribe module", "Модуль ejabberd Публікації-Абонування"}. -{"PubSub subscriber request", "Запит на абонування PubSub"}. -{"Choose whether to approve this entity's subscription.", "Вирішіть, чи задовольнити запит цього об'єкту на підписку"}. -{"Node ID", "ID вузла"}. -{"Subscriber Address", "Адреса абонента"}. -{"Allow this JID to subscribe to this pubsub node?", "Чи дозволити цьому JID абонувати новини наданого вузла"}. -{"Deliver event notifications", "Доставляти сповіщення про події"}. -{"Specify the access model", "Визначити модель доступу"}. -{"When to send the last published item", "Коли надсилати останній опублікований елемент"}. -{"Deliver payloads with event notifications", "Доставляти разом з повідомленнями про публікації самі публікації"}. -{"Notify subscribers when the node configuration changes", "Повідомляти абонентів про зміни в конфігурації збірника"}. -{"Notify subscribers when the node is deleted", "Повідомляти абонентів про видалення збірника"}. -{"Notify subscribers when items are removed from the node", "Повідомляти абонентів про видалення публікацій із збірника"}. -{"Persist items to storage", "Зберегати публікації до сховища"}. -{"Max # of items to persist", "Максимальне число збережених публікацій"}. -{"Whether to allow subscriptions", "Дозволити передплату"}. -{"Specify the publisher model", "Умови публікації"}. -{"Max payload size in bytes", "Максимальний розмір корисного навантаження в байтах"}. -{"Only deliver notifications to available users", "Доставляти повідомленнями тільки доступним користувачам"}. - -% mod_muc/mod_muc.erl -{"Chatrooms", "Кімнати"}. -{"You need an x:data capable client to register nickname", "Для реєстрації псевдоніму необхідний x:data-придатний клієнт"}. -{"Nickname Registration at ", "Реєстрація псевдоніма на "}. -{"Enter nickname you want to register", "Введіть псевдонім, який ви хочете зареєструвати"}. -{"ejabberd MUC module", "ejabberd MUC модуль"}. -{"Only service administrators are allowed to send service messages", "Тільки адміністратор сервісу може надсилати службові повідомлення"}. -{"Room creation is denied by service policy", "Створювати конференцію заборонено політикою служби"}. -{"Conference room does not exist", "Конференція не існує"}. -{"Access denied by service policy", "Доступ заборонений політикою служби"}. -{"You must fill in field \"Nickname\" in the form", "Вам необхідно заповнити поле \"Псевдонім\" у формі"}. -{"Specified nickname is already registered", "Вказаний псевдонім вже зареєстрований"}. - -% /home/sergei/src/ejabberd/ejabberd/src/mod_muc/mod_muc_log.erl -{"has been kicked because of an affiliation change", "вигнано з кімнати як наслідок зміни ранга"}. -{"has been kicked because the room has been changed to members-only", "вигнано з кімнати тому, що воня стала тільки для учасників"}. -{"has been kicked because of a system shutdown", "вигнано з кімнати як наслідок зупинки системи"}. -{"Chatroom configuration modified", "Конфігурація кімнати змінилась"}. -{"joins the room", "увійшов(ла) в кімнату"}. -{"leaves the room", "вийшов(ла) з кімнати"}. -{"has been kicked", "вигнали з кімнати"}. -{"has been banned", "заборонили вхід в кімнату"}. -{"is now known as", "змінив(ла) им'я на"}. -{"Monday", "Понеділок"}. -{"Tuesday", "Вівторок"}. -{"Wednesday", "Середа"}. -{"Thursday", "Четвер"}. -{"Friday", "П'ятниця"}. -{"Saturday", "Субота"}. -{"Sunday", "Неділя"}. -{"January", "січня"}. -{"February", "лютого"}. -{"March", "березня"}. -{"April", "квітня"}. -{"May", "травня"}. -{"June", "червня"}. -{"July", "липня"}. -{"August", "серпня"}. -{"September", "вересня"}. -{"October", "грудня"}. -{"November", "листопада"}. -{"December", "грудня"}. -{"Room Configuration", "Конфігурація кімнати"}. - -% mod_muc/mod_muc_room.erl -{"This participant is kicked from the room because he sent an error message", "Цього учасника було відключено від кімнати через те, що він надіслав помилкове повідомлення"}. -{"This participant is kicked from the room because he sent an error message to another participant", "Цього учасника було відключено від кімнати через те, що він надіслав помилкове повідомлення іншому учаснику"}. -{"This participant is kicked from the room because he sent an error presence", "Цього учасника було відключено від кімнати через те, що він надіслав помилковий статус присутності"}. -{"Make room moderated", "Зробити кімнату модерованою"}. -{"Traffic rate limit is exceeded", "Швидкість передачі інформації було перевищено"}. -{"Maximum Number of Occupants", "Максимальна кількість учасників"}. -{"No limit", "Без обмежень"}. -{"~s invites you to the room ~s", "~s запрошує вас до кімнати ~s"}. -{"the password is", "пароль:"}. -{" has set the subject to: ", " встановив(ла) тему: "}. -{"This room is not anonymous", "Ця кімната не анонімна"}. -{"You need an x:data capable client to configure room", "Для конфігурування кімнати необхідний x:data-придатний кліент"}. -{"Configuration for ", "Конфігурація "}. -{"Room title", "Назва кімнати"}. -{"Allow users to change subject", "Дозволити користувачам змінювати тему"}. -{"Allow users to query other users", "Дозволити iq-запити до користувачів"}. -{"Allow users to send private messages", "Дозволити приватні повідомлення"}. -{"Make room public searchable", "Зробити кімнату видимою всім"}. -{"Make participants list public", "Зробити список учасників видимим всім"}. -{"Make room persistent", "Зробити кімнату постійною"}. -{"Make - room moderated", "Зробити кімнату модерованою"}. -{"Default users as participants", "Зробити користувачів учасниками за замовчуванням"}. -{"Make room members-only", "Кімната тільки для зареєтрованых учасників"}. -{"Allow users to send invites", "Дозволити користувачам надсилати запрошення"}. -{"Make room password protected", "Зробити кімнату захищеною паролем"}. -{"Password", "Пароль"}. -{"Present real JIDs to", "Зробити реальні JID учасників видимими"}. -{"moderators only", "тільки модераторам"}. -{"anyone", "всім учасникам"}. -{"Enable logging", "Включити журнал роботи"}. -{"Only moderators and participants are allowed to change subject in this room", "Тільки модератори та учасники можуть змінювати тему в цій кімнаті"}. -{"Only moderators are allowed to change subject in this room", "Тільки модератори можуть змінювати тему в цій кімнаті"}. -{"Visitors are not allowed to send messages to all occupants", "Відвідувачам не дозволяється надсилати повідомлення всім присутнім"}. -{"Only occupants are allowed to send messages to the conference", "Тільки присутнім дозволяється надсилати повідомленняя в конференцію"}. -{"It is not allowed to send private messages to the conference", "Не дозволяється надсилати приватні повідомлення в конференцію"}. -{"Improper message type", "Неправильний тип повідомлення"}. -{"Nickname is already in use by another occupant", "Псевдонім зайнятий кимось з присутніх"}. -{"Nickname is registered by another person", "Псевдонім зареєстрований кимось іншим"}. -{"It is not allowed to send private messages of type \"groupchat\"", "Не дозволяється надсилати приватні повідомлення типу \"groupchat\""}. -{"Recipient is not in the conference room", "Адресата немає в конференції"}. -{"Only occupants are allowed to send queries to the conference", "Тільки присутнім дозволяється відправляти запити в конференцію"}. -{"Queries to the conference members are not allowed in this room", "Запити до користувачів в цій конференції зоборонені"}. -{"You have been banned from this room", "Вам заборонено входити в цю конференцію"}. -{"Membership required to enter this room", "В цю конференціию можуть входити тільки її члени"}. -{"Password required to enter this room", "Щоб зайти в цю конференцію, необхідний пароль"}. -{"Incorrect password", "Неправильний пароль"}. -{"Administrator privileges required", "Необхідні права адміністратора"}. -{"Moderator privileges required", "Необхідні права модератора"}. -{"JID ~s is invalid", "JID ~s недопустимий"}. -{"Nickname ~s does not exist in the room", "Псевдонім ~s в кімнаті відсутній"}. -{"Invalid affiliation: ~s", "Недопустимий ранг: ~s"}. -{"Invalid role: ~s", "Недопустима роль: ~s"}. -{"Owner privileges required", "Необхідні права власника"}. -{"private, ", "приватна, "}. -{"Number of occupants", "Кількість присутніх"}. - -% mod_irc/mod_irc.erl -{"IRC Transport", "IRC Транспорт"}. -{"ejabberd IRC module", "ejabberd IRC модуль"}. -{"You need an x:data capable client to configure mod_irc settings", "Для налагодження параметрів mod_irc необхідний x:data-придатний клієнт"}. -{"Registration in mod_irc for ", "Реєстрація в mod_irc для "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Введіть ім'я користувача та кодування, які будуть використовуватися при підключенні до IRC-серверів"}. -{"IRC Username", "Ім'я користувача IRC"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Щоб вказати різні кодування для різних серверів IRC, заповніть список значеннями в форматі '{\"irc server\", \"encoding\"}'. За замовчуванням ця служба використовує кодування \"~s\"."}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Приклад: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"Encodings", "Кодування"}. - -% web/ejabberd_web_admin.erl -{"ejabberd Web Admin", "Веб-інтерфейс Адміністрування ejabberd"}. -{"Administration", "Адміністрування"}. -{"Users", "Користувачі"}. -{"Nodes", "Вузли"}. -{"Statistics", "Статистика"}. -{"(Raw)", "(Необроблений формат)"}. -{"Submitted", "Відправлено"}. -{"Bad format", "Неправильний формат"}. -{"Raw", "необроблений формат"}. -{"Delete Selected", "Видалити виділені"}. -{"Submit", "Відправити"}. -{"~s access rule configuration", "Конфігурація правила доступу ~s"}. -{"Node not found", "Вузол не знайдено"}. -{"Add New", "Додати"}. -{"Registered Users", "Зареєстровані користувачі"}. -{"Registered Users:", "Зареєстровані користувачі:"}. -{"Online Users", "Підключені користувачі"}. -{"Online Users:", "Підключені користувачі:"}. -{"Outgoing s2s Connections:", "Вихідні s2s-з'єднання:"}. -{"Outgoing s2s Servers:", "Вихідні s2s-сервери:"}. -{"Change Password", "Змінити пароль"}. -{"Connected Resources:", "Підключені ресурси:"}. -{"Password:", "Пароль:"}. -{"None", "Немає"}. -{"Node ", "Вузол "}. -{"Listened Ports", "Відкриті порти"}. -{"Restart", "Перезапустити"}. -{"Stop", "Зупинити"}. -{"RPC Call Error", "Помилка виклику RPC"}. -{"Database Tables at ", "Таблиці бази даних на "}. -{"Name", "Назва"}. -{"Storage Type", "Тип таблиці"}. -{"Size", "Розмір"}. -{"Memory", "Пам'ять"}. -{"Backup of ", "Резервне копіювання "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "Зауважте, що тут відбувається резервне копіювання тільки вбудованної бази даних Mnesia. Якщо Ви також використовуєте інше сховище для даних (наприклад за допомогою модуля ODBC), то його резервне копіювання потрібно робити окремо."}. -{"Store binary backup:", "Зберегти бінарну резервну копію:"}. -{"OK", "Продовжити"}. -{"Restore binary backup immediately:", "Відновити з бінарної резервної копії негайно:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Відновити з бінарної резервної копії при наступному запуску (потребує менше пам'яті):"}. -{"Store plain text backup:", "Зберегти текстову резервну копію:"}. -{"Restore plain text backup immediately:", "Відновити з текстової резервної копії негайно:"}. -{"Listened Ports at ", "Відкриті порти на "}. -{"Statistics of ~p", "статистика вузла ~p"}. -{"Uptime:", "Час роботи:"}. -{"CPU Time:", "Процесорний час:"}. -{"Transactions Commited:", "Транзакції завершені:"}. -{"Transactions Aborted:", "Транзакції відмінені:"}. -{"Transactions Restarted:", "Транзакції перезапущені:"}. -{"Transactions Logged:", "Транзакції запротокольовані:"}. -{"Update ", "Поновлення "}. -{"Update plan", "План поновлення"}. -{"Updated modules", "Поновлені модулі"}. -{"Update script", "Сценарій поновлення"}. -{"Low level update script", "Низькорівневий сценарій поновлення"}. -{"Script check", "Перевірка сценарію"}. -{"Port", "Порт"}. -{"Module", "Модуль"}. -{"Options", "Параметри"}. -{"Update", "Обновити"}. -{"Delete", "Видалити"}. -{"Add User", "Додати користувача"}. -{"Offline Messages", "Офлайнові повідомлення"}. -{"Offline Messages:", "Офлайнові повідомлення:"}. -{"Last Activity", "Останнє підключення"}. -{"Never", "Ніколи"}. -{"~s's Offline Messages Queue", "Черга офлайнових повідомлень ~s"}. -{"Time", "Час"}. -{"From", "Від кого"}. -{"To", "Кому"}. -{"Packet", "Пакет"}. -{"Roster", "Ростер"}. -{"Nickname", "Псевдонім"}. -{"Subscription", "Підписка"}. -{"Pending", "Очікування"}. -{"Groups", "Групи"}. -{"Remove", "Видалити"}. -{"Add Jabber ID", "Додати Jabber ID"}. -{"User ", "Користувач "}. -{"Roster of ", "Ростер користувача "}. -{"Online", "Підключений"}. -{"Validate", "Затвердити"}. -{"Shared Roster Groups", "Спільні групи контактів"}. -{"Name:", "Назва:"}. -{"Description:", "Опис:"}. -{"Members:", "Члени:"}. -{"Displayed Groups:", "Видимі групи:"}. -{"Group ", "Група "}. -{"Users Last Activity", "Статистика останнього підключення користувачів"}. -{"Period: ", "Період"}. -{"Last month", "За останній місяць"}. -{"Last year", "За останній рік"}. -{"All activity", "Вся статистика"}. -{"Show Ordinary Table", "Показати звичайну таблицю"}. -{"Show Integral Table", "Показати інтегральну таблицю"}. -{"Start", "Запустити"}. -{"Modules at ", "Модулі на "}. -{"No Data", "Немає даних"}. -{"Virtual Hosts", "Віртуальні хости"}. -{"ejabberd virtual hosts", "віртуальні хости ejabberd"}. -{"Host", "Хост"}. - -% mod_vcard_odbc.erl -{"vCard User Search", "Пошук користувачів по vCard"}. - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "Черга повідомлень, що не були доставлені, переповнена. Повідомлення не було збережено."}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Конфігурація доступа"}. +{"Access Control List Configuration","Конфігурація списків керування доступом"}. +{"Access control lists","Списки керування доступом"}. +{"Access Control Lists","Списки керування доступом"}. +{"Access denied by service policy","Доступ заборонений політикою служби"}. +{"Access rules","Правила доступу"}. +{"Access Rules","Правила доступу"}. +{"Action on user","Дія над користувачем"}. +{"Add Jabber ID","Додати Jabber ID"}. +{"Add New","Додати"}. +{"Add User","Додати користувача"}. +{"Administration of ","Адміністрування "}. +{"Administration","Адміністрування"}. +{"Administrator privileges required","Необхідні права адміністратора"}. +{"A friendly name for the node","Псевдонім для вузла"}. +{"All activity","Вся статистика"}. +{"Allow this JID to subscribe to this pubsub node?","Чи дозволити цьому JID абонувати новини наданого вузла"}. +{"Allow users to change subject","Дозволити користувачам змінювати тему"}. +{"Allow users to query other users","Дозволити iq-запити до користувачів"}. +{"Allow users to send invites","Дозволити користувачам надсилати запрошення"}. +{"Allow users to send private messages","Дозволити приватні повідомлення"}. +{"Allow visitors to change nickname","Дозволити відвідувачам змінювати псевдонім"}. +{"Allow visitors to send status text in presence updates","Дозволити відвідувачам відсилати текст статусу в оновленнях присутності"}. +{"All Users","Всі користувачі"}. +{"Announcements","Оголошення"}. +{"anyone","всім учасникам"}. +{"April","квітня"}. +{"August","серпня"}. +{"Backup Management","Керування резервним копіюванням"}. +{"Backup of ","Резервне копіювання "}. +{"Backup to File at ","Резервне копіювання в файл на "}. +{"Backup","Резервне копіювання"}. +{"Bad format","Неправильний формат"}. +{"Birthday","День народження"}. +{"Change Password","Змінити пароль"}. +{"Change User Password","Змінити Пароль Користувача"}. +{"Chatroom configuration modified","Конфігурація кімнати змінилась"}. +{"Chatrooms","Кімнати"}. +{"Choose a username and password to register with this server","Виберіть назву користувача та пароль для реєстрації на цьому сервері"}. +{"Choose modules to stop","Виберіть модулі, які необхідно зупинити"}. +{"Choose storage type of tables","Оберіть тип збереження таблиць"}. +{"Choose whether to approve this entity's subscription.","Вирішіть, чи задовольнити запит цього об'єкту на підписку"}. +{"City","Місто"}. +{"Commands","Команди"}. +{"Conference room does not exist","Конференція не існує"}. +{"Configuration for ","Конфігурація "}. +{"Configuration","Конфігурація"}. +{"Connected Resources:","Підключені ресурси:"}. +{"Country","Країна"}. +{"CPU Time:","Процесорний час:"}. +{"Database Tables at ","Таблиці бази даних на "}. +{"Database Tables Configuration at ","Конфігурація таблиць бази даних на "}. +{"Database","База даних"}. +{"December","грудня"}. +{"Default users as participants","Зробити користувачів учасниками за замовчуванням"}. +{"Delete message of the day on all hosts","Видалити повідомлення дня на усіх хостах"}. +{"Delete message of the day","Видалити повідомлення дня"}. +{"Delete Selected","Видалити виділені"}. +{"Delete User","Видалити Користувача"}. +{"Delete","Видалити"}. +{"Deliver event notifications","Доставляти сповіщення про події"}. +{"Deliver payloads with event notifications","Доставляти разом з повідомленнями про публікації самі публікації"}. +{"Description:","Опис:"}. +{"Disc only copy","тільки диск"}. +{"Displayed Groups:","Видимі групи:"}. +{"Dump Backup to Text File at ","Копіювання в текстовий файл на "}. +{"Dump to Text File","Копіювання в текстовий файл"}. +{"Edit Properties","Змінити параметри"}. +{"ejabberd IRC module","ejabberd IRC модуль"}. +{"ejabberd MUC module","ejabberd MUC модуль"}. +{"ejabberd Publish-Subscribe module","Модуль ejabberd Публікації-Абонування"}. +{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestreams модуль"}. +{"ejabberd vCard module","ejabberd vCard модуль"}. +{"ejabberd virtual hosts","віртуальні хости ejabberd"}. +{"ejabberd Web Admin","Веб-інтерфейс Адміністрування ejabberd"}. +{"Email","Електронна пошта"}. +{"Enable logging","Включити журнал роботи"}. +{"Encodings","Кодування"}. +{"End User Session","Закінчити Сеанс Користувача"}. +{"Enter list of {Module, [Options]}","Введіть перелік такого виду {Module, [Options]}"}. +{"Enter nickname you want to register","Введіть псевдонім, який ви хочете зареєструвати"}. +{"Enter path to backup file","Введіть шлях до резервного файла"}. +{"Enter path to jabberd1.4 spool dir","Введіть шлях до директорії спула jabberd1.4"}. +{"Enter path to jabberd1.4 spool file","Введіть шлях до файла зі спула jabberd1.4"}. +{"Enter path to text file","Введіть шлях до текстового файла"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Введіть ім'я користувача та кодування, які будуть використовуватися при підключенні до IRC-серверів"}. +{"Erlang Jabber Server","Erlang Jabber Server"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Приклад: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","Прізвище"}. +{"February","лютого"}. +{"Fill in fields to search for any matching Jabber User","Заповніть поля для пошуку користувача Jabber"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Заповніть поля для пошуку користувача Jabber (Додайте * в кінець поля для пошуку підрядка)"}. +{"Friday","П'ятниця"}. +{"From ~s","Від ~s"}. +{"From","Від кого"}. +{"Full Name","Повне ім'я"}. +{"Get Number of Online Users","Отримати Кількість Підключених Користувачів"}. +{"Get Number of Registered Users","Отримати Кількість Зареєстрованих Користувачів"}. +{"Get User Last Login Time","Отримати Час Останнього Підключення Користувача"}. +{"Get User Password","Отримати Пароль Користувача"}. +{"Get User Statistics","Отримати Статистику по Користувачу"}. +{"Groups","Групи"}. +{"Group ","Група "}. +{"has been banned","заборонили вхід в кімнату"}. +{"has been kicked because of an affiliation change","вигнано з кімнати як наслідок зміни ранга"}. +{"has been kicked because of a system shutdown","вигнано з кімнати як наслідок зупинки системи"}. +{"has been kicked because the room has been changed to members-only","вигнано з кімнати тому, що воня стала тільки для учасників"}. +{"has been kicked","вигнали з кімнати"}. +{" has set the subject to: "," встановив(ла) тему: "}. +{"Host","Хост"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Щоб вказати різні кодування для різних серверів IRC, заповніть список значеннями в форматі '{\"irc server\", \"encoding\"}'. За замовчуванням ця служба використовує кодування \"~s\"."}. +{"Import Directory","Імпорт з директорії"}. +{"Import File","Імпорт з файла"}. +{"Import User from File at ","Імпортування користувача з файла на "}. +{"Import Users from Dir at ","Імпортування користувача з директорії на "}. +{"Import Users From jabberd 1.4 Spool Files","Імпорт користувачів зі спулу jabberd 1.4"}. +{"Improper message type","Неправильний тип повідомлення"}. +{"Incorrect password","Неправильний пароль"}. +{"Invalid affiliation: ~s","Недопустимий ранг: ~s"}. +{"Invalid role: ~s","Недопустима роль: ~s"}. +{"IP addresses","IP адреси"}. +{"IRC Transport","IRC Транспорт"}. +{"IRC Username","Ім'я користувача IRC"}. +{"is now known as","змінив(ла) им'я на"}. +{"It is not allowed to send private messages of type \"groupchat\"","Не дозволяється надсилати приватні повідомлення типу \"groupchat\""}. +{"It is not allowed to send private messages to the conference","Не дозволяється надсилати приватні повідомлення в конференцію"}. +{"It is not allowed to send private messages","Приватні повідомлення не дозволені"}. +{"Jabber ID","Jabber ID"}. +{"January","січня"}. +{"JID ~s is invalid","JID ~s недопустимий"}. +{"joins the room","увійшов(ла) в кімнату"}. +{"July","липня"}. +{"June","червня"}. +{"Last Activity","Останнє підключення"}. +{"Last login","Останнє підключення"}. +{"Last month","За останній місяць"}. +{"Last year","За останній рік"}. +{"leaves the room","вийшов(ла) з кімнати"}. +{"Listened Ports at ","Відкриті порти на "}. +{"Listened Ports","Відкриті порти"}. +{"List of modules to start","Список завантажуваних модулів"}. +{"Low level update script","Низькорівневий сценарій поновлення"}. +{"Make participants list public","Зробити список учасників видимим всім"}. +{"Make room members-only","Кімната тільки для зареєтрованых учасників"}. +{"Make room moderated","Зробити кімнату модерованою"}. +{"Make room password protected","Зробити кімнату захищеною паролем"}. +{"Make room persistent","Зробити кімнату постійною"}. +{"Make room public searchable","Зробити кімнату видимою всім"}. +{"March","березня"}. +{"Maximum Number of Occupants","Максимальна кількість учасників"}. +{"Max # of items to persist","Максимальне число збережених публікацій"}. +{"Max payload size in bytes","Максимальний розмір корисного навантаження в байтах"}. +{"May","травня"}. +{"Membership required to enter this room","В цю конференціию можуть входити тільки її члени"}. +{"Members:","Члени:"}. +{"Memory","Пам'ять"}. +{"Message body","Тіло повідомлення"}. +{"Middle Name","По-батькові"}. +{"Moderator privileges required","Необхідні права модератора"}. +{"moderators only","тільки модераторам"}. +{"Modules at ","Модулі на "}. +{"Modules","Модулі"}. +{"Module","Модуль"}. +{"Monday","Понеділок"}. +{"Name:","Назва:"}. +{"Name","Назва"}. +{"Never","Ніколи"}. +{"Nickname is already in use by another occupant","Псевдонім зайнятий кимось з присутніх"}. +{"Nickname is registered by another person","Псевдонім зареєстрований кимось іншим"}. +{"Nickname Registration at ","Реєстрація псевдоніма на "}. +{"Nickname ~s does not exist in the room","Псевдонім ~s в кімнаті відсутній"}. +{"Nickname","Псевдонім"}. +{"No body provided for announce message","Тіло оголошення має бути непустим"}. +{"No Data","Немає даних"}. +{"Node ID","ID вузла"}. +{"Node not found","Вузол не знайдено"}. +{"Nodes","Вузли"}. +{"Node ","Вузол "}. +{"No limit","Без обмежень"}. +{"None","Немає"}. +{"No resource provided","Не вказаний ресурс"}. +{"Notify subscribers when items are removed from the node","Повідомляти абонентів про видалення публікацій із збірника"}. +{"Notify subscribers when the node configuration changes","Повідомляти абонентів про зміни в конфігурації збірника"}. +{"Notify subscribers when the node is deleted","Повідомляти абонентів про видалення збірника"}. +{"November","листопада"}. +{"Number of occupants","Кількість присутніх"}. +{"Number of online users","Кількість Підключених Користувачів"}. +{"Number of registered users","Кількість Зареєстрованих Користувачів"}. +{"October","грудня"}. +{"Offline Messages:","Офлайнові повідомлення:"}. +{"Offline Messages","Офлайнові повідомлення"}. +{"OK","Продовжити"}. +{"Online Users:","Підключені користувачі:"}. +{"Online Users","Підключені користувачі"}. +{"Online","Підключений"}. +{"Only deliver notifications to available users","Доставляти повідомленнями тільки доступним користувачам"}. +{"Only moderators and participants are allowed to change subject in this room","Тільки модератори та учасники можуть змінювати тему в цій кімнаті"}. +{"Only moderators are allowed to change subject in this room","Тільки модератори можуть змінювати тему в цій кімнаті"}. +{"Only occupants are allowed to send messages to the conference","Тільки присутнім дозволяється надсилати повідомленняя в конференцію"}. +{"Only occupants are allowed to send queries to the conference","Тільки присутнім дозволяється відправляти запити в конференцію"}. +{"Only service administrators are allowed to send service messages","Тільки адміністратор сервісу може надсилати службові повідомлення"}. +{"Options","Параметри"}. +{"Organization Name","Назва організації"}. +{"Organization Unit","Відділ організації"}. +{"Outgoing s2s Connections:","Вихідні s2s-з'єднання:"}. +{"Outgoing s2s Connections","Вихідні s2s-з'єднання"}. +{"Outgoing s2s Servers:","Вихідні s2s-сервери:"}. +{"Owner privileges required","Необхідні права власника"}. +{"Packet","Пакет"}. +{"Password required to enter this room","Щоб зайти в цю конференцію, необхідний пароль"}. +{"Password Verification","Перевірка Пароля"}. +{"Password:","Пароль:"}. +{"Password","Пароль"}. +{"Path to Dir","шлях до директорії"}. +{"Path to File","Шлях до файла"}. +{"Pending","Очікування"}. +{"Period: ","Період"}. +{"Persist items to storage","Зберегати публікації до сховища"}. +{"Ping","Пінг"}. +{"Pong","Понг"}. +{"Port","Порт"}. +{"Present real JIDs to","Зробити реальні JID учасників видимими"}. +{"private, ","приватна, "}. +{"Publish-Subscribe","Опублікувати-Абонувати"}. +{"PubSub subscriber request","Запит на абонування PubSub"}. +{"Queries to the conference members are not allowed in this room","Запити до користувачів в цій конференції зоборонені"}. +{"RAM and disc copy","ОЗП та диск"}. +{"RAM copy","ОЗП"}. +{"Raw","необроблений формат"}. +{"(Raw)","(Необроблений формат)"}. +{"Really delete message of the day?","Дійсно видалити повідомлення дня"}. +{"Recipient is not in the conference room","Адресата немає в конференції"}. +{"Registered Users:","Зареєстровані користувачі:"}. +{"Registered Users","Зареєстровані користувачі"}. +{"Registration in mod_irc for ","Реєстрація в mod_irc для "}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Зауважте, що тут відбувається резервне копіювання тільки вбудованної бази даних Mnesia. Якщо Ви також використовуєте інше сховище для даних (наприклад за допомогою модуля ODBC), то його резервне копіювання потрібно робити окремо."}. +{"Remote copy","не зберігаеться локально"}. +{"Remove User","Видалити користувача"}. +{"Remove","Видалити"}. +{"Replaced by new connection","Замінено новим з'єднанням"}. +{"Resources","Ресурси"}. +{"Restart Service","Перезапустити Сервіс"}. +{"Restart","Перезапустити"}. +{"Restore Backup from File at ","Відновлення з резервної копії на "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Відновити з бінарної резервної копії при наступному запуску (потребує менше пам'яті):"}. +{"Restore binary backup immediately:","Відновити з бінарної резервної копії негайно:"}. +{"Restore plain text backup immediately:","Відновити з текстової резервної копії негайно:"}. +{"Restore","Відновлення з резервної копії"}. +{"Room Configuration","Конфігурація кімнати"}. +{"Room creation is denied by service policy","Створювати конференцію заборонено політикою служби"}. +{"Room title","Назва кімнати"}. +{"Roster groups allowed to subscribe","Дозволені для абонування групи ростера"}. +{"Roster of ","Ростер користувача "}. +{"Roster size","Кількість контактів"}. +{"Roster","Ростер"}. +{"RPC Call Error","Помилка виклику RPC"}. +{"Running Nodes","Працюючі вузли"}. +{"~s access rule configuration","Конфігурація правила доступу ~s"}. +{"Saturday","Субота"}. +{"Script check","Перевірка сценарію"}. +{"Search Results for ","Результати пошуку в "}. +{"Search users in ","Пошук користувачів в "}. +{"Send announcement to all online users on all hosts","Надіслати оголошення всім підключеним користувачам на всіх віртуальних серверах"}. +{"Send announcement to all online users","Надіслати оголошення всім підключеним користувачам"}. +{"Send announcement to all users on all hosts","Надіслати сповіщення до усіх користувачів на усіх хостах"}. +{"Send announcement to all users","Надіслати оголошення всім користувачам"}. +{"September","вересня"}. +{"Set message of the day and send to online users","Встановити повідомлення дня та надіслати його підключеним користувачам"}. +{"Set message of the day on all hosts and send to online users","Встановити повідомлення дня на всіх хостах та надійслати його підключеним користувачам"}. +{"Shared Roster Groups","Спільні групи контактів"}. +{"Show Integral Table","Показати інтегральну таблицю"}. +{"Show Ordinary Table","Показати звичайну таблицю"}. +{"Shut Down Service","Відключити Сервіс"}. +{"~s invites you to the room ~s","~s запрошує вас до кімнати ~s"}. +{"Size","Розмір"}. +{"Specified nickname is already registered","Вказаний псевдонім вже зареєстрований"}. +{"Specify the access model","Визначити модель доступу"}. +{"Specify the publisher model","Умови публікації"}. +{"~s's Offline Messages Queue","Черга офлайнових повідомлень ~s"}. +{"Start Modules at ","Запуск модулів на "}. +{"Start Modules","Запуск модулів"}. +{"Start","Запустити"}. +{"Statistics of ~p","статистика вузла ~p"}. +{"Statistics","Статистика"}. +{"Stop Modules at ","Зупинка модулів на "}. +{"Stop Modules","Зупинка модулів"}. +{"Stopped Nodes","Зупинені вузли"}. +{"Stop","Зупинити"}. +{"Storage Type","Тип таблиці"}. +{"Store binary backup:","Зберегти бінарну резервну копію:"}. +{"Store plain text backup:","Зберегти текстову резервну копію:"}. +{"Subject","Тема"}. +{"Submitted","Відправлено"}. +{"Submit","Відправити"}. +{"Subscriber Address","Адреса абонента"}. +{"Subscription","Підписка"}. +{"Sunday","Неділя"}. +{"the password is","пароль:"}. +{"This participant is kicked from the room because he sent an error message to another participant","Цього учасника було відключено від кімнати через те, що він надіслав помилкове повідомлення іншому учаснику"}. +{"This participant is kicked from the room because he sent an error message","Цього учасника було відключено від кімнати через те, що він надіслав помилкове повідомлення"}. +{"This participant is kicked from the room because he sent an error presence","Цього учасника було відключено від кімнати через те, що він надіслав помилковий статус присутності"}. +{"This room is not anonymous","Ця кімната не анонімна"}. +{"Thursday","Четвер"}. +{"Time delay","Час затримки"}. +{"Time","Час"}. +{"To ~s","До ~s"}. +{"To","Кому"}. +{"Traffic rate limit is exceeded","Швидкість передачі інформації було перевищено"}. +{"Transactions Aborted:","Транзакції відмінені:"}. +{"Transactions Commited:","Транзакції завершені:"}. +{"Transactions Logged:","Транзакції запротокольовані:"}. +{"Transactions Restarted:","Транзакції перезапущені:"}. +{"Tuesday","Вівторок"}. +{"Updated modules","Поновлені модулі"}. +{"Update message of the day (don't send)","Поновити повідомлення дня (не надсилати)"}. +{"Update message of the day on all hosts (don't send)","Оновити повідомлення дня на всіх хостах (не надсилати)"}. +{"Update plan","План поновлення"}. +{"Update script","Сценарій поновлення"}. +{"Update","Обновити"}. +{"Update ","Поновлення "}. +{"Uptime:","Час роботи:"}. +{"Use of STARTTLS required","Ви мусите використовувати STARTTLS"}. +{"User Management","Управління Користувачами"}. +{"Users are not allowed to register accounts so fast","Користувачам не дозволено так часто реєструвати облікові записи"}. +{"Users Last Activity","Статистика останнього підключення користувачів"}. +{"Users","Користувачі"}. +{"User ","Користувач "}. +{"User","Користувач"}. +{"Validate","Затвердити"}. +{"vCard User Search","Пошук користувачів по vCard"}. +{"Virtual Hosts","Віртуальні хости"}. +{"Visitors are not allowed to change their nicknames in this room","Відвідувачам не дозволяється змінювати псевдонім в цій кімнаті"}. +{"Visitors are not allowed to send messages to all occupants","Відвідувачам не дозволяється надсилати повідомлення всім присутнім"}. +{"Wednesday","Середа"}. +{"When to send the last published item","Коли надсилати останній опублікований елемент"}. +{"Whether to allow subscriptions","Дозволити передплату"}. +{"You have been banned from this room","Вам заборонено входити в цю конференцію"}. +{"You must fill in field \"Nickname\" in the form","Вам необхідно заповнити поле \"Псевдонім\" у формі"}. +{"You need an x:data capable client to configure mod_irc settings","Для налагодження параметрів mod_irc необхідний x:data-придатний клієнт"}. +{"You need an x:data capable client to configure room","Для конфігурування кімнати необхідний x:data-придатний кліент"}. +{"You need an x:data capable client to register nickname","Для реєстрації псевдоніму необхідний x:data-придатний клієнт"}. +{"You need an x:data capable client to search","Для пошуку необхідний x:data-придатний клієнт"}. +{"Your contact offline message queue is full. The message has been discarded.","Черга повідомлень, що не були доставлені, переповнена. Повідомлення не було збережено."}. diff --git a/src/msgs/uk.po b/src/msgs/uk.po new file mode 100644 index 000000000..2eebfdad0 --- /dev/null +++ b/src/msgs/uk.po @@ -0,0 +1,1498 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Ruslan Rakhmanin\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Ukrainian (українська)\n" +"X-Additional-Translator: Stoune\n" +"X-Additional-Translator: Sergei Golovan\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "Ви мусите використовувати STARTTLS" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Не вказаний ресурс" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Замінено новим з'єднанням" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Команди" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Пінг" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Понг" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Дійсно видалити повідомлення дня" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Тема" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Тіло повідомлення" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "Тіло оголошення має бути непустим" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Оголошення" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Надіслати оголошення всім користувачам" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Надіслати сповіщення до усіх користувачів на усіх хостах" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Надіслати оголошення всім підключеним користувачам" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "" +"Надіслати оголошення всім підключеним користувачам на всіх віртуальних " +"серверах" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Встановити повідомлення дня та надіслати його підключеним користувачам" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Встановити повідомлення дня на всіх хостах та надійслати його підключеним " +"користувачам" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Поновити повідомлення дня (не надсилати)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Оновити повідомлення дня на всіх хостах (не надсилати)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Видалити повідомлення дня" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Видалити повідомлення дня на усіх хостах" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Конфігурація" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "База даних" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Запуск модулів" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Зупинка модулів" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Резервне копіювання" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Відновлення з резервної копії" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Копіювання в текстовий файл" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Імпорт з файла" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Імпорт з директорії" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Перезапустити Сервіс" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Відключити Сервіс" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Додати користувача" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Видалити Користувача" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Закінчити Сеанс Користувача" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Отримати Пароль Користувача" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Змінити Пароль Користувача" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Отримати Час Останнього Підключення Користувача" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Отримати Статистику по Користувачу" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Отримати Кількість Зареєстрованих Користувачів" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Отримати Кількість Підключених Користувачів" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Списки керування доступом" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Правила доступу" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Управління Користувачами" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Підключені користувачі" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Всі користувачі" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Вихідні s2s-з'єднання" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Працюючі вузли" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Зупинені вузли" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Модулі" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Керування резервним копіюванням" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Імпорт користувачів зі спулу jabberd 1.4" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "До ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "Від ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Конфігурація таблиць бази даних на " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Оберіть тип збереження таблиць" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "тільки диск" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "ОЗП та диск" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "ОЗП" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "не зберігаеться локально" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Зупинка модулів на " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Виберіть модулі, які необхідно зупинити" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Запуск модулів на " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Введіть перелік такого виду {Module, [Options]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Список завантажуваних модулів" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Резервне копіювання в файл на " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Введіть шлях до резервного файла" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Шлях до файла" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Відновлення з резервної копії на " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Копіювання в текстовий файл на " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Введіть шлях до текстового файла" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Імпортування користувача з файла на " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Введіть шлях до файла зі спула jabberd1.4" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Імпортування користувача з директорії на " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Введіть шлях до директорії спула jabberd1.4" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "шлях до директорії" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Час затримки" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Конфігурація списків керування доступом" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Списки керування доступом" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Конфігурація доступа" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Правила доступу" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Пароль" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Перевірка Пароля" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Кількість Зареєстрованих Користувачів" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Кількість Підключених Користувачів" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Ніколи" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Підключений" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Останнє підключення" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Кількість контактів" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "IP адреси" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Ресурси" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Адміністрування " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Дія над користувачем" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Змінити параметри" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Видалити користувача" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Доступ заборонений політикою служби" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "IRC Транспорт" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "ejabberd IRC модуль" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "Для налагодження параметрів mod_irc необхідний x:data-придатний клієнт" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Реєстрація в mod_irc для " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Введіть ім'я користувача та кодування, які будуть використовуватися при " +"підключенні до IRC-серверів" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "Ім'я користувача IRC" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Щоб вказати різні кодування для різних серверів IRC, заповніть список " +"значеннями в форматі '{\"irc server\", \"encoding\"}'. За замовчуванням ця " +"служба використовує кодування \"~s\"." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Приклад: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Кодування" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "Тільки адміністратор сервісу може надсилати службові повідомлення" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "Створювати конференцію заборонено політикою служби" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "Конференція не існує" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Кімнати" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "Для реєстрації псевдоніму необхідний x:data-придатний клієнт" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Реєстрація псевдоніма на " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Введіть псевдонім, який ви хочете зареєструвати" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Псевдонім" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "Вказаний псевдонім вже зареєстрований" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Вам необхідно заповнити поле \"Псевдонім\" у формі" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "ejabberd MUC модуль" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Конфігурація кімнати змінилась" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "увійшов(ла) в кімнату" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "вийшов(ла) з кімнати" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "заборонили вхід в кімнату" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "вигнали з кімнати" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "вигнано з кімнати як наслідок зміни ранга" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "вигнано з кімнати тому, що воня стала тільки для учасників" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "вигнано з кімнати як наслідок зупинки системи" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "змінив(ла) им'я на" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " встановив(ла) тему: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "Понеділок" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "Вівторок" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "Середа" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "Четвер" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "П'ятниця" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "Субота" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "Неділя" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "січня" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "лютого" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "березня" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "квітня" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "травня" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "червня" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "липня" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "серпня" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "вересня" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "грудня" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "листопада" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "грудня" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Конфігурація кімнати" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Назва кімнати" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Швидкість передачі інформації було перевищено" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" +"Цього учасника було відключено від кімнати через те, що він надіслав " +"помилкове повідомлення" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Не дозволяється надсилати приватні повідомлення в конференцію" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Неправильний тип повідомлення" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Цього учасника було відключено від кімнати через те, що він надіслав " +"помилкове повідомлення іншому учаснику" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "Не дозволяється надсилати приватні повідомлення типу \"groupchat\"" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "Адресата немає в конференції" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Тільки присутнім дозволяється надсилати повідомленняя в конференцію" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "Приватні повідомлення не дозволені" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Тільки присутнім дозволяється відправляти запити в конференцію" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "Запити до користувачів в цій конференції зоборонені" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "приватна, " + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "Тільки модератори та учасники можуть змінювати тему в цій кімнаті" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Тільки модератори можуть змінювати тему в цій кімнаті" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "Відвідувачам не дозволяється надсилати повідомлення всім присутнім" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" +"Цього учасника було відключено від кімнати через те, що він надіслав " +"помилковий статус присутності" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Відвідувачам не дозволяється змінювати псевдонім в цій кімнаті" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "Псевдонім зайнятий кимось з присутніх" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "Псевдонім зареєстрований кимось іншим" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Вам заборонено входити в цю конференцію" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "В цю конференціию можуть входити тільки її члени" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Ця кімната не анонімна" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Щоб зайти в цю конференцію, необхідний пароль" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Неправильний пароль" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Необхідні права адміністратора" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Необхідні права модератора" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "JID ~s недопустимий" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "Псевдонім ~s в кімнаті відсутній" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Недопустимий ранг: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Недопустима роль: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Необхідні права власника" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Конфігурація " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Опис:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Зробити кімнату постійною" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Зробити кімнату видимою всім" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Зробити список учасників видимим всім" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Зробити кімнату захищеною паролем" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Максимальна кількість учасників" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Без обмежень" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Зробити реальні JID учасників видимими" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "тільки модераторам" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "всім учасникам" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Кімната тільки для зареєтрованых учасників" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Зробити кімнату модерованою" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Зробити користувачів учасниками за замовчуванням" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Дозволити користувачам змінювати тему" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Дозволити приватні повідомлення" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Дозволити iq-запити до користувачів" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Дозволити користувачам надсилати запрошення" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "" +"Дозволити відвідувачам відсилати текст статусу в оновленнях присутності" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Дозволити відвідувачам змінювати псевдонім" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Включити журнал роботи" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "Для конфігурування кімнати необхідний x:data-придатний кліент" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Кількість присутніх" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s запрошує вас до кімнати ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "пароль:" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "" +"Черга повідомлень, що не були доставлені, переповнена. Повідомлення не було " +"збережено." + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "Черга офлайнових повідомлень ~s" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Відправлено" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Час" + +#: mod_offline.erl:507 +msgid "From" +msgstr "Від кого" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Кому" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Пакет" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Видалити виділені" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Офлайнові повідомлення:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "ejabberd SOCKS5 Bytestreams модуль" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Опублікувати-Абонувати" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "Модуль ejabberd Публікації-Абонування" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "Запит на абонування PubSub" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Вирішіть, чи задовольнити запит цього об'єкту на підписку" + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "ID вузла" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Адреса абонента" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Чи дозволити цьому JID абонувати новини наданого вузла" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Доставляти разом з повідомленнями про публікації самі публікації" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Доставляти сповіщення про події" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Повідомляти абонентів про зміни в конфігурації збірника" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Повідомляти абонентів про видалення збірника" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Повідомляти абонентів про видалення публікацій із збірника" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Зберегати публікації до сховища" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "Псевдонім для вузла" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Максимальне число збережених публікацій" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Дозволити передплату" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Визначити модель доступу" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Дозволені для абонування групи ростера" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Умови публікації" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Максимальний розмір корисного навантаження в байтах" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Коли надсилати останній опублікований елемент" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Доставляти повідомленнями тільки доступним користувачам" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "Виберіть назву користувача та пароль для реєстрації на цьому сервері" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "Користувачам не дозволено так часто реєструвати облікові записи" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Немає" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Підписка" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Очікування" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Групи" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Затвердити" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Видалити" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Ростер користувача " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Неправильний формат" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Додати Jabber ID" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Ростер" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Спільні групи контактів" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Додати" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Назва:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Опис:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Члени:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Видимі групи:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Група " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Відправити" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Erlang Jabber Server" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "День народження" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Місто" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "Країна" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "Електронна пошта" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Прізвище" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Заповніть поля для пошуку користувача Jabber (Додайте * в кінець поля для " +"пошуку підрядка)" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Повне ім'я" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "По-батькові" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Назва" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Назва організації" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Відділ організації" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Пошук користувачів в " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Користувач" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "Для пошуку необхідний x:data-придатний клієнт" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "Пошук користувачів по vCard" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "ejabberd vCard модуль" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Результати пошуку в " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Заповніть поля для пошуку користувача Jabber" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "Веб-інтерфейс Адміністрування ejabberd" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Адміністрування" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Віртуальні хости" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Вузли" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Статистика" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Користувачі" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Останнє підключення" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Необроблений формат)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "необроблений формат" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "Конфігурація правила доступу ~s" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "віртуальні хости ejabberd" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Статистика останнього підключення користувачів" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Період" + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "За останній місяць" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "За останній рік" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Вся статистика" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Показати звичайну таблицю" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Показати інтегральну таблицю" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Вузол не знайдено" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Хост" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Зареєстровані користувачі" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Офлайнові повідомлення" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Зареєстровані користувачі:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Підключені користувачі:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Вихідні s2s-з'єднання:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Вихідні s2s-сервери:" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Змінити пароль" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Користувач " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Підключені ресурси:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Пароль:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Немає даних" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Вузол " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Відкриті порти" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Обновити" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Перезапустити" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Зупинити" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "Помилка виклику RPC" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Таблиці бази даних на " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Тип таблиці" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Розмір" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Пам'ять" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Резервне копіювання " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Зауважте, що тут відбувається резервне копіювання тільки вбудованної бази " +"даних Mnesia. Якщо Ви також використовуєте інше сховище для даних (наприклад " +"за допомогою модуля ODBC), то його резервне копіювання потрібно робити " +"окремо." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Зберегти бінарну резервну копію:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "Продовжити" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Відновити з бінарної резервної копії негайно:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"Відновити з бінарної резервної копії при наступному запуску (потребує менше " +"пам'яті):" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Зберегти текстову резервну копію:" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Відновити з текстової резервної копії негайно:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Відкриті порти на " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Модулі на " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "статистика вузла ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Час роботи:" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "Процесорний час:" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Транзакції завершені:" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Транзакції відмінені:" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Транзакції перезапущені:" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Транзакції запротокольовані:" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Поновлення " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "План поновлення" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Поновлені модулі" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Сценарій поновлення" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Низькорівневий сценарій поновлення" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Перевірка сценарію" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Порт" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Модуль" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Параметри" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Видалити" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Запустити" diff --git a/src/msgs/vi.msg b/src/msgs/vi.msg index 545224a4d..77783bd42 100644 --- a/src/msgs/vi.msg +++ b/src/msgs/vi.msg @@ -1,374 +1,328 @@ -% $Id$ -% Language: Vietnamese (tiếng việt) -% Author: EQHO Communications (Thailand) Ltd. - http://www.eqho.com - -% mod_vcard_odbc.erl -{"Erlang Jabber Server", "Erlang Jabber Server Bản quyền"}. -{"You need an x:data capable client to search", "Bạn cần có một trình ứng dụng khách hỗ trợ định dạng dữ liệu x: để tìm kiếm"}. -{"Search users in ", "Tìm kiếm người sử dụng trong"}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Điền vào mẫu này để tìm kiếm bất kỳ thông tin nào khớp với Người sử dụng Jabber (Thêm dấu * vào cuối ô để thông tin khớp với chuỗi bên trong)"}. -{"User", "Người sử dụng"}. -{"Full Name", "Tên Đầy Đủ"}. -{"Name", "Tên"}. -{"Middle Name", "Họ Đệm"}. -{"Family Name", "Họ"}. -{"Nickname", "Bí danh"}. -{"Birthday", "Ngày sinh"}. -{"Country", "Quốc gia"}. -{"City", "Thành phố"}. -{"Email", "Email"}. -{"Organization Name", "Tên Tổ Chức"}. -{"Organization Unit", "Bộ Phận"}. -{"vCard User Search", "Tìm Kiếm Người Sử Dụng vCard"}. -{"ejabberd vCard module", "Môdun ejabberd vCard Bản quyền"}. -{"Search Results for ", "Kết Quả Tìm Kiếm cho "}. -{"Jabber ID", "Jabber ID"}. - -% mod_roster.erl -{"None", "Không có"}. -{"Subscription", "Đăng ký"}. -{"Pending", "Chờ"}. -{"Groups", "Nhóm"}. -{"Validate", "Xác nhận hợp lệ"}. -{"Remove", "Gỡ bỏ"}. -{"Roster of ", "Bảng phân công của "}. -{"Submitted", "Đã gửi"}. -{"Bad format", "Định dạng hỏng"}. -{"Add Jabber ID", "Thêm Jabber ID"}. -{"Roster", "Bảng phân công"}. - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "Danh sách chờ thư liên lạc ngoại tuyến của bạn đã đầy. Thư này đã bị loại bỏ."}. -{"~s's Offline Messages Queue", "~s's Danh Sách Chờ Thư Ngoại Tuyến"}. -{"Packet", "Gói thông tin"}. -{"Delete Selected", "Tùy chọn Xóa được Chọn"}. -{"Offline Messages:", "Thư Ngoại Tuyến:"}. - -% ejabberd_c2s.erl -{"Use of STARTTLS required", "Yêu cầu sử dụng STARTTLS"}. -{"No resource provided", "Không có nguồn lực cung cấp"}. -{"Replaced by new connection", "Được thay thế bởi kết nối mới"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Chọn một tên truy cập và mật khẩu để đăng ký với máy chủ này"}. - -% mod_vcard_ldap.erl -{"Fill in fields to search for any matching Jabber User", "Điền vào các ô để tìm kiếm bất kỳ các thông tin nào khớp với Người sử dụng Jabber"}. - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "Môdun SOCKS5 Bytestreams Bản quyền"}. - -% mod_shared_roster.erl -{"Add New", "Thêm Mới"}. -{"Shared Roster Groups", "Nhóm Phân Công Chia Sẻ"}. -{"Name:", "Tên:"}. -{"Description:", "Miêu tả:"}. -{"Members:", "Thành viên:"}. -{"Displayed Groups:", "Nhóm được hiển thị:"}. -{"Group ", "Nhóm "}. -{"Submit", "Gửi"}. - -% mod_announce.erl -{"Really delete message of the day?", "Có thực sự xóa thư trong ngày này không?"}. -{"Subject", "Tiêu đề"}. -{"Message body", "Thân thư"}. -{"No body provided for announce message", "Không có nội dung trong thư thông báo"}. -{"Announcements", "Thông báo"}. -{"Send announcement to all users", "Gửi thông báo đến tất cả người sử dụng"}. -{"Send announcement to all users on all hosts", "Gửi thông báo đến tất cả người sử dụng trên tất cả các máy chủ"}. -{"Send announcement to all online users", "Gửi thông báo đến tất cả người sử dụng trực tuyến"}. -{"Send announcement to all online users on all hosts", "Gửi thông báo đến tất cả người sử dụng trực tuyến trên tất cả các máy chủ"}. -{"Set message of the day and send to online users", "Tạo lập thư trong ngày và gửi đến những người sử dụng trực tuyến"}. -{"Set message of the day on all hosts and send to online users", "Tạo lập thư trong ngày trên tất cả các máy chủ và gửi đến những người sử dụng trực tuyến"}. -{"Update message of the day (don't send)", "Cập nhật thư trong ngày (không gửi)"}. -{"Update message of the day on all hosts (don't send)", "Cập nhật thư trong ngày trên tất cả các máy chủ (không gửi)"}. -{"Delete message of the day", "Xóa thư trong ngày"}. -{"Delete message of the day on all hosts", "Xóa thư trong ngày trên tất cả các máy chủ"}. - -% mod_adhoc.erl -{"Commands", "Lệnh"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% mod_irc/mod_irc.erl -{"Access denied by service policy", "Sự truy cập bị chặn theo chính sách phục vụ"}. -{"IRC Transport", "Truyền tải IRC"}. -{"ejabberd IRC module", "Môdun ejabberd IRC Bản quyền"}. -{"You need an x:data capable client to configure mod_irc settings", "Bạn cần có một trình ứng dụng khách hỗ trợ định dạng dữ liệu x: để xác định các thiết lập mod_irc"}. -{"Registration in mod_irc for ", "Đăng ký trong mod_irc cho "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Nhập tên truy cập và mã hóa mà bạn muốn sử dụng khi kết nối với các máy chủ IRC"}. -{"IRC Username", "Tên truy cập IRC"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Nếu bạn muốn xác định các cách thức mã hóa khác nhau cho các máy chủ IRC, hãy điền vào danh sách này những giá trị theo định dạng '{\"máy chủ irc\", \"mã hóa\"}'. Dịch vụ này mặc định sử dụng định dạng mã hóa \"~s\"."}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Ví dụ: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]"}. -{"Encodings", "Mã hóa"}. - -% mod_configure.erl -{"Configuration", "Cấu hình"}. -{"Database", "Cơ sở dữ liệu"}. -{"Start Modules", "Môđun Khởi Động"}. -{"Stop Modules", "Môđun Dừng"}. -{"Backup", "Sao lưu dự phòng"}. -{"Restore", "Khôi phục"}. -{"Dump to Text File", "Kết xuất ra Tập Tin Văn Bản"}. -{"Import File", "Nhập Tập Tin"}. -{"Import Directory", "Nhập Thư Mục"}. -{"Restart Service", "Khởi Động Lại Dịch Vụ"}. -{"Shut Down Service", "Tắt Dịch Vụ"}. -{"Add User", "Thêm Người Sử Dụng"}. -{"Delete User", "Xóa Người Sử Dụng"}. -{"End User Session", "Kết Thúc Phiên Giao Dịch Người Sử Dụng"}. -{"Get User Password", "Nhận Mật Khẩu Người Sử Dụng"}. -{"Change User Password", "Thay Đổi Mật Khẩu Người Sử Dụng"}. -{"Get User Last Login Time", "Nhận Thời Gian Đăng Nhập Cuối Cùng Của Người Sử Dụng"}. -{"Get User Statistics", "Nhận Thông Tin Thống Kê Người Sử Dụng"}. -{"Get Number of Registered Users", "Nhận Số Người Sử Dụng Đã Đăng Ký"}. -{"Get Number of Online Users", "Nhận Số Người Sử Dụng Trực Tuyến"}. -{"Access Control Lists", "Danh Sách Kiểm Soát Truy Cập"}. -{"Access Rules", "Quy Tắc Truy Cập"}. -{"User Management", "Quản Lý Người Sử Dụng"}. -{"Online Users", "Người Sử Dụng Trực Tuyến"}. -{"All Users", "Tất Cả Người Sử Dụng"}. -{"Outgoing s2s Connections", "Kết Nối Bên Ngoài s2s"}. -{"Running Nodes", "Nút Hoạt Động"}. -{"Stopped Nodes", "Nút Dừng"}. -{"Modules", "Môđun"}. -{"Backup Management", "Quản lý Sao Lưu Dự Phòng"}. -{"Import Users From jabberd 1.4 Spool Files", "Nhập Người Sử Dụng Từ Các Tập Tin Spool jabberd 1,4"}. -{"To ~s", "Gửi đến ~s"}. -{"From ~s", "Nhận từ ~s"}. -{"Database Tables Configuration at ", "Cấu Hình Bảng Cơ Sở Dữ Liệu tại"}. -{"Choose storage type of tables", "Chọn loại bảng lưu trữ"}. -{"RAM copy", "Sao chép vào RAM"}. -{"RAM and disc copy", "Sao chép vào RAM và đĩa"}. -{"Disc only copy", "Chỉ sao chép vào đĩa"}. -{"Remote copy", "Sao chép từ xa"}. -{"Stop Modules at ", "Môđun Dừng tại"}. -{"Choose modules to stop", "Chọn môđun để dừng"}. -{"Start Modules at ", "Môđun Khởi Động tại "}. -{"Enter list of {Module, [Options]}", "Nhập danh sách {Môđun, [Các Tùy Chọn]}"}. -{"List of modules to start", "Danh sách các môđun khởi động"}. -{"Backup to File at ", "Sao lưu dự phòng ra Tập Tin tại"}. -{"Enter path to backup file", "Nhập đường dẫn đến tập tin sao lưu dự phòng"}. -{"Path to File", "Đường dẫn đến Tập Tin"}. -{"Restore Backup from File at ", "Phục hồi Sao Lưu từ Tập Tin tại "}. -{"Dump Backup to Text File at ", "Kết Xuất Sao Lưu ra Tập Tin Văn Bản tại"}. -{"Enter path to text file", "Nhập đường dẫn đến tập tin văn bản"}. -{"Import User from File at ", "Nhập Người Sử Dụng từ Tập Tin tại"}. -{"Enter path to jabberd1.4 spool file", "Nhập đường dẫn đến tập tin spool jabberd1,4"}. -{"Import Users from Dir at ", "Nhập Người Sử Dụng từ Thư Mục tại"}. -{"Enter path to jabberd1.4 spool dir", "Nhập đường dẫn đến thư mục spool jabberd1,4"}. -{"Path to Dir", "Đường Dẫn đến Thư Mục"}. -{"Time delay", "Thời gian trì hoãn"}. -{"Access Control List Configuration", "Cấu Hình Danh Sách Kiểm Soát Truy Cập"}. -{"Access control lists", "Danh sách kiểm soát truy cập"}. -{"Access Configuration", "Cấu Hình Truy Cập"}. -{"Access rules", "Quy tắc Truy Cập"}. -{"Password", "Mật Khẩu"}. -{"Password Verification", "Kiểm Tra Mật Khẩu"}. -{"Number of registered users", "Số người sử dụng đã đăng ký"}. -{"Number of online users", "Số người sử dụng trực tuyến"}. -{"Never", "Không bao giờ"}. -{"Online", "Trực tuyến"}. -{"Last login", "Đăng nhập lần cuối"}. -{"Roster size", "Kích thước bảng phân công"}. -{"IP addresses", "Địa chỉ IP"}. -{"Resources", "Nguồn tài nguyên"}. -{"Administration of ", "Quản trị về "}. -{"Action on user", "Hành động đối với người sử dụng"}. -{"Edit Properties", "Chỉnh Sửa Thuộc Tính"}. -{"Remove User", "Gỡ Bỏ Người Sử Dụng"}. - -% mod_pubsub/mod_pubsub.erl -{"Publish-Subscribe", "Xuất Bản-Đăng Ký"}. -{"ejabberd Publish-Subscribe module", "Môdun ejabberd Xuất Bản-Đăng Ký Bản quyền"}. -{"PubSub subscriber request", "Yêu cầu người đăng ký môđun Xuất Bản Đăng Ký"}. -{"Choose whether to approve this entity's subscription.", "Chọn có nên chấp nhận sự đăng ký của đối tượng này không"}. -{"Node ID", "ID Nút"}. -{"Subscriber Address", "Địa Chỉ Người Đăng Ký"}. -{"Allow this JID to subscribe to this pubsub node?", "Cho phép JID đăng ký nút môđun xuất bản đăng ký này không?"}. -{"Deliver payloads with event notifications", "Đưa ra thông tin dung lượng với các thông báo sự kiện"}. -{"Deliver event notifications", "Đưa ra các thông báo sự kiện"}. -{"Notify subscribers when the node configuration changes", "Thông báo cho người đăng ký khi nào cấu hình nút thay đổi"}. -{"Notify subscribers when the node is deleted", "Thông báo cho người đăng ký khi nào nút bị xóa bỏ"}. -{"Notify subscribers when items are removed from the node", "Thông báo cho người đăng ký khi nào các mục chọn bị gỡ bỏ khỏi nút"}. -{"Persist items to storage", "Những mục cần để lưu trữ"}. -{"Max # of items to persist", "Số mục tối đa để lưu trữ"}. -{"Whether to allow subscriptions", "Xác định nên cho phép đăng ký không"}. -{"Specify the access model", "Xác định mô hình truy cập"}. -{"Roster groups that may subscribe (if access model is roster)", "Các nhóm phân công có thể đăng ký (nếu mô hình truy cập là dạng phân công)"}. -{"Specify the publisher model", "Xác định mô hình nhà xuất bản"}. -{"Max payload size in bytes", "Kích thước dung lượng byte tối đa"}. -{"When to send the last published item", "Khi cần gửi mục được xuất bản cuối cùng"}. -{"Only deliver notifications to available users", "Chỉ gửi thông báo đến những người sử dụng hiện có"}. - -% web/ejabberd_web_admin.erl -{"ejabberd Web Interface", "Giao diện Web ejabberd"}. -{"Administration", "Quản trị"}. -{"Virtual Hosts", "Máy Chủ Ảo"}. -{"Nodes", "Nút"}. -{"Statistics", "Số liệu thống kê"}. -{"Users", "Người sử dụng"}. -{"Last Activity", "Hoạt Động Cuối Cùng"}. -{"(Raw)", "(Thô)"}. -{"Raw", "Thô"}. -{"~s access rule configuration", "~s cấu hình quy tắc truy cập"}. -{"ejabberd virtual hosts", "Máy chủ ảo ejabberd"}. -{"Users Last Activity", "Hoạt Động Cuối Cùng Của Người Sử Dụng"}. -{"Period: ", "Giai đoạn: "}. -{"Last month", "Tháng trước"}. -{"Last year", "Năm trước"}. -{"All activity", "Tất cả hoạt động"}. -{"Show Ordinary Table", "Hiển Thị Bảng Thường"}. -{"Show Integral Table", "Hiển Thị Bảng Đầy Đủ"}. -{"Node not found", "Nút không tìm thấy"}. -{"Host", "Máy chủ"}. -{"Registered Users", "Người Sử Dụng Đã Đăng Ký"}. -{"Offline Messages", "Thư Ngoại Tuyến"}. -{"Registered Users:", "Người Sử Dụng Đã Đăng Ký:"}. -{"Online Users:", "Người Sử Dụng Trực Tuyến:"}. -{"Outgoing s2s Connections:", "Kết Nối Bên Ngoài s2s:"}. -{"Outgoing s2s Servers:", "Máy chủ Bên Ngoài s2s:"}. -{"Change Password", "Thay Đổi Mật Khẩu"}. -{"User ", "Người sử dụng "}. -{"Connected Resources:", "Tài Nguyên Được Kết Nối:"}. -{"Password:", "Mật Khẩu:"}. -{"No Data", "Không Dữ Liệu"}. -{"Node ", "Nút "}. -{"Listened Ports", "Cổng Kết Nối"}. -{"Update", "Cập Nhật"}. -{"Restart", "Khởi động lại"}. -{"Stop", "Dừng"}. -{"RPC Call Error", "Lỗi Gọi RPC"}. -{"Database Tables at ", "Bảng Cơ Sở Dữ Liệu tại"}. -{"Storage Type", "Loại Lưu Trữ"}. -{"Size", "Kích thước"}. -{"Memory", "Bộ Nhớ"}. -{"Backup of ", "Sao lưu dự phòng về"}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "Lưu ý rằng những tùy chọn này sẽ chỉ được sao lưu cơ sở dữ liệu bên trong Mnesia. Nếu bạn đang sử dụng môđun ODBC, bạn cũng cần sao lưu cơ sở dữ liệu SQL của bạn riêng biệt."}. -{"Store binary backup:", "Lưu dữ liệu sao lưu dạng nhị phân:"}. -{"OK", "OK"}. -{"Restore binary backup immediately:", "Khôi phục bản sao lưu dự phòng dạng nhị phận ngay lập tức:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Khôi phục bản sao lưu dự phòng dạng nhị phân sau lần khởi động ejabberd kế tiếp (yêu cầu ít bộ nhớ hơn):"}. -{"Store plain text backup:", "Khôi phục bản sao lưu dự phòng thuần văn bản"}. -{"Restore plain text backup immediately:", "Khôi phục bản sao lưu dự phòng thuần văn bản ngay lập tức:"}. -{"Listened Ports at ", "Cổng Liên Lạc tại"}. -{"Modules at ", "Môđun tại "}. -{"Statistics of ~p", "Thống kê về ~p"}. -{"Uptime:", "Thời gian tải lên:"}. -{"CPU Time:", "Thời Gian CPU:"}. -{"Transactions Commited:", "Giao Dịch Được Cam Kết:"}. -{"Transactions Aborted:", "Giao Dịch Hủy Bỏ:"}. -{"Transactions Restarted:", "Giao Dịch Khởi Động Lại:"}. -{"Transactions Logged:", "Giao Dịch Được Ghi Nhận:"}. -{"Update ", "Cập Nhật "}. -{"Update plan", "Kế hoạch cập nhật"}. -{"Updated modules", "Môđun cập nhật"}. -{"Update script", "Cập nhận lệnh"}. -{"Low level update script", "Lệnh cập nhật mức độ thấp"}. -{"Script check", "Lệnh kiểm tra"}. -{"Port", "Cổng"}. -{"Module", "Môđun"}. -{"Options", "Tùy chọn"}. -{"Delete", "Xóa"}. -{"Start", "Khởi động"}. - -% mod_muc/mod_muc.erl -{"Only service administrators are allowed to send service messages", "Chỉ có người quản trị dịch vụ mới được phép gửi những thư dịch vụ"}. -{"Room creation is denied by service policy", "Việc tạo phòng bị ngăn lại theo chính sách dịch vụ"}. -{"Conference room does not exist", "Phòng họp không tồn tại"}. -{"Chatrooms", "Phòng trò chuyện"}. -{"You need an x:data capable client to register nickname", "Bạn cần có một trình ứng dụng khách hỗ trợ định dạng dữ liệu x: để đăng ký bí danh"}. -{"Nickname Registration at ", "Đăng Ký Bí Danh tại"}. -{"Enter nickname you want to register", "Nhập bí danh bạn muốn đăng ký"}. -{"Specified nickname is already registered", "Bí danh xác định đã đăng ký rồi"}. -{"You must fill in field \"Nickname\" in the form", "Bạn phải điền thông tin vào ô \"Nickname\" trong biểu mẫu này"}. -{"ejabberd MUC module", "Môdun ejabberd MUC Bản quyền"}. - -% mod_muc/mod_muc_room.erl -{"Traffic rate limit is exceeded", "Quá giới hạn tỷ lệ lưu lượng truyền tải"}. -{"It is not allowed to send private messages to the conference", "Không được phép gửi những thư riêng đến phòng họp"}. -{"Improper message type", "Loại thư không phù hợp"}. -{"Only occupants are allowed to send messages to the conference", "Chỉ có những đối tượng tham gia mới được phép gửi thư đến phòng họp"}. -{"It is not allowed to send private messages of type \"groupchat\"", "Không được phép gửi những thư riêng loại \"groupchat\""}. -{"Recipient is not in the conference room", "Người nhận không có trong phòng họp"}. -{"Only occupants are allowed to send queries to the conference", "Chỉ có những đối tượng tham gia mới được phép gửi yêu cầu đến phòng họp"}. -{"Queries to the conference members are not allowed in this room", "Không được phép gửi các yêu cầu gửi đến các thành viên trong phòng họp này"}. -{"private, ", "riêng,"}. -{"Only moderators and participants are allowed to change subject in this room", "Chỉ có những người điều phối và những người tham gia được phép thay đổi chủ đề trong phòng này"}. -{"Only moderators are allowed to change subject in this room", "Chỉ có những người điều phối được phép thay đổi chủ đề trong phòng này"}. -{"Visitors are not allowed to send messages to all occupants", "Người ghé thăm không được phép gửi thư đến tất cả các người tham dự"}. -{"Nickname is already in use by another occupant", "Bí danh đang do một người tham dự khác sử dụng"}. -{"Nickname is registered by another person", "Một người khác đã đăng ký bí danh này rồi"}. -{"You have been banned from this room", "Bạn bị cấm tham gia phòng này"}. -{"Membership required to enter this room", "Yêu cầu tư cách thành viên khi tham gia vào phòng này"}. -{"This room is not anonymous", "Phòng này không nặc danh"}. -{"Password required to enter this room", "Yêu cầu nhập mật khẩu để vào phòng này"}. -{"Incorrect password", "Mật khẩu sai"}. -{" has set the subject to: ", " đã đặt chủ đề thành: "}. -{"Administrator privileges required", "Yêu cầu đặc quyền của nhà quản trị"}. -{"Moderator privileges required", "Yêu cầu đặc quyền của nhà điều phối"}. -{"JID ~s is invalid", "JID ~s không hợp lệ"}. -{"Nickname ~s does not exist in the room", "Bí danh ~s không tồn tại trong phòng này"}. -{"Invalid affiliation: ~s", "Tư cách không hợp lệ: ~s"}. -{"Invalid role: ~s", "Vai trò không hợp lệ: ~s"}. -{"Owner privileges required", "Yêu cầu đặc quyền của người sở hữu"}. -{"Configuration for ", "Cấu hình cho "}. -{"Room title", "Tên phòng"}. -{"Make room persistent", "Tạo phòng bền vững"}. -{"Make room public searchable", "Tạo phòng có thể tìm kiếm công khai"}. -{"Make participants list public", "Tạo danh sách người tham dự công khai"}. -{"Make room password protected", "Tạo phòng được bảo vệ bằng mật khẩu"}. -{"Maximum Number of Occupants", "Số Lượng Người Tham Dự Tối Đa"}. -{"No limit", "Không giới hạn"}. -{"Present real JIDs to", "JID thực tế hiện hành đến"}. -{"moderators only", "nhà điều phối duy nhất"}. -{"anyone", "bất kỳ ai"}. -{"Make room members-only", "Tạo phòng chỉ cho phép tư cách thành viên tham gia"}. -{"Default users as participants", "Người sử dụng mặc định là người tham dự"}. -{"Allow users to change subject", "Cho phép người sử dụng thay đổi chủ đề"}. -{"Allow users to send private messages", "Cho phép người sử dụng gửi thư riêng"}. -{"Allow users to query other users", "Cho phép người sử dụng hỏi người sử dụng khác"}. -{"Allow users to send invites", "Cho phép người sử dụng gửi lời mời"}. -{"Enable logging", "Cho phép ghi nhật ký"}. -{"You need an x:data capable client to configure room", "Bạn cần có một trình ứng dụng khách hỗ trợ định dạng dữ liệu x: để xác định cấu hình phòng họp"}. -{"Number of occupants", "Số người tham dự"}. -{"~s invites you to the room ~s", "~s mời bạn vào phòng ~s"}. -{"the password is", "mật khẩu là"}. - -% mod_muc/mod_muc_log.erl -{"Chatroom configuration modified", "Cấu hình phòng trò chuyện được chỉnh sửa"}. -{"joins the room", "tham gia phòng này"}. -{"leaves the room", "rời khỏi phòng này"}. -{"has been kicked", "đã bị đẩy ra khỏi"}. -{"has been banned", "đã bị cấm"}. -{"is now known as", "bây giờ được biết như"}. -{"Monday", "Thứ Hai"}. -{"Tuesday", "Thứ Ba"}. -{"Wednesday", "Thứ Tư"}. -{"Thursday", "Thứ Năm"}. -{"Friday", "Thứ Sáu"}. -{"Saturday", "Thứ Bảy"}. -{"Sunday", "Chủ Nhật"}. -{"January", "Tháng Một"}. -{"February", "Tháng Hai"}. -{"March", "Tháng Ba"}. -{"April", "Tháng Tư"}. -{"May", "Tháng Năm"}. -{"June", "Tháng Sáu"}. -{"July", "Tháng Bảy"}. -{"August", "Tháng Tám"}. -{"September", "Tháng Chín"}. -{"October", "Tháng Mười"}. -{"November", "Tháng Mười Một"}. -{"December", "Tháng Mười Hai"}. -{"Room Configuration", "Cấu Hình Phòng"}. - -% mod_offline.erl -{"Time", "Thời Gian"}. -{"From", "Từ"}. -{"To", "Đến"}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Cấu Hình Truy Cập"}. +{"Access Control List Configuration","Cấu Hình Danh Sách Kiểm Soát Truy Cập"}. +{"Access control lists","Danh sách kiểm soát truy cập"}. +{"Access Control Lists","Danh Sách Kiểm Soát Truy Cập"}. +{"Access denied by service policy","Sự truy cập bị chặn theo chính sách phục vụ"}. +{"Access rules","Quy tắc Truy Cập"}. +{"Access Rules","Quy Tắc Truy Cập"}. +{"Action on user","Hành động đối với người sử dụng"}. +{"Add Jabber ID","Thêm Jabber ID"}. +{"Add New","Thêm Mới"}. +{"Add User","Thêm Người Sử Dụng"}. +{"Administration of ","Quản trị về "}. +{"Administration","Quản trị"}. +{"Administrator privileges required","Yêu cầu đặc quyền của nhà quản trị"}. +{"All activity","Tất cả hoạt động"}. +{"Allow this JID to subscribe to this pubsub node?","Cho phép JID đăng ký nút môđun xuất bản đăng ký này không?"}. +{"Allow users to change subject","Cho phép người sử dụng thay đổi chủ đề"}. +{"Allow users to query other users","Cho phép người sử dụng hỏi người sử dụng khác"}. +{"Allow users to send invites","Cho phép người sử dụng gửi lời mời"}. +{"Allow users to send private messages","Cho phép người sử dụng gửi thư riêng"}. +{"All Users","Tất Cả Người Sử Dụng"}. +{"Announcements","Thông báo"}. +{"anyone","bất kỳ ai"}. +{"April","Tháng Tư"}. +{"August","Tháng Tám"}. +{"Backup Management","Quản lý Sao Lưu Dự Phòng"}. +{"Backup of ","Sao lưu dự phòng về"}. +{"Backup","Sao lưu dự phòng"}. +{"Backup to File at ","Sao lưu dự phòng ra Tập Tin tại"}. +{"Bad format","Định dạng hỏng"}. +{"Birthday","Ngày sinh"}. +{"Change Password","Thay Đổi Mật Khẩu"}. +{"Change User Password","Thay Đổi Mật Khẩu Người Sử Dụng"}. +{"Chatroom configuration modified","Cấu hình phòng trò chuyện được chỉnh sửa"}. +{"Chatrooms","Phòng trò chuyện"}. +{"Choose a username and password to register with this server","Chọn một tên truy cập và mật khẩu để đăng ký với máy chủ này"}. +{"Choose modules to stop","Chọn môđun để dừng"}. +{"Choose storage type of tables","Chọn loại bảng lưu trữ"}. +{"Choose whether to approve this entity's subscription.","Chọn có nên chấp nhận sự đăng ký của đối tượng này không"}. +{"City","Thành phố"}. +{"Commands","Lệnh"}. +{"Conference room does not exist","Phòng họp không tồn tại"}. +{"Configuration","Cấu hình"}. +{"Configuration for ","Cấu hình cho "}. +{"Connected Resources:","Tài Nguyên Được Kết Nối:"}. +{"Country","Quốc gia"}. +{"CPU Time:","Thời Gian CPU:"}. +{"Database","Cơ sở dữ liệu"}. +{"Database Tables at ","Bảng Cơ Sở Dữ Liệu tại"}. +{"Database Tables Configuration at ","Cấu Hình Bảng Cơ Sở Dữ Liệu tại"}. +{"December","Tháng Mười Hai"}. +{"Default users as participants","Người sử dụng mặc định là người tham dự"}. +{"Delete message of the day on all hosts","Xóa thư trong ngày trên tất cả các máy chủ"}. +{"Delete message of the day","Xóa thư trong ngày"}. +{"Delete Selected","Tùy chọn Xóa được Chọn"}. +{"Delete User","Xóa Người Sử Dụng"}. +{"Delete","Xóa"}. +{"Deliver event notifications","Đưa ra các thông báo sự kiện"}. +{"Deliver payloads with event notifications","Đưa ra thông tin dung lượng với các thông báo sự kiện"}. +{"Description:","Miêu tả:"}. +{"Disc only copy","Chỉ sao chép vào đĩa"}. +{"Displayed Groups:","Nhóm được hiển thị:"}. +{"Dump Backup to Text File at ","Kết Xuất Sao Lưu ra Tập Tin Văn Bản tại"}. +{"Dump to Text File","Kết xuất ra Tập Tin Văn Bản"}. +{"Edit Properties","Chỉnh Sửa Thuộc Tính"}. +{"ejabberd IRC module","Môdun ejabberd IRC Bản quyền"}. +{"ejabberd MUC module","Môdun ejabberd MUC Bản quyền"}. +{"ejabberd Publish-Subscribe module","Môdun ejabberd Xuất Bản-Đăng Ký Bản quyền"}. +{"ejabberd SOCKS5 Bytestreams module","Môdun SOCKS5 Bytestreams Bản quyền"}. +{"ejabberd vCard module","Môdun ejabberd vCard Bản quyền"}. +{"ejabberd virtual hosts","Máy chủ ảo ejabberd"}. +{"Email","Email"}. +{"Enable logging","Cho phép ghi nhật ký"}. +{"Encodings","Mã hóa"}. +{"End User Session","Kết Thúc Phiên Giao Dịch Người Sử Dụng"}. +{"Enter list of {Module, [Options]}","Nhập danh sách {Môđun, [Các Tùy Chọn]}"}. +{"Enter nickname you want to register","Nhập bí danh bạn muốn đăng ký"}. +{"Enter path to backup file","Nhập đường dẫn đến tập tin sao lưu dự phòng"}. +{"Enter path to jabberd1.4 spool dir","Nhập đường dẫn đến thư mục spool jabberd1,4"}. +{"Enter path to jabberd1.4 spool file","Nhập đường dẫn đến tập tin spool jabberd1,4"}. +{"Enter path to text file","Nhập đường dẫn đến tập tin văn bản"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Nhập tên truy cập và mã hóa mà bạn muốn sử dụng khi kết nối với các máy chủ IRC"}. +{"Erlang Jabber Server","Erlang Jabber Server Bản quyền"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Ví dụ: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]"}. +{"Family Name","Họ"}. +{"February","Tháng Hai"}. +{"Fill in fields to search for any matching Jabber User","Điền vào các ô để tìm kiếm bất kỳ các thông tin nào khớp với Người sử dụng Jabber"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Điền vào mẫu này để tìm kiếm bất kỳ thông tin nào khớp với Người sử dụng Jabber (Thêm dấu * vào cuối ô để thông tin khớp với chuỗi bên trong)"}. +{"Friday","Thứ Sáu"}. +{"From ~s","Nhận từ ~s"}. +{"From","Từ"}. +{"Full Name","Tên Đầy Đủ"}. +{"Get Number of Online Users","Nhận Số Người Sử Dụng Trực Tuyến"}. +{"Get Number of Registered Users","Nhận Số Người Sử Dụng Đã Đăng Ký"}. +{"Get User Last Login Time","Nhận Thời Gian Đăng Nhập Cuối Cùng Của Người Sử Dụng"}. +{"Get User Password","Nhận Mật Khẩu Người Sử Dụng"}. +{"Get User Statistics","Nhận Thông Tin Thống Kê Người Sử Dụng"}. +{"Group ","Nhóm "}. +{"Groups","Nhóm"}. +{"has been banned","đã bị cấm"}. +{"has been kicked","đã bị đẩy ra khỏi"}. +{" has set the subject to: "," đã đặt chủ đề thành: "}. +{"Host","Máy chủ"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Nếu bạn muốn xác định các cách thức mã hóa khác nhau cho các máy chủ IRC, hãy điền vào danh sách này những giá trị theo định dạng '{\"máy chủ irc\", \"mã hóa\"}'. Dịch vụ này mặc định sử dụng định dạng mã hóa \"~s\"."}. +{"Import Directory","Nhập Thư Mục"}. +{"Import File","Nhập Tập Tin"}. +{"Import User from File at ","Nhập Người Sử Dụng từ Tập Tin tại"}. +{"Import Users from Dir at ","Nhập Người Sử Dụng từ Thư Mục tại"}. +{"Import Users From jabberd 1.4 Spool Files","Nhập Người Sử Dụng Từ Các Tập Tin Spool jabberd 1,4"}. +{"Improper message type","Loại thư không phù hợp"}. +{"Incorrect password","Mật khẩu sai"}. +{"Invalid affiliation: ~s","Tư cách không hợp lệ: ~s"}. +{"Invalid role: ~s","Vai trò không hợp lệ: ~s"}. +{"IP addresses","Địa chỉ IP"}. +{"IRC Transport","Truyền tải IRC"}. +{"IRC Username","Tên truy cập IRC"}. +{"is now known as","bây giờ được biết như"}. +{"It is not allowed to send private messages of type \"groupchat\"","Không được phép gửi những thư riêng loại \"groupchat\""}. +{"It is not allowed to send private messages to the conference","Không được phép gửi những thư riêng đến phòng họp"}. +{"Jabber ID","Jabber ID"}. +{"January","Tháng Một"}. +{"JID ~s is invalid","JID ~s không hợp lệ"}. +{"joins the room","tham gia phòng này"}. +{"July","Tháng Bảy"}. +{"June","Tháng Sáu"}. +{"Last Activity","Hoạt Động Cuối Cùng"}. +{"Last login","Đăng nhập lần cuối"}. +{"Last month","Tháng trước"}. +{"Last year","Năm trước"}. +{"leaves the room","rời khỏi phòng này"}. +{"Listened Ports at ","Cổng Liên Lạc tại"}. +{"Listened Ports","Cổng Kết Nối"}. +{"List of modules to start","Danh sách các môđun khởi động"}. +{"Low level update script","Lệnh cập nhật mức độ thấp"}. +{"Make participants list public","Tạo danh sách người tham dự công khai"}. +{"Make room members-only","Tạo phòng chỉ cho phép tư cách thành viên tham gia"}. +{"Make room password protected","Tạo phòng được bảo vệ bằng mật khẩu"}. +{"Make room persistent","Tạo phòng bền vững"}. +{"Make room public searchable","Tạo phòng có thể tìm kiếm công khai"}. +{"March","Tháng Ba"}. +{"Maximum Number of Occupants","Số Lượng Người Tham Dự Tối Đa"}. +{"Max # of items to persist","Số mục tối đa để lưu trữ"}. +{"Max payload size in bytes","Kích thước dung lượng byte tối đa"}. +{"May","Tháng Năm"}. +{"Membership required to enter this room","Yêu cầu tư cách thành viên khi tham gia vào phòng này"}. +{"Members:","Thành viên:"}. +{"Memory","Bộ Nhớ"}. +{"Message body","Thân thư"}. +{"Middle Name","Họ Đệm"}. +{"Moderator privileges required","Yêu cầu đặc quyền của nhà điều phối"}. +{"moderators only","nhà điều phối duy nhất"}. +{"Module","Môđun"}. +{"Modules at ","Môđun tại "}. +{"Modules","Môđun"}. +{"Monday","Thứ Hai"}. +{"Name:","Tên:"}. +{"Name","Tên"}. +{"Never","Không bao giờ"}. +{"Nickname","Bí danh"}. +{"Nickname is already in use by another occupant","Bí danh đang do một người tham dự khác sử dụng"}. +{"Nickname is registered by another person","Một người khác đã đăng ký bí danh này rồi"}. +{"Nickname Registration at ","Đăng Ký Bí Danh tại"}. +{"Nickname ~s does not exist in the room","Bí danh ~s không tồn tại trong phòng này"}. +{"No body provided for announce message","Không có nội dung trong thư thông báo"}. +{"No Data","Không Dữ Liệu"}. +{"Node ID","ID Nút"}. +{"Node not found","Nút không tìm thấy"}. +{"Node ","Nút "}. +{"Nodes","Nút"}. +{"No limit","Không giới hạn"}. +{"None","Không có"}. +{"No resource provided","Không có nguồn lực cung cấp"}. +{"Notify subscribers when items are removed from the node","Thông báo cho người đăng ký khi nào các mục chọn bị gỡ bỏ khỏi nút"}. +{"Notify subscribers when the node configuration changes","Thông báo cho người đăng ký khi nào cấu hình nút thay đổi"}. +{"Notify subscribers when the node is deleted","Thông báo cho người đăng ký khi nào nút bị xóa bỏ"}. +{"November","Tháng Mười Một"}. +{"Number of occupants","Số người tham dự"}. +{"Number of online users","Số người sử dụng trực tuyến"}. +{"Number of registered users","Số người sử dụng đã đăng ký"}. +{"October","Tháng Mười"}. +{"Offline Messages:","Thư Ngoại Tuyến:"}. +{"Offline Messages","Thư Ngoại Tuyến"}. +{"OK","OK"}. +{"Online","Trực tuyến"}. +{"Online Users:","Người Sử Dụng Trực Tuyến:"}. +{"Online Users","Người Sử Dụng Trực Tuyến"}. +{"Only deliver notifications to available users","Chỉ gửi thông báo đến những người sử dụng hiện có"}. +{"Only moderators and participants are allowed to change subject in this room","Chỉ có những người điều phối và những người tham gia được phép thay đổi chủ đề trong phòng này"}. +{"Only moderators are allowed to change subject in this room","Chỉ có những người điều phối được phép thay đổi chủ đề trong phòng này"}. +{"Only occupants are allowed to send messages to the conference","Chỉ có những đối tượng tham gia mới được phép gửi thư đến phòng họp"}. +{"Only occupants are allowed to send queries to the conference","Chỉ có những đối tượng tham gia mới được phép gửi yêu cầu đến phòng họp"}. +{"Only service administrators are allowed to send service messages","Chỉ có người quản trị dịch vụ mới được phép gửi những thư dịch vụ"}. +{"Options","Tùy chọn"}. +{"Organization Name","Tên Tổ Chức"}. +{"Organization Unit","Bộ Phận"}. +{"Outgoing s2s Connections:","Kết Nối Bên Ngoài s2s:"}. +{"Outgoing s2s Connections","Kết Nối Bên Ngoài s2s"}. +{"Outgoing s2s Servers:","Máy chủ Bên Ngoài s2s:"}. +{"Owner privileges required","Yêu cầu đặc quyền của người sở hữu"}. +{"Packet","Gói thông tin"}. +{"Password:","Mật Khẩu:"}. +{"Password","Mật Khẩu"}. +{"Password required to enter this room","Yêu cầu nhập mật khẩu để vào phòng này"}. +{"Password Verification","Kiểm Tra Mật Khẩu"}. +{"Path to Dir","Đường Dẫn đến Thư Mục"}. +{"Path to File","Đường dẫn đến Tập Tin"}. +{"Pending","Chờ"}. +{"Period: ","Giai đoạn: "}. +{"Persist items to storage","Những mục cần để lưu trữ"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","Cổng"}. +{"Present real JIDs to","JID thực tế hiện hành đến"}. +{"private, ","riêng,"}. +{"Publish-Subscribe","Xuất Bản-Đăng Ký"}. +{"PubSub subscriber request","Yêu cầu người đăng ký môđun Xuất Bản Đăng Ký"}. +{"Queries to the conference members are not allowed in this room","Không được phép gửi các yêu cầu gửi đến các thành viên trong phòng họp này"}. +{"RAM and disc copy","Sao chép vào RAM và đĩa"}. +{"RAM copy","Sao chép vào RAM"}. +{"(Raw)","(Thô)"}. +{"Raw","Thô"}. +{"Really delete message of the day?","Có thực sự xóa thư trong ngày này không?"}. +{"Recipient is not in the conference room","Người nhận không có trong phòng họp"}. +{"Registered Users:","Người Sử Dụng Đã Đăng Ký:"}. +{"Registered Users","Người Sử Dụng Đã Đăng Ký"}. +{"Registration in mod_irc for ","Đăng ký trong mod_irc cho "}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Lưu ý rằng những tùy chọn này sẽ chỉ được sao lưu cơ sở dữ liệu bên trong Mnesia. Nếu bạn đang sử dụng môđun ODBC, bạn cũng cần sao lưu cơ sở dữ liệu SQL của bạn riêng biệt."}. +{"Remote copy","Sao chép từ xa"}. +{"Remove","Gỡ bỏ"}. +{"Remove User","Gỡ Bỏ Người Sử Dụng"}. +{"Replaced by new connection","Được thay thế bởi kết nối mới"}. +{"Resources","Nguồn tài nguyên"}. +{"Restart","Khởi động lại"}. +{"Restart Service","Khởi Động Lại Dịch Vụ"}. +{"Restore Backup from File at ","Phục hồi Sao Lưu từ Tập Tin tại "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Khôi phục bản sao lưu dự phòng dạng nhị phân sau lần khởi động ejabberd kế tiếp (yêu cầu ít bộ nhớ hơn):"}. +{"Restore binary backup immediately:","Khôi phục bản sao lưu dự phòng dạng nhị phận ngay lập tức:"}. +{"Restore","Khôi phục"}. +{"Restore plain text backup immediately:","Khôi phục bản sao lưu dự phòng thuần văn bản ngay lập tức:"}. +{"Room Configuration","Cấu Hình Phòng"}. +{"Room creation is denied by service policy","Việc tạo phòng bị ngăn lại theo chính sách dịch vụ"}. +{"Room title","Tên phòng"}. +{"Roster","Bảng phân công"}. +{"Roster of ","Bảng phân công của "}. +{"Roster size","Kích thước bảng phân công"}. +{"RPC Call Error","Lỗi Gọi RPC"}. +{"Running Nodes","Nút Hoạt Động"}. +{"~s access rule configuration","~s cấu hình quy tắc truy cập"}. +{"Saturday","Thứ Bảy"}. +{"Script check","Lệnh kiểm tra"}. +{"Search Results for ","Kết Quả Tìm Kiếm cho "}. +{"Search users in ","Tìm kiếm người sử dụng trong"}. +{"Send announcement to all online users","Gửi thông báo đến tất cả người sử dụng trực tuyến"}. +{"Send announcement to all online users on all hosts","Gửi thông báo đến tất cả người sử dụng trực tuyến trên tất cả các máy chủ"}. +{"Send announcement to all users","Gửi thông báo đến tất cả người sử dụng"}. +{"Send announcement to all users on all hosts","Gửi thông báo đến tất cả người sử dụng trên tất cả các máy chủ"}. +{"September","Tháng Chín"}. +{"Set message of the day and send to online users","Tạo lập thư trong ngày và gửi đến những người sử dụng trực tuyến"}. +{"Set message of the day on all hosts and send to online users","Tạo lập thư trong ngày trên tất cả các máy chủ và gửi đến những người sử dụng trực tuyến"}. +{"Shared Roster Groups","Nhóm Phân Công Chia Sẻ"}. +{"Show Integral Table","Hiển Thị Bảng Đầy Đủ"}. +{"Show Ordinary Table","Hiển Thị Bảng Thường"}. +{"Shut Down Service","Tắt Dịch Vụ"}. +{"~s invites you to the room ~s","~s mời bạn vào phòng ~s"}. +{"Size","Kích thước"}. +{"Specified nickname is already registered","Bí danh xác định đã đăng ký rồi"}. +{"Specify the access model","Xác định mô hình truy cập"}. +{"Specify the publisher model","Xác định mô hình nhà xuất bản"}. +{"~s's Offline Messages Queue","~s's Danh Sách Chờ Thư Ngoại Tuyến"}. +{"Start","Khởi động"}. +{"Start Modules at ","Môđun Khởi Động tại "}. +{"Start Modules","Môđun Khởi Động"}. +{"Statistics of ~p","Thống kê về ~p"}. +{"Statistics","Số liệu thống kê"}. +{"Stop","Dừng"}. +{"Stop Modules at ","Môđun Dừng tại"}. +{"Stop Modules","Môđun Dừng"}. +{"Stopped Nodes","Nút Dừng"}. +{"Storage Type","Loại Lưu Trữ"}. +{"Store binary backup:","Lưu dữ liệu sao lưu dạng nhị phân:"}. +{"Store plain text backup:","Khôi phục bản sao lưu dự phòng thuần văn bản"}. +{"Subject","Tiêu đề"}. +{"Submit","Gửi"}. +{"Submitted","Đã gửi"}. +{"Subscriber Address","Địa Chỉ Người Đăng Ký"}. +{"Subscription","Đăng ký"}. +{"Sunday","Chủ Nhật"}. +{"the password is","mật khẩu là"}. +{"This room is not anonymous","Phòng này không nặc danh"}. +{"Thursday","Thứ Năm"}. +{"Time delay","Thời gian trì hoãn"}. +{"Time","Thời Gian"}. +{"To","Đến"}. +{"To ~s","Gửi đến ~s"}. +{"Traffic rate limit is exceeded","Quá giới hạn tỷ lệ lưu lượng truyền tải"}. +{"Transactions Aborted:","Giao Dịch Hủy Bỏ:"}. +{"Transactions Commited:","Giao Dịch Được Cam Kết:"}. +{"Transactions Logged:","Giao Dịch Được Ghi Nhận:"}. +{"Transactions Restarted:","Giao Dịch Khởi Động Lại:"}. +{"Tuesday","Thứ Ba"}. +{"Update ","Cập Nhật "}. +{"Update","Cập Nhật"}. +{"Updated modules","Môđun cập nhật"}. +{"Update message of the day (don't send)","Cập nhật thư trong ngày (không gửi)"}. +{"Update message of the day on all hosts (don't send)","Cập nhật thư trong ngày trên tất cả các máy chủ (không gửi)"}. +{"Update plan","Kế hoạch cập nhật"}. +{"Update script","Cập nhận lệnh"}. +{"Uptime:","Thời gian tải lên:"}. +{"Use of STARTTLS required","Yêu cầu sử dụng STARTTLS"}. +{"User Management","Quản Lý Người Sử Dụng"}. +{"User ","Người sử dụng "}. +{"User","Người sử dụng"}. +{"Users Last Activity","Hoạt Động Cuối Cùng Của Người Sử Dụng"}. +{"Users","Người sử dụng"}. +{"Validate","Xác nhận hợp lệ"}. +{"vCard User Search","Tìm Kiếm Người Sử Dụng vCard"}. +{"Virtual Hosts","Máy Chủ Ảo"}. +{"Visitors are not allowed to send messages to all occupants","Người ghé thăm không được phép gửi thư đến tất cả các người tham dự"}. +{"Wednesday","Thứ Tư"}. +{"When to send the last published item","Khi cần gửi mục được xuất bản cuối cùng"}. +{"Whether to allow subscriptions","Xác định nên cho phép đăng ký không"}. +{"You have been banned from this room","Bạn bị cấm tham gia phòng này"}. +{"You must fill in field \"Nickname\" in the form","Bạn phải điền thông tin vào ô \"Nickname\" trong biểu mẫu này"}. +{"You need an x:data capable client to configure mod_irc settings","Bạn cần có một trình ứng dụng khách hỗ trợ định dạng dữ liệu x: để xác định các thiết lập mod_irc"}. +{"You need an x:data capable client to configure room","Bạn cần có một trình ứng dụng khách hỗ trợ định dạng dữ liệu x: để xác định cấu hình phòng họp"}. +{"You need an x:data capable client to register nickname","Bạn cần có một trình ứng dụng khách hỗ trợ định dạng dữ liệu x: để đăng ký bí danh"}. +{"You need an x:data capable client to search","Bạn cần có một trình ứng dụng khách hỗ trợ định dạng dữ liệu x: để tìm kiếm"}. +{"Your contact offline message queue is full. The message has been discarded.","Danh sách chờ thư liên lạc ngoại tuyến của bạn đã đầy. Thư này đã bị loại bỏ."}. diff --git a/src/msgs/vi.po b/src/msgs/vi.po new file mode 100644 index 000000000..8cdb0c945 --- /dev/null +++ b/src/msgs/vi.po @@ -0,0 +1,1510 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: EQHO Communications (Thailand) Ltd. - http://www.eqho.com\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Vietnamese (tiếng việt)\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "Yêu cầu sử dụng STARTTLS" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Không có nguồn lực cung cấp" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Được thay thế bởi kết nối mới" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Lệnh" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Có thực sự xóa thư trong ngày này không?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Tiêu đề" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Thân thư" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "Không có nội dung trong thư thông báo" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Thông báo" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Gửi thông báo đến tất cả người sử dụng" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Gửi thông báo đến tất cả người sử dụng trên tất cả các máy chủ" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Gửi thông báo đến tất cả người sử dụng trực tuyến" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "" +"Gửi thông báo đến tất cả người sử dụng trực tuyến trên tất cả các máy chủ" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Tạo lập thư trong ngày và gửi đến những người sử dụng trực tuyến" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Tạo lập thư trong ngày trên tất cả các máy chủ và gửi đến những người sử " +"dụng trực tuyến" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Cập nhật thư trong ngày (không gửi)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Cập nhật thư trong ngày trên tất cả các máy chủ (không gửi)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Xóa thư trong ngày" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Xóa thư trong ngày trên tất cả các máy chủ" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Cấu hình" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Cơ sở dữ liệu" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Môđun Khởi Động" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Môđun Dừng" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Sao lưu dự phòng" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Khôi phục" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Kết xuất ra Tập Tin Văn Bản" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Nhập Tập Tin" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Nhập Thư Mục" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Khởi Động Lại Dịch Vụ" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Tắt Dịch Vụ" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Thêm Người Sử Dụng" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Xóa Người Sử Dụng" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Kết Thúc Phiên Giao Dịch Người Sử Dụng" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Nhận Mật Khẩu Người Sử Dụng" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Thay Đổi Mật Khẩu Người Sử Dụng" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Nhận Thời Gian Đăng Nhập Cuối Cùng Của Người Sử Dụng" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Nhận Thông Tin Thống Kê Người Sử Dụng" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Nhận Số Người Sử Dụng Đã Đăng Ký" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Nhận Số Người Sử Dụng Trực Tuyến" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Danh Sách Kiểm Soát Truy Cập" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Quy Tắc Truy Cập" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Quản Lý Người Sử Dụng" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Người Sử Dụng Trực Tuyến" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Tất Cả Người Sử Dụng" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Kết Nối Bên Ngoài s2s" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Nút Hoạt Động" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Nút Dừng" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Môđun" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Quản lý Sao Lưu Dự Phòng" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Nhập Người Sử Dụng Từ Các Tập Tin Spool jabberd 1,4" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "Gửi đến ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "Nhận từ ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Cấu Hình Bảng Cơ Sở Dữ Liệu tại" + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Chọn loại bảng lưu trữ" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Chỉ sao chép vào đĩa" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "Sao chép vào RAM và đĩa" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "Sao chép vào RAM" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Sao chép từ xa" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Môđun Dừng tại" + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Chọn môđun để dừng" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Môđun Khởi Động tại " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Nhập danh sách {Môđun, [Các Tùy Chọn]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Danh sách các môđun khởi động" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Sao lưu dự phòng ra Tập Tin tại" + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Nhập đường dẫn đến tập tin sao lưu dự phòng" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Đường dẫn đến Tập Tin" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Phục hồi Sao Lưu từ Tập Tin tại " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Kết Xuất Sao Lưu ra Tập Tin Văn Bản tại" + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Nhập đường dẫn đến tập tin văn bản" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Nhập Người Sử Dụng từ Tập Tin tại" + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Nhập đường dẫn đến tập tin spool jabberd1,4" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Nhập Người Sử Dụng từ Thư Mục tại" + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Nhập đường dẫn đến thư mục spool jabberd1,4" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Đường Dẫn đến Thư Mục" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Thời gian trì hoãn" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Cấu Hình Danh Sách Kiểm Soát Truy Cập" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Danh sách kiểm soát truy cập" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Cấu Hình Truy Cập" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Quy tắc Truy Cập" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Mật Khẩu" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Kiểm Tra Mật Khẩu" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Số người sử dụng đã đăng ký" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Số người sử dụng trực tuyến" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Không bao giờ" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Trực tuyến" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Đăng nhập lần cuối" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Kích thước bảng phân công" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "Địa chỉ IP" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Nguồn tài nguyên" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Quản trị về " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Hành động đối với người sử dụng" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Chỉnh Sửa Thuộc Tính" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Gỡ Bỏ Người Sử Dụng" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "Sự truy cập bị chặn theo chính sách phục vụ" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "Truyền tải IRC" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "Môdun ejabberd IRC Bản quyền" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "" +"Bạn cần có một trình ứng dụng khách hỗ trợ định dạng dữ liệu x: để xác định " +"các thiết lập mod_irc" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Đăng ký trong mod_irc cho " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Nhập tên truy cập và mã hóa mà bạn muốn sử dụng khi kết nối với các máy chủ " +"IRC" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "Tên truy cập IRC" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Nếu bạn muốn xác định các cách thức mã hóa khác nhau cho các máy chủ IRC, " +"hãy điền vào danh sách này những giá trị theo định dạng '{\"máy chủ irc\", " +"\"mã hóa\"}'. Dịch vụ này mặc định sử dụng định dạng mã hóa \"~s\"." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Ví dụ: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]" + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Mã hóa" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "Chỉ có người quản trị dịch vụ mới được phép gửi những thư dịch vụ" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "Việc tạo phòng bị ngăn lại theo chính sách dịch vụ" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "Phòng họp không tồn tại" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Phòng trò chuyện" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "" +"Bạn cần có một trình ứng dụng khách hỗ trợ định dạng dữ liệu x: để đăng ký " +"bí danh" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Đăng Ký Bí Danh tại" + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Nhập bí danh bạn muốn đăng ký" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Bí danh" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "Bí danh xác định đã đăng ký rồi" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Bạn phải điền thông tin vào ô \"Nickname\" trong biểu mẫu này" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "Môdun ejabberd MUC Bản quyền" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "Cấu hình phòng trò chuyện được chỉnh sửa" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "tham gia phòng này" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "rời khỏi phòng này" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "đã bị cấm" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "đã bị đẩy ra khỏi" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "bây giờ được biết như" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " đã đặt chủ đề thành: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "Thứ Hai" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "Thứ Ba" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "Thứ Tư" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "Thứ Năm" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "Thứ Sáu" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "Thứ Bảy" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "Chủ Nhật" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "Tháng Một" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "Tháng Hai" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "Tháng Ba" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "Tháng Tư" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "Tháng Năm" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "Tháng Sáu" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "Tháng Bảy" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "Tháng Tám" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "Tháng Chín" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "Tháng Mười" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "Tháng Mười Một" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "Tháng Mười Hai" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Cấu Hình Phòng" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Tên phòng" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Quá giới hạn tỷ lệ lưu lượng truyền tải" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "Không được phép gửi những thư riêng đến phòng họp" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Loại thư không phù hợp" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "Không được phép gửi những thư riêng loại \"groupchat\"" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "Người nhận không có trong phòng họp" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Chỉ có những đối tượng tham gia mới được phép gửi thư đến phòng họp" + +#: mod_muc/mod_muc_room.erl:528 +#, fuzzy +msgid "It is not allowed to send private messages" +msgstr "Không được phép gửi những thư riêng đến phòng họp" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "" +"Chỉ có những đối tượng tham gia mới được phép gửi yêu cầu đến phòng họp" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "" +"Không được phép gửi các yêu cầu gửi đến các thành viên trong phòng họp này" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "riêng," + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "" +"Chỉ có những người điều phối và những người tham gia được phép thay đổi chủ " +"đề trong phòng này" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Chỉ có những người điều phối được phép thay đổi chủ đề trong phòng này" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "Người ghé thăm không được phép gửi thư đến tất cả các người tham dự" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" + +#: mod_muc/mod_muc_room.erl:949 +#, fuzzy +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Chỉ có những người điều phối được phép thay đổi chủ đề trong phòng này" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "Bí danh đang do một người tham dự khác sử dụng" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "Một người khác đã đăng ký bí danh này rồi" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Bạn bị cấm tham gia phòng này" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "Yêu cầu tư cách thành viên khi tham gia vào phòng này" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Phòng này không nặc danh" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "Yêu cầu nhập mật khẩu để vào phòng này" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Mật khẩu sai" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "Yêu cầu đặc quyền của nhà quản trị" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "Yêu cầu đặc quyền của nhà điều phối" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "JID ~s không hợp lệ" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "Bí danh ~s không tồn tại trong phòng này" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Tư cách không hợp lệ: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Vai trò không hợp lệ: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "Yêu cầu đặc quyền của người sở hữu" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Cấu hình cho " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Miêu tả:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Tạo phòng bền vững" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Tạo phòng có thể tìm kiếm công khai" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Tạo danh sách người tham dự công khai" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Tạo phòng được bảo vệ bằng mật khẩu" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Số Lượng Người Tham Dự Tối Đa" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Không giới hạn" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "JID thực tế hiện hành đến" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "nhà điều phối duy nhất" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "bất kỳ ai" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Tạo phòng chỉ cho phép tư cách thành viên tham gia" + +#: mod_muc/mod_muc_room.erl:2748 +#, fuzzy +msgid "Make room moderated" +msgstr "Tạo phòng bền vững" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Người sử dụng mặc định là người tham dự" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Cho phép người sử dụng thay đổi chủ đề" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Cho phép người sử dụng gửi thư riêng" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Cho phép người sử dụng hỏi người sử dụng khác" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Cho phép người sử dụng gửi lời mời" + +#: mod_muc/mod_muc_room.erl:2766 +#, fuzzy +msgid "Allow visitors to send status text in presence updates" +msgstr "Cho phép người sử dụng gửi thư riêng" + +#: mod_muc/mod_muc_room.erl:2769 +#, fuzzy +msgid "Allow visitors to change nickname" +msgstr "Cho phép người sử dụng thay đổi chủ đề" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Cho phép ghi nhật ký" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "" +"Bạn cần có một trình ứng dụng khách hỗ trợ định dạng dữ liệu x: để xác định " +"cấu hình phòng họp" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Số người tham dự" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s mời bạn vào phòng ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "mật khẩu là" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "" +"Danh sách chờ thư liên lạc ngoại tuyến của bạn đã đầy. Thư này đã bị loại bỏ." + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "~s's Danh Sách Chờ Thư Ngoại Tuyến" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Đã gửi" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Thời Gian" + +#: mod_offline.erl:507 +msgid "From" +msgstr "Từ" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Đến" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Gói thông tin" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Tùy chọn Xóa được Chọn" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Thư Ngoại Tuyến:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "Môdun SOCKS5 Bytestreams Bản quyền" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Xuất Bản-Đăng Ký" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "Môdun ejabberd Xuất Bản-Đăng Ký Bản quyền" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "Yêu cầu người đăng ký môđun Xuất Bản Đăng Ký" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Chọn có nên chấp nhận sự đăng ký của đối tượng này không" + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "ID Nút" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Địa Chỉ Người Đăng Ký" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "Cho phép JID đăng ký nút môđun xuất bản đăng ký này không?" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Đưa ra thông tin dung lượng với các thông báo sự kiện" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Đưa ra các thông báo sự kiện" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Thông báo cho người đăng ký khi nào cấu hình nút thay đổi" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Thông báo cho người đăng ký khi nào nút bị xóa bỏ" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Thông báo cho người đăng ký khi nào các mục chọn bị gỡ bỏ khỏi nút" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Những mục cần để lưu trữ" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Số mục tối đa để lưu trữ" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Xác định nên cho phép đăng ký không" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Xác định mô hình truy cập" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Xác định mô hình nhà xuất bản" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Kích thước dung lượng byte tối đa" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Khi cần gửi mục được xuất bản cuối cùng" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Chỉ gửi thông báo đến những người sử dụng hiện có" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "Chọn một tên truy cập và mật khẩu để đăng ký với máy chủ này" + +#: mod_register.erl:232 +#, fuzzy +msgid "Users are not allowed to register accounts so fast" +msgstr "Người ghé thăm không được phép gửi thư đến tất cả các người tham dự" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Không có" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Đăng ký" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Chờ" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Nhóm" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Xác nhận hợp lệ" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Gỡ bỏ" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Bảng phân công của " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Định dạng hỏng" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Thêm Jabber ID" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Bảng phân công" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Nhóm Phân Công Chia Sẻ" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Thêm Mới" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Tên:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Miêu tả:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Thành viên:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Nhóm được hiển thị:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Nhóm " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Gửi" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Erlang Jabber Server Bản quyền" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Ngày sinh" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Thành phố" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "Quốc gia" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "Email" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "Họ" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Điền vào mẫu này để tìm kiếm bất kỳ thông tin nào khớp với Người sử dụng " +"Jabber (Thêm dấu * vào cuối ô để thông tin khớp với chuỗi bên trong)" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "Tên Đầy Đủ" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "Họ Đệm" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "Tên" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "Tên Tổ Chức" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Bộ Phận" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Tìm kiếm người sử dụng trong" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Người sử dụng" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "" +"Bạn cần có một trình ứng dụng khách hỗ trợ định dạng dữ liệu x: để tìm kiếm" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "Tìm Kiếm Người Sử Dụng vCard" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "Môdun ejabberd vCard Bản quyền" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Kết Quả Tìm Kiếm cho " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "" +"Điền vào các ô để tìm kiếm bất kỳ các thông tin nào khớp với Người sử dụng " +"Jabber" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +#, fuzzy +msgid "ejabberd Web Admin" +msgstr "Giao diện Web ejabberd" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Quản trị" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Máy Chủ Ảo" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Nút" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Số liệu thống kê" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Người sử dụng" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Hoạt Động Cuối Cùng" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Thô)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Thô" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "~s cấu hình quy tắc truy cập" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "Máy chủ ảo ejabberd" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Hoạt Động Cuối Cùng Của Người Sử Dụng" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Giai đoạn: " + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Tháng trước" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Năm trước" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Tất cả hoạt động" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Hiển Thị Bảng Thường" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Hiển Thị Bảng Đầy Đủ" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Nút không tìm thấy" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Máy chủ" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Người Sử Dụng Đã Đăng Ký" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Thư Ngoại Tuyến" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Người Sử Dụng Đã Đăng Ký:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Người Sử Dụng Trực Tuyến:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Kết Nối Bên Ngoài s2s:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Máy chủ Bên Ngoài s2s:" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Thay Đổi Mật Khẩu" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Người sử dụng " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Tài Nguyên Được Kết Nối:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Mật Khẩu:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Không Dữ Liệu" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Nút " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Cổng Kết Nối" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Cập Nhật" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Khởi động lại" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Dừng" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "Lỗi Gọi RPC" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Bảng Cơ Sở Dữ Liệu tại" + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Loại Lưu Trữ" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Kích thước" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Bộ Nhớ" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Sao lưu dự phòng về" + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Lưu ý rằng những tùy chọn này sẽ chỉ được sao lưu cơ sở dữ liệu bên trong " +"Mnesia. Nếu bạn đang sử dụng môđun ODBC, bạn cũng cần sao lưu cơ sở dữ liệu " +"SQL của bạn riêng biệt." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Lưu dữ liệu sao lưu dạng nhị phân:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "OK" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Khôi phục bản sao lưu dự phòng dạng nhị phận ngay lập tức:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"Khôi phục bản sao lưu dự phòng dạng nhị phân sau lần khởi động ejabberd kế " +"tiếp (yêu cầu ít bộ nhớ hơn):" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Khôi phục bản sao lưu dự phòng thuần văn bản" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Khôi phục bản sao lưu dự phòng thuần văn bản ngay lập tức:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Cổng Liên Lạc tại" + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Môđun tại " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "Thống kê về ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Thời gian tải lên:" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "Thời Gian CPU:" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Giao Dịch Được Cam Kết:" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Giao Dịch Hủy Bỏ:" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Giao Dịch Khởi Động Lại:" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Giao Dịch Được Ghi Nhận:" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Cập Nhật " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Kế hoạch cập nhật" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Môđun cập nhật" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Cập nhận lệnh" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Lệnh cập nhật mức độ thấp" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Lệnh kiểm tra" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Cổng" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Môđun" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Tùy chọn" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Xóa" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Khởi động" + +#~ msgid "Roster groups that may subscribe (if access model is roster)" +#~ msgstr "" +#~ "Các nhóm phân công có thể đăng ký (nếu mô hình truy cập là dạng phân công)" diff --git a/src/msgs/wa.msg b/src/msgs/wa.msg index 0c62c28b2..c032ca866 100644 --- a/src/msgs/wa.msg +++ b/src/msgs/wa.msg @@ -1,373 +1,343 @@ -% $Id$ -% Language: Walon (Walloon) -% Author: Pablo Saratxaga - -% jlib.hrl -{"No resource provided", "Nole rissoûce di dnêye"}. - -% mod_configure.erl -{"Choose storage type of tables", "Tchoezi l' sôre di wårdaedje po les tåves"}. -{"RAM copy", "Copeye e memwere (RAM)"}. -{"RAM and disc copy", "Copeye e memwere (RAM) et sol deure plake"}. -{"Disc only copy", "Copeye seulmint sol deure plake"}. -{"Remote copy", "Copeye å lon"}. -{"Stop Modules at ", "Arester les modules so "}. -{"Choose modules to stop", "Tchoezixhoz les modules a-z arester"}. -{"Start Modules at ", "Renonder les modules so "}. -{"Enter list of {Module, [Options]}", "Dinez ene djivêye del cogne {Module, [Tchuzes]}"}. -{"List of modules to start", "Djivêye di modules a-z enonder"}. -{"Backup to File at ", "Fé ene copeye di såvrité dins on fitchî so "}. -{"Enter path to backup file", "Dinez l' tchimin viè l' fitchî copeye di såvrité"}. -{"Path to File", "Tchimin viè l' fitchî"}. -{"Restore Backup from File at ", "Rapexhî dispoy li fitchî copeye di såvrité so "}. -{"Dump Backup to Text File at ", "Copeye di såvritè viè on fitchî tecse so "}. -{"Enter path to text file", "Dinez l' tchimin viè l' fitchî tecse"}. -{"Import User from File at ", "Sititchî uzeu d' on fitchî so "}. -{"Enter path to jabberd1.4 spool file", "Dinez l' tchimin viè l' fitchî di spool jabberd1.4"}. -{"Import Users from Dir at ", "Sitichî des uzeus d' on ridant so "}. -{"Enter path to jabberd1.4 spool dir", "Dinez l' tchimin viè l' ridant di spool jabberd1.4"}. -{"Path to Dir", "Tchimin viè l' ridant"}. -{"Access Control List Configuration", "Apontiaedje des droets (ACL)"}. -{"Access control lists", "Droets (ACL)"}. -{"Access Configuration", "Apontiaedje des accès"}. -{"Access rules", "Rîles d' accès"}. -{"Administration of ", "Manaedjaedje di "}. -{"Action on user", "Accion so l' uzeu"}. -{"Edit Properties", "Candjî les prôpietés"}. -{"Remove User", "Disfacer l' uzeu"}. -{"Database", "Båze di dnêyes"}. -{"Outgoing s2s Connections", "Raloyaedjes s2s e rexhowe"}. -{"Import Users From jabberd 1.4 Spool Files", "Sititchî des uzeus Jabberd 1.4"}. -{"Database Tables Configuration at ", "Apontiaedje des tåves del båze di dnêyes so "}. -{"Change User Password", "Candjî l' sicret d' l' uzeu"}. -% mod_configure.erl -{"Get User Last Login Time", "Riçure li date/eure do dierin elodjaedje di l' uzeu"}. -{"Get User Statistics", "Riçure les statistikes di l' uzeu"}. -{"Get Number of Registered Users", "Riçure li nombe d' uzeus edjîstrés"}. -{"Get Number of Online Users", "Riçure li nombe d' uzeus raloyîs"}. -{"User Management", "Manaedjaedje des uzeus"}. -{"Time delay", "Tårdjaedje"}. -{"Password Verification", "Acertinaedje do scret"}. -{"Number of registered users", "Nombe d' uzeus edjîstrés"}. -{"Number of online users", "Nombe d' uzeus raloyîs"}. -{"Last login", "Dierin elodjaedje"}. -{"Roster size", "Grandeu del djivêye des soçons"}. -{"IP addresses", "Adresses IP"}. -{"Resources", "Rissoûces"}. - -% src/ejabberd_c2s.erl -{"Use of STARTTLS required", "L' eployaedje di STARTTL est oblidjî"}. -{"Replaced by new connection", "Replaecî pa on novea raloyaedje"}. - -% mod_disco.erl -{"Configuration", "Apontiaedjes"}. -{"Online Users", "Uzeus raloyîs"}. -{"All Users", "Tos les uzeus"}. -{"To ~s", "Viè ~s"}. -{"From ~s", "Dispoy ~s"}. -{"Running Nodes", "Nuks en alaedje"}. -{"Stopped Nodes", "Nuks essoctés"}. -{"Access Control Lists", "Droets (ACL)"}. -{"Access Rules", "Rîles d' accès"}. -{"Modules", "Modules"}. -{"Start Modules", "Enonder des modules"}. -{"Stop Modules", "Arester des modules"}. -{"Backup Management", "Manaedjaedje des copeyes di såvrité"}. -{"Backup", "Copeye di såvrité"}. -{"Restore", "Rapexhî"}. -{"Dump to Text File", "Schaper en on fitchî tecse"}. -{"Import File", "Sititchî d' on fitchî"}. -{"Import Directory", "Sititchî d' on ridant"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "Tchoezixhoz on no d' uzeu eyet on scret po vs edjîstrer so ç' sierveu ci"}. - -% mod_vcard_ldap.erl -{"Erlang Jabber Server", "Sierveu Jabber Erlang"}. -{"ejabberd vCard module", "Module vCard ejabberd"}. -{"Email", "Emile"}. -{"Search Results for ", "Rizultats do cweraedje po "}. -{"Jabber ID", "ID Jabber"}. - -% mod_vcard_odbc.erl -{"vCard User Search", "Calpin des uzeus"}. - -% mod_vcard.erl -{"You need an x:data capable client to search", "Vos avoz mezåjhe d' on cliyint ki sopoite x:data po fé on cweraedje"}. -{"Search users in ", "Cweri des uzeus dins "}. - -{"Fill in fields to search for any matching Jabber User", "Rimplixhoz les tchamps po cweri èn uzeu Jabber"}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "Rimplixhoz les tchamps do formulaire po cweri èn uzeu Jabber (radjouter «*» al fén do tchamp po cweri tot l' minme kéne fén d' tchinne"}. - -{"User", "Uzeu"}. -{"Full Name", "No etir"}. -{"Name", "Pitit no"}. -{"Middle Name", "No do mitan"}. -{"Family Name", "No d' famile"}. -{"Nickname", "Metou no"}. -{"Birthday", "Date d' askepiaedje"}. -{"Country", "Payis"}. -{"City", "Veye"}. -{"Organization Name", "No d' l' organizåcion"}. -{"Organization Unit", "Unité d' l' organizåcion"}. - -% mod_adhoc.erl -{"Commands", "Comandes"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% mod_announce.erl -{"Really delete message of the day?", "Voloz vs vormint disfacer l' messaedje do djoû?"}. -{"Subject", "Sudjet"}. -{"Message body", "Coir do messaedje"}. -{"No body provided for announce message", "I n' a nou coir do messaedje po ciste anonce la"}. -{"Announcements", "Anonces"}. -{"Send announcement to all users", "Evoyî l' anonce a tos les uzeus"}. -{"Send announcement to all users on all hosts", "Evoyî l' anonce a tos les uzeus so tos les lodjoes"}. -{"Send announcement to all online users", "Evoyî l' anonce a tos les uzeus raloyîs"}. -{"Send announcement to all online users on all hosts", "Evoyî l' anonce a tos les uzeus raloyîs so tos les lodjoes"}. -{"Set message of the day and send to online users", "Defini l' messaedje do djoû et l' evoyî åzès uzeus raloyîs"}. -{"Set message of the day on all hosts and send to online users", "Defini l' messaedje do djoû so tos les lodjoes et l' evoyî åzès uzeus raloyîs"}. -{"Update message of the day (don't send)", "Mete a djoû l' messaedje do djoû (nén l' evoyî)"}. -{"Update message of the day on all hosts (don't send)", "Mete a djoû l' messaedje do djoû so tos les lodjoes (nén l' evoyî)"}. -{"Delete message of the day", "Disfacer l' messaedje do djoû"}. -{"Delete message of the day on all hosts", "Disfacer l' messaedje do djoû so tos les lodjoes"}. - -% mod_pubsub/mod_pubsub.erl -{"ejabberd pub/sub module", "Module pub/sub ejabberd"}. -{"Publish-Subscribe", "Eplaiaedje-abounmint"}. -{"Node Creator", "Ahiveu do nuk"}. -{"Notify subscribers when the node configuration changes", "Notifyî åzès abounés cwand l' apontiaedje do nuk candje"}. -{"Notify subscribers when the node is deleted", "Notifyî åzès abounés cwand l' nuk est disfacé"}. -{"Notify subscribers when items are removed from the node", "Notifyî åzès abounés cwand des cayets sont oisté foû do nuk"}. -{"Whether to allow subscriptions", "Si on permete les abounmints"}. -{"Specify the subscriber model", "Dinez l' modele d' abouné"}. -{"Specify the publisher model", "Dinez l' modele d' eplaideu"}. -{"Send items to new subscribers", "Evoyî des cayets åzès noveas abounés"}. -{"Only deliver notifications to available users", "Seulmint evoyî des notifiaedje åzès uzeus disponibes"}. -{"Specify the current subscription approver", "Diner l' asproveu d' abounmints pol moumint"}. - -% mod_muc/mod_muc_log.erl -{"Chatroom configuration modified", "L' apontiaedje del såle di berdelaedje a candjî"}. -{"joins the room", "arive sol såle"}. -{"leaves the room", "cwite li såle"}. -{"has been kicked", "a stpi pité evoye"}. -{"has been banned", "a stî bani"}. -{"is now known as", "est asteure kinoxhou come"}. -{"Monday", "londi"}. -{"Tuesday", "mårdi"}. -{"Wednesday", "mierkidi"}. -{"Thursday", "djudi"}. -{"Friday", "vénrdi"}. -{"Saturday", "semdi"}. -{"Sunday", "dimegne"}. -{"January", "djanvî"}. -{"February", "fevrî"}. -{"March", "måss"}. -{"April", "avri"}. -{"May", "may"}. -{"June", "djun"}. -{"July", "djulete"}. -{"August", "awousse"}. -{"September", "setimbe"}. -{"October", "octôbe"}. -{"November", "nôvimbe"}. -{"December", "decimbe"}. -{"Room Configuration", "Apontiaedje del såle"}. - -% mod_muc/mod_muc.erl -{"Chatrooms", "Såles di berdelaedje"}. -{"You need an x:data capable client to register nickname", "Vos avoz mezåjhe d' on cliyint ki sopoite x:data po-z edjîstrer on metou no"}. -{"Nickname Registration at ", "Edjîstraedje di metou no amon "}. -{"Enter nickname you want to register", "Dinez l' metou no ki vos vloz edjîstrer"}. -{"ejabberd MUC module", "Module MUC (såles di berdelaedje) po ejabberd"}. -{"Only service administrators are allowed to send service messages", "Seulmint les manaedjeus d' siervices polèt evoyî des messaedjes di siervice"}. -{"Room creation is denied by service policy", "L' ahivaedje del såle est rfuzé pal politike do siervice"}. -{"Conference room does not exist", "Li såle di conferince n' egzistêye nén"}. -{"Access denied by service policy", "L' accès a stî rfuzé pal politike do siervice"}. -{"Specified nickname is already registered", "Li no metou dné est ddja edjîstré"}. -{"You must fill in field \"Nickname\" in the form", "Vos dvoz rimpli l' tchamp «Metou no» dins l' formiulaire"}. - -% mod_muc/mod_muc_room.erl -{" has set the subject to: ", " a candjî l' tite a: "}. -{"You need an x:data capable client to configure room", "I vs fåt on cliyint ki sopoite x:data por vos poleur apontyî l' såle"}. -{"Configuration for ", "Apontiaedje po "}. -{"Room title", "Tite del såle"}. -{"Password", "Sicret"}. -{"Only moderators and participants are allowed to change subject in this room", "Seulmint les moderateus et les pårticipants polèt candjî l' sudjet dins cisse såle ci"}. -{"Only moderators are allowed to change subject in this room", "Seulmint les moderateus polèt candjî l' sudjet dins cisse såle ci"}. -{"Visitors are not allowed to send messages to all occupants", "Les viziteus n' polèt nén evoyî des messaedjes a tos les prezints"}. -{"Only occupants are allowed to send messages to the conference", "Seulmint les prezints polèt evoyî des messaedjes al conferince"}. -{"It is not allowed to send private messages to the conference", "On n' pout nén evoyî des messaedjes privés dins cisse conferince ci"}. -{"Nickname is already in use by another occupant", "Li metou no est ddja eployî pa ene ôte sakî sol såle"}. -{"Nickname is registered by another person", "Li metou no est ddja edjîstré pa ene ôte sakî"}. -{"It is not allowed to send private messages of type \"groupchat\"", "C' est nén possibe d' evoyî des messaedjes privés del sôre «groupchat»"}. -{"Recipient is not in the conference room", "Li riçuveu n' est nén dins l' såle -di conferince"}. -{"Only occupants are allowed to send queries to the conference", "Seulmint les prezints polèt evoyî des cweraedjes sol conferince"}. -{"Queries to the conference members are not allowed in this room", "Les cweraedjes des mimbes del conferince ni sont nén permetous dins cisse såle ci"}. -{"You have been banned from this room", "Vos avoz stî bani di cisse såle ci"}. -{"Membership required to enter this room", "I fåt esse mimbe po poleur intrer dins cisse såle ci"}. -{"Password required to enter this room", "I fåt dner on scret po poleur intrer dins cisse såle ci"}. -{"Incorrect password", "Sicret nén corek"}. -{"Administrator privileges required", "I fåt des priviledjes di manaedjeu"}. -{"Moderator privileges required", "I fåt des priviledjes di moderateu"}. -{"JID ~s is invalid", "Li JID ~s n' est nén valide"}. -{"Nickname ~s does not exist in the room", "Li metou no ~s n' egzistêye nén dins l' såle"}. -{"Invalid role: ~s", "Role nén valide: ~s"}. -{"Owner privileges required", "I fåt des priviledjes di prôpietaire"}. -{"private, ", "privé, "}. -{"This room is not anonymous", "Cisse såle ci n' est nén anonime"}. -{"Make room public searchable", "Rinde li såle di berdelaedje cweråve publicmint"}. -{"Make participants list public", "Rinde publike li djivêye des pårticipants"}. -{"Make room password protected", "Rinde li såle di berdelaedje protedjeye pa scret"}. -{"Make room members-only", "Rinde li såle di berdelaedje ristrindowe ås mimbes seulmint"}. -{"Make room moderated", "Rinde li såle di berdelaedje moderêye"}. -{"Default users as participants", "Les uzeus sont des pårticipants come prémetowe dujhance"}. -{"Allow users to change subject", "Les uzeus polèt candjî l' tite"}. -{"Allow users to send private messages", "Les uzeus polèt evoyî des messaedjes privés"}. -{"Allow users to query other users", "Les uzeus polèt cweri ls ôtes uzeus"}. -{"Allow users to send invites", "Les uzeus polèt evoyî priyaedjes"}. -{"Enable logging", "Mete en alaedje li djournå"}. -{"Description", "Discrijhaedje"}. -{"Number of occupants", "Nombe di prezints"}. -{"Present real JIDs to", "Mostrer les vraiys JIDs a"}. -{"moderators only", "les moderateus seulmint"}. -{"anyone", "tot l' minme kî"}. -{"Traffic rate limit is exceeded", "Li limite pol volume di trafik a stî passêye"}. -{"Improper message type", "Sôre di messaedje nén valide"}. -{"Maximum Number of Occupants", "Nombe macsimom di prezints"}. -{"No limit", "Pont d' limite"}. -{"You have been invited to ~s by ~s", "Vos avoz stî proyî a ~s pa ~s"}. -{"the password is", "li scret est"}. - - -% mod_irc/mod_irc.erl -{"IRC Transport", "Transpoirt IRC"}. -{"ejabberd IRC module", "Module IRC po ejabberd"}. -{"You need an x:data capable client to configure mod_irc settings", "Vos avoz mezåjhe d' on cliyint ki sopoite x:data po candjî ls apontiaedjes di mod_irc"}. -{"Registration in mod_irc for ", "Edjîstraedje dins mod_irc po "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "Dinez les nos d' uzeu et ls ecôdaedjes ki vos vloz eployî po vs raloyî åzès sierveus IRC"}. -{"IRC Username", "No d' uzeu IRC"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "Si vos vloz dner des ecôdaedjes diferins po les sierveus IRC, rimplixhoz cisse djivêye ci avou des valixhances del cogne «{\"sierveu irc\", \"ecôdaedje\"}». Li prémetou ecôdaedje do siervice c' est «~s»."}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "Egzimpe: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"Encodings", "Ecôdaedjes"}. - -% web/ejabberd_web_admin.erl -{"Administration", "Manaedjaedje"}. -{"Users", "Uzeus"}. -{"Nodes", "Nuks"}. -{"Statistics", "Sitatistikes"}. -{"ejabberd (c) 2002-2008 Alexey Shchepin, 2004-2008 Process One", "ejabberd © 2002-2008 Alexey Shchepin, 2004-2008 Process One"}. -{"(Raw)", "(Dinêyes brutes)"}. -{"Submitted", "Candjmints evoyîs"}. -{"Bad format", "Mwais fôrmat"}. -{"Raw", "Dinêyes brutes"}. -{"Delete Selected", "Disfacer les elemints tchoezis"}. -{"Submit", "Evoyî"}. -{"~s access rule configuration", "Apontiaedje des rîles d' accès a ~s"}. -{"Node not found", "Nuk nén trové"}. -{"Add New", "Radjouter"}. -{"Registered Users", "Uzeus edjistrés"}. -{"Registered Users:", "Uzeus edjistrés:"}. -{"Change Password", "Candjî l' sicret"}. -{"Connected Resources:", "Raloyî avou les rsoûces:"}. -{"Password:", "Sicret:"}. -{"None", "Nole"}. -{"Node ", "Nuk "}. -{"Listened Ports", "Pôrts drovous"}. -{"Restart", "Renonder"}. -{"Stop", "Arester"}. -{"Restart Service", "Renonder siervice"}. -{"Shut Down Service", "Arester siervice"}. -{"RPC Call Error", "Aroke di houcaedje RPC"}. -{"Name", "No"}. -{"Storage Type", "Sôre di wårdaedje"}. -{"Size", "Grandeu"}. -{"Memory", "Memwere"}. -{"OK", "'l est bon"}. -{"Listened Ports at ", "Pôrts drovous so "}. -{"Uptime:", "Tins dispoy l' enondaedje:"}. -{"CPU Time:", "Tins CPU:"}. -{"Transactions Commited:", "Transaccions evoyeyes:"}. -{"Transactions Aborted:", "Transaccions arestêyes:"}. -{"Transactions Restarted:", "Transaccions renondêyes:"}. -{"Transactions Logged:", "Transaccions wårdêyes e djournå:"}. -{"Port", "Pôrt"}. -{"Module", "Module"}. -{"Options", "Tchuzes"}. -{"Update", "Mete a djoû"}. -{"Delete", "Disfacer"}. -{"Add User", "Radjouter èn uzeu"}. -{"Delete User", "Disfacer èn uzeu"}. -{"End User Session", "Fini l' session d' l' uzeu"}. -{"Get User Password", "Riçure sicret d' l' uzeu"}. -{"Offline Messages", "Messaedjes ki ratindèt"}. -{"Users Last Activity", "Dierinne activité des uzeus"}. -{"Never", "Måy"}. -{"~s's Offline Messages Queue", "messaedjes ki ratindèt el cawêye po ~s"}. -{"Time", "Date"}. -{"From", "Di"}. -{"To", "Po"}. -{"Packet", "Paket"}. -{"Offline Messages:", "Messaedjes ki ratindèt:"}. -{"Roster", "Djivêye des soçons"}. -{"Nickname", "Metou no"}. -{"Subscription", "Abounmimnt"}. -{"Pending", "Ratindant"}. -{"Groups", "Groupes"}. -{"Remove", "Oister"}. -{"Add Jabber ID", "Radjouter èn ID Jabber"}. -{"User ", "Uzeu "}. -{"Roster of ", "Djivêye des soçons da "}. -{"Online", "Raloyî"}. -{"Validate", "Valider"}. -{"Name:", "Pitit no:"}. -{"Description:", "Discrijhaedje:"}. -{"Members:", "Mimbes:"}. -{"Displayed Groups:", "Groupes håynés:"}. -{"Group ", "Groupe "}. -{"Period: ", "Termene:"}. -{"Last month", "Dierin moes"}. -{"Last year", "Dierinne anêye"}. -{"All activity", "Dispoy todi"}. -{"Show Ordinary Table", "Mostrer crexhince"}. -{"Show Integral Table", "Mostrer totå"}. -{"Modules at ", "Modules so "}. -{"Start", "Enonder"}. -{"Virtual Hosts", "Forveyous sierveus"}. -{"ejabberd virtual hosts", "Forveyous sierveus da ejabberd"}. -{"Host", "Sierveu"}. -{"No Data", "Nole dinêye disponibe"}. -{"ejabberd Web Interface", "Ejabberd - Eterface waibe"}. -{"Online Users:", "Uzeus raloyîs:"}. -{"Outgoing s2s Connections:", "Raloyaedjes s2s e rexhowe:"}. -{"Outgoing s2s Servers:", "Sierveus s2s e rexhowe:"}. -{"Database Tables at ", "Tåves del båze di dnêyes so "}. -{"Backup of ", "Copeye di såvrité po "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "Notez ki ces tchuzes la vont seulmint fé ene copeye di såvrité del båze di dnêyes Mnesia costrûte å dvins do programe. Si vos eployîz ene difoûtrinne båze di dnêyes avou l' module ODBC, vos dvoz fé ene copeye di såvrité del båze SQL da vosse sepårumint."}. -{"Store binary backup:", "Copeye di såvrité binaire:"}. -{"Restore binary backup immediately:", "Rapexhî do côp foû d' ene copeye di såvrité binaire:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "Rapexhî l' copeye di såvrité binaire après l' renondaedje ki vént d' ejabberd (çoula prind moens d' memwere del fé insi):"}. -{"Store plain text backup:", "Copeye di såvrité tecse:"}. -{"Restore plain text backup immediately:", "Rapexhî do côp foû d' ene copeye di såvrité tecse:"}. -{"Statistics of ~p", "Sitatistikes di ~p"}. -{"Update ", "Metaedje a djoû "}. -{"Update plan", "Plan d' metaedje a djoû"}. -{"Updated modules", "Modules metous a djoû"}. -{"Update script", "Sicripe di metaedje a djoû"}. -{"Low level update script", "Sicripe di metaedje a djoû d' bas livea"}. -{"Script check", "Acertinaedje do scripe"}. -{"Shared Roster Groups", "Pårtaedjîs groupes ezès djivêyes di soçons"}. -{"Last Activity", "Dierinne activité"}. - -% mod_offline.erl -{"Your contact offline message queue is full. The message has been discarded.", "Li cawêye di messaedjes e môde disraloyî di vosse soçon est plinne. Li messaedje a stî tapé å diale."}. - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "Module SOCKS5 Bytestreams po ejabberd"}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","Apontiaedje des accès"}. +{"Access Control List Configuration","Apontiaedje des droets (ACL)"}. +{"Access control lists","Droets (ACL)"}. +{"Access Control Lists","Droets (ACL)"}. +{"Access denied by service policy","L' accès a stî rfuzé pal politike do siervice"}. +{"Access rules","Rîles d' accès"}. +{"Access Rules","Rîles d' accès"}. +{"Action on user","Accion so l' uzeu"}. +{"Add Jabber ID","Radjouter èn ID Jabber"}. +{"Add New","Radjouter"}. +{"Add User","Radjouter èn uzeu"}. +{"Administration","Manaedjaedje"}. +{"Administration of ","Manaedjaedje di "}. +{"Administrator privileges required","I fåt des priviledjes di manaedjeu"}. +{"A friendly name for the node","On no uzeu-ahessåve pol nuk"}. +{"All activity","Dispoy todi"}. +{"Allow this JID to subscribe to this pubsub node?","Permete ki ci JID ci si poye abouner a ç' nuk eplaidaedje-abounmint ci?"}. +{"Allow users to change subject","Les uzeus polèt candjî l' tite"}. +{"Allow users to query other users","Les uzeus polèt cweri ls ôtes uzeus"}. +{"Allow users to send invites","Les uzeus polèt evoyî priyaedjes"}. +{"Allow users to send private messages","Les uzeus polèt evoyî des messaedjes privés"}. +{"Allow visitors to change nickname","Permete ki les viziteus candjexhe leus metous nos"}. +{"Allow visitors to send status text in presence updates","Permete ki les viziteus evoyexhe des tecse d' estat dins leus messaedjes di prezince"}. +{"All Users","Tos les uzeus"}. +{"Announcements","Anonces"}. +{"anyone","tot l' minme kî"}. +{"April","avri"}. +{"August","awousse"}. +{"Backup","Copeye di såvrité"}. +{"Backup Management","Manaedjaedje des copeyes di såvrité"}. +{"Backup of ","Copeye di såvrité po "}. +{"Backup to File at ","Fé ene copeye di såvrité dins on fitchî so "}. +{"Bad format","Mwais fôrmat"}. +{"Birthday","Date d' askepiaedje"}. +{"Change Password","Candjî l' sicret"}. +{"Change User Password","Candjî l' sicret d' l' uzeu"}. +{"Chatroom configuration modified","L' apontiaedje del såle di berdelaedje a candjî"}. +{"Chatrooms","Såles di berdelaedje"}. +{"Choose a username and password to register with this server","Tchoezixhoz on no d' uzeu eyet on scret po vs edjîstrer so ç' sierveu ci"}. +{"Choose modules to stop","Tchoezixhoz les modules a-z arester"}. +{"Choose storage type of tables","Tchoezi l' sôre di wårdaedje po les tåves"}. +{"Choose whether to approve this entity's subscription.","Tchoezi s' i fåt aprover ou nén l' abounmint di ciste intité."}. +{"City","Veye"}. +{"Commands","Comandes"}. +{"Conference room does not exist","Li såle di conferince n' egzistêye nén"}. +{"Configuration","Apontiaedjes"}. +{"Configuration for ","Apontiaedje po "}. +{"Connected Resources:","Raloyî avou les rsoûces:"}. +{"Country","Payis"}. +{"CPU Time:","Tins CPU:"}. +{"Database","Båze di dnêyes"}. +{"Database Tables at ","Tåves del båze di dnêyes so "}. +{"Database Tables Configuration at ","Apontiaedje des tåves del båze di dnêyes so "}. +{"December","decimbe"}. +{"Default users as participants","Les uzeus sont des pårticipants come prémetowe dujhance"}. +{"Delete","Disfacer"}. +{"Delete message of the day","Disfacer l' messaedje do djoû"}. +{"Delete message of the day on all hosts","Disfacer l' messaedje do djoû so tos les lodjoes"}. +{"Delete Selected","Disfacer les elemints tchoezis"}. +{"Delete User","Disfacer èn uzeu"}. +{"Deliver event notifications","Evoyî des notifiaedjes d' evenmints"}. +{"Deliver payloads with event notifications","Evoyî l' contnou avou les notifiaedjes d' evenmints"}. +{"Description:","Discrijhaedje:"}. +{"Disc only copy","Copeye seulmint sol deure plake"}. +{"Displayed Groups:","Groupes håynés:"}. +{"Dump Backup to Text File at ","Copeye di såvritè viè on fitchî tecse so "}. +{"Dump to Text File","Schaper en on fitchî tecse"}. +{"Edit Properties","Candjî les prôpietés"}. +{"ejabberd IRC module","Module IRC po ejabberd"}. +{"ejabberd MUC module","Module MUC (såles di berdelaedje) po ejabberd"}. +{"ejabberd Publish-Subscribe module","Module d' eplaidaedje-abounmint po ejabberd"}. +{"ejabberd SOCKS5 Bytestreams module","Module SOCKS5 Bytestreams po ejabberd"}. +{"ejabberd vCard module","Module vCard ejabberd"}. +{"ejabberd virtual hosts","Forveyous sierveus da ejabberd"}. +{"ejabberd Web Admin","Manaedjeu waibe ejabberd"}. +{"Email","Emile"}. +{"Enable logging","Mete en alaedje li djournå"}. +{"Encodings","Ecôdaedjes"}. +{"End User Session","Fini l' session d' l' uzeu"}. +{"Enter list of {Module, [Options]}","Dinez ene djivêye del cogne {Module, [Tchuzes]}"}. +{"Enter nickname you want to register","Dinez l' metou no ki vos vloz edjîstrer"}. +{"Enter path to backup file","Dinez l' tchimin viè l' fitchî copeye di såvrité"}. +{"Enter path to jabberd1.4 spool dir","Dinez l' tchimin viè l' ridant di spool jabberd1.4"}. +{"Enter path to jabberd1.4 spool file","Dinez l' tchimin viè l' fitchî di spool jabberd1.4"}. +{"Enter path to text file","Dinez l' tchimin viè l' fitchî tecse"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","Dinez les nos d' uzeu et ls ecôdaedjes ki vos vloz eployî po vs raloyî åzès sierveus IRC"}. +{"Erlang Jabber Server","Sierveu Jabber Erlang"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","Egzimpe: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","No d' famile"}. +{"February","fevrî"}. +{"Fill in fields to search for any matching Jabber User","Rimplixhoz les tchamps po cweri èn uzeu Jabber"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","Rimplixhoz les tchamps do formulaire po cweri èn uzeu Jabber (radjouter «*» al fén do tchamp po cweri tot l' minme kéne fén d' tchinne"}. +{"Friday","vénrdi"}. +{"From","Di"}. +{"From ~s","Dispoy ~s"}. +{"Full Name","No etir"}. +{"Get Number of Online Users","Riçure li nombe d' uzeus raloyîs"}. +{"Get Number of Registered Users","Riçure li nombe d' uzeus edjîstrés"}. +{"Get User Last Login Time","Riçure li date/eure do dierin elodjaedje di l' uzeu"}. +{"Get User Password","Riçure sicret d' l' uzeu"}. +{"Get User Statistics","Riçure les statistikes di l' uzeu"}. +{"Group ","Groupe "}. +{"Groups","Groupes"}. +{"has been banned","a stî bani"}. +{"has been kicked","a stî pité evoye"}. +{"has been kicked because of an affiliation change","a stî pité evoye cåze d' on candjmint d' afiyaedje"}. +{"has been kicked because of a system shutdown","a stî pité evoye cåze d' èn arestaedje do sistinme"}. +{"has been kicked because the room has been changed to members-only","a stî pité evoye cåze ki l' såle a stî ristrindowe åzès mimbes seulmint"}. +{" has set the subject to: "," a candjî l' tite a: "}. +{"Host","Sierveu"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","Si vos vloz dner des ecôdaedjes diferins po les sierveus IRC, rimplixhoz cisse djivêye ci avou des valixhances del cogne «{\"sierveu irc\", \"ecôdaedje\"}». Li prémetou ecôdaedje do siervice c' est «~s»."}. +{"Import Directory","Sititchî d' on ridant"}. +{"Import File","Sititchî d' on fitchî"}. +{"Import User from File at ","Sititchî uzeu d' on fitchî so "}. +{"Import Users from Dir at ","Sitichî des uzeus d' on ridant so "}. +{"Import Users From jabberd 1.4 Spool Files","Sititchî des uzeus Jabberd 1.4"}. +{"Improper message type","Sôre di messaedje nén valide"}. +{"Incorrect password","Sicret nén corek"}. +{"Invalid affiliation: ~s","Afiyaedje nén valide: ~s"}. +{"Invalid role: ~s","Role nén valide: ~s"}. +{"IP addresses","Adresses IP"}. +{"IRC Transport","Transpoirt IRC"}. +{"IRC Username","No d' uzeu IRC"}. +{"is now known as","est asteure kinoxhou come"}. +{"It is not allowed to send private messages","Ci n' est nén permetou d' evoyî des messaedjes privés"}. +{"It is not allowed to send private messages of type \"groupchat\"","C' est nén possibe d' evoyî des messaedjes privés del sôre «groupchat»"}. +{"It is not allowed to send private messages to the conference","On n' pout nén evoyî des messaedjes privés dins cisse conferince ci"}. +{"Jabber ID","ID Jabber"}. +{"January","djanvî"}. +{"JID ~s is invalid","Li JID ~s n' est nén valide"}. +{"joins the room","arive sol såle"}. +{"July","djulete"}. +{"June","djun"}. +{"Last Activity","Dierinne activité"}. +{"Last login","Dierin elodjaedje"}. +{"Last month","Dierin moes"}. +{"Last year","Dierinne anêye"}. +{"leaves the room","cwite li såle"}. +{"Listened Ports at ","Pôrts drovous so "}. +{"Listened Ports","Pôrts drovous"}. +{"List of modules to start","Djivêye di modules a-z enonder"}. +{"Low level update script","Sicripe di metaedje a djoû d' bas livea"}. +{"Make participants list public","Rinde publike li djivêye des pårticipants"}. +{"Make room members-only","Rinde li såle di berdelaedje ristrindowe ås mimbes seulmint"}. +{"Make room moderated","Rinde li såle di berdelaedje moderêye"}. +{"Make room password protected","Rinde li såle di berdelaedje protedjeye pa scret"}. +{"Make room persistent","Rinde li såle permaninte"}. +{"Make room public searchable","Rinde li såle di berdelaedje cweråve publicmint"}. +{"March","måss"}. +{"Maximum Number of Occupants","Nombe macsimom di prezints"}. +{"Max # of items to persist","Nombe macsimoms di cayets permanints"}. +{"Max payload size in bytes","Contnou macsimom en octets"}. +{"May","may"}. +{"Membership required to enter this room","I fåt esse mimbe po poleur intrer dins cisse såle ci"}. +{"Members:","Mimbes:"}. +{"Memory","Memwere"}. +{"Message body","Coir do messaedje"}. +{"Middle Name","No do mitan"}. +{"Moderator privileges required","I fåt des priviledjes di moderateu"}. +{"moderators only","les moderateus seulmint"}. +{"Module","Module"}. +{"Modules at ","Modules so "}. +{"Modules","Modules"}. +{"Monday","londi"}. +{"Name","No"}. +{"Name:","Pitit no:"}. +{"Never","Måy"}. +{"Nickname is already in use by another occupant","Li metou no est ddja eployî pa ene ôte sakî sol såle"}. +{"Nickname is registered by another person","Li metou no est ddja edjîstré pa ene ôte sakî"}. +{"Nickname","Metou no"}. +{"Nickname Registration at ","Edjîstraedje di metou no amon "}. +{"Nickname ~s does not exist in the room","Li metou no ~s n' egzistêye nén dins l' såle"}. +{"No body provided for announce message","I n' a nou coir do messaedje po ciste anonce la"}. +{"No Data","Nole dinêye disponibe"}. +{"Node ID","ID d' nuk"}. +{"Node not found","Nuk nén trové"}. +{"Node ","Nuk "}. +{"Nodes","Nuks"}. +{"No limit","Pont d' limite"}. +{"None","Nole"}. +{"No resource provided","Nole rissoûce di dnêye"}. +{"Notify subscribers when items are removed from the node","Notifyî åzès abounés cwand des cayets sont oisté foû do nuk"}. +{"Notify subscribers when the node configuration changes","Notifyî åzès abounés cwand l' apontiaedje do nuk candje"}. +{"Notify subscribers when the node is deleted","Notifyî åzès abounés cwand l' nuk est disfacé"}. +{"November","nôvimbe"}. +{"Number of occupants","Nombe di prezints"}. +{"Number of online users","Nombe d' uzeus raloyîs"}. +{"Number of registered users","Nombe d' uzeus edjîstrés"}. +{"October","octôbe"}. +{"Offline Messages:","Messaedjes ki ratindèt:"}. +{"Offline Messages","Messaedjes ki ratindèt"}. +{"OK","'l est bon"}. +{"Online","Raloyî"}. +{"Online Users:","Uzeus raloyîs:"}. +{"Online Users","Uzeus raloyîs"}. +{"Only deliver notifications to available users","Seulmint evoyî des notifiaedje åzès uzeus disponibes"}. +{"Only moderators and participants are allowed to change subject in this room","Seulmint les moderateus et les pårticipants polèt candjî l' sudjet dins cisse såle ci"}. +{"Only moderators are allowed to change subject in this room","Seulmint les moderateus polèt candjî l' sudjet dins cisse såle ci"}. +{"Only occupants are allowed to send messages to the conference","Seulmint les prezints polèt evoyî des messaedjes al conferince"}. +{"Only occupants are allowed to send queries to the conference","Seulmint les prezints polèt evoyî des cweraedjes sol conferince"}. +{"Only service administrators are allowed to send service messages","Seulmint les manaedjeus d' siervices polèt evoyî des messaedjes di siervice"}. +{"Options","Tchuzes"}. +{"Organization Name","No d' l' organizåcion"}. +{"Organization Unit","Unité d' l' organizåcion"}. +{"Outgoing s2s Connections:","Raloyaedjes s2s e rexhowe:"}. +{"Outgoing s2s Connections","Raloyaedjes s2s e rexhowe"}. +{"Outgoing s2s Servers:","Sierveus s2s e rexhowe:"}. +{"Owner privileges required","I fåt des priviledjes di prôpietaire"}. +{"Packet","Paket"}. +{"Password required to enter this room","I fåt dner on scret po poleur intrer dins cisse såle ci"}. +{"Password:","Sicret:"}. +{"Password","Sicret"}. +{"Password Verification","Acertinaedje do scret"}. +{"Path to Dir","Tchimin viè l' ridant"}. +{"Path to File","Tchimin viè l' fitchî"}. +{"Pending","Ratindant"}. +{"Period: ","Termene:"}. +{"Persist items to storage","Cayets permanints a wårder"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","Pôrt"}. +{"Present real JIDs to","Mostrer les vraiys JIDs a"}. +{"private, ","privé, "}. +{"Publish-Subscribe","Eplaidaedje-abounmint"}. +{"PubSub subscriber request","Dimande d' eplaidaedje-abounmint d' èn abouné"}. +{"Queries to the conference members are not allowed in this room","Les cweraedjes des mimbes del conferince ni sont nén permetous dins cisse såle ci"}. +{"RAM and disc copy","Copeye e memwere (RAM) et sol deure plake"}. +{"RAM copy","Copeye e memwere (RAM)"}. +{"(Raw)","(Dinêyes brutes)"}. +{"Raw","Dinêyes brutes"}. +{"Really delete message of the day?","Voloz vs vormint disfacer l' messaedje do djoû?"}. +{"Recipient is not in the conference room","Li riçuveu n' est nén dins l' såle di conferince"}. +{"Registered Users:","Uzeus edjistrés:"}. +{"Registered Users","Uzeus edjistrés"}. +{"Registration in mod_irc for ","Edjîstraedje dins mod_irc po "}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","Notez ki ces tchuzes la vont seulmint fé ene copeye di såvrité del båze di dnêyes Mnesia costrûte å dvins do programe. Si vos eployîz ene difoûtrinne båze di dnêyes avou l' module ODBC, vos dvoz fé ene copeye di såvrité del båze SQL da vosse sepårumint."}. +{"Remote copy","Copeye å lon"}. +{"Remove","Oister"}. +{"Remove User","Disfacer l' uzeu"}. +{"Replaced by new connection","Replaecî pa on novea raloyaedje"}. +{"Resources","Rissoûces"}. +{"Restart","Renonder"}. +{"Restart Service","Renonder siervice"}. +{"Restore Backup from File at ","Rapexhî dispoy li fitchî copeye di såvrité so "}. +{"Restore binary backup after next ejabberd restart (requires less memory):","Rapexhî l' copeye di såvrité binaire après l' renondaedje ki vént d' ejabberd (çoula prind moens d' memwere del fé insi):"}. +{"Restore binary backup immediately:","Rapexhî do côp foû d' ene copeye di såvrité binaire:"}. +{"Restore plain text backup immediately:","Rapexhî do côp foû d' ene copeye di såvrité tecse:"}. +{"Restore","Rapexhî"}. +{"Room Configuration","Apontiaedje del såle"}. +{"Room creation is denied by service policy","L' ahivaedje del såle est rfuzé pal politike do siervice"}. +{"Room title","Tite del såle"}. +{"Roster","Djivêye des soçons"}. +{"Roster groups allowed to subscribe","Pårtaedjîs groupes di soçons k' on s' î pout abouner"}. +{"Roster of ","Djivêye des soçons da "}. +{"Roster size","Grandeu del djivêye des soçons"}. +{"RPC Call Error","Aroke di houcaedje RPC"}. +{"Running Nodes","Nuks en alaedje"}. +{"~s access rule configuration","Apontiaedje des rîles d' accès a ~s"}. +{"Saturday","semdi"}. +{"Script check","Acertinaedje do scripe"}. +{"Search Results for ","Rizultats do cweraedje po "}. +{"Search users in ","Cweri des uzeus dins "}. +{"Send announcement to all online users","Evoyî l' anonce a tos les uzeus raloyîs"}. +{"Send announcement to all online users on all hosts","Evoyî l' anonce a tos les uzeus raloyîs so tos les lodjoes"}. +{"Send announcement to all users","Evoyî l' anonce a tos les uzeus"}. +{"Send announcement to all users on all hosts","Evoyî l' anonce a tos les uzeus so tos les lodjoes"}. +{"September","setimbe"}. +{"Set message of the day and send to online users","Defini l' messaedje do djoû et l' evoyî åzès uzeus raloyîs"}. +{"Set message of the day on all hosts and send to online users","Defini l' messaedje do djoû so tos les lodjoes et l' evoyî åzès uzeus raloyîs"}. +{"Shared Roster Groups","Pårtaedjîs groupes ezès djivêyes di soçons"}. +{"Show Integral Table","Mostrer totå"}. +{"Show Ordinary Table","Mostrer crexhince"}. +{"Shut Down Service","Arester siervice"}. +{"~s invites you to the room ~s","~s vos preye sol såle ~s"}. +{"Size","Grandeu"}. +{"Specified nickname is already registered","Li no metou dné est ddja edjîstré"}. +{"Specify the access model","Sipecifyî l' modele d' accès"}. +{"Specify the publisher model","Dinez l' modele d' eplaideu"}. +{"~s's Offline Messages Queue","messaedjes ki ratindèt el cawêye po ~s"}. +{"Start","Enonder"}. +{"Start Modules at ","Renonder les modules so "}. +{"Start Modules","Enonder des modules"}. +{"Statistics of ~p","Sitatistikes di ~p"}. +{"Statistics","Sitatistikes"}. +{"Stop","Arester"}. +{"Stop Modules","Arester des modules"}. +{"Stop Modules at ","Arester les modules so "}. +{"Stopped Nodes","Nuks essoctés"}. +{"Storage Type","Sôre di wårdaedje"}. +{"Store binary backup:","Copeye di såvrité binaire:"}. +{"Store plain text backup:","Copeye di såvrité tecse:"}. +{"Subject","Sudjet"}. +{"Submit","Evoyî"}. +{"Submitted","Candjmints evoyîs"}. +{"Subscriber Address","Adresse di l' abouné"}. +{"Subscription","Abounmimnt"}. +{"Sunday","dimegne"}. +{"the password is","li scret est"}. +{"This participant is kicked from the room because he sent an error message","Ci pårticipant ci a stî pité evoye del såle cåze k' il a-st evoyî on messaedje d' aroke"}. +{"This participant is kicked from the room because he sent an error message to another participant","Ci pårticipant ci a stî pité evoye del såle cåze k' il a-st evoyî on messaedje d' aroke a èn ôte pårticipant"}. +{"This participant is kicked from the room because he sent an error presence","Ci pårticipant ci a stî pité evoye del såle cåze k' il a-st evoyî ene aroke di prezince"}. +{"This room is not anonymous","Cisse såle ci n' est nén anonime"}. +{"Thursday","djudi"}. +{"Time","Date"}. +{"Time delay","Tårdjaedje"}. +{"To","Po"}. +{"To ~s","Viè ~s"}. +{"Traffic rate limit is exceeded","Li limite pol volume di trafik a stî passêye"}. +{"Transactions Aborted:","Transaccions arestêyes:"}. +{"Transactions Commited:","Transaccions evoyeyes:"}. +{"Transactions Logged:","Transaccions wårdêyes e djournå:"}. +{"Transactions Restarted:","Transaccions renondêyes:"}. +{"Tuesday","mårdi"}. +{"Updated modules","Modules metous a djoû"}. +{"Update message of the day (don't send)","Mete a djoû l' messaedje do djoû (nén l' evoyî)"}. +{"Update message of the day on all hosts (don't send)","Mete a djoû l' messaedje do djoû so tos les lodjoes (nén l' evoyî)"}. +{"Update ","Metaedje a djoû "}. +{"Update","Mete a djoû"}. +{"Update plan","Plan d' metaedje a djoû"}. +{"Update script","Sicripe di metaedje a djoû"}. +{"Uptime:","Tins dispoy l' enondaedje:"}. +{"Use of STARTTLS required","L' eployaedje di STARTTL est oblidjî"}. +{"User Management","Manaedjaedje des uzeus"}. +{"Users are not allowed to register accounts so fast","Les noveas uzeus n' si polèt nén edjîstrer si raddimint"}. +{"Users Last Activity","Dierinne activité des uzeus"}. +{"Users","Uzeus"}. +{"User ","Uzeu "}. +{"User","Uzeu"}. +{"Validate","Valider"}. +{"vCard User Search","Calpin des uzeus"}. +{"Virtual Hosts","Forveyous sierveus"}. +{"Visitors are not allowed to change their nicknames in this room","Les viziteus èn polèt nén candjî leus metous no po ç' såle ci"}. +{"Visitors are not allowed to send messages to all occupants","Les viziteus n' polèt nén evoyî des messaedjes a tos les prezints"}. +{"Wednesday","mierkidi"}. +{"When to send the last published item","Cwand evoyî l' dierin cayet eplaidî"}. +{"Whether to allow subscriptions","Si on permete les abounmints"}. +{"You have been banned from this room","Vos avoz stî bani di cisse såle ci"}. +{"You must fill in field \"Nickname\" in the form","Vos dvoz rimpli l' tchamp «Metou no» dins l' formiulaire"}. +{"You need an x:data capable client to configure mod_irc settings","Vos avoz mezåjhe d' on cliyint ki sopoite x:data po candjî ls apontiaedjes di mod_irc"}. +{"You need an x:data capable client to configure room","I vs fåt on cliyint ki sopoite x:data por vos poleur apontyî l' såle"}. +{"You need an x:data capable client to register nickname","Vos avoz mezåjhe d' on cliyint ki sopoite x:data po-z edjîstrer on metou no"}. +{"You need an x:data capable client to search","Vos avoz mezåjhe d' on cliyint ki sopoite x:data po fé on cweraedje"}. +{"Your contact offline message queue is full. The message has been discarded.","Li cawêye di messaedjes e môde disraloyî di vosse soçon est plinne. Li messaedje a stî tapé å diale."}. diff --git a/src/msgs/wa.po b/src/msgs/wa.po new file mode 100644 index 000000000..9dd938183 --- /dev/null +++ b/src/msgs/wa.po @@ -0,0 +1,1505 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Pablo Saratxaga\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Walon (Walloon)\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "L' eployaedje di STARTTL est oblidjî" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "Nole rissoûce di dnêye" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "Replaecî pa on novea raloyaedje" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "Comandes" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "Voloz vs vormint disfacer l' messaedje do djoû?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "Sudjet" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "Coir do messaedje" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "I n' a nou coir do messaedje po ciste anonce la" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "Anonces" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "Evoyî l' anonce a tos les uzeus" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "Evoyî l' anonce a tos les uzeus so tos les lodjoes" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "Evoyî l' anonce a tos les uzeus raloyîs" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "Evoyî l' anonce a tos les uzeus raloyîs so tos les lodjoes" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "Defini l' messaedje do djoû et l' evoyî åzès uzeus raloyîs" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "" +"Defini l' messaedje do djoû so tos les lodjoes et l' evoyî åzès uzeus raloyîs" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "Mete a djoû l' messaedje do djoû (nén l' evoyî)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "Mete a djoû l' messaedje do djoû so tos les lodjoes (nén l' evoyî)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "Disfacer l' messaedje do djoû" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "Disfacer l' messaedje do djoû so tos les lodjoes" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "Apontiaedjes" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "Båze di dnêyes" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "Enonder des modules" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "Arester des modules" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "Copeye di såvrité" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "Rapexhî" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "Schaper en on fitchî tecse" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "Sititchî d' on fitchî" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "Sititchî d' on ridant" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "Renonder siervice" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "Arester siervice" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "Radjouter èn uzeu" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "Disfacer èn uzeu" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "Fini l' session d' l' uzeu" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "Riçure sicret d' l' uzeu" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "Candjî l' sicret d' l' uzeu" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "Riçure li date/eure do dierin elodjaedje di l' uzeu" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "Riçure les statistikes di l' uzeu" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "Riçure li nombe d' uzeus edjîstrés" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "Riçure li nombe d' uzeus raloyîs" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "Droets (ACL)" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "Rîles d' accès" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "Manaedjaedje des uzeus" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "Uzeus raloyîs" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "Tos les uzeus" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "Raloyaedjes s2s e rexhowe" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "Nuks en alaedje" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "Nuks essoctés" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "Modules" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "Manaedjaedje des copeyes di såvrité" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "Sititchî des uzeus Jabberd 1.4" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "Viè ~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "Dispoy ~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "Apontiaedje des tåves del båze di dnêyes so " + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "Tchoezi l' sôre di wårdaedje po les tåves" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "Copeye seulmint sol deure plake" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "Copeye e memwere (RAM) et sol deure plake" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "Copeye e memwere (RAM)" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "Copeye å lon" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "Arester les modules so " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "Tchoezixhoz les modules a-z arester" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "Renonder les modules so " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "Dinez ene djivêye del cogne {Module, [Tchuzes]}" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "Djivêye di modules a-z enonder" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "Fé ene copeye di såvrité dins on fitchî so " + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "Dinez l' tchimin viè l' fitchî copeye di såvrité" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "Tchimin viè l' fitchî" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "Rapexhî dispoy li fitchî copeye di såvrité so " + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "Copeye di såvritè viè on fitchî tecse so " + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "Dinez l' tchimin viè l' fitchî tecse" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "Sititchî uzeu d' on fitchî so " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "Dinez l' tchimin viè l' fitchî di spool jabberd1.4" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "Sitichî des uzeus d' on ridant so " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "Dinez l' tchimin viè l' ridant di spool jabberd1.4" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "Tchimin viè l' ridant" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "Tårdjaedje" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "Apontiaedje des droets (ACL)" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "Droets (ACL)" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "Apontiaedje des accès" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "Rîles d' accès" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "ID Jabber" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "Sicret" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "Acertinaedje do scret" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "Nombe d' uzeus edjîstrés" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "Nombe d' uzeus raloyîs" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "Måy" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "Raloyî" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "Dierin elodjaedje" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "Grandeu del djivêye des soçons" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "Adresses IP" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "Rissoûces" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "Manaedjaedje di " + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "Accion so l' uzeu" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "Candjî les prôpietés" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "Disfacer l' uzeu" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "L' accès a stî rfuzé pal politike do siervice" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "Transpoirt IRC" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "Module IRC po ejabberd" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "" +"Vos avoz mezåjhe d' on cliyint ki sopoite x:data po candjî ls apontiaedjes " +"di mod_irc" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "Edjîstraedje dins mod_irc po " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "" +"Dinez les nos d' uzeu et ls ecôdaedjes ki vos vloz eployî po vs raloyî åzès " +"sierveus IRC" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "No d' uzeu IRC" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"Si vos vloz dner des ecôdaedjes diferins po les sierveus IRC, rimplixhoz " +"cisse djivêye ci avou des valixhances del cogne «{\"sierveu irc\", \"ecôdaedje" +"\"}». Li prémetou ecôdaedje do siervice c' est «~s»." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"Egzimpe: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "Ecôdaedjes" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "" +"Seulmint les manaedjeus d' siervices polèt evoyî des messaedjes di siervice" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "L' ahivaedje del såle est rfuzé pal politike do siervice" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "Li såle di conferince n' egzistêye nén" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "Såles di berdelaedje" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "" +"Vos avoz mezåjhe d' on cliyint ki sopoite x:data po-z edjîstrer on metou no" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "Edjîstraedje di metou no amon " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "Dinez l' metou no ki vos vloz edjîstrer" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "Metou no" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "Li no metou dné est ddja edjîstré" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "Vos dvoz rimpli l' tchamp «Metou no» dins l' formiulaire" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "Module MUC (såles di berdelaedje) po ejabberd" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "L' apontiaedje del såle di berdelaedje a candjî" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "arive sol såle" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "cwite li såle" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "a stî bani" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "a stî pité evoye" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "a stî pité evoye cåze d' on candjmint d' afiyaedje" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "" +"a stî pité evoye cåze ki l' såle a stî ristrindowe åzès mimbes seulmint" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "a stî pité evoye cåze d' èn arestaedje do sistinme" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "est asteure kinoxhou come" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr " a candjî l' tite a: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "londi" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "mårdi" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "mierkidi" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "djudi" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "vénrdi" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "semdi" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "dimegne" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "djanvî" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "fevrî" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "måss" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "avri" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "may" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "djun" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "djulete" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "awousse" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "setimbe" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "octôbe" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "nôvimbe" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "decimbe" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "Apontiaedje del såle" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "Tite del såle" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "Li limite pol volume di trafik a stî passêye" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "" +"Ci pårticipant ci a stî pité evoye del såle cåze k' il a-st evoyî on " +"messaedje d' aroke" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "On n' pout nén evoyî des messaedjes privés dins cisse conferince ci" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "Sôre di messaedje nén valide" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "" +"Ci pårticipant ci a stî pité evoye del såle cåze k' il a-st evoyî on " +"messaedje d' aroke a èn ôte pårticipant" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "C' est nén possibe d' evoyî des messaedjes privés del sôre «groupchat»" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "Li riçuveu n' est nén dins l' såle di conferince" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "Seulmint les prezints polèt evoyî des messaedjes al conferince" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "Ci n' est nén permetou d' evoyî des messaedjes privés" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "Seulmint les prezints polèt evoyî des cweraedjes sol conferince" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "" +"Les cweraedjes des mimbes del conferince ni sont nén permetous dins cisse " +"såle ci" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "privé, " + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "" +"Seulmint les moderateus et les pårticipants polèt candjî l' sudjet dins " +"cisse såle ci" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "Seulmint les moderateus polèt candjî l' sudjet dins cisse såle ci" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "Les viziteus n' polèt nén evoyî des messaedjes a tos les prezints" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "" +"Ci pårticipant ci a stî pité evoye del såle cåze k' il a-st evoyî ene aroke " +"di prezince" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "Les viziteus èn polèt nén candjî leus metous no po ç' såle ci" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "Li metou no est ddja eployî pa ene ôte sakî sol såle" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "Li metou no est ddja edjîstré pa ene ôte sakî" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "Vos avoz stî bani di cisse såle ci" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "I fåt esse mimbe po poleur intrer dins cisse såle ci" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "Cisse såle ci n' est nén anonime" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "I fåt dner on scret po poleur intrer dins cisse såle ci" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "Sicret nén corek" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "I fåt des priviledjes di manaedjeu" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "I fåt des priviledjes di moderateu" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "Li JID ~s n' est nén valide" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "Li metou no ~s n' egzistêye nén dins l' såle" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "Afiyaedje nén valide: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "Role nén valide: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "I fåt des priviledjes di prôpietaire" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "Apontiaedje po " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "Discrijhaedje:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "Rinde li såle permaninte" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "Rinde li såle di berdelaedje cweråve publicmint" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "Rinde publike li djivêye des pårticipants" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "Rinde li såle di berdelaedje protedjeye pa scret" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "Nombe macsimom di prezints" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "Pont d' limite" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "Mostrer les vraiys JIDs a" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "les moderateus seulmint" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "tot l' minme kî" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "Rinde li såle di berdelaedje ristrindowe ås mimbes seulmint" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "Rinde li såle di berdelaedje moderêye" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "Les uzeus sont des pårticipants come prémetowe dujhance" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "Les uzeus polèt candjî l' tite" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "Les uzeus polèt evoyî des messaedjes privés" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "Les uzeus polèt cweri ls ôtes uzeus" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "Les uzeus polèt evoyî priyaedjes" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "" +"Permete ki les viziteus evoyexhe des tecse d' estat dins leus messaedjes di " +"prezince" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "Permete ki les viziteus candjexhe leus metous nos" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "Mete en alaedje li djournå" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "I vs fåt on cliyint ki sopoite x:data por vos poleur apontyî l' såle" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "Nombe di prezints" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s vos preye sol såle ~s" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "li scret est" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "" +"Li cawêye di messaedjes e môde disraloyî di vosse soçon est plinne. Li " +"messaedje a stî tapé å diale." + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "messaedjes ki ratindèt el cawêye po ~s" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "Candjmints evoyîs" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "Date" + +#: mod_offline.erl:507 +msgid "From" +msgstr "Di" + +#: mod_offline.erl:508 +msgid "To" +msgstr "Po" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "Paket" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "Disfacer les elemints tchoezis" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "Messaedjes ki ratindèt:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "Module SOCKS5 Bytestreams po ejabberd" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "Eplaidaedje-abounmint" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "Module d' eplaidaedje-abounmint po ejabberd" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "Dimande d' eplaidaedje-abounmint d' èn abouné" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "Tchoezi s' i fåt aprover ou nén l' abounmint di ciste intité." + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "ID d' nuk" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "Adresse di l' abouné" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "" +"Permete ki ci JID ci si poye abouner a ç' nuk eplaidaedje-abounmint ci?" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "Evoyî l' contnou avou les notifiaedjes d' evenmints" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "Evoyî des notifiaedjes d' evenmints" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "Notifyî åzès abounés cwand l' apontiaedje do nuk candje" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "Notifyî åzès abounés cwand l' nuk est disfacé" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "Notifyî åzès abounés cwand des cayets sont oisté foû do nuk" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "Cayets permanints a wårder" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "On no uzeu-ahessåve pol nuk" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "Nombe macsimoms di cayets permanints" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "Si on permete les abounmints" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "Sipecifyî l' modele d' accès" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "Pårtaedjîs groupes di soçons k' on s' î pout abouner" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "Dinez l' modele d' eplaideu" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "Contnou macsimom en octets" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "Cwand evoyî l' dierin cayet eplaidî" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "Seulmint evoyî des notifiaedje åzès uzeus disponibes" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "" +"Tchoezixhoz on no d' uzeu eyet on scret po vs edjîstrer so ç' sierveu ci" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "Les noveas uzeus n' si polèt nén edjîstrer si raddimint" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "Nole" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "Abounmimnt" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "Ratindant" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "Groupes" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "Valider" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "Oister" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "Djivêye des soçons da " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "Mwais fôrmat" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "Radjouter èn ID Jabber" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "Djivêye des soçons" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "Pårtaedjîs groupes ezès djivêyes di soçons" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "Radjouter" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "Pitit no:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "Discrijhaedje:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "Mimbes:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "Groupes håynés:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "Groupe " + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "Evoyî" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Sierveu Jabber Erlang" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "Date d' askepiaedje" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "Veye" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "Payis" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "Emile" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "No d' famile" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "" +"Rimplixhoz les tchamps do formulaire po cweri èn uzeu Jabber (radjouter «*» " +"al fén do tchamp po cweri tot l' minme kéne fén d' tchinne" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "No etir" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "No do mitan" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "No" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "No d' l' organizåcion" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "Unité d' l' organizåcion" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "Cweri des uzeus dins " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "Uzeu" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "Vos avoz mezåjhe d' on cliyint ki sopoite x:data po fé on cweraedje" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "Calpin des uzeus" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "Module vCard ejabberd" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "Rizultats do cweraedje po " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "Rimplixhoz les tchamps po cweri èn uzeu Jabber" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "Manaedjeu waibe ejabberd" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "Manaedjaedje" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "Forveyous sierveus" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "Nuks" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "Sitatistikes" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "Uzeus" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "Dierinne activité" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(Dinêyes brutes)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "Dinêyes brutes" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "Apontiaedje des rîles d' accès a ~s" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "Forveyous sierveus da ejabberd" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "Dierinne activité des uzeus" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "Termene:" + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "Dierin moes" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "Dierinne anêye" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "Dispoy todi" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "Mostrer crexhince" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "Mostrer totå" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "Nuk nén trové" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "Sierveu" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "Uzeus edjistrés" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "Messaedjes ki ratindèt" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "Uzeus edjistrés:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "Uzeus raloyîs:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "Raloyaedjes s2s e rexhowe:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "Sierveus s2s e rexhowe:" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "Candjî l' sicret" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "Uzeu " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "Raloyî avou les rsoûces:" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "Sicret:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "Nole dinêye disponibe" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "Nuk " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "Pôrts drovous" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "Mete a djoû" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "Renonder" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "Arester" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "Aroke di houcaedje RPC" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "Tåves del båze di dnêyes so " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "Sôre di wårdaedje" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "Grandeu" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "Memwere" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "Copeye di såvrité po " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"Notez ki ces tchuzes la vont seulmint fé ene copeye di såvrité del båze di " +"dnêyes Mnesia costrûte å dvins do programe. Si vos eployîz ene difoûtrinne " +"båze di dnêyes avou l' module ODBC, vos dvoz fé ene copeye di såvrité del " +"båze SQL da vosse sepårumint." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "Copeye di såvrité binaire:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "'l est bon" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "Rapexhî do côp foû d' ene copeye di såvrité binaire:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "" +"Rapexhî l' copeye di såvrité binaire après l' renondaedje ki vént " +"d' ejabberd (çoula prind moens d' memwere del fé insi):" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "Copeye di såvrité tecse:" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "Rapexhî do côp foû d' ene copeye di såvrité tecse:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "Pôrts drovous so " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "Modules so " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "Sitatistikes di ~p" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "Tins dispoy l' enondaedje:" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "Tins CPU:" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "Transaccions evoyeyes:" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "Transaccions arestêyes:" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "Transaccions renondêyes:" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "Transaccions wårdêyes e djournå:" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "Metaedje a djoû " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "Plan d' metaedje a djoû" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "Modules metous a djoû" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "Sicripe di metaedje a djoû" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "Sicripe di metaedje a djoû d' bas livea" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "Acertinaedje do scripe" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "Pôrt" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "Module" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "Tchuzes" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "Disfacer" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "Enonder" diff --git a/src/msgs/zh.msg b/src/msgs/zh.msg index 9dd0bd749..82d0d1fae 100644 --- a/src/msgs/zh.msg +++ b/src/msgs/zh.msg @@ -1,387 +1,343 @@ -% $Id$ -% Language: Chinese (中文) -% Author: Mike Wang -% Author: Zhan Caibao - zhancaibao AT gmail DOT com -% Author: Shelley Shyan - skylarkbj AT 163 DOT com - -% jlib.hrl -{"No resource provided", "无资源提供"}. - -% mod_offline_odbc.erl -{"Your contact offline message queue is full. The message has been discarded.", "您联系人的离线消息队列已满. 消息已被丢弃"}. - -% mod_configure.erl -{"Choose storage type of tables", "请选择表格的存储类型"}. -{"RAM copy", "内存(RAM)复制"}. -{"RAM and disc copy", "内存与磁盘复制"}. -{"Disc only copy", "仅复制磁盘"}. -{"Remote copy", "远程复制"}. -{"Stop Modules at ", "要停止的模块位于 "}. -{"Choose modules to stop", "请选择要停止的模块"}. -{"Start Modules at ", "要启动的模块位于 "}. -{"Enter list of {Module, [Options]}", "请输入{模块, [选项]}列表"}. -{"List of modules to start", "要启动的模块列表"}. -{"Backup to File at ", "将文件备份到"}. -{"Enter path to backup file", "请输入备份文件的路径"}. -{"Path to File", "文件路径"}. -{"Restore Backup from File at ", "要恢复的备份文件位于"}. -{"Dump Backup to Text File at ", "转储备份到文本文件于"}. -{"Enter path to text file", "请输入文本文件的路径"}. -{"Import User from File at ", "导入用户的文件位于 "}. -{"Enter path to jabberd1.4 spool file", "请输入jabberd1.4 spool文件的路径"}. -{"Import Users from Dir at ", "导入用户的目录位于 "}. -{"Enter path to jabberd1.4 spool dir", "请输入jabberd1.4 spool目录的路径"}. -{"Path to Dir", "目录的路径"}. -{"Access Control List Configuration", "访问控制列表(ACL)配置"}. -{"Access control lists", "访问控制列表(ACL)"}. -{"Access Configuration", "访问配置"}. -{"Access rules", "访问规则"}. -{"Administration of ", "管理"}. -{"Action on user", "对用户的动作"}. -{"Edit Properties", "编辑属性"}. -{"Remove User", "删除用户"}. -{"Database", "数据库"}. -{"Outgoing s2s Connections", "出站s2s连接"}. -{"Import Users From jabberd 1.4 Spool Files", "从Jabberd 1.4 Spool文件导入用户"}. -{"Database Tables Configuration at ", "数据库表格配置位于"}. -{"Restart Service", "重启服务"}. -{"Shut Down Service", "关闭服务"}. -{"Delete User", "删除用户"}. -{"End User Session", "结束用户会话"}. -{"Get User Password", "获取用户密码"}. -{"Change User Password", "更改用户密码"}. -{"Get User Last Login Time", "获取用户上次登陆时间"}. -{"Get User Statistics", "获取用户统计"}. -{"Get Number of Registered Users", "获取注册用户数"}. -{"Get Number of Online Users", "获取在线用户数"}. -{"User Management", "用户管理"}. -{"Time delay", "时间延迟"}. -{"Password Verification", "确认密码"}. -{"Number of registered users", "注册用户数"}. -{"Number of online users", "在线用户数"}. -{"Last login", "上次登陆"}. -{"Roster size", "花名册大小"}. -{"IP addresses", "IP地址"}. -{"Resources", "资源"}. - -% src/ejabberd_c2s.erl -{"Use of STARTTLS required", "要求使用STARTTLS"}. -{"Replaced by new connection", "被新的连接替换"}. - -% mod_disco.erl -{"Configuration", "配 置"}. -{"Online Users", "在线用户"}. -{"All Users", "所有用户"}. -{"To ~s", "发送给~s"}. -{"From ~s", "来自~s"}. -{"Running Nodes", "正在运行的节点"}. -{"Stopped Nodes", "已经停止的节点"}. -{"Access Control Lists", "访问控制列表(ACL)"}. -{"Access Rules", "访问规则"}. -{"Modules", "模块"}. -{"Start Modules", "启动模块"}. -{"Stop Modules", "停止模块"}. -{"Backup Management", "备份管理"}. -{"Backup", "备份"}. -{"Restore", "恢复"}. -{"Dump to Text File", "转储到文本文件"}. -{"Import File", "导入文件"}. -{"Import Directory", "导入目录"}. - -% mod_register.erl -{"Choose a username and password to register with this server", "请选择在此服务器上注册所需的用户名和密码"}. - -% src/mod_vcard_ldap.erl -{"Erlang Jabber Server", "Erlang Jabber 服务器"}. -{"ejabberd vCard module", "ejabberd vCard 模块"}. -{"Email", "电子邮件"}. -{"Search Results for ", "搜索结果属于关键词 "}. -{"Jabber ID", "Jabber ID"}. - -% mod_vcard.erl -{"You need an x:data capable client to search", "您需要一个兼容x:data的客户端来搜索"}. -{"Search users in ", "要搜索的用户位于 "}. - -{"Fill in fields to search for any matching Jabber User", "填充字段以搜索任何匹配的Jabber用户"}. -{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)", "填充表单以搜索任何匹配的Jabber用户(在字段末添加*来匹配子串)"}. - -{"User", "用户"}. -{"Full Name", "全名"}. -{"Name", "名字"}. -{"Middle Name", "中间名"}. -{"Family Name", "姓氏"}. -{"Nickname", "昵称"}. -{"Birthday", "出生日期"}. -{"Country", "国家"}. -{"City", "城市"}. -{"Organization Name", "组织名称"}. -{"Organization Unit", "组织单位"}. - -% mod_adhoc.erl -{"Commands", "命令"}. -{"Ping", "Ping"}. -{"Pong", "Pong"}. - -% mod_announce.erl -{"Really delete message of the day?", "确实要删除当日的消息吗?"}. -{"Subject", "标题"}. -{"Message body", "消息主体"}. -{"No body provided for announce message", "没有人提供通知消息"}. -{"Announcements", "通知"}. -{"Send announcement to all users", "将通知发送给所有用户"}. -{"Send announcement to all online users", "将通知发送给所有在线用户"}. -{"Send announcement to all online users on all hosts", "将通知发送给所有主机的所有用户"}. -{"Set message of the day and send to online users", "设定当日消息并发送给所有在线用户"}. -{"Update message of the day (don't send)", "更新当日的消息(不发送)"}. -{"Delete message of the day", "删除当日的消息"}. -{"Send announcement to all users on all hosts", "给所有主机上的所有用户发送通知"}. -{"Set message of the day on all hosts and send to online users", "设置当日所有主机上 的消息并发送给在线用户"}. -{"Update message of the day on all hosts (don't send)", "更新当日所有主机上 的消息(不发送)"}. -{"Delete message of the day on all hosts", "删除当日所有主机上 的消息"}. - -% mod_pubsub/mod_pubsub.erl -{"Roster groups allowed to subscribe", "允许订阅的花名册组"}. -{"Publish-Subscribe", "发布-订阅"}. -{"Deliver payloads with event notifications", "用事件通告传输有效负载"}. -{"Notify subscribers when the node configuration changes", "当节点设置改变时通知订阅人"}. -{"Notify subscribers when the node is deleted", "当节点被删除时通知订阅人"}. -{"Notify subscribers when items are removed from the node", "当从节点删除条款时通知订阅人"}. -{"Persist items to storage", "要存储的持续条款"}. -{"Max # of items to persist", "最多持有条款数"}. -{"Whether to allow subscriptions", "是否允许订阅"}. -{"Specify the publisher model", "指定发布人样式"}. -{"Max payload size in bytes", "最大有效负载比特数"}. -{"Only deliver notifications to available users", "仅将通知发送给可发送的用户"}. -{"ejabberd Publish-Subscribe module", "ejabberd发行-订阅模块"}. -{"PubSub subscriber request", "PubSub订阅人请求"}. -{"Choose whether to approve this entity's subscription.", "选择是否赞成该实体的订阅"}. -{"Node ID", "节点ID"}. -{"Subscriber Address", "订阅人地址"}. -{"Allow this JID to subscribe to this pubsub node?", "允许该JID订阅该pubsub节点?"}. -{"Deliver event notifications", "传递事件通知"}. -{"Specify the access model", "指定访问模式"}. -{"When to send the last published item", "何时发送最新公布的条款"}. - -% mod_muc/mod_muc_log.erl -{"has been kicked because of an affiliation change", "已经因联属关系改变而被踢出"}. -{"has been kicked because the room has been changed to members-only", "已经因该房间已被改为只对会员开放而被踢出"}. -{"has been kicked because of a system shutdown", "已经因系统关机而被踢出"}. -{"Chatroom configuration modified", "聊天室配置已修改"}. -{"joins the room", "加入房间"}. -{"leaves the room", "离开房间"}. -{"has been kicked", "已被踢出"}. -{"has been banned", "已被禁止"}. -{"is now known as", "现在称呼为"}. -{"Monday", "星期一"}. -{"Tuesday", "星期二"}. -{"Wednesday", "星期三"}. -{"Thursday", "星期四"}. -{"Friday", "星期五"}. -{"Saturday", "星期六"}. -{"Sunday", "星期天"}. -{"January", "一月"}. -{"February", "二月"}. -{"March", "三月"}. -{"April", "四月"}. -{"May", "五月"}. -{"June", "六月"}. -{"July", "七月"}. -{"August", "八月"}. -{"September", "九月"}. -{"October", "十月"}. -{"November", "十一月"}. -{"December", "十二月"}. -{"Room Configuration", "房间配置"}. - -% mod_muc/mod_muc.erl -{"You need an x:data capable client to register nickname", "您需要一个兼容x:data的客户端来注册昵称"}. -{"Nickname Registration at ", "昵称注册于 "}. -{"Enter nickname you want to register", "请输入您想要注册的昵称"}. -{"ejabberd MUC module", "ejabberd MUC模块"}. -{"Only service administrators are allowed to send service messages", "只有服务管理员可以发送服务消息"}. -{"Room creation is denied by service policy", "创建房间被服务政策拒绝"}. -{"Conference room does not exist", "会议室不存在"}. -{"Access denied by service policy", "访问被服务政策拒绝"}. -{"Specified nickname is already registered", "指定的名称已被注册"}. -{"You must fill in field \"Nickname\" in the form", "您必须填充表单中\"昵称\"项"}. -{"Chatrooms", "聊天室"}. - -% mod_muc/mod_muc_room.erl -{"Make room moderated", "使房间处于监管状态"}. -{"This participant is kicked from the room because he sent an error message", "该用户由于发生了错误而被踢出了聊天室"}. -{"This participant is kicked from the room because he sent an error message to another participant", "该用户由于给其他人发送了出错信息而被踢出了聊天室"}. -{"This participant is kicked from the room because he sent an error presence", "该用户由于状态信息错误而被踢出了聊天室"}. -{"Traffic rate limit is exceeded", "已经超过传输率限制"}. -{"Maximum Number of Occupants", "占有人最大数"}. -{"No limit", "不限"}. -{"~s invites you to the room ~s", "~s邀请你到~s房间"}. -{"the password is", "密码是"}. -{" has set the subject to: ", "已将标题设置为: "}. -{"You need an x:data capable client to configure room", "您需要一个兼容x:data的客户端来配置房间"}. -{"Configuration for ", "配置 "}. -{"Room title", "房间标题"}. -{"Password", "密码"}. -{"Only moderators and participants are allowed to change subject in this room", "只允许调解人和参与人更改此房间的主题"}. -{"Only moderators are allowed to change subject in this room", "只允许调解人更改此房间的主题"}. -{"Visitors are not allowed to send messages to all occupants", "不允许访客给所有占有者发送消息"}. -{"Only occupants are allowed to send messages to the conference", "只允许占有者向会议发送消息"}. -{"It is not allowed to send private messages to the conference", "不允许向会议发送隐私消息"}. -{"Improper message type", "消息类型不恰当"}. -{"Nickname is already in use by another occupant", "昵称已被另一用户占用"}. -{"Nickname is registered by another person", "昵称已被另一人注册"}. -{"It is not allowed to send private messages of type \"groupchat\"", "\"群组聊天\"类型是不允许发送隐私消息的"}. -{"Recipient is not in the conference room", "接收人不在会议室"}. -{"Only occupants are allowed to send queries to the conference", "只允许占有者向大会询问"}. -{"Queries to the conference members are not allowed in this room", "本房间不允许向大会成员询问"}. -{"You have been banned from this room", "您已被禁止进入该房间"}. -{"Membership required to enter this room", "进入此房间需要会员身份"}. -{"Password required to enter this room", "进入此房间需要密码"}. -{"Incorrect password", "密码不正确"}. -{"Administrator privileges required", "需要管理员权限"}. -{"Moderator privileges required", "需要调解人权限"}. -{"JID ~s is invalid", "JID ~s无效"}. -{"Nickname ~s does not exist in the room", "昵称~s不在该房间"}. -{"Invalid affiliation: ~s", "无效加入: ~s"}. -{"Invalid role: ~s", "无效角色: ~s"}. -{"Owner privileges required", "需要持有人权限"}. -{"private, ", "保密"}. -{"This room is not anonymous", "此房间不是匿名房间"}. -{"Make room persistent", "持续开放房间"}. -{"Make room public searchable", "使房间可被公开搜索"}. -{"Make participants list public", "公开参与人列表"}. -{"Make room password protected", "保护房间密码"}. -{"Make room members-only", "设置房间只接收会员"}. -{"Default users as participants", "将默认用户视为参与人"}. -{"Allow users to change subject", "允许用户更改主题"}. -{"Allow users to send private messages", "允许用户发送隐私消息"}. -{"Allow users to query other users", "允许用户查询其它用户"}. -{"Allow users to send invites", "允许用户发送邀请"}. -{"Enable logging", "允许使用日志"}. -{"Number of occupants", "占用人数"}. -{"Present real JIDs to", "将真实JID显示给"}. -{"moderators only", "仅一般人"}. -{"anyone", "任何人"}. - -% mod_irc/mod_irc.erl -{"ejabberd IRC module", "ejabberd IRC 模块"}. -{"You need an x:data capable client to configure mod_irc settings", "您需要一个兼容x:data的客户端来配置mod_irc设置"}. -{"Registration in mod_irc for ", "mod_irc中的注册是为 "}. -{"Enter username and encodings you wish to use for connecting to IRC servers", "请输入您想使用的用来连接到IRC服务器的用户名和编码"}. -{"IRC Username", "IRC用户名"}. -{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.", "如果您想为IRC服务器指定不同的编码, 请用'{\"irc 服务器\", \"编码\"}'格式的值填充此表单. 默认情况下此服务使用\"~s\"编码."}. -{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].", "例如: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. -{"Encodings", "编码"}. -{"IRC Transport", "IRC传输"}. - -% web/ejabberd_web_admin.erl -{"ejabberd Web Admin", "ejabberd网页管理"}. -{"Administration", "管理"}. -{"Users", "用户"}. -{"Nodes", "节点"}. -{"Statistics", "统计"}. -{"(Raw)", "(原始格式)"}. -{"Submitted", "已提交"}. -{"Bad format", "格式错误"}. -{"Raw", "原始格式"}. -{"Delete Selected", "删除已选内容"}. -{"Submit", "提交"}. -{"~s access rule configuration", "~s访问规则配置"}. -{"Node not found", "没有找到节点"}. -{"Add New", "添加新用户"}. -{"Registered Users", "注册用户"}. -{"Registered Users:", "注册用户:"}. -{"Change Password", "更改密码"}. -{"Connected Resources:", "已连接资源"}. -{"Password:", "密码:"}. -{"None", "无"}. -{"Node ", "节点 "}. -{"Listened Ports", "监听端口"}. -{"Restart", "重启"}. -{"Stop", "停止"}. -{"RPC Call Error", "RPC调用错误"}. -{"Name", "名称"}. -{"Storage Type", "存储类型"}. -{"Size", "大小"}. -{"Memory", "内存"}. -{"OK", "OK"}. -{"Listened Ports at ", "监听的端口位于 "}. -{"Uptime:", "正常运行时间:"}. -{"CPU Time:", "CPU时间:"}. -{"Transactions Commited:", "要提交的事务:"}. -{"Transactions Aborted:", "要取消的事务:"}. -{"Transactions Restarted:", "要重启的事务:"}. -{"Transactions Logged:", "要记入日志的事务:"}. -{"Port", "端口"}. -{"Module", "模块"}. -{"Options", "选项"}. -{"Update", "更新"}. -{"Delete", "删除"}. -{"Add User", "添加用户"}. -{"Offline Messages", "离线消息"}. -{"Users Last Activity", "用户上次活动"}. -{"Never", "从未"}. -{"~s's Offline Messages Queue", "~s的离线消息队列"}. -{"Time", "时间"}. -{"From", "从"}. -{"To", "到"}. -{"Packet", "数据包"}. -{"Offline Messages:", "离线消息:"}. -{"Roster", "花名册"}. -{"Nickname", "昵称"}. -{"Subscription", "订阅"}. -{"Pending", "待审"}. -{"Groups", "组"}. -{"Remove", "移除"}. -{"Add Jabber ID", "添加Jabber ID"}. -{"User ", "用户 "}. -{"Roster of ", "花名册属于 "}. -{"Online", "在线"}. -{"Validate", "确认"}. -{"Name:", "名称:"}. -{"Description:", "描述:"}. -{"Members:", "会员:"}. -{"Displayed Groups:", "已显示的组:"}. -{"Group ", "组"}. -{"Period: ", "持续时间:"}. -{"Last month", "上个月"}. -{"Last year", "上一年"}. -{"All activity", "所有活动"}. -{"Show Ordinary Table", "显示普通列表"}. -{"Show Integral Table", "显示完整列表"}. -{"Modules at ", "模块位于 "}. -{"Start", "开始"}. -{"Virtual Hosts", "虚拟主机"}. -{"ejabberd virtual hosts", "ejabberd虚拟主机"}. -{"Host", "主机"}. -{"No Data", "没有数据"}. -{"Online Users:", "在线用户:"}. -{"Outgoing s2s Connections:", "出站s2s连接:"}. -{"Outgoing s2s Servers:", "出站s2s服务器"}. -{"Database Tables at ", "数据库列表位于 "}. -{"Backup of ", "备份来源 "}. -{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.", "注意:这些选项仅将备份内置的Mnesia数据库. 如果您在使用ODBC模块, 您还需要分别备份您的数据库."}. -{"Store binary backup:", "存储为二进制备份:"}. -{"Restore binary backup immediately:", "立即恢复二进制备份:"}. -{"Restore binary backup after next ejabberd restart (requires less memory):", "在下次ejabberd重启后恢复二进制备份(需要的内存更少):"}. -{"Store plain text backup:", "存储为普通文本备份:"}. -{"Restore plain text backup immediately:", "立即恢复普通文本备份:"}. -{"Statistics of ~p", "~p的统计"}. -{"Update ", "更新 "}. -{"Update plan", "更新计划"}. -{"Updated modules", "更新模块"}. -{"Update script", "更新脚本"}. -{"Low level update script", "低级别更新脚本"}. -{"Script check", "检查脚本"}. -{"Shared Roster Groups", "共享的花名册组群"}. -{"Last Activity", "上次活动"}. - -% mod_proxy65/mod_proxy65_service.erl -{"ejabberd SOCKS5 Bytestreams module", "ejabberd SOCKS5字节流模块"}. - -% mod_vcard_odbc.erl -{"vCard User Search", "vCard用户搜索"}. - -% Local Variables: -% mode: erlang -% End: -% vim: set filetype=erlang tabstop=8: +{"Access Configuration","访问配置"}. +{"Access Control List Configuration","访问控制列表(ACL)配置"}. +{"Access control lists","访问控制列表(ACL)"}. +{"Access Control Lists","访问控制列表(ACL)"}. +{"Access denied by service policy","访问被服务策略拒绝"}. +{"Access rules","访问规则"}. +{"Access Rules","访问规则"}. +{"Action on user","对用户的动作"}. +{"Add Jabber ID","添加Jabber ID"}. +{"Add New","添加新用户"}. +{"Add User","添加用户"}. +{"Administration of ","管理"}. +{"Administration","管理"}. +{"Administrator privileges required","需要管理员权限"}. +{"A friendly name for the node","该节点的友好名称"}. +{"All activity","所有活动"}. +{"Allow this JID to subscribe to this pubsub node?","允许该JID订阅该pubsub节点?"}. +{"Allow users to change subject","允许用户更改主题"}. +{"Allow users to query other users","允许用户查询其它用户"}. +{"Allow users to send invites","允许用户发送邀请"}. +{"Allow users to send private messages","允许用户发送私聊消息"}. +{"Allow visitors to change nickname","允许用户更改昵称"}. +{"Allow visitors to send status text in presence updates","更新在线状态时允许用户发送状态文本"}. +{"All Users","所有用户"}. +{"Announcements","通知"}. +{"anyone","任何人"}. +{"April","四月"}. +{"August","八月"}. +{"Backup Management","备份管理"}. +{"Backup of ","备份来源 "}. +{"Backup to File at ","备份到文件位于"}. +{"Backup","备份"}. +{"Bad format","格式错误"}. +{"Birthday","出生日期"}. +{"Change Password","更改密码"}. +{"Change User Password","更改用户密码"}. +{"Chatroom configuration modified","聊天室配置已修改"}. +{"Chatrooms","聊天室"}. +{"Choose a username and password to register with this server","请选择在此服务器上注册所需的用户名和密码"}. +{"Choose modules to stop","请选择要停止的模块"}. +{"Choose storage type of tables","请选择表格的存储类型"}. +{"Choose whether to approve this entity's subscription.","选择是否允许该实体的订阅"}. +{"City","城市"}. +{"Commands","命令"}. +{"Conference room does not exist","会议室不存在"}. +{"Configuration for ","配置 "}. +{"Configuration","配 置"}. +{"Connected Resources:","已连接资源"}. +{"Country","国家"}. +{"CPU Time:","CPU时间:"}. +{"Database Tables at ","数据库列表位于 "}. +{"Database Tables Configuration at ","数据库表格配置位于"}. +{"Database","数据库"}. +{"December","十二月"}. +{"Default users as participants","将默认用户视为参与人"}. +{"Delete message of the day on all hosts","删除所有主机上的每日消息"}. +{"Delete message of the day","删除每日消息"}. +{"Delete Selected","删除已选内容"}. +{"Delete User","删除用户"}. +{"Delete","删除"}. +{"Deliver event notifications","传递事件通知"}. +{"Deliver payloads with event notifications","用事件通告传输有效负载"}. +{"Description:","描述:"}. +{"Disc only copy","仅磁盘复制"}. +{"Displayed Groups:","已显示的组:"}. +{"Dump Backup to Text File at ","转储备份到文本文件于"}. +{"Dump to Text File","转储到文本文件"}. +{"Edit Properties","编辑属性"}. +{"ejabberd IRC module","ejabberd IRC 模块"}. +{"ejabberd MUC module","ejabberd MUC模块"}. +{"ejabberd Publish-Subscribe module","ejabberd发行-订阅模块"}. +{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5字节流模块"}. +{"ejabberd vCard module","ejabberd vCard 模块"}. +{"ejabberd virtual hosts","ejabberd虚拟主机"}. +{"ejabberd Web Admin","ejabberd网页管理"}. +{"Email","电子邮件"}. +{"Enable logging","启用服务器端聊天记录"}. +{"Encodings","编码"}. +{"End User Session","结束用户会话"}. +{"Enter list of {Module, [Options]}","请输入{模块, [选项]}列表"}. +{"Enter nickname you want to register","请输入您想要注册的昵称"}. +{"Enter path to backup file","请输入备份文件的路径"}. +{"Enter path to jabberd1.4 spool dir","请输入jabberd1.4 spool目录的路径"}. +{"Enter path to jabberd1.4 spool file","请输入jabberd1.4 spool文件的路径"}. +{"Enter path to text file","请输入文本文件的路径"}. +{"Enter username and encodings you wish to use for connecting to IRC servers","请输入您想使用的用来连接到IRC服务器的用户名和编码"}. +{"Erlang Jabber Server","Erlang Jabber 服务器"}. +{"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}].","例如: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1\"}]."}. +{"Family Name","姓氏"}. +{"February","二月"}. +{"Fill in fields to search for any matching Jabber User","填充字段以搜索任何匹配的Jabber用户"}. +{"Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)","填充表单以搜索任何匹配的Jabber用户(在字段末添加*来匹配子串)"}. +{"Friday","星期五"}. +{"From ~s","来自~s"}. +{"From","从"}. +{"Full Name","全名"}. +{"Get Number of Online Users","获取在线用户数"}. +{"Get Number of Registered Users","获取注册用户数"}. +{"Get User Last Login Time","获取用户上次登陆时间"}. +{"Get User Password","获取用户密码"}. +{"Get User Statistics","获取用户统计"}. +{"Groups","组"}. +{"Group ","组"}. +{"has been banned","已被禁止"}. +{"has been kicked because of an affiliation change","因联属关系改变而被踢出"}. +{"has been kicked because of a system shutdown","因系统关机而被踢出"}. +{"has been kicked because the room has been changed to members-only","因该房间改为只对会员开放而被踢出"}. +{"has been kicked","已被踢出"}. +{" has set the subject to: ","已将标题设置为: "}. +{"Host","主机"}. +{"If you want to specify different encodings for IRC servers, fill this list with values in format '{\"irc server\", \"encoding\"}'. By default this service use \"~s\" encoding.","如果您想为IRC服务器指定不同的编码, 请用'{\"irc 服务器\", \"编码\"}'格式的值填充此表单. 默认情况下此服务使用\"~s\"编码."}. +{"Import Directory","导入目录"}. +{"Import File","导入文件"}. +{"Import User from File at ","导入用户的文件位于 "}. +{"Import Users from Dir at ","导入用户的目录位于 "}. +{"Import Users From jabberd 1.4 Spool Files","从Jabberd 1.4 Spool文件导入用户"}. +{"Improper message type","消息类型不恰当"}. +{"Incorrect password","密码不正确"}. +{"Invalid affiliation: ~s","无效加入: ~s"}. +{"Invalid role: ~s","无效角色: ~s"}. +{"IP addresses","IP地址"}. +{"IRC Transport","IRC传输"}. +{"IRC Username","IRC用户名"}. +{"is now known as","现在称呼为"}. +{"It is not allowed to send private messages of type \"groupchat\"","\"群组聊天\"类型不允许发送私聊消息"}. +{"It is not allowed to send private messages to the conference","不允许向会议发送私聊消息"}. +{"It is not allowed to send private messages","不允许发送私聊消息"}. +{"Jabber ID","Jabber ID"}. +{"January","一月"}. +{"JID ~s is invalid","JID ~s无效"}. +{"joins the room","加入房间"}. +{"July","七月"}. +{"June","六月"}. +{"Last Activity","上次活动"}. +{"Last login","上次登陆"}. +{"Last month","上个月"}. +{"Last year","上一年"}. +{"leaves the room","离开房间"}. +{"Listened Ports at ","监听的端口位于 "}. +{"Listened Ports","监听端口"}. +{"List of modules to start","要启动的模块列表"}. +{"Low level update script","低级别更新脚本"}. +{"Make participants list public","公开参与人列表"}. +{"Make room members-only","设置房间只接收会员"}. +{"Make room moderated","使房间处于监管状态"}. +{"Make room password protected","保护房间密码"}. +{"Make room persistent","在服务器端保存该房间"}. +{"Make room public searchable","使房间可被公开搜索"}. +{"March","三月"}. +{"Maximum Number of Occupants","占有人最大数"}. +{"Max # of items to persist","允许持久化的最大内容条目数"}. +{"Max payload size in bytes","最大有效负载比特数"}. +{"May","五月"}. +{"Membership required to enter this room","进入此房间需要会员身份"}. +{"Members:","会员:"}. +{"Memory","内存"}. +{"Message body","消息主体"}. +{"Middle Name","中间名"}. +{"Moderator privileges required","需要调解人权限"}. +{"moderators only","仅一般人"}. +{"Modules at ","模块位于 "}. +{"Modules","模块"}. +{"Module","模块"}. +{"Monday","星期一"}. +{"Name:","名称:"}. +{"Name","名称"}. +{"Never","从未"}. +{"Nickname is already in use by another occupant","昵称已被另一用户占用"}. +{"Nickname is registered by another person","昵称已被另一人注册"}. +{"Nickname Registration at ","昵称注册于 "}. +{"Nickname ~s does not exist in the room","昵称~s不在该房间"}. +{"Nickname","昵称"}. +{"No body provided for announce message","通知消息无正文内容"}. +{"No Data","没有数据"}. +{"Node ID","节点ID"}. +{"Node not found","没有找到节点"}. +{"Nodes","节点"}. +{"Node ","节点 "}. +{"No limit","不限"}. +{"None","无"}. +{"No resource provided","无资源提供"}. +{"Notify subscribers when items are removed from the node","当从节点删除内容条目时通知订阅人"}. +{"Notify subscribers when the node configuration changes","当节点设置改变时通知订阅人"}. +{"Notify subscribers when the node is deleted","当节点被删除时通知订阅人"}. +{"November","十一月"}. +{"Number of occupants","占用人数"}. +{"Number of online users","在线用户数"}. +{"Number of registered users","注册用户数"}. +{"October","十月"}. +{"Offline Messages:","离线消息:"}. +{"Offline Messages","离线消息"}. +{"OK","OK"}. +{"Online Users:","在线用户:"}. +{"Online Users","在线用户"}. +{"Online","在线"}. +{"Only deliver notifications to available users","仅将通知发送给可发送的用户"}. +{"Only moderators and participants are allowed to change subject in this room","只允许监管人和参与人更改此房间的主题"}. +{"Only moderators are allowed to change subject in this room","只允许监管人更改此房间的主题"}. +{"Only occupants are allowed to send messages to the conference","只允许占有者向会议发送消息"}. +{"Only occupants are allowed to send queries to the conference","只允许占有者发出查询请求"}. +{"Only service administrators are allowed to send service messages","只有服务管理员可以发送服务消息"}. +{"Options","选项"}. +{"Organization Name","组织名称"}. +{"Organization Unit","组织单位"}. +{"Outgoing s2s Connections:","出站s2s连接:"}. +{"Outgoing s2s Connections","出站s2s连接"}. +{"Outgoing s2s Servers:","出站s2s服务器"}. +{"Owner privileges required","需要持有人权限"}. +{"Packet","数据包"}. +{"Password required to enter this room","进入此房间需要密码"}. +{"Password Verification","确认密码"}. +{"Password:","密码:"}. +{"Password","密码"}. +{"Path to Dir","目录的路径"}. +{"Path to File","文件路径"}. +{"Pending","挂起"}. +{"Period: ","持续时间:"}. +{"Persist items to storage","持久化内容条目"}. +{"Ping","Ping"}. +{"Pong","Pong"}. +{"Port","端口"}. +{"Present real JIDs to","将真实JID显示给"}. +{"private, ","保密"}. +{"Publish-Subscribe","发布-订阅"}. +{"PubSub subscriber request","PubSub订阅人请求"}. +{"Queries to the conference members are not allowed in this room","本房间不允许发出成员查询请求"}. +{"RAM and disc copy","内存与磁盘复制"}. +{"RAM copy","内存(RAM)复制"}. +{"(Raw)","(原始格式)"}. +{"Raw","原始格式"}. +{"Really delete message of the day?","确实要删除每日消息吗?"}. +{"Recipient is not in the conference room","接收人不在会议室"}. +{"Registered Users:","注册用户:"}. +{"Registered Users","注册用户"}. +{"Registration in mod_irc for ","mod_irc中的注册是为 "}. +{"Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately.","注意:这些选项仅将备份内置的Mnesia数据库. 如果您在使用ODBC模块, 您还需要分别备份您的数据库."}. +{"Remote copy","远程复制"}. +{"Remove User","删除用户"}. +{"Remove","移除"}. +{"Replaced by new connection","被新的连接替换"}. +{"Resources","资源"}. +{"Restart Service","重启服务"}. +{"Restart","重启"}. +{"Restore Backup from File at ","要恢复的备份文件位于"}. +{"Restore binary backup after next ejabberd restart (requires less memory):","在下次ejabberd重启后恢复二进制备份(需要的内存更少):"}. +{"Restore binary backup immediately:","立即恢复二进制备份:"}. +{"Restore plain text backup immediately:","立即恢复普通文本备份:"}. +{"Restore","恢复"}. +{"Room Configuration","房间配置"}. +{"Room creation is denied by service policy","创建房间被服务策略拒绝"}. +{"Room title","房间标题"}. +{"Roster groups allowed to subscribe","允许订阅的花名册组"}. +{"Roster of ","花名册属于 "}. +{"Roster size","花名册大小"}. +{"Roster","花名册"}. +{"RPC Call Error","RPC调用错误"}. +{"Running Nodes","正在运行的节点"}. +{"~s access rule configuration","~s访问规则配置"}. +{"Saturday","星期六"}. +{"Script check","检查脚本"}. +{"Search Results for ","搜索结果属于关键词 "}. +{"Search users in ","要搜索的用户位于 "}. +{"Send announcement to all online users on all hosts","将通知发送给所有主机的所有用户"}. +{"Send announcement to all online users","将通知发送给所有在线用户"}. +{"Send announcement to all users on all hosts","给所有主机上的所有用户发送通知"}. +{"Send announcement to all users","将通知发送给所有用户"}. +{"September","九月"}. +{"Set message of the day and send to online users","设定每日消息并发送给所有在线用户"}. +{"Set message of the day on all hosts and send to online users","设置所有主机上的每日消息并发送给在线用户"}. +{"Shared Roster Groups","共享的花名册组群"}. +{"Show Integral Table","显示完整列表"}. +{"Show Ordinary Table","显示普通列表"}. +{"Shut Down Service","关闭服务"}. +{"~s invites you to the room ~s","~s邀请你到~s房间"}. +{"Size","大小"}. +{"Specified nickname is already registered","指定的名称已被注册"}. +{"Specify the access model","指定访问模式"}. +{"Specify the publisher model","指定发布人样式"}. +{"~s's Offline Messages Queue","~s的离线消息队列"}. +{"Start Modules at ","要启动的模块位于 "}. +{"Start Modules","启动模块"}. +{"Start","开始"}. +{"Statistics of ~p","~p的统计"}. +{"Statistics","统计"}. +{"Stop Modules at ","要停止的模块位于 "}. +{"Stop Modules","停止模块"}. +{"Stopped Nodes","已经停止的节点"}. +{"Stop","停止"}. +{"Storage Type","存储类型"}. +{"Store binary backup:","存储为二进制备份:"}. +{"Store plain text backup:","存储为普通文本备份:"}. +{"Subject","标题"}. +{"Submitted","已提交"}. +{"Submit","提交"}. +{"Subscriber Address","订阅人地址"}. +{"Subscription","订阅"}. +{"Sunday","星期天"}. +{"the password is","密码是"}. +{"This participant is kicked from the room because he sent an error message to another participant","该用户由于给其他人发送了出错信息而被踢出了聊天室"}. +{"This participant is kicked from the room because he sent an error message","该用户由于发生了错误而被踢出了聊天室"}. +{"This participant is kicked from the room because he sent an error presence","该用户由于状态信息错误而被踢出了聊天室"}. +{"This room is not anonymous","此房间不是匿名房间"}. +{"Thursday","星期四"}. +{"Time delay","时间延迟"}. +{"Time","时间"}. +{"To ~s","发送给~s"}. +{"To","到"}. +{"Traffic rate limit is exceeded","已经超过传输率限制"}. +{"Transactions Aborted:","取消的事务:"}. +{"Transactions Commited:","提交的事务:"}. +{"Transactions Logged:","记入日志的事务:"}. +{"Transactions Restarted:","重启的事务:"}. +{"Tuesday","星期二"}. +{"Updated modules","更新模块"}. +{"Update message of the day (don't send)","更新每日消息(不发送)"}. +{"Update message of the day on all hosts (don't send)","更新所有主机上的每日消息(不发送)"}. +{"Update plan","更新计划"}. +{"Update script","更新脚本"}. +{"Update ","更新 "}. +{"Update","更新"}. +{"Uptime:","正常运行时间:"}. +{"Use of STARTTLS required","要求使用STARTTLS"}. +{"User Management","用户管理"}. +{"Users are not allowed to register accounts so fast","不允许用户注册帐户太快"}. +{"Users Last Activity","用户上次活动"}. +{"Users","用户"}. +{"User ","用户 "}. +{"User","用户"}. +{"Validate","确认"}. +{"vCard User Search","vCard用户搜索"}. +{"Virtual Hosts","虚拟主机"}. +{"Visitors are not allowed to change their nicknames in this room","此房间不允许用户更改昵称"}. +{"Visitors are not allowed to send messages to all occupants","不允许访客给所有占有者发送消息"}. +{"Wednesday","星期三"}. +{"When to send the last published item","何时发送最新发布的内容条目"}. +{"Whether to allow subscriptions","是否允许订阅"}. +{"You have been banned from this room","您已被禁止进入该房间"}. +{"You must fill in field \"Nickname\" in the form","您必须填充表单中\"昵称\"项"}. +{"You need an x:data capable client to configure mod_irc settings","您需要一个兼容x:data的客户端来配置mod_irc设置"}. +{"You need an x:data capable client to configure room","您需要一个兼容x:data的客户端来配置房间"}. +{"You need an x:data capable client to register nickname","您需要一个兼容x:data的客户端来注册昵称"}. +{"You need an x:data capable client to search","您需要一个兼容x:data的客户端来搜索"}. +{"Your contact offline message queue is full. The message has been discarded.","您的离线消息队列已满. 消息已被丢弃"}. diff --git a/src/msgs/zh.po b/src/msgs/zh.po new file mode 100644 index 000000000..91169c305 --- /dev/null +++ b/src/msgs/zh.po @@ -0,0 +1,1476 @@ +msgid "" +msgstr "" +"Project-Id-Version: 2.1.0-alpha\n" +"Last-Translator: Shelley Shyan - skylarkbj AT 163 DOT com\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Language: Chinese (中文)\n" +"X-Additional-Translator: Zhan Caibao - zhancaibao AT gmail DOT com\n" +"X-Additional-Translator: Mike Wang\n" + +#: ejabberd_c2s.erl:350 ejabberd_c2s.erl:651 +msgid "Use of STARTTLS required" +msgstr "要求使用STARTTLS" + +#: ejabberd_c2s.erl:434 +msgid "No resource provided" +msgstr "无资源提供" + +#: ejabberd_c2s.erl:1045 +msgid "Replaced by new connection" +msgstr "被新的连接替换" + +#: mod_adhoc.erl:95 mod_adhoc.erl:125 mod_adhoc.erl:143 mod_adhoc.erl:161 +msgid "Commands" +msgstr "命令" + +#: mod_adhoc.erl:149 mod_adhoc.erl:243 +msgid "Ping" +msgstr "Ping" + +#: mod_adhoc.erl:260 +msgid "Pong" +msgstr "Pong" + +#: mod_announce.erl:505 +msgid "Really delete message of the day?" +msgstr "确实要删除每日消息吗?" + +#: mod_announce.erl:513 mod_configure.erl:1034 mod_configure.erl:1079 +msgid "Subject" +msgstr "标题" + +#: mod_announce.erl:518 mod_configure.erl:1039 mod_configure.erl:1084 +msgid "Message body" +msgstr "消息主体" + +#: mod_announce.erl:598 +msgid "No body provided for announce message" +msgstr "通知消息无正文内容" + +#: mod_announce.erl:633 +msgid "Announcements" +msgstr "通知" + +#: mod_announce.erl:635 +msgid "Send announcement to all users" +msgstr "将通知发送给所有用户" + +#: mod_announce.erl:637 +msgid "Send announcement to all users on all hosts" +msgstr "给所有主机上的所有用户发送通知" + +#: mod_announce.erl:639 +msgid "Send announcement to all online users" +msgstr "将通知发送给所有在线用户" + +#: mod_announce.erl:641 mod_configure.erl:1029 mod_configure.erl:1074 +msgid "Send announcement to all online users on all hosts" +msgstr "将通知发送给所有主机的所有用户" + +#: mod_announce.erl:643 +msgid "Set message of the day and send to online users" +msgstr "设定每日消息并发送给所有在线用户" + +#: mod_announce.erl:645 +msgid "Set message of the day on all hosts and send to online users" +msgstr "设置所有主机上的每日消息并发送给在线用户" + +#: mod_announce.erl:647 +msgid "Update message of the day (don't send)" +msgstr "更新每日消息(不发送)" + +#: mod_announce.erl:649 +msgid "Update message of the day on all hosts (don't send)" +msgstr "更新所有主机上的每日消息(不发送)" + +#: mod_announce.erl:651 +msgid "Delete message of the day" +msgstr "删除每日消息" + +#: mod_announce.erl:653 +msgid "Delete message of the day on all hosts" +msgstr "删除所有主机上的每日消息" + +#: mod_configure.erl:114 mod_configure.erl:258 mod_configure.erl:280 +#: mod_configure.erl:453 +msgid "Configuration" +msgstr "配 置" + +#: mod_configure.erl:125 mod_configure.erl:531 web/ejabberd_web_admin.erl:1673 +msgid "Database" +msgstr "数据库" + +#: mod_configure.erl:127 mod_configure.erl:545 +msgid "Start Modules" +msgstr "启动模块" + +#: mod_configure.erl:129 mod_configure.erl:546 +msgid "Stop Modules" +msgstr "停止模块" + +#: mod_configure.erl:131 mod_configure.erl:554 web/ejabberd_web_admin.erl:1674 +msgid "Backup" +msgstr "备份" + +#: mod_configure.erl:133 mod_configure.erl:555 +msgid "Restore" +msgstr "恢复" + +#: mod_configure.erl:135 mod_configure.erl:556 +msgid "Dump to Text File" +msgstr "转储到文本文件" + +#: mod_configure.erl:137 mod_configure.erl:565 +msgid "Import File" +msgstr "导入文件" + +#: mod_configure.erl:139 mod_configure.erl:566 +msgid "Import Directory" +msgstr "导入目录" + +#: mod_configure.erl:141 mod_configure.erl:536 mod_configure.erl:1008 +msgid "Restart Service" +msgstr "重启服务" + +#: mod_configure.erl:143 mod_configure.erl:537 mod_configure.erl:1053 +msgid "Shut Down Service" +msgstr "关闭服务" + +#: mod_configure.erl:145 mod_configure.erl:473 mod_configure.erl:1148 +#: web/ejabberd_web_admin.erl:1338 +msgid "Add User" +msgstr "添加用户" + +#: mod_configure.erl:147 mod_configure.erl:474 mod_configure.erl:1170 +msgid "Delete User" +msgstr "删除用户" + +#: mod_configure.erl:149 mod_configure.erl:475 mod_configure.erl:1182 +msgid "End User Session" +msgstr "结束用户会话" + +#: mod_configure.erl:151 mod_configure.erl:476 mod_configure.erl:1194 +#: mod_configure.erl:1206 +msgid "Get User Password" +msgstr "获取用户密码" + +#: mod_configure.erl:153 mod_configure.erl:477 +msgid "Change User Password" +msgstr "更改用户密码" + +#: mod_configure.erl:155 mod_configure.erl:478 mod_configure.erl:1223 +msgid "Get User Last Login Time" +msgstr "获取用户上次登陆时间" + +#: mod_configure.erl:157 mod_configure.erl:479 mod_configure.erl:1235 +msgid "Get User Statistics" +msgstr "获取用户统计" + +#: mod_configure.erl:159 mod_configure.erl:480 +msgid "Get Number of Registered Users" +msgstr "获取注册用户数" + +#: mod_configure.erl:161 mod_configure.erl:481 +msgid "Get Number of Online Users" +msgstr "获取在线用户数" + +#: mod_configure.erl:163 mod_configure.erl:464 web/ejabberd_web_admin.erl:135 +#: web/ejabberd_web_admin.erl:190 web/ejabberd_web_admin.erl:605 +#: web/ejabberd_web_admin.erl:624 web/ejabberd_web_admin.erl:679 +#: web/ejabberd_web_admin.erl:722 +msgid "Access Control Lists" +msgstr "访问控制列表(ACL)" + +#: mod_configure.erl:165 mod_configure.erl:465 web/ejabberd_web_admin.erl:136 +#: web/ejabberd_web_admin.erl:191 web/ejabberd_web_admin.erl:607 +#: web/ejabberd_web_admin.erl:626 web/ejabberd_web_admin.erl:790 +#: web/ejabberd_web_admin.erl:828 +msgid "Access Rules" +msgstr "访问规则" + +#: mod_configure.erl:281 mod_configure.erl:454 +msgid "User Management" +msgstr "用户管理" + +#: mod_configure.erl:455 web/ejabberd_web_admin.erl:193 +#: web/ejabberd_web_admin.erl:629 web/ejabberd_web_admin.erl:905 +#: web/ejabberd_web_admin.erl:1275 +msgid "Online Users" +msgstr "在线用户" + +#: mod_configure.erl:456 +msgid "All Users" +msgstr "所有用户" + +#: mod_configure.erl:457 +msgid "Outgoing s2s Connections" +msgstr "出站s2s连接" + +#: mod_configure.erl:458 web/ejabberd_web_admin.erl:1644 +msgid "Running Nodes" +msgstr "正在运行的节点" + +#: mod_configure.erl:459 web/ejabberd_web_admin.erl:1646 +msgid "Stopped Nodes" +msgstr "已经停止的节点" + +#: mod_configure.erl:532 web/ejabberd_web_admin.erl:1690 +msgid "Modules" +msgstr "模块" + +#: mod_configure.erl:533 +msgid "Backup Management" +msgstr "备份管理" + +#: mod_configure.erl:534 +msgid "Import Users From jabberd 1.4 Spool Files" +msgstr "从Jabberd 1.4 Spool文件导入用户" + +#: mod_configure.erl:649 +msgid "To ~s" +msgstr "发送给~s" + +#: mod_configure.erl:667 +msgid "From ~s" +msgstr "来自~s" + +#: mod_configure.erl:864 +msgid "Database Tables Configuration at " +msgstr "数据库表格配置位于" + +#: mod_configure.erl:869 +msgid "Choose storage type of tables" +msgstr "请选择表格的存储类型" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Disc only copy" +msgstr "仅磁盘复制" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM and disc copy" +msgstr "内存与磁盘复制" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "RAM copy" +msgstr "内存(RAM)复制" + +#: mod_configure.erl:877 mod_configure.erl:879 +msgid "Remote copy" +msgstr "远程复制" + +#: mod_configure.erl:901 +msgid "Stop Modules at " +msgstr "要停止的模块位于 " + +#: mod_configure.erl:905 +msgid "Choose modules to stop" +msgstr "请选择要停止的模块" + +#: mod_configure.erl:920 +msgid "Start Modules at " +msgstr "要启动的模块位于 " + +#: mod_configure.erl:924 +msgid "Enter list of {Module, [Options]}" +msgstr "请输入{模块, [选项]}列表" + +#: mod_configure.erl:925 +msgid "List of modules to start" +msgstr "要启动的模块列表" + +#: mod_configure.erl:934 +msgid "Backup to File at " +msgstr "备份到文件位于" + +#: mod_configure.erl:938 mod_configure.erl:952 +msgid "Enter path to backup file" +msgstr "请输入备份文件的路径" + +#: mod_configure.erl:939 mod_configure.erl:953 mod_configure.erl:967 +#: mod_configure.erl:981 +msgid "Path to File" +msgstr "文件路径" + +#: mod_configure.erl:948 +msgid "Restore Backup from File at " +msgstr "要恢复的备份文件位于" + +#: mod_configure.erl:962 +msgid "Dump Backup to Text File at " +msgstr "转储备份到文本文件于" + +#: mod_configure.erl:966 +msgid "Enter path to text file" +msgstr "请输入文本文件的路径" + +#: mod_configure.erl:976 +msgid "Import User from File at " +msgstr "导入用户的文件位于 " + +#: mod_configure.erl:980 +msgid "Enter path to jabberd1.4 spool file" +msgstr "请输入jabberd1.4 spool文件的路径" + +#: mod_configure.erl:990 +msgid "Import Users from Dir at " +msgstr "导入用户的目录位于 " + +#: mod_configure.erl:994 +msgid "Enter path to jabberd1.4 spool dir" +msgstr "请输入jabberd1.4 spool目录的路径" + +#: mod_configure.erl:995 +msgid "Path to Dir" +msgstr "目录的路径" + +#: mod_configure.erl:1011 mod_configure.erl:1056 +msgid "Time delay" +msgstr "时间延迟" + +#: mod_configure.erl:1094 +msgid "Access Control List Configuration" +msgstr "访问控制列表(ACL)配置" + +#: mod_configure.erl:1098 +msgid "Access control lists" +msgstr "访问控制列表(ACL)" + +#: mod_configure.erl:1122 +msgid "Access Configuration" +msgstr "访问配置" + +#: mod_configure.erl:1126 +msgid "Access rules" +msgstr "访问规则" + +#: mod_configure.erl:1151 mod_configure.erl:1173 mod_configure.erl:1185 +#: mod_configure.erl:1197 mod_configure.erl:1209 mod_configure.erl:1226 +#: mod_configure.erl:1238 mod_configure.erl:1599 mod_configure.erl:1647 +#: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 +#: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 +msgid "Jabber ID" +msgstr "Jabber ID" + +#: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 +#: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 +#: web/ejabberd_web_admin.erl:1331 +msgid "Password" +msgstr "密码" + +#: mod_configure.erl:1161 +msgid "Password Verification" +msgstr "确认密码" + +#: mod_configure.erl:1252 +msgid "Number of registered users" +msgstr "注册用户数" + +#: mod_configure.erl:1266 +msgid "Number of online users" +msgstr "在线用户数" + +#: mod_configure.erl:1629 web/ejabberd_web_admin.erl:1397 +msgid "Never" +msgstr "从未" + +#: mod_configure.erl:1643 web/ejabberd_web_admin.erl:1411 +msgid "Online" +msgstr "在线" + +#: mod_configure.erl:1648 +msgid "Last login" +msgstr "上次登陆" + +#: mod_configure.erl:1668 +msgid "Roster size" +msgstr "花名册大小" + +#: mod_configure.erl:1669 +msgid "IP addresses" +msgstr "IP地址" + +#: mod_configure.erl:1670 +msgid "Resources" +msgstr "资源" + +#: mod_configure.erl:1796 +msgid "Administration of " +msgstr "管理" + +#: mod_configure.erl:1799 +msgid "Action on user" +msgstr "对用户的动作" + +#: mod_configure.erl:1803 +msgid "Edit Properties" +msgstr "编辑属性" + +#: mod_configure.erl:1806 web/ejabberd_web_admin.erl:1514 +msgid "Remove User" +msgstr "删除用户" + +#: mod_irc/mod_irc.erl:198 mod_muc/mod_muc.erl:305 +msgid "Access denied by service policy" +msgstr "访问被服务策略拒绝" + +#: mod_irc/mod_irc.erl:311 +msgid "IRC Transport" +msgstr "IRC传输" + +#: mod_irc/mod_irc.erl:325 +msgid "ejabberd IRC module" +msgstr "ejabberd IRC 模块" + +#: mod_irc/mod_irc.erl:443 +msgid "You need an x:data capable client to configure mod_irc settings" +msgstr "您需要一个兼容x:data的客户端来配置mod_irc设置" + +#: mod_irc/mod_irc.erl:450 +msgid "Registration in mod_irc for " +msgstr "mod_irc中的注册是为 " + +#: mod_irc/mod_irc.erl:455 +msgid "" +"Enter username and encodings you wish to use for connecting to IRC servers" +msgstr "请输入您想使用的用来连接到IRC服务器的用户名和编码" + +#: mod_irc/mod_irc.erl:460 +msgid "IRC Username" +msgstr "IRC用户名" + +#: mod_irc/mod_irc.erl:470 +msgid "" +"If you want to specify different encodings for IRC servers, fill this list " +"with values in format '{\"irc server\", \"encoding\"}'. By default this " +"service use \"~s\" encoding." +msgstr "" +"如果您想为IRC服务器指定不同的编码, 请用'{\"irc 服务器\", \"编码\"}'格式的值填" +"充此表单. 默认情况下此服务使用\"~s\"编码." + +#: mod_irc/mod_irc.erl:480 +msgid "" +"Example: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." +msgstr "" +"例如: [{\"irc.lucky.net\", \"koi8-r\"}, {\"vendetta.fef.net\", \"iso8859-1" +"\"}]." + +#: mod_irc/mod_irc.erl:485 +msgid "Encodings" +msgstr "编码" + +#: mod_muc/mod_muc.erl:403 +msgid "Only service administrators are allowed to send service messages" +msgstr "只有服务管理员可以发送服务消息" + +#: mod_muc/mod_muc.erl:446 +msgid "Room creation is denied by service policy" +msgstr "创建房间被服务策略拒绝" + +#: mod_muc/mod_muc.erl:453 +msgid "Conference room does not exist" +msgstr "会议室不存在" + +#: mod_muc/mod_muc.erl:510 +msgid "Chatrooms" +msgstr "聊天室" + +#: mod_muc/mod_muc.erl:561 +msgid "You need an x:data capable client to register nickname" +msgstr "您需要一个兼容x:data的客户端来注册昵称" + +#: mod_muc/mod_muc.erl:567 +msgid "Nickname Registration at " +msgstr "昵称注册于 " + +#: mod_muc/mod_muc.erl:571 +msgid "Enter nickname you want to register" +msgstr "请输入您想要注册的昵称" + +#: mod_muc/mod_muc.erl:572 mod_roster.erl:804 mod_roster_odbc.erl:911 +#: mod_vcard.erl:357 mod_vcard.erl:465 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:462 +msgid "Nickname" +msgstr "昵称" + +#: mod_muc/mod_muc.erl:611 +msgid "Specified nickname is already registered" +msgstr "指定的名称已被注册" + +#: mod_muc/mod_muc.erl:635 +msgid "You must fill in field \"Nickname\" in the form" +msgstr "您必须填充表单中\"昵称\"项" + +#: mod_muc/mod_muc.erl:657 +msgid "ejabberd MUC module" +msgstr "ejabberd MUC模块" + +#: mod_muc/mod_muc_log.erl:338 +msgid "Chatroom configuration modified" +msgstr "聊天室配置已修改" + +#: mod_muc/mod_muc_log.erl:341 +msgid "joins the room" +msgstr "加入房间" + +#: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 +msgid "leaves the room" +msgstr "离开房间" + +#: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 +msgid "has been banned" +msgstr "已被禁止" + +#: mod_muc/mod_muc_log.erl:356 mod_muc/mod_muc_log.erl:359 +msgid "has been kicked" +msgstr "已被踢出" + +#: mod_muc/mod_muc_log.erl:362 +msgid "has been kicked because of an affiliation change" +msgstr "因联属关系改变而被踢出" + +#: mod_muc/mod_muc_log.erl:365 +msgid "has been kicked because the room has been changed to members-only" +msgstr "因该房间改为只对会员开放而被踢出" + +#: mod_muc/mod_muc_log.erl:368 +msgid "has been kicked because of a system shutdown" +msgstr "因系统关机而被踢出" + +#: mod_muc/mod_muc_log.erl:371 +msgid "is now known as" +msgstr "现在称呼为" + +#: mod_muc/mod_muc_log.erl:374 mod_muc/mod_muc_log.erl:619 +#: mod_muc/mod_muc_room.erl:1973 +msgid " has set the subject to: " +msgstr "已将标题设置为: " + +#: mod_muc/mod_muc_log.erl:405 +msgid "Monday" +msgstr "星期一" + +#: mod_muc/mod_muc_log.erl:406 +msgid "Tuesday" +msgstr "星期二" + +#: mod_muc/mod_muc_log.erl:407 +msgid "Wednesday" +msgstr "星期三" + +#: mod_muc/mod_muc_log.erl:408 +msgid "Thursday" +msgstr "星期四" + +#: mod_muc/mod_muc_log.erl:409 +msgid "Friday" +msgstr "星期五" + +#: mod_muc/mod_muc_log.erl:410 +msgid "Saturday" +msgstr "星期六" + +#: mod_muc/mod_muc_log.erl:411 +msgid "Sunday" +msgstr "星期天" + +#: mod_muc/mod_muc_log.erl:415 +msgid "January" +msgstr "一月" + +#: mod_muc/mod_muc_log.erl:416 +msgid "February" +msgstr "二月" + +#: mod_muc/mod_muc_log.erl:417 +msgid "March" +msgstr "三月" + +#: mod_muc/mod_muc_log.erl:418 +msgid "April" +msgstr "四月" + +#: mod_muc/mod_muc_log.erl:419 +msgid "May" +msgstr "五月" + +#: mod_muc/mod_muc_log.erl:420 +msgid "June" +msgstr "六月" + +#: mod_muc/mod_muc_log.erl:421 +msgid "July" +msgstr "七月" + +#: mod_muc/mod_muc_log.erl:422 +msgid "August" +msgstr "八月" + +#: mod_muc/mod_muc_log.erl:423 +msgid "September" +msgstr "九月" + +#: mod_muc/mod_muc_log.erl:424 +msgid "October" +msgstr "十月" + +#: mod_muc/mod_muc_log.erl:425 +msgid "November" +msgstr "十一月" + +#: mod_muc/mod_muc_log.erl:426 +msgid "December" +msgstr "十二月" + +#: mod_muc/mod_muc_log.erl:675 +msgid "Room Configuration" +msgstr "房间配置" + +#: mod_muc/mod_muc_log.erl:768 mod_muc/mod_muc_room.erl:2678 +msgid "Room title" +msgstr "房间标题" + +#: mod_muc/mod_muc_room.erl:226 +msgid "Traffic rate limit is exceeded" +msgstr "已经超过传输率限制" + +#: mod_muc/mod_muc_room.erl:303 +msgid "" +"This participant is kicked from the room because he sent an error message" +msgstr "该用户由于发生了错误而被踢出了聊天室" + +#: mod_muc/mod_muc_room.erl:312 +msgid "It is not allowed to send private messages to the conference" +msgstr "不允许向会议发送私聊消息" + +#: mod_muc/mod_muc_room.erl:357 +msgid "Improper message type" +msgstr "消息类型不恰当" + +#: mod_muc/mod_muc_room.erl:474 +msgid "" +"This participant is kicked from the room because he sent an error message to " +"another participant" +msgstr "该用户由于给其他人发送了出错信息而被踢出了聊天室" + +#: mod_muc/mod_muc_room.erl:487 +msgid "It is not allowed to send private messages of type \"groupchat\"" +msgstr "\"群组聊天\"类型不允许发送私聊消息" + +#: mod_muc/mod_muc_room.erl:499 mod_muc/mod_muc_room.erl:553 +msgid "Recipient is not in the conference room" +msgstr "接收人不在会议室" + +#: mod_muc/mod_muc_room.erl:519 mod_muc/mod_muc_room.erl:872 +#: mod_muc/mod_muc_room.erl:3272 +msgid "Only occupants are allowed to send messages to the conference" +msgstr "只允许占有者向会议发送消息" + +#: mod_muc/mod_muc_room.erl:528 +msgid "It is not allowed to send private messages" +msgstr "不允许发送私聊消息" + +#: mod_muc/mod_muc_room.erl:574 +msgid "Only occupants are allowed to send queries to the conference" +msgstr "只允许占有者发出查询请求" + +#: mod_muc/mod_muc_room.erl:586 +msgid "Queries to the conference members are not allowed in this room" +msgstr "本房间不允许发出成员查询请求" + +#: mod_muc/mod_muc_room.erl:671 +msgid "private, " +msgstr "保密" + +#: mod_muc/mod_muc_room.erl:848 +msgid "" +"Only moderators and participants are allowed to change subject in this room" +msgstr "只允许监管人和参与人更改此房间的主题" + +#: mod_muc/mod_muc_room.erl:853 +msgid "Only moderators are allowed to change subject in this room" +msgstr "只允许监管人更改此房间的主题" + +#: mod_muc/mod_muc_room.erl:863 +msgid "Visitors are not allowed to send messages to all occupants" +msgstr "不允许访客给所有占有者发送消息" + +#: mod_muc/mod_muc_room.erl:931 +msgid "" +"This participant is kicked from the room because he sent an error presence" +msgstr "该用户由于状态信息错误而被踢出了聊天室" + +#: mod_muc/mod_muc_room.erl:949 +msgid "Visitors are not allowed to change their nicknames in this room" +msgstr "此房间不允许用户更改昵称" + +#: mod_muc/mod_muc_room.erl:962 mod_muc/mod_muc_room.erl:1484 +msgid "Nickname is already in use by another occupant" +msgstr "昵称已被另一用户占用" + +#: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 +msgid "Nickname is registered by another person" +msgstr "昵称已被另一人注册" + +#: mod_muc/mod_muc_room.erl:1473 +msgid "You have been banned from this room" +msgstr "您已被禁止进入该房间" + +#: mod_muc/mod_muc_room.erl:1476 +msgid "Membership required to enter this room" +msgstr "进入此房间需要会员身份" + +#: mod_muc/mod_muc_room.erl:1511 +msgid "This room is not anonymous" +msgstr "此房间不是匿名房间" + +#: mod_muc/mod_muc_room.erl:1536 +msgid "Password required to enter this room" +msgstr "进入此房间需要密码" + +#: mod_muc/mod_muc_room.erl:1545 +msgid "Incorrect password" +msgstr "密码不正确" + +#: mod_muc/mod_muc_room.erl:2028 +msgid "Administrator privileges required" +msgstr "需要管理员权限" + +#: mod_muc/mod_muc_room.erl:2043 +msgid "Moderator privileges required" +msgstr "需要调解人权限" + +#: mod_muc/mod_muc_room.erl:2198 +msgid "JID ~s is invalid" +msgstr "JID ~s无效" + +#: mod_muc/mod_muc_room.erl:2212 +msgid "Nickname ~s does not exist in the room" +msgstr "昵称~s不在该房间" + +#: mod_muc/mod_muc_room.erl:2238 mod_muc/mod_muc_room.erl:2609 +msgid "Invalid affiliation: ~s" +msgstr "无效加入: ~s" + +#: mod_muc/mod_muc_room.erl:2295 +msgid "Invalid role: ~s" +msgstr "无效角色: ~s" + +#: mod_muc/mod_muc_room.erl:2586 mod_muc/mod_muc_room.erl:2622 +msgid "Owner privileges required" +msgstr "需要持有人权限" + +#: mod_muc/mod_muc_room.erl:2672 +msgid "Configuration for " +msgstr "配置 " + +#: mod_muc/mod_muc_room.erl:2681 mod_muc/mod_muc_room.erl:3082 +#, fuzzy +msgid "Room description" +msgstr "描述:" + +#: mod_muc/mod_muc_room.erl:2688 +msgid "Make room persistent" +msgstr "在服务器端保存该房间" + +#: mod_muc/mod_muc_room.erl:2693 +msgid "Make room public searchable" +msgstr "使房间可被公开搜索" + +#: mod_muc/mod_muc_room.erl:2696 +msgid "Make participants list public" +msgstr "公开参与人列表" + +#: mod_muc/mod_muc_room.erl:2699 +msgid "Make room password protected" +msgstr "保护房间密码" + +#: mod_muc/mod_muc_room.erl:2710 +msgid "Maximum Number of Occupants" +msgstr "占有人最大数" + +#: mod_muc/mod_muc_room.erl:2723 +msgid "No limit" +msgstr "不限" + +#: mod_muc/mod_muc_room.erl:2733 +msgid "Present real JIDs to" +msgstr "将真实JID显示给" + +#: mod_muc/mod_muc_room.erl:2741 +msgid "moderators only" +msgstr "仅一般人" + +#: mod_muc/mod_muc_room.erl:2743 +msgid "anyone" +msgstr "任何人" + +#: mod_muc/mod_muc_room.erl:2745 +msgid "Make room members-only" +msgstr "设置房间只接收会员" + +#: mod_muc/mod_muc_room.erl:2748 +msgid "Make room moderated" +msgstr "使房间处于监管状态" + +#: mod_muc/mod_muc_room.erl:2751 +msgid "Default users as participants" +msgstr "将默认用户视为参与人" + +#: mod_muc/mod_muc_room.erl:2754 +msgid "Allow users to change subject" +msgstr "允许用户更改主题" + +#: mod_muc/mod_muc_room.erl:2757 +msgid "Allow users to send private messages" +msgstr "允许用户发送私聊消息" + +#: mod_muc/mod_muc_room.erl:2760 +msgid "Allow users to query other users" +msgstr "允许用户查询其它用户" + +#: mod_muc/mod_muc_room.erl:2763 +msgid "Allow users to send invites" +msgstr "允许用户发送邀请" + +#: mod_muc/mod_muc_room.erl:2766 +msgid "Allow visitors to send status text in presence updates" +msgstr "更新在线状态时允许用户发送状态文本" + +#: mod_muc/mod_muc_room.erl:2769 +msgid "Allow visitors to change nickname" +msgstr "允许用户更改昵称" + +#: mod_muc/mod_muc_room.erl:2777 +msgid "Enable logging" +msgstr "启用服务器端聊天记录" + +#: mod_muc/mod_muc_room.erl:2785 +msgid "You need an x:data capable client to configure room" +msgstr "您需要一个兼容x:data的客户端来配置房间" + +#: mod_muc/mod_muc_room.erl:3084 +msgid "Number of occupants" +msgstr "占用人数" + +#: mod_muc/mod_muc_room.erl:3192 +msgid "~s invites you to the room ~s" +msgstr "~s邀请你到~s房间" + +#: mod_muc/mod_muc_room.erl:3201 +msgid "the password is" +msgstr "密码是" + +#: mod_offline.erl:446 mod_offline_odbc.erl:296 +msgid "" +"Your contact offline message queue is full. The message has been discarded." +msgstr "您的离线消息队列已满. 消息已被丢弃" + +#: mod_offline.erl:495 mod_offline_odbc.erl:351 +msgid "~s's Offline Messages Queue" +msgstr "~s的离线消息队列" + +#: mod_offline.erl:498 mod_offline_odbc.erl:354 mod_roster.erl:847 +#: mod_roster_odbc.erl:954 mod_shared_roster.erl:648 mod_shared_roster.erl:748 +#: web/ejabberd_web_admin.erl:681 web/ejabberd_web_admin.erl:724 +#: web/ejabberd_web_admin.erl:792 web/ejabberd_web_admin.erl:830 +#: web/ejabberd_web_admin.erl:870 web/ejabberd_web_admin.erl:1319 +#: web/ejabberd_web_admin.erl:1506 web/ejabberd_web_admin.erl:1668 +#: web/ejabberd_web_admin.erl:1735 web/ejabberd_web_admin.erl:1816 +#: web/ejabberd_web_admin.erl:1839 web/ejabberd_web_admin.erl:1908 +msgid "Submitted" +msgstr "已提交" + +#: mod_offline.erl:506 +msgid "Time" +msgstr "时间" + +#: mod_offline.erl:507 +msgid "From" +msgstr "从" + +#: mod_offline.erl:508 +msgid "To" +msgstr "到" + +#: mod_offline.erl:509 mod_offline_odbc.erl:362 +msgid "Packet" +msgstr "数据包" + +#: mod_offline.erl:522 mod_offline_odbc.erl:375 mod_shared_roster.erl:655 +#: web/ejabberd_web_admin.erl:732 web/ejabberd_web_admin.erl:838 +msgid "Delete Selected" +msgstr "删除已选内容" + +#: mod_offline.erl:557 mod_offline_odbc.erl:440 +msgid "Offline Messages:" +msgstr "离线消息:" + +#: mod_proxy65/mod_proxy65_service.erl:192 +msgid "ejabberd SOCKS5 Bytestreams module" +msgstr "ejabberd SOCKS5字节流模块" + +#: mod_pubsub/mod_pubsub.erl:753 +msgid "Publish-Subscribe" +msgstr "发布-订阅" + +#: mod_pubsub/mod_pubsub.erl:846 +msgid "ejabberd Publish-Subscribe module" +msgstr "ejabberd发行-订阅模块" + +#: mod_pubsub/mod_pubsub.erl:997 +msgid "PubSub subscriber request" +msgstr "PubSub订阅人请求" + +#: mod_pubsub/mod_pubsub.erl:999 +msgid "Choose whether to approve this entity's subscription." +msgstr "选择是否允许该实体的订阅" + +#: mod_pubsub/mod_pubsub.erl:1005 +msgid "Node ID" +msgstr "节点ID" + +#: mod_pubsub/mod_pubsub.erl:1010 +msgid "Subscriber Address" +msgstr "订阅人地址" + +#: mod_pubsub/mod_pubsub.erl:1016 +msgid "Allow this JID to subscribe to this pubsub node?" +msgstr "允许该JID订阅该pubsub节点?" + +#: mod_pubsub/mod_pubsub.erl:2497 +msgid "Deliver payloads with event notifications" +msgstr "用事件通告传输有效负载" + +#: mod_pubsub/mod_pubsub.erl:2498 +msgid "Deliver event notifications" +msgstr "传递事件通知" + +#: mod_pubsub/mod_pubsub.erl:2499 +msgid "Notify subscribers when the node configuration changes" +msgstr "当节点设置改变时通知订阅人" + +#: mod_pubsub/mod_pubsub.erl:2500 +msgid "Notify subscribers when the node is deleted" +msgstr "当节点被删除时通知订阅人" + +#: mod_pubsub/mod_pubsub.erl:2501 +msgid "Notify subscribers when items are removed from the node" +msgstr "当从节点删除内容条目时通知订阅人" + +#: mod_pubsub/mod_pubsub.erl:2502 +msgid "Persist items to storage" +msgstr "持久化内容条目" + +#: mod_pubsub/mod_pubsub.erl:2503 +msgid "A friendly name for the node" +msgstr "该节点的友好名称" + +#: mod_pubsub/mod_pubsub.erl:2504 +msgid "Max # of items to persist" +msgstr "允许持久化的最大内容条目数" + +#: mod_pubsub/mod_pubsub.erl:2505 +msgid "Whether to allow subscriptions" +msgstr "是否允许订阅" + +#: mod_pubsub/mod_pubsub.erl:2506 +msgid "Specify the access model" +msgstr "指定访问模式" + +#: mod_pubsub/mod_pubsub.erl:2510 +msgid "Roster groups allowed to subscribe" +msgstr "允许订阅的花名册组" + +#: mod_pubsub/mod_pubsub.erl:2514 +msgid "Specify the publisher model" +msgstr "指定发布人样式" + +#: mod_pubsub/mod_pubsub.erl:2516 +msgid "Max payload size in bytes" +msgstr "最大有效负载比特数" + +#: mod_pubsub/mod_pubsub.erl:2517 +msgid "When to send the last published item" +msgstr "何时发送最新发布的内容条目" + +#: mod_pubsub/mod_pubsub.erl:2519 +msgid "Only deliver notifications to available users" +msgstr "仅将通知发送给可发送的用户" + +#: mod_register.erl:191 +msgid "Choose a username and password to register with this server" +msgstr "请选择在此服务器上注册所需的用户名和密码" + +#: mod_register.erl:232 +msgid "Users are not allowed to register accounts so fast" +msgstr "不允许用户注册帐户太快" + +#: mod_roster.erl:798 mod_roster_odbc.erl:905 web/ejabberd_web_admin.erl:1481 +#: web/ejabberd_web_admin.erl:1623 web/ejabberd_web_admin.erl:1634 +#: web/ejabberd_web_admin.erl:1898 +msgid "None" +msgstr "无" + +#: mod_roster.erl:805 mod_roster_odbc.erl:912 +msgid "Subscription" +msgstr "订阅" + +#: mod_roster.erl:806 mod_roster_odbc.erl:913 +msgid "Pending" +msgstr "挂起" + +#: mod_roster.erl:807 mod_roster_odbc.erl:914 +msgid "Groups" +msgstr "组" + +#: mod_roster.erl:834 mod_roster_odbc.erl:941 +msgid "Validate" +msgstr "确认" + +#: mod_roster.erl:842 mod_roster_odbc.erl:949 +msgid "Remove" +msgstr "移除" + +#: mod_roster.erl:845 mod_roster_odbc.erl:952 +msgid "Roster of " +msgstr "花名册属于 " + +#: mod_roster.erl:848 mod_roster_odbc.erl:955 mod_shared_roster.erl:649 +#: mod_shared_roster.erl:749 web/ejabberd_web_admin.erl:682 +#: web/ejabberd_web_admin.erl:725 web/ejabberd_web_admin.erl:793 +#: web/ejabberd_web_admin.erl:831 web/ejabberd_web_admin.erl:871 +#: web/ejabberd_web_admin.erl:1320 web/ejabberd_web_admin.erl:1507 +#: web/ejabberd_web_admin.erl:1669 web/ejabberd_web_admin.erl:1817 +#: web/ejabberd_web_admin.erl:1840 web/ejabberd_web_admin.erl:1909 +msgid "Bad format" +msgstr "格式错误" + +#: mod_roster.erl:855 mod_roster_odbc.erl:962 +msgid "Add Jabber ID" +msgstr "添加Jabber ID" + +#: mod_roster.erl:936 mod_roster_odbc.erl:1043 +msgid "Roster" +msgstr "花名册" + +#: mod_shared_roster.erl:604 mod_shared_roster.erl:646 +#: mod_shared_roster.erl:745 +msgid "Shared Roster Groups" +msgstr "共享的花名册组群" + +#: mod_shared_roster.erl:642 web/ejabberd_web_admin.erl:1189 +#: web/ejabberd_web_admin.erl:2082 +msgid "Add New" +msgstr "添加新用户" + +#: mod_shared_roster.erl:716 +msgid "Name:" +msgstr "名称:" + +#: mod_shared_roster.erl:721 +msgid "Description:" +msgstr "描述:" + +#: mod_shared_roster.erl:729 +msgid "Members:" +msgstr "会员:" + +#: mod_shared_roster.erl:737 +msgid "Displayed Groups:" +msgstr "已显示的组:" + +#: mod_shared_roster.erl:746 +msgid "Group " +msgstr "组" + +#: mod_shared_roster.erl:755 web/ejabberd_web_admin.erl:691 +#: web/ejabberd_web_admin.erl:734 web/ejabberd_web_admin.erl:802 +#: web/ejabberd_web_admin.erl:877 web/ejabberd_web_admin.erl:1751 +msgid "Submit" +msgstr "提交" + +#: mod_vcard.erl:165 mod_vcard_ldap.erl:235 mod_vcard_odbc.erl:129 +msgid "Erlang Jabber Server" +msgstr "Erlang Jabber 服务器" + +#: mod_vcard.erl:357 mod_vcard.erl:466 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:463 +msgid "Birthday" +msgstr "出生日期" + +#: mod_vcard.erl:357 mod_vcard.erl:468 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:465 +msgid "City" +msgstr "城市" + +#: mod_vcard.erl:357 mod_vcard.erl:467 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:464 +msgid "Country" +msgstr "国家" + +#: mod_vcard.erl:357 mod_vcard.erl:469 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:466 +msgid "Email" +msgstr "电子邮件" + +#: mod_vcard.erl:357 mod_vcard.erl:464 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:461 +msgid "Family Name" +msgstr "姓氏" + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 +msgid "" +"Fill in the form to search for any matching Jabber User (Add * to the end of " +"field to match substring)" +msgstr "填充表单以搜索任何匹配的Jabber用户(在字段末添加*来匹配子串)" + +#: mod_vcard.erl:357 mod_vcard.erl:461 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:458 +msgid "Full Name" +msgstr "全名" + +#: mod_vcard.erl:357 mod_vcard.erl:463 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:460 +msgid "Middle Name" +msgstr "中间名" + +#: mod_vcard.erl:357 mod_vcard.erl:462 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:459 web/ejabberd_web_admin.erl:1740 +msgid "Name" +msgstr "名称" + +#: mod_vcard.erl:357 mod_vcard.erl:470 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:467 +msgid "Organization Name" +msgstr "组织名称" + +#: mod_vcard.erl:357 mod_vcard.erl:471 mod_vcard_odbc.erl:354 +#: mod_vcard_odbc.erl:468 +msgid "Organization Unit" +msgstr "组织单位" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "Search users in " +msgstr "要搜索的用户位于 " + +#: mod_vcard.erl:357 mod_vcard_odbc.erl:354 web/ejabberd_web_admin.erl:1326 +#: web/ejabberd_web_admin.erl:1381 +msgid "User" +msgstr "用户" + +#: mod_vcard.erl:357 mod_vcard_ldap.erl:455 mod_vcard_odbc.erl:354 +msgid "You need an x:data capable client to search" +msgstr "您需要一个兼容x:data的客户端来搜索" + +#: mod_vcard.erl:379 mod_vcard_ldap.erl:477 mod_vcard_odbc.erl:376 +msgid "vCard User Search" +msgstr "vCard用户搜索" + +#: mod_vcard.erl:433 mod_vcard_ldap.erl:531 mod_vcard_odbc.erl:430 +msgid "ejabberd vCard module" +msgstr "ejabberd vCard 模块" + +#: mod_vcard.erl:457 mod_vcard_ldap.erl:541 mod_vcard_odbc.erl:454 +msgid "Search Results for " +msgstr "搜索结果属于关键词 " + +#: mod_vcard_ldap.erl:455 +msgid "Fill in fields to search for any matching Jabber User" +msgstr "填充字段以搜索任何匹配的Jabber用户" + +#: web/ejabberd_web_admin.erl:115 web/ejabberd_web_admin.erl:166 +msgid "ejabberd Web Admin" +msgstr "ejabberd网页管理" + +#: web/ejabberd_web_admin.erl:130 web/ejabberd_web_admin.erl:181 +#: web/ejabberd_web_admin.erl:603 web/ejabberd_web_admin.erl:622 +msgid "Administration" +msgstr "管理" + +#: web/ejabberd_web_admin.erl:137 web/ejabberd_web_admin.erl:609 +msgid "Virtual Hosts" +msgstr "虚拟主机" + +#: web/ejabberd_web_admin.erl:138 web/ejabberd_web_admin.erl:195 +#: web/ejabberd_web_admin.erl:610 web/ejabberd_web_admin.erl:631 +#: web/ejabberd_web_admin.erl:1643 +msgid "Nodes" +msgstr "节点" + +#: web/ejabberd_web_admin.erl:139 web/ejabberd_web_admin.erl:196 +#: web/ejabberd_web_admin.erl:611 web/ejabberd_web_admin.erl:632 +#: web/ejabberd_web_admin.erl:950 web/ejabberd_web_admin.erl:1676 +msgid "Statistics" +msgstr "统计" + +#: web/ejabberd_web_admin.erl:192 web/ejabberd_web_admin.erl:628 +#: web/ejabberd_web_admin.erl:892 web/ejabberd_web_admin.erl:898 +msgid "Users" +msgstr "用户" + +#: web/ejabberd_web_admin.erl:194 web/ejabberd_web_admin.erl:630 +#: web/ejabberd_web_admin.erl:1383 +msgid "Last Activity" +msgstr "上次活动" + +#: web/ejabberd_web_admin.erl:606 web/ejabberd_web_admin.erl:608 +#: web/ejabberd_web_admin.erl:625 web/ejabberd_web_admin.erl:627 +msgid "(Raw)" +msgstr "(原始格式)" + +#: web/ejabberd_web_admin.erl:728 web/ejabberd_web_admin.erl:834 +msgid "Raw" +msgstr "原始格式" + +#: web/ejabberd_web_admin.erl:868 +msgid "~s access rule configuration" +msgstr "~s访问规则配置" + +#: web/ejabberd_web_admin.erl:885 +msgid "ejabberd virtual hosts" +msgstr "ejabberd虚拟主机" + +#: web/ejabberd_web_admin.erl:924 +msgid "Users Last Activity" +msgstr "用户上次活动" + +#: web/ejabberd_web_admin.erl:926 +msgid "Period: " +msgstr "持续时间:" + +#: web/ejabberd_web_admin.erl:936 +msgid "Last month" +msgstr "上个月" + +#: web/ejabberd_web_admin.erl:937 +msgid "Last year" +msgstr "上一年" + +#: web/ejabberd_web_admin.erl:938 +msgid "All activity" +msgstr "所有活动" + +#: web/ejabberd_web_admin.erl:940 +msgid "Show Ordinary Table" +msgstr "显示普通列表" + +#: web/ejabberd_web_admin.erl:942 +msgid "Show Integral Table" +msgstr "显示完整列表" + +#: web/ejabberd_web_admin.erl:971 +msgid "Node not found" +msgstr "没有找到节点" + +#: web/ejabberd_web_admin.erl:1273 +msgid "Host" +msgstr "主机" + +#: web/ejabberd_web_admin.erl:1274 +msgid "Registered Users" +msgstr "注册用户" + +#: web/ejabberd_web_admin.erl:1382 +msgid "Offline Messages" +msgstr "离线消息" + +#: web/ejabberd_web_admin.erl:1439 web/ejabberd_web_admin.erl:1455 +msgid "Registered Users:" +msgstr "注册用户:" + +#: web/ejabberd_web_admin.erl:1441 web/ejabberd_web_admin.erl:1457 +#: web/ejabberd_web_admin.erl:1871 +msgid "Online Users:" +msgstr "在线用户:" + +#: web/ejabberd_web_admin.erl:1443 +msgid "Outgoing s2s Connections:" +msgstr "出站s2s连接:" + +#: web/ejabberd_web_admin.erl:1445 +msgid "Outgoing s2s Servers:" +msgstr "出站s2s服务器" + +#: web/ejabberd_web_admin.erl:1501 +msgid "Change Password" +msgstr "更改密码" + +#: web/ejabberd_web_admin.erl:1504 +msgid "User " +msgstr "用户 " + +#: web/ejabberd_web_admin.erl:1511 +msgid "Connected Resources:" +msgstr "已连接资源" + +#: web/ejabberd_web_admin.erl:1512 +msgid "Password:" +msgstr "密码:" + +#: web/ejabberd_web_admin.erl:1567 +msgid "No Data" +msgstr "没有数据" + +#: web/ejabberd_web_admin.erl:1666 web/ejabberd_web_admin.erl:1688 +msgid "Node " +msgstr "节点 " + +#: web/ejabberd_web_admin.erl:1675 +msgid "Listened Ports" +msgstr "监听端口" + +#: web/ejabberd_web_admin.erl:1677 web/ejabberd_web_admin.erl:1913 +#: web/ejabberd_web_admin.erl:2071 +msgid "Update" +msgstr "更新" + +#: web/ejabberd_web_admin.erl:1680 web/ejabberd_web_admin.erl:2148 +msgid "Restart" +msgstr "重启" + +#: web/ejabberd_web_admin.erl:1682 web/ejabberd_web_admin.erl:2150 +msgid "Stop" +msgstr "停止" + +#: web/ejabberd_web_admin.erl:1696 +msgid "RPC Call Error" +msgstr "RPC调用错误" + +#: web/ejabberd_web_admin.erl:1734 +msgid "Database Tables at " +msgstr "数据库列表位于 " + +#: web/ejabberd_web_admin.erl:1741 +msgid "Storage Type" +msgstr "存储类型" + +#: web/ejabberd_web_admin.erl:1742 +msgid "Size" +msgstr "大小" + +#: web/ejabberd_web_admin.erl:1743 +msgid "Memory" +msgstr "内存" + +#: web/ejabberd_web_admin.erl:1758 +msgid "Backup of " +msgstr "备份来源 " + +#: web/ejabberd_web_admin.erl:1759 +msgid "" +"Remark that these options will only backup the builtin Mnesia database. If " +"you are using the ODBC module, you also need to backup your SQL database " +"separately." +msgstr "" +"注意:这些选项仅将备份内置的Mnesia数据库. 如果您在使用ODBC模块, 您还需要分别" +"备份您的数据库." + +#: web/ejabberd_web_admin.erl:1764 +msgid "Store binary backup:" +msgstr "存储为二进制备份:" + +#: web/ejabberd_web_admin.erl:1768 web/ejabberd_web_admin.erl:1775 +#: web/ejabberd_web_admin.erl:1783 web/ejabberd_web_admin.erl:1790 +#: web/ejabberd_web_admin.erl:1797 +msgid "OK" +msgstr "OK" + +#: web/ejabberd_web_admin.erl:1771 +msgid "Restore binary backup immediately:" +msgstr "立即恢复二进制备份:" + +#: web/ejabberd_web_admin.erl:1779 +msgid "" +"Restore binary backup after next ejabberd restart (requires less memory):" +msgstr "在下次ejabberd重启后恢复二进制备份(需要的内存更少):" + +#: web/ejabberd_web_admin.erl:1786 +msgid "Store plain text backup:" +msgstr "存储为普通文本备份:" + +#: web/ejabberd_web_admin.erl:1793 +msgid "Restore plain text backup immediately:" +msgstr "立即恢复普通文本备份:" + +#: web/ejabberd_web_admin.erl:1814 +msgid "Listened Ports at " +msgstr "监听的端口位于 " + +#: web/ejabberd_web_admin.erl:1837 +msgid "Modules at " +msgstr "模块位于 " + +#: web/ejabberd_web_admin.erl:1862 +msgid "Statistics of ~p" +msgstr "~p的统计" + +#: web/ejabberd_web_admin.erl:1865 +msgid "Uptime:" +msgstr "正常运行时间:" + +#: web/ejabberd_web_admin.erl:1868 +msgid "CPU Time:" +msgstr "CPU时间:" + +#: web/ejabberd_web_admin.erl:1874 +msgid "Transactions Commited:" +msgstr "提交的事务:" + +#: web/ejabberd_web_admin.erl:1877 +msgid "Transactions Aborted:" +msgstr "取消的事务:" + +#: web/ejabberd_web_admin.erl:1880 +msgid "Transactions Restarted:" +msgstr "重启的事务:" + +#: web/ejabberd_web_admin.erl:1883 +msgid "Transactions Logged:" +msgstr "记入日志的事务:" + +#: web/ejabberd_web_admin.erl:1906 +msgid "Update " +msgstr "更新 " + +#: web/ejabberd_web_admin.erl:1914 +msgid "Update plan" +msgstr "更新计划" + +#: web/ejabberd_web_admin.erl:1915 +msgid "Updated modules" +msgstr "更新模块" + +#: web/ejabberd_web_admin.erl:1916 +msgid "Update script" +msgstr "更新脚本" + +#: web/ejabberd_web_admin.erl:1917 +msgid "Low level update script" +msgstr "低级别更新脚本" + +#: web/ejabberd_web_admin.erl:1918 +msgid "Script check" +msgstr "检查脚本" + +#: web/ejabberd_web_admin.erl:2054 +msgid "Port" +msgstr "端口" + +#: web/ejabberd_web_admin.erl:2055 web/ejabberd_web_admin.erl:2135 +msgid "Module" +msgstr "模块" + +#: web/ejabberd_web_admin.erl:2056 web/ejabberd_web_admin.erl:2136 +msgid "Options" +msgstr "选项" + +#: web/ejabberd_web_admin.erl:2073 +msgid "Delete" +msgstr "删除" + +#: web/ejabberd_web_admin.erl:2158 +msgid "Start" +msgstr "开始" diff --git a/src/odbc/ejabberd_odbc.erl b/src/odbc/ejabberd_odbc.erl index a1717a665..a373cc2d1 100644 --- a/src/odbc/ejabberd_odbc.erl +++ b/src/odbc/ejabberd_odbc.erl @@ -5,7 +5,7 @@ %%% Created : 8 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -166,13 +166,27 @@ init([Host]) -> %% {stop, Reason, State} (terminate/2 is called) %%---------------------------------------------------------------------- handle_call({sql_query, Query}, _From, State) -> - Reply = sql_query_internal(State, Query), - {reply, Reply, State}; - + case sql_query_internal(State, Query) of + % error returned by MySQL driver + {error, "query timed out"} = Reply -> + {stop, timeout, Reply, State}; + % error returned by MySQL driver + {error, "Failed sending data on socket"++_} = Reply -> + {stop, closed, Reply, State}; + Reply -> + {reply, Reply, State} + end; handle_call({sql_transaction, F}, _From, State) -> - Reply = execute_transaction(State, F, ?MAX_TRANSACTION_RESTARTS), - {reply, Reply, State}; - + case execute_transaction(State, F, ?MAX_TRANSACTION_RESTARTS) of + % error returned by MySQL driver + {error, "query timed out"} -> + {stop, timeout, State}; + % error returned by MySQL driver + {error, "Failed sending data on socket"++_} = Reply -> + {stop, closed, Reply, State}; + Reply -> + {reply, Reply, State} + end; handle_call(_Request, _From, State) -> Reply = ok, {reply, Reply, State}. @@ -308,7 +322,12 @@ mysql_connect(Server, Port, DB, Username, Password) -> case mysql_conn:start(Server, Port, Username, Password, DB, NoLogFun) of {ok, Ref} -> erlang:monitor(process, Ref), - mysql_conn:fetch(Ref, ["set names 'utf8';"], self()), + mysql_conn:fetch(Ref, ["set names 'utf8';"], self()), + % needed to ensure the order of queries, specifically at + % roster subscription time (this can also be set-up in the + % MySQL configuration, but not at the database level): + mysql_conn:fetch(Ref, ["SET SESSION TRANSACTION ISOLATION LEVEL " + "SERIALIZABLE;"], self()), {ok, #state{db_ref = Ref, db_type = mysql}}; {error, Reason} -> ?ERROR_MSG("MySQL connection failed: ~p~n", [Reason]), diff --git a/src/odbc/ejabberd_odbc_sup.erl b/src/odbc/ejabberd_odbc_sup.erl index 326ef6af9..c007da527 100644 --- a/src/odbc/ejabberd_odbc_sup.erl +++ b/src/odbc/ejabberd_odbc_sup.erl @@ -5,7 +5,7 @@ %%% Created : 22 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/odbc/mssql.sql b/src/odbc/mssql2000.sql similarity index 96% rename from src/odbc/mssql.sql rename to src/odbc/mssql2000.sql index c4e45938b..c9313ede1 100644 --- a/src/odbc/mssql.sql +++ b/src/odbc/mssql2000.sql @@ -1,5 +1,5 @@ /* - * ejabberd, Copyright (C) 2002-2008 Process-one + * ejabberd, Copyright (C) 2002-2008 ProcessOne * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/odbc/mssql2005.sql b/src/odbc/mssql2005.sql new file mode 100644 index 000000000..ca5007f15 --- /dev/null +++ b/src/odbc/mssql2005.sql @@ -0,0 +1,1053 @@ +/* + * ejabberd, Copyright (C) 2002-2008 Process-one + * + * 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., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + */ + +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +exec sp_dboption N'ejabberd', N'autoclose', N'false' +GO + +exec sp_dboption N'ejabberd', N'bulkcopy', N'true' +GO + +exec sp_dboption N'ejabberd', N'trunc. log', N'false' +GO + +exec sp_dboption N'ejabberd', N'torn page detection', N'true' +GO + +exec sp_dboption N'ejabberd', N'read only', N'false' +GO + +exec sp_dboption N'ejabberd', N'dbo use', N'false' +GO + +exec sp_dboption N'ejabberd', N'single', N'false' +GO + +exec sp_dboption N'ejabberd', N'autoshrink', N'false' +GO + +exec sp_dboption N'ejabberd', N'ANSI null default', N'false' +GO + +exec sp_dboption N'ejabberd', N'recursive triggers', N'false' +GO + +exec sp_dboption N'ejabberd', N'ANSI nulls', N'false' +GO + +exec sp_dboption N'ejabberd', N'concat null yields null', N'false' +GO + +exec sp_dboption N'ejabberd', N'cursor close on commit', N'false' +GO + +exec sp_dboption N'ejabberd', N'default to local cursor', N'false' +GO + +exec sp_dboption N'ejabberd', N'quoted identifier', N'false' +GO + +exec sp_dboption N'ejabberd', N'ANSI warnings', N'false' +GO + +exec sp_dboption N'ejabberd', N'auto create statistics', N'true' +GO + +exec sp_dboption N'ejabberd', N'auto update statistics', N'true' +GO + +use [ejabberd] +GO + +if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[last]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) +drop table [dbo].[last] +GO + +if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[rostergroups]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) +drop table [dbo].[rostergroups] +GO + +if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[rosterusers]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) +drop table [dbo].[rosterusers] +GO + +if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[spool]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) +drop table [dbo].[spool] +GO + +if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[users]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) +drop table [dbo].[users] +GO + +if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[vcard]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) +drop table [dbo].[vcard] +GO + +if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[private_storage]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) +drop table [dbo].[private_storage] +GO + +CREATE TABLE [dbo].[last] ( + [username] [varchar] (250) NOT NULL , + [seconds] [varchar] (50) NOT NULL , + [state] [varchar] (100) NOT NULL , + [Modify_Date] [datetime] NOT NULL +) ON [PRIMARY] +GO + +CREATE TABLE [dbo].[rostergroups] ( + [username] [varchar] (250) NOT NULL , + [jid] [varchar] (250) NOT NULL , + [grp] [varchar] (100) NOT NULL +) ON [PRIMARY] +GO + +CREATE TABLE [dbo].[rosterusers] ( + [username] [varchar] (250) NOT NULL , + [jid] [varchar] (250) NOT NULL , + [nick] [varchar] (50) NOT NULL , + [subscription] [char] (1) NOT NULL , + [ask] [char] (1) NOT NULL , + [askmessage] [varchar] (250) NOT NULL , + [server] [char] (1) NOT NULL , + [subscribe] [varchar] (200) NULL , + [type] [varchar] (50) NULL , +CONSTRAINT [PK_rosterusers] PRIMARY KEY NONCLUSTERED +( + [username] ASC, + [jid] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY] +GO + +CREATE TABLE [dbo].[spool] ( + [id] [numeric](19, 0) IDENTITY (1, 1) NOT NULL , + [username] [varchar] (250) NOT NULL , + [xml] [text] NOT NULL , + [notifyprocessed] [bit] NULL , + [created] [datetime] NULL , + [MustDelete] [bit] NOT NULL +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO + +CREATE TABLE [dbo].[users] ( + [username] [varchar] (250) NOT NULL , + [password] [varchar] (50) NOT NULL , + [created] [datetime] NULL +) ON [PRIMARY] +GO + +CREATE TABLE [dbo].[vcard] ( + [username] [varchar] (250) NOT NULL , + [full_name] [varchar] (250) NULL , + [first_name] [varchar] (50) NULL , + [last_name] [varchar] (50) NULL , + [nick_name] [varchar] (50) NULL , + [url] [varchar] (1024) NULL , + [address1] [varchar] (50) NULL , + [address2] [varchar] (50) NULL , + [locality] [varchar] (50) NULL , + [region] [varchar] (50) NULL , + [pcode] [varchar] (50) NULL , + [country] [varchar] (50) NULL , + [telephone] [varchar] (50) NULL , + [email] [varchar] (250) NULL , + [orgname] [varchar] (50) NULL , + [orgunit] [varchar] (50) NULL , + [title] [varchar] (50) NULL , + [role] [varchar] (50) NULL , + [b_day] [datetime] NULL , + [descr] [varchar] (500) NULL +) ON [PRIMARY] +GO + +CREATE TABLE [dbo].[private_storage] ( + [username] [varchar] (250) NOT NULL , + [namespace] [varchar] (250) NOT NULL , + [data] [text] NOT NULL +) ON [PRIMARY] +GO + +CREATE TABLE [dbo].[privacy_default_list] ( + [username] [varchar] (250) NOT NULL, + [name] [varchar] (250) NOT NULL +) ON [PRIMARY] +GO + +CREATE TABLE [dbo].[privacy_list]( + [username] [varchar](250) NOT NULL, + [name] [varchar](250) NOT NULL, + [id] [bigint] IDENTITY(1,1) NOT NULL, + CONSTRAINT [PK_privacy_list] PRIMARY KEY CLUSTERED +( + [id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY] +GO + +CREATE TABLE [dbo].[privacy_list_data] ( + [id] [bigint] NOT NULL, + [t] [character] (1) NOT NULL, + [value] [text] NOT NULL, + [action] [character] (1) NOT NULL, + [ord] [NUMERIC] NOT NULL, + [match_all] [bit] NOT NULL, + [match_iq] [bit] NOT NULL, + [match_message] [bit] NOT NULL, + [match_presence_in] [bit] NOT NULL, + [match_presence_out] [bit] NOT NULL +) ON [PRIMARY] +GO + +/* Constraints to add: +- id in privacy_list is a SERIAL autogenerated number +- id in privacy_list_data must exist in the table privacy_list */ + +ALTER TABLE [dbo].[last] WITH NOCHECK ADD + CONSTRAINT [PK_last] PRIMARY KEY CLUSTERED + ( + [username] + ) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + +ALTER TABLE [dbo].[rostergroups] WITH NOCHECK ADD + CONSTRAINT [PK_rostergroups] PRIMARY KEY CLUSTERED + ( + [username], + [jid], + [grp] + ) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + +ALTER TABLE [dbo].[spool] WITH NOCHECK ADD + CONSTRAINT [PK_spool] PRIMARY KEY CLUSTERED + ( + [username], + [id] + ) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + +ALTER TABLE [dbo].[users] WITH NOCHECK ADD + CONSTRAINT [PK_users] PRIMARY KEY CLUSTERED + ( + [username] + ) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + +ALTER TABLE [dbo].[vcard] WITH NOCHECK ADD + CONSTRAINT [PK_vcard] PRIMARY KEY CLUSTERED + ( + [username] + ) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + +CREATE CLUSTERED INDEX [IX_rosterusers_user] ON [dbo].[rosterusers]([username]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + +ALTER TABLE [dbo].[last] WITH NOCHECK ADD + CONSTRAINT [DF_last_updated] DEFAULT (getdate()) FOR [Modify_Date] +GO + +ALTER TABLE [dbo].[spool] WITH NOCHECK ADD + CONSTRAINT [DF_spool_notifyprocessed] DEFAULT (0) FOR [notifyprocessed], + CONSTRAINT [DF_spool_created] DEFAULT (getdate()) FOR [created], + CONSTRAINT [DF_spool_MustDelete] DEFAULT (0) FOR [MustDelete] +GO + +ALTER TABLE [dbo].[users] WITH NOCHECK ADD + CONSTRAINT [DF_users_created] DEFAULT (getdate()) FOR [created] +GO + +ALTER TABLE [dbo].[privacy_default_list] WITH NOCHECK ADD + CONSTRAINT [PK_privacy_defaut_list] PRIMARY KEY CLUSTERED + ( + [username] + ) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + + CREATE INDEX [IX_rostergroups_jid] ON [dbo].[rostergroups]([jid]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + + CREATE INDEX [IX_rostergroups_user] ON [dbo].[rostergroups]([username]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + + CREATE INDEX [IX_spool_user] ON [dbo].[spool]([username]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + + CREATE INDEX [IX_spool_process] ON [dbo].[spool]([created], [notifyprocessed]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + + CREATE INDEX [IK_Spool_Del] ON [dbo].[spool]([MustDelete]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + + CREATE INDEX [IK_Spool_Created] ON [dbo].[spool]([created]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + + CREATE INDEX [IX_private_user] ON [dbo].[private_storage]([username]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + + CREATE INDEX [IX_private_user_ns] ON [dbo].[private_storage]([username], [namespace]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + + CREATE INDEX [IX_privacy_list_username] ON [dbo].[privacy_list]([username]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + + CREATE INDEX [IX_privacy_list_username_name] ON [dbo].[privacy_list]([username], [name]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + +/*********************************************************/ +/** These store procedures are for use with ejabberd **/ +/** 1.1 and Microsoft Sql Server 2000 **/ +/** **/ +/** The stored procedures reduce the need to sql **/ +/** compilation of the database and also allow for also **/ +/** provide each of database integration. The stored **/ +/** procedure have been optimized to increase database **/ +/** performance and a reduction of 80% in CPU was **/ +/** achieved over the use of standard sql. **/ +/*********************************************************/ + +/****** Object: StoredProcedure [dbo].[add_roster] ******/ +/** Add or update user entries in the roster **/ +/*********************************************************/ +CREATE PROCEDURE [dbo].[add_roster] + @Username varchar(250), + @JID varchar(250), + @Nick varchar(50), + @Subscription char(1), + @Ask char(1), + @AskMessage varchar(250), + @Server char(1), + @Subscribe varchar(200), + @Type varchar(50), + @Grp varchar(100) +AS +BEGIN + BEGIN TRANSACTION + --- Update Roster if user exist else add roster item + IF EXISTS (SELECT username FROM rosterusers WITH (NOLOCK) WHERE rosterusers.username=@Username AND rosterusers.jid=@JID) + BEGIN + UPDATE rosterusers + SET rosterusers.username=@Username, + rosterusers.jid=@JID, + rosterusers.nick=@Nick, + rosterusers.subscription=@Subscription, + rosterusers.ask=@Ask, + rosterusers.askmessage=@AskMessage, + rosterusers.server=@Server, + rosterusers.subscribe=@Subscribe, + rosterusers.type=@Type + WHERE (rosterusers.username=@Username) AND (rosterusers.jid=@JID); + END + ELSE + BEGIN + INSERT INTO rosterusers + ( rosterusers.username, + rosterusers.jid, + rosterusers.nick, + rosterusers.subscription, + rosterusers.ask, + rosterusers.askmessage, + rosterusers.server, + rosterusers.subscribe, + rosterusers.type + ) + VALUES + ( @Username, + @JID, + @Nick, + @Subscription, + @Ask, + @AskMessage, + @Server, + @Subscribe, + @Type + ); + END + + --- Update Roster Groups if exist else add group entry + IF NOT EXISTS (SELECT username FROM rostergroups WITH (NOLOCK) WHERE rostergroups.username=@Username AND rostergroups.jid=@JID AND rostergroups.grp=@Grp) + BEGIN + INSERT INTO rostergroups + ( rostergroups.username, + rostergroups.jid, + rostergroups.grp + ) + VALUES + ( @Username, + @JID, + @Grp + ); + END + + COMMIT +END +GO + +/***************************************************************/ +/****** Object: StoredProcedure [dbo].[add_roster_group] ******/ +/** Add or update user group entries in the roster groups **/ +/***************************************************************/ +CREATE PROCEDURE [dbo].[add_roster_group] + @Username varchar(250), + @JID varchar(250), + @Grp varchar(100) +AS +BEGIN + --- Update Roster Groups if exist else add group + IF NOT EXISTS (SELECT username FROM rostergroups WHERE rostergroups.username=@Username AND rostergroups.jid=@JID AND rostergroups.grp=@Grp) + BEGIN + INSERT INTO rostergroups + ( rostergroups.username, + rostergroups.jid, + rostergroups.grp + ) + VALUES + ( @Username, + @JID, + @Grp + ) + END +END +GO + +/***************************************************************/ +/****** Object: StoredProcedure [dbo].[add_roster_user] ******/ +/** Add or update user entries in the roster **/ +/***************************************************************/ +CREATE PROCEDURE [dbo].[add_roster_user] + @Username varchar(250), + @JID varchar(250), + @Nick varchar(50), + @Subscription char(1), + @Ask char(1), + @AskMessage varchar(250), + @Server char(1), + @Subscribe varchar(200), + @Type varchar(50), + @Grp varchar(100) = Null +AS +BEGIN + BEGIN TRANSACTION + --- Update Roster Users if exist of add new user + IF EXISTS (SELECT username FROM rosterusers WHERE rosterusers.username=@Username AND rosterusers.jid=@JID) + BEGIN + UPDATE rosterusers + SET rosterusers.username=@Username, + rosterusers.jid=@JID, + rosterusers.nick=@Nick, + rosterusers.subscription=@Subscription, + rosterusers.ask=@Ask, + rosterusers.askmessage=@AskMessage, + rosterusers.server=@Server, + rosterusers.subscribe=@Subscribe, + rosterusers.type=@Type + WHERE (rosterusers.username=@Username) AND (rosterusers.jid=@JID); + END + ELSE + BEGIN + INSERT INTO rosterusers + ( rosterusers.username, + rosterusers.jid, + rosterusers.nick, + rosterusers.subscription, + rosterusers.ask, + rosterusers.askmessage, + rosterusers.server, + rosterusers.subscribe, + rosterusers.type + ) + VALUES + ( @Username, + @JID, + @Nick, + @Subscription, + @Ask, + @AskMessage, + @Server, + @Subscribe, + @Type + ); + END + + --- Update Roster Group if exist of add new group + IF @Grp IS NOT NULL + EXECUTE [dbo].[add_roster_group] @Username, @JID, @Grp + + COMMIT +END +GO + +/***************************************************************/ +/****** Object: StoredProcedure [dbo].[del_roster_groups] ******/ +/** Remove user group entries from the roster groups table **/ +/***************************************************************/ +CREATE PROCEDURE [dbo].[del_roster_groups] + @Username varchar(250), + @JID varchar(250) +AS +BEGIN + DELETE FROM rostergroups + WITH (ROWLOCK) + WHERE (rostergroups.username = @Username) AND (rostergroups.jid = @JID); +END +GO + +/***************************************************************/ +/****** Object: StoredProcedure [dbo].[add_spool] ******/ +/** Add a entry to the spool table **/ +/***************************************************************/ +CREATE PROCEDURE [dbo].[add_spool] + @Username varchar(250), + @XML varchar(8000) +AS +BEGIN + INSERT INTO spool + ( spool.username, + spool.xml + ) + VALUES + ( @Username, + @XML + ) +END +GO + +/***************************************************************/ +/****** Object: StoredProcedure [dbo].[add_user] ******/ +/** Add or update user entries to jabber **/ +/***************************************************************/ +CREATE PROCEDURE [dbo].[add_user] + @Username varchar(200), + @Password varchar(50) +AS +BEGIN + INSERT INTO users + ( [username], + [password] + ) + VALUES + ( @Username, + @Password + ); +END +GO + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[set_password] **/ +/** Update users password **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[set_password] + @Username varchar(200), + @Password varchar(50) +AS +BEGIN + IF EXISTS (SELECT username FROM users WITH (NOLOCK) WHERE username=@Username) + BEGIN + UPDATE users SET username=@Username, password=@Password WHERE username=@Username; + END + ELSE + BEGIN + INSERT INTO users (username, password) VALUES (@Username, @Password); + END +END +GO + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[get_password] **/ +/** Retrive the user password **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[get_password] + @Username varchar(200) +AS +BEGIN + SELECT users.password as password + FROM users WITH (NOLOCK) + WHERE username=@Username; +END +GO + +/***************************************************************/ +/****** Object: StoredProcedure [dbo].[clean_spool_msg] ******/ +/** Delete messages older that 3 days from spool **/ +/***************************************************************/ +CREATE PROCEDURE [dbo].[clean_spool_msg] +AS +DECLARE + @dt datetime, + @myRowCount int +BEGIN + -- Delete small amounts because if locks the database table + SET ROWCOUNT 500 + SET @myRowCount = 1 + + WHILE (@myRowCount) > 0 + BEGIN + BEGIN TRANSACTION + SELECT @dt = DATEADD(d, -3, GETDATE()) + DELETE FROM spool + WITH (ROWLOCK) + WHERE (MustDelete=1) OR (Created < @dt); + + SET @myRowCount = @@RowCount + COMMIT + END +END +GO + +/***************************************************************/ +/****** Object: StoredProcedure [dbo].[del_last] ******/ +/** Delete an entry from the last table **/ +/***************************************************************/ +CREATE PROCEDURE [dbo].[del_last] + @Username varchar(250) +AS +BEGIN + DELETE FROM [last] + WITH (ROWLOCK) + WHERE [last].username=@Username; +END +GO + +/***************************************************************/ +/****** Object: StoredProcedure [dbo].[del_roster] ******/ +/** Delete an entry from the roster **/ +/***************************************************************/ +CREATE PROCEDURE [dbo].[del_roster] + @Username varchar(250), + @JID varchar(250) +AS +BEGIN + BEGIN TRANSACTION + DELETE FROM rosterusers + WITH (ROWLOCK) + WHERE (rosterusers.username = @Username) AND (rosterusers.jid = @JID); + + DELETE FROM rostergroups + WITH (ROWLOCK) + WHERE (rostergroups.username = @Username) AND (rostergroups.jid = @JID); + COMMIT +END +GO + + +/***************************************************************/ +/****** Object: StoredProcedure [dbo].[del_spool_msg] ******/ +/** Delete an entry from the spool table **/ +/***************************************************************/ +CREATE PROCEDURE [dbo].[del_spool_msg] + @Username varchar(250) +AS +BEGIN + DELETE FROM spool + WITH (ROWLOCK) + WHERE spool.username=@Username; +END +GO + +/***************************************************************/ +/****** Object: StoredProcedure [dbo].[del_user] ******/ +/** Delete an entry from the user table **/ +/***************************************************************/ +CREATE PROCEDURE [dbo].[del_user] + @Username varchar(200) +AS +BEGIN + DELETE FROM users + WITH (ROWLOCK) + WHERE username=@Username; +END +GO + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[del_user_return_password]**/ +/** Delete an entry from the user table and return user password **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[del_user_return_password] + @Username varchar(250) +AS +DECLARE + @Pwd varchar(50) +BEGIN + EXECUTE @Pwd = dbo.get_password @Username + DELETE FROM users + WITH (ROWLOCK) + WHERE username=@Username + + SELECT @Pwd; +END +GO + + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[del_user_roster] **/ +/** Delete the users roster **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[del_user_roster] + @Username varchar(250) +AS +BEGIN + BEGIN TRANSACTION + DELETE FROM rosterusers + WITH (ROWLOCK) + WHERE rosterusers.username = @Username; + + DELETE FROM rostergroups + WITH (ROWLOCK) + WHERE rostergroups.username = @Username; + COMMIT +END +GO + + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[get_and_del_spool_msg] **/ +/** Fetch and delete the users offline messages **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[get_and_del_spool_msg] + @Username varchar(250) +AS +DECLARE + @vSpool table( username varchar(1), + xml varchar(1)) +BEGIN + IF EXISTS (SELECT username FROM spool with (nolock) WHERE spool.username=@Username) + BEGIN + SELECT spool.username AS username, + spool.xml AS xml + FROM spool WITH (NOLOCK) + WHERE spool.username=@Username; + + DELETE spool + WITH (ROWLOCK) + WHERE spool.username=@Username + END + ELSE + BEGIN + SELECT * FROM @vSpool; + END +END +GO + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[get_last] **/ +/** Retrive the last user login **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[get_last] + @Username varchar(250) +AS +BEGIN + SELECT last.seconds AS seconds, + last.state AS state + FROM last WITH (NOLOCK) + WHERE last.username=@Username; +END +GO + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[get_roster] **/ +/** Retrive the user roster **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[get_roster] + @Username varchar(250) +AS +DECLARE + @vRosterusers table( username varchar(1), + jid varchar(1), + nick varchar(1), + subscription varchar(1), + ask varchar(1), + askmessage varchar(1), + server varchar(1), + subscribe varchar(1), + type varchar(1)) +BEGIN + IF EXISTS (SELECT username FROM rosterusers with (nolock) WHERE rosterusers.username = @Username) + BEGIN + SELECT rosterusers.username AS username, + rosterusers.jid AS jid, + rosterusers.nick AS nick, + rosterusers.subscription AS subscription, + rosterusers.ask AS ask, + rosterusers.askmessage AS askmessage, + rosterusers.server AS server, + rosterusers.subscribe AS subscribe, + rosterusers.type AS type + FROM rosterusers WITH (NOLOCK) + WHERE rosterusers.username = @Username; + END + ELSE + BEGIN + SELECT * FROM @vRosterusers + END +END +GO + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[get_roster_by_jid] **/ +/** Retrive the user roster via JID **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[get_roster_by_jid] + @Username varchar(200), + @JID varchar(250) +AS +DECLARE + @vRosterusers table( username varchar(1), + jid varchar(1), + nick varchar(1), + subscription varchar(1), + ask varchar(1), + askmessage varchar(1), + server varchar(1), + subscribe varchar(1), + type varchar(1)) +BEGIN + IF EXISTS (SELECT username FROM rosterusers with (nolock) WHERE (rosterusers.username = @Username) AND (rosterusers.jid = @JID)) + BEGIN + SELECT rosterusers.username AS username, + rosterusers.jid AS jid, + rosterusers.nick AS nick, + rosterusers.subscription AS subscription, + rosterusers.ask AS ask, + rosterusers.askmessage AS askmessage, + rosterusers.server AS server, + rosterusers.subscribe AS subscribe, + rosterusers.type AS type + FROM rosterusers WITH (NOLOCK) + WHERE (rosterusers.username = @Username) AND (rosterusers.jid = @JID); + END + ELSE + BEGIN + SELECT * FROM @vRosterusers + END +END +GO + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[get_roster_jid_groups] **/ +/** Retrieve the user roster groups **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[get_roster_jid_groups] + @Username varchar(200) +AS +DECLARE + @vrostergroups table( jid varchar(1), + grp varchar(1)) +BEGIN + IF EXISTS (SELECT username FROM rostergroups with (nolock) WHERE rostergroups.username = @Username) + BEGIN + SELECT rostergroups.jid AS jid, + rostergroups.grp AS grp + FROM rostergroups WITH (NOLOCK) + WHERE rostergroups.username = @Username; + END + ELSE + BEGIN + SELECT * FROM @vrostergroups + END +END +GO + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[get_roster_groups] **/ +/** Retrive the user roster groups **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[get_roster_groups] + @Username varchar(200), + @JID varchar(250) +AS +DECLARE + @vrostergroups table( grp varchar(1)) +BEGIN + IF EXISTS (SELECT username FROM rostergroups with (nolock) WHERE rostergroups.username = @Username) + BEGIN + SELECT rostergroups.grp AS grp + FROM rostergroups WITH (NOLOCK) + WHERE (rostergroups.username = @Username) AND (rostergroups.jid = @JID); + END + ELSE + BEGIN + SELECT * FROM @vrostergroups + END +END +GO + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[get_rostergroup_by_jid] **/ +/** Retrive the user roster groups via JID **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[get_rostergroup_by_jid] + @Username varchar(250), + @JID varchar(250) +AS +DECLARE + @vrostergroups table(grp varchar(1)) +BEGIN + IF EXISTS (SELECT username FROM rostergroups with (nolock) WHERE rostergroups.username=@Username AND rostergroups.jid=@JID) + BEGIN + SELECT rostergroups.grp AS grp + FROM rostergroups WITH (NOLOCK) + WHERE rostergroups.username=@Username AND rostergroups.jid=@JID; + END + ELSE + BEGIN + SELECT * FROM @vrostergroups + END +END +GO + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[get_subscription] **/ +/** Retrive the user subscription requests **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[get_subscription] + @Username varchar(250), + @JID varchar(250) +AS +DECLARE + @vrosterusers table( subscription varchar(1)) +BEGIN + IF EXISTS (SELECT username FROM rosterusers with (nolock) WHERE rosterusers.username=@Username AND rosterusers.jid=@JID) + BEGIN + SELECT rosterusers.subscription AS subscription + FROM rosterusers WITH (NOLOCK) + WHERE rosterusers.username=@Username AND rosterusers.jid=@JID; + END + ELSE + BEGIN + SELECT * FROM @vrosterusers + END +END +GO + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[list_users] **/ +/** Retrieve a list of all users **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[list_users] +AS +BEGIN + SELECT users.username AS username FROM users WITH (NOLOCK); +END +GO + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[set_last] **/ +/** Update users last login status **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[set_last] + @Username varchar(250), + @Seconds varchar(50), + @State varchar(100) +AS +BEGIN + IF EXISTS (SELECT username FROM [last] WITH (NOLOCK) WHERE username=@Username) + BEGIN + UPDATE [last] + SET [last].username = @Username, + [last].seconds = @Seconds, + [last].state = @State + WHERE last.username=@Username; + END + ELSE + BEGIN + INSERT INTO [last] + ( [last].username, + [last].seconds, + [last].state + ) + VALUES + ( @Username, + @Seconds, + @State + ) + END +END +GO + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[set_private_data] **/ +/** store user private data by namespace **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[set_private_data] + @Username varchar(250), + @Namespace varchar(250), + @Data varchar(8000) +AS +BEGIN + IF EXISTS (SELECT username FROM private_storage with (nolock) WHERE private_storage.username = @Username AND private_storage.namespace = @Namespace) + BEGIN + UPDATE [private_storage] + SET [private_storage].username = @Username, + [private_storage].namespace = @Namespace, + [private_storage].data = @Data + WHERE private_storage.username = @Username AND private_storage.namespace = @Namespace; + END + ELSE + BEGIN + INSERT INTO [private_storage] + ( [private_storage].username, + [private_storage].namespace, + [private_storage].data + ) + VALUES + ( @Username, + @Namespace, + @Data + ) + END +END +GO + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[get_private_data] **/ +/** Retrieve user private data by namespace **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[get_private_data] + @Username varchar(250), + @Namespace varchar(250) +AS +BEGIN + SELECT private_storage.data AS data + FROM private_storage WITH (NOLOCK) + WHERE username=@Username and namespace=@Namespace; +END +GO + +/***************************************************************/ +/****** Object: StoredProcedure [dbo].[del_user_storage] ******/ +/** Delete private storage area for a given user **/ +/***************************************************************/ +CREATE PROCEDURE [dbo].[del_user_storage] + @Username varchar(250) +AS +BEGIN + DELETE FROM [private_storage] + WITH (ROWLOCK) + WHERE [private_storage].username=@Username; +END +GO + + + diff --git a/src/odbc/mysql.sql b/src/odbc/mysql.sql index bec3f705a..376164a5d 100644 --- a/src/odbc/mysql.sql +++ b/src/odbc/mysql.sql @@ -1,5 +1,5 @@ -- --- ejabberd, Copyright (C) 2002-2008 Process-one +-- ejabberd, Copyright (C) 2002-2008 ProcessOne -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License as diff --git a/src/odbc/odbc_queries.erl b/src/odbc/odbc_queries.erl index 1dac2dfdd..33caa71d1 100644 --- a/src/odbc/odbc_queries.erl +++ b/src/odbc/odbc_queries.erl @@ -5,7 +5,7 @@ %%% Created : by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -322,7 +322,7 @@ update_roster_sql(Username, SJID, ItemVals, ItemGroups) -> " and jid='", SJID, "';"], ["insert into rosterusers(" " username, jid, nick, " - " subscription, ask, askmessage" + " subscription, ask, askmessage, " " server, subscribe, type) " " values (", ItemVals, ");"], ["delete from rostergroups " diff --git a/src/odbc/pg.sql b/src/odbc/pg.sql index 712b4c736..971cde42f 100644 --- a/src/odbc/pg.sql +++ b/src/odbc/pg.sql @@ -1,5 +1,5 @@ -- --- ejabberd, Copyright (C) 2002-2008 Process-one +-- ejabberd, Copyright (C) 2002-2008 ProcessOne -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License as diff --git a/src/p1_fsm.erl b/src/p1_fsm.erl index 4b8f89401..f280286b9 100644 --- a/src/p1_fsm.erl +++ b/src/p1_fsm.erl @@ -13,8 +13,8 @@ %% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings %% AB. All Rights Reserved.'' %% -%% The code has been modified and improved by Process-one. -%% Copyright 2007-2008, Process-one +%% The code has been modified and improved by ProcessOne. +%% Copyright 2007-2008, ProcessOne %% %% The change adds the following features: %% - You can send exit(priority_shutdown) to the p1_fsm process to diff --git a/src/p1_mnesia.erl b/src/p1_mnesia.erl index 9baf44e79..417a7cc08 100644 --- a/src/p1_mnesia.erl +++ b/src/p1_mnesia.erl @@ -9,8 +9,8 @@ %% the License for the specific language governing rights and limitations %% under the License. %% -%% The Initial Developer of the Original Code is Process-one. -%% Portions created by Process-one are Copyright 2006-2008, Process-one +%% The Initial Developer of the Original Code is ProcessOne. +%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne %% All Rights Reserved.'' -module(p1_mnesia). diff --git a/src/pam/epam.c b/src/pam/epam.c index 40dbf78c8..715de9049 100644 --- a/src/pam/epam.c +++ b/src/pam/epam.c @@ -1,5 +1,5 @@ /* - * ejabberd, Copyright (C) 2002-2008 Process-one + * ejabberd, Copyright (C) 2002-2008 ProcessOne * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/pam/epam.erl b/src/pam/epam.erl index df24496ba..dc97da64b 100644 --- a/src/pam/epam.erl +++ b/src/pam/epam.erl @@ -5,7 +5,7 @@ %%% Created : 5 Jul 2007 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/randoms.erl b/src/randoms.erl index 511e06b3f..bb71a23f8 100644 --- a/src/randoms.erl +++ b/src/randoms.erl @@ -5,7 +5,7 @@ %%% Created : 13 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/sha.erl b/src/sha.erl index d4f280119..2b19f55f9 100644 --- a/src/sha.erl +++ b/src/sha.erl @@ -5,7 +5,7 @@ %%% Created : 20 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/shaper.erl b/src/shaper.erl index c3f85039f..cc707dff6 100644 --- a/src/shaper.erl +++ b/src/shaper.erl @@ -5,7 +5,7 @@ %%% Created : 9 Feb 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/stringprep/stringprep.erl b/src/stringprep/stringprep.erl index b47b49f76..3acfa87b7 100644 --- a/src/stringprep/stringprep.erl +++ b/src/stringprep/stringprep.erl @@ -5,7 +5,7 @@ %%% Created : 16 Feb 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/stringprep/stringprep_drv.c b/src/stringprep/stringprep_drv.c index 808229873..ac89eaca7 100644 --- a/src/stringprep/stringprep_drv.c +++ b/src/stringprep/stringprep_drv.c @@ -1,5 +1,5 @@ /* - * ejabberd, Copyright (C) 2002-2008 Process-one + * ejabberd, Copyright (C) 2002-2008 ProcessOne * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/stringprep/stringprep_sup.erl b/src/stringprep/stringprep_sup.erl index dc58e59fd..ba885139a 100644 --- a/src/stringprep/stringprep_sup.erl +++ b/src/stringprep/stringprep_sup.erl @@ -5,7 +5,7 @@ %%% Created : 29 Jun 2007 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/tls/tls.erl b/src/tls/tls.erl index 3e45b2f70..72897cf08 100644 --- a/src/tls/tls.erl +++ b/src/tls/tls.erl @@ -5,7 +5,7 @@ %%% Created : 24 Jul 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/tls/tls_drv.c b/src/tls/tls_drv.c index 5e86e78f5..3efe72cf7 100644 --- a/src/tls/tls_drv.c +++ b/src/tls/tls_drv.c @@ -1,5 +1,5 @@ /* - * ejabberd, Copyright (C) 2002-2008 Process-one + * ejabberd, Copyright (C) 2002-2008 ProcessOne * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/translate.erl b/src/translate.erl index bc1d9e0c9..c3b5b63cd 100644 --- a/src/translate.erl +++ b/src/translate.erl @@ -5,7 +5,7 @@ %%% Created : 6 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/treap.erl b/src/treap.erl index 48361d17d..efe0d477f 100644 --- a/src/treap.erl +++ b/src/treap.erl @@ -5,7 +5,7 @@ %%% Created : 22 Apr 2008 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/web/ejabberd_http.erl b/src/web/ejabberd_http.erl index 34eeef739..5c15fcd16 100644 --- a/src/web/ejabberd_http.erl +++ b/src/web/ejabberd_http.erl @@ -5,7 +5,7 @@ %%% Created : 27 Feb 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -57,6 +57,10 @@ %% {request_handlers, [{["test", "module"], mod_test_web}]}]} %% request_handlers = [], + request_host, + request_port, + request_tp, + request_headers = [], end_of_request = false, trail = "" }). @@ -218,16 +222,24 @@ process_header(State, Data) -> end; {ok, {http_header, _, 'Accept-Language', _, Langs}} -> State#state{request_lang = parse_lang(Langs)}; - {ok, {http_header, _, _, _, _}} -> - State; + {ok, {http_header, _, 'Host', _, Host}} -> + State#state{request_host = Host}; + {ok, {http_header, _, Name, _, Value}} -> + Headers = [{Name, Value} | State#state.request_headers], + State#state{request_headers=Headers}; {ok, http_eoh} -> ?DEBUG("(~w) http query: ~w ~s~n", - [State#state.socket, - State#state.request_method, - element(2, State#state.request_path)]), - Out = process_request(State), - send_text(State, Out), - case State#state.request_keepalive of + [State#state.socket, + State#state.request_method, + element(2, State#state.request_path)]), + {Host, Port, TP} = get_transfer_protocol(SockMod, + State#state.request_host), + State2 = State#state{request_host = Host, + request_port = Port, + request_tp = TP}, + Out = process_request(State2), + send_text(State2, Out), + case State2#state.request_keepalive of true -> case SockMod of gen_tcp -> @@ -250,6 +262,27 @@ process_header(State, Data) -> request_handlers = State#state.request_handlers} 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) -> + [Host | PortList] = string:tokens(HostPort, ":"), + case {SockMod, PortList} of + {gen_tcp, []} -> + {Host, 80, http}; + {gen_tcp, [Port]} -> + {Host, list_to_integer(Port), http}; + {tls, []} -> + {Host, 443, https}; + {tls, [Port]} -> + {Host, list_to_integer(Port), https} + end. + %% XXX bard: search through request handlers looking for one that %% matches the requested URL path, and pass control to it. If none is %% found, answer with HTTP 404. @@ -276,6 +309,10 @@ process_request(#state{request_method = Method, request_auth = Auth, request_lang = Lang, request_handlers = RequestHandlers, + request_host = Host, + request_port = Port, + request_tp = TP, + request_headers = RequestHeaders, sockmod = SockMod, socket = Socket} = State) when Method=:='GET' orelse Method=:='HEAD' orelse Method=:='DELETE' -> @@ -302,6 +339,10 @@ process_request(#state{request_method = Method, q = LQuery, auth = Auth, lang = Lang, + host = Host, + port = Port, + tp = TP, + headers = RequestHeaders, ip = IP}, %% XXX bard: This previously passed control to %% ejabberd_web:process_get, now passes it to a local @@ -327,6 +368,10 @@ process_request(#state{request_method = Method, request_lang = Lang, sockmod = SockMod, socket = Socket, + request_host = Host, + request_port = Port, + request_tp = TP, + request_headers = RequestHeaders, request_handlers = RequestHandlers} = State) when (Method=:='POST' orelse Method=:='PUT') andalso is_integer(Len) -> case SockMod of @@ -361,6 +406,10 @@ process_request(#state{request_method = Method, auth = Auth, data = Data, lang = Lang, + host = Host, + port = Port, + tp = TP, + headers = RequestHeaders, ip = IP}, case process(RequestHandlers, Request) of El when element(1, El) == xmlelement -> @@ -391,7 +440,10 @@ recv_data(_State, 0, Acc) -> recv_data(State, Len, Acc) -> case State#state.trail of [] -> - case (State#state.sockmod):recv(State#state.socket, Len, 300000) of + %% TODO: Fix the problem in tls C driver and revert this workaround + %% https://support.process-one.net/browse/EJAB-611 + %%case (State#state.sockmod):recv(State#state.socket, Len, 300000) of + case (State#state.sockmod):recv(State#state.socket, 0, 300000) of {ok, Data} -> recv_data(State, Len - size(Data), [Acc | Data]); _ -> diff --git a/src/web/ejabberd_http.hrl b/src/web/ejabberd_http.hrl index 4bcf047ec..c8f8a4e21 100644 --- a/src/web/ejabberd_http.hrl +++ b/src/web/ejabberd_http.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -26,5 +26,9 @@ auth, lang = "", data = "", - ip + ip, + host, % string() + port, % integer() + tp, % transfer protocol = http | https + headers }). diff --git a/src/web/ejabberd_http_poll.erl b/src/web/ejabberd_http_poll.erl index 2b36136cd..9c2cdee46 100644 --- a/src/web/ejabberd_http_poll.erl +++ b/src/web/ejabberd_http_poll.erl @@ -5,7 +5,7 @@ %%% Created : 4 Mar 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/web/ejabberd_web.erl b/src/web/ejabberd_web.erl index 56f65a0b9..166d430ff 100644 --- a/src/web/ejabberd_web.erl +++ b/src/web/ejabberd_web.erl @@ -5,7 +5,7 @@ %%% Created : 28 Feb 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index d133fa14d..9497efeb9 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -5,7 +5,7 @@ %%% Created : 9 Apr 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/web/ejabberd_web_admin.hrl b/src/web/ejabberd_web_admin.hrl index 7c37d076f..ddceaa1ee 100644 --- a/src/web/ejabberd_web_admin.hrl +++ b/src/web/ejabberd_web_admin.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/xml.erl b/src/xml.erl index 4fb998c58..1eb4a8606 100644 --- a/src/xml.erl +++ b/src/xml.erl @@ -5,7 +5,7 @@ %%% Created : 20 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/xml_stream.erl b/src/xml_stream.erl index 7976ba53b..332bb4d34 100644 --- a/src/xml_stream.erl +++ b/src/xml_stream.erl @@ -5,7 +5,7 @@ %%% Created : 17 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 Process-one +%%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as From 56a0c8ed1d94bba32a98b65496aa81294dda6b7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 18 Sep 2008 14:55:03 +0000 Subject: [PATCH 068/582] Convert to exmpp. SVN Revision: 1565 --- ChangeLog | 4 + src/mod_roster_odbc.erl | 987 ++++++++++++++++++++-------------------- 2 files changed, 504 insertions(+), 487 deletions(-) diff --git a/ChangeLog b/ChangeLog index b7c0329aa..fbaad6a97 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2008-09-18 Jean-Sébastien Pédron + + * src/mod_roster_odbc.erl: Convert to exmpp. + 2008-09-16 Jean-Sébastien Pédron Merge from trunk (r1457 to r1563). diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 94b45ead8..aabe62e65 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -43,8 +43,9 @@ webadmin_page/3, webadmin_user/4]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("mod_roster.hrl"). -include("web/ejabberd_http.hrl"). -include("web/ejabberd_web_admin.hrl"). @@ -99,39 +100,32 @@ stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ROSTER). -process_iq(From, To, IQ) -> - #iq{sub_el = SubEl} = IQ, - #jid{lserver = LServer} = From, +process_iq(From, To, IQ_Rec) -> + #jid{ldomain = LServer} = From, case lists:member(LServer, ?MYHOSTS) of true -> - process_local_iq(From, To, IQ); + process_local_iq(From, To, IQ_Rec); _ -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]} + exmpp_iq:error(IQ_Rec, 'item-not-found') end. -process_local_iq(From, To, #iq{type = Type} = IQ) -> - case Type of - set -> - process_iq_set(From, To, IQ); - get -> - process_iq_get(From, To, IQ) - end. +process_local_iq(From, To, #iq{type = get} = IQ_Rec) -> + process_iq_get(From, To, IQ_Rec); +process_local_iq(From, To, #iq{type = set} = IQ_Rec) -> + process_iq_set(From, To, IQ_Rec). -process_iq_get(From, To, #iq{sub_el = SubEl} = IQ) -> - LUser = From#jid.luser, - LServer = From#jid.lserver, - US = {LUser, LServer}, - case catch ejabberd_hooks:run_fold(roster_get, To#jid.lserver, [], [US]) of +process_iq_get(From, To, IQ_Rec) -> + US = {From#jid.lnode, From#jid.ldomain}, + case catch ejabberd_hooks:run_fold(roster_get, To#jid.ldomain, [], [US]) of Items when is_list(Items) -> XItems = lists:map(fun item_to_xml/1, Items), - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_ROSTER}], - XItems}]}; + Result = #xmlel{ns = ?NS_ROSTER, name = 'query', + children = XItems}, + exmpp_iq:result(IQ_Rec, Result); _ -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]} + exmpp_iq:error(IQ_Rec, 'internal-server-error') end. get_user_roster(Acc, {LUser, LServer}) -> @@ -162,7 +156,8 @@ get_roster(LUser, LServer) -> error -> []; R -> - SJID = jlib:jid_to_string(R#roster.jid), + {U2, S2, R2} = R#roster.jid, + SJID = exmpp_jid:jid_to_list(U2, S2, R2), Groups = lists:flatmap( fun({S, G}) when S == SJID -> [G]; @@ -179,154 +174,142 @@ get_roster(LUser, LServer) -> item_to_xml(Item) -> - Attrs1 = [{"jid", jlib:jid_to_string(Item#roster.jid)}], + {U, S, R} = Item#roster.jid, + Attrs1 = exmpp_xml:set_attribute_in_list([], + 'jid', exmpp_jid:jid_to_list(U, S, R)), Attrs2 = case Item#roster.name of "" -> Attrs1; Name -> - [{"name", Name} | Attrs1] - end, - Attrs3 = case Item#roster.subscription of - none -> - [{"subscription", "none"} | Attrs2]; - from -> - [{"subscription", "from"} | Attrs2]; - to -> - [{"subscription", "to"} | Attrs2]; - both -> - [{"subscription", "both"} | Attrs2]; - remove -> - [{"subscription", "remove"} | Attrs2] + exmpp_xml:set_attribute_in_list(Attrs1, 'name', Name) end, + Attrs3 = exmpp_xml:set_attribute_in_list(Attrs2, + 'subscription', Item#roster.subscription), Attrs = case ask_to_pending(Item#roster.ask) of out -> - [{"ask", "subscribe"} | Attrs3]; + exmpp_xml:set_attribute_in_list(Attrs3, + 'ask', "subscribe"); both -> - [{"ask", "subscribe"} | Attrs3]; + exmpp_xml:set_attribute_in_list(Attrs3, + 'ask', "subscribe"); _ -> Attrs3 end, SubEls = lists:map(fun(G) -> - {xmlelement, "group", [], [{xmlcdata, G}]} + exmpp_xml:set_cdata( + #xmlel{ns = ?NS_ROSTER, name = 'group'}, G) end, Item#roster.groups), - {xmlelement, "item", Attrs, SubEls}. + #xmlel{ns = ?NS_ROSTER, name = 'item', attrs = Attrs, children = SubEls}. -process_iq_set(From, To, #iq{sub_el = SubEl} = IQ) -> - {xmlelement, _Name, _Attrs, Els} = SubEl, - lists:foreach(fun(El) -> process_item_set(From, To, El) end, Els), - IQ#iq{type = result, sub_el = []}. - -process_item_set(From, To, {xmlelement, _Name, Attrs, Els}) -> - JID1 = jlib:string_to_jid(xml:get_attr_s("jid", Attrs)), - #jid{user = User, luser = LUser, lserver = LServer} = From, - case JID1 of - error -> - ok; +process_iq_set(From, To, #iq{payload = Request} = IQ_Rec) -> + case Request of + #xmlel{children = Els} -> + lists:foreach(fun(El) -> process_item_set(From, To, El) end, Els); _ -> - LJID = jlib:jid_tolower(JID1), - Username = ejabberd_odbc:escape(LUser), - SJID = ejabberd_odbc:escape(jlib:jid_to_string(LJID)), - F = fun() -> - {selected, - ["username", "jid", "nick", "subscription", - "ask", "askmessage", "server", "subscribe", "type"], - Res} = odbc_queries:get_roster_by_jid(LServer, Username, SJID), - Item = case Res of - [] -> - #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, - jid = LJID}; - [I] -> - R = raw_to_record(LServer, I), - case R of - %% Bad JID in database: - error -> - #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, - jid = LJID}; - _ -> - R#roster{ - usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, - jid = LJID, - name = ""} - end - end, - Item1 = process_item_attrs(Item, Attrs), - Item2 = process_item_els(Item1, Els), - case Item2#roster.subscription of - remove -> - odbc_queries:del_roster(LServer, Username, SJID); - _ -> - ItemVals = record_to_string(Item2), - ItemGroups = groups_to_string(Item2), - odbc_queries:update_roster(LServer, Username, SJID, ItemVals, ItemGroups) - end, - %% If the item exist in shared roster, take the - %% subscription information from there: - Item3 = ejabberd_hooks:run_fold(roster_process_item, - LServer, Item2, [LServer]), - {Item, Item3} - end, - case odbc_queries:sql_transaction(LServer, F) of - {atomic, {OldItem, Item}} -> - push_item(User, LServer, To, Item), - case Item#roster.subscription of + ok + end, + exmpp_iq:result(IQ_Rec). + +process_item_set(From, To, #xmlel{} = El) -> + try + JID1 = exmpp_jid:list_to_jid(exmpp_xml:get_attribute(El, 'jid', "")), + #jid{node = User, lnode = LUser, ldomain = LServer} = From, + LJID = jlib:short_prepd_jid(JID1), + Username = ejabberd_odbc:escape(LUser), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(LJID)), + F = fun() -> + {selected, + ["username", "jid", "nick", "subscription", + "ask", "askmessage", "server", "subscribe", "type"], + Res} = odbc_queries:get_roster_by_jid(LServer, Username, SJID), + Item = case Res of + [] -> + #roster{usj = {LUser, LServer, LJID}, + us = {LUser, LServer}, + jid = LJID}; + [I] -> + R = raw_to_record(LServer, I), + case R of + %% Bad JID in database: + error -> + #roster{usj = {LUser, LServer, LJID}, + us = {LUser, LServer}, + jid = LJID}; + _ -> + R#roster{ + usj = {LUser, LServer, LJID}, + us = {LUser, LServer}, + jid = LJID, + name = ""} + end + end, + Item1 = process_item_attrs(Item, El#xmlel.attrs), + Item2 = process_item_els(Item1, El#xmlel.children), + case Item2#roster.subscription of remove -> - IsTo = case OldItem#roster.subscription of - both -> true; - to -> true; - _ -> false - end, - IsFrom = case OldItem#roster.subscription of - both -> true; - from -> true; - _ -> false - end, - if IsTo -> - ejabberd_router:route( - jlib:jid_remove_resource(From), - jlib:make_jid(OldItem#roster.jid), - {xmlelement, "presence", - [{"type", "unsubscribe"}], - []}); - true -> ok - end, - if IsFrom -> - ejabberd_router:route( - jlib:jid_remove_resource(From), - jlib:make_jid(OldItem#roster.jid), - {xmlelement, "presence", - [{"type", "unsubscribed"}], - []}); - true -> ok - end, - ok; + odbc_queries:del_roster(LServer, Username, SJID); _ -> - ok - end; - E -> - ?DEBUG("ROSTER: roster item set error: ~p~n", [E]), - ok - end + ItemVals = record_to_string(Item2), + ItemGroups = groups_to_string(Item2), + odbc_queries:update_roster(LServer, Username, SJID, ItemVals, ItemGroups) + end, + %% If the item exist in shared roster, take the + %% subscription information from there: + Item3 = ejabberd_hooks:run_fold(roster_process_item, + LServer, Item2, [LServer]), + {Item, Item3} + end, + case odbc_queries:sql_transaction(LServer, F) of + {atomic, {OldItem, Item}} -> + push_item(User, LServer, To, Item), + case Item#roster.subscription of + remove -> + IsTo = case OldItem#roster.subscription of + both -> true; + to -> true; + _ -> false + end, + IsFrom = case OldItem#roster.subscription of + both -> true; + from -> true; + _ -> false + end, + {U, S, R} = OldItem#roster.jid, + if IsTo -> + ejabberd_router:route( + exmpp_jid:jid_to_bare_jid(From), + exmpp_jid:make_jid(U, S, R), + exmpp_presence:unsubscribe()); + true -> ok + end, + if IsFrom -> + ejabberd_router:route( + exmpp_jid:jid_to_bare_jid(From), + exmpp_jid:make_jid(U, S, R), + exmpp_presence:unsubscribed()); + true -> ok + end, + ok; + _ -> + ok + end; + E -> + ?DEBUG("ROSTER: roster item set error: ~p~n", [E]), + ok + end + catch + _ -> + ok end; process_item_set(_From, _To, _) -> ok. -process_item_attrs(Item, [{Attr, Val} | Attrs]) -> +process_item_attrs(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> case Attr of - "jid" -> - case jlib:string_to_jid(Val) of - error -> - process_item_attrs(Item, Attrs); - JID1 -> - JID = {JID1#jid.luser, JID1#jid.lserver, JID1#jid.lresource}, - process_item_attrs(Item#roster{jid = JID}, Attrs) - end; - "name" -> + 'name' -> process_item_attrs(Item#roster{name = Val}, Attrs); - "subscription" -> + 'subscription' -> case Val of "remove" -> process_item_attrs(Item#roster{subscription = remove}, @@ -334,7 +317,7 @@ process_item_attrs(Item, [{Attr, Val} | Attrs]) -> _ -> process_item_attrs(Item, Attrs) end; - "ask" -> + 'ask' -> process_item_attrs(Item, Attrs); _ -> process_item_attrs(Item, Attrs) @@ -343,24 +326,24 @@ process_item_attrs(Item, []) -> Item. -process_item_els(Item, [{xmlelement, Name, _Attrs, SEls} | Els]) -> +process_item_els(Item, [#xmlel{name = Name} = El | Els]) -> case Name of - "group" -> - Groups = [xml:get_cdata(SEls) | Item#roster.groups], + 'group' -> + Groups = [exmpp_xml:get_cdata(El) | Item#roster.groups], process_item_els(Item#roster{groups = Groups}, Els); _ -> process_item_els(Item, Els) end; -process_item_els(Item, [{xmlcdata, _} | Els]) -> +process_item_els(Item, [_ | Els]) -> process_item_els(Item, Els); process_item_els(Item, []) -> Item. push_item(User, Server, From, Item) -> - ejabberd_sm:route(jlib:make_jid("", "", ""), - jlib:make_jid(User, Server, ""), - {xmlelement, "broadcast", [], + ejabberd_sm:route(#jid{}, + exmpp_jid:make_bare_jid(User, Server), + #xmlel{name = 'broadcast', children = [{item, Item#roster.jid, Item#roster.subscription}]}), @@ -370,25 +353,28 @@ push_item(User, Server, From, Item) -> % TODO: don't push to those who not load roster push_item(User, Server, Resource, From, Item) -> - ResIQ = #iq{type = set, xmlns = ?NS_ROSTER, - id = "push", - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_ROSTER}], - [item_to_xml(Item)]}]}, + Request = #xmlel{ns = ?NS_ROSTER, name = 'query', + children = item_to_xml(Item)}, + ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request, "push"), ejabberd_router:route( From, - jlib:make_jid(User, Server, Resource), - jlib:iq_to_xml(ResIQ)). + exmpp_jid:make_jid(User, Server, Resource), + ResIQ). get_subscription_lists(_, User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - Username = ejabberd_odbc:escape(LUser), - case catch odbc_queries:get_roster(LServer, Username) of - {selected, ["username", "jid", "nick", "subscription", "ask", - "askmessage", "server", "subscribe", "type"], - Items} when is_list(Items) -> - fill_subscription_lists(LServer, Items, [], []); + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + Username = ejabberd_odbc:escape(LUser), + case catch odbc_queries:get_roster(LServer, Username) of + {selected, ["username", "jid", "nick", "subscription", "ask", + "askmessage", "server", "subscribe", "type"], + Items} when is_list(Items) -> + fill_subscription_lists(LServer, Items, [], []); + _ -> + {[], []} + end + catch _ -> {[], []} end. @@ -428,104 +414,105 @@ out_subscription(User, Server, JID, Type) -> process_subscription(out, User, Server, JID, Type, []). process_subscription(Direction, User, Server, JID1, Type, Reason) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - LJID = jlib:jid_tolower(JID1), - Username = ejabberd_odbc:escape(LUser), - SJID = ejabberd_odbc:escape(jlib:jid_to_string(LJID)), - F = fun() -> - Item = - case odbc_queries:get_roster_by_jid(LServer, Username, SJID) of - {selected, - ["username", "jid", "nick", "subscription", "ask", - "askmessage", "server", "subscribe", "type"], - [I]} -> - %% raw_to_record can return error, but - %% jlib_to_string would fail before this point - R = raw_to_record(LServer, I), - Groups = - case odbc_queries:get_roster_groups(LServer, Username, SJID) of - {selected, ["grp"], JGrps} when is_list(JGrps) -> - [JGrp || {JGrp} <- JGrps]; - _ -> - [] - end, - R#roster{groups = Groups}; - {selected, - ["username", "jid", "nick", "subscription", "ask", - "askmessage", "server", "subscribe", "type"], - []} -> - #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, - jid = LJID} - end, - NewState = case Direction of - out -> - out_state_change(Item#roster.subscription, - Item#roster.ask, - Type); - in -> - in_state_change(Item#roster.subscription, - Item#roster.ask, - Type) - end, - AutoReply = case Direction of - out -> - none; - in -> - in_auto_reply(Item#roster.subscription, - Item#roster.ask, - Type) - end, - AskMessage = case NewState of - {_, both} -> Reason; - {_, in} -> Reason; - _ -> "" - end, - case NewState of - none -> - {none, AutoReply}; - {none, none} when Item#roster.subscription == none, - Item#roster.ask == in -> - odbc_queries:del_roster(LServer, Username, SJID), - {none, AutoReply}; - {Subscription, Pending} -> - NewItem = Item#roster{subscription = Subscription, - ask = Pending, - askmessage = AskMessage}, - ItemVals = record_to_string(NewItem), - odbc_queries:roster_subscribe(LServer, Username, SJID, ItemVals), - {{push, NewItem}, AutoReply} - end - end, - case odbc_queries:sql_transaction(LServer, F) of - {atomic, {Push, AutoReply}} -> - case AutoReply of - none -> - ok; - _ -> - T = case AutoReply of - subscribed -> "subscribed"; - unsubscribed -> "unsubscribed" + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + LJID = exmpp_jid:jid_to_bare_jid(JID1), + Username = ejabberd_odbc:escape(LUser), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(LJID)), + F = fun() -> + Item = + case odbc_queries:get_roster_by_jid(LServer, Username, SJID) of + {selected, + ["username", "jid", "nick", "subscription", "ask", + "askmessage", "server", "subscribe", "type"], + [I]} -> + %% raw_to_record can return error, but + %% jlib_to_string would fail before this point + R = raw_to_record(LServer, I), + Groups = + case odbc_queries:get_roster_groups(LServer, Username, SJID) of + {selected, ["grp"], JGrps} when is_list(JGrps) -> + [JGrp || {JGrp} <- JGrps]; + _ -> + [] + end, + R#roster{groups = Groups}; + {selected, + ["username", "jid", "nick", "subscription", "ask", + "askmessage", "server", "subscribe", "type"], + []} -> + #roster{usj = {LUser, LServer, LJID}, + us = {LUser, LServer}, + jid = LJID} end, - ejabberd_router:route( - jlib:make_jid(User, Server, ""), JID1, - {xmlelement, "presence", [{"type", T}], []}) + NewState = case Direction of + out -> + out_state_change(Item#roster.subscription, + Item#roster.ask, + Type); + in -> + in_state_change(Item#roster.subscription, + Item#roster.ask, + Type) + end, + AutoReply = case Direction of + out -> + none; + in -> + in_auto_reply(Item#roster.subscription, + Item#roster.ask, + Type) + end, + AskMessage = case NewState of + {_, both} -> Reason; + {_, in} -> Reason; + _ -> "" + end, + case NewState of + none -> + {none, AutoReply}; + {none, none} when Item#roster.subscription == none, + Item#roster.ask == in -> + odbc_queries:del_roster(LServer, Username, SJID), + {none, AutoReply}; + {Subscription, Pending} -> + NewItem = Item#roster{subscription = Subscription, + ask = Pending, + askmessage = list_to_binary(AskMessage)}, + ItemVals = record_to_string(NewItem), + odbc_queries:roster_subscribe(LServer, Username, SJID, ItemVals), + {{push, NewItem}, AutoReply} + end end, - case Push of - {push, Item} -> - if - Item#roster.subscription == none, - Item#roster.ask == in -> - ok; - true -> - push_item(User, Server, - jlib:make_jid(User, Server, ""), Item) - end, - true; - none -> - false - end; + case odbc_queries:sql_transaction(LServer, F) of + {atomic, {Push, AutoReply}} -> + case AutoReply of + none -> + ok; + _ -> + ejabberd_router:route( + exmpp_jid:make_bare_jid(User, Server), JID1, + exmpp_presence:AutoReply()) + end, + case Push of + {push, Item} -> + if + Item#roster.subscription == none, + Item#roster.ask == in -> + ok; + true -> + push_item(User, Server, + exmpp_jid:make_bare_jid(User, Server), Item) + end, + true; + none -> + false + end; + _ -> + false + end + catch _ -> false end. @@ -628,63 +615,64 @@ in_auto_reply(_, _, _) -> none. remove_user(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - Username = ejabberd_odbc:escape(LUser), - odbc_queries:del_user_roster_t(LServer, Username), - ok. + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + Username = ejabberd_odbc:escape(LUser), + odbc_queries:del_user_roster_t(LServer, Username), + ok + catch + _ -> + ok + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -set_items(User, Server, SubEl) -> - {xmlelement, _Name, _Attrs, Els} = SubEl, - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - catch odbc_queries:sql_transaction( - LServer, - lists:map(fun(El) -> - process_item_set_t(LUser, LServer, El) - end, Els)). - -process_item_set_t(LUser, LServer, {xmlelement, _Name, Attrs, Els}) -> - JID1 = jlib:string_to_jid(xml:get_attr_s("jid", Attrs)), - case JID1 of - error -> - []; +set_items(User, Server, #xmlel{children = Els}) -> + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + catch odbc_queries:sql_transaction( + LServer, + lists:map(fun(El) -> + process_item_set_t(LUser, LServer, El) + end, Els)) + catch _ -> - LJID = {JID1#jid.luser, JID1#jid.lserver, JID1#jid.lresource}, - Username = ejabberd_odbc:escape(LUser), - SJID = ejabberd_odbc:escape(jlib:jid_to_string(LJID)), - Item = #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, - jid = LJID}, - Item1 = process_item_attrs_ws(Item, Attrs), - Item2 = process_item_els(Item1, Els), - case Item2#roster.subscription of - remove -> - odbc_queries:del_roster_sql(Username, SJID); - _ -> - ItemVals = record_to_string(Item1), - ItemGroups = groups_to_string(Item2), - odbc_queries:update_roster_sql(Username, SJID, ItemVals, ItemGroups) - end + ok + end. + +process_item_set_t(LUser, LServer, #xmlel{} = El) -> + try + JID1 = exmpp_jid:list_to_jid(exmpp_xml:get_attribute(El, 'jid', "")), + LJID = jlib:short_prepd_jid(JID1), + Username = ejabberd_odbc:escape(LUser), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(LJID)), + Item = #roster{usj = {LUser, LServer, LJID}, + us = {LUser, LServer}, + jid = LJID}, + Item1 = process_item_attrs_ws(Item, El#xmlel.attrs), + Item2 = process_item_els(Item1, El#xmlel.children), + case Item2#roster.subscription of + remove -> + odbc_queries:del_roster_sql(Username, SJID); + _ -> + ItemVals = record_to_string(Item1), + ItemGroups = groups_to_string(Item2), + odbc_queries:update_roster_sql(Username, SJID, ItemVals, ItemGroups) + end + catch + _ -> + [] end; process_item_set_t(_LUser, _LServer, _) -> []. -process_item_attrs_ws(Item, [{Attr, Val} | Attrs]) -> +process_item_attrs_ws(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> case Attr of - "jid" -> - case jlib:string_to_jid(Val) of - error -> - process_item_attrs_ws(Item, Attrs); - JID1 -> - JID = {JID1#jid.luser, JID1#jid.lserver, JID1#jid.lresource}, - process_item_attrs_ws(Item#roster{jid = JID}, Attrs) - end; - "name" -> + 'name' -> process_item_attrs_ws(Item#roster{name = Val}, Attrs); - "subscription" -> + 'subscription' -> case Val of "remove" -> process_item_attrs_ws(Item#roster{subscription = remove}, @@ -704,7 +692,7 @@ process_item_attrs_ws(Item, [{Attr, Val} | Attrs]) -> _ -> process_item_attrs_ws(Item, Attrs) end; - "ask" -> + 'ask' -> process_item_attrs_ws(Item, Attrs); _ -> process_item_attrs_ws(Item, Attrs) @@ -713,9 +701,9 @@ process_item_attrs_ws(Item, []) -> Item. get_in_pending_subscriptions(Ls, User, Server) -> - JID = jlib:make_jid(User, Server, ""), - LUser = JID#jid.luser, - LServer = JID#jid.lserver, + JID = exmpp_jid:make_bare_jid(User, Server), + LUser = JID#jid.lnode, + LServer = JID#jid.ldomain, Username = ejabberd_odbc:escape(LUser), case catch odbc_queries:get_roster(LServer, Username) of {selected, ["username", "jid", "nick", "subscription", "ask", @@ -724,12 +712,12 @@ get_in_pending_subscriptions(Ls, User, Server) -> Ls ++ lists:map( fun(R) -> Message = R#roster.askmessage, - {xmlelement, "presence", - [{"from", jlib:jid_to_string(R#roster.jid)}, - {"to", jlib:jid_to_string(JID)}, - {"type", "subscribe"}], - [{xmlelement, "status", [], - [{xmlcdata, Message}]}]} + {U, S, R} = R#roster.jid, + Pres1 = exmpp_presence:subscribe(), + Pres2 = exmpp_stanza:set_jids(Pres1, + exmpp_jid:jid_to_list(U, S, R), + exmpp_jid:jid_to_list(JID)), + exmpp_presence:set_status(Pres2, Message) end, lists:flatmap( fun(I) -> @@ -754,84 +742,90 @@ get_in_pending_subscriptions(Ls, User, Server) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% get_jid_info(_, User, Server, JID) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - LJID = jlib:jid_tolower(JID), - Username = ejabberd_odbc:escape(LUser), - SJID = ejabberd_odbc:escape(jlib:jid_to_string(LJID)), - case catch odbc_queries:get_subscription(LServer, Username, SJID) of - {selected, ["subscription"], [{SSubscription}]} -> - Subscription = case SSubscription of - "B" -> both; - "T" -> to; - "F" -> from; - _ -> none - end, - Groups = case catch odbc_queries:get_rostergroup_by_jid(LServer, Username, SJID) of - {selected, ["grp"], JGrps} when is_list(JGrps) -> - [JGrp || {JGrp} <- JGrps]; - _ -> - [] - end, - {Subscription, Groups}; + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + LJID = jlib:short_prepd_jid(JID), + Username = ejabberd_odbc:escape(LUser), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(LJID)), + case catch odbc_queries:get_subscription(LServer, Username, SJID) of + {selected, ["subscription"], [{SSubscription}]} -> + Subscription = case SSubscription of + "B" -> both; + "T" -> to; + "F" -> from; + _ -> none + end, + Groups = case catch odbc_queries:get_rostergroup_by_jid(LServer, Username, SJID) of + {selected, ["grp"], JGrps} when is_list(JGrps) -> + [JGrp || {JGrp} <- JGrps]; + _ -> + [] + end, + {Subscription, Groups}; + _ -> + LRJID = jlib:short_prepd_bare_jid(JID), + if + LRJID == LJID -> + {none, []}; + true -> + SRJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(LRJID)), + case catch odbc_queries:get_subscription(LServer, Username, SRJID) of + {selected, ["subscription"], [{SSubscription}]} -> + Subscription = case SSubscription of + "B" -> both; + "T" -> to; + "F" -> from; + _ -> none + end, + Groups = case catch odbc_queries:get_rostergroup_by_jid(LServer, Username, SRJID) of + {selected, ["grp"], JGrps} when is_list(JGrps) -> + [JGrp || {JGrp} <- JGrps]; + _ -> + [] + end, + {Subscription, Groups}; + _ -> + {none, []} + end + end + end + catch _ -> - LRJID = jlib:jid_tolower(jlib:jid_remove_resource(JID)), - if - LRJID == LJID -> - {none, []}; - true -> - SRJID = ejabberd_odbc:escape(jlib:jid_to_string(LRJID)), - case catch odbc_queries:get_subscription(LServer, Username, SRJID) of - {selected, ["subscription"], [{SSubscription}]} -> - Subscription = case SSubscription of - "B" -> both; - "T" -> to; - "F" -> from; - _ -> none - end, - Groups = case catch odbc_queries:get_rostergroup_by_jid(LServer, Username, SRJID) of - {selected, ["grp"], JGrps} when is_list(JGrps) -> - [JGrp || {JGrp} <- JGrps]; - _ -> - [] - end, - {Subscription, Groups}; - _ -> - {none, []} - end - end + {none, []} end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% raw_to_record(LServer, {User, SJID, Nick, SSubscription, SAsk, SAskMessage, _SServer, _SSubscribe, _SType}) -> - case jlib:string_to_jid(SJID) of - error -> - error; - JID -> - LJID = jlib:jid_tolower(JID), - Subscription = case SSubscription of - "B" -> both; - "T" -> to; - "F" -> from; - _ -> none - end, - Ask = case SAsk of - "S" -> subscribe; - "U" -> unsubscribe; - "B" -> both; - "O" -> out; - "I" -> in; - _ -> none - end, - #roster{usj = {User, LServer, LJID}, - us = {User, LServer}, - jid = LJID, - name = Nick, - subscription = Subscription, - ask = Ask, - askmessage = SAskMessage} + try + JID = exmpp_jid:list_to_jid(SJID), + LJID = jlib:short_prepd_jid(JID), + Subscription = case SSubscription of + "B" -> both; + "T" -> to; + "F" -> from; + _ -> none + end, + Ask = case SAsk of + "S" -> subscribe; + "U" -> unsubscribe; + "B" -> both; + "O" -> out; + "I" -> in; + _ -> none + end, + #roster{usj = {User, LServer, LJID}, + us = {User, LServer}, + jid = LJID, + name = Nick, + subscription = Subscription, + ask = Ask, + askmessage = list_to_binary(SAskMessage)} + catch + _ -> + error end. record_to_string(#roster{us = {User, _Server}, @@ -841,7 +835,8 @@ record_to_string(#roster{us = {User, _Server}, ask = Ask, askmessage = AskMessage}) -> Username = ejabberd_odbc:escape(User), - SJID = ejabberd_odbc:escape(jlib:jid_to_string(jlib:jid_tolower(JID))), + {U, S, R} = jlib:short_prepd_jid(JID), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(U, S, R)), Nick = ejabberd_odbc:escape(Name), SSubscription = case Subscription of both -> "B"; @@ -857,7 +852,7 @@ record_to_string(#roster{us = {User, _Server}, in -> "I"; none -> "N" end, - SAskMessage = ejabberd_odbc:escape(AskMessage), + SAskMessage = ejabberd_odbc:escape(binary_to_list(AskMessage)), ["'", Username, "'," "'", SJID, "'," "'", Nick, "'," @@ -870,7 +865,8 @@ groups_to_string(#roster{us = {User, _Server}, jid = JID, groups = Groups}) -> Username = ejabberd_odbc:escape(User), - SJID = ejabberd_odbc:escape(jlib:jid_to_string(jlib:jid_tolower(JID))), + {U, S, R} = jlib:short_prepd_jid(JID), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(U, S, R)), %% Empty groups do not need to be converted to string to be inserted in %% the database @@ -892,75 +888,87 @@ webadmin_page(_, Host, webadmin_page(Acc, _, _) -> Acc. user_roster(User, Server, Query, Lang) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - US = {LUser, LServer}, - Items1 = get_roster(LUser, LServer), - Res = user_roster_parse_query(User, Server, Items1, Query), - Items = get_roster(LUser, LServer), - SItems = lists:sort(Items), - FItems = - case SItems of - [] -> - [?CT("None")]; - _ -> - [?XE("table", - [?XE("thead", - [?XE("tr", - [?XCT("td", "Jabber ID"), - ?XCT("td", "Nickname"), - ?XCT("td", "Subscription"), - ?XCT("td", "Pending"), - ?XCT("td", "Groups") - ])]), - ?XE("tbody", - lists:map( - fun(R) -> - Groups = - lists:flatmap( - fun(Group) -> - [?C(Group), ?BR] - end, R#roster.groups), - Pending = ask_to_pending(R#roster.ask), - ?XE("tr", - [?XAC("td", [{"class", "valign"}], - jlib:jid_to_string(R#roster.jid)), - ?XAC("td", [{"class", "valign"}], - R#roster.name), - ?XAC("td", [{"class", "valign"}], - atom_to_list(R#roster.subscription)), - ?XAC("td", [{"class", "valign"}], - atom_to_list(Pending)), - ?XAE("td", [{"class", "valign"}], Groups), - if - Pending == in -> - ?XAE("td", [{"class", "valign"}], - [?INPUTT("submit", - "validate" ++ - ejabberd_web_admin:term_to_id(R#roster.jid), - "Validate")]); - true -> - ?X("td") - end, - ?XAE("td", [{"class", "valign"}], - [?INPUTT("submit", - "remove" ++ - ejabberd_web_admin:term_to_id(R#roster.jid), - "Remove")])]) - end, SItems))])] - end, - [?XC("h1", ?T("Roster of ") ++ us_to_list(US))] ++ - case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; - nothing -> [] - end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], - FItems ++ - [?P, - ?INPUT("text", "newjid", ""), ?C(" "), - ?INPUTT("submit", "addjid", "Add Jabber ID") - ])]. + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + Items1 = get_roster(LUser, LServer), + Res = user_roster_parse_query(User, Server, Items1, Query), + Items = get_roster(LUser, LServer), + SItems = lists:sort(Items), + FItems = + case SItems of + [] -> + [?CT("None")]; + _ -> + [?XE("table", + [?XE("thead", + [?XE("tr", + [?XCT("td", "Jabber ID"), + ?XCT("td", "Nickname"), + ?XCT("td", "Subscription"), + ?XCT("td", "Pending"), + ?XCT("td", "Groups") + ])]), + ?XE("tbody", + lists:map( + fun(R) -> + Groups = + lists:flatmap( + fun(Group) -> + [?C(Group), ?BR] + end, R#roster.groups), + Pending = ask_to_pending(R#roster.ask), + {U, S, R} = R#roster.jid, + ?XE("tr", + [?XAC("td", [{"class", "valign"}], + catch exmpp_jid:jid_to_list(U, S, R)), + ?XAC("td", [{"class", "valign"}], + R#roster.name), + ?XAC("td", [{"class", "valign"}], + atom_to_list(R#roster.subscription)), + ?XAC("td", [{"class", "valign"}], + atom_to_list(Pending)), + ?XAE("td", [{"class", "valign"}], Groups), + if + Pending == in -> + ?XAE("td", [{"class", "valign"}], + [?INPUTT("submit", + "validate" ++ + ejabberd_web_admin:term_to_id(R#roster.jid), + "Validate")]); + true -> + ?X("td") + end, + ?XAE("td", [{"class", "valign"}], + [?INPUTT("submit", + "remove" ++ + ejabberd_web_admin:term_to_id(R#roster.jid), + "Remove")])]) + end, SItems))])] + end, + [?XC("h1", ?T("Roster of ") ++ us_to_list(US))] ++ + case Res of + ok -> [?CT("Submitted"), ?P]; + error -> [?CT("Bad format"), ?P]; + nothing -> [] + end ++ + [?XAE("form", [{"action", ""}, {"method", "post"}], + FItems ++ + [?P, + ?INPUT("text", "newjid", ""), ?C(" "), + ?INPUTT("submit", "addjid", "Add Jabber ID") + ])] + catch + _ -> + [?XC("h1", ?T("Roster of ") ++ us_to_list({User, Server}))] ++ + [?CT("Bad format"), ?P] ++ + [?XAE("form", [{"action", ""}, {"method", "post"}], + [?P, + ?INPUT("text", "newjid", ""), ?C(" "), + ?INPUTT("submit", "addjid", "Add Jabber ID") + ])] + end. user_roster_parse_query(User, Server, Items, Query) -> case lists:keysearch("addjid", 1, Query) of @@ -969,11 +977,12 @@ user_roster_parse_query(User, Server, Items, Query) -> {value, {_, undefined}} -> error; {value, {_, SJID}} -> - case jlib:string_to_jid(SJID) of - JID when is_record(JID, jid) -> - user_roster_subscribe_jid(User, Server, JID), - ok; - error -> + try + JID = exmpp_jid:list_to_jid(SJID), + user_roster_subscribe_jid(User, Server, JID), + ok + catch + _ -> error end; false -> @@ -994,9 +1003,9 @@ user_roster_parse_query(User, Server, Items, Query) -> user_roster_subscribe_jid(User, Server, JID) -> out_subscription(User, Server, JID, subscribe), - UJID = jlib:make_jid(User, Server, ""), + UJID = jlib:make_bare_jid(User, Server), ejabberd_router:route( - UJID, JID, {xmlelement, "presence", [{"type", "subscribe"}], []}). + UJID, JID, exmpp_presence:subscribe()). user_roster_item_parse_query(User, Server, Items, Query) -> lists:foreach( @@ -1005,28 +1014,32 @@ user_roster_item_parse_query(User, Server, Items, Query) -> case lists:keysearch( "validate" ++ ejabberd_web_admin:term_to_id(JID), 1, Query) of {value, _} -> - JID1 = jlib:make_jid(JID), + {U, S, R} = JID, + JID1 = exmpp_jid:make_jid(U, S, R), out_subscription( User, Server, JID1, subscribed), - UJID = jlib:make_jid(User, Server, ""), + UJID = exmpp_jid:make_bare_jid(User, Server), ejabberd_router:route( - UJID, JID1, {xmlelement, "presence", - [{"type", "subscribed"}], []}), + UJID, JID1, exmpp_presence:subscribed()), throw(submitted); false -> case lists:keysearch( "remove" ++ ejabberd_web_admin:term_to_id(JID), 1, Query) of {value, _} -> - UJID = jlib:make_jid(User, Server, ""), + UJID = jlib:make_bare_jid(User, Server), + Attrs1 = exmpp_xml:set_attribute_in_list([], + 'jid', exmpp_jid:jid_to_list(JID)), + Attrs2 = exmpp_xml:set_attribute_in_list(Attrs1, + 'subscription', "remove"), + Item = #xmlel{ns = ?NS_ROSTER, name = 'item', + attrs = Attrs2}, + Request = #xmlel{ + ns = ?NS_ROSTER, + name = 'query', + children = [Item]}, process_iq( UJID, UJID, - #iq{type = set, - sub_el = {xmlelement, "query", - [{"xmlns", ?NS_ROSTER}], - [{xmlelement, "item", - [{"jid", jlib:jid_to_string(JID)}, - {"subscription", "remove"}], - []}]}}), + exmpp_iq:set(?NS_JABBER_CLIENT, Request)), throw(submitted); false -> ok @@ -1037,7 +1050,7 @@ user_roster_item_parse_query(User, Server, Items, Query) -> nothing. us_to_list({User, Server}) -> - jlib:jid_to_string({User, Server, ""}). + exmpp_jid:bare_jid_to_list(User, Server). webadmin_user(Acc, _User, _Server, Lang) -> Acc ++ [?XE("h3", [?ACT("roster/", "Roster")])]. From e9d7ac68dae7d1349a8f4cc94080d25df51a4e28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 18 Sep 2008 14:55:43 +0000 Subject: [PATCH 069/582] o Fix a bug in get_in_pending_subscriptions() where the type of the presence stanza was lost. o Reorganize a few lines in user_roster() to match mod_roster_odbc. SVN Revision: 1566 --- ChangeLog | 4 ++++ src/mod_roster.erl | 12 ++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index fbaad6a97..335d81aa7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,10 @@ * src/mod_roster_odbc.erl: Convert to exmpp. + * src/mod_roster.erl (get_in_pending_subscriptions): Fix a bug where + the type of the presence stanza was lost. + (user_roster): Reorganize a few lines to match mod_roster_odbc. + 2008-09-16 Jean-Sébastien Pédron Merge from trunk (r1457 to r1563). diff --git a/src/mod_roster.erl b/src/mod_roster.erl index fb9ba3cbd..878305652 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -649,12 +649,10 @@ get_in_pending_subscriptions(Ls, User, Server) -> fun(R) -> Message = R#roster.askmessage, {U, S, R} = R#roster.jid, - Attrs1 = exmpp_stanza:set_sender_in_list([], - exmpp_jid:jid_to_list(U, S, R)), - Attrs2 = exmpp_stanza:set_recipient_in_list(Attrs1, - exmpp_jid:jid_to_list(JID)), Pres1 = exmpp_presence:subscribe(), - Pres2 = Pres1#xmlel{attrs = Attrs2}, + Pres2 = exmpp_stanza:set_jids(Pres1, + exmpp_jid:jid_to_list(U, S, R), + exmpp_jid:jid_to_list(JID)), exmpp_presence:set_status(Pres2, Message) end, lists:filter( @@ -847,7 +845,9 @@ webadmin_page(Acc, _, _) -> Acc. user_roster(User, Server, Query, Lang) -> try - US = {exmpp_stringprep:nodeprep(User), exmpp_stringprep:nameprep(Server)}, + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, Items1 = mnesia:dirty_index_read(roster, US, #roster.us), Res = user_roster_parse_query(User, Server, Items1, Query), Items = mnesia:dirty_index_read(roster, US, #roster.us), From 35a73424165b9519568b5a0176bc9c94bbe87b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 22 Sep 2008 11:17:23 +0000 Subject: [PATCH 070/582] o Remove unappropriate comments in get_sm_features/5. o Use the '_s' variants of NS_* macros instead of a call to atom_to_list/1 in do_route/4. o A call to the stringprep module was left in filter_fields/3. SVN Revision: 1567 --- ChangeLog | 8 ++++++++ src/mod_vcard.erl | 8 +++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 335d81aa7..565bf503e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2008-09-22 Jean-Sébastien Pédron + + * src/mod_vcard.erl (get_sm_features): Remove unappropriate + comments. + (do_route): Use the '_s' variants of NS_* macros instead of a call to + atom_to_list/1. + (filter_fields): A call to the stringprep module was left. + 2008-09-18 Jean-Sébastien Pédron * src/mod_roster_odbc.erl: Convert to exmpp. diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index c81b016f0..0a0b9bf21 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -141,10 +141,8 @@ get_sm_features(Acc, _From, _To, Node, _Lang) -> [] -> case Acc of {result, Features} -> - % XXX OLD FORMAT: NS as string. {result, [?NS_VCARD_s | Features]}; empty -> - % XXX OLD FORMAT: NS as string. {result, [?NS_VCARD_s]} end; _ -> @@ -372,11 +370,11 @@ do_route(ServerHost, From, To, Packet) -> #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ #xmlattr{name = 'var', - value = atom_to_list(?NS_SEARCH)}]}, + value = ?NS_SEARCH_s}]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ #xmlattr{name = 'var', - value = atom_to_list(?NS_VCARD)}]} + value = ?NS_VCARD_s}]} ]}, ResIQ = exmpp_iq:result(Packet, Result), ejabberd_router:route(To, @@ -516,7 +514,7 @@ filter_fields([], Match, _LServer) -> Match; filter_fields([{SVar, [Val]} | Ds], Match, LServer) when is_list(Val) and (Val /= "") -> - LVal = stringprep:tolower(Val), + LVal = exmpp_stringprep:to_lower(Val), NewMatch = case SVar of "user" -> case gen_mod:get_module_opt(LServer, ?MODULE, From 5803c5163374aec7c5ee2a612c1a077c47ea083e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 22 Sep 2008 11:18:08 +0000 Subject: [PATCH 071/582] Convert to exmpp. SVN Revision: 1568 --- ChangeLog | 2 + src/mod_vcard_ldap.erl | 414 ++++++++++++++--------------- src/mod_vcard_odbc.erl | 576 ++++++++++++++++++++--------------------- 3 files changed, 474 insertions(+), 518 deletions(-) diff --git a/ChangeLog b/ChangeLog index 565bf503e..18b96220c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,8 @@ atom_to_list/1. (filter_fields): A call to the stringprep module was left. + * src/mod_vcard_ldap.erl, src/mod_vcard_odbc.erl: Convert to exmpp. + 2008-09-18 Jean-Sébastien Pédron * src/mod_roster_odbc.erl: Convert to exmpp. diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index 4c0ca6177..caae4b667 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -49,9 +49,10 @@ route/4 ]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). -include("eldap/eldap.hrl"). --include("jlib.hrl"). -define(PROCNAME, ejabberd_mod_vcard_ldap). @@ -193,7 +194,8 @@ handle_info({route, From, To, Packet}, State) -> Pid when is_pid(Pid) -> ok; _ -> - Err = jlib:make_error_reply(Packet, ?ERR_INTERNAL_SERVER_ERROR), + Err = exmpp_stanza:reply_with_error(Packet, + 'internal-server-error'), ejabberd_router:route(To, From, Err) end, {noreply, State}; @@ -208,53 +210,45 @@ get_sm_features(Acc, _From, _To, Node, _Lang) -> [] -> case Acc of {result, Features} -> - {result, [?NS_VCARD | Features]}; + {result, [?NS_VCARD_s | Features]}; empty -> - {result, [?NS_VCARD]} + {result, [?NS_VCARD_s]} end; _ -> Acc end. -process_local_iq(_From, _To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> - case Type of - set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; - get -> - IQ#iq{type = result, - sub_el = [{xmlelement, "vCard", - [{"xmlns", ?NS_VCARD}], - [{xmlelement, "FN", [], - [{xmlcdata, "ejabberd"}]}, - {xmlelement, "URL", [], - [{xmlcdata, ?EJABBERD_URI}]}, - {xmlelement, "DESC", [], - [{xmlcdata, - translate:translate( - Lang, - "Erlang Jabber Server") ++ - "\nCopyright (c) 2002-2008 ProcessOne"}]}, - {xmlelement, "BDAY", [], - [{xmlcdata, "2002-11-16"}]} - ]}]} - end. +process_local_iq(_From, _To, #iq{type = get, lang = Lang} = IQ_Rec) -> + Result = #xmlel{ns = ?NS_VCARD, name = 'vCard', children = [ + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'FN'}, + "ejabberd"), + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'URL'}, + ?EJABBERD_URI), + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'DESC'}, + translate:translate(Lang, "Erlang Jabber Server") ++ + "\nCopyright (c) 2002-2008 ProcessOne"), + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'BDAY'}, + "2002-11-16") + ]}, + exmpp_iq:result(IQ_Rec, Result); +process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> + exmpp_iq:error(IQ_Rec, 'not-allowed'). -process_sm_iq(_From, #jid{lserver=LServer} = To, #iq{sub_el = SubEl} = IQ) -> - case catch process_vcard_ldap(To, IQ, LServer) of +process_sm_iq(_From, #jid{ldomain=LServer} = To, #iq{} = IQ_Rec) -> + case catch process_vcard_ldap(To, IQ_Rec, LServer) of {'EXIT', _} -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}; + exmpp_iq:error(IQ_Rec, 'internal-server-error'); Other -> Other end. -process_vcard_ldap(To, IQ, Server) -> +process_vcard_ldap(To, IQ_Rec, Server) -> {ok, State} = eldap_utils:get_state(Server, ?PROCNAME), - #iq{type = Type, sub_el = SubEl} = IQ, - case Type of + case IQ_Rec#iq.type of set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + exmpp_iq:error(IQ_Rec, 'not-allowed'); get -> - #jid{luser = LUser} = To, + #jid{lnode = LUser} = To, LServer = State#state.serverhost, case ejabberd_auth:is_user_exists(LUser, LServer) of true -> @@ -262,12 +256,12 @@ process_vcard_ldap(To, IQ, Server) -> case find_ldap_user(LUser, State) of #eldap_entry{attributes = Attributes} -> Vcard = ldap_attributes_to_vcard(Attributes, VCardMap, {LUser, LServer}), - IQ#iq{type = result, sub_el = Vcard}; + exmpp_iq:result(IQ_Rec, Vcard); _ -> - IQ#iq{type = result, sub_el = []} + exmpp_iq:result(IQ_Rec) end; _ -> - IQ#iq{type = result, sub_el = []} + exmpp_iq:result(IQ_Rec) end end. @@ -300,247 +294,237 @@ find_ldap_user(User, State) -> ldap_attributes_to_vcard(Attributes, VCardMap, UD) -> Attrs = lists:map( fun({VCardName, _, _}) -> - {stringprep:tolower(VCardName), + {exmpp_stringprep:to_lower(VCardName), map_vcard_attr(VCardName, Attributes, VCardMap, UD)} end, VCardMap), Elts = [ldap_attribute_to_vcard(vCard, Attr) || Attr <- Attrs], NElts = [ldap_attribute_to_vcard(vCardN, Attr) || Attr <- Attrs], OElts = [ldap_attribute_to_vcard(vCardO, Attr) || Attr <- Attrs], AElts = [ldap_attribute_to_vcard(vCardA, Attr) || Attr <- Attrs], - [{xmlelement, "vCard", [{"xmlns", ?NS_VCARD}], + [#xmlel{ns = ?NS_VCARD, name = 'vCard', children = lists:append([X || X <- Elts, X /= none], - [{xmlelement,"N",[], [X || X <- NElts, X /= none]}, - {xmlelement,"ORG",[], [X || X <- OElts, X /= none]}, - {xmlelement,"ADR",[], [X || X <- AElts, X /= none]}]) + [#xmlel{ns = ?NS_VCARD, name = 'N', children = [X || X <- NElts, X /= none]}, + #xmlel{ns = ?NS_VCARD, name = 'ORG', children = [X || X <- OElts, X /= none]}, + #xmlel{ns = ?NS_VCARD, name = 'ADR', children = [X || X <- AElts, X /= none]}]) }]. ldap_attribute_to_vcard(vCard, {"fn", Value}) -> - {xmlelement,"FN",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'FN'}, Value); ldap_attribute_to_vcard(vCard, {"nickname", Value}) -> - {xmlelement,"NICKNAME",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'NICKNAME'}, Value); ldap_attribute_to_vcard(vCard, {"title", Value}) -> - {xmlelement,"TITLE",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'TITLE'}, Value); ldap_attribute_to_vcard(vCard, {"bday", Value}) -> - {xmlelement,"BDAY",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'BDAY'}, Value); ldap_attribute_to_vcard(vCard, {"url", Value}) -> - {xmlelement,"URL",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'URL'}, Value); ldap_attribute_to_vcard(vCard, {"desc", Value}) -> - {xmlelement,"DESC",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'DESC'}, Value); ldap_attribute_to_vcard(vCard, {"role", Value}) -> - {xmlelement,"ROLE",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'ROLE'}, Value); ldap_attribute_to_vcard(vCard, {"tel", Value}) -> - {xmlelement,"TEL",[],[{xmlelement,"VOICE",[],[]}, - {xmlelement,"WORK",[],[]}, - {xmlelement,"NUMBER",[],[{xmlcdata,Value}]}]}; + #xmlel{ns = ?NS_VCARD, name = 'TEL', children = [ + #xmlel{ns = ?NS_VCARD, name = 'VOICE'}, + #xmlel{ns = ?NS_VCARD, name = 'WORK'}, + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'NUMBER'}, Value)]}; ldap_attribute_to_vcard(vCard, {"email", Value}) -> - {xmlelement,"EMAIL",[],[{xmlelement,"INTERNET",[],[]}, - {xmlelement,"PREF",[],[]}, - {xmlelement,"USERID",[],[{xmlcdata,Value}]}]}; + #xmlel{ns = ?NS_VCARD, name = 'EMAIL', children = [ + #xmlel{ns = ?NS_VCARD, name = 'INTERNET'}, + #xmlel{ns = ?NS_VCARD, name = 'PREF'}, + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'USERID'}, Value)]}; ldap_attribute_to_vcard(vCard, {"photo", Value}) -> - {xmlelement,"PHOTO",[],[ - {xmlelement,"BINVAL",[],[{xmlcdata, jlib:encode_base64(Value)}]}]}; + #xmlel{ns = ?NS_VCARD, name = 'PHOTO', children = [ + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'BINVAL'}, + jlib:encode_base64(Value))]}; ldap_attribute_to_vcard(vCardN, {"family", Value}) -> - {xmlelement,"FAMILY",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'FAMILY'}, Value); ldap_attribute_to_vcard(vCardN, {"given", Value}) -> - {xmlelement,"GIVEN",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'GIVEN'}, Value); ldap_attribute_to_vcard(vCardN, {"middle", Value}) -> - {xmlelement,"MIDDLE",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'MIDDLE'}, Value); ldap_attribute_to_vcard(vCardO, {"orgname", Value}) -> - {xmlelement,"ORGNAME",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'ORGNAME'}, Value); ldap_attribute_to_vcard(vCardO, {"orgunit", Value}) -> - {xmlelement,"ORGUNIT",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'ORGUNIT'}, Value); ldap_attribute_to_vcard(vCardA, {"locality", Value}) -> - {xmlelement,"LOCALITY",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'LOCALITY'}, Value); ldap_attribute_to_vcard(vCardA, {"street", Value}) -> - {xmlelement,"STREET",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'STREET'}, Value); ldap_attribute_to_vcard(vCardA, {"ctry", Value}) -> - {xmlelement,"CTRY",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'CTRY'}, Value); ldap_attribute_to_vcard(vCardA, {"region", Value}) -> - {xmlelement,"REGION",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'REGION'}, Value); ldap_attribute_to_vcard(vCardA, {"pcode", Value}) -> - {xmlelement,"PCODE",[],[{xmlcdata,Value}]}; + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'PCODE'}, Value); ldap_attribute_to_vcard(_, _) -> none. -define(TLFIELD(Type, Label, Var), - {xmlelement, "field", [{"type", Type}, - {"label", translate:translate(Lang, Label)}, - {"var", Var}], []}). + #xmlel{ns = ?NS_VCARD, name = 'field', attrs = [ + #xmlattr{name = 'type', value = Type}, + #xmlattr{name = 'label', value = translate:translate(Lang, Label)}, + #xmlattr{name = 'var', value = Var}]}). -define(FORM(JID, SearchFields), - [{xmlelement, "instructions", [], - [{xmlcdata, translate:translate(Lang, "You need an x:data capable client to search")}]}, - {xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}], - [{xmlelement, "title", [], - [{xmlcdata, translate:translate(Lang, "Search users in ") ++ - jlib:jid_to_string(JID)}]}, - {xmlelement, "instructions", [], - [{xmlcdata, translate:translate(Lang, "Fill in fields to search " - "for any matching Jabber User")}]} + [#xmlel{ns = ?NS_SEARCH, name = 'instructions', children = + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "You need an x:data capable client to search"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = + [#xmlattr{name = 'type', value = "form"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ + exmpp_jid:jid_to_list(JID))}]}, + #xmlel{ns = ?NS_SEARCH, name = 'instructions', children = + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Fill in fields to search " + "for any matching Jabber User"))}]} ] ++ lists:map(fun({X,Y}) -> ?TLFIELD("text-single", X, Y) end, SearchFields)}]). do_route(State, From, To, Packet) -> spawn(?MODULE, route, [State, From, To, Packet]). route(State, From, To, Packet) -> - #jid{user = User, resource = Resource} = To, + #jid{node = User, resource = Resource} = To, if - (User /= "") or (Resource /= "") -> - Err = jlib:make_error_reply(Packet, ?ERR_SERVICE_UNAVAILABLE), + (User /= undefined) or (Resource /= undefined) -> + Err = exmpp_stanza:reply_with_error(Packet, 'service-unavailable'), ejabberd_router:route(To, From, Err); true -> - IQ = jlib:iq_query_info(Packet), - case IQ of - #iq{type = Type, xmlns = ?NS_SEARCH, lang = Lang, sub_el = SubEl} -> - case Type of - set -> - XDataEl = find_xdata_el(SubEl), - case XDataEl of - false -> - Err = jlib:make_error_reply( - Packet, ?ERR_BAD_REQUEST), - ejabberd_router:route(To, From, Err); - _ -> - XData = jlib:parse_xdata_submit(XDataEl), - case XData of - invalid -> - Err = jlib:make_error_reply( - Packet, - ?ERR_BAD_REQUEST), - ejabberd_router:route(To, From, - Err); - _ -> - ResIQ = - IQ#iq{ - type = result, - sub_el = - [{xmlelement, - "query", - [{"xmlns", ?NS_SEARCH}], - [{xmlelement, "x", - [{"xmlns", ?NS_XDATA}, - {"type", "result"}], - search_result(Lang, To, State, XData) - }]}]}, - ejabberd_router:route( - To, From, jlib:iq_to_xml(ResIQ)) - end - end; - get -> - SearchFields = State#state.search_fields, - ResIQ = IQ#iq{type = result, - sub_el = [{xmlelement, - "query", - [{"xmlns", ?NS_SEARCH}], - ?FORM(To, SearchFields) - }]}, - ejabberd_router:route(To, - From, - jlib:iq_to_xml(ResIQ)) - end; - #iq{type = Type, xmlns = ?NS_DISCO_INFO, lang = Lang} -> - case Type of - set -> - Err = jlib:make_error_reply( - Packet, ?ERR_NOT_ALLOWED), - ejabberd_router:route(To, From, Err); - get -> - ResIQ = - IQ#iq{type = result, - sub_el = [{xmlelement, - "query", - [{"xmlns", ?NS_DISCO_INFO}], - [{xmlelement, "identity", - [{"category", "directory"}, - {"type", "user"}, - {"name", - translate:translate(Lang, "vCard User Search")}], - []}, - {xmlelement, "feature", - [{"var", ?NS_SEARCH}], []}, - {xmlelement, "feature", - [{"var", ?NS_VCARD}], []} - ] - }]}, - ejabberd_router:route(To, - From, - jlib:iq_to_xml(ResIQ)) - end; - #iq{type = Type, xmlns = ?NS_DISCO_ITEMS} -> - case Type of - set -> - Err = jlib:make_error_reply( - Packet, ?ERR_NOT_ALLOWED), - ejabberd_router:route(To, From, Err); - get -> - ResIQ = - IQ#iq{type = result, - sub_el = [{xmlelement, - "query", - [{"xmlns", ?NS_DISCO_ITEMS}], - []}]}, - ejabberd_router:route(To, - From, - jlib:iq_to_xml(ResIQ)) - end; - #iq{type = get, xmlns = ?NS_VCARD, lang = Lang} -> - ResIQ = - IQ#iq{type = result, - sub_el = [{xmlelement, - "vCard", - [{"xmlns", ?NS_VCARD}], - iq_get_vcard(Lang)}]}, - ejabberd_router:route(To, - From, - jlib:iq_to_xml(ResIQ)); + try + Request = exmpp_iq:get_request(Packet), + Type = exmpp_iq:get_type(Packet), + Lang = exmpp_stanza:get_lang(Packet), + case {Type, Request#xmlel.ns} of + {set, ?NS_SEARCH} -> + XDataEl = find_xdata_el(Request), + case XDataEl of + false -> + Err = exmpp_iq:error(Packet, 'bad-request'), + ejabberd_router:route(To, From, Err); + _ -> + XData = jlib:parse_xdata_submit(XDataEl), + case XData of + invalid -> + Err = exmpp_iq:error(Packet, + 'bad-request'), + ejabberd_router:route(To, From, + Err); + _ -> + Result = #xmlel{ + ns = ?NS_SEARCH, + name = 'query', + children = [ + #xmlel{ + ns = ?NS_DATA_FORMS, + name = 'x', + attrs = [#xmlattr{name = 'type', + value = "result"}], + children = search_result(Lang, To, State, XData)}]}, + ResIQ = exmpp_iq:result(Packet, + Result), + ejabberd_router:route( + To, From, ResIQ) + end + end; + {get, ?NS_SEARCH} -> + SearchFields = State#state.search_fields, + Result = #xmlel{ns = ?NS_SEARCH, name = 'query', + children = ?FORM(To, SearchFields)}, + ResIQ = exmpp_iq:result(Packet, Result), + ejabberd_router:route(To, + From, + ResIQ); + {set, ?NS_DISCO_INFO} -> + Err = exmpp_iq:error(Packet, 'not-allowed'), + ejabberd_router:route(To, From, Err); + {get, ?NS_DISCO_INFO} -> + Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', + children = [ + #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', + attrs = [ + #xmlattr{name = 'category', + value = "directory"}, + #xmlattr{name = 'type', + value = "user"}, + #xmlattr{name = 'name', + value = translate:translate(Lang, + "vCard User Search")}]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', + attrs = [ + #xmlattr{name = 'var', + value = ?NS_SEARCH_s}]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', + attrs = [ + #xmlattr{name = 'var', + value = ?NS_VCARD_s}]} + ]}, + ResIQ = exmpp_iq:result(Packet, Result), + ejabberd_router:route(To, + From, + ResIQ); + {set, ?NS_DISCO_ITEMS} -> + Err = exmpp_iq:error(Packet, 'not-allowed'), + ejabberd_router:route(To, From, Err); + {get, ?NS_DISCO_ITEMS} -> + Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query'}, + ResIQ = exmpp_iq:result(Packet, Result), + ejabberd_router:route(To, + From, + ResIQ); + {get, ?NS_VCARD} -> + Result = #xmlel{ns = ?NS_VCARD, name = 'vCard', + children = iq_get_vcard(Lang)}, + ResIQ = exmpp_iq:result(Packet, Result), + ejabberd_router:route(To, + From, + ResIQ); + _ -> + Err = exmpp_iq:error(Packet, 'service-unavailable'), + ejabberd_router:route(To, From, Err) + end + catch _ -> - Err = jlib:make_error_reply(Packet, - ?ERR_SERVICE_UNAVAILABLE), - ejabberd_router:route(To, From, Err) + Err1 = exmpp_iq:error(Packet, 'service-unavailable'), + ejabberd_router:route(To, From, Err1) end end. iq_get_vcard(Lang) -> - [{xmlelement, "FN", [], - [{xmlcdata, "ejabberd/mod_vcard"}]}, - {xmlelement, "URL", [], - [{xmlcdata, ?EJABBERD_URI}]}, - {xmlelement, "DESC", [], - [{xmlcdata, translate:translate( - Lang, - "ejabberd vCard module") ++ - "\nCopyright (c) 2003-2008 ProcessOne"}]}]. - --define(LFIELD(Label, Var), - {xmlelement, "field", [{"label", translate:translate(Lang, Label)}, - {"var", Var}], []}). + [ + #xmlel{ns = ?NS_SEARCH, name = 'FN', children = [ + #xmlcdata{cdata = <<"ejabberd/mod_vcard">>}]}, + #xmlel{ns = ?NS_SEARCH, name = 'URL', children = [ + #xmlcdata{cdata = list_to_binary(?EJABBERD_URI)}]}, + #xmlel{ns = ?NS_SEARCH, name ='DESC', children = [ + #xmlcdata{cdata = list_to_binary( + translate:translate(Lang, "ejabberd vCard module") ++ + "\nCopyright (c) 2003-2008 ProcessOne")}]} + ]. search_result(Lang, JID, State, Data) -> SearchReported = State#state.search_reported, - Header = [{xmlelement, "title", [], - [{xmlcdata, translate:translate(Lang, "Search Results for ") ++ - jlib:jid_to_string(JID)}]}, - {xmlelement, "reported", [], + Header = [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search Results for ") ++ + exmpp_jid:jid_to_list(JID))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'reported', children = [?TLFIELD("text-single", "Jabber ID", "jid")] ++ lists:map( fun({Name, Value}) -> ?TLFIELD("text-single", Name, Value) end, @@ -554,9 +538,10 @@ search_result(Lang, JID, State, Data) -> end. -define(FIELD(Var, Val), - {xmlelement, "field", [{"var", Var}], - [{xmlelement, "value", [], - [{xmlcdata, Val}]}]}). + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'var', value = Var}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = + [#xmlcdata{cdata = list_to_binary(Val)}]}]}). search(State, Data) -> Base = State#state.base, @@ -605,7 +590,7 @@ search_items(Entries, State) -> end, SearchReported), Result = [?FIELD("jid", Username ++ "@" ++ LServer)] ++ [?FIELD(Name, Value) || {Name, Value} <- RFields], - [{xmlelement, "item", [], Result}]; + [#xmlel{ns = ?NS_DATA_FORMS, name = 'item', children = Result}]; _ -> [] end; @@ -645,13 +630,8 @@ find_xdata_el({xmlelement, _Name, _Attrs, SubEls}) -> find_xdata_el1([]) -> false; -find_xdata_el1([{xmlelement, Name, Attrs, SubEls} | Els]) -> - case xml:get_attr_s("xmlns", Attrs) of - ?NS_XDATA -> - {xmlelement, Name, Attrs, SubEls}; - _ -> - find_xdata_el1(Els) - end; +find_xdata_el1([#xmlel{ns = ?NS_DATA_FORMS} = El | _Els]) -> + El; find_xdata_el1([_ | Els]) -> find_xdata_el1(Els). diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl index 7c3d78dab..0a46efa6b 100644 --- a/src/mod_vcard_odbc.erl +++ b/src/mod_vcard_odbc.erl @@ -36,8 +36,9 @@ %reindex_vcards/0, remove_user/2]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -define(JUD_MATCHES, 30). @@ -102,85 +103,85 @@ get_sm_features(Acc, _From, _To, Node, _Lang) -> [] -> case Acc of {result, Features} -> - {result, [?NS_VCARD | Features]}; + {result, [?NS_VCARD_s | Features]}; empty -> - {result, [?NS_VCARD]} + {result, [?NS_VCARD_s]} end; _ -> Acc end. -process_local_iq(_From, _To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> - case Type of - set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; - get -> - IQ#iq{type = result, - sub_el = [{xmlelement, "vCard", - [{"xmlns", ?NS_VCARD}], - [{xmlelement, "FN", [], - [{xmlcdata, "ejabberd"}]}, - {xmlelement, "URL", [], - [{xmlcdata, ?EJABBERD_URI}]}, - {xmlelement, "DESC", [], - [{xmlcdata, - translate:translate( - Lang, - "Erlang Jabber Server") ++ - "\nCopyright (c) 2002-2008 ProcessOne"}]}, - {xmlelement, "BDAY", [], - [{xmlcdata, "2002-11-16"}]} - ]}]} - end. +process_local_iq(_From, _To, #iq{type = get, lang = Lang} = IQ_Rec) -> + Result = #xmlel{ns = ?NS_VCARD, name = 'vCard', children = [ + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'FN'}, + "ejabberd"), + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'URL'}, + ?EJABBERD_URI), + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'DESC'}, + translate:translate(Lang, "Erlang Jabber Server") ++ + "\nCopyright (c) 2002-2008 ProcessOne"), + exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'BDAY'}, + "2002-11-16") + ]}, + exmpp_iq:result(IQ_Rec, Result); +process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> + exmpp_iq:error(IQ_Rec, 'not-allowed'). -process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> - case Type of - set -> - #jid{user = User, lserver = LServer} = From, - case lists:member(LServer, ?MYHOSTS) of - true -> - set_vcard(User, LServer, SubEl), - IQ#iq{type = result, sub_el = []}; - false -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]} - end; - get -> - #jid{luser = LUser, lserver = LServer} = To, - Username = ejabberd_odbc:escape(LUser), - case catch ejabberd_odbc:sql_query( - LServer, - ["select vcard from vcard " - "where username='", Username, "';"]) of - {selected, ["vcard"], [{SVCARD}]} -> - case xml_stream:parse_element(SVCARD) of - {error, _Reason} -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]}; - VCARD -> - IQ#iq{type = result, sub_el = [VCARD]} - end; - {selected, ["vcard"], []} -> - IQ#iq{type = result, sub_el = []}; - _ -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]} - end +process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> + #jid{lnode = LUser, ldomain = LServer} = To, + Username = ejabberd_odbc:escape(LUser), + case catch ejabberd_odbc:sql_query( + LServer, + ["select vcard from vcard " + "where username='", Username, "';"]) of + {selected, ["vcard"], [{SVCARD}]} -> + case exmpp_xml:parse_document(SVCARD) of + {error, _Reason} -> + exmpp_iq:error(IQ_Rec, 'service-unavailable'); + VCARD -> + exmpp_iq:result(IQ_Rec, VCARD) + end; + {selected, ["vcard"], []} -> + exmpp_iq:result(IQ_Rec); + _ -> + exmpp_iq:error(IQ_Rec, 'internal-server-error') + end; +process_sm_iq(From, _To, #iq{type = set, payload = Request} = IQ_Rec) -> + #jid{node = User, ldomain = LServer} = From, + case lists:member(LServer, ?MYHOSTS) of + true -> + set_vcard(User, LServer, Request), + exmpp_iq:result(IQ_Rec); + false -> + exmpp_iq:error(IQ_Rec, 'not-allowed') end. set_vcard(User, LServer, VCARD) -> - FN = xml:get_path_s(VCARD, [{elem, "FN"}, cdata]), - Family = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "FAMILY"}, cdata]), - Given = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "GIVEN"}, cdata]), - Middle = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "MIDDLE"}, cdata]), - Nickname = xml:get_path_s(VCARD, [{elem, "NICKNAME"}, cdata]), - BDay = xml:get_path_s(VCARD, [{elem, "BDAY"}, cdata]), - CTRY = xml:get_path_s(VCARD, [{elem, "ADR"}, {elem, "CTRY"}, cdata]), - Locality = xml:get_path_s(VCARD, [{elem, "ADR"}, {elem, "LOCALITY"},cdata]), - EMail1 = xml:get_path_s(VCARD, [{elem, "EMAIL"}, {elem, "USERID"},cdata]), - EMail2 = xml:get_path_s(VCARD, [{elem, "EMAIL"}, cdata]), - OrgName = xml:get_path_s(VCARD, [{elem, "ORG"}, {elem, "ORGNAME"}, cdata]), - OrgUnit = xml:get_path_s(VCARD, [{elem, "ORG"}, {elem, "ORGUNIT"}, cdata]), + FN = exmpp_xml:get_path(VCARD, + [{element, 'FN'}, cdata_as_list]), + Family = exmpp_xml:get_path(VCARD, + [{element, 'N'}, {element, 'FAMILY'}, cdata_as_list]), + Given = exmpp_xml:get_path(VCARD, + [{element, 'N'}, {element, 'GIVEN'}, cdata_as_list]), + Middle = exmpp_xml:get_path(VCARD, + [{element, 'N'}, {element, 'MIDDLE'}, cdata_as_list]), + Nickname = exmpp_xml:get_path(VCARD, + [{element, 'NICKNAME'}, cdata_as_list]), + BDay = exmpp_xml:get_path(VCARD, + [{element, 'BDAY'}, cdata_as_list]), + CTRY = exmpp_xml:get_path(VCARD, + [{element, 'ADR'}, {element, 'CTRY'}, cdata_as_list]), + Locality = exmpp_xml:get_path(VCARD, + [{element, 'ADR'}, {element, 'LOCALITY'}, cdata_as_list]), + EMail1 = exmpp_xml:get_path(VCARD, + [{element, 'EMAIL'}, {element, 'USERID'}, cdata_as_list]), + EMail2 = exmpp_xml:get_path(VCARD, + [{element, 'EMAIL'}, cdata_as_list]), + OrgName = exmpp_xml:get_path(VCARD, + [{element, 'ORG'}, {element, 'ORGNAME'}, cdata_as_list]), + OrgUnit = exmpp_xml:get_path(VCARD, + [{element, 'ORG'}, {element, 'ORGUNIT'}, cdata_as_list]), EMail = case EMail1 of "" -> EMail2; @@ -188,106 +189,96 @@ set_vcard(User, LServer, VCARD) -> EMail1 end, - LUser = jlib:nodeprep(User), - LFN = stringprep:tolower(FN), - LFamily = stringprep:tolower(Family), - LGiven = stringprep:tolower(Given), - LMiddle = stringprep:tolower(Middle), - LNickname = stringprep:tolower(Nickname), - LBDay = stringprep:tolower(BDay), - LCTRY = stringprep:tolower(CTRY), - LLocality = stringprep:tolower(Locality), - LEMail = stringprep:tolower(EMail), - LOrgName = stringprep:tolower(OrgName), - LOrgUnit = stringprep:tolower(OrgUnit), + try + LUser = exmpp_stringprep:nodeprep(User), + LFN = exmpp_stringprep:to_lower(FN), + LFamily = exmpp_stringprep:to_lower(Family), + LGiven = exmpp_stringprep:to_lower(Given), + LMiddle = exmpp_stringprep:to_lower(Middle), + LNickname = exmpp_stringprep:to_lower(Nickname), + LBDay = exmpp_stringprep:to_lower(BDay), + LCTRY = exmpp_stringprep:to_lower(CTRY), + LLocality = exmpp_stringprep:to_lower(Locality), + LEMail = exmpp_stringprep:to_lower(EMail), + LOrgName = exmpp_stringprep:to_lower(OrgName), + LOrgUnit = exmpp_stringprep:to_lower(OrgUnit), - if - (LUser == error) or - (LFN == error) or - (LFamily == error) or - (LGiven == error) or - (LMiddle == error) or - (LNickname == error) or - (LBDay == error) or - (LCTRY == error) or - (LLocality == error) or - (LEMail == error) or - (LOrgName == error) or - (LOrgUnit == error) -> - {error, badarg}; - true -> - Username = ejabberd_odbc:escape(User), - LUsername = ejabberd_odbc:escape(LUser), - SVCARD = ejabberd_odbc:escape( - lists:flatten(xml:element_to_string(VCARD))), + Username = ejabberd_odbc:escape(User), + LUsername = ejabberd_odbc:escape(LUser), + SVCARD = ejabberd_odbc:escape(exmpp_xml:document_to_list(VCARD)), - SFN = ejabberd_odbc:escape(FN), - SLFN = ejabberd_odbc:escape(LFN), - SFamily = ejabberd_odbc:escape(Family), - SLFamily = ejabberd_odbc:escape(LFamily), - SGiven = ejabberd_odbc:escape(Given), - SLGiven = ejabberd_odbc:escape(LGiven), - SMiddle = ejabberd_odbc:escape(Middle), - SLMiddle = ejabberd_odbc:escape(LMiddle), - SNickname = ejabberd_odbc:escape(Nickname), - SLNickname = ejabberd_odbc:escape(LNickname), - SBDay = ejabberd_odbc:escape(BDay), - SLBDay = ejabberd_odbc:escape(LBDay), - SCTRY = ejabberd_odbc:escape(CTRY), - SLCTRY = ejabberd_odbc:escape(LCTRY), - SLocality = ejabberd_odbc:escape(Locality), - SLLocality = ejabberd_odbc:escape(LLocality), - SEMail = ejabberd_odbc:escape(EMail), - SLEMail = ejabberd_odbc:escape(LEMail), - SOrgName = ejabberd_odbc:escape(OrgName), - SLOrgName = ejabberd_odbc:escape(LOrgName), - SOrgUnit = ejabberd_odbc:escape(OrgUnit), - SLOrgUnit = ejabberd_odbc:escape(LOrgUnit), + SFN = ejabberd_odbc:escape(FN), + SLFN = ejabberd_odbc:escape(LFN), + SFamily = ejabberd_odbc:escape(Family), + SLFamily = ejabberd_odbc:escape(LFamily), + SGiven = ejabberd_odbc:escape(Given), + SLGiven = ejabberd_odbc:escape(LGiven), + SMiddle = ejabberd_odbc:escape(Middle), + SLMiddle = ejabberd_odbc:escape(LMiddle), + SNickname = ejabberd_odbc:escape(Nickname), + SLNickname = ejabberd_odbc:escape(LNickname), + SBDay = ejabberd_odbc:escape(BDay), + SLBDay = ejabberd_odbc:escape(LBDay), + SCTRY = ejabberd_odbc:escape(CTRY), + SLCTRY = ejabberd_odbc:escape(LCTRY), + SLocality = ejabberd_odbc:escape(Locality), + SLLocality = ejabberd_odbc:escape(LLocality), + SEMail = ejabberd_odbc:escape(EMail), + SLEMail = ejabberd_odbc:escape(LEMail), + SOrgName = ejabberd_odbc:escape(OrgName), + SLOrgName = ejabberd_odbc:escape(LOrgName), + SOrgUnit = ejabberd_odbc:escape(OrgUnit), + SLOrgUnit = ejabberd_odbc:escape(LOrgUnit), - ejabberd_odbc:sql_transaction( - LServer, - [["delete from vcard where username='", LUsername, "';"], - ["insert into vcard(username, vcard) " - "values ('", LUsername, "', '", SVCARD, "');"], - ["delete from vcard_search where lusername='", LUsername, "';"], - ["insert into vcard_search(" - " username, lusername, fn, lfn, family, lfamily," - " given, lgiven, middle, lmiddle, nickname, lnickname," - " bday, lbday, ctry, lctry, locality, llocality," - " email, lemail, orgname, lorgname, orgunit, lorgunit)" - "values (", - " '", Username, "', '", LUsername, "'," - " '", SFN, "', '", SLFN, "'," - " '", SFamily, "', '", SLFamily, "'," - " '", SGiven, "', '", SLGiven, "'," - " '", SMiddle, "', '", SLMiddle, "'," - " '", SNickname, "', '", SLNickname, "'," - " '", SBDay, "', '", SLBDay, "'," - " '", SCTRY, "', '", SLCTRY, "'," - " '", SLocality, "', '", SLLocality, "'," - " '", SEMail, "', '", SLEMail, "'," - " '", SOrgName, "', '", SLOrgName, "'," - " '", SOrgUnit, "', '", SLOrgUnit, "');"]]) + ejabberd_odbc:sql_transaction( + LServer, + [["delete from vcard where username='", LUsername, "';"], + ["insert into vcard(username, vcard) " + "values ('", LUsername, "', '", SVCARD, "');"], + ["delete from vcard_search where lusername='", LUsername, "';"], + ["insert into vcard_search(" + " username, lusername, fn, lfn, family, lfamily," + " given, lgiven, middle, lmiddle, nickname, lnickname," + " bday, lbday, ctry, lctry, locality, llocality," + " email, lemail, orgname, lorgname, orgunit, lorgunit)" + "values (", + " '", Username, "', '", LUsername, "'," + " '", SFN, "', '", SLFN, "'," + " '", SFamily, "', '", SLFamily, "'," + " '", SGiven, "', '", SLGiven, "'," + " '", SMiddle, "', '", SLMiddle, "'," + " '", SNickname, "', '", SLNickname, "'," + " '", SBDay, "', '", SLBDay, "'," + " '", SCTRY, "', '", SLCTRY, "'," + " '", SLocality, "', '", SLLocality, "'," + " '", SEMail, "', '", SLEMail, "'," + " '", SOrgName, "', '", SLOrgName, "'," + " '", SOrgUnit, "', '", SLOrgUnit, "');"]]) + catch + _ -> + {error, badarg} end. -define(TLFIELD(Type, Label, Var), - {xmlelement, "field", [{"type", Type}, - {"label", translate:translate(Lang, Label)}, - {"var", Var}], []}). + #xmlel{ns = ?NS_VCARD, name = 'field', attrs = [ + #xmlattr{name = 'type', value = Type}, + #xmlattr{name = 'label', value = translate:translate(Lang, Label)}, + #xmlattr{name = 'var', value = Var}]}). -define(FORM(JID), - [{xmlelement, "instructions", [], - [{xmlcdata, translate:translate(Lang, "You need an x:data capable client to search")}]}, - {xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}], - [{xmlelement, "title", [], - [{xmlcdata, translate:translate(Lang, "Search users in ") ++ - jlib:jid_to_string(JID)}]}, - {xmlelement, "instructions", [], - [{xmlcdata, translate:translate(Lang, "Fill in the form to search " - "for any matching Jabber User " - "(Add * to the end of field to " - "match substring)")}]}, + [#xmlel{ns = ?NS_SEARCH, name = 'instructions', children = + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "You need an x:data capable client to search"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = + [#xmlattr{name = 'type', value = "form"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ exmpp_jid:jid_to_list(JID))}]}, + #xmlel{ns = ?NS_SEARCH, name = 'instructions', children = + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, + "Fill in the form to search " + "for any matching Jabber User " + "(Add * to the end of field to " + "match substring)"))}]}, ?TLFIELD("text-single", "User", "user"), ?TLFIELD("text-single", "Full Name", "fn"), ?TLFIELD("text-single", "Name", "first"), @@ -303,157 +294,139 @@ set_vcard(User, LServer, VCARD) -> ]}]). do_route(ServerHost, From, To, Packet) -> - #jid{user = User, resource = Resource} = To, + #jid{node = User, resource = Resource} = To, if - (User /= "") or (Resource /= "") -> - Err = jlib:make_error_reply(Packet, ?ERR_SERVICE_UNAVAILABLE), + (User /= undefined) or (Resource /= undefined) -> + Err = exmpp_stanza:reply_with_error(Packet, 'service-unavailable'), ejabberd_router:route(To, From, Err); true -> - IQ = jlib:iq_query_info(Packet), - case IQ of - #iq{type = Type, xmlns = ?NS_SEARCH, lang = Lang, sub_el = SubEl} -> - case Type of - set -> - XDataEl = find_xdata_el(SubEl), - case XDataEl of - false -> - Err = jlib:make_error_reply( - Packet, ?ERR_BAD_REQUEST), - ejabberd_router:route(To, From, Err); - _ -> - XData = jlib:parse_xdata_submit(XDataEl), - case XData of - invalid -> - Err = jlib:make_error_reply( - Packet, - ?ERR_BAD_REQUEST), - ejabberd_router:route(To, From, - Err); - _ -> - ResIQ = - IQ#iq{ - type = result, - sub_el = - [{xmlelement, - "query", - [{"xmlns", ?NS_SEARCH}], - [{xmlelement, "x", - [{"xmlns", ?NS_XDATA}, - {"type", "result"}], - search_result(Lang, To, ServerHost, XData) - }]}]}, - ejabberd_router:route( - To, From, jlib:iq_to_xml(ResIQ)) - end - end; - get -> - ResIQ = IQ#iq{type = result, - sub_el = [{xmlelement, - "query", - [{"xmlns", ?NS_SEARCH}], - ?FORM(To) - }]}, - ejabberd_router:route(To, - From, - jlib:iq_to_xml(ResIQ)) - end; - #iq{type = Type, xmlns = ?NS_DISCO_INFO, lang = Lang} -> - case Type of - set -> - Err = jlib:make_error_reply( - Packet, ?ERR_NOT_ALLOWED), - ejabberd_router:route(To, From, Err); - get -> - ResIQ = - IQ#iq{type = result, - sub_el = [{xmlelement, - "query", - [{"xmlns", ?NS_DISCO_INFO}], - [{xmlelement, "identity", - [{"category", "directory"}, - {"type", "user"}, - {"name", - translate:translate(Lang, "vCard User Search")}], - []}, - {xmlelement, "feature", - [{"var", ?NS_SEARCH}], []}, - {xmlelement, "feature", - [{"var", ?NS_VCARD}], []} - ] - }]}, - ejabberd_router:route(To, - From, - jlib:iq_to_xml(ResIQ)) - end; - #iq{type = Type, xmlns = ?NS_DISCO_ITEMS} -> - case Type of - set -> - Err = jlib:make_error_reply( - Packet, ?ERR_NOT_ALLOWED), - ejabberd_router:route(To, From, Err); - get -> - ResIQ = - IQ#iq{type = result, - sub_el = [{xmlelement, - "query", - [{"xmlns", ?NS_DISCO_ITEMS}], - []}]}, - ejabberd_router:route(To, - From, - jlib:iq_to_xml(ResIQ)) - end; - #iq{type = get, xmlns = ?NS_VCARD, lang = Lang} -> - ResIQ = - IQ#iq{type = result, - sub_el = [{xmlelement, - "vCard", - [{"xmlns", ?NS_VCARD}], - iq_get_vcard(Lang)}]}, - ejabberd_router:route(To, - From, - jlib:iq_to_xml(ResIQ)); + try + Request = exmpp_iq:get_request(Packet), + Type = exmpp_iq:get_type(Packet), + Lang = exmpp_stanza:get_lang(Packet), + case {Type, Request#xmlel.ns} of + {set, ?NS_SEARCH} -> + XDataEl = find_xdata_el(Request), + case XDataEl of + false -> + Err = exmpp_iq:error(Packet, 'bad-request'), + ejabberd_router:route(To, From, Err); + _ -> + XData = jlib:parse_xdata_submit(XDataEl), + case XData of + invalid -> + Err = exmpp_iq:error(Packet, + 'bad-request'), + ejabberd_router:route(To, From, + Err); + _ -> + Result = #xmlel{ + ns = ?NS_SEARCH, + name = 'query', + children = [ + #xmlel{ + ns = ?NS_DATA_FORMS, + name = 'x', + attrs = [#xmlattr{name = 'type', + value = "result"}], + children = search_result(Lang, + To, ServerHost, XData)}]}, + ResIQ = exmpp_iq:result(Packet, + Result), + ejabberd_router:route( + To, From, jlib:iq_to_xml(ResIQ)) + end + end; + {get, ?NS_SEARCH} -> + Result = #xmlel{ns = ?NS_SEARCH, name = 'query', + children = ?FORM(To)}, + ResIQ = exmpp_iq:result(Packet, Result), + ejabberd_router:route(To, + From, + ResIQ); + {set, ?NS_DISCO_INFO} -> + Err = exmpp_iq:error(Packet, 'not-allowed'), + ejabberd_router:route(To, From, Err); + {get, ?NS_DISCO_INFO} -> + Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', + children = [ + #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', + attrs = [ + #xmlattr{name = 'category', + value = "directory"}, + #xmlattr{name = 'type', + value = "user"}, + #xmlattr{name = 'name', + value = translate:translate(Lang, + "vCard User Search")}]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', + attrs = [ + #xmlattr{name = 'var', + value = ?NS_SEARCH_s}]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', + attrs = [ + #xmlattr{name = 'var', + value = ?NS_VCARD_s}]} + ]}, + ResIQ = exmpp_iq:result(Packet, Result), + ejabberd_router:route(To, + From, + ResIQ); + {set, ?NS_DISCO_ITEMS} -> + Err = exmpp_iq:error(Packet, 'not-allowed'), + ejabberd_router:route(To, From, Err); + {get, ?NS_DISCO_ITEMS} -> + Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query'}, + ResIQ = exmpp_iq:result(Packet, Result), + ejabberd_router:route(To, + From, + ResIQ); + {get, ?NS_VCARD} -> + Result = #xmlel{ns = ?NS_VCARD, name = 'vCard', + children = iq_get_vcard(Lang)}, + ResIQ = exmpp_iq:result(Packet, Result), + ejabberd_router:route(To, + From, + ResIQ); + _ -> + Err = exmpp_iq:error(Packet, 'service-unavailable'), + ejabberd_router:route(To, From, Err) + end + catch _ -> - Err = jlib:make_error_reply(Packet, - ?ERR_SERVICE_UNAVAILABLE), - ejabberd_router:route(To, From, Err) + Err1 = exmpp_iq:error(Packet, 'service-unavailable'), + ejabberd_router:route(To, From, Err1) end end. iq_get_vcard(Lang) -> - [{xmlelement, "FN", [], - [{xmlcdata, "ejabberd/mod_vcard"}]}, - {xmlelement, "URL", [], - [{xmlcdata, ?EJABBERD_URI}]}, - {xmlelement, "DESC", [], - [{xmlcdata, translate:translate( - Lang, - "ejabberd vCard module") ++ - "\nCopyright (c) 2003-2008 ProcessOne"}]}]. + [ + #xmlel{ns = ?NS_SEARCH, name = 'FN', children = [ + #xmlcdata{cdata = <<"ejabberd/mod_vcard">>}]}, + #xmlel{ns = ?NS_SEARCH, name = 'URL', children = [ + #xmlcdata{cdata = list_to_binary(?EJABBERD_URI)}]}, + #xmlel{ns = ?NS_SEARCH, name ='DESC', children = [ + #xmlcdata{cdata = list_to_binary( + translate:translate(Lang, "ejabberd vCard module") ++ + "\nCopyright (c) 2003-2008 ProcessOne")}]} + ]. -find_xdata_el({xmlelement, _Name, _Attrs, SubEls}) -> +find_xdata_el(#xmlel{children = SubEls}) -> find_xdata_el1(SubEls). find_xdata_el1([]) -> false; -find_xdata_el1([{xmlelement, Name, Attrs, SubEls} | Els]) -> - case xml:get_attr_s("xmlns", Attrs) of - ?NS_XDATA -> - {xmlelement, Name, Attrs, SubEls}; - _ -> - find_xdata_el1(Els) - end; +find_xdata_el1([#xmlel{ns = ?NS_DATA_FORMS} = El | _Els]) -> + El; find_xdata_el1([_ | Els]) -> find_xdata_el1(Els). --define(LFIELD(Label, Var), - {xmlelement, "field", [{"label", translate:translate(Lang, Label)}, - {"var", Var}], []}). - search_result(Lang, JID, ServerHost, Data) -> - [{xmlelement, "title", [], - [{xmlcdata, translate:translate(Lang, "Search Results for ") ++ - jlib:jid_to_string(JID)}]}, - {xmlelement, "reported", [], + [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary( + translate:translate(Lang, "Search Results for ") ++ + exmpp_jid:jid_to_list(JID))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'reported', children = [?TLFIELD("text-single", "Jabber ID", "jid"), ?TLFIELD("text-single", "Full Name", "fn"), ?TLFIELD("text-single", "Name", "first"), @@ -470,15 +443,16 @@ search_result(Lang, JID, ServerHost, Data) -> search(ServerHost, Data)). -define(FIELD(Var, Val), - {xmlelement, "field", [{"var", Var}], - [{xmlelement, "value", [], - [{xmlcdata, Val}]}]}). + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [#xmlattr{name = 'var', value = Var}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = + [#xmlcdata{cdata = list_to_binary(Val)}]}]}). record_to_item(LServer, {Username, FN, Family, Given, Middle, Nickname, BDay, CTRY, Locality, EMail, OrgName, OrgUnit}) -> - {xmlelement, "item", [], + #xmlel{ns = ?NS_DATA_FORMS, name = 'item', children = [ ?FIELD("jid", Username ++ "@" ++ LServer), ?FIELD("fn", FN), @@ -546,7 +520,7 @@ filter_fields([], Match, _LServer) -> end; filter_fields([{SVar, [Val]} | Ds], Match, LServer) when is_list(Val) and (Val /= "") -> - LVal = stringprep:tolower(Val), + LVal = exmpp_stringprep:to_lower(Val), NewMatch = case SVar of "user" -> make_val(Match, "lusername", LVal); "fn" -> make_val(Match, "lfn", LVal); @@ -659,8 +633,8 @@ make_val(Match, Field, Val) -> remove_user(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), Username = ejabberd_odbc:escape(LUser), ejabberd_odbc:sql_transaction( LServer, From 0e91ea9e5fdbf07234913a8dabd8ab80ea16b65a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 23 Sep 2008 13:05:43 +0000 Subject: [PATCH 072/582] o Fix a bug in process_sm_iq/3 where a badmatch exception was raised when the user didn't have a vCard. o Fix a bug in remove_user/2 where the exmpp_jid module was use instead of exmpp_stringprep. SVN Revision: 1570 --- ChangeLog | 7 +++++++ src/mod_vcard.erl | 13 +++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 18b96220c..9ac30a97f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2008-09-23 Jean-Sébastien Pédron + + * src/mod_vcard.erl (process_sm_iq): Fix a bug where a badmatch + exception was raised when the user didn't have a vCard. + (remove_user): Fix a bug where the exmpp_jid module was use instead of + exmpp_stringprep. + 2008-09-22 Jean-Sébastien Pédron * src/mod_vcard.erl (get_sm_features): Remove unappropriate diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index 0a0b9bf21..16967fbb0 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -172,7 +172,7 @@ process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> F = fun() -> mnesia:read({vcard, US}) end, - [VCard | _] = case mnesia:transaction(F) of + Els = case mnesia:transaction(F) of {atomic, Rs} -> lists:map(fun(R) -> R#vcard.vcard @@ -180,7 +180,12 @@ process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> {aborted, _Reason} -> [] end, - exmpp_iq:result(IQ_Rec, VCard); + case Els of + [VCard | _] -> + exmpp_iq:result(IQ_Rec, VCard); + _ -> + exmpp_iq:result(IQ_Rec) + end; process_sm_iq(From, _To, #iq{type = set, payload = Request} = IQ_Rec) -> #jid{node = User, ldomain = LServer} = From, case lists:member(LServer, ?MYHOSTS) of @@ -643,8 +648,8 @@ reindex_vcards() -> remove_user(User, Server) -> - LUser = exmpp_jid:nodeprep(User), - LServer = exmpp_jid:nameprep(Server), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, F = fun() -> mnesia:delete({vcard, US}), From 052d006c885cf882c625882106929bf8f81e99c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 23 Sep 2008 13:06:45 +0000 Subject: [PATCH 073/582] Fix a typo in the exmpp_stringprep module name. SVN Revision: 1571 --- ChangeLog | 3 +++ src/ejabberd_auth_odbc.erl | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 9ac30a97f..6c85b890f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,9 @@ (remove_user): Fix a bug where the exmpp_jid module was use instead of exmpp_stringprep. + * src/ejabberd_auth_odbc.erl (check_password): Fix a typo in the + exmpp_stringprep module name. + 2008-09-22 Jean-Sébastien Pédron * src/mod_vcard.erl (get_sm_features): Remove unappropriate diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index 26eca6ab3..0daa24f8f 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -79,7 +79,7 @@ check_password(User, Server, Password) -> check_password(User, Server, Password, StreamID, Digest) -> try - LUser = exmpp_stringpre:nodeprep(User), + LUser = exmpp_stringprep:nodeprep(User), Username = ejabberd_odbc:escape(LUser), LServer = exmpp_stringprep:nameprep(Server), case catch odbc_queries:get_password(LServer, Username) of From 0dbbf53fbec8a887c48ec7de33320d9d3b493841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 23 Sep 2008 13:09:32 +0000 Subject: [PATCH 074/582] o Fix a misuse of exmpp_stanza:error/2: the namespace argument (the first one) was missing. o Fix a bug in process_privacy_iq/4 where the #iq record was not converted back to an #xmlel before calling ejabberd_router:route/3. SVN Revision: 1572 --- ChangeLog | 5 +++++ src/ejabberd_c2s.erl | 17 +++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6c85b890f..f873d3018 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,11 @@ * src/ejabberd_auth_odbc.erl (check_password): Fix a typo in the exmpp_stringprep module name. + * src/ejabberd_c2s.erl: Fix a misuse of exmpp_stanza:error/2: the + namespace argument (the first one) was missing. + (process_privacy_iq): Fix a bug where the #iq record was not converted + back to an #xmlel before calling ejabberd_router:route/3. + 2008-09-22 Jean-Sébastien Pédron * src/mod_vcard.erl (get_sm_features): Remove unappropriate diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 5b00509f3..53d364043 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -120,10 +120,11 @@ -define(DEFAULT_NS, ?NS_JABBER_CLIENT). -define(PREFIXED_NS, [{?NS_XMPP, ?NS_XMPP_pfx}]). --define(STANZA_ERROR(Condition), - exmpp_xml:xmlel_to_xmlelement(exmpp_stanza:error(Condition), +-define(STANZA_ERROR(NS, Condition), + exmpp_xml:xmlel_to_xmlelement(exmpp_stanza:error(NS, Condition), [?NS_JABBER_CLIENT], [{?NS_XMPP, "stream"}])). --define(ERR_FEATURE_NOT_IMPLEMENTED, ?STANZA_ERROR('feature-not-implemented')). +-define(ERR_FEATURE_NOT_IMPLEMENTED(NS), + ?STANZA_ERROR(NS, 'feature-not-implemented')). %%%---------------------------------------------------------------------- %%% API @@ -383,7 +384,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> exmpp_server_legacy_auth:fields(El, Fields)), fsm_next_state(wait_for_auth, StateData); {auth, _ID, set, {_U, _P, _D, undefined}} -> - Err = exmpp_stanza:error('not-acceptable', + Err = exmpp_stanza:error(El#xmlel.ns, 'not-acceptable', {"en", "No resource provided"}), send_element(StateData, exmpp_iq:error(El, Err)), fsm_next_state(wait_for_auth, StateData); @@ -1741,20 +1742,20 @@ update_priority(Priority, Packet, StateData) -> Info). process_privacy_iq(From, To, - #iq{type = Type} = IQ_Rec, + #iq{type = Type, iq_ns = IQ_NS} = IQ_Rec, StateData) -> {Res, NewStateData} = case Type of get -> R = ejabberd_hooks:run_fold( privacy_iq_get, StateData#state.server, - {error, ?ERR_FEATURE_NOT_IMPLEMENTED}, + {error, ?ERR_FEATURE_NOT_IMPLEMENTED(IQ_NS)}, [From, To, IQ_Rec, StateData#state.privacy_list]), {R, StateData}; set -> case ejabberd_hooks:run_fold( privacy_iq_set, StateData#state.server, - {error, ?ERR_FEATURE_NOT_IMPLEMENTED}, + {error, ?ERR_FEATURE_NOT_IMPLEMENTED(IQ_NS)}, [From, To, IQ_Rec]) of {result, R, NewPrivList} -> {{result, R}, @@ -1770,7 +1771,7 @@ process_privacy_iq(From, To, exmpp_iq:error(IQ_Rec, Error) end, ejabberd_router:route( - To, From, IQRes), + To, From, exmpp_iq:iq_to_xmlel(IQRes)), NewStateData. From 44c77364ce052661d5df32b513e30d2334dc3e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 23 Sep 2008 13:10:33 +0000 Subject: [PATCH 075/582] Fix a typo in the exmpp_stringprep module name. SVN Revision: 1573 --- ChangeLog | 4 ++-- src/mod_roster.erl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index f873d3018..c72d2c44c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,8 +5,8 @@ (remove_user): Fix a bug where the exmpp_jid module was use instead of exmpp_stringprep. - * src/ejabberd_auth_odbc.erl (check_password): Fix a typo in the - exmpp_stringprep module name. + * src/ejabberd_auth_odbc.erl (check_password), src/mod_roster.erl + (remove_user): Fix a typo in the exmpp_stringprep module name. * src/ejabberd_c2s.erl: Fix a misuse of exmpp_stanza:error/2: the namespace argument (the first one) was missing. diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 878305652..b97171a5e 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -553,7 +553,7 @@ in_auto_reply(_, _, _) -> none. remove_user(User, Server) -> try - LUser = exmpp_stringpre:nodeprep(User), + LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, F = fun() -> From c74ab439efea4ac389e7229542c014f8ba68ecb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 23 Sep 2008 13:11:05 +0000 Subject: [PATCH 076/582] Convert to exmpp. SVN Revision: 1574 --- ChangeLog | 2 + src/mod_register.erl | 190 +++++++++++++++++++------------------------ 2 files changed, 87 insertions(+), 105 deletions(-) diff --git a/ChangeLog b/ChangeLog index c72d2c44c..2f185edc8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,8 @@ (process_privacy_iq): Fix a bug where the #iq record was not converted back to an #xmlel before calling ejabberd_router:route/3. + * src/mod_register.erl: Convert to exmpp. + 2008-09-22 Jean-Sébastien Pédron * src/mod_vcard.erl (get_sm_features): Remove unappropriate diff --git a/src/mod_register.erl b/src/mod_register.erl index 7a4eca79f..49c3b209b 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -35,14 +35,15 @@ unauthenticated_iq_register/4, process_iq/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_REGISTER, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_INBAND_REGISTER, ?MODULE, process_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_REGISTER, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_INBAND_REGISTER, ?MODULE, process_iq, IQDisc), ejabberd_hooks:add(c2s_stream_features, Host, ?MODULE, stream_feature_register, 50), @@ -60,61 +61,56 @@ stop(Host) -> ?MODULE, stream_feature_register, 50), ejabberd_hooks:delete(c2s_unauthenticated_iq, Host, ?MODULE, unauthenticated_iq_register, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_REGISTER), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_REGISTER). + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_INBAND_REGISTER), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_INBAND_REGISTER). stream_feature_register(Acc) -> - [{xmlelement, "register", - [{"xmlns", ?NS_FEATURE_IQREGISTER}], []} | Acc]. + [#xmlel{ns = ?NS_INBAND_REGISTER_FEAT, name = 'register'} | Acc]. unauthenticated_iq_register(_Acc, - Server, #iq{xmlns = ?NS_REGISTER} = IQ, IP) -> + Server, #iq{ns = ?NS_INBAND_REGISTER} = IQ_Rec, IP) -> Address = case IP of {A, _Port} -> A; _ -> undefined end, - ResIQ = process_iq(jlib:make_jid("", "", ""), - jlib:make_jid("", Server, ""), - IQ, + ResIQ = process_iq(#jid{}, + exmpp_jid:make_bare_jid(Server), + IQ_Rec, Address), - Res1 = jlib:replace_from_to(jlib:make_jid("", Server, ""), - jlib:make_jid("", "", ""), - jlib:iq_to_xml(ResIQ)), - jlib:remove_attr("to", Res1); + exmpp_iq:iq_to_xmlel(ResIQ, exmpp_jid:make_bare_jid(Server), undefined); unauthenticated_iq_register(Acc, _Server, _IQ, _IP) -> Acc. process_iq(From, To, IQ) -> - process_iq(From, To, IQ, jlib:jid_tolower(jlib:jid_remove_resource(From))). + process_iq(From, To, IQ, jlib:short_prepd_bare_jid(From)). process_iq(From, To, - #iq{type = Type, lang = Lang, sub_el = SubEl, id = ID} = IQ, + #iq{type = Type, lang = Lang, payload = SubEl} = IQ_Rec, Source) -> case Type of set -> - UTag = xml:get_subtag(SubEl, "username"), - PTag = xml:get_subtag(SubEl, "password"), - RTag = xml:get_subtag(SubEl, "remove"), - Server = To#jid.lserver, + UTag = exmpp_xml:get_element(SubEl, 'username'), + PTag = exmpp_xml:get_element(SubEl, 'password'), + RTag = exmpp_xml:get_element(SubEl, 'remove'), + Server = To#jid.ldomain, if - (UTag /= false) and (RTag /= false) -> - User = xml:get_tag_cdata(UTag), + (UTag /= undefined) and (RTag /= undefined) -> + User = exmpp_xml:get_cdata_as_list(UTag), case From of - #jid{user = User, lserver = Server} -> + #jid{node = User, ldomain = Server} -> ejabberd_auth:remove_user(User, Server), - IQ#iq{type = result, sub_el = [SubEl]}; + exmpp_iq:result(IQ_Rec, SubEl); _ -> if - PTag /= false -> - Password = xml:get_tag_cdata(PTag), + PTag /= undefined -> + Password = exmpp_xml:get_cdata_as_list(PTag), case ejabberd_auth:remove_user(User, Server, Password) of ok -> - IQ#iq{type = result, - sub_el = [SubEl]}; + exmpp_iq:result(IQ_Rec, SubEl); %% TODO FIXME: This piece of %% code does not work since %% the code have been changed @@ -122,102 +118,88 @@ process_iq(From, To, %% modules. lists:foreach can %% only return ok: not_allowed -> - IQ#iq{type = error, - sub_el = - [SubEl, ?ERR_NOT_ALLOWED]}; + exmpp_iq:error(IQ_Rec, + 'not-allowed'); not_exists -> - IQ#iq{type = error, - sub_el = - [SubEl, ?ERR_ITEM_NOT_FOUND]}; + exmpp_iq:error(IQ_Rec, + 'item-not-found'); _ -> - IQ#iq{type = error, - sub_el = - [SubEl, - ?ERR_INTERNAL_SERVER_ERROR]} + exmpp_iq:error(IQ_Rec, + 'internal-server-error') end; true -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_BAD_REQUEST]} + exmpp_iq:error(IQ_Rec, 'bad-request') end end; - (UTag == false) and (RTag /= false) -> + (UTag == undefined) and (RTag /= undefined) -> case From of - #jid{user = User, - lserver = Server, + #jid{node = User, + ldomain = Server, resource = Resource} -> - ResIQ = #iq{type = result, xmlns = ?NS_REGISTER, - id = ID, - sub_el = [SubEl]}, + ResIQ = exmpp_iq:result(IQ_Rec, SubEl), ejabberd_router:route( - jlib:make_jid(User, Server, Resource), - jlib:make_jid(User, Server, Resource), - jlib:iq_to_xml(ResIQ)), + exmpp_jid:make_jid(User, Server, Resource), + exmpp_jid:make_jid(User, Server, Resource), + exmpp_iq:iq_to_xmlel(ResIQ)), ejabberd_auth:remove_user(User, Server), ignore; _ -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_NOT_ALLOWED]} + exmpp_iq:error(IQ_Rec, 'not-allowed') end; - (UTag /= false) and (PTag /= false) -> - User = xml:get_tag_cdata(UTag), - Password = xml:get_tag_cdata(PTag), + (UTag /= undefined) and (PTag /= undefined) -> + User = exmpp_xml:get_cdata_as_list(UTag), + Password = exmpp_xml:get_cdata_as_list(PTag), case From of - #jid{user = User, lserver = Server} -> - try_set_password(User, Server, Password, IQ, SubEl); + #jid{node = User, ldomain = Server} -> + try_set_password(User, Server, Password, IQ_Rec, SubEl); _ -> case try_register(User, Server, Password, Source, Lang) of ok -> - IQ#iq{type = result, sub_el = [SubEl]}; + exmpp_iq:result(IQ_Rec, SubEl); {error, Error} -> - IQ#iq{type = error, - sub_el = [SubEl, Error]} + exmpp_iq:error(IQ_Rec, Error) end end; true -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_BAD_REQUEST]} + exmpp_iq:error(IQ_Rec, 'bad-request') end; get -> - IQ#iq{type = result, - sub_el = [{xmlelement, - "query", - [{"xmlns", "jabber:iq:register"}], - [{xmlelement, "instructions", [], - [{xmlcdata, - translate:translate( - Lang, - "Choose a username and password " - "to register with this server")}]}, - {xmlelement, "username", [], []}, - {xmlelement, "password", [], []}]}]} + Result = #xmlel{ns = ?NS_INBAND_REGISTER, name = 'query', children = + [#xmlel{ns = ?NS_INBAND_REGISTER, name = 'instructions', children = + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, + "Choose a username and password " + "to register with this server"))}]}, + #xmlel{ns = ?NS_INBAND_REGISTER, name = 'username'}, + #xmlel{ns = ?NS_INBAND_REGISTER, name = 'password'}]}, + exmpp_iq:result(IQ_Rec, Result) end. %% @doc Try to change password and return IQ response -try_set_password(User, Server, Password, IQ, SubEl) -> +try_set_password(User, Server, Password, IQ_Rec, SubEl) -> case ejabberd_auth:set_password(User, Server, Password) of ok -> - IQ#iq{type = result, sub_el = [SubEl]}; + exmpp_iq:result(IQ_Rec, SubEl); {error, empty_password} -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]}; + exmpp_iq:error(IQ_Rec, 'bad-request'); {error, not_allowed} -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + exmpp_iq:error(IQ_Rec, 'not-allowed'); {error, invalid_jid} -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]}; + exmpp_iq:error(IQ_Rec, 'item-not-found'); _ -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]} + exmpp_iq:error(IQ_Rec, 'internal-server-error') end. try_register(User, Server, Password, Source, Lang) -> - case jlib:is_nodename(User) of + case exmpp_stringprep:is_node(User) of false -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; _ -> - JID = jlib:make_jid(User, Server, ""), + JID = exmpp_jid:make_bare_jid(User, Server), Access = gen_mod:get_module_opt(Server, ?MODULE, access, all), case acl:match_rule(Server, Access, JID) of deny -> - {error, ?ERR_CONFLICT}; + {error, 'conflict'}; allow -> case check_timeout(Source) of true -> @@ -232,60 +214,58 @@ try_register(User, Server, Password, Source, Lang) -> remove_timeout(Source), case Error of {atomic, exists} -> - {error, ?ERR_CONFLICT}; + {error, 'conflict'}; {error, invalid_jid} -> - {error, ?ERR_JID_MALFORMED}; + {error, 'jid-malformed'}; {error, not_allowed} -> - {error, ?ERR_NOT_ALLOWED}; + {error, 'not-allowed'}; {error, _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR} + {error, 'internal-server-error'} end end; false -> ErrText = "Users are not allowed to register " "accounts so fast", - {error, ?ERRT_RESOURCE_CONSTRAINT(Lang, ErrText)} + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'resource-constraint', {Lang, ErrText})} end end end. send_welcome_message(JID) -> - Host = JID#jid.lserver, + Host = JID#jid.ldomain, case gen_mod:get_module_opt(Host, ?MODULE, welcome_message, {"", ""}) of {"", ""} -> ok; {Subj, Body} -> ejabberd_router:route( - jlib:make_jid("", Host, ""), + exmpp_jid:make_bare_jid(Host), JID, - {xmlelement, "message", [{"type", "normal"}], - [{xmlelement, "subject", [], [{xmlcdata, Subj}]}, - {xmlelement, "body", [], [{xmlcdata, Body}]}]}); + exmpp_message:normal(Subj, Body)); _ -> ok end. send_registration_notifications(UJID) -> - Host = UJID#jid.lserver, + Host = UJID#jid.ldomain, case gen_mod:get_module_opt(Host, ?MODULE, registration_watchers, []) of [] -> ok; JIDs when is_list(JIDs) -> Body = lists:flatten( io_lib:format( "The user '~s' was just created on node ~w.", - [jlib:jid_to_string(UJID), node()])), + [exmpp_jid:jid_to_list(UJID), node()])), lists:foreach( fun(S) -> - case jlib:string_to_jid(S) of - error -> ok; - JID -> - ejabberd_router:route( - jlib:make_jid("", Host, ""), - JID, - {xmlelement, "message", [{"type", "chat"}], - [{xmlelement, "body", [], - [{xmlcdata, Body}]}]}) + try + JID = exmpp_jid:list_to_jid(S), + ejabberd_router:route( + exmpp_jid:make_bare_jid(Host), + JID, + exmpp_message:chat(Body)) + catch + _ -> + ok end end, JIDs); _ -> From c068d20588d9d7a6892f85d2e964b2279b240e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 25 Sep 2008 10:46:00 +0000 Subject: [PATCH 077/582] In mod_offline: o Remove any compatibility code: the core of Ejabberd expects new structures. o Add table conversion. o Add try/catch block around exmpp_stringprep:*prep/1 uses. To permit the complete removal of the compatibility code, jlib had to be changed too: the timestamp_to_xml/1 function now returns an #xmlel. SVN Revision: 1575 --- ChangeLog | 9 ++ src/jlib.erl | 13 +- src/mod_offline.erl | 291 +++++++++++++++++++++++++++----------------- 3 files changed, 195 insertions(+), 118 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2f185edc8..f12ab5cd0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2008-09-25 Jean-Sébastien Pédron + + * src/jlib.erl (timestamp_to_xml): Create an #xmlel element, not an + old #xmlelement. + + * src/mod_offline.erl: Remove any compatibility code: the core of + Ejabberd expects new structures. Add table conversion. Add try/catch + block around exmpp_stringprep:*prep/1 uses. + 2008-09-23 Jean-Sébastien Pédron * src/mod_vcard.erl (process_sm_iq): Fix a bug where a badmatch diff --git a/src/jlib.erl b/src/jlib.erl index 288e5f6c6..b64fc3a1b 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -68,6 +68,8 @@ short_prepd_jid/1, short_prepd_bare_jid/1]). +-include_lib("exmpp/include/exmpp_xml.hrl"). + -include("jlib.hrl"). %send_iq(From, To, ID, SubTags) -> @@ -517,12 +519,11 @@ timestamp_to_iso({{Year, Month, Day}, {Hour, Minute, Second}}) -> [Year, Month, Day, Hour, Minute, Second])). timestamp_to_xml({{Year, Month, Day}, {Hour, Minute, Second}}) -> - {xmlelement, "x", - [{"xmlns", ?NS_DELAY}, - {"stamp", lists:flatten( - io_lib:format("~4..0w~2..0w~2..0wT~2..0w:~2..0w:~2..0w", - [Year, Month, Day, Hour, Minute, Second]))}], - []}. + Timestamp = lists:flatten( + io_lib:format("~4..0w~2..0w~2..0wT~2..0w:~2..0w:~2..0w", + [Year, Month, Day, Hour, Minute, Second])), + exmpp_xml:set_attribute(#xmlel{ns = ?NS_DELAY, name = 'x'}, + 'stamp', Timestamp). now_to_utc_string({MegaSecs, Secs, MicroSecs}) -> {{Year, Month, Day}, {Hour, Minute, Second}} = diff --git a/src/mod_offline.erl b/src/mod_offline.erl index f79b0c19f..ecabbf5c5 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -157,16 +157,13 @@ store_packet(From, To, Packet) -> #jid{lnode = LUser, ldomain = LServer} = To, TimeStamp = now(), Expire = find_x_expire(TimeStamp, Packet#xmlel.children), - % XXX OLD FORMAT: Packet is stored in the old format. - PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet, - [?DEFAULT_NS], ?PREFIXED_NS), gen_mod:get_module_proc(To#jid.ldomain, ?PROCNAME) ! #offline_msg{us = {LUser, LServer}, timestamp = TimeStamp, expire = Expire, from = From, to = To, - packet = PacketOld}, + packet = Packet}, stop; _ -> ok @@ -233,80 +230,76 @@ find_x_expire(TimeStamp, [_ | Els]) -> resend_offline_messages(User, Server) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - US = {LUser, LServer}, - F = fun() -> - Rs = mnesia:wread({offline_msg, US}), - mnesia:delete({offline_msg, US}), - Rs - end, - case mnesia:transaction(F) of - {atomic, Rs} -> - lists:foreach( - fun(R) -> - Packet = case R#offline_msg.packet of - #xmlelement{} = P -> - exmpp_xml:xmlelement_to_xmlel(P, - [?DEFAULT_NS], ?PREFIXED_NS); - #xmlel{} = P -> - P - end, - % XXX OLD FORMAT: Convert From & To. - ejabberd_sm ! - {route, - jlib:from_old_jid(R#offline_msg.from), - jlib:from_old_jid(R#offline_msg.to), - exmpp_xml:append_child(Packet, - jlib:timestamp_to_xml( - calendar:now_to_universal_time( - R#offline_msg.timestamp)))} - end, - lists:keysort(#offline_msg.timestamp, Rs)); + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + F = fun() -> + Rs = mnesia:wread({offline_msg, US}), + mnesia:delete({offline_msg, US}), + Rs + end, + case mnesia:transaction(F) of + {atomic, Rs} -> + lists:foreach( + fun(R) -> + Packet = R#offline_msg.packet, + ejabberd_sm ! + {route, + R#offline_msg.from, + R#offline_msg.to, + exmpp_xml:append_child(Packet, + jlib:timestamp_to_xml( + calendar:now_to_universal_time( + R#offline_msg.timestamp)))} + end, + lists:keysort(#offline_msg.timestamp, Rs)); + _ -> + ok + end + catch _ -> ok end. pop_offline_messages(Ls, User, Server) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - US = {LUser, LServer}, - F = fun() -> - Rs = mnesia:wread({offline_msg, US}), - mnesia:delete({offline_msg, US}), - Rs - end, - case mnesia:transaction(F) of - {atomic, Rs} -> - TS = now(), - Ls ++ lists:map( - fun(R) -> - Packet = case R#offline_msg.packet of - #xmlelement{} = P -> - exmpp_xml:xmlelement_to_xmlel(P, - [?DEFAULT_NS], ?PREFIXED_NS); - #xmlel{} = P -> - P - end, - % XXX OLD FORMAT: Convert From & To. - {route, - jlib:from_old_jid(R#offline_msg.from), - jlib:from_old_jid(R#offline_msg.to), - exmpp_xml:append_child(Packet, - jlib:timestamp_to_xml( - calendar:now_to_universal_time( - R#offline_msg.timestamp)))} - end, - lists:filter( - fun(R) -> - case R#offline_msg.expire of - never -> - true; - TimeStamp -> - TS < TimeStamp - end - end, - lists:keysort(#offline_msg.timestamp, Rs))); + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + F = fun() -> + Rs = mnesia:wread({offline_msg, US}), + mnesia:delete({offline_msg, US}), + Rs + end, + case mnesia:transaction(F) of + {atomic, Rs} -> + TS = now(), + Ls ++ lists:map( + fun(R) -> + Packet = R#offline_msg.packet, + {route, + R#offline_msg.from, + R#offline_msg.to, + exmpp_xml:append_child(Packet, + jlib:timestamp_to_xml( + calendar:now_to_universal_time( + R#offline_msg.timestamp)))} + end, + lists:filter( + fun(R) -> + case R#offline_msg.expire of + never -> + true; + TimeStamp -> + TS < TimeStamp + end + end, + lists:keysort(#offline_msg.timestamp, Rs))); + _ -> + Ls + end + catch _ -> Ls end. @@ -350,19 +343,24 @@ remove_old_messages(Days) -> mnesia:transaction(F). remove_user(User, Server) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - US = {LUser, LServer}, - F = fun() -> - mnesia:delete({offline_msg, US}) - end, - mnesia:transaction(F). + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + F = fun() -> + mnesia:delete({offline_msg, US}) + end, + mnesia:transaction(F) + catch + _ -> + ok + end. update_table() -> Fields = record_info(fields, offline_msg), case mnesia:table_info(offline_msg, attributes) of Fields -> - ok; + convert_to_exmpp(); [user, timestamp, expire, from, to, packet] -> ?INFO_MSG("Converting offline_msg table from " "{user, timestamp, expire, from, to, packet} format", []), @@ -378,11 +376,19 @@ update_table() -> F1 = fun() -> mnesia:write_lock_table(mod_offline_tmp_table), mnesia:foldl( - fun(#offline_msg{us = U, packet = P} = R, _) -> + fun(#offline_msg{us = U, from = F, to = T, packet = P} = R, _) -> + U1 = convert_jid_to_exmpp(U), + F1 = jlib:from_old_jid(F), + T1 = jlib:from_old_jid(T), + P1 = exmpp_xml:xmlelement_to_xmlel( + P, + [?DEFAULT_NS], + ?PREFIXED_NS), New_R = R#offline_msg{ - us = {U, Host}, - packet = exmpp_xml:xmlelement_to_xmlel(P, - [?DEFAULT_NS], ?PREFIXED_NS) + us = {U1, Host}, + from = F1, + to = T1, + packet = P1 }, mnesia:dirty_write( mod_offline_tmp_table, @@ -415,12 +421,19 @@ update_table() -> offline_msg, fun({_, U, TS, F, T, P}) -> Expire = find_x_expire(TS, P#xmlelement.children), - #offline_msg{us = U, + U1 = convert_jid_to_exmpp(U), + F1 = jlib:from_old_jid(F), + T1 = jlib:from_old_jid(T), + P1 = exmpp_xml:xmlelement_to_xmlel( + P, + [?DEFAULT_NS], + ?PREFIXED_NS), + #offline_msg{us = U1, timestamp = TS, expire = Expire, - from = F, - to = T, - packet = P} + from = F1, + to = T1, + packet = P1} end, Fields), F1 = fun() -> mnesia:write_lock_table(mod_offline_tmp_table), @@ -447,27 +460,64 @@ update_table() -> mnesia:transform_table(offline_msg, ignore, Fields) end. +convert_to_exmpp() -> + Fun = fun() -> + case mnesia:first(offline_msg) of + '$end_of_table' -> + none; + Key -> + case mnesia:read({offline_msg, Key}) of + [#offline_msg{packet = #xmlel{}} | _] -> + none; + [#offline_msg{packet = #xmlelement{}} | _] -> + mnesia:foldl(fun convert_to_exmpp2/2, + done, offline_msg, write) + end + end + end, + mnesia:transaction(Fun). + +convert_to_exmpp2(#offline_msg{ + us = {US_U, US_S}, + from = From, + to = To, + packet = Packet} = R, Acc) -> + % Remove old entry. + mnesia:delete_object(R), + % Convert "" to undefined in JIDs. + US_U1 = convert_jid_to_exmpp(US_U), + US_S1 = convert_jid_to_exmpp(US_S), + From1 = jlib:from_old_jid(From), + To1 = jlib:from_old_jid(To), + % Convert stanza. + Packet1 = exmpp_xml:xmlelement_to_xmlel(Packet, + [?DEFAULT_NS], ?PREFIXED_NS), + % Prepare the new record. + New_R = R#offline_msg{ + us = {US_U1, US_S1}, + from = From1, + to = To1, + packet = Packet1}, + % Write the new record. + mnesia:write(New_R), + Acc. + +convert_jid_to_exmpp("") -> undefined; +convert_jid_to_exmpp(V) -> V. %% Helper functions: %% Warn senders that their messages have been discarded: discard_warn_sender(Msgs) -> lists:foreach( - fun(#offline_msg{from=From, to=To, packet=Packet0}) -> - Packet = case Packet0 of - #xmlelement{} = P -> - exmpp_xml:xmlelement_to_xmlel(P, - [?DEFAULT_NS], ?PREFIXED_NS); - #xmlel{} = P -> - P - end, + fun(#offline_msg{from=From, to=To, packet=Packet}) -> ErrText = "Your contact offline message queue is full. The message has been discarded.", Error = exmpp_stanza:error('resource-constraint', {"en", ErrText}), Err = exmpp_stanza:reply_with_error(Packet, Error), ejabberd_router:route( - jlib:from_old_jid(To), - jlib:from_old_jid(From), Err) + To, + From, Err) end, Msgs). @@ -482,10 +532,21 @@ webadmin_page(_, Host, webadmin_page(Acc, _, _) -> Acc. user_queue(User, Server, Query, Lang) -> - US = {exmpp_stringprep:nodeprep(User), exmpp_stringprep:nameprep(Server)}, - Res = user_queue_parse_query(US, Query), - Msgs = lists:keysort(#offline_msg.timestamp, - mnesia:dirty_read({offline_msg, US})), + {US, Msgs, Res} = try + US0 = { + exmpp_stringprep:nodeprep(User), + exmpp_stringprep:nameprep(Server) + }, + { + US0, + lists:keysort(#offline_msg.timestamp, + mnesia:dirty_read({offline_msg, US0})), + user_queue_parse_query(US0, Query) + } + catch + _ -> + {{"invalid", "invalid"}, [], nothing} + end, FMsgs = lists:map( fun(#offline_msg{timestamp = TimeStamp, from = From, to = To, @@ -497,11 +558,9 @@ user_queue(User, Server, Query, Lang) -> io_lib:format( "~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", [Year, Month, Day, Hour, Minute, Second])), - SFrom = exmpp_jid:jid_to_list(jlib:from_old_jid(From)), - STo = exmpp_jid:jid_to_list(jlib:from_old_jid(To)), - Packet0 = exmpp_xml:xmlelement_to_xmlel(Packet, - [?DEFAULT_NS], ?PREFIXED_NS), - Packet1 = exmpp_stanza:set_jids(Packet0, SFrom, STo), + SFrom = exmpp_jid:jid_to_list(From), + STo = exmpp_jid:jid_to_list(To), + Packet1 = exmpp_stanza:set_jids(Packet, SFrom, STo), FPacket = exmpp_xml:node_to_list( exmpp_xml:indent_document(Packet1, <<" ">>), [?DEFAULT_NS], ?PREFIXED_NS), @@ -571,8 +630,16 @@ us_to_list({User, Server}) -> exmpp_jid:jid_to_list(User, Server). webadmin_user(Acc, User, Server, Lang) -> - US = {exmpp_stringprep:nodeprep(User), exmpp_stringprep:nameprep(Server)}, - QueueLen = length(mnesia:dirty_read({offline_msg, US})), - FQueueLen = [?AC("queue/", - integer_to_list(QueueLen))], + FQueueLen = try + US = { + exmpp_stringprep:nodeprep(User), + exmpp_stringprep:nameprep(Server) + }, + QueueLen = length(mnesia:dirty_read({offline_msg, US})), + [?AC("queue/", + integer_to_list(QueueLen))] + catch + _ -> + [?C("?")] + end, Acc ++ [?XCT("h3", "Offline Messages:")] ++ FQueueLen. From c32cbd90e8d0d24c35c9b16d0fea37e2446043b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 29 Sep 2008 09:42:05 +0000 Subject: [PATCH 078/582] Fix a bug in parse_xdata_submit/1 and parse_xdata_fields/2 where exmpp_xml:get_attribute_from_list/3 was called with only 2 arguments; this code has not been updated when exmpp_xml's API changed... SVN Revision: 1577 --- ChangeLog | 7 +++++++ src/jlib.erl | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index f12ab5cd0..fe63130b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2008-09-29 Jean-Sébastien Pédron + + * src/jlib.erl (parse_xdata_submit, parse_xdata_fields): Fix a bug + where exmpp_xml:get_attribute_from_list/3 was called with only 2 + arguments; this code has not been updated when exmpp_xml's API + changed... + 2008-09-25 Jean-Sébastien Pédron * src/jlib.erl (timestamp_to_xml): Create an #xmlel element, not an diff --git a/src/jlib.erl b/src/jlib.erl index b64fc3a1b..73fc5fc0f 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -453,7 +453,7 @@ iq_to_xml(#iq{id = ID, type = Type, sub_el = SubEl}) -> parse_xdata_submit({xmlel, _, _, _, Attrs, Els}) -> - case exmpp_xml:get_attribute_from_list(Attrs, 'type') of + case exmpp_xml:get_attribute_from_list(Attrs, 'type', "") of "submit" -> lists:reverse(parse_xdata_fields(Els, [])); _ -> @@ -472,7 +472,7 @@ parse_xdata_fields([], Res) -> Res; parse_xdata_fields([{xmlel, _, _, 'field', Attrs, SubEls} | Els], Res) -> - case exmpp_xml:get_attribute_from_list(Attrs, 'var') of + case exmpp_xml:get_attribute_from_list(Attrs, 'var', "") of "" -> parse_xdata_fields(Els, Res); Var -> From 76242840709f355b81dbc59603a1bb0e99b99773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 29 Sep 2008 09:42:46 +0000 Subject: [PATCH 079/582] Remove compatilibity code. SVN Revision: 1578 --- ChangeLog | 2 ++ src/mod_disco.erl | 30 ++++++------------------------ 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index fe63130b1..b2f45b347 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,8 @@ arguments; this code has not been updated when exmpp_xml's API changed... + * src/mod_disco.erl: Remove compatilibity code. + 2008-09-25 Jean-Sébastien Pédron * src/jlib.erl (timestamp_to_xml): Create an #xmlel element, not an diff --git a/src/mod_disco.erl b/src/mod_disco.erl index e1539fbd3..21097c79d 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -131,15 +131,11 @@ process_local_iq_items(From, To, #iq{type = get, payload = SubEl, Host = To#jid.ldomain, Node = exmpp_xml:get_attribute(SubEl, 'node', ""), - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), case ejabberd_hooks:run_fold(disco_local_items, Host, empty, - [FromOld, ToOld, Node, Lang]) of + [From, To, Node, Lang]) of {result, Items} -> - % XXX OLD FORMAT: Items might be an #xmlelement. ANode = case Node of "" -> []; _ -> [#xmlattr{name = 'node', value = Node}] @@ -148,7 +144,6 @@ process_local_iq_items(From, To, #iq{type = get, payload = SubEl, attrs = ANode, children = Items}, exmpp_iq:result(IQ_Rec, Result); {error, Error} -> - % XXX OLD FORMAT: Error. exmpp_iq:error(IQ_Rec, Error) end; process_local_iq_items(_From, _To, #iq{type = set} = IQ_Rec) -> @@ -159,19 +154,14 @@ process_local_iq_info(From, To, #iq{type = get, payload = SubEl, lang = Lang} = IQ_Rec) -> Host = To#jid.ldomain, Node = exmpp_xml:get_attribute(SubEl, 'node', ""), - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - % XXX OLD FORMAT: Identity might be an #xmlelement. Identity = ejabberd_hooks:run_fold(disco_local_identity, Host, [], - [FromOld, ToOld, Node, Lang]), - % XXX OLD FORMAT: From, To. + [From, To, Node, Lang]), case ejabberd_hooks:run_fold(disco_local_features, Host, empty, - [FromOld, ToOld, Node, Lang]) of + [From, To, Node, Lang]) of {result, Features} -> ANode = case Node of "" -> []; @@ -243,7 +233,6 @@ get_local_services({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; get_local_services(Acc, _From, To, [], _Lang) -> - % XXX OLD FORMAT: Items might be an #xmlelement. Items = case Acc of {result, Its} -> Its; empty -> [] @@ -283,13 +272,10 @@ process_sm_iq_items(From, To, #iq{type = get, payload = SubEl, lang = Lang} = IQ_Rec) -> Host = To#jid.ldomain, Node = exmpp_xml:get_attribute(SubEl, 'node', ""), - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), case ejabberd_hooks:run_fold(disco_sm_items, Host, empty, - [FromOld, ToOld, Node, Lang]) of + [From, To, Node, Lang]) of {result, Items} -> ANode = case Node of "" -> []; @@ -355,18 +341,14 @@ process_sm_iq_info(From, To, #iq{type = get, payload = SubEl, lang = Lang} = IQ_Rec) -> Host = To#jid.ldomain, Node = exmpp_xml:get_attribute(SubEl, 'node', ""), - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - % XXX OLD FORMAT: Identity might be an #xmlelement. Identity = ejabberd_hooks:run_fold(disco_sm_identity, Host, [], - [FromOld, ToOld, Node, Lang]), + [From, To, Node, Lang]), case ejabberd_hooks:run_fold(disco_sm_features, Host, empty, - [FromOld, ToOld, Node, Lang]) of + [From, To, Node, Lang]) of {result, Features} -> ANode = case Node of "" -> []; From 9a4f5bb2d9fa4468faa3b29bcc54eab7b186356d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 29 Sep 2008 10:31:24 +0000 Subject: [PATCH 080/582] When the status is not specified in a presence stanza, default to an empty binary, not an empty string; this is what mod_last expects. SVN Revision: 1579 --- ChangeLog | 4 ++++ src/ejabberd_c2s.erl | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index b2f45b347..2232ab668 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,10 @@ * src/mod_disco.erl: Remove compatilibity code. + * src/ejabberd_c2s.erl: When the status is not specified in a presence + stanza, default to an empty binary, not an empty string; this is what + mod_last expects. + 2008-09-25 Jean-Sébastien Pédron * src/jlib.erl (timestamp_to_xml): Create an #xmlel element, not an diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 53d364043..636c1d33f 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1382,7 +1382,7 @@ presence_update(From, Packet, StateData) -> case exmpp_presence:get_type(Packet) of 'unavailable' -> Status = case exmpp_presence:get_status(Packet) of - undefined -> ""; + undefined -> <<>>; S -> S end, Info = [{ip, StateData#state.ip}, {conn, StateData#state.conn}, From d8153b702a949224c6033bf7b273c0a73c9356ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 29 Sep 2008 10:34:06 +0000 Subject: [PATCH 081/582] o Add try/catch block around exmpp_stringprep:*prep/1 uses. o Add table conversion. o In get_last/3, do not convert status to binary because it's already one. SVN Revision: 1580 --- ChangeLog | 4 +++ src/mod_last.erl | 86 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 69 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2232ab668..696cac7ff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,6 +11,10 @@ stanza, default to an empty binary, not an empty string; this is what mod_last expects. + * src/mod_last.erl: Add try/catch block around + exmpp_stringprep:*prep/1 uses. Add table conversion. + (get_last): Do not convert status to binary because it's already one. + 2008-09-25 Jean-Sébastien Pédron * src/jlib.erl (timestamp_to_xml): Create an #xmlel element, not an diff --git a/src/mod_last.erl b/src/mod_last.erl index cfdfa65e9..a08b5404b 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -122,7 +122,7 @@ get_last(IQ_Rec, LUser, LServer) -> Sec = TimeStamp2 - TimeStamp, Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}], - children = [#xmlcdata{cdata = list_to_binary(Status)}]}, + children = [#xmlcdata{cdata = Status}]}, exmpp_iq:result(IQ_Rec, Response) end. @@ -134,15 +134,20 @@ on_presence_update(User, Server, _Resource, Status) -> store_last_info(User, Server, TimeStamp, Status). store_last_info(User, Server, TimeStamp, Status) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - US = {LUser, LServer}, - F = fun() -> - mnesia:write(#last_activity{us = US, - timestamp = TimeStamp, - status = Status}) - end, - mnesia:transaction(F). + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + F = fun() -> + mnesia:write(#last_activity{us = US, + timestamp = TimeStamp, + status = Status}) + end, + mnesia:transaction(F) + catch + _ -> + ok + end. %% Returns: {ok, Timestamp, Status} | not_found get_last_info(LUser, LServer) -> @@ -156,20 +161,25 @@ get_last_info(LUser, LServer) -> end. remove_user(User, Server) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - US = {LUser, LServer}, - F = fun() -> - mnesia:delete({last_activity, US}) - end, - mnesia:transaction(F). + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + F = fun() -> + mnesia:delete({last_activity, US}) + end, + mnesia:transaction(F) + catch + _ -> + ok + end. update_table() -> Fields = record_info(fields, last_activity), case mnesia:table_info(last_activity, attributes) of Fields -> - ok; + convert_to_exmpp(); [user, timestamp, status] -> ?INFO_MSG("Converting last_activity table from {user, timestamp, status} format", []), Host = ?MYNAME, @@ -178,11 +188,12 @@ update_table() -> mnesia:write_lock_table(last_activity), mnesia:foldl( fun({_, U, T, S} = R, _) -> + U1 = convert_jid_to_exmpp(U), mnesia:delete_object(R), mnesia:write( - #last_activity{us = {U, Host}, + #last_activity{us = {U1, Host}, timestamp = T, - status = S}) + status = list_to_binary(S)}) end, ok, last_activity) end, mnesia:transaction(F); @@ -194,7 +205,7 @@ update_table() -> fun({_, U, T}) -> #last_activity{us = U, timestamp = T, - status = ""} + status = <<>>} end, Fields), F = fun() -> mnesia:write_lock_table(last_activity), @@ -213,3 +224,36 @@ update_table() -> mnesia:transform_table(last_activity, ignore, Fields) end. +convert_to_exmpp() -> + Fun = fun() -> + case mnesia:first(last_activity) of + '$end_of_table' -> + none; + Key -> + case mnesia:read({last_activity, Key}) of + [#last_activity{status = Status}] when is_binary(Status) -> + none; + [#last_activity{}] -> + mnesia:foldl(fun convert_to_exmpp2/2, + done, last_activity, write) + end + end + end, + mnesia:transaction(Fun). + +convert_to_exmpp2(#last_activity{us = {U, S} = Key, status = Status} = LA, + Acc) -> + % Remove old entry. + mnesia:delete({last_activity, Key}), + % Convert "" to undefined in JIDs. + U1 = convert_jid_to_exmpp(U), + % Convert status. + Status1 = list_to_binary(Status), + % Prepare the new record. + New_LA = LA#last_activity{us = {U1, S}, status = Status1}, + % Write the new record. + mnesia:write(New_LA), + Acc. + +convert_jid_to_exmpp("") -> undefined; +convert_jid_to_exmpp(V) -> V. From f5f3c851122323ed2c4e330b21352024e71a9ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 29 Sep 2008 10:38:04 +0000 Subject: [PATCH 082/582] Remove compatibility code (not tested yet). SVN Revision: 1581 --- ChangeLog | 2 ++ src/mod_adhoc.erl | 15 +++------------ 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 696cac7ff..b4ddaaabc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,6 +15,8 @@ exmpp_stringprep:*prep/1 uses. Add table conversion. (get_last): Do not convert status to binary because it's already one. + * src/mod_adhoc.erl: Remove compatibility code (not tested yet). + 2008-09-25 Jean-Sébastien Pédron * src/jlib.erl (timestamp_to_xml): Create an #xmlel element, not an diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl index b1a2a7bf7..db010ef27 100644 --- a/src/mod_adhoc.erl +++ b/src/mod_adhoc.erl @@ -99,10 +99,7 @@ get_local_commands(Acc, _From, #jid{domain = Server, ldomain = LServer} = _To, " end; get_local_commands(_Acc, From, #jid{ldomain = LServer} = To, ?NS_ADHOC_s, Lang) -> - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - ejabberd_hooks:run_fold(adhoc_local_items, LServer, {result, []}, [FromOld, ToOld, Lang]); + ejabberd_hooks:run_fold(adhoc_local_items, LServer, {result, []}, [From, To, Lang]); get_local_commands(_Acc, _From, _To, "ping", _Lang) -> {result, []}; @@ -132,10 +129,7 @@ get_sm_commands(Acc, _From, #jid{ldomain = LServer} = To, "", Lang) -> end; get_sm_commands(_Acc, From, #jid{ldomain = LServer} = To, ?NS_ADHOC_s, Lang) -> - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), - ejabberd_hooks:run_fold(adhoc_sm_items, LServer, {result, []}, [FromOld, ToOld, Lang]); + ejabberd_hooks:run_fold(adhoc_sm_items, LServer, {result, []}, [From, To, Lang]); get_sm_commands(Acc, _From, _To, _Node, _Lang) -> Acc. @@ -223,11 +217,8 @@ process_adhoc_request(From, To, IQ_Rec, Hook) -> exmpp_iq:error(IQ_Rec, Error); #adhoc_request{} = AdhocRequest -> Host = To#jid.ldomain, - % XXX OLD FORMAT: From, To. - FromOld = jlib:to_old_jid(From), - ToOld = jlib:to_old_jid(To), case ejabberd_hooks:run_fold(Hook, Host, empty, - [FromOld, ToOld, AdhocRequest]) of + [From, To, AdhocRequest]) of ignore -> ignore; empty -> From 12d515a8fe8b44737076d6347e450b48e6e92737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 29 Sep 2008 11:29:09 +0000 Subject: [PATCH 083/582] Convert to exmpp (not tested yet). SVN Revision: 1582 --- ChangeLog | 2 + src/mod_shared_roster.erl | 266 ++++++++++++++++++++------------------ 2 files changed, 141 insertions(+), 127 deletions(-) diff --git a/ChangeLog b/ChangeLog index b4ddaaabc..52db9ee99 100644 --- a/ChangeLog +++ b/ChangeLog @@ -17,6 +17,8 @@ * src/mod_adhoc.erl: Remove compatibility code (not tested yet). + * src/mod_shared_roster.erl: Convert to exmpp (not tested yet). + 2008-09-25 Jean-Sébastien Pédron * src/jlib.erl (timestamp_to_xml): Create an #xmlel element, not an diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index c24ffb6cf..8b436f137 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -49,8 +49,9 @@ add_user_to_group/3, remove_user_from_group/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("mod_roster.hrl"). -include("web/ejabberd_http.hrl"). -include("web/ejabberd_web_admin.hrl"). @@ -145,9 +146,9 @@ get_user_roster(Items, US) -> end, SRUsers, Items), %% Export items in roster format: - SRItems = [#roster{usj = {U, S, {U1, S1, ""}}, + SRItems = [#roster{usj = {U, S, {U1, S1, undefined}}, us = US, - jid = {U1, S1, ""}, + jid = {U1, S1, undefined}, name = "", subscription = both, ask = none, @@ -193,7 +194,7 @@ process_item(RosterItem, Host) -> end. build_roster_record(User1, Server1, User2, Server2, Groups) -> - USR2 = {User2, Server2, ""}, + USR2 = {User2, Server2, undefined}, #roster{usj = {User1, Server1, USR2}, us = {User1, Server1}, jid = USR2, @@ -214,12 +215,12 @@ set_new_rosteritems(UserFrom, ServerFrom, RIFrom = build_roster_record(UserFrom, ServerFrom, UserTo, ServerTo, GroupsFrom), set_item(UserFrom, ServerFrom, ResourceTo, RIFrom), - JIDTo = jlib:make_jid(UserTo, ServerTo, ""), + JIDTo = exmpp_jid:make_bare_jid(UserTo, ServerTo), - JIDFrom = jlib:make_jid(UserFrom, ServerFrom, ""), + JIDFrom = exmpp_jid:make_bare_jid(UserFrom, ServerFrom), RITo = build_roster_record(UserTo, ServerTo, UserFrom, ServerFrom, []), - set_item(UserTo, ServerTo, "", RITo), + set_item(UserTo, ServerTo, undefined, RITo), %% From requests Mod:out_subscription(UserFrom, ServerFrom, JIDTo, subscribe), @@ -240,56 +241,64 @@ set_new_rosteritems(UserFrom, ServerFrom, RIFrom. set_item(User, Server, Resource, Item) -> - ResIQ = #iq{type = set, xmlns = ?NS_ROSTER, - id = "push", - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_ROSTER}], - [mod_roster:item_to_xml(Item)]}]}, + Request = #xmlel{ns = ?NS_ROSTER, name = 'query', + children = [mod_roster:item_to_xml(Item)]}, + ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request, "push"), ejabberd_router:route( - jlib:make_jid(User, Server, Resource), - jlib:make_jid("", Server, ""), - jlib:iq_to_xml(ResIQ)). + exmpp_jid:make_jid(User, Server, Resource), + exmpp_jid:make_bare_jid(Server), + ResIQ). get_subscription_lists({F, T}, User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - US = {LUser, LServer}, - DisplayedGroups = get_user_displayed_groups(US), - SRUsers = - lists:usort( - lists:flatmap( - fun(Group) -> - get_group_users(LServer, Group) - end, DisplayedGroups)), - SRJIDs = [{U1, S1, ""} || {U1, S1} <- SRUsers], - {lists:usort(SRJIDs ++ F), lists:usort(SRJIDs ++ T)}. + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + DisplayedGroups = get_user_displayed_groups(US), + SRUsers = + lists:usort( + lists:flatmap( + fun(Group) -> + get_group_users(LServer, Group) + end, DisplayedGroups)), + SRJIDs = [{U1, S1, undefined} || {U1, S1} <- SRUsers], + {lists:usort(SRJIDs ++ F), lists:usort(SRJIDs ++ T)} + catch + _ -> + {[], []} + end. get_jid_info({Subscription, Groups}, User, Server, JID) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - US = {LUser, LServer}, - {U1, S1, _} = jlib:jid_tolower(JID), - US1 = {U1, S1}, - DisplayedGroups = get_user_displayed_groups(US), - SRUsers = - lists:foldl( - fun(Group, Acc1) -> - lists:foldl( - fun(User1, Acc2) -> - dict:append( - User1, get_group_name(LServer, Group), Acc2) - end, Acc1, get_group_users(LServer, Group)) - end, dict:new(), DisplayedGroups), - case dict:find(US1, SRUsers) of - {ok, GroupNames} -> - NewGroups = if - Groups == [] -> GroupNames; - true -> Groups - end, - {both, NewGroups}; - error -> - {Subscription, Groups} + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + {U1, S1, _} = jlib:short_prepd_jid(JID), + US1 = {U1, S1}, + DisplayedGroups = get_user_displayed_groups(US), + SRUsers = + lists:foldl( + fun(Group, Acc1) -> + lists:foldl( + fun(User1, Acc2) -> + dict:append( + User1, get_group_name(LServer, Group), Acc2) + end, Acc1, get_group_users(LServer, Group)) + end, dict:new(), DisplayedGroups), + case dict:find(US1, SRUsers) of + {ok, GroupNames} -> + NewGroups = if + Groups == [] -> GroupNames; + true -> Groups + end, + {both, NewGroups}; + error -> + {Subscription, Groups} + end + catch + _ -> + {[], []} end. in_subscription(Acc, User, Server, JID, Type, _Reason) -> @@ -299,27 +308,32 @@ out_subscription(User, Server, JID, Type) -> process_subscription(out, User, Server, JID, Type, false). process_subscription(Direction, User, Server, JID, _Type, Acc) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - US = {LUser, LServer}, - {U1, S1, _} = jlib:jid_tolower(jlib:jid_remove_resource(JID)), - US1 = {U1, S1}, - DisplayedGroups = get_user_displayed_groups(US), - SRUsers = - lists:usort( - lists:flatmap( - fun(Group) -> - get_group_users(LServer, Group) - end, DisplayedGroups)), - case lists:member(US1, SRUsers) of - true -> - case Direction of - in -> - {stop, false}; - out -> - stop - end; - false -> + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + {U1, S1, _} = jlib:short_prepd_bare_jid(JID), + US1 = {U1, S1}, + DisplayedGroups = get_user_displayed_groups(US), + SRUsers = + lists:usort( + lists:flatmap( + fun(Group) -> + get_group_users(LServer, Group) + end, DisplayedGroups)), + case lists:member(US1, SRUsers) of + true -> + case Direction of + in -> + {stop, false}; + out -> + stop + end; + false -> + Acc + end + catch + _ -> Acc end. @@ -511,27 +525,32 @@ remove_user_from_group(Host, US, Group) -> mnesia:transaction(F). user_registered(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - GroupsOpts = groups_with_opts(LServer), - SpecialGroups = get_special_displayed_groups(GroupsOpts), - UserGroups = get_user_displayed_groups(LUser, LServer, GroupsOpts), - lists:foreach( - fun(Group) -> - GroupOpts = proplists:get_value(Group, GroupsOpts, []), - GroupName = proplists:get_value(name, GroupOpts, Group), - lists:foreach( - fun({U, S}) -> - Item = #roster{usj = {U, S, {LUser, LServer, ""}}, - us = {U, S}, - jid = {LUser, LServer, ""}, - name = "", - subscription = both, - ask = none, - groups = [GroupName]}, - push_item(U, S, jlib:make_jid("", S, ""), Item) - end, get_group_users(LUser, LServer, Group, GroupOpts)) - end, lists:usort(SpecialGroups++UserGroups)). + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + GroupsOpts = groups_with_opts(LServer), + SpecialGroups = get_special_displayed_groups(GroupsOpts), + UserGroups = get_user_displayed_groups(LUser, LServer, GroupsOpts), + lists:foreach( + fun(Group) -> + GroupOpts = proplists:get_value(Group, GroupsOpts, []), + GroupName = proplists:get_value(name, GroupOpts, Group), + lists:foreach( + fun({U, S}) -> + Item = #roster{usj = {U, S, {LUser, LServer, undefined}}, + us = {U, S}, + jid = {LUser, LServer, undefined}, + name = "", + subscription = both, + ask = none, + groups = [GroupName]}, + push_item(U, S, exmpp_jid:make_bare_jid(S), Item) + end, get_group_users(LUser, LServer, Group, GroupOpts)) + end, lists:usort(SpecialGroups++UserGroups)) + catch + _ -> + ok + end. push_item(_User, _Server, _From, none) -> ok; @@ -540,56 +559,48 @@ push_item(User, Server, From, Item) -> %% ejabberd_sm:route(jlib:make_jid("", "", ""), %% jlib:make_jid(User, Server, "") %% why? - ejabberd_sm:route(From, jlib:make_jid(User, Server, ""), - {xmlelement, "broadcast", [], - [{item, - Item#roster.jid, + ejabberd_sm:route(From, exmpp_jid:make_bare_jid(User, Server), + #xmlel{name = 'broadcast', children = + [{item, + Item#roster.jid, Item#roster.subscription}]}), - Stanza = jlib:iq_to_xml( - #iq{type = set, xmlns = ?NS_ROSTER, - id = "push", - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_ROSTER}], - [item_to_xml(Item)]}]}), + Request = #xmlel{ns = ?NS_ROSTER, name = 'query', + children = [item_to_xml(Item)]}, + Stanza = exmpp_iq:set(?NS_JABBER_CLIENT, Request, "push"), lists:foreach( fun(Resource) -> - JID = jlib:make_jid(User, Server, Resource), + JID = exmpp_jid:make_jid(User, Server, Resource), ejabberd_router:route(JID, JID, Stanza) end, ejabberd_sm:get_user_resources(User, Server)). item_to_xml(Item) -> - Attrs1 = [{"jid", jlib:jid_to_string(Item#roster.jid)}], + {U, S, R} = Item#roster.jid, + Attrs1 = exmpp_xml:set_attribute_in_list([], + 'jid', exmpp_jid:jid_to_list(U, S, R)), Attrs2 = case Item#roster.name of "" -> Attrs1; Name -> - [{"name", Name} | Attrs1] - end, - Attrs3 = case Item#roster.subscription of - none -> - [{"subscription", "none"} | Attrs2]; - from -> - [{"subscription", "from"} | Attrs2]; - to -> - [{"subscription", "to"} | Attrs2]; - both -> - [{"subscription", "both"} | Attrs2]; - remove -> - [{"subscription", "remove"} | Attrs2] + exmpp_xml:set_attribute_in_list(Attrs1, 'name', Name) end, + Attrs3 = exmpp_xml:set_attribute_in_list(Attrs2, + 'subscription', Item#roster.subscription), Attrs4 = case ask_to_pending(Item#roster.ask) of out -> - [{"ask", "subscribe"} | Attrs3]; + exmpp_xml:set_attribute_in_list(Attrs3, + 'ask', "subscribe"); both -> - [{"ask", "subscribe"} | Attrs3]; + exmpp_xml:set_attribute_in_list(Attrs3, + 'ask', "subscribe"); _ -> Attrs3 end, SubEls1 = lists:map(fun(G) -> - {xmlelement, "group", [], [{xmlcdata, G}]} + exmpp_xml:set_cdata( + #xmlel{ns = ?NS_ROSTER, name = 'group'}, G) end, Item#roster.groups), SubEls = SubEls1 ++ Item#roster.xs, - {xmlelement, "item", Attrs4, SubEls}. + #xmlel{ns = ?NS_ROSTER, name = 'item', attrs = Attrs4, children = SubEls}. ask_to_pending(subscribe) -> out; ask_to_pending(unsubscribe) -> none; @@ -791,10 +802,11 @@ shared_roster_group_parse_query(Host, Group, Query) -> "@all@" -> USs; _ -> - case jlib:string_to_jid(SJID) of - JID when is_record(JID, jid) -> - [{JID#jid.luser, JID#jid.lserver} | USs]; - error -> + try + JID = exmpp_jid:list_to_jid(SJID), + [{JID#jid.lnode, JID#jid.ldomain} | USs] + catch + _ -> error end end @@ -839,4 +851,4 @@ get_opt(Opts, Opt, Default) -> end. us_to_list({User, Server}) -> - jlib:jid_to_string({User, Server, ""}). + exmpp_jid:bare_jid_to_list(User, Server). From da034b309056827f7901b938d4be59ff20ccca6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 29 Sep 2008 11:30:25 +0000 Subject: [PATCH 084/582] Fix a bug in #xmlel construction: children must be a list. SVN Revision: 1583 --- ChangeLog | 3 +++ src/mod_roster.erl | 2 +- src/mod_roster_odbc.erl | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 52db9ee99..dcf564881 100644 --- a/ChangeLog +++ b/ChangeLog @@ -19,6 +19,9 @@ * src/mod_shared_roster.erl: Convert to exmpp (not tested yet). + * src/mod_roster.erl (push_item), src/mod_roster_odbc.erl (push_item): + Fix a bug in #xmlel construction: children must be a list. + 2008-09-25 Jean-Sébastien Pédron * src/jlib.erl (timestamp_to_xml): Create an #xmlel element, not an diff --git a/src/mod_roster.erl b/src/mod_roster.erl index b97171a5e..ebaebbbc0 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -319,7 +319,7 @@ push_item(User, Server, From, Item) -> % TODO: don't push to those who didn't load roster push_item(User, Server, Resource, From, Item) -> Request = #xmlel{ns = ?NS_ROSTER, name = 'query', - children = item_to_xml(Item)}, + children = [item_to_xml(Item)]}, ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request, "push"), ejabberd_router:route( From, diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index aabe62e65..3b7d84eee 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -354,7 +354,7 @@ push_item(User, Server, From, Item) -> % TODO: don't push to those who not load roster push_item(User, Server, Resource, From, Item) -> Request = #xmlel{ns = ?NS_ROSTER, name = 'query', - children = item_to_xml(Item)}, + children = [item_to_xml(Item)]}, ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request, "push"), ejabberd_router:route( From, From 5f7e16eac355d76faf3fa22c5168564aa0a5841c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 29 Sep 2008 13:17:21 +0000 Subject: [PATCH 085/582] Add the {autoload_known, true} flag to the XML parser options. This allows modules to extend the known nss/names/attrs with their own data. SVN Revision: 1584 --- ChangeLog | 4 ++++ src/ejabberd_receiver.erl | 1 + 2 files changed, 5 insertions(+) diff --git a/ChangeLog b/ChangeLog index dcf564881..5739e451c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,10 @@ * src/mod_roster.erl (push_item), src/mod_roster_odbc.erl (push_item): Fix a bug in #xmlel construction: children must be a list. + * src/ejabberd_receiver.erl: Add the {autoload_known, true} flag to + the XML parser options. This allows modules to extend the known + nss/names/attrs with their own data. + 2008-09-25 Jean-Sébastien Pédron * src/jlib.erl (timestamp_to_xml): Create an #xmlel element, not an diff --git a/src/ejabberd_receiver.erl b/src/ejabberd_receiver.erl index 6d5b30ec3..adf2634a0 100644 --- a/src/ejabberd_receiver.erl +++ b/src/ejabberd_receiver.erl @@ -163,6 +163,7 @@ handle_call({become_controller, C2SPid}, _From, State) -> Parser = exmpp_xml:start_parser([ {namespace, true}, {name_as_atom, true}, + {autoload_known, true}, {maxsize, State#state.max_stanza_size} ]), XMLStreamState = exmpp_xmlstream:start( From ddcb94649d01fcb7f70554999e7c762ac6617766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 29 Sep 2008 13:19:11 +0000 Subject: [PATCH 086/582] Fill exmpp_xml known list with the nss/names/attrs used by this module. SVN Revision: 1585 --- ChangeLog | 3 +++ src/mod_configure2.erl | 25 ++++++++++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5739e451c..606b21b2d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -26,6 +26,9 @@ the XML parser options. This allows modules to extend the known nss/names/attrs with their own data. + * src/mod_configure2.erl: Fill exmpp_xml known list with the + nss/names/attrs used by this module. + 2008-09-25 Jean-Sébastien Pédron * src/jlib.erl (timestamp_to_xml): Create an #xmlel element, not an diff --git a/src/mod_configure2.erl b/src/mod_configure2.erl index 919927c38..e6d64c4ce 100644 --- a/src/mod_configure2.erl +++ b/src/mod_configure2.erl @@ -37,11 +37,6 @@ -include("ejabberd.hrl"). -% XXX The namespace used in this module isn't known by Exmpp: if the -% known list isn't updated by Ejabberd, some element names will be -% represented with strings. -% XXX This module currently supposed that they'll be atoms. - -define(NS_ECONFIGURE, 'http://ejabberd.jabberstudio.org/protocol/configure'). -define(NS_ECONFIGURE_s, "http://ejabberd.jabberstudio.org/protocol/configure"). @@ -49,6 +44,26 @@ start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE, ?MODULE, process_local_iq, IQDisc), + % Add nss/names/attrs used by this module to the known lists of Exmpp. + exmpp_xml:add_autoload_known_nss([?NS_ECONFIGURE]), + exmpp_xml:add_autoload_known_names([ + 'access', + 'acls', + 'body', + 'info', + 'jid', + 'last', + 'registration-watchers', + 'subject', + 'welcome-message' + ]), + exmpp_xml:add_autoload_known_attrs([ + 'online-users', + 'outgoing-s2s-servers', + 'registered-users', + 'running-nodes', + 'stopped-nodes' + ]), ok. stop(Host) -> From 2309f9b8bc20216e52760f1535b31633cc6f16c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 1 Oct 2008 09:41:57 +0000 Subject: [PATCH 087/582] Fix multiple bugs in ODBC mods. PR: EJABP-1 Submitted by: Pablo Polvorin SVN Revision: 1589 --- ChangeLog | 6 ++ src/mod_offline_odbc.erl | 153 ++++++++++++++++++++++----------------- src/mod_roster_odbc.erl | 4 +- src/mod_vcard_odbc.erl | 11 ++- 4 files changed, 102 insertions(+), 72 deletions(-) diff --git a/ChangeLog b/ChangeLog index 606b21b2d..d0939b05e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-10-01 Jean-Sébastien Pédron + + * src/mod_offline_odbc.erl, src/mod_vcard_odbc.erl, + src/mod_roster_odbc.erl: Fix multiple bugs in ODBC mods, thanks to + Pablo Polvorin! + 2008-09-29 Jean-Sébastien Pédron * src/jlib.erl (parse_xdata_submit, parse_xdata_fields): Fix a bug diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index cfceb41e2..bc6a57ee7 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -103,16 +103,16 @@ loop(Host, MaxOfflineMsgs) -> From = M#offline_msg.from, To = M#offline_msg.to, Packet0 = exmpp_stanza:set_jids( + M#offline_msg.packet, From, - To, - M#offline_msg.packet), + To), Packet1 = exmpp_xml:append_child(Packet0, jlib:timestamp_to_xml( calendar:now_to_universal_time( M#offline_msg.timestamp))), XML = ejabberd_odbc:escape( - exmpp_xml:document_to_string(Packet1)), + exmpp_xml:document_to_list(Packet1)), odbc_queries:add_spool_sql(Username, XML) end, Msgs), case catch odbc_queries:add_spool(Host, Query) of @@ -156,7 +156,7 @@ stop(Host) -> ok. store_packet(From, To, Packet) -> - Type = exmpp_stanza_:get_type(Packet, 'type'), + Type = exmpp_stanza:get_type(Packet), if (Type /= "error") and (Type /= "groupchat") and (Type /= "headline") -> @@ -237,35 +237,45 @@ find_x_expire(TimeStamp, [_ | Els]) -> pop_offline_messages(Ls, User, Server) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - EUser = ejabberd_odbc:escape(LUser), - case odbc_queries:get_and_del_spool_msg_t(LServer, EUser) of - {atomic, {selected, ["username","xml"], Rs}} -> - Ls ++ lists:flatmap( - fun({_, XML}) -> - try - [El] = exmpp_xml:parse_document(XML, [namespace, name_as_atom]), - To = exmpp_jid:list_to_jid( - exmpp_stanza:get_recipient(El)), - From = exmpp_jid:list_to_jid( - exmpp_stanza:get_sender(El)), - [{route, From, To, El}] - catch - _ -> - [] - end - end, Rs); + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + EUser = ejabberd_odbc:escape(LUser), + case odbc_queries:get_and_del_spool_msg_t(LServer, EUser) of + {atomic, {selected, ["username","xml"], Rs}} -> + Ls ++ lists:flatmap( + fun({_, XML}) -> + try + [El] = exmpp_xml:parse_document(XML, [namespace, name_as_atom, autoload_known]), + To = exmpp_jid:list_to_jid( + exmpp_stanza:get_recipient(El)), + From = exmpp_jid:list_to_jid( + exmpp_stanza:get_sender(El)), + [{route, From, To, El}] + catch + _ -> + [] + end + end, Rs); + _ -> + Ls + end + catch _ -> - Ls + [] end. remove_user(User, Server) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - Username = ejabberd_odbc:escape(LUser), - odbc_queries:del_spool_msg(LServer, Username). + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + Username = ejabberd_odbc:escape(LUser), + odbc_queries:del_spool_msg(LServer, Username) + catch + _ -> + ok + end. %% Helper functions: @@ -298,30 +308,36 @@ webadmin_page(_, Host, webadmin_page(Acc, _, _) -> Acc. user_queue(User, Server, Query, Lang) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - Username = ejabberd_odbc:escape(LUser), - US = {LUser, LServer}, - Res = user_queue_parse_query(Username, LServer, Query), - Msgs = case catch ejabberd_odbc:sql_query( - LServer, - ["select username, xml from spool" - " where username='", Username, "'" - " order by seq;"]) of - {selected, ["username", "xml"], Rs} -> - lists:flatmap( - fun({_, XML}) -> - try exmpp_xml:parse_document(XML, [namespace, name_as_atom]) of - [El] -> - [El] - catch - _ -> - [] - end - end, Rs); - _ -> - [] - end, + {US, Msgs, Res} = try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + Username = ejabberd_odbc:escape(LUser), + US0 = {LUser, LServer}, + R = user_queue_parse_query(Username, LServer, Query), + M = case catch ejabberd_odbc:sql_query( + LServer, + ["select username, xml from spool" + " where username='", Username, "'" + " order by seq;"]) of + {selected, ["username", "xml"], Rs} -> + lists:flatmap( + fun({_, XML}) -> + try exmpp_xml:parse_document(XML, [namespace, name_as_atom, autoload_known]) of + [El] -> + [El] + catch + _ -> + [] + end + end, Rs); + _ -> + [] + end, + {US0, M, R} + catch + _ -> + {{"invalid", "invalid"}, [], nothing} + end, FMsgs = lists:map( fun(#xmlel{} = Msg) -> @@ -373,7 +389,7 @@ user_queue_parse_query(Username, LServer, Query) -> {selected, ["xml", "seq"], Rs} -> lists:flatmap( fun({XML, Seq}) -> - try exmpp_xml:parse_document(XML, [namespace, name_as_atom]) of + try exmpp_xml:parse_document(XML, [namespace, name_as_atom, autoload_known]) of [El] -> [{El, Seq}] catch @@ -412,19 +428,24 @@ us_to_list({User, Server}) -> exmpp_jid:jid_to_list(User, Server). webadmin_user(Acc, User, Server, Lang) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - Username = ejabberd_odbc:escape(LUser), - QueueLen = case catch ejabberd_odbc:sql_query( - LServer, - ["select count(*) from spool" - " where username='", Username, "';"]) of - {selected, [_], [{SCount}]} -> - SCount; - _ -> - 0 - end, - FQueueLen = [?AC("queue/", QueueLen)], + FQueueLen = try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + Username = ejabberd_odbc:escape(LUser), + QueueLen = case catch ejabberd_odbc:sql_query( + LServer, + ["select count(*) from spool" + " where username='", Username, "';"]) of + {selected, [_], [{SCount}]} -> + SCount; + _ -> + 0 + end, + [?AC("queue/", QueueLen)] + catch + _ -> + [?C("?")] + end, Acc ++ [?XCT("h3", "Offline Messages:")] ++ FQueueLen. %% ------------------------------------------------ diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 3b7d84eee..73d5c5035 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -835,7 +835,7 @@ record_to_string(#roster{us = {User, _Server}, ask = Ask, askmessage = AskMessage}) -> Username = ejabberd_odbc:escape(User), - {U, S, R} = jlib:short_prepd_jid(JID), + {U, S, R} = JID, SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(U, S, R)), Nick = ejabberd_odbc:escape(Name), SSubscription = case Subscription of @@ -865,7 +865,7 @@ groups_to_string(#roster{us = {User, _Server}, jid = JID, groups = Groups}) -> Username = ejabberd_odbc:escape(User), - {U, S, R} = jlib:short_prepd_jid(JID), + {U, S, R} = JID, SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(U, S, R)), %% Empty groups do not need to be converted to string to be inserted in diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl index 0a46efa6b..980d8d608 100644 --- a/src/mod_vcard_odbc.erl +++ b/src/mod_vcard_odbc.erl @@ -136,11 +136,14 @@ process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> ["select vcard from vcard " "where username='", Username, "';"]) of {selected, ["vcard"], [{SVCARD}]} -> - case exmpp_xml:parse_document(SVCARD) of - {error, _Reason} -> - exmpp_iq:error(IQ_Rec, 'service-unavailable'); - VCARD -> + try exmpp_xml:parse_document(SVCARD, + [namespace, name_as_atom, autoload_known]) of + [VCARD] -> exmpp_iq:result(IQ_Rec, VCARD) + catch + _Type:_Error -> + ?ERROR_MSG("Error parsing vCard: ~s", [SVCARD]), + exmpp_iq:error(IQ_Rec, 'service-unavailable') end; {selected, ["vcard"], []} -> exmpp_iq:result(IQ_Rec); From 7c28aba6a17ef1c301ef5b16fd152bf87c0542fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 2 Oct 2008 13:17:49 +0000 Subject: [PATCH 088/582] Fix a bug where a JID represented as a tuple was used in a function expecting a #jid. PR: EJABP-1 Submitted by: Pablo Polvorin SVN Revision: 1591 --- ChangeLog | 6 ++++++ src/mod_roster_odbc.erl | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index d0939b05e..8111e0ed9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-10-02 Jean-Sébastien Pédron + + * src/mod_roster_odbc.erl: Fix a bug where a JID represented as a + tuple was used in a function expecting a #jid; thanks to Pablo + Polvorin again! + 2008-10-01 Jean-Sébastien Pédron * src/mod_offline_odbc.erl, src/mod_vcard_odbc.erl, diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 73d5c5035..819fa483a 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -215,9 +215,9 @@ process_item_set(From, To, #xmlel{} = El) -> try JID1 = exmpp_jid:list_to_jid(exmpp_xml:get_attribute(El, 'jid', "")), #jid{node = User, lnode = LUser, ldomain = LServer} = From, - LJID = jlib:short_prepd_jid(JID1), + {U0, S0, R0} = LJID = jlib:short_prepd_jid(JID1), Username = ejabberd_odbc:escape(LUser), - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(LJID)), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(U0, S0, R0)), F = fun() -> {selected, ["username", "jid", "nick", "subscription", @@ -645,9 +645,9 @@ set_items(User, Server, #xmlel{children = Els}) -> process_item_set_t(LUser, LServer, #xmlel{} = El) -> try JID1 = exmpp_jid:list_to_jid(exmpp_xml:get_attribute(El, 'jid', "")), - LJID = jlib:short_prepd_jid(JID1), + {U0, S0, R0} = LJID = jlib:short_prepd_jid(JID1), Username = ejabberd_odbc:escape(LUser), - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(LJID)), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(U0, S0, R0)), Item = #roster{usj = {LUser, LServer, LJID}, us = {LUser, LServer}, jid = LJID}, From 24cb7cb0395988095f558ff13d4003a589a1aa25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 2 Oct 2008 13:34:52 +0000 Subject: [PATCH 089/582] exmpp_xml:get_element_by_name/2 is deprecated; use exmpp_xml:get_element/2 instead. SVN Revision: 1592 --- ChangeLog | 4 ++++ src/mod_announce.erl | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8111e0ed9..426d4c588 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,10 @@ tuple was used in a function expecting a #jid; thanks to Pablo Polvorin again! + * src/mod_announce.erl (get_stored_motd): + exmpp_xml:get_element_by_name/2 is deprecated; use + exmpp_xml:get_element/2 instead. + 2008-10-01 Jean-Sébastien Pédron * src/mod_offline_odbc.erl, src/mod_vcard_odbc.erl, diff --git a/src/mod_announce.erl b/src/mod_announce.erl index e59e65fdb..f70c487cb 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -839,8 +839,8 @@ send_motd(#jid{lnode = LUser, ldomain = LServer} = JID) -> get_stored_motd(LServer) -> case catch mnesia:dirty_read({motd, LServer}) of [#motd{packet = Packet}] -> - {exmpp_xml:get_cdata_as_list(exmpp_xml:get_element_by_name(Packet, 'subject')), - exmpp_xml:get_cdata_as_list(exmpp_xml:get_element_by_name(Packet, 'body'))}; + {exmpp_xml:get_cdata_as_list(exmpp_xml:get_element(Packet, 'subject')), + exmpp_xml:get_cdata_as_list(exmpp_xml:get_element(Packet, 'body'))}; _ -> {"", ""} end. From 9e018532c88f72e57b43b15efb2e4a86c8ffda2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 2 Oct 2008 13:52:39 +0000 Subject: [PATCH 090/582] o In #jid, when the node isn't specified, it defaults to the atom "undefined", not an empty binary. o Fix a bug where we expected an #xmlelement to have only one #xmlcdata child. SVN Revision: 1593 --- ChangeLog | 4 ++++ src/mod_echo.erl | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 426d4c588..457d50962 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,10 @@ exmpp_xml:get_element_by_name/2 is deprecated; use exmpp_xml:get_element/2 instead. + * src/mod_echo.erl: In #jid, when the node isn't specified, it + defaults to the atom "undefined", not an empty binary. Fix a bug where + we expected an #xmlelement to have only one #xmlcdata child. + 2008-10-01 Jean-Sébastien Pédron * src/mod_offline_odbc.erl, src/mod_vcard_odbc.erl, diff --git a/src/mod_echo.erl b/src/mod_echo.erl index 9e9748b55..991788a3f 100644 --- a/src/mod_echo.erl +++ b/src/mod_echo.erl @@ -119,7 +119,7 @@ handle_cast(_Msg, State) -> %%-------------------------------------------------------------------- handle_info({route, From, To, Packet}, State) -> Packet2 = case From#jid.node of - <<>> -> exmpp_stanza:reply_with_error(Packet, 'bad-request'); + undefined -> exmpp_stanza:reply_with_error(Packet, 'bad-request'); _ -> Packet end, do_client_version(disabled, To, From), % Put 'enabled' to enable it @@ -195,7 +195,7 @@ do_client_version(enabled, From, To) -> after 5000 -> % Timeout in miliseconds: 5 seconds [] end, - Values = [{Name, binary_to_list(Value)} || #xmlel{name = Name, children = [#xmlcdata{cdata = Value}]} <- Els], + Values = [{Name, exmpp_xml:get_cdata_as_list(Children)} || #xmlel{name = Name, children = Children} <- Els], %% Print in log Values_string1 = [io_lib:format("~n~s: ~p", [N, V]) || {N, V} <- Values], From 1698b8ec04c0cd0a9cfc4e4674674e2b640860c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 2 Oct 2008 14:59:48 +0000 Subject: [PATCH 091/582] o In start/2 and stop/1, the IQ registration must use a namespace as atom, not list. o The functions process_local_iq/3, process_sm_iq/3 and get_last/3 receive an #iq, not an #xmlel. o In store_last_info/4 and remove_user/2, add try/catch block around exmpp_stringprep:*prep/1 uses. SVN Revision: 1594 --- ChangeLog | 7 +++ src/mod_last_odbc.erl | 128 ++++++++++++++++++++++-------------------- 2 files changed, 73 insertions(+), 62 deletions(-) diff --git a/ChangeLog b/ChangeLog index 457d50962..ef7caf102 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,13 @@ defaults to the atom "undefined", not an empty binary. Fix a bug where we expected an #xmlelement to have only one #xmlcdata child. + * src/mod_last_odbc.erl (start/2, stop/1): The IQ registration must + use a namespace as atom, not list. + (process_local_iq/3, process_sm_iq/3, get_last/3): These functions + receive an #iq, not an #xmlel. + (store_last_info/4, remove_user/2): Add try/catch block around + exmpp_stringprep:*prep/1 uses. + 2008-10-01 Jean-Sébastien Pédron * src/mod_offline_odbc.erl, src/mod_vcard_odbc.erl, diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index f2ac26114..077a6ee52 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -45,9 +45,9 @@ start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY_s, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY_s, + gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY, ?MODULE, process_sm_iq, IQDisc), ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), @@ -59,60 +59,54 @@ stop(Host) -> ?MODULE, remove_user, 50), ejabberd_hooks:delete(unset_presence_hook, Host, ?MODULE, on_presence_update, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY_s), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY_s). + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY), + gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY). -process_local_iq(_From, _To, IQ) -> - case exmpp_iq:get_type(IQ) of - set -> - exmpp_iq:error(IQ, 'not-allowed'); - get -> - Sec = trunc(element(1, erlang:statistics(wall_clock))/1000), - Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = - [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}]}, - exmpp_iq:result(IQ, Response) - end. +process_local_iq(_From, _To, #iq{type = get} = IQ_Rec) -> + Sec = trunc(element(1, erlang:statistics(wall_clock))/1000), + Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = + [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}]}, + exmpp_iq:result(IQ_Rec, Response); +process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> + exmpp_iq:error(IQ_Rec, 'not-allowed'). -process_sm_iq(From, To, IQ) -> - case exmpp_iq:get_type(IQ) of - set -> - exmpp_iq:error(IQ, 'not-allowed'); - get -> - User = To#jid.lnode, - Server = To#jid.ldomain, - {Subscription, _Groups} = - ejabberd_hooks:run_fold( - roster_get_jid_info, Server, - {none, []}, [User, Server, From]), - if - (Subscription == both) or (Subscription == from) -> - UserListRecord = ejabberd_hooks:run_fold( - privacy_get_user_list, Server, - #userlist{}, - [User, Server]), - case ejabberd_hooks:run_fold( - privacy_check_packet, Server, - allow, - [User, Server, UserListRecord, - {From, To, - exmpp_presence:available()}, - out]) of - allow -> - get_last(IQ, User, Server); - deny -> - exmpp_iq:error(IQ, 'not-allowed') - end; - true -> - exmpp_iq:error(IQ, 'not-allowed') - end - end. +process_sm_iq(From, To, #iq{type = get} = IQ_Rec) -> + User = To#jid.lnode, + Server = To#jid.ldomain, + {Subscription, _Groups} = + ejabberd_hooks:run_fold( + roster_get_jid_info, Server, + {none, []}, [User, Server, From]), + if + (Subscription == both) or (Subscription == from) -> + UserListRecord = ejabberd_hooks:run_fold( + privacy_get_user_list, Server, + #userlist{}, + [User, Server]), + case ejabberd_hooks:run_fold( + privacy_check_packet, Server, + allow, + [User, Server, UserListRecord, + {From, To, + exmpp_presence:available()}, + out]) of + allow -> + get_last(IQ_Rec, User, Server); + deny -> + exmpp_iq:error(IQ_Rec, 'not-allowed') + end; + true -> + exmpp_iq:error(IQ_Rec, 'not-allowed') + end; +process_sm_iq(_From, _To, #iq{type = set} = IQ_Rec) -> + exmpp_iq:error(IQ_Rec, 'not-allowed'). %% TODO: This function could use get_last_info/2 -get_last(IQ, LUser, LServer) -> +get_last(IQ_Rec, LUser, LServer) -> Username = ejabberd_odbc:escape(LUser), case catch odbc_queries:get_last(LServer, Username) of {selected, ["seconds","state"], []} -> - exmpp_iq:error(IQ, 'service-unavailable'); + exmpp_iq:error(IQ_Rec, 'service-unavailable'); {selected, ["seconds","state"], [{STimeStamp, Status}]} -> case catch list_to_integer(STimeStamp) of TimeStamp when is_integer(TimeStamp) -> @@ -122,12 +116,12 @@ get_last(IQ, LUser, LServer) -> Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}], children = [#xmlcdata{cdata = list_to_binary(Status)}]}, - exmpp_iq:result(IQ, Response); + exmpp_iq:result(IQ_Rec, Response); _ -> - exmpp_iq:error(IQ, 'internal-server-error') + exmpp_iq:error(IQ_Rec, 'internal-server-error') end; _ -> - exmpp_iq:error(IQ, 'internal-server-error') + exmpp_iq:error(IQ_Rec, 'internal-server-error') end. on_presence_update(User, Server, _Resource, Status) -> @@ -136,12 +130,17 @@ on_presence_update(User, Server, _Resource, Status) -> store_last_info(User, Server, TimeStamp, Status). store_last_info(User, Server, TimeStamp, Status) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - Username = ejabberd_odbc:escape(LUser), - Seconds = ejabberd_odbc:escape(integer_to_list(TimeStamp)), - State = ejabberd_odbc:escape(Status), - odbc_queries:set_last_t(LServer, Username, Seconds, State). + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + Username = ejabberd_odbc:escape(LUser), + Seconds = ejabberd_odbc:escape(integer_to_list(TimeStamp)), + State = ejabberd_odbc:escape(Status), + odbc_queries:set_last_t(LServer, Username, Seconds, State) + catch + _ -> + ok + end. %% Returns: {ok, Timestamp, Status} | not_found get_last_info(LUser, LServer) -> @@ -161,7 +160,12 @@ get_last_info(LUser, LServer) -> end. remove_user(User, Server) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - Username = ejabberd_odbc:escape(LUser), - odbc_queries:del_last(LServer, Username). + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + Username = ejabberd_odbc:escape(LUser), + odbc_queries:del_last(LServer, Username) + catch + _ -> + ok + end. From 028a3c2ded90d2e95d3c3e75741e1522d6a1226e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 6 Oct 2008 14:56:36 +0000 Subject: [PATCH 092/582] Fix a bug where we were matching on #iq.type instead of #iq.kind, resulting in bad-request sent to the client. PR: EJABP-1 SVN Revision: 1602 --- ChangeLog | 6 ++++++ src/ejabberd_sm.erl | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index ef7caf102..d05c89d1a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-10-06 Jean-Sébastien Pédron + + * src/ejabberd_sm.erl (process_iq/3): Fix a bug where we were matching + on #iq.type instead of #iq.kind, resulting in bad-request sent to the + client. + 2008-10-02 Jean-Sébastien Pédron * src/mod_roster_odbc.erl: Fix a bug where a JID represented as a diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 2d24d17a5..4d8ea55c2 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -661,7 +661,7 @@ process_iq(From, To, Packet) -> Err = exmpp_iq:error(Packet, 'service-unavailable'), ejabberd_router:route(To, From, Err) end; - #iq{type = response} -> + #iq{kind = response} -> ok; _ -> Err = exmpp_iq:error(Packet, 'bad-request'), From 01da93bf70782efdf1e5868e5a87c5bdad236308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 6 Oct 2008 14:58:45 +0000 Subject: [PATCH 093/582] mod_privacy & friends may return an empty list. PR: EJABP-1 Submitted by: Pablo Polvorin SVN Revision: 1603 --- ChangeLog | 3 +++ src/ejabberd_c2s.erl | 2 ++ 2 files changed, 5 insertions(+) diff --git a/ChangeLog b/ChangeLog index d05c89d1a..4692cfacb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,9 @@ on #iq.type instead of #iq.kind, resulting in bad-request sent to the client. + * src/ejabberd_c2s.erl (process_privacy_iq/4): mod_privacy & friends + may return an empty list. Thanks to Pablo Polvorin! + 2008-10-02 Jean-Sébastien Pédron * src/mod_roster_odbc.erl: Fix a bug where a JID represented as a diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 636c1d33f..abf2cd75c 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1765,6 +1765,8 @@ process_privacy_iq(From, To, end, IQRes = case Res of + {result, []} -> + exmpp_iq:result(IQ_Rec); {result, Result} -> exmpp_iq:result(IQ_Rec, Result); {error, Error} -> From 5ceffdd5a7cd5bb948a55170b0839146dd3fa8f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 6 Oct 2008 15:00:34 +0000 Subject: [PATCH 094/582] Fix a confusion between #jid and tuples. PR: EJABP-1 Submitted by: Pablo Polvorin SVN Revision: 1604 --- ChangeLog | 3 +++ src/mod_roster_odbc.erl | 10 ++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4692cfacb..6abb9c51a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,9 @@ * src/ejabberd_c2s.erl (process_privacy_iq/4): mod_privacy & friends may return an empty list. Thanks to Pablo Polvorin! + * src/mod_roster_odbc.erl (get_jid_info/4): Fix a confusion between + #jid and tuples. Thanks to Pablo Polvorin! + 2008-10-02 Jean-Sébastien Pédron * src/mod_roster_odbc.erl: Fix a bug where a JID represented as a diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 819fa483a..be3ffcb03 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -740,14 +740,15 @@ get_in_pending_subscriptions(Ls, User, Server) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - +%% JID is #jid record, because it's used latter on for both short_prepd_jid +%% and short_prepd_bare_jid get_jid_info(_, User, Server, JID) -> try LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), - LJID = jlib:short_prepd_jid(JID), + LJID = {N, D, R} = jlib:short_prepd_jid(JID), Username = ejabberd_odbc:escape(LUser), - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(LJID)), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(N, D, R)), case catch odbc_queries:get_subscription(LServer, Username, SJID) of {selected, ["subscription"], [{SSubscription}]} -> Subscription = case SSubscription of @@ -769,7 +770,8 @@ get_jid_info(_, User, Server, JID) -> LRJID == LJID -> {none, []}; true -> - SRJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(LRJID)), + {LR_N, LR_D, LR_R} = LRJID, + SRJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(LR_N, LR_D, LR_R)), case catch odbc_queries:get_subscription(LServer, Username, SRJID) of {selected, ["subscription"], [{SSubscription}]} -> Subscription = case SSubscription of From 3f8a3032862a3eb5a50838458aed76a7b0c1ee5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 6 Oct 2008 15:01:36 +0000 Subject: [PATCH 095/582] Convert to exmpp. PR: EJABP-1 Submitted by: Pablo Polvorin SVN Revision: 1606 --- ChangeLog | 3 + src/mod_privacy.erl | 387 +++++++++++++++++++++------------------ src/mod_privacy_odbc.erl | 338 +++++++++++++++++----------------- 3 files changed, 382 insertions(+), 346 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6abb9c51a..fbddd3eb5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,9 @@ * src/mod_roster_odbc.erl (get_jid_info/4): Fix a confusion between #jid and tuples. Thanks to Pablo Polvorin! + * src/mod_privacy.erl, src/mod_privacy_odbc.erl: Convert to exmpp. + Thanks to Pablo Polvorin! + 2008-10-02 Jean-Sébastien Pédron * src/mod_roster_odbc.erl: Fix a bug where a JID represented as a diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 4de51b260..db20ff1ac 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -37,8 +37,9 @@ check_packet/6, updated_list/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("mod_privacy.hrl"). @@ -73,102 +74,93 @@ stop(Host) -> ?MODULE, updated_list, 50), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVACY). -process_iq(_From, _To, IQ) -> - SubEl = IQ#iq.sub_el, - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}. +process_iq(_From, _To, IQ_Rec) -> + exmpp_iq:error(IQ_Rec, 'not-allowed'). -process_iq_get(_, From, _To, #iq{sub_el = SubEl}, +process_iq_get(_, From, _To, #iq{payload = SubEl}, #userlist{name = Active}) -> - #jid{luser = LUser, lserver = LServer} = From, - {xmlelement, _, _, Els} = SubEl, - case xml:remove_cdata(Els) of + #jid{lnode = LUser, ldomain = LServer} = From, + case exmpp_xml:get_child_elements(SubEl) of [] -> process_lists_get(LUser, LServer, Active); - [{xmlelement, Name, Attrs, _SubEls}] -> + [#xmlel{name = Name} = Child] -> case Name of - "list" -> - ListName = xml:get_attr("name", Attrs), + list -> + ListName = exmpp_xml:get_attribute(Child, name, false), process_list_get(LUser, LServer, ListName); _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end. process_lists_get(LUser, LServer, Active) -> case catch mnesia:dirty_read(privacy, {LUser, LServer}) of {'EXIT', _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, 'internal-server-error'}; [] -> - {result, [{xmlelement, "query", [{"xmlns", ?NS_PRIVACY}], []}]}; + {result, #xmlel{ns = ?NS_PRIVACY, name = 'query'}}; [#privacy{default = Default, lists = Lists}] -> case Lists of [] -> - {result, [{xmlelement, "query", - [{"xmlns", ?NS_PRIVACY}], []}]}; + {result, #xmlel{ns = ?NS_PRIVACY, name = 'query'}}; _ -> LItems = lists:map( fun({N, _}) -> - {xmlelement, "list", - [{"name", N}], []} + exmpp_xml:set_attribute(#xmlel{ns = ?NS_PRIVACY, name = list}, name, N) end, Lists), DItems = case Default of none -> LItems; _ -> - [{xmlelement, "default", - [{"name", Default}], []} | LItems] + [exmpp_xml:set_attribute(#xmlel{ns = ?NS_PRIVACY, name = default}, name, Default) | LItems] end, ADItems = case Active of none -> DItems; _ -> - [{xmlelement, "active", - [{"name", Active}], []} | DItems] + [exmpp_xml:set_attribute(#xmlel{ns = ?NS_PRIVACY, name = active}, name, Active) | DItems] end, - {result, - [{xmlelement, "query", [{"xmlns", ?NS_PRIVACY}], - ADItems}]} + {result, #xmlel{ns = ?NS_PRIVACY, name = 'query', children = ADItems}} end end. -process_list_get(LUser, LServer, {value, Name}) -> +process_list_get(_LUser, _LServer, false) -> + {error, 'bad-request'}; + +process_list_get(LUser, LServer, Name) -> case catch mnesia:dirty_read(privacy, {LUser, LServer}) of {'EXIT', _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, 'internal-server-error'}; [] -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; %{result, [{xmlelement, "query", [{"xmlns", ?NS_PRIVACY}], []}]}; [#privacy{lists = Lists}] -> case lists:keysearch(Name, 1, Lists) of {value, {_, List}} -> LItems = lists:map(fun item_to_xml/1, List), - {result, - [{xmlelement, "query", [{"xmlns", ?NS_PRIVACY}], - [{xmlelement, "list", - [{"name", Name}], LItems}]}]}; + ListEl = exmpp_xml:set_attribute(#xmlel{ns = ?NS_PRIVACY, name = list, children = LItems}, name, Name), + {result,#xmlel{ns = ?NS_PRIVACY, name = 'query', children = [ListEl]}}; _ -> - {error, ?ERR_ITEM_NOT_FOUND} + {error, 'item-not-found'} end - end; + end. -process_list_get(_LUser, _LServer, false) -> - {error, ?ERR_BAD_REQUEST}. item_to_xml(Item) -> - Attrs1 = [{"action", action_to_list(Item#listitem.action)}, - {"order", order_to_list(Item#listitem.order)}], + Attrs1 = [#xmlattr{name = 'action', value = action_to_list(Item#listitem.action)}, + #xmlattr{name = 'order', value = order_to_list(Item#listitem.order)}], Attrs2 = case Item#listitem.type of none -> Attrs1; Type -> - [{"type", type_to_list(Item#listitem.type)}, - {"value", value_to_list(Type, Item#listitem.value)} | + [#xmlattr{name = 'type', value = type_to_list(Item#listitem.type)}, + #xmlattr{name = 'value', value = value_to_list(Type, Item#listitem.value)} | Attrs1] end, SubEls = case Item#listitem.match_all of @@ -177,31 +169,31 @@ item_to_xml(Item) -> false -> SE1 = case Item#listitem.match_iq of true -> - [{xmlelement, "iq", [], []}]; + [#xmlel{ns = ?NS_PRIVACY, name = iq}]; false -> [] end, SE2 = case Item#listitem.match_message of true -> - [{xmlelement, "message", [], []} | SE1]; + [#xmlel{ns = ?NS_PRIVACY, name = message} | SE1]; false -> SE1 end, SE3 = case Item#listitem.match_presence_in of true -> - [{xmlelement, "presence-in", [], []} | SE2]; + [#xmlel{ns = ?NS_PRIVACY, name = 'presence-in'} | SE2]; false -> SE2 end, SE4 = case Item#listitem.match_presence_out of true -> - [{xmlelement, "presence-out", [], []} | SE3]; + [#xmlel{ns = ?NS_PRIVACY, name = 'presence-out'} | SE3]; false -> SE3 end, SE4 end, - {xmlelement, "item", Attrs2, SubEls}. + exmpp_xml:set_attributes(#xmlel{ns = ?NS_PRIVACY, name = item, children = SubEls}, Attrs2). action_to_list(Action) -> @@ -222,7 +214,9 @@ type_to_list(Type) -> value_to_list(Type, Val) -> case Type of - jid -> jlib:jid_to_string(Val); + jid -> + {N, D, R} = Val, + exmpp_jid:jid_to_list(N, D, R); group -> Val; subscription -> case Val of @@ -243,53 +237,27 @@ list_to_action(S) -> -process_iq_set(_, From, _To, #iq{sub_el = SubEl}) -> - #jid{luser = LUser, lserver = LServer} = From, - {xmlelement, _, _, Els} = SubEl, - case xml:remove_cdata(Els) of - [{xmlelement, Name, Attrs, SubEls}] -> - ListName = xml:get_attr("name", Attrs), +process_iq_set(_, From, _To, #iq{payload = SubEl}) -> + #jid{lnode = LUser, ldomain = LServer} = From, + case exmpp_xml:get_child_elements(SubEl) of + [#xmlel{name = Name} = Child] -> + ListName = exmpp_xml:get_attribute(Child, 'name', false), case Name of - "list" -> + list -> process_list_set(LUser, LServer, ListName, - xml:remove_cdata(SubEls)); - "active" -> + exmpp_xml:get_child_elements(Child)); + active -> process_active_set(LUser, LServer, ListName); - "default" -> + default -> process_default_set(LUser, LServer, ListName); _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end. -process_default_set(LUser, LServer, {value, Name}) -> - F = fun() -> - case mnesia:read({privacy, {LUser, LServer}}) of - [] -> - {error, ?ERR_ITEM_NOT_FOUND}; - [#privacy{lists = Lists} = P] -> - case lists:keymember(Name, 1, Lists) of - true -> - mnesia:write(P#privacy{default = Name, - lists = Lists}), - {result, []}; - false -> - {error, ?ERR_ITEM_NOT_FOUND} - end - end - end, - case mnesia:transaction(F) of - {atomic, {error, _} = Error} -> - Error; - {atomic, {result, _} = Res} -> - Res; - _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} - end; - process_default_set(LUser, LServer, false) -> F = fun() -> case mnesia:read({privacy, {LUser, LServer}}) of @@ -306,31 +274,60 @@ process_default_set(LUser, LServer, false) -> {atomic, {result, _} = Res} -> Res; _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} + {error, 'internal-server-error'} + end; + +process_default_set(LUser, LServer, Name) -> + F = fun() -> + case mnesia:read({privacy, {LUser, LServer}}) of + [] -> + {error, 'item-not-found'}; + [#privacy{lists = Lists} = P] -> + case lists:keymember(Name, 1, Lists) of + true -> + mnesia:write(P#privacy{default = Name, + lists = Lists}), + {result, []}; + false -> + {error, 'item-not-found'} + end + end + end, + case mnesia:transaction(F) of + {atomic, {error, _} = Error} -> + Error; + {atomic, {result, _} = Res} -> + Res; + _ -> + {error, 'internal-server-error'} end. -process_active_set(LUser, LServer, {value, Name}) -> +process_active_set(_LUser, _LServer, false) -> + {result, [], #userlist{}}; + +process_active_set(LUser, LServer, Name) -> case catch mnesia:dirty_read(privacy, {LUser, LServer}) of [] -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; [#privacy{lists = Lists}] -> case lists:keysearch(Name, 1, Lists) of {value, {_, List}} -> {result, [], #userlist{name = Name, list = List}}; false -> - {error, ?ERR_ITEM_NOT_FOUND} + {error, 'item-not-found'} end - end; - -process_active_set(_LUser, _LServer, false) -> - {result, [], #userlist{}}. + end. -process_list_set(LUser, LServer, {value, Name}, Els) -> + +process_list_set(_LUser, _LServer, false, _Els) -> + {error, 'bad-request'}; + +process_list_set(LUser, LServer, Name, Els) -> case parse_items(Els) of false -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; remove -> F = fun() -> @@ -341,7 +338,7 @@ process_list_set(LUser, LServer, {value, Name}, Els) -> % TODO: check active if Name == Default -> - {error, ?ERR_CONFLICT}; + {error, 'conflict'}; true -> NewLists = lists:keydelete(Name, 1, Lists), @@ -356,15 +353,15 @@ process_list_set(LUser, LServer, {value, Name}, Els) -> Error; {atomic, {result, _} = Res} -> ejabberd_router:route( - jlib:make_jid(LUser, LServer, ""), - jlib:make_jid(LUser, LServer, ""), - {xmlelement, "broadcast", [], - [{privacy_list, - #userlist{name = Name, list = []}, - Name}]}), + exmpp_jid:make_bare_jid(LUser, LServer), + exmpp_jid:make_bare_jid(LUser, LServer), + #xmlel{name = 'broadcast', + children=[{privacy_list, + #userlist{name = Name, list = []}, + Name}]}), Res; _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} + {error, 'internal-server-error'} end; List -> F = @@ -387,20 +384,18 @@ process_list_set(LUser, LServer, {value, Name}, Els) -> Error; {atomic, {result, _} = Res} -> ejabberd_router:route( - jlib:make_jid(LUser, LServer, ""), - jlib:make_jid(LUser, LServer, ""), - {xmlelement, "broadcast", [], - [{privacy_list, - #userlist{name = Name, list = List}, - Name}]}), + exmpp_jid:make_bare_jid(LUser, LServer), + exmpp_jid:make_bare_jid(LUser, LServer), + #xmlel{name = 'broadcast', + children=[{privacy_list, + #userlist{name = Name, list = List}, + Name}]}), Res; _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} + {error, 'internal_server_error'} end - end; + end. -process_list_set(_LUser, _LServer, false, _Els) -> - {error, ?ERR_BAD_REQUEST}. parse_items([]) -> @@ -410,16 +405,16 @@ parse_items(Els) -> parse_items([], Res) -> lists:reverse(Res); -parse_items([{xmlelement, "item", Attrs, SubEls} | Els], Res) -> - Type = xml:get_attr("type", Attrs), - Value = xml:get_attr("value", Attrs), - SAction = xml:get_attr("action", Attrs), - SOrder = xml:get_attr("order", Attrs), - Action = case catch list_to_action(element(2, SAction)) of +parse_items([El = #xmlel{name = item} | Els], Res) -> + Type = exmpp_xml:get_attribute(El, type, false), + Value = exmpp_xml:get_attribute(El, value, false), + SAction =exmpp_xml:get_attribute(El, action, false), + SOrder = exmpp_xml:get_attribute(El, order, false), + Action = case catch list_to_action(SAction) of {'EXIT', _} -> false; Val -> Val end, - Order = case catch list_to_integer(element(2, SOrder)) of + Order = case catch list_to_integer(SOrder) of {'EXIT', _} -> false; IntVal -> @@ -434,16 +429,17 @@ parse_items([{xmlelement, "item", Attrs, SubEls} | Els], Res) -> (Action /= false) and (Order /= false) -> I1 = #listitem{action = Action, order = Order}, I2 = case {Type, Value} of - {{value, T}, {value, V}} -> + {T, V} when is_list(T), is_list(V) -> case T of "jid" -> - case jlib:string_to_jid(V) of - error -> - false; - JID -> - I1#listitem{ - type = jid, - value = jlib:jid_tolower(JID)} + try + JID = exmpp_jid:list_to_jid(V), + I1#listitem{ + type = jid, + value = jlib:short_prepd_jid(JID)} + catch + _ -> + false end; "group" -> I1#listitem{type = group, @@ -466,7 +462,7 @@ parse_items([{xmlelement, "item", Attrs, SubEls} | Els], Res) -> false end end; - {{value, _}, false} -> + {T, false} when is_list(T) -> false; _ -> I1 @@ -475,7 +471,7 @@ parse_items([{xmlelement, "item", Attrs, SubEls} | Els], Res) -> false -> false; _ -> - case parse_matches(I2, xml:remove_cdata(SubEls)) of + case parse_matches(I2, exmpp_xml:get_child_elements(El)) of false -> false; I3 -> @@ -497,15 +493,15 @@ parse_matches(Item, Els) -> parse_matches1(Item, []) -> Item; -parse_matches1(Item, [{xmlelement, "message", _, _} | Els]) -> +parse_matches1(Item, [#xmlel{name = message} | Els]) -> parse_matches1(Item#listitem{match_message = true}, Els); -parse_matches1(Item, [{xmlelement, "iq", _, _} | Els]) -> +parse_matches1(Item, [#xmlel{name = iq} | Els]) -> parse_matches1(Item#listitem{match_iq = true}, Els); -parse_matches1(Item, [{xmlelement, "presence-in", _, _} | Els]) -> +parse_matches1(Item, [#xmlel{name = 'presence-in'} | Els]) -> parse_matches1(Item#listitem{match_presence_in = true}, Els); -parse_matches1(Item, [{xmlelement, "presence-out", _, _} | Els]) -> +parse_matches1(Item, [#xmlel{name = 'presence-out'} | Els]) -> parse_matches1(Item#listitem{match_presence_out = true}, Els); -parse_matches1(_Item, [{xmlelement, _, _, _} | _Els]) -> +parse_matches1(_Item, [#xmlel{} | _Els]) -> false. @@ -515,24 +511,29 @@ parse_matches1(_Item, [{xmlelement, _, _, _} | _Els]) -> get_user_list(_, User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - case catch mnesia:dirty_read(privacy, {LUser, LServer}) of - [] -> - #userlist{}; - [#privacy{default = Default, lists = Lists}] -> - case Default of - none -> - #userlist{}; - _ -> - case lists:keysearch(Default, 1, Lists) of - {value, {_, List}} -> - SortedList = lists:keysort(#listitem.order, List), - #userlist{name = Default, list = SortedList}; - _ -> - #userlist{} - end - end; + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + case catch mnesia:dirty_read(privacy, {LUser, LServer}) of + [] -> + #userlist{}; + [#privacy{default = Default, lists = Lists}] -> + case Default of + none -> + #userlist{}; + _ -> + case lists:keysearch(Default, 1, Lists) of + {value, {_, List}} -> + SortedList = lists:keysort(#listitem.order, List), + #userlist{name = Default, list = SortedList}; + _ -> + #userlist{} + end + end; + _ -> + #userlist{} + end + catch _ -> #userlist{} end. @@ -540,48 +541,45 @@ get_user_list(_, User, Server) -> check_packet(_, User, Server, #userlist{list = List}, - {From, To, {xmlelement, PName, _, _}}, - Dir) -> + {From, To, #xmlel{name = PName}}, + Dir) when PName =:= message ; + PName =:= iq ; + PName =:= presence -> case List of [] -> allow; _ -> - PType = case PName of - "message" -> message; - "iq" -> iq; - "presence" -> presence - end, - case {PType, Dir} of + case {PName, Dir} of {message, in} -> - LJID = jlib:jid_tolower(From), + LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, jlib:nameprep(Server), - {none, []}, [User, Server, LJID]), + roster_get_jid_info, exmpp_stringprep:nameprep(Server), + {none, []}, [User, Server, From]), check_packet_aux(List, message, LJID, Subscription, Groups); {iq, in} -> - LJID = jlib:jid_tolower(From), + LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, jlib:nameprep(Server), - {none, []}, [User, Server, LJID]), + roster_get_jid_info, exmpp_stringprep:nameprep(Server), + {none, []}, [User, Server, From]), check_packet_aux(List, iq, LJID, Subscription, Groups); {presence, in} -> - LJID = jlib:jid_tolower(From), + LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, jlib:nameprep(Server), - {none, []}, [User, Server, LJID]), + roster_get_jid_info, exmpp_stringprep:nameprep(Server), + {none, []}, [User, Server, From]), check_packet_aux(List, presence_in, LJID, Subscription, Groups); {presence, out} -> - LJID = jlib:jid_tolower(To), + LJID = jlib:short_prepd_jid(To), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, jlib:nameprep(Server), - {none, []}, [User, Server, LJID]), + roster_get_jid_info, exmpp_stringprep:nameprep(Server), + {none, []}, [User, Server, To]), check_packet_aux(List, presence_out, LJID, Subscription, Groups); _ -> @@ -635,14 +633,14 @@ is_type_match(Type, Value, JID, Subscription, Groups) -> case Type of jid -> case Value of - {"", Server, ""} -> + {undefined, Server, undefined} -> case JID of {_, Server, _} -> true; _ -> false end; - {User, Server, ""} -> + {User, Server, undefined} -> case JID of {User, Server, _} -> true; @@ -675,7 +673,7 @@ update_table() -> Fields = record_info(fields, privacy), case mnesia:table_info(privacy, attributes) of Fields -> - ok; + convert_to_exmpp(); [user, default, lists] -> ?INFO_MSG("Converting privacy table from " "{user, default, lists} format", []), @@ -714,3 +712,42 @@ update_table() -> end. +convert_to_exmpp() -> + Fun = fun() -> + mnesia:foldl(fun convert_to_exmpp2/2, done, privacy, write) + end, + mnesia:transaction(Fun). + +convert_to_exmpp2(#privacy{us = {U, S} = Key, lists = L} = P, Acc) -> + U1 = convert_jid_to_exmpp(U), + L1 = convert_lists_to_exmpp(L), + New_P = P#privacy{ + us = {U1, S}, + lists = L1 + }, + if + New_P /= P -> mnesia:delete({privacy, Key}), mnesia:write(New_P); + true -> ok + end, + Acc. + +convert_jid_to_exmpp("") -> undefined; +convert_jid_to_exmpp(V) -> V. + +convert_lists_to_exmpp(L) -> + convert_lists_to_exmpp2(L, []). + +convert_lists_to_exmpp2([{Name, List} | Rest], Result) -> + convert_lists_to_exmpp2(Rest, + [{Name, convert_list_to_exmpp(List, [])} | Result]); +convert_lists_to_exmpp2([], Result) -> + lists:reverse(Result). + +convert_list_to_exmpp([#listitem{type = jid, value = {U, S, R}} = I | Rest], + Result) -> + U1 = convert_jid_to_exmpp(U), + R1 = convert_jid_to_exmpp(R), + New_I = I#listitem{value = {U1, S, R1}}, + convert_list_to_exmpp(Rest, [New_I | Result]); +convert_list_to_exmpp([], Result) -> + lists:reverse(Result). diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 11e3956eb..00269d0e9 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -37,8 +37,9 @@ check_packet/6, updated_list/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("mod_privacy.hrl"). start(Host, Opts) -> @@ -69,28 +70,26 @@ stop(Host) -> ?MODULE, updated_list, 50), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVACY). -process_iq(_From, _To, IQ) -> - SubEl = IQ#iq.sub_el, - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}. +process_iq(_From, _To, IQ_Rec) -> + exmpp_iq:error(IQ_Rec, 'not-allowed'). -process_iq_get(_, From, _To, #iq{sub_el = SubEl}, +process_iq_get(_, From, _To, #iq{payload = SubEl}, #userlist{name = Active}) -> - #jid{luser = LUser, lserver = LServer} = From, - {xmlelement, _, _, Els} = SubEl, - case xml:remove_cdata(Els) of + #jid{lnode = LUser, ldomain = LServer} = From, + case exmpp_xml:get_child_elements(SubEl) of [] -> process_lists_get(LUser, LServer, Active); - [{xmlelement, Name, Attrs, _SubEls}] -> + [#xmlel{name = Name} = Child] -> case Name of - "list" -> - ListName = xml:get_attr("name", Attrs), + list -> + ListName = exmpp_xml:get_attribute(Child, name, false), process_list_get(LUser, LServer, ListName); _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end. @@ -105,40 +104,38 @@ process_lists_get(LUser, LServer, Active) -> end, case catch sql_get_privacy_list_names(LUser, LServer) of {selected, ["name"], []} -> - {result, [{xmlelement, "query", [{"xmlns", ?NS_PRIVACY}], []}]}; + {result, #xmlel{ns = ?NS_PRIVACY, name = 'query'}}; {selected, ["name"], Names} -> LItems = lists:map( fun({N}) -> - {xmlelement, "list", - [{"name", N}], []} + exmpp_xml:set_attribute(#xmlel{ns = ?NS_PRIVACY, name = list}, name, N) end, Names), DItems = case Default of none -> LItems; _ -> - [{xmlelement, "default", - [{"name", Default}], []} | LItems] + [exmpp_xml:set_attribute(#xmlel{ns = ?NS_PRIVACY, name = default}, name, Default) | LItems] end, ADItems = case Active of none -> DItems; _ -> - [{xmlelement, "active", - [{"name", Active}], []} | DItems] + [exmpp_xml:set_attribute(#xmlel{ns = ?NS_PRIVACY, name = active}, name, Active) | DItems] end, - {result, - [{xmlelement, "query", [{"xmlns", ?NS_PRIVACY}], - ADItems}]}; + {result, #xmlel{ns = ?NS_PRIVACY, name = 'query', children = ADItems}}; _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} + {error, 'internal-server-error'} end. -process_list_get(LUser, LServer, {value, Name}) -> +process_list_get(_LUser, _LServer, false) -> + {error, 'bad-request'}; + +process_list_get(LUser, LServer, Name) -> case catch sql_get_privacy_list_id(LUser, LServer, Name) of {selected, ["id"], []} -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; {selected, ["id"], [{ID}]} -> case catch sql_get_privacy_list_data_by_id(ID, LServer) of {selected, ["t", "value", "action", "ord", "match_all", @@ -147,29 +144,29 @@ process_list_get(LUser, LServer, {value, Name}) -> RItems} -> Items = lists:map(fun raw_to_item/1, RItems), LItems = lists:map(fun item_to_xml/1, Items), - {result, - [{xmlelement, "query", [{"xmlns", ?NS_PRIVACY}], - [{xmlelement, "list", - [{"name", Name}], LItems}]}]}; - _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} + ListEl = exmpp_xml:set_attribute(#xmlel{name = list, + ns = ?NS_PRIVACY, + children = LItems}, + name, + Name), + {result, #xmlel{ns = ?NS_PRIVACY, name = 'query', children = [ListEl]}}; + _ -> + {error, 'internal-server-error'} end; _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} - end; + {error, 'internal-server-error'} + end. -process_list_get(_LUser, _LServer, false) -> - {error, ?ERR_BAD_REQUEST}. item_to_xml(Item) -> - Attrs1 = [{"action", action_to_list(Item#listitem.action)}, - {"order", order_to_list(Item#listitem.order)}], + Attrs1 = [#xmlattr{name = 'action', value = action_to_list(Item#listitem.action)}, + #xmlattr{name = 'order', value = order_to_list(Item#listitem.order)}], Attrs2 = case Item#listitem.type of none -> Attrs1; Type -> - [{"type", type_to_list(Item#listitem.type)}, - {"value", value_to_list(Type, Item#listitem.value)} | + [#xmlattr{name = 'type', value = type_to_list(Item#listitem.type)}, + #xmlattr{name = 'value', value = value_to_list(Type, Item#listitem.value)} | Attrs1] end, SubEls = case Item#listitem.match_all of @@ -178,31 +175,31 @@ item_to_xml(Item) -> false -> SE1 = case Item#listitem.match_iq of true -> - [{xmlelement, "iq", [], []}]; + [#xmlel{ns = ?NS_PRIVACY, name = iq}]; false -> [] end, SE2 = case Item#listitem.match_message of true -> - [{xmlelement, "message", [], []} | SE1]; + [#xmlel{ns = ?NS_PRIVACY, name = message} | SE1]; false -> SE1 end, SE3 = case Item#listitem.match_presence_in of true -> - [{xmlelement, "presence-in", [], []} | SE2]; + [#xmlel{ns = ?NS_PRIVACY, name = 'presence-in'} | SE2]; false -> SE2 end, SE4 = case Item#listitem.match_presence_out of true -> - [{xmlelement, "presence-out", [], []} | SE3]; + [#xmlel{ns = ?NS_PRIVACY, name = 'presence-out'} | SE3]; false -> SE3 end, SE4 end, - {xmlelement, "item", Attrs2, SubEls}. + exmpp_xml:set_attributes(#xmlel{ns = ?NS_PRIVACY, name = item, children = SubEls}, Attrs2). action_to_list(Action) -> @@ -223,7 +220,9 @@ type_to_list(Type) -> value_to_list(Type, Val) -> case Type of - jid -> jlib:jid_to_string(Val); + jid -> + {N, D, R} = Val, + exmpp_jid:jid_to_list(N, D, R); group -> Val; subscription -> case Val of @@ -244,40 +243,49 @@ list_to_action(S) -> -process_iq_set(_, From, _To, #iq{sub_el = SubEl}) -> - #jid{luser = LUser, lserver = LServer} = From, - {xmlelement, _, _, Els} = SubEl, - case xml:remove_cdata(Els) of - [{xmlelement, Name, Attrs, SubEls}] -> - ListName = xml:get_attr("name", Attrs), +process_iq_set(_, From, _To, #iq{payload = SubEl}) -> + #jid{lnode = LUser, ldomain = LServer} = From, + case exmpp_xml:get_child_elements(SubEl) of + [#xmlel{name = Name} = Child] -> + ListName = exmpp_xml:get_attribute(Child, 'name', false), case Name of - "list" -> + list -> process_list_set(LUser, LServer, ListName, - xml:remove_cdata(SubEls)); - "active" -> + exmpp_xml:get_child_elements(Child)); + active -> process_active_set(LUser, LServer, ListName); - "default" -> + default -> process_default_set(LUser, LServer, ListName); _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end. -process_default_set(LUser, LServer, {value, Name}) -> +process_default_set(LUser, LServer, false) -> + case catch sql_unset_default_privacy_list(LUser, LServer) of + {'EXIT', _Reason} -> + {error, 'internal_server_error'}; + {error, _Reason} -> + {error, 'internal_server_error'}; + _ -> + {result, []} + end; + +process_default_set(LUser, LServer, Name) -> F = fun() -> case sql_get_privacy_list_names_t(LUser) of {selected, ["name"], []} -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; {selected, ["name"], Names} -> - case lists:member({Name}, Names) of + case lists:member({Name}, Names) of true -> sql_set_default_privacy_list(LUser, Name), {result, []}; false -> - {error, ?ERR_ITEM_NOT_FOUND} + {error, 'item-not-found'} end end end, @@ -287,24 +295,17 @@ process_default_set(LUser, LServer, {value, Name}) -> {atomic, {result, _} = Res} -> Res; _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} - end; - -process_default_set(LUser, LServer, false) -> - case catch sql_unset_default_privacy_list(LUser, LServer) of - {'EXIT', _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; - {error, _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; - _ -> - {result, []} + {error, 'internal-server-error'} end. -process_active_set(LUser, LServer, {value, Name}) -> +process_active_set(_LUser, _LServer, false) -> + {result, [], #userlist{}}; + +process_active_set(LUser, LServer, Name) -> case catch sql_get_privacy_list_id(LUser, LServer, Name) of {selected, ["id"], []} -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; {selected, ["id"], [{ID}]} -> case catch sql_get_privacy_list_data_by_id(ID, LServer) of {selected, ["t", "value", "action", "ord", "match_all", @@ -314,24 +315,21 @@ process_active_set(LUser, LServer, {value, Name}) -> Items = lists:map(fun raw_to_item/1, RItems), {result, [], #userlist{name = Name, list = Items}}; _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} + {error, 'internal-server-error'} end; _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} - end; - -process_active_set(_LUser, _LServer, false) -> - {result, [], #userlist{}}. + {error, 'internal_server_error'} + end. +process_list_set(_LUser, _LServer, false, _Els) -> + {error, 'bad-request'}; - - -process_list_set(LUser, LServer, {value, Name}, Els) -> +process_list_set(LUser, LServer, Name, Els) -> case parse_items(Els) of false -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; remove -> F = fun() -> @@ -340,10 +338,10 @@ process_list_set(LUser, LServer, {value, Name}, Els) -> sql_remove_privacy_list(LUser, Name), {result, []}; {selected, ["name"], [{Default}]} -> - %% TODO: check active + % TODO: check active if Name == Default -> - {error, ?ERR_CONFLICT}; + {error, 'conflict'}; true -> sql_remove_privacy_list(LUser, Name), {result, []} @@ -355,15 +353,15 @@ process_list_set(LUser, LServer, {value, Name}, Els) -> Error; {atomic, {result, _} = Res} -> ejabberd_router:route( - jlib:make_jid(LUser, LServer, ""), - jlib:make_jid(LUser, LServer, ""), - {xmlelement, "broadcast", [], - [{privacy_list, - #userlist{name = Name, list = []}, - Name}]}), + exmpp_jid:make_bare_jid(LUser, LServer), + exmpp_jid:make_bare_jid(LUser, LServer), + #xmlel{name = 'broadcast', + children=[{privacy_list, + #userlist{name = Name, list = []}, + Name}]}), Res; _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} + {error, 'internal-server-error'} end; List -> RItems = lists:map(fun item_to_raw/1, List), @@ -387,20 +385,18 @@ process_list_set(LUser, LServer, {value, Name}, Els) -> Error; {atomic, {result, _} = Res} -> ejabberd_router:route( - jlib:make_jid(LUser, LServer, ""), - jlib:make_jid(LUser, LServer, ""), - {xmlelement, "broadcast", [], - [{privacy_list, - #userlist{name = Name, list = List}, - Name}]}), + exmpp_jid:make_bare_jid(LUser, LServer), + exmpp_jid:make_bare_jid(LUser, LServer), + #xmlel{name = 'broadcast', + children=[{privacy_list, + #userlist{name = Name, list = List}, + Name}]}), Res; _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} + {error, 'internal_server_error'} end - end; + end. -process_list_set(_LUser, _LServer, false, _Els) -> - {error, ?ERR_BAD_REQUEST}. parse_items([]) -> @@ -410,16 +406,16 @@ parse_items(Els) -> parse_items([], Res) -> lists:reverse(Res); -parse_items([{xmlelement, "item", Attrs, SubEls} | Els], Res) -> - Type = xml:get_attr("type", Attrs), - Value = xml:get_attr("value", Attrs), - SAction = xml:get_attr("action", Attrs), - SOrder = xml:get_attr("order", Attrs), - Action = case catch list_to_action(element(2, SAction)) of +parse_items([El = #xmlel{name = item} | Els], Res) -> + Type = exmpp_xml:get_attribute(El, type, false), + Value = exmpp_xml:get_attribute(El, value, false), + SAction =exmpp_xml:get_attribute(El, action, false), + SOrder = exmpp_xml:get_attribute(El, order, false), + Action = case catch list_to_action(SAction) of {'EXIT', _} -> false; Val -> Val end, - Order = case catch list_to_integer(element(2, SOrder)) of + Order = case catch list_to_integer(SOrder) of {'EXIT', _} -> false; IntVal -> @@ -434,16 +430,17 @@ parse_items([{xmlelement, "item", Attrs, SubEls} | Els], Res) -> (Action /= false) and (Order /= false) -> I1 = #listitem{action = Action, order = Order}, I2 = case {Type, Value} of - {{value, T}, {value, V}} -> + {T, V} when is_list(T), is_list(V) -> case T of "jid" -> - case jlib:string_to_jid(V) of - error -> - false; - JID -> - I1#listitem{ - type = jid, - value = jlib:jid_tolower(JID)} + try + JID = exmpp_jid:list_to_jid(V), + I1#listitem{ + type = jid, + value = jlib:short_prepd_jid(JID)} + catch + _ -> + false end; "group" -> I1#listitem{type = group, @@ -466,7 +463,7 @@ parse_items([{xmlelement, "item", Attrs, SubEls} | Els], Res) -> false end end; - {{value, _}, false} -> + {T, false} when is_list(T) -> false; _ -> I1 @@ -475,7 +472,7 @@ parse_items([{xmlelement, "item", Attrs, SubEls} | Els], Res) -> false -> false; _ -> - case parse_matches(I2, xml:remove_cdata(SubEls)) of + case parse_matches(I2, exmpp_xml:get_child_elements(El)) of false -> false; I3 -> @@ -497,15 +494,15 @@ parse_matches(Item, Els) -> parse_matches1(Item, []) -> Item; -parse_matches1(Item, [{xmlelement, "message", _, _} | Els]) -> +parse_matches1(Item, [#xmlel{name = message} | Els]) -> parse_matches1(Item#listitem{match_message = true}, Els); -parse_matches1(Item, [{xmlelement, "iq", _, _} | Els]) -> +parse_matches1(Item, [#xmlel{name = iq} | Els]) -> parse_matches1(Item#listitem{match_iq = true}, Els); -parse_matches1(Item, [{xmlelement, "presence-in", _, _} | Els]) -> +parse_matches1(Item, [#xmlel{name = 'presence-in'} | Els]) -> parse_matches1(Item#listitem{match_presence_in = true}, Els); -parse_matches1(Item, [{xmlelement, "presence-out", _, _} | Els]) -> +parse_matches1(Item, [#xmlel{name = 'presence-out'} | Els]) -> parse_matches1(Item#listitem{match_presence_out = true}, Els); -parse_matches1(_Item, [{xmlelement, _, _, _} | _Els]) -> +parse_matches1(_Item, [#xmlel{} | _Els]) -> false. @@ -515,23 +512,27 @@ parse_matches1(_Item, [{xmlelement, _, _, _} | _Els]) -> get_user_list(_, User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - - case catch sql_get_default_privacy_list(LUser, LServer) of - {selected, ["name"], []} -> - #userlist{}; - {selected, ["name"], [{Default}]} -> - case catch sql_get_privacy_list_data(LUser, LServer, Default) of - {selected, ["t", "value", "action", "ord", "match_all", - "match_iq", "match_message", - "match_presence_in", "match_presence_out"], - RItems} -> - Items = lists:map(fun raw_to_item/1, RItems), - #userlist{name = Default, list = Items}; - _ -> - #userlist{} - end; + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + case catch sql_get_default_privacy_list(LUser, LServer) of + {selected, ["name"], []} -> + #userlist{}; + {selected, ["name"], [{Default}]} -> + case catch sql_get_privacy_list_data(LUser, LServer, Default) of + {selected, ["t", "value", "action", "ord", "match_all", + "match_iq", "match_message", + "match_presence_in", "match_presence_out"], + RItems} -> + Items = lists:map(fun raw_to_item/1, RItems), + #userlist{name = Default, list = Items}; + _ -> + #userlist{} + end; + _ -> + #userlist{} + end + catch _ -> #userlist{} end. @@ -539,48 +540,45 @@ get_user_list(_, User, Server) -> check_packet(_, User, Server, #userlist{list = List}, - {From, To, {xmlelement, PName, _, _}}, - Dir) -> + {From, To, #xmlel{name = PName}}, + Dir) when PName =:= message ; + PName =:= iq ; + PName =:= presence -> case List of [] -> allow; _ -> - PType = case PName of - "message" -> message; - "iq" -> iq; - "presence" -> presence - end, - case {PType, Dir} of + case {PName, Dir} of {message, in} -> - LJID = jlib:jid_tolower(From), + LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, jlib:nameprep(Server), - {none, []}, [User, Server, LJID]), + roster_get_jid_info, exmpp_stringprep:nameprep(Server), + {none, []}, [User, Server, From]), check_packet_aux(List, message, LJID, Subscription, Groups); {iq, in} -> - LJID = jlib:jid_tolower(From), + LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, jlib:nameprep(Server), - {none, []}, [User, Server, LJID]), + roster_get_jid_info, exmpp_stringprep:nameprep(Server), + {none, []}, [User, Server, From]), check_packet_aux(List, iq, LJID, Subscription, Groups); {presence, in} -> - LJID = jlib:jid_tolower(From), + LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, jlib:nameprep(Server), - {none, []}, [User, Server, LJID]), + roster_get_jid_info, exmpp_stringprep:nameprep(Server), + {none, []}, [User, Server, From]), check_packet_aux(List, presence_in, LJID, Subscription, Groups); {presence, out} -> - LJID = jlib:jid_tolower(To), + LJID = jlib:short_prepd_jid(To), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, jlib:nameprep(Server), - {none, []}, [User, Server, LJID]), + roster_get_jid_info, exmpp_stringprep:nameprep(Server), + {none, []}, [User, Server, To]), check_packet_aux(List, presence_out, LJID, Subscription, Groups); _ -> @@ -634,14 +632,14 @@ is_type_match(Type, Value, JID, Subscription, Groups) -> case Type of jid -> case Value of - {"", Server, ""} -> + {undefined, Server, undefined} -> case JID of {_, Server, _} -> true; _ -> false end; - {User, Server, ""} -> + {User, Server, undefined} -> case JID of {User, Server, _} -> true; @@ -676,10 +674,8 @@ raw_to_item({SType, SValue, SAction, SOrder, SMatchAll, SMatchIQ, "n" -> {none, none}; "j" -> - case jlib:string_to_jid(SValue) of - #jid{} = JID -> - {jid, jlib:jid_tolower(JID)} - end; + JID = exmpp_jid:list_to_jid(SValue), + {jid, jlib:short_prepd_jid(JID)}; "g" -> {group, SValue}; "s" -> @@ -731,7 +727,7 @@ item_to_raw(#listitem{type = Type, none -> {"n", ""}; jid -> - {"j", jlib:jid_to_string(Value)}; + {"j", exmpp_jid:jid_to_list(Value)}; group -> {"g", Value}; subscription -> @@ -871,5 +867,5 @@ sql_set_privacy_list(ID, RItems) -> "match_message, match_presence_in, " "match_presence_out " ") " - "values ('", ID, "', ", Items, ");"]) + "values ('", ID, "', ", Items, ");"]) end, RItems). From 0434c1424a6df9bec3cd7f2fd62e843980b9ad5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 6 Oct 2008 15:14:01 +0000 Subject: [PATCH 096/582] The Mnesia table wasn't updated when converting from an old schema. PR: EJABP-1 SVN Revision: 1607 --- ChangeLog | 3 +++ src/mod_privacy.erl | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index fbddd3eb5..c7c8f9b14 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,9 @@ * src/mod_privacy.erl, src/mod_privacy_odbc.erl: Convert to exmpp. Thanks to Pablo Polvorin! + * src/mod_privacy.erl: The Mnesia table wasn't updated when converting + from an old schema. + 2008-10-02 Jean-Sébastien Pédron * src/mod_roster_odbc.erl: Fix a bug where a JID represented as a diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index db20ff1ac..ecd1006f4 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -689,10 +689,12 @@ update_table() -> F1 = fun() -> mnesia:write_lock_table(mod_privacy_tmp_table), mnesia:foldl( - fun(#privacy{us = U} = R, _) -> + fun(#privacy{us = U, lists = L} = R, _) -> + U1 = convert_jid_to_exmpp(U), + L1 = convert_lists_to_exmpp(L), mnesia:dirty_write( mod_privacy_tmp_table, - R#privacy{us = {U, Host}}) + R#privacy{us = {U1, Host}, lists = L1}) end, ok, privacy) end, mnesia:transaction(F1), From bc0d8613abde6439ee5235a4a8c01864bc00846a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 6 Oct 2008 15:16:09 +0000 Subject: [PATCH 097/582] Fix status handling by always using binaries: until now, we were mixing lists and binaries in a non-working way. PR: EJABP-1 Submitted by: Pablo Polvorin SVN Revision: 1608 --- ChangeLog | 4 ++++ src/ejabberd_sm.erl | 6 +++--- src/mod_roster.erl | 14 +++++++++----- src/mod_roster_odbc.erl | 20 ++++++++++++-------- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index c7c8f9b14..7e9b774ac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,10 @@ * src/mod_privacy.erl: The Mnesia table wasn't updated when converting from an old schema. + * src/ejabberd_sm.erl, src/mod_roster.erl, src/mod_roster_odbc.erl: + Fix status handling by always using binaries: until now, we were + mixing lists and binaries in a non-working way. + 2008-10-02 Jean-Sébastien Pédron * src/mod_roster_odbc.erl: Fix a bug where a JID represented as a diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 4d8ea55c2..0ce7505bf 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -420,21 +420,21 @@ do_route(From, To, Packet) -> roster_in_subscription, LServer, false, - [User, Server, From, subscribed, ""]), + [User, Server, From, subscribed, <<>>]), true}; 'unsubscribe' -> {ejabberd_hooks:run_fold( roster_in_subscription, LServer, false, - [User, Server, From, unsubscribe, ""]), + [User, Server, From, unsubscribe, <<>>]), true}; 'unsubscribed' -> {ejabberd_hooks:run_fold( roster_in_subscription, LServer, false, - [User, Server, From, unsubscribed, ""]), + [User, Server, From, unsubscribed, <<>>]), true}; _ -> {true, false} diff --git a/src/mod_roster.erl b/src/mod_roster.erl index ebaebbbc0..a18fc0d03 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -367,7 +367,7 @@ in_subscription(_, User, Server, JID, Type, Reason) -> process_subscription(in, User, Server, JID, Type, Reason). out_subscription(User, Server, JID, Type) -> - process_subscription(out, User, Server, JID, Type, []). + process_subscription(out, User, Server, JID, Type, <<>>). process_subscription(Direction, User, Server, JID1, Type, Reason) -> try @@ -406,7 +406,7 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) -> AskMessage = case NewState of {_, both} -> Reason; {_, in} -> Reason; - _ -> "" + _ -> <<>> end, case NewState of none -> @@ -416,9 +416,13 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) -> mnesia:delete({roster, {LUser, LServer, LJID}}), {none, AutoReply}; {Subscription, Pending} -> + AskBinary = case AskMessage of + undefined -> <<>>; + B -> B + end, NewItem = Item#roster{subscription = Subscription, ask = Pending, - askmessage = list_to_binary(AskMessage)}, + askmessage = AskBinary}, mnesia:write(NewItem), {{push, NewItem}, AutoReply} end @@ -648,10 +652,10 @@ get_in_pending_subscriptions(Ls, User, Server) -> Ls ++ lists:map( fun(R) -> Message = R#roster.askmessage, - {U, S, R} = R#roster.jid, + {U0, S0, R0} = R#roster.jid, Pres1 = exmpp_presence:subscribe(), Pres2 = exmpp_stanza:set_jids(Pres1, - exmpp_jid:jid_to_list(U, S, R), + exmpp_jid:jid_to_list(U0, S0, R0), exmpp_jid:jid_to_list(JID)), exmpp_presence:set_status(Pres2, Message) end, diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index be3ffcb03..88d0b8667 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -411,15 +411,15 @@ in_subscription(_, User, Server, JID, Type, Reason) -> process_subscription(in, User, Server, JID, Type, Reason). out_subscription(User, Server, JID, Type) -> - process_subscription(out, User, Server, JID, Type, []). + process_subscription(out, User, Server, JID, Type, <<>>). process_subscription(Direction, User, Server, JID1, Type, Reason) -> try LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), - LJID = exmpp_jid:jid_to_bare_jid(JID1), + {N0,D0,R0} = LJID = jlib:short_prepd_jid(JID1), Username = ejabberd_odbc:escape(LUser), - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(LJID)), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(N0,D0,R0)), F = fun() -> Item = case odbc_queries:get_roster_by_jid(LServer, Username, SJID) of @@ -467,7 +467,7 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) -> AskMessage = case NewState of {_, both} -> Reason; {_, in} -> Reason; - _ -> "" + _ -> <<>> end, case NewState of none -> @@ -477,9 +477,13 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) -> odbc_queries:del_roster(LServer, Username, SJID), {none, AutoReply}; {Subscription, Pending} -> + AskBinary = case AskMessage of + undefined -> <<>>; + B -> B + end, NewItem = Item#roster{subscription = Subscription, ask = Pending, - askmessage = list_to_binary(AskMessage)}, + askmessage = AskBinary}, ItemVals = record_to_string(NewItem), odbc_queries:roster_subscribe(LServer, Username, SJID, ItemVals), {{push, NewItem}, AutoReply} @@ -712,10 +716,10 @@ get_in_pending_subscriptions(Ls, User, Server) -> Ls ++ lists:map( fun(R) -> Message = R#roster.askmessage, - {U, S, R} = R#roster.jid, + {U0, S0, R0} = R#roster.jid, Pres1 = exmpp_presence:subscribe(), Pres2 = exmpp_stanza:set_jids(Pres1, - exmpp_jid:jid_to_list(U, S, R), + exmpp_jid:jid_to_list(U0, S0, R0), exmpp_jid:jid_to_list(JID)), exmpp_presence:set_status(Pres2, Message) end, @@ -876,7 +880,7 @@ groups_to_string(#roster{us = {User, _Server}, (Group, Acc) -> String = ["'", Username, "'," "'", SJID, "'," - "'", ejabberd_odbc:escape(Group), "'"], + "'", ejabberd_odbc:escape(binary_to_list(Group)), "'"], [String|Acc] end, [], Groups). webadmin_page(_, Host, From ca7a0813b42ff3ef5a594d0914fa44617452b708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 7 Oct 2008 09:54:53 +0000 Subject: [PATCH 098/582] Fix a bug where an error stanza was not created correctly, leading to ejabberd_c2s crash. PR: EJABP-1 SVN Revision: 1609 --- ChangeLog | 8 +++++++- src/ejabberd_local.erl | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7e9b774ac..4e6144532 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-10-07 Jean-Sébastien Pédron + + * src/ejabberd_local.erl: Fix a bug where an error stanza was not + created correctly, leading to ejabberd_c2s crash. + 2008-10-06 Jean-Sébastien Pédron * src/ejabberd_sm.erl (process_iq/3): Fix a bug where we were matching @@ -18,7 +23,8 @@ * src/ejabberd_sm.erl, src/mod_roster.erl, src/mod_roster_odbc.erl: Fix status handling by always using binaries: until now, we were - mixing lists and binaries in a non-working way. + mixing lists and binaries in a non-working way. Thanks to Pablo + Polvorin! 2008-10-02 Jean-Sébastien Pédron diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 232ce8415..96118c457 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -163,7 +163,7 @@ refresh_iq_handlers() -> ejabberd_local ! refresh_iq_handlers. bounce_resource_packet(From, To, Packet) -> - Err = exmpp_stanza:error(Packet, 'item-not-found'), + Err = exmpp_stanza:reply_with_error(Packet, 'item-not-found'), ejabberd_router:route(To, From, Err), stop. From 78466384c4a52eb44bf894fb0ac0ffce81e60214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 7 Oct 2008 09:55:38 +0000 Subject: [PATCH 099/582] Convert to exmpp. PR: EJABP-1 SVN Revision: 1610 --- ChangeLog | 3 ++ src/mod_service_log.erl | 22 ++++++-------- src/mod_stats.erl | 65 ++++++++++++++++++----------------------- src/mod_time.erl | 25 ++++++++-------- 4 files changed, 53 insertions(+), 62 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4e6144532..0c1a114cc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,9 @@ * src/ejabberd_local.erl: Fix a bug where an error stanza was not created correctly, leading to ejabberd_c2s crash. + * src/mod_stats.erl, src/mod_service_log.erl, src/mod_time.erl: + Convert to exmpp. + 2008-10-06 Jean-Sébastien Pédron * src/ejabberd_sm.erl (process_iq/3): Fix a bug where we were matching diff --git a/src/mod_service_log.erl b/src/mod_service_log.erl index 4dd967fbb..2b360fea4 100644 --- a/src/mod_service_log.erl +++ b/src/mod_service_log.erl @@ -34,8 +34,9 @@ log_user_send/3, log_user_receive/4]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). start(Host, _Opts) -> ejabberd_hooks:add(user_send_packet, Host, @@ -52,26 +53,21 @@ stop(Host) -> ok. log_user_send(From, To, Packet) -> - log_packet(From, To, Packet, From#jid.lserver). + log_packet(From, To, Packet, From#jid.ldomain). log_user_receive(_JID, From, To, Packet) -> - log_packet(From, To, Packet, To#jid.lserver). + log_packet(From, To, Packet, To#jid.ldomain). -log_packet(From, To, {xmlelement, Name, Attrs, Els}, Host) -> +log_packet(From, To, Packet, Host) -> Loggers = gen_mod:get_module_opt(Host, ?MODULE, loggers, []), - ServerJID = #jid{user = "", server = Host, resource = "", - luser = "", lserver = Host, lresource = ""}, - NewAttrs = jlib:replace_from_to_attrs(jlib:jid_to_string(From), - jlib:jid_to_string(To), - Attrs), - FixedPacket = {xmlelement, Name, NewAttrs, Els}, + ServerJID = #jid{domain = Host, ldomain = Host}, + FixedPacket = exmpp_stanza:set_jids(Packet, From, To), lists:foreach( fun(Logger) -> ejabberd_router:route( ServerJID, - #jid{user = "", server = Logger, resource = "", - luser = "", lserver = Logger, lresource = ""}, - {xmlelement, "route", [], [FixedPacket]}) + #jid{domain = Logger, ldomain = Logger}, + #xmlel{name = 'route', children = [FixedPacket]}) end, Loggers). diff --git a/src/mod_stats.erl b/src/mod_stats.erl index 234c7106e..f5910ea8a 100644 --- a/src/mod_stats.erl +++ b/src/mod_stats.erl @@ -33,7 +33,7 @@ stop/1, process_local_iq/3]). --include("jlib.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), @@ -44,33 +44,26 @@ stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_STATS). -process_local_iq(_From, To, #iq{id = _ID, type = Type, - xmlns = XMLNS, sub_el = SubEl} = IQ) -> - %%Lang = xml:get_tag_attr_s("xml:lang", SubEl), - case Type of - set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; - get -> - {xmlelement, _, _Attrs, Els} = SubEl, - Node = string:tokens(xml:get_tag_attr_s("node", SubEl), "/"), - Names = get_names(Els, []), +process_local_iq(_From, To, #iq{type = get, + ns = XMLNS, payload = SubEl} = IQ_Rec) -> + Node = string:tokens(exmpp_xml:get_attribute(SubEl, 'node', ""), "/"), + Names = get_names(exmpp_xml:get_child_elements(SubEl), []), - case get_local_stats(To#jid.server, Node, Names) of - {result, Res} -> - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", XMLNS}], - Res}]}; - {error, Error} -> - IQ#iq{type = error, sub_el = [SubEl, Error]} - end - end. + case get_local_stats(To#jid.domain, Node, Names) of + {result, Res} -> + Result = #xmlel{ns = XMLNS, name = 'query', children = Res}, + exmpp_iq:result(IQ_Rec, Result); + {error, Error} -> + exmpp_iq:error(IQ_Rec, Error) + end; +process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> + exmpp_iq:error(IQ_Rec, 'not-allowed'). get_names([], Res) -> Res; -get_names([{xmlelement, "stat", Attrs, _} | Els], Res) -> - Name = xml:get_attr_s("name", Attrs), +get_names([#xmlel{name = 'stat', attrs = Attrs} | Els], Res) -> + Name = exmpp_xml:get_attribute_from_list(Attrs, 'name', ""), case Name of "" -> get_names(Els, Res); @@ -81,7 +74,7 @@ get_names([_ | Els], Res) -> get_names(Els, Res). --define(STAT(Name), {xmlelement, "stat", [{"name", Name}], []}). +-define(STAT(Name), #xmlel{ns = ?NS_STATS, name = 'stat', attrs = [#xmlattr{name = 'name', value = Name}]}). get_local_stats(_Server, [], []) -> {result, @@ -110,30 +103,30 @@ get_local_stats(_Server, ["running nodes", _], []) -> get_local_stats(_Server, ["running nodes", ENode], Names) -> case search_running_node(ENode) of false -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; Node -> {result, lists:map(fun(Name) -> get_node_stat(Node, Name) end, Names)} end; get_local_stats(_Server, _, _) -> - {error, ?ERR_FEATURE_NOT_IMPLEMENTED}. + {error, 'feature-not-implemented'}. -define(STATVAL(Val, Unit), - {xmlelement, "stat", - [{"name", Name}, - {"units", Unit}, - {"value", Val} - ], []}). + #xmlel{ns = ?NS_STATS, name = 'stat', attrs = + [#xmlattr{name = 'name', value = Name}, + #xmlattr{name = 'units', value = Unit}, + #xmlattr{name = 'value', value = Val} + ]}). -define(STATERR(Code, Desc), - {xmlelement, "stat", - [{"name", Name}], - [{xmlelement, "error", - [{"code", Code}], - [{xmlcdata, Desc}]}]}). + #xmlel{ns = ?NS_STATS, name = 'stat', attrs= + [#xmlattr{name = 'name', value = Name}], children = + [#xmlel{ns = ?NS_STATS, name = 'error', attrs = + [#xmlattr{name = 'code', value = Code}], children = + [#xmlcdata{cdata = list_to_binary(Desc)}]}]}). get_local_stat(Server, [], Name) when Name == "users/online" -> diff --git a/src/mod_time.erl b/src/mod_time.erl index 0bc72e599..c8cdaff63 100644 --- a/src/mod_time.erl +++ b/src/mod_time.erl @@ -33,8 +33,9 @@ stop/1, process_local_iq/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). start(Host, Opts) -> @@ -45,17 +46,15 @@ start(Host, Opts) -> stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_TIME). -process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) -> - case Type of - set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; - get -> - UTC = jlib:timestamp_to_iso(calendar:universal_time()), - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_TIME}], - [{xmlelement, "utc", [], - [{xmlcdata, UTC}]}]}]} - end. +process_local_iq(_From, _To, #iq{type = get} = IQ_Rec) -> + UTC = jlib:timestamp_to_iso(calendar:universal_time()), + Result = #xmlel{ns = ?NS_TIME, name = 'query', children = [ + #xmlel{ns = ?NS_TIME, name = 'utc', children = [ + #xmlcdata{cdata = list_to_binary(UTC)} + ]} + ]}, + exmpp_iq:result(IQ_Rec, Result); +process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> + exmpp_iq:error(IQ_Rec, 'not-allowed'). From aaecdc4b8a0b9aacb4a4b670fc409a65ca126b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 7 Oct 2008 12:20:09 +0000 Subject: [PATCH 100/582] Convert to exmpp. PR: EJABP-1 Submitted by: Pablo Polvorin SVN Revision: 1611 --- ChangeLog | 3 + src/mod_private.erl | 216 ++++++++++++++++++++++++++------------- src/mod_private_odbc.erl | 176 +++++++++++++++++++------------ src/mod_version.erl | 33 +++--- 4 files changed, 271 insertions(+), 157 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0c1a114cc..882217ace 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,9 @@ * src/mod_stats.erl, src/mod_service_log.erl, src/mod_time.erl: Convert to exmpp. + * src/mod_private.erl, src/mod_private_odbc.erl, src/mod_version.erl: + Convert to exmpp. Thanks to Pablo Polvorin! + 2008-10-06 Jean-Sébastien Pédron * src/ejabberd_sm.erl (process_iq/3): Fix a bug where we were matching diff --git a/src/mod_private.erl b/src/mod_private.erl index 1a4ad4fff..f88bc3b4d 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -34,8 +34,9 @@ process_sm_iq/3, remove_user/2]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -record(private_storage, {usns, xml}). @@ -56,52 +57,90 @@ stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE). -process_sm_iq(From, _To, #iq{type = Type, sub_el = SubEl} = IQ) -> - #jid{luser = LUser, lserver = LServer} = From, - case lists:member(LServer, ?MYHOSTS) of - true -> - {xmlelement, Name, Attrs, Els} = SubEl, +process_sm_iq(From, To, #iq{type = Type} = IQ_Rec) -> + case check_packet(From, To, IQ_Rec) of + ok -> case Type of set -> - F = fun() -> - lists:foreach( - fun(El) -> - set_data(LUser, LServer, El) - end, Els) - end, - mnesia:transaction(F), - IQ#iq{type = result, - sub_el = [{xmlelement, Name, Attrs, []}]}; + process_iq_set(From, To, IQ_Rec); get -> - case catch get_data(LUser, LServer, Els) of - {'EXIT', _Reason} -> - IQ#iq{type = error, - sub_el = [SubEl, - ?ERR_INTERNAL_SERVER_ERROR]}; - Res -> - IQ#iq{type = result, - sub_el = [{xmlelement, Name, Attrs, Res}]} - end + process_iq_get(From, To, IQ_Rec) end; - false -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]} + {error, Error} -> + exmpp_iq:error(IQ_Rec, Error) + end. + +process_iq_get(From, _To, #iq{payload = SubEl} = IQ_Rec) -> + #jid{lnode = LUser, ldomain = LServer} = From, + case catch get_data(LUser, + LServer, + exmpp_xml:get_child_elements(SubEl)) of + {'EXIT', _Reason} -> + {error, 'internal-server-error'}; + Res -> + exmpp_iq:result(IQ_Rec, #xmlel{ns = ?NS_PRIVATE, + name = 'query', + children = Res}) + end. + + +process_iq_set(From, _To, #iq{payload = SubEl} = IQ_Rec) -> + #jid{lnode = LUser, ldomain = LServer} = From, + F = fun() -> + lists:foreach( + fun(El) -> + set_data(LUser, LServer, El) + end, exmpp_xml:get_child_elements(SubEl)) + end, + mnesia:transaction(F), + exmpp_iq:result(IQ_Rec). + + +check_packet(From, To, IQ_Rec) -> + check_packet(From, To, IQ_Rec, [ fun check_domain/3, + fun check_user/3, + fun check_ns/3]). +check_packet(_From, _To, _IQ_Rec, []) -> + ok; +check_packet(From, To, IQ_Rec, [F | R]) -> + case F(From, To, IQ_Rec) of + {error, _} = Error -> Error; + ok -> check_packet(From, To, IQ_Rec, R) + end. + +check_domain(#jid{ldomain = LServer}, _To, _IQ_Rec) -> + case lists:member(LServer, ?MYHOSTS) of + true -> ok; + false -> {error, 'not-allowed'} + end. + +% the iq can't be directed to another jid +check_user(From, To, _IQ_Rec) -> + case exmpp_jid:compare_bare_jids(From, To) of + true -> ok; + false -> {error, 'forbidden'} + end. + +%there must be at least one child, and every child should have +%a namespace specified (reject if the namespace is jabber:iq:private, +%the same than the parent element). +check_ns(_From, _To, #iq{payload = SubEl}) -> + case exmpp_xml:get_child_elements(SubEl) of + [] -> + {error, 'not-acceptable'}; + Children -> + case lists:any(fun(Child) -> + exmpp_xml:get_ns_as_atom(Child) =:= ?NS_PRIVATE + end, Children) of + true -> {error, 'not-acceptable'}; + false -> ok + end end. set_data(LUser, LServer, El) -> - case El of - {xmlelement, _Name, Attrs, _Els} -> - XMLNS = xml:get_attr_s("xmlns", Attrs), - case XMLNS of - "" -> - ignore; - _ -> - mnesia:write( - #private_storage{usns = {LUser, LServer, XMLNS}, - xml = El}) - end; - _ -> - ignore - end. + XMLNS = exmpp_xml:get_ns_as_atom(El), + mnesia:write(#private_storage{usns = {LUser, LServer, XMLNS}, + xml = El}). get_data(LUser, LServer, Els) -> get_data(LUser, LServer, Els, []). @@ -109,45 +148,45 @@ get_data(LUser, LServer, Els) -> get_data(_LUser, _LServer, [], Res) -> lists:reverse(Res); get_data(LUser, LServer, [El | Els], Res) -> - case El of - {xmlelement, _Name, Attrs, _} -> - XMLNS = xml:get_attr_s("xmlns", Attrs), - case mnesia:dirty_read(private_storage, {LUser, LServer, XMLNS}) of - [R] -> - get_data(LUser, LServer, Els, - [R#private_storage.xml | Res]); - [] -> - get_data(LUser, LServer, Els, - [El | Res]) - end; - _ -> - get_data(LUser, LServer, Els, Res) + XMLNS = exmpp_xml:get_ns_as_atom(El), + case mnesia:dirty_read(private_storage, {LUser, LServer, XMLNS}) of + [R] -> + get_data(LUser, LServer, Els, + [R#private_storage.xml | Res]); + [] -> + get_data(LUser, LServer, Els, + [El | Res]) end. remove_user(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - F = fun() -> - Namespaces = mnesia:select( - private_storage, - [{#private_storage{usns={LUser, LServer, '$1'}, - _ = '_'}, - [], - ['$$']}]), - lists:foreach( - fun([Namespace]) -> - mnesia:delete({private_storage, - {LUser, LServer, Namespace}}) - end, Namespaces) - end, - mnesia:transaction(F). + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + F = fun() -> + Namespaces = mnesia:select( + private_storage, + [{#private_storage{usns = {LUser, LServer, '$1'}, + _ = '_'}, + [], + ['$$']}]), + lists:foreach( + fun([Namespace]) -> + mnesia:delete({private_storage, + {LUser, LServer, Namespace}}) + end, Namespaces) + end, + mnesia:transaction(F) + catch + _ -> + ok + end. update_table() -> Fields = record_info(fields, private_storage), case mnesia:table_info(private_storage, attributes) of Fields -> - ok; + convert_to_exmpp(); [userns, xml] -> ?INFO_MSG("Converting private_storage table from " "{user, default, lists} format", []), @@ -163,10 +202,14 @@ update_table() -> F1 = fun() -> mnesia:write_lock_table(mod_private_tmp_table), mnesia:foldl( - fun(#private_storage{usns = {U, NS}} = R, _) -> + fun(#private_storage{usns = {U, NS}, xml = El} = R, _) -> + NS1 = list_to_atom(NS), + El0 = exmpp_xml:xmlelement_to_xmlel(El, + [?NS_PRIVATE], [{?NS_XMPP, ?NS_XMPP_pfx}]), + El1 = exmpp_xml:remove_whitespaces_deeply(El0), mnesia:dirty_write( mod_private_tmp_table, - R#private_storage{usns = {U, Host, NS}}) + R#private_storage{usns = {U, Host, NS1}, xml = El1}) end, ok, private_storage) end, mnesia:transaction(F1), @@ -186,3 +229,32 @@ update_table() -> end. +convert_to_exmpp() -> + Fun = fun() -> + case mnesia:first(private_storage) of + '$end_of_table' -> + none; + Key -> + case mnesia:read({private_storage, Key}) of + [#private_storage{xml = #xmlel{}}] -> + none; + [#private_storage{xml = #xmlelement{}}] -> + mnesia:foldl(fun convert_to_exmpp2/2, + done, private_storage, write) + end + end + end, + mnesia:transaction(Fun). + +convert_to_exmpp2(#private_storage{usns = {U, S, NS} = Key, xml = El} = R, + Acc) -> + mnesia:delete({private_storage, Key}), + NS1 = list_to_atom(NS), + El0 = exmpp_xml:xmlelement_to_xmlel(El, + [?NS_PRIVATE], [{?NS_XMPP, ?NS_XMPP_pfx}]), + El1 = exmpp_xml:remove_whitespaces_deeply(El0), + New_R = R#private_storage{ + usns = {U, S, NS1}, + xml = El1}, + mnesia:write(New_R), + Acc. diff --git a/src/mod_private_odbc.erl b/src/mod_private_odbc.erl index 6ea9a9af2..09dce943d 100644 --- a/src/mod_private_odbc.erl +++ b/src/mod_private_odbc.erl @@ -34,8 +34,9 @@ process_sm_iq/3, remove_user/2]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), @@ -50,87 +51,126 @@ stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE). -process_sm_iq(From, _To, #iq{type = Type, sub_el = SubEl} = IQ) -> - #jid{luser = LUser, lserver = LServer} = From, - case lists:member(LServer, ?MYHOSTS) of - true -> - {xmlelement, Name, Attrs, Els} = SubEl, +process_sm_iq(From, To, #iq{type = Type} = IQ_Rec) -> + case check_packet(From, To, IQ_Rec) of + ok -> case Type of set -> - F = fun() -> - lists:foreach( - fun(El) -> - set_data(LUser, LServer, El) - end, Els) - end, - odbc_queries:sql_transaction(LServer, F), - IQ#iq{type = result, - sub_el = [{xmlelement, Name, Attrs, []}]}; + process_iq_set(From, To, IQ_Rec); get -> - case catch get_data(LUser, LServer, Els) of - {'EXIT', _Reason} -> - IQ#iq{type = error, - sub_el = [SubEl, - ?ERR_INTERNAL_SERVER_ERROR]}; - Res -> - IQ#iq{type = result, - sub_el = [{xmlelement, Name, Attrs, Res}]} - end + process_iq_get(From, To, IQ_Rec) end; - false -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]} + {error, Error} -> + exmpp_iq:error(IQ_Rec, Error) end. -set_data(LUser, LServer, El) -> - case El of - {xmlelement, _Name, Attrs, _Els} -> - XMLNS = xml:get_attr_s("xmlns", Attrs), - case XMLNS of - "" -> - ignore; - _ -> - Username = ejabberd_odbc:escape(LUser), - LXMLNS = ejabberd_odbc:escape(XMLNS), - SData = ejabberd_odbc:escape( - lists:flatten(xml:element_to_string(El))), - odbc_queries:set_private_data(LServer, Username, LXMLNS, SData) - end; - _ -> - ignore +process_iq_get(From, _To, #iq{payload = SubEl} = IQ_Rec) -> + #jid{lnode = LUser, ldomain = LServer} = From, + case catch get_data(LUser, + LServer, + exmpp_xml:get_child_elements(SubEl)) of + {'EXIT', _Reason} -> + {error, 'internal-server-error'}; + Res -> + exmpp_iq:result(IQ_Rec, #xmlel{ns = ?NS_PRIVATE, + name = 'query', + children = Res}) end. + +process_iq_set(From, _To, #iq{payload = SubEl} = IQ_Rec) -> + #jid{lnode = LUser, ldomain = LServer} = From, + F = fun() -> + lists:foreach( + fun(El) -> + set_data(LUser, LServer, El) + end, exmpp_xml:get_child_elements(SubEl)) + end, + odbc_queries:sql_transaction(LServer, F), + exmpp_iq:result(IQ_Rec). + + +check_packet(From, To, IQ_Rec) -> + check_packet(From, To, IQ_Rec, [ fun check_domain/3, + fun check_user/3, + fun check_ns/3]). +check_packet(_From, _To, _IQ_Rec, []) -> + ok; +check_packet(From, To, IQ_Rec, [F | R]) -> + case F(From, To, IQ_Rec) of + {error, _} = Error -> Error; + ok -> check_packet(From, To, IQ_Rec, R) + end. + +check_domain(#jid{ldomain = LServer}, _To, _IQ_Rec) -> + case lists:member(LServer, ?MYHOSTS) of + true -> ok; + false -> {error, 'not-allowed'} + end. + +% the iq can't be directed to another jid +check_user(From, To, _IQ_Rec) -> + case exmpp_jid:compare_bare_jids(From, To) of + true -> ok; + false -> {error, 'forbidden'} + end. + +%there must be at least one child, and every child should have +%a namespace specified (reject if the namespace is jabber:iq:private, +%the same than the parent element). +check_ns(_From, _To, #iq{payload = SubEl}) -> + case exmpp_xml:get_child_elements(SubEl) of + [] -> + {error, 'not-acceptable'}; + Children -> + case lists:any(fun(Child) -> + exmpp_xml:get_ns_as_atom(Child) =:= ?NS_PRIVATE + end, Children) of + true -> {error, 'not-acceptable'}; + false -> ok + end + end. + + + +set_data(LUser, LServer, El) -> + XMLNS = exmpp_xml:get_ns_as_list(El), + Username = ejabberd_odbc:escape(LUser), + LXMLNS = ejabberd_odbc:escape(XMLNS), + SData = ejabberd_odbc:escape(exmpp_xml:document_to_list(El)), + odbc_queries:set_private_data(LServer, Username, LXMLNS, SData). + get_data(LUser, LServer, Els) -> get_data(LUser, LServer, Els, []). get_data(_LUser, _LServer, [], Res) -> lists:reverse(Res); get_data(LUser, LServer, [El | Els], Res) -> - case El of - {xmlelement, _Name, Attrs, _} -> - XMLNS = xml:get_attr_s("xmlns", Attrs), - Username = ejabberd_odbc:escape(LUser), - LXMLNS = ejabberd_odbc:escape(XMLNS), - case catch odbc_queries:get_private_data(LServer, Username, LXMLNS) of - {selected, ["data"], [{SData}]} -> - case xml_stream:parse_element(SData) of - Data when element(1, Data) == xmlelement -> - get_data(LUser, LServer, Els, - [Data | Res]) - end; - %% MREMOND: I wonder when the query could return a vcard ? - {selected, ["vcard"], []} -> - get_data(LUser, LServer, Els, - [El | Res]); - _ -> - get_data(LUser, LServer, Els,[El | Res]) - end; - _ -> - get_data(LUser, LServer, Els, Res) - end. + XMLNS = exmpp_xml:get_ns_as_list(El), + Username = ejabberd_odbc:escape(LUser), + LXMLNS = ejabberd_odbc:escape(XMLNS), + case catch odbc_queries:get_private_data(LServer, Username, LXMLNS) of + {selected, ["data"], [{SData}]} -> + [Data] = exmpp_xml:parse_document(SData,[namespace, + name_as_atom, + autoload_known]), + get_data(LUser, LServer, Els, [Data | Res]); + %% MREMOND: I wonder when the query could return a vcard ? + {selected, ["vcard"], []} -> + get_data(LUser, LServer, Els, + [El | Res]); + _ -> + get_data(LUser, LServer, Els, [El | Res]) +end. remove_user(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - Username = ejabberd_odbc:escape(LUser), - odbc_queries:del_user_private_storage(LServer, Username). + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + Username = ejabberd_odbc:escape(LUser), + odbc_queries:del_user_private_storage(LServer, Username) + catch + _ -> + ok + end. diff --git a/src/mod_version.erl b/src/mod_version.erl index 26a960dca..ec7115a37 100644 --- a/src/mod_version.erl +++ b/src/mod_version.erl @@ -33,40 +33,39 @@ stop/1, process_local_iq/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VERSION, + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_SOFT_VERSION, ?MODULE, process_local_iq, IQDisc). stop(Host) -> - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VERSION). + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_SOFT_VERSION). -process_local_iq(_From, To, #iq{id = _ID, type = Type, - xmlns = _XMLNS, sub_el = SubEl} = IQ) -> +process_local_iq(_From, To, #iq{type = Type} = IQ_Rec) -> case Type of set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + exmpp_iq:error(IQ_Rec, 'not-allowed'); get -> - Host = To#jid.server, + Host = To#jid.domain, OS = case gen_mod:get_module_opt(Host, ?MODULE, show_os, true) of true -> [get_os()]; false -> [] end, - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_VERSION}], - [{xmlelement, "name", [], - [{xmlcdata, "ejabberd"}]}, - {xmlelement, "version", [], - [{xmlcdata, ?VERSION}]} - ] ++ OS - }]} + R = #xmlel{ns = ?NS_SOFT_VERSION, name = 'query', + children = [ exmpp_xml:set_cdata(#xmlel{ns = ?NS_SOFT_VERSION, + name = 'name'}, + <<"ejabberd">>), + exmpp_xml:set_cdata(#xmlel{ns = ?NS_SOFT_VERSION, + name = 'version'}, + ?VERSION) | OS]}, + exmpp_iq:result(IQ_Rec, R) end. @@ -87,4 +86,4 @@ get_os() -> VersionString end, OS = OSType ++ " " ++ OSVersion, - {xmlelement, "os", [], [{xmlcdata, OS}]}. + exmpp_xml:set_cdata(#xmlel{ns = ?NS_SOFT_VERSION, name = 'os'}, OS). From 67a87af459f070c94c27f7b68db85c65d3adbdf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 8 Oct 2008 12:02:30 +0000 Subject: [PATCH 101/582] Merge from trunk (r1563 to r1613). PR: EJABP-1 SVN Revision: 1614 --- ChangeLog | 66 +++++ doc/guide.html | 274 +++++++++++---------- doc/guide.tex | 317 ++++++++++++------------ src/ejabberd_rdbms.erl | 15 +- src/ejabberd_zlib/Makefile.win32 | 3 +- src/eldap/Makefile.win32 | 3 +- src/mod_configure.erl | 4 +- src/mod_irc/Makefile.win32 | 3 +- src/mod_muc/Makefile.win32 | 3 +- src/mod_proxy65/Makefile.win32 | 5 +- src/mod_pubsub/Makefile.win32 | 17 +- src/mod_pubsub/gen_pubsub_node.erl | 2 +- src/mod_pubsub/mod_pubsub.erl | 65 +++-- src/mod_pubsub/node.template | 6 +- src/mod_pubsub/node_buddy.erl | 6 +- src/mod_pubsub/node_club.erl | 6 +- src/mod_pubsub/node_default.erl | 10 +- src/mod_pubsub/node_dispatch.erl | 6 +- src/mod_pubsub/node_mb.erl | 197 +++++++++++++++ src/mod_pubsub/node_pep.erl | 9 +- src/mod_pubsub/node_private.erl | 6 +- src/mod_pubsub/node_public.erl | 6 +- src/mod_pubsub/node_zoo.erl | 6 +- src/mod_roster_odbc.erl | 7 +- src/mod_shared_roster.erl | 13 +- src/mod_vcard_odbc.erl | 66 ++--- src/odbc/Makefile.win32 | 3 +- src/odbc/ejabberd_odbc.erl | 43 ++-- src/odbc/ejabberd_odbc_sup.erl | 38 ++- src/odbc/mssql2005.sql | 382 +++++++++++++++++++++-------- src/odbc/odbc_queries.erl | 61 ++++- src/stringprep/Makefile.win32 | 3 +- src/tls/Makefile.win32 | 3 +- src/web/Makefile.win32 | 12 +- 34 files changed, 1106 insertions(+), 560 deletions(-) create mode 100644 src/mod_pubsub/node_mb.erl diff --git a/ChangeLog b/ChangeLog index 882217ace..9353205f7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2008-10-08 Jean-Sébastien Pédron + + Merge from trunk (r1563 to r1613). + 2008-10-07 Jean-Sébastien Pédron * src/ejabberd_local.erl: Fix a bug where an error stanza was not @@ -9,6 +13,10 @@ * src/mod_private.erl, src/mod_private_odbc.erl, src/mod_version.erl: Convert to exmpp. Thanks to Pablo Polvorin! +2008-10-07 Jerome Sautret + + * src/mod_roster_odbc.erl: fix MySQL multiple requests issue. + 2008-10-06 Jean-Sébastien Pédron * src/ejabberd_sm.erl (process_iq/3): Fix a bug where we were matching @@ -32,6 +40,29 @@ mixing lists and binaries in a non-working way. Thanks to Pablo Polvorin! +2008-10-06 Badlop + + * doc/guide.html: Regenerated + +2008-10-06 Jerome Sautret + + * src/ejabberd_rdbms.erl: fix SQL database reconnection + issues (EJAB-764) and add odbc_start_interval configuration + directive (default to 30 seconds). + * src/odbc/ejabberd_odbc.erl: likewise. + * src/odbc/ejabberd_odbc_sup.erl: likewise. + * doc/guide.tex: likewise. + +2008-10-03 Jerome Sautret + + * src/odbc/odbc_queries.erl: Fix empty query that fail on MySQL. + +2008-10-03 Jerome Sautret + + * src/mod_vcard_odbc: added vCard support for MS SQL Server 2005. + * src/odbc/odbc_queries.erl: likewise. + * src/odbc/mssql2005.sql: likewise. + 2008-10-02 Jean-Sébastien Pédron * src/mod_roster_odbc.erl: Fix a bug where a JID represented as a @@ -59,6 +90,17 @@ src/mod_roster_odbc.erl: Fix multiple bugs in ODBC mods, thanks to Pablo Polvorin! +2008-10-01 Mickael Remond + + * src/mod_shared_roster.erl: Correct roster push when changing + a shared roster entry name (EJAB-738). + +2008-09-30 Badlop + + * src/*/Makefile.win32: Provide explicit beam filenames because + nmake does not accept wildcards (thanks to Attila + Vangel)(EJAB-543) + 2008-09-29 Jean-Sébastien Pédron * src/jlib.erl (parse_xdata_submit, parse_xdata_fields): Fix a bug @@ -99,6 +141,25 @@ Ejabberd expects new structures. Add table conversion. Add try/catch block around exmpp_stringprep:*prep/1 uses. +2008-09-24 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: Allow PEP node type to be mapped with + namespace (EJAB-739). Change get_items to use From (EJAB-751). (Thanks + to Eric Cestari) + * src/mod_pubsub/gen_pubsub_node.erl: Likewise + * src/mod_pubsub/node_dispatch.erl: Likewise + * src/mod_pubsub/node_buddy.erl: Likewise + * src/mod_pubsub/node_zoo.erl: Likewise + * src/mod_pubsub/node.template: Likewise + * src/mod_pubsub/node_private.erl: Likewise + * src/mod_pubsub/node_public.erl: Likewise + * src/mod_pubsub/node_default.erl: Likewise + * src/mod_pubsub/node_pep.erl: Likewise + * src/mod_pubsub/node_club.erl: Likewise + + * src/mod_pubsub/node_mb.erl: Added PEP microglobing node (Thanks to + Eric Cestari) + 2008-09-23 Jean-Sébastien Pédron * src/mod_vcard.erl (process_sm_iq): Fix a bug where a badmatch @@ -126,6 +187,11 @@ * src/mod_vcard_ldap.erl, src/mod_vcard_odbc.erl: Convert to exmpp. +2008-09-22 Mickael Remond + + * src/mod_configure.erl: Fix adhoc commands reply types for + "get-online-users-num" and "get-registered-users-num" (EJAB-756). + 2008-09-18 Jean-Sébastien Pédron * src/mod_roster_odbc.erl: Convert to exmpp. diff --git a/doc/guide.html b/doc/guide.html index 97e0f9248..320d0db62 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -272,8 +272,8 @@ Support for virtual hosting.

    Chapter 2  Installing ejabberd

    2.1  Installing ejabberd with Binary Installer

    Probably the easiest way to install an ejabberd instant messaging server -is using the binary installer published by ProcessOne. -The binary installers of released ejabberd versions +is using the binary installer published by ProcessOne. +The binary installers of released ejabberd versions are available in the ProcessOne ejabberd downloads page: http://www.process-one.net/en/ejabberd/downloads

    The installer will deploy and configure a full featured ejabberd server and does not require any extra dependencies.

    In *nix systems, remember to set executable the binary installer before starting it. For example: @@ -282,13 +282,13 @@ server and does not require any extra dependencies.

    In *nix systems, remem

    ejabberd can be started manually at any time, or automatically by the operating system at system boot time.

    To start and stop ejabberd manually, use the desktop shortcuts created by the installer. -If the machine doesn’t have a graphical system, use the scripts ’start’ +If the machine doesn’t have a graphical system, use the scripts ’start’ and ’stop’ in the ’bin’ directory where ejabberd is installed.

    The Windows installer also adds ejabberd as a system service, and a shortcut to a debug console for experienced administrators. -If you want ejabberd to be started automatically at boot time, +If you want ejabberd to be started automatically at boot time, go to the Windows service settings and set ejabberd to be automatically started. -Note that the Windows service is a feature still in development, -and for example it doesn’t read the file ejabberdctl.cfg.

    On a *nix system, if you want ejabberd to be started as daemon at boot time, +Note that the Windows service is a feature still in development, +and for example it doesn’t read the file ejabberdctl.cfg.

    On a *nix system, if you want ejabberd to be started as daemon at boot time, copy ejabberd.init from the ’bin’ directory to something like /etc/init.d/ejabberd (depending on your distribution) and call /etc/inid.d/ejabberd start to start it.

    If ejabberd doesn’t start correctly in Windows, try to start it using the shortcut in desktop or start menu. @@ -305,9 +305,9 @@ This way you see the error message provided by Erlang and can identify what is exactly the problem.

    The ejabberdctl administration script is included in the bin directory. Please refer to the section 4.1 for details about ejabberdctl, and configurable options to fine tune the Erlang runtime system.

    -

    2.2  Installing ejabberd with Operating System specific packages

    Some Operating Systems provide a specific ejabberd package adapted to +

    2.2  Installing ejabberd with Operating System specific packages

    Some Operating Systems provide a specific ejabberd package adapted to the system architecture and libraries. -It usually also checks dependencies +It usually also checks dependencies and performs basic configuration tasks like creating the initial administrator account. Some examples are Debian and Gentoo. Consult the resources provided by your Operating System for more information.

    Usually those packages create a script like /etc/init.d/ejabberd @@ -317,12 +317,12 @@ to start and stop ejabberd as a service at boot time.

    2.4  Installing ejabberd from Source Code

    The canonical form for distribution of ejabberd stable releases is the source code package. -Compiling ejabberd from source code is quite easy in *nix systems, +Compiling ejabberd from source code is quite easy in *nix systems, as long as your system have all the dependencies.

    2.4.1  Requirements

    To compile ejabberd on a ‘Unix-like’ operating system, you need: @@ -350,10 +350,10 @@ To get the full list run the command:

    ./configure --help
     

    Some options that you may be interested in modifying:

    - --prefix=/
    + --prefix=/
    Specify the path prefix where the files will be copied when running the make install command.

    --enable-user[=USER]
    - Allow this normal system user to execute the ejabberdctl script + Allow this normal system user to execute the ejabberdctl script (see section 4.1), read the configuration files, read and write in the spool directory, @@ -361,14 +361,14 @@ To get the full list run the command: The account user and group must exist in the machine before running make install. This account doesn’t need an explicit HOME directory, because - /var/lib/ejabberd/ will be used by default.

    --enable-pam
    + /var/lib/ejabberd/ will be used by default.

    --enable-pam
    Enable the PAM authentication method (see section 3.1.4).

    --enable-odbc or --enable-mssql
    Required if you want to use an external database. - See section 3.2 for more information.

    --enable-full-xml
    + See section 3.2 for more information.

    --enable-full-xml
    Enable the use of XML based optimisations. - It will for example use CDATA to escape characters in the XMPP stream. + It will for example use CDATA to escape characters in the XMPP stream. Use this option only if you are sure your Jabber clients include a fully compliant XML parser.

    --disable-transient-supervisors
    - Disable the use of Erlang/OTP supervision for transient processes. + Disable the use of Erlang/OTP supervision for transient processes.

    2.4.4  Install

    To install ejabberd in the destination directories, run the command: @@ -432,8 +432,8 @@ and configurable options to fine tune the Erlang runtime system.

    You need to have GNU install, but it isn’t included in Solaris. It can be easily installed if your Solaris system -is set up for blastwave.org -package repository. +is set up for blastwave.org +package repository. Make sure /opt/csw/bin is in your PATH and run:

    pkg-get -i fileutils
     

    If that program is called ginstall, @@ -471,8 +471,8 @@ directory, you can add the directories C:\sdk\GnuWin32\bin to the PATH environment variable.

  • Install OpenSSL in C:\sdk\OpenSSL and add C:\sdk\OpenSSL\lib\VC to your path or copy the binaries to your system directory. -
  • Install ZLib in C:\sdk\gnuWin32. Copy -C:\sdk\GnuWin32\bin\zlib1.dll to your system directory. If you change your path it should already be set after libiconv install. +
  • Install ZLib in C:\sdk\gnuWin32. Copy +C:\sdk\GnuWin32\bin\zlib1.dll to your system directory. If you change your path it should already be set after libiconv install.
  • Make sure the you can access Erlang binaries from your path. For example: set PATH=%PATH%;"C:\sdk\erl5.5.5\bin"
  • Depending on how you end up actually installing the library you might need to check and tweak the paths in the file configure.erl.
  • While in the directory ejabberd\src run: @@ -484,7 +484,7 @@ nmake -f Makefile.win32

    2.5  Create a Jabber Account for Administration

    You need a Jabber account and grant him administrative privileges to enter the ejabberd Web Admin:

    1. -Register a Jabber account on your ejabberd server, for example admin1@example.org. +Register a Jabber account on your ejabberd server, for example admin1@example.org. There are two ways to register a Jabber account:
      1. Using ejabberdctl (see section 4.1): @@ -504,7 +504,7 @@ suffix, is because ejabberd’s virtual hosting support.

      2.6  Upgrading ejabberd

      To upgrade an ejabberd installation to a new version, simply uninstall the old version, and then install the new one. -Of course, it is important that the configuration file +Of course, it is important that the configuration file and Mnesia database spool directory are not removed.

      ejabberd automatically updates the Mnesia table definitions at startup when needed. If you also use an external database for storage of some modules, check if the release notes of the new ejabberd version @@ -514,7 +514,7 @@ indicates you need to also update those tables.

      3.1  Basic Configuration

      The configuration file will be loaded the first time you start ejabberd. The content from this file will be parsed and stored in the internal ejabberd database. Subsequently the configuration will be loaded from the database and any commands in the -configuration file are appended to the entries in the database.

      Note that ejabberd never edits the configuration file. +configuration file are appended to the entries in the database.

      Note that ejabberd never edits the configuration file. So, the configuration changes done using the Web Admin are stored in the database, but are not reflected in the configuration file. If you want those changes to be use after ejabberd restart, you can either @@ -625,7 +625,7 @@ Port number.

    2. The available modules, their purpose and the options allowed by each one are:

      -ejabberd_c2s
      +ejabberd_c2s
      Handles c2s connections.
      Options: access, certfile, inet6, ip, max_stanza_size, shaper, @@ -635,7 +635,7 @@ Handles c2s connections.
      Handles incoming s2s connections.
      Options: inet6, ip, max_stanza_size
      ejabberd_service
      -Interacts with external components +Interacts with an external component (as defined in the Jabber Component Protocol (XEP-0114).
      Options: access, hosts, inet6, ip, shaper, service_check_from @@ -655,9 +655,10 @@ used to disable control on the from field on packets send by an external components. The option can be either true or false. The default value is true which conforms to XEP-0114.
      {hosts, [Hostnames], [HostOptions]}
      -This option of ejabberd_service allows to define one or more hostnames -of external Jabber components that provide a service. -In HostOptions it is possible to define the password required to those components +The external Jabber component that connects to this ejabberd_service +can serve one or more hostnames. +In HostOptions you can define options for the component; +currently the only allowed option is the password required to the component when attempt to connect to ejabberd: {password, Secret}. Note that you cannot define in a single ejabberd_service components of different services: add an ejabberd_service for each service, @@ -669,7 +670,7 @@ do not allow outgoing sockets on port 5222.

      Remember that you must also instal http://server:port/http-bind/. Be aware that support for HTTP Bind is also needed in the Jabber client. Remark also that HTTP Bind can be interesting to host a web-based Jabber client such as -JWChat +JWChat (check the tutorials to install JWChat with ejabberd and an embedded local web server or Apache). @@ -683,7 +684,7 @@ interesting to host a web-based Jabber client such as JWChat.

      inet6
      Set up the socket for IPv6 instead of IPv4. Note: this option is not required for S2S outgoing connections, -because when ejabberd attempts to establish a S2S outgoing connection +because when ejabberd attempts to establish a S2S outgoing connection it first tries IPv4, and if that fails it attempts with IPv6.
      {ip, IPAddress}
      This option specifies which network interface to listen for. For example {ip, {192, 168, 1, 1}}. @@ -715,7 +716,7 @@ You should also set the certfile option. You can define a certificate file for a specific domain using the global option domain_certfile.
      starttls_required
      This option specifies that STARTTLS encryption is required on connections to the port. -No unencrypted connections will be allowed. +No unencrypted connections will be allowed. You should also set the certfile option. You can define a certificate file for a specific domain using the global option domain_certfile.
      tls
      This option specifies that traffic on @@ -746,7 +747,7 @@ The default policy for incoming and outgoing s2s connections to other Jabber ser The default value is allow.
      {{s2s_host, Host}, allow|deny}
      Defines if incoming and outgoing s2s connections with a specific remote host are allowed or denied. -This allows to restrict ejabberd to only establish s2s connections +This allows to restrict ejabberd to only establish s2s connections with a small list of trusted servers, or to block some specific servers.
      {s2s_max_retry_delay, Seconds}
      The maximum allowed delay for retry to connect after a failed connection attempt. @@ -755,7 +756,7 @@ Specified in seconds. The default value is 300 seconds (5 minutes).

      • There are three domains. The default certificate file is server.pem. However, the c2s and s2s connections to the domain example.com use the file example_com.pem. -
      • Port 5222 listens for c2s connections with STARTTLS, +
      • Port 5222 listens for c2s connections with STARTTLS, and also allows plain connections for old clients.
      • Port 5223 listens for c2s connections with the old SSL.
      • Port 5269 listens for s2s connections with STARTTLS. @@ -766,7 +767,7 @@ section 4.2. {listen, [ {5222, ejabberd_c2s, [ - {access, c2s}, + {access, c2s}, {shaper, c2s_shaper}, starttls, {certfile, "/etc/ejabberd/server.pem"}, {max_stanza_size, 65536} @@ -804,7 +805,7 @@ only two servers can connect: "jabber.example.org" and "example.com".
      • Port 5280 is serving the Web Admin and the HTTP Polling service. Note that it is also possible to serve them on different ports. The second example in section 4.2 shows how exactly this can be done. -
      • All users except for the administrators have a traffic of limit +
      • All users except for the administrators have a traffic of limit 1,000 Bytes/second
      • The AIM transport @@ -1122,7 +1123,7 @@ following syntax:

        {maxrate, <rate>}
         

        where <rate> stands for the maximum allowed incoming rate in bytes per second. -When a connection exceeds this limit, ejabberd stops reading from the socket +When a connection exceeds this limit, ejabberd stops reading from the socket until the average rate is again below the allowed maximum.

        Examples:

        • To define a shaper named ‘normal’ with traffic speed limited to @@ -1166,7 +1167,7 @@ The default value is: all If such an option is present, the option will not be accepted. The file is in a subdirectory from where the main configuration file is.

          {include_config_file, "./example.org/additional_not_listen.cfg", [{disallow, [listen]}]}.
          -

          In this example, ejabberd.cfg defines some ACL and Access rules, +

          In this example, ejabberd.cfg defines some ACL and Access rules, and later includes another file with additional rules:

          {acl, admin, {user, "admin", "localhost"}}.
           {access, announce, [{allow, admin}]}.
          @@ -1256,11 +1257,14 @@ you. This file contains the ejabberd schema for MySQL. At the end of th
           you can find information to update your database schema.

          By default ejabberd opens 10 connections to the database for each virtual host. Use this option to modify the value:

          {odbc_pool_size, 10}.
          -

          You can configure an interval to make a dummy SQL request -to keep alive the connections to the database. -The default value is ’undefined’, so no keepalive requests are made. +

          You can configure an interval to make a dummy SQL request +to keep alive the connections to the database. +The default value is ’undefined’, so no keepalive requests are made. Specify in seconds: for example 28800 means 8 hours.

          {odbc_keepalive_interval, undefined}.
          +

          If the connection to the database fails, ejabberd waits 30 seconds before retrying. +You can modify this interval with this option: +

          {odbc_start_interval, 30}.
           

          Driver Compilation

          You can skip this step if you installed ejabberd using a binary installer or @@ -1313,9 +1317,9 @@ you. This file contains the ejabberd schema for Microsoft SQL Server. A of the file you can find information to update your database schema.

          By default ejabberd opens 10 connections to the database for each virtual host. Use this option to modify the value:

          {odbc_pool_size, 10}.
          -

          You can configure an interval to make a dummy SQL request -to keep alive the connections to the database. -The default value is ’undefined’, so no keepalive requests are made. +

          You can configure an interval to make a dummy SQL request +to keep alive the connections to the database. +The default value is ’undefined’, so no keepalive requests are made. Specify in seconds: for example 28800 means 8 hours.

          {odbc_keepalive_interval, undefined}.
           

          @@ -1348,9 +1352,9 @@ This file contains the ejabberd schema for PostgreSQL. At the end of th you can find information to update your database schema.

          By default ejabberd opens 10 connections to the database for each virtual host. Use this option to modify the value:

          {odbc_pool_size, 10}.
          -

          You can configure an interval to make a dummy SQL request -to keep alive the connections to the database. -The default value is ’undefined’, so no keepalive requests are made. +

          You can configure an interval to make a dummy SQL request +to keep alive the connections to the database. +The default value is ’undefined’, so no keepalive requests are made. Specify in seconds: for example 28800 means 8 hours.

          {odbc_keepalive_interval, undefined}.
           

          @@ -1359,7 +1363,7 @@ Specify in seconds: for example 28800 means 8 hours. if the binary packages of ejabberd you are using include support for PostgreSQL.

          1. First, install the Erlang pgsql library from -ejabberd-modules SVN repository. +ejabberd-modules SVN repository. Make sure the compiled files are in your Erlang path; you can put them for example in the same directory as your ejabberd .beam files. @@ -1405,9 +1409,9 @@ contains information about ejabberd’s configuration which is dup this section.

            By default ejabberd opens 10 connections to the database for each virtual host. Use this option to modify the value:

            {odbc_pool_size, 10}.
            -

            You can configure an interval to make a dummy SQL request -to keep alive the connections to the database. -The default value is ’undefined’, so no keepalive requests are made. +

            You can configure an interval to make a dummy SQL request +to keep alive the connections to the database. +The default value is ’undefined’, so no keepalive requests are made. Specify in seconds: for example 28800 means 8 hours.

            {odbc_keepalive_interval, undefined}.
             

            @@ -1444,17 +1448,17 @@ module loaded!

            ejabberd has built-in LDAP support. You can authenticate users against LDAP server and use LDAP directory as vCard storage. Shared rosters are not supported yet.

            Note that ejabberd treats LDAP as a read-only storage: -it is possible to consult data, but not possible to +it is possible to consult data, but not possible to create accounts, change password or edit vCard that is stored in LDAP.

            Connection

            Parameters:

            ldap_servers
            List of IP addresses or DNS names of your LDAP servers. This option is required.
            ldap_port
            Port to connect to your LDAP server. -The initial default value is 389, so it is used when nothing is set into the -configuration file. -If you configure a value, it is stored in ejabberd’s database. -Then, if you remove that value from the configuration file, +The initial default value is 389, so it is used when nothing is set into the +configuration file. +If you configure a value, it is stored in ejabberd’s database. +Then, if you remove that value from the configuration file, the value previously stored in the database will be used instead of the default 389.
            ldap_rootdn
            Bind DN. The default value is "" which means ‘anonymous connection’. @@ -1738,7 +1742,7 @@ number of processes (32000 by default).

            host

            This option defines the Jabber ID of a service provided by an ejabberd module. The keyword "@HOST@" is replaced at start time with the real virtual host string.

            This example configures -the echo module to provide its echoing service +the echo module to provide its echoing service in the Jabber ID mirror.example.org:

            {modules,
              [
            @@ -1757,7 +1761,7 @@ the "@HOST@" keyword must be used:
             

            3.3.3  mod_announce

            This module enables configured users to broadcast announcements and to set -the message of the day (MOTD). +the message of the day (MOTD). Configured users can perform these actions with a Jabber client either using Ad-hoc commands or sending messages to specific JIDs.

            The Ad-hoc commands are listed in the Server Discovery. @@ -1831,7 +1835,7 @@ for the superseded Jabber Browsing (

            -iqdisc
            This specifies +iqdisc
            This specifies the processing discipline for Service Discovery (http://jabber.org/protocol/disco#items and http://jabber.org/protocol/disco#info) IQ queries (see section 3.3.2).
            extra_domains
            With this option, @@ -1947,7 +1951,7 @@ discover when a disconnected user last accessed the server, to know when a connected user was last active on the server, or to query the uptime of the ejabberd server.

            Options:

            -iqdisc
            This specifies +iqdisc
            This specifies the processing discipline for Last activity (jabber:iq:last) IQ queries (see section 3.3.2).

            3.3.8  mod_muc

            @@ -1962,7 +1966,7 @@ Sending public and private messages to room occupants.

          2. Kicking and banning occupants.

        The MUC service allows any Jabber ID to register a nickname, so nobody else can use that nickname in any room in the MUC service. -To register a nickname, open the Service Discovery in your +To register a nickname, open the Service Discovery in your Jabber client and register in the MUC service.

        This module supports clustering and load balancing. One module can be started per cluster node. Rooms are distributed at creation time on all available MUC module @@ -2041,7 +2045,7 @@ interval delay. Intermediate presence packets are silently discarded. A good value for this option is 4 seconds.

      default_room_options
      This module option allows to define the desired default room options. -Note that the creator of a room can modify the options of his room +Note that the creator of a room can modify the options of his room at any time using a Jabber client with MUC capability. The available room options and the default values are:
      @@ -2055,7 +2059,9 @@ change nickname. status text in presence updates. If disallowed, the status text is stripped before broadcasting the presence update to all the room occupants. -
      {anonymous, true}
      Occupants are allowed to see the real JIDs of other occupants. +
      {anonymous, true}
      The room is anonymous: +occupants don’t see the real JIDs of other occupants. +Note that the room moderators can always see the real JIDs of the occupants.
      {logging, false}
      The public messages are logged using mod_muc_log.
      {max_users, 200}
      Maximum number of occupants in the room.
      {members_by_default, true}
      The occupants that enter the room are participants by default, so they have ’voice’. @@ -2214,7 +2220,7 @@ directory. The default value is "www/muc". To prevent spam, the spam_prevention option adds a special attribute to links that prevent their indexation by search engines. The default value is true, which mean that nofollow attributes will be added to user -submitted links. +submitted links.
      timezone
      The time zone for the logs is configurable with this option. Allowed values are local and universal. With the first value, the local time, @@ -2310,7 +2316,7 @@ subscription type (or globally). (from http://www.xmpp.org/specs/rfc3921.html#privacy)

      Options:

      -iqdisc
      This specifies +iqdisc
      This specifies the processing discipline for Blocking Communication (jabber:iq:privacy) IQ queries (see section 3.3.2).

      3.3.12  mod_private

      @@ -2322,7 +2328,7 @@ it is valid XML. One typical usage for this namespace is the server-side storage of client-specific preferences; another is Bookmark Storage (XEP-0048).

      Options:

      -iqdisc
      This specifies +iqdisc
      This specifies the processing discipline for Private XML Storage (jabber:iq:private) IQ queries (see section 3.3.2).

      3.3.13  mod_proxy65

      @@ -2399,7 +2405,7 @@ ACL and ACCESS. The default value is pubsub_createnode.

      nodetree
      To specify which nodetree to use. If not defined, the default pubsub nodetree is used. Nodetrees are default and virtual. Only one nodetree can be used -and is shared by all node plugins. +and is shared by all node plugins.

      Example:

      {modules,
        [
      @@ -2425,12 +2431,12 @@ rules to restrict registration. If a rule returns ‘deny’ on the re
       user name, registration for that user name is denied. (there are no
       restrictions by default).
       
      welcome_message
      Set a welcome message that -is sent to each newly registered account. The first string is the subject, and +is sent to each newly registered account. The first string is the subject, and the second string is the message body. In the body you can set a newline with the characters: \n -
      registration_watchers
      This option defines a +
      registration_watchers
      This option defines a list of JIDs which will be notified each time a new account is registered. -
      iqdisc
      This specifies +
      iqdisc
      This specifies the processing discipline for In-Band Registration (jabber:iq:register) IQ queries (see section 3.3.2).

      This module reads also another option defined globably for the server: {registration_timeout, Timeout}. @@ -2487,7 +2493,7 @@ Also define a registration timeout of one hour:

      3.3.16  mod_roster

      This module implements roster management as defined in RFC 3921: XMPP IM.

      Options:

      -iqdisc
      This specifies +iqdisc
      This specifies the processing discipline for Roster Management (jabber:iq:roster) IQ queries (see section 3.3.2).

      3.3.17  mod_service_log

      @@ -2510,7 +2516,7 @@ To log all end user packets to the Bandersnatch service running on ... ]}.

    3. To log all end user packets to the Bandersnatch service running on -bandersnatch.example.com and the backup service on +bandersnatch.example.com and the backup service on bandersnatch.example.org:
      {modules,
        [
      @@ -2525,9 +2531,9 @@ To log all end user packets to the Bandersnatch service running on
       create groups of people that can see members from (other) groups in their
       rosters. The big advantages of this feature are that end users do not need to
       manually add all users to their rosters, and that they cannot permanently delete
      -users from the shared roster groups. 
      +users from the shared roster groups.
       A shared roster group can have members from any Jabber server,
      -but the presence will only be available from and to members 
      +but the presence will only be available from and to members
       of the same virtual host where the group is created.

      Shared roster groups can be edited only via the Web Admin. Each group has a unique identification and the following parameters:

      @@ -2605,7 +2611,7 @@ Total number of registered users on the current virtual host (users/total).
    4. Total number of online users on all virtual hosts (users/all-hosts/online).
    5. Options:

      -iqdisc
      This specifies +iqdisc
      This specifies the processing discipline for Statistics Gathering (http://jabber.org/protocol/stats) IQ queries (see section 3.3.2).

      As there are only a small amount of clients (for example Tkabber) and software libraries with @@ -2631,7 +2637,7 @@ by sending:

      This module features support for Entity Time (XEP-0090). By using this XEP, you are able to discover the time at another entity’s location.

      Options:

      -iqdisc
      This specifies +iqdisc
      This specifies the processing discipline for Entity Time (jabber:iq:time) IQ queries (see section 3.3.2).

      3.3.21  mod_vcard

      @@ -2646,7 +2652,7 @@ service. If the host option is not specified, the Jabber ID will be the hostname of the virtual host with the prefix ‘vjud.’. The keyword "@HOST@" is replaced at start time with the real virtual host name. -

      iqdisc
      This specifies +
      iqdisc
      This specifies the processing discipline for vcard-temp IQ queries (see section 3.3.2).
      search
      This option specifies whether the search functionality is enabled (value: true) or disabled (value: @@ -2693,7 +2699,7 @@ and that all virtual hosts will be searched instead of only the current one:

      ejabberd can map LDAP attributes to vCard fields. This behaviour is implemented in the mod_vcard_ldap module. This module does not depend on the authentication method (see 3.2.5).

      Note that ejabberd treats LDAP as a read-only storage: -it is possible to consult data, but not possible to +it is possible to consult data, but not possible to create accounts, change password or edit vCard that is stored in LDAP.

      The mod_vcard_ldap module has its own optional parameters. The first group of parameters has the same meaning as the top-level LDAP parameters to set the authentication method: @@ -2709,7 +2715,7 @@ service. If the host option is not specified, the Jabber ID will be the hostname of the virtual host with the prefix ‘vjud.’. The keyword "@HOST@" is replaced at start time with the real virtual host name. -

      iqdisc
      This specifies +
      iqdisc
      This specifies the processing discipline for vcard-temp IQ queries (see section 3.3.2).
      search
      This option specifies whether the search functionality is enabled (value: true) or disabled (value: @@ -2871,14 +2877,14 @@ answers ejabberd’s version when queried.

      Options:

      show_os
      Should the operating system be revealed or not. The default value is true. -
      iqdisc
      This specifies +
      iqdisc
      This specifies the processing discipline for Software Version (jabber:iq:version) IQ queries (see section 3.3.2).

      Chapter 4  Managing an ejabberd server

      4.1  ejabberdctl

      -

      4.1.1  Commands

      The ejabberdctl command line administration script allows to start, stop and perform +

      4.1.1  Commands

      The ejabberdctl command line administration script allows to start, stop and perform many other administrative tasks in a local or remote ejabberd server.

      When ejabberdctl is executed without any parameter, -it displays the available options. If there isn’t an ejabberd server running, +it displays the available options. If there isn’t an ejabberd server running, the available parameters are:

      start
      Start ejabberd in background mode. This is the default method. @@ -2893,7 +2899,7 @@ The more interesting ones are:
      reopen-log
      If you use a tool to rotate logs, you have to configure it so that this command is executed after each rotation.
      backup, restore, install-fallback, dump, load
      You can use these -commands to create and restore backups. +commands to create and restore backups.
      import-file, import-dir
      These options can be used to migrate from other Jabber/XMPP servers. There exist tutorials to migrate from other software to ejabberd. @@ -2912,66 +2918,66 @@ for example using: echo $?

      4.1.2  Erlang runtime system

      ejabberd is an Erlang/OTP application that runs inside an Erlang runtime system. This system is configured using environment variables and command line parameters. The ejabberdctl administration script uses many of those possibilities. -You can configure some of them with the file ejabberdctl.cfg, +You can configure some of them with the file ejabberdctl.cfg, which includes detailed description about them. -This section describes for reference purposes +This section describes for reference purposes all the environment variables and command line parameters.

      The environment variables:

      -EJABBERD_CONFIG_PATH
      +EJABBERD_CONFIG_PATH
      Path to the ejabberd configuration file. -
      EJABBERD_MSGS_PATH
      +
      EJABBERD_MSGS_PATH
      Path to the directory with translated strings. -
      EJABBERD_LOG_PATH
      +
      EJABBERD_LOG_PATH
      Path to the ejabberd service log file. -
      EJABBERD_SO_PATH
      +
      EJABBERD_SO_PATH
      Path to the directory with binary system libraries. -
      HOME
      +
      HOME
      Path to the directory that is considered ejabberd’s home. This path is used to read the file .erlang.cookie. -
      ERL_CRASH_DUMP
      +
      ERL_CRASH_DUMP
      Path to the file where crash reports will be dumped. -
      ERL_INETRC
      +
      ERL_INETRC
      Indicates which IP name resolution to use. If using -sname, specify either this option or -kernel inetrc filepath. -
      ERL_MAX_PORTS
      +
      ERL_MAX_PORTS
      Maximum number of simultaneously open Erlang ports. -
      ERL_MAX_ETS_TABLES
      +
      ERL_MAX_ETS_TABLES
      Maximum number of ETS and Mnesia tables.

      The command line parameters:

      --sname ejabberd
      +-sname ejabberd
      The Erlang node will be identified using only the first part of the host name, i. e. other Erlang nodes outside this domain cannot contact this node. This is the preferable option in most cases. -
      -name ejabberd
      +
      -name ejabberd
      The Erlang node will be fully identified. This is only useful if you plan to setup an ejabberd cluster with nodes in different networks. -
      -kernel inetrc "/etc/ejabberd/inetrc"
      - Indicates which IP name resolution to use. +
      -kernel inetrc "/etc/ejabberd/inetrc"
      + Indicates which IP name resolution to use. If using -sname, specify either this option or ERL_INETRC. -
      -kernel inet_dist_listen_min 4200 inet_dist_listen_min 4210
      +
      -kernel inet_dist_listen_min 4200 inet_dist_listen_min 4210
      Define the first and last ports that epmd (section 5.2) can listen to. -
      -detached
      -Starts the Erlang system detached from the system console. - Useful for running daemons and backgrounds processes. -
      -noinput
      +
      -detached
      +Starts the Erlang system detached from the system console. + Useful for running daemons and backgrounds processes. +
      -noinput
      Ensures that the Erlang system never tries to read any input. - Useful for running daemons and backgrounds processes. -
      -pa /var/lib/ejabberd/ebin
      + Useful for running daemons and backgrounds processes. +
      -pa /var/lib/ejabberd/ebin
      Specify the directory where Erlang binary files (*.beam) are located. -
      -s ejabberd
      +
      -s ejabberd
      Tell Erlang runtime system to start the ejabberd application.
      -mnesia dir "/var/lib/ejabberd/"
      Specify the Mnesia database directory.
      -sasl sasl_error_logger {file, "/var/log/ejabberd/sasl.log"}
      Path to the Erlang/OTP system log file. -
      +K [true|false]
      +
      +K [true|false]
      Kernel polling. -
      -smp [auto|enable|disable]
      +
      -smp [auto|enable|disable]
      SMP support. -
      +P 250000
      +
      +P 250000
      Maximum number of Erlang processes. -
      -remsh ejabberd@localhost
      +
      -remsh ejabberd@localhost
      Open an Erlang shell in a remote Erlang node.

      Note that some characters need to be escaped when used in shell scripts, for instance " and {}. @@ -2979,7 +2985,7 @@ You can find other options in the Erlang manual page (erl -man erl).

      4.2  Web Admin

      The ejabberd Web Admin allows to administer most of ejabberd using a web browser.

      This feature is enabled by default: a ejabberd_http listener with the option web_admin (see -section 3.1.3) is included in the listening ports. Then you can open +section 3.1.3) is included in the listening ports. Then you can open http://server:port/admin/ in your favourite web browser. You will be asked to enter the username (the full Jabber ID) and password of an ejabberd user with administrator rights. After authentication @@ -3042,7 +3048,7 @@ with a Jabber client. The client must support Ad-Hoc Commands (XEP-0050), and you must login in the Jabber server with an account with proper privileges.

      -

      4.4  Change Computer Hostname

      ejabberd uses the distributed Mnesia database. +

      4.4  Change Computer Hostname

      ejabberd uses the distributed Mnesia database. Being distributed, Mnesia enforces consistency of its file, so it stores the name of the Erlang node in it (see section 5.4). The name of an Erlang node includes the hostname of the computer. @@ -3052,7 +3058,7 @@ or when you move ejabberd to a different machine.

      So, if you want you must follow these instructions:

      1. In the old server, backup the Mnesia database using the Web Admin or ejabberdctl. - For example: + For example:
        ejabberdctl backup /tmp/ejabberd-oldhost.backup
         
      2. In the new server, restore the backup file using the Web Admin or ejabberdctl. For example: @@ -3071,13 +3077,13 @@ you must follow these instructions:

  • 5.2  epmd

    epmd (Erlang Port Mapper Daemon) -is a small name server included in Erlang/OTP -and used by Erlang programs when establishing distributed Erlang communications. -ejabberd needs epmd to use ejabberdctl and also when clustering ejabberd nodes. +is a small name server included in Erlang/OTP +and used by Erlang programs when establishing distributed Erlang communications. +ejabberd needs epmd to use ejabberdctl and also when clustering ejabberd nodes. This small program is automatically started by Erlang, and is never stopped. -If ejabberd is stopped, and there aren’t any other Erlang programs -running in the system, you can safely stop epmd if you want.

    ejabberd runs inside an Erlang node. -To communicate with ejabberd, the script ejabberdctl starts a new Erlang node +If ejabberd is stopped, and there aren’t any other Erlang programs +running in the system, you can safely stop epmd if you want.

    ejabberd runs inside an Erlang node. +To communicate with ejabberd, the script ejabberdctl starts a new Erlang node and connects to the Erlang node that holds ejabberd. In order for this communication to work, epmd must be running and listening for name requests in the port 4369. @@ -3090,32 +3096,32 @@ So, if you plan to build a cluster of ejabberd nodes you must open the port 4369 for the machines involved in the cluster. Remember to block the port so Internet doesn’t have access to it.

    Once an Erlang node solved the node name of another Erlang node using EPMD and port 4369, the nodes communicate directly. -The ports used in this case by default are random, +The ports used in this case by default are random, but can be configured in the file ejabberdctl.cfg. The Erlang command-line parameter used internally is, for example:

    erl ... -kernel inet_dist_listen_min 4370 inet_dist_listen_max 4375
     

    -

    5.3  Erlang Cookie

    The Erlang cookie is a string with numbers and letters. +

    5.3  Erlang Cookie

    The Erlang cookie is a string with numbers and letters. An Erlang node reads the cookie at startup from the command-line parameter -setcookie. If not indicated, the cookie is read from the cookie file $HOME/.erlang.cookie. If this file does not exist, it is created immediately with a random cookie. Two Erlang nodes communicate only if they have the same cookie. -Setting a cookie on the Erlang node allows you to structure your Erlang network +Setting a cookie on the Erlang node allows you to structure your Erlang network and define which nodes are allowed to connect to which.

    Thanks to Erlang cookies, you can prevent access to the Erlang node by mistake, for example when there are several Erlang nodes running different programs in the same machine.

    Setting a secret cookie is a simple method to difficult unauthorized access to your Erlang node. -However, the cookie system is not ultimately effective +However, the cookie system is not ultimately effective to prevent unauthorized access or intrusion to an Erlang node. The communication between Erlang nodes are not encrypted, so the cookie could be read sniffing the traffic on the network. The recommended way to secure the Erlang node is to block the port 4369.

    5.4  Erlang node name

    An Erlang node may have a node name. -The name can be short (if indicated with the command-line parameter -sname) -or long (if indicated with the parameter -name). -Starting an Erlang node with -sname limits the communication between Erlang nodes to the LAN.

    Using the option -sname instead of -name is a simple method +The name can be short (if indicated with the command-line parameter -sname) +or long (if indicated with the parameter -name). +Starting an Erlang node with -sname limits the communication between Erlang nodes to the LAN.

    Using the option -sname instead of -name is a simple method to difficult unauthorized access to your Erlang node. However, it is not ultimately effective to prevent access to the Erlang node, -because it may be possible to fake the fact that you are on another network +because it may be possible to fake the fact that you are on another network using a modified version of Erlang epmd. The recommended way to secure the Erlang node is to block the port 4369.

    5.5  Securing sensible files

    ejabberd stores sensible data in the file system either in plain text or binary files. @@ -3184,11 +3190,15 @@ Copy ~ejabberd/.erlang.cookie file from first to second.

    (alt) You can also add ‘-cookie content_of_.erlang.cookie’ option to all ‘erl’ commands below.

  • On second run the following command as the ejabberd daemon user, in the working directory of ejabberd:
    erl -sname ejabberd \
    +    -mnesia dir "/var/lib/ejabberd/" \
         -mnesia extra_db_nodes "['ejabberd@first']" \
         -s mnesia
     

    This will start Mnesia serving the same database as ejabberd@first. You can check this by running the command ‘mnesia:info().’. You -should see a lot of remote tables and a line like the following:

    running db nodes   = [ejabberd@first, ejabberd@second]
    +should see a lot of remote tables and a line like the following:

    Note: the Mnesia directory may be different in your system. +To know where does ejabberd expect Mnesia to be installed by default, +call 4.1 without options and it will show some help, +including the Mnesia database spool dir.

    running db nodes   = [ejabberd@first, ejabberd@second]
     
  • Now run the following in the same ‘erl’ session:
    mnesia:change_table_copy_type(schema, node(), disc_copies).
     

    This will create local disc storage for the database.

    (alt) Change storage type of the scheme table to ‘RAM and disc copy’ on the second node via the Web Admin.

  • Now you can add replicas of various tables to this node with @@ -3214,7 +3224,7 @@ domain.

    6.3.1  Components Load-Balancing

    6.3.2  Domain Load-Balancing Algorithm

    -

    ejabberd includes an algorithm to load balance the components that are plugged on an ejabberd cluster. It means that you can plug one or several instances of the same component on each ejabberd cluster and that the traffic will be automatically distributed.

    The default distribution algorithm try to deliver to a local instance of a component. If several local instances are available, one instance is chosen randomly. If no instance is available locally, one instance is chosen randomly among the remote component instances.

    If you need a different behaviour, you can change the load balancing behaviour with the option domain_balancing. The syntax of the option is the following:

    {domain_balancing, "component.example.com", <balancing_criterium>}.                                   
    +

    ejabberd includes an algorithm to load balance the components that are plugged on an ejabberd cluster. It means that you can plug one or several instances of the same component on each ejabberd cluster and that the traffic will be automatically distributed.

    The default distribution algorithm try to deliver to a local instance of a component. If several local instances are available, one instance is chosen randomly. If no instance is available locally, one instance is chosen randomly among the remote component instances.

    If you need a different behaviour, you can change the load balancing behaviour with the option domain_balancing. The syntax of the option is the following:

    {domain_balancing, "component.example.com", <balancing_criterium>}.
     

    Several balancing criteria are available:

    • destination: the full JID of the packet to attribute is used. @@ -3260,12 +3270,12 @@ For example, the default configuration is:

      7.3  Debug Console

      The Debug Console is an Erlang shell attached to an already running ejabberd server. With this Erlang shell, an experienced administrator can perform complex tasks.

      This shell gives complete control over the ejabberd server, so it is important to use it with extremely care. -There are some simple and safe examples in the article +There are some simple and safe examples in the article Interconnecting Erlang Nodes

      To exit the shell, close the window or press the keys: control+c control+c.

      Appendix A  Internationalization and Localization

      The source code of ejabberd supports localization. -The translators can edit the -gettext .po files +The translators can edit the +gettext .po files using any capable program (KBabel, Lokalize, Poedit...) or a simple text editor.

      Then gettext is used to extract, update and export those .po files to the .msg format read by ejabberd. To perform those management tasks, in the src/ directory execute make translations. @@ -3292,7 +3302,7 @@ Figure A.1, for example, shows the reply to the webadmmainru.png -

      Figure A.2: Web Admin showing a virtual host when the web browser provides the +
      Figure A.2: Web Admin showing a virtual host when the web browser provides the HTTP header ‘Accept-Language: ru’
      diff --git a/doc/guide.tex b/doc/guide.tex index 7d5631f9c..6c62769ae 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -102,7 +102,7 @@ \include{contributed_modules} %% Common options -\newcommand{\iqdiscitem}[1]{\titem{iqdisc} \ind{options!iqdisc}This specifies +\newcommand{\iqdiscitem}[1]{\titem{iqdisc} \ind{options!iqdisc}This specifies the processing discipline for #1 IQ queries (see section~\ref{modiqdiscoption}).} \newcommand{\hostitem}[1]{ \titem{host} \ind{options!host} This option defines the Jabber ID of the @@ -159,8 +159,8 @@ ejabberd Development Team \newstyle{table[border="1"]}{border-collapse:collapse;margin-bottom:1em;} \newstyle{table[border="1"] td}{border:1px solid \#aaa;padding:2px} % Don't display
      before and after tables or images: -\newstyle{BLOCKQUOTE.table DIV.center DIV.center HR}{display:none;} -\newstyle{BLOCKQUOTE.figure DIV.center DIV.center HR}{display:none;} +\newstyle{BLOCKQUOTE.table DIV.center DIV.center HR}{display:none;} +\newstyle{BLOCKQUOTE.figure DIV.center DIV.center HR}{display:none;} %% Footnotes \begin{latexonly} @@ -208,8 +208,8 @@ ejabberd Development Team \makesection{install.binary}{Installing \ejabberd{} with Binary Installer} Probably the easiest way to install an \ejabberd{} instant messaging server -is using the binary installer published by ProcessOne. -The binary installers of released \ejabberd{} versions +is using the binary installer published by ProcessOne. +The binary installers of released \ejabberd{} versions are available in the ProcessOne \ejabberd{} downloads page: \ahrefurl{http://www.process-one.net/en/ejabberd/downloads} @@ -227,17 +227,17 @@ or automatically by the operating system at system boot time. To start and stop \ejabberd{} manually, use the desktop shortcuts created by the installer. -If the machine doesn't have a graphical system, use the scripts 'start' +If the machine doesn't have a graphical system, use the scripts 'start' and 'stop' in the 'bin' directory where \ejabberd{} is installed. The Windows installer also adds ejabberd as a system service, and a shortcut to a debug console for experienced administrators. -If you want ejabberd to be started automatically at boot time, +If you want ejabberd to be started automatically at boot time, go to the Windows service settings and set ejabberd to be automatically started. -Note that the Windows service is a feature still in development, +Note that the Windows service is a feature still in development, and for example it doesn't read the file ejabberdctl.cfg. -On a *nix system, if you want ejabberd to be started as daemon at boot time, +On a *nix system, if you want ejabberd to be started as daemon at boot time, copy \term{ejabberd.init} from the 'bin' directory to something like \term{/etc/init.d/ejabberd} (depending on your distribution) and call \term{/etc/inid.d/ejabberd start} to start it. @@ -263,9 +263,9 @@ and configurable options to fine tune the Erlang runtime system. \makesection{install.os}{Installing \ejabberd{} with Operating System specific packages} -Some Operating Systems provide a specific \ejabberd{} package adapted to +Some Operating Systems provide a specific \ejabberd{} package adapted to the system architecture and libraries. -It usually also checks dependencies +It usually also checks dependencies and performs basic configuration tasks like creating the initial administrator account. Some examples are Debian and Gentoo. Consult the resources provided by your Operating System for more information. @@ -282,7 +282,7 @@ The binaries are available for many different system architectures, so this is a alternative to the binary installer and Operating System's \ejabberd{} packages. You will have to create your own \ejabberd{} start -script depending of how you handle your CEAN installation. +script depending of how you handle your CEAN installation. The default \term{ejabberdctl} script is located into \ejabberd{}'s priv directory and can be used as an example. @@ -290,7 +290,7 @@ into \ejabberd{}'s priv directory and can be used as an example. \ind{install} The canonical form for distribution of \ejabberd{} stable releases is the source code package. -Compiling \ejabberd{} from source code is quite easy in *nix systems, +Compiling \ejabberd{} from source code is quite easy in *nix systems, as long as your system have all the dependencies. \makesubsection{installreq}{Requirements} @@ -337,12 +337,12 @@ To get the full list run the command: Some options that you may be interested in modifying: \begin{description} - \titem{--prefix=/} + \titem{--prefix=/} Specify the path prefix where the files will be copied when running the \term{make install} command. \titem{--enable-user[=USER]} - Allow this normal system user to execute the ejabberdctl script + Allow this normal system user to execute the ejabberdctl script (see section~\ref{ejabberdctl}), read the configuration files, read and write in the spool directory, @@ -352,20 +352,20 @@ Some options that you may be interested in modifying: This account doesn't need an explicit HOME directory, because \term{/var/lib/ejabberd/} will be used by default. - \titem{--enable-pam} + \titem{--enable-pam} Enable the PAM authentication method (see section \ref{pam}). \titem{--enable-odbc or --enable-mssql} Required if you want to use an external database. See section~\ref{database} for more information. - \titem{--enable-full-xml} + \titem{--enable-full-xml} Enable the use of XML based optimisations. - It will for example use CDATA to escape characters in the XMPP stream. + It will for example use CDATA to escape characters in the XMPP stream. Use this option only if you are sure your Jabber clients include a fully compliant XML parser. \titem{--disable-transient-supervisors} - Disable the use of Erlang/OTP supervision for transient processes. + Disable the use of Erlang/OTP supervision for transient processes. \end{description} @@ -456,8 +456,8 @@ gmake You need to have \term{GNU install}, but it isn't included in Solaris. It can be easily installed if your Solaris system -is set up for \footahref{http://www.blastwave.org/}{blastwave.org} -package repository. +is set up for \footahref{http://www.blastwave.org/}{blastwave.org} +package repository. Make sure \term{/opt/csw/bin} is in your \term{PATH} and run: \begin{verbatim} pkg-get -i fileutils @@ -519,8 +519,8 @@ We assume that we will try to put as much library as possible into \verb|C:\sdk\ \verb|C:\sdk\GnuWin32\bin| to the \verb|PATH| environment variable. \item Install OpenSSL in \verb|C:\sdk\OpenSSL| and add \verb|C:\sdk\OpenSSL\lib\VC| to your path or copy the binaries to your system directory. -\item Install ZLib in \verb|C:\sdk\gnuWin32|. Copy - \verb|C:\sdk\GnuWin32\bin\zlib1.dll| to your system directory. If you change your path it should already be set after libiconv install. +\item Install ZLib in \verb|C:\sdk\gnuWin32|. Copy + \verb|C:\sdk\GnuWin32\bin\zlib1.dll| to your system directory. If you change your path it should already be set after libiconv install. \item Make sure the you can access Erlang binaries from your path. For example: \verb|set PATH=%PATH%;"C:\sdk\erl5.5.5\bin"| \item Depending on how you end up actually installing the library you might need to check and tweak the paths in the file configure.erl. \item While in the directory \verb|ejabberd\src| run: @@ -542,20 +542,20 @@ werl -s ejabberd -name ejabberd You need a Jabber account and grant him administrative privileges to enter the \ejabberd{} Web Admin: \begin{enumerate} -\item Register a Jabber account on your \ejabberd{} server, for example \term{admin1@example.org}. +\item Register a Jabber account on your \ejabberd{} server, for example \term{admin1@example.org}. There are two ways to register a Jabber account: \begin{enumerate} \item Using \term{ejabberdctl}\ind{ejabberdctl} (see section~\ref{ejabberdctl}): \begin{verbatim} ejabberdctl register admin1 example.org FgT5bk3 -\end{verbatim} +\end{verbatim} \item Using a Jabber client and In-Band Registration (see section~\ref{modregister}). \end{enumerate} \item Edit the \ejabberd{} configuration file to give administration rights to the Jabber account you created: \begin{verbatim} {acl, admins, {user, "admin1", "example.org"}}. {access, configure, [{allow, admins}]}. -\end{verbatim} +\end{verbatim} You can grant administrative privileges to many Jabber accounts, and also to accounts in other Jabber servers. \item Restart \ejabberd{} to load the new configuration. @@ -569,7 +569,7 @@ ejabberdctl register admin1 example.org FgT5bk3 To upgrade an ejabberd installation to a new version, simply uninstall the old version, and then install the new one. -Of course, it is important that the configuration file +Of course, it is important that the configuration file and Mnesia database spool directory are not removed. \ejabberd{} automatically updates the Mnesia table definitions at startup when needed. @@ -586,9 +586,9 @@ indicates you need to also update those tables. The configuration file will be loaded the first time you start \ejabberd{}. The content from this file will be parsed and stored in the internal \ejabberd{} database. Subsequently the configuration will be loaded from the database and any commands in the -configuration file are appended to the entries in the database. +configuration file are appended to the entries in the database. -Note that \ejabberd{} never edits the configuration file. +Note that \ejabberd{} never edits the configuration file. So, the configuration changes done using the Web Admin are stored in the database, but are not reflected in the configuration file. If you want those changes to be use after \ejabberd{} restart, you can either @@ -675,7 +675,7 @@ Examples: {ldap_password, ""}]}. \end{verbatim} \end{itemize} - + To define specific ejabberd modules in a virtual host, you can define the global \term{modules} option with the common modules, and later add specific modules to certain virtual hosts. @@ -740,7 +740,7 @@ tuple with the following elements: \ind{modules!ejabberd\_c2s}\ind{modules!ejabberd\_s2s\_in}\ind{modules!ejabberd\_service}\ind{modules!ejabberd\_http}\ind{protocols!XEP-0114: Jabber Component Protocol} The available modules, their purpose and the options allowed by each one are: \begin{description} - \titem{\texttt{ejabberd\_c2s}} + \titem{\texttt{ejabberd\_c2s}} Handles c2s connections.\\ Options: \texttt{access}, \texttt{certfile}, \texttt{inet6}, \texttt{ip}, \texttt{max\_stanza\_size}, \texttt{shaper}, @@ -750,7 +750,7 @@ The available modules, their purpose and the options allowed by each one are: Handles incoming s2s connections.\\ Options: \texttt{inet6}, \texttt{ip}, \texttt{max\_stanza\_size} \titem{\texttt{ejabberd\_service}} - Interacts with an \footahref{http://www.ejabberd.im/tutorials-transports}{external component} + Interacts with an \footahref{http://www.ejabberd.im/tutorials-transports}{external component} (as defined in the Jabber Component Protocol (\xepref{0114}).\\ Options: \texttt{access}, \texttt{hosts}, \texttt{inet6}, \texttt{ip}, \texttt{shaper}, \texttt{service\_check\_from} @@ -791,7 +791,7 @@ This is a detailed description of each option allowed by the listening modules: \verb|http://server:port/http-bind/|. Be aware that support for HTTP Bind is also needed in the \Jabber{} client. Remark also that HTTP Bind can be interesting to host a web-based \Jabber{} client such as - \footahref{http://jwchat.sourceforge.net/}{JWChat} + \footahref{http://jwchat.sourceforge.net/}{JWChat} (check the tutorials to install JWChat with ejabberd and an \footahref{http://www.ejabberd.im/jwchat-localserver}{embedded local web server} or \footahref{http://www.ejabberd.im/jwchat-apache}{Apache}). @@ -807,7 +807,7 @@ This is a detailed description of each option allowed by the listening modules: \footahref{http://jwchat.sourceforge.net/}{JWChat}. \titem{inet6} \ind{options!inet6}\ind{IPv6}Set up the socket for IPv6 instead of IPv4. Note: this option is not required for S2S outgoing connections, - because when ejabberd attempts to establish a S2S outgoing connection + because when ejabberd attempts to establish a S2S outgoing connection it first tries IPv4, and if that fails it attempts with IPv6. \titem{\{ip, IPAddress\}} \ind{options!ip}This option specifies which network interface to listen for. For example \verb|{ip, {192, 168, 1, 1}}|. @@ -839,7 +839,7 @@ This is a detailed description of each option allowed by the listening modules: You can define a certificate file for a specific domain using the global option \option{domain\_certfile}. \titem{starttls\_required} \ind{options!starttls\_required}This option specifies that STARTTLS encryption is required on connections to the port. - No unencrypted connections will be allowed. + No unencrypted connections will be allowed. You should also set the \option{certfile} option. You can define a certificate file for a specific domain using the global option \option{domain\_certfile}. \titem{tls} \ind{options!tls}\ind{TLS}This option specifies that traffic on @@ -872,7 +872,7 @@ There are some additional global options: The default value is \term{allow}. \titem{\{\{s2s\_host, Host\}, allow|deny\}} Defines if incoming and outgoing s2s connections with a specific remote host are allowed or denied. - This allows to restrict ejabberd to only establish s2s connections + This allows to restrict ejabberd to only establish s2s connections with a small list of trusted servers, or to block some specific servers. \titem{\{s2s\_max\_retry\_delay, Seconds\}} \ind{options!s2s\_max\_retry\_delay} The maximum allowed delay for retry to connect after a failed connection attempt. @@ -883,7 +883,7 @@ For example, the following simple configuration defines: \begin{itemize} \item There are three domains. The default certificate file is \term{server.pem}. However, the c2s and s2s connections to the domain \term{example.com} use the file \term{example\_com.pem}. -\item Port 5222 listens for c2s connections with STARTTLS, +\item Port 5222 listens for c2s connections with STARTTLS, and also allows plain connections for old clients. \item Port 5223 listens for c2s connections with the old SSL. \item Port 5269 listens for s2s connections with STARTTLS. @@ -896,7 +896,7 @@ However, the c2s and s2s connections to the domain \term{example.com} use the fi {listen, [ {5222, ejabberd_c2s, [ - {access, c2s}, + {access, c2s}, {shaper, c2s_shaper}, starttls, {certfile, "/etc/ejabberd/server.pem"}, {max_stanza_size, 65536} @@ -936,7 +936,7 @@ In this example, the following configuration defines that: \item Port 5280 is serving the Web Admin and the HTTP Polling service. Note that it is also possible to serve them on different ports. The second example in section~\ref{webadmin} shows how exactly this can be done. -\item All users except for the administrators have a traffic of limit +\item All users except for the administrators have a traffic of limit 1,000\,Bytes/second \item \ind{transports!AIM}The \footahref{http://www.ejabberd.im/pyaimt}{AIM transport} @@ -1380,7 +1380,7 @@ following syntax: \end{verbatim} where \term{} stands for the maximum allowed incoming rate in bytes per second. -When a connection exceeds this limit, \ejabberd{} stops reading from the socket +When a connection exceeds this limit, \ejabberd{} stops reading from the socket until the average rate is again below the allowed maximum. Examples: @@ -1462,7 +1462,7 @@ The file is in a subdirectory from where the main configuration file is. {include_config_file, "./example.org/additional_not_listen.cfg", [{disallow, [listen]}]}. \end{verbatim} -In this example, \term{ejabberd.cfg} defines some ACL and Access rules, +In this example, \term{ejabberd.cfg} defines some ACL and Access rules, and later includes another file with additional rules: \begin{verbatim} {acl, admin, {user, "admin", "localhost"}}. @@ -1609,14 +1609,21 @@ Use this option to modify the value: {odbc_pool_size, 10}. \end{verbatim} -You can configure an interval to make a dummy SQL request -to keep alive the connections to the database. -The default value is 'undefined', so no keepalive requests are made. +You can configure an interval to make a dummy SQL request +to keep alive the connections to the database. +The default value is 'undefined', so no keepalive requests are made. Specify in seconds: for example 28800 means 8 hours. \begin{verbatim} {odbc_keepalive_interval, undefined}. \end{verbatim} +If the connection to the database fails, \ejabberd{} waits 30 seconds before retrying. +You can modify this interval with this option: +\begin{verbatim} +{odbc_start_interval, 30}. +\end{verbatim} + + \makesubsubsection{compilemysql}{Driver Compilation} \ind{MySQL!Driver Compilation} @@ -1706,9 +1713,9 @@ Use this option to modify the value: {odbc_pool_size, 10}. \end{verbatim} -You can configure an interval to make a dummy SQL request -to keep alive the connections to the database. -The default value is 'undefined', so no keepalive requests are made. +You can configure an interval to make a dummy SQL request +to keep alive the connections to the database. +The default value is 'undefined', so no keepalive requests are made. Specify in seconds: for example 28800 means 8 hours. \begin{verbatim} {odbc_keepalive_interval, undefined}. @@ -1766,9 +1773,9 @@ Use this option to modify the value: {odbc_pool_size, 10}. \end{verbatim} -You can configure an interval to make a dummy SQL request -to keep alive the connections to the database. -The default value is 'undefined', so no keepalive requests are made. +You can configure an interval to make a dummy SQL request +to keep alive the connections to the database. +The default value is 'undefined', so no keepalive requests are made. Specify in seconds: for example 28800 means 8 hours. \begin{verbatim} {odbc_keepalive_interval, undefined}. @@ -1783,7 +1790,7 @@ PostgreSQL. \begin{enumerate} \item First, install the Erlang pgsql library from - \footahref{http://www.ejabberd.im/ejabberd-modules/}{ejabberd-modules SVN repository}. + \footahref{http://www.ejabberd.im/ejabberd-modules/}{ejabberd-modules SVN repository}. Make sure the compiled files are in your Erlang path; you can put them for example in the same directory as your \ejabberd{} .beam files. @@ -1860,9 +1867,9 @@ Use this option to modify the value: {odbc_pool_size, 10}. \end{verbatim} -You can configure an interval to make a dummy SQL request -to keep alive the connections to the database. -The default value is 'undefined', so no keepalive requests are made. +You can configure an interval to make a dummy SQL request +to keep alive the connections to the database. +The default value is 'undefined', so no keepalive requests are made. Specify in seconds: for example 28800 means 8 hours. \begin{verbatim} {odbc_keepalive_interval, undefined}. @@ -1924,7 +1931,7 @@ server and use LDAP directory as vCard storage. Shared rosters are not supported yet. Note that \ejabberd{} treats LDAP as a read-only storage: -it is possible to consult data, but not possible to +it is possible to consult data, but not possible to create accounts, change password or edit vCard that is stored in LDAP. @@ -1935,10 +1942,10 @@ Parameters: \titem{ldap\_servers} \ind{options!ldap\_server}List of IP addresses or DNS names of your LDAP servers. This option is required. \titem{ldap\_port} \ind{options!ldap\_port}Port to connect to your LDAP server. - The initial default value is~389, so it is used when nothing is set into the -configuration file. -If you configure a value, it is stored in \ejabberd{}'s database. -Then, if you remove that value from the configuration file, + The initial default value is~389, so it is used when nothing is set into the +configuration file. +If you configure a value, it is stored in \ejabberd{}'s database. +Then, if you remove that value from the configuration file, the value previously stored in the database will be used instead of the default 389. \titem{ldap\_rootdn} \ind{options!ldap\_rootdn}Bind DN. The default value is~\term{""} which means `anonymous connection'. @@ -2181,38 +2188,38 @@ The following table lists all modules included in \ejabberd{}. \begin{table}[H] \centering \begin{tabular}{|l|l|l|} - \hline {\bf Module} & {\bf Feature} & {\bf Dependencies} \\ + \hline {\bf Module} & {\bf Feature} & {\bf Dependencies} \\ \hline - \hline \modadhoc{} & Ad-Hoc Commands (\xepref{0050}) & \\ - \hline \ahrefloc{modannounce}{\modannounce{}} & Manage announcements & recommends \modadhoc{} \\ - \hline \modcaps{} & Entity Capabilities (\xepref{0115}) & \\ - \hline \modconfigure{} & Server configuration using Ad-Hoc & \modadhoc{} \\ - \hline \ahrefloc{moddisco}{\moddisco{}} & Service Discovery (\xepref{0030}) & \\ - \hline \ahrefloc{modecho}{\modecho{}} & Echoes Jabber packets & \\ - \hline \ahrefloc{modirc}{\modirc{}} & IRC transport & \\ - \hline \ahrefloc{modlast}{\modlast{}} & Last Activity (\xepref{0012}) & \\ - \hline \ahrefloc{modlast}{\modlastodbc{}} & Last Activity (\xepref{0012}) & supported DB (*) \\ - \hline \ahrefloc{modmuc}{\modmuc{}} & Multi-User Chat (\xepref{0045}) & \\ - \hline \ahrefloc{modmuclog}{\modmuclog{}} & Multi-User Chat room logging & \modmuc{} \\ - \hline \ahrefloc{modoffline}{\modoffline{}} & Offline message storage (\xepref{0160}) & \\ - \hline \ahrefloc{modoffline}{\modofflineodbc{}} & Offline message storage (\xepref{0160}) & supported DB (*) \\ - \hline \ahrefloc{modprivacy}{\modprivacy{}} & Blocking Communication (XMPP IM) & \\ - \hline \ahrefloc{modprivacy}{\modprivacyodbc{}} & Blocking Communication (XMPP IM) & supported DB (*) \\ - \hline \ahrefloc{modprivate}{\modprivate{}} & Private XML Storage (\xepref{0049}) & \\ - \hline \ahrefloc{modprivate}{\modprivateodbc{}} & Private XML Storage (\xepref{0049}) & supported DB (*) \\ + \hline \modadhoc{} & Ad-Hoc Commands (\xepref{0050}) & \\ + \hline \ahrefloc{modannounce}{\modannounce{}} & Manage announcements & recommends \modadhoc{} \\ + \hline \modcaps{} & Entity Capabilities (\xepref{0115}) & \\ + \hline \modconfigure{} & Server configuration using Ad-Hoc & \modadhoc{} \\ + \hline \ahrefloc{moddisco}{\moddisco{}} & Service Discovery (\xepref{0030}) & \\ + \hline \ahrefloc{modecho}{\modecho{}} & Echoes Jabber packets & \\ + \hline \ahrefloc{modirc}{\modirc{}} & IRC transport & \\ + \hline \ahrefloc{modlast}{\modlast{}} & Last Activity (\xepref{0012}) & \\ + \hline \ahrefloc{modlast}{\modlastodbc{}} & Last Activity (\xepref{0012}) & supported DB (*) \\ + \hline \ahrefloc{modmuc}{\modmuc{}} & Multi-User Chat (\xepref{0045}) & \\ + \hline \ahrefloc{modmuclog}{\modmuclog{}} & Multi-User Chat room logging & \modmuc{} \\ + \hline \ahrefloc{modoffline}{\modoffline{}} & Offline message storage (\xepref{0160}) & \\ + \hline \ahrefloc{modoffline}{\modofflineodbc{}} & Offline message storage (\xepref{0160}) & supported DB (*) \\ + \hline \ahrefloc{modprivacy}{\modprivacy{}} & Blocking Communication (XMPP IM) & \\ + \hline \ahrefloc{modprivacy}{\modprivacyodbc{}} & Blocking Communication (XMPP IM) & supported DB (*) \\ + \hline \ahrefloc{modprivate}{\modprivate{}} & Private XML Storage (\xepref{0049}) & \\ + \hline \ahrefloc{modprivate}{\modprivateodbc{}} & Private XML Storage (\xepref{0049}) & supported DB (*) \\ \hline \ahrefloc{modproxy}{\modproxy{}} & SOCKS5 Bytestreams (\xepref{0065}) & \\ - \hline \ahrefloc{modpubsub}{\modpubsub{}} & Pub-Sub (\xepref{0060}), PEP (\xepref{0163}) & \modcaps{} \\ - \hline \ahrefloc{modregister}{\modregister{}} & In-Band Registration (\xepref{0077}) & \\ - \hline \ahrefloc{modroster}{\modroster{}} & Roster management (XMPP IM) & \\ - \hline \ahrefloc{modroster}{\modrosterodbc{}} & Roster management (XMPP IM) & supported DB (*) \\ - \hline \ahrefloc{modservicelog}{\modservicelog{}} & Copy user messages to logger service & \\ - \hline \ahrefloc{modsharedroster}{\modsharedroster{}} & Shared roster management & \modroster{} or \\ - & & \modrosterodbc\\ - \hline \ahrefloc{modstats}{\modstats{}} & Statistics Gathering (\xepref{0039}) & \\ - \hline \ahrefloc{modtime}{\modtime{}} & Entity Time (\xepref{0090}) & \\ - \hline \ahrefloc{modvcard}{\modvcard{}} & vcard-temp (\xepref{0054}) & \\ - \hline \ahrefloc{modvcardldap}{\modvcardldap{}} & vcard-temp (\xepref{0054}) & LDAP server \\ - \hline \ahrefloc{modvcard}{\modvcardodbc{}} & vcard-temp (\xepref{0054}) & supported DB (*) \\ + \hline \ahrefloc{modpubsub}{\modpubsub{}} & Pub-Sub (\xepref{0060}), PEP (\xepref{0163}) & \modcaps{} \\ + \hline \ahrefloc{modregister}{\modregister{}} & In-Band Registration (\xepref{0077}) & \\ + \hline \ahrefloc{modroster}{\modroster{}} & Roster management (XMPP IM) & \\ + \hline \ahrefloc{modroster}{\modrosterodbc{}} & Roster management (XMPP IM) & supported DB (*) \\ + \hline \ahrefloc{modservicelog}{\modservicelog{}} & Copy user messages to logger service & \\ + \hline \ahrefloc{modsharedroster}{\modsharedroster{}} & Shared roster management & \modroster{} or \\ + & & \modrosterodbc\\ + \hline \ahrefloc{modstats}{\modstats{}} & Statistics Gathering (\xepref{0039}) & \\ + \hline \ahrefloc{modtime}{\modtime{}} & Entity Time (\xepref{0090}) & \\ + \hline \ahrefloc{modvcard}{\modvcard{}} & vcard-temp (\xepref{0054}) & \\ + \hline \ahrefloc{modvcardldap}{\modvcardldap{}} & vcard-temp (\xepref{0054}) & LDAP server \\ + \hline \ahrefloc{modvcard}{\modvcardodbc{}} & vcard-temp (\xepref{0054}) & supported DB (*) \\ \hline \ahrefloc{modversion}{\modversion{}} & Software Version (\xepref{0092}) & \\ \hline \end{tabular} @@ -2303,7 +2310,7 @@ This option defines the Jabber ID of a service provided by an \ejabberd{} module The keyword "@HOST@" is replaced at start time with the real virtual host string. This example configures -the \ind{modules!\modecho{}}echo module to provide its echoing service +the \ind{modules!\modecho{}}echo module to provide its echoing service in the Jabber ID \jid{mirror.example.org}: \begin{verbatim} {modules, @@ -2329,7 +2336,7 @@ the "@HOST@" keyword must be used: \ind{modules!\modannounce{}}\ind{MOTD}\ind{message of the day}\ind{announcements} This module enables configured users to broadcast announcements and to set -the message of the day (MOTD). +the message of the day (MOTD). Configured users can perform these actions with a \Jabber{} client either using Ad-hoc commands or sending messages to specific JIDs. @@ -2587,7 +2594,7 @@ Some of the features of Multi-User Chat: The MUC service allows any Jabber ID to register a nickname, so nobody else can use that nickname in any room in the MUC service. -To register a nickname, open the Service Discovery in your +To register a nickname, open the Service Discovery in your Jabber client and register in the MUC service. This module supports clustering and load @@ -2665,7 +2672,7 @@ Module options: discarded. A good value for this option is 4 seconds. \titem{default\_room\_options} \ind{options!default\_room\_options} This module option allows to define the desired default room options. - Note that the creator of a room can modify the options of his room + Note that the creator of a room can modify the options of his room at any time using a Jabber client with MUC capability. The available room options and the default values are: \begin{description} @@ -2861,7 +2868,7 @@ Options: To prevent spam, the \term{spam\_prevention} option adds a special attribute to links that prevent their indexation by search engines. The default value is \term{true}, which mean that nofollow attributes will be added to user - submitted links. + submitted links. \titem{timezone}\ind{options!timezone} The time zone for the logs is configurable with this option. Allowed values are \term{local} and \term{universal}. With the first value, the local time, @@ -3078,7 +3085,7 @@ Options: pubsub plugin is always used. \titem{nodetree} To specify which nodetree to use. If not defined, the default pubsub nodetree is used. Nodetrees are default and virtual. Only one nodetree can be used - and is shared by all node plugins. + and is shared by all node plugins. %\titem{served\_hosts} \ind{options!served\_hosts} % This option allows to create additional pubsub virtual hosts in a single module instance. \end{description} @@ -3116,10 +3123,10 @@ Options: user name, registration for that user name is denied. (there are no restrictions by default). \titem{welcome\_message} \ind{options!welcomem}Set a welcome message that - is sent to each newly registered account. The first string is the subject, and + is sent to each newly registered account. The first string is the subject, and the second string is the message body. In the body you can set a newline with the characters: \verb|\n| -\titem{registration\_watchers} \ind{options!rwatchers}This option defines a +\titem{registration\_watchers} \ind{options!rwatchers}This option defines a list of JIDs which will be notified each time a new account is registered. \iqdiscitem{In-Band Registration (\ns{jabber:iq:register})} \end{description} @@ -3223,7 +3230,7 @@ Examples: ]}. \end{verbatim} \item To log all end user packets to the Bandersnatch service running on - \jid{bandersnatch.example.com} and the backup service on + \jid{bandersnatch.example.com} and the backup service on \jid{bandersnatch.example.org}: \begin{verbatim} {modules, @@ -3243,9 +3250,9 @@ This module enables you to create shared roster groups. This means that you can create groups of people that can see members from (other) groups in their rosters. The big advantages of this feature are that end users do not need to manually add all users to their rosters, and that they cannot permanently delete -users from the shared roster groups. +users from the shared roster groups. A shared roster group can have members from any Jabber server, -but the presence will only be available from and to members +but the presence will only be available from and to members of the same virtual host where the group is created. Shared roster groups can be edited \emph{only} via the Web Admin. Each group @@ -3467,7 +3474,7 @@ implemented in the \modvcardldap{} module. This module does not depend on the authentication method (see~\ref{ldapauth}). Note that \ejabberd{} treats LDAP as a read-only storage: -it is possible to consult data, but not possible to +it is possible to consult data, but not possible to create accounts, change password or edit vCard that is stored in LDAP. The \modvcardldap{} module has @@ -3571,7 +3578,7 @@ consists of the following \modvcardldap{}-specific options: %TODO: this examples still should be organised better Examples: \begin{itemize} -\item +\item Let's say \term{ldap.example.org} is the name of our LDAP server. We have users with their passwords in \term{"ou=Users,dc=example,dc=org"} directory. @@ -3689,11 +3696,11 @@ Options: \makesubsection{commands}{Commands} -The \term{ejabberdctl} command line administration script allows to start, stop and perform +The \term{ejabberdctl} command line administration script allows to start, stop and perform many other administrative tasks in a local or remote \ejabberd{} server. When \term{ejabberdctl} is executed without any parameter, -it displays the available options. If there isn't an \ejabberd{} server running, +it displays the available options. If there isn't an \ejabberd{} server running, the available parameters are: \begin{description} \titem{start} Start \ejabberd{} in background mode. This is the default method. @@ -3710,7 +3717,7 @@ The more interesting ones are: \titem{reopen-log} If you use a tool to rotate logs, you have to configure it so that this command is executed after each rotation. \titem {backup, restore, install-fallback, dump, load} You can use these - commands to create and restore backups. + commands to create and restore backups. %%More information about backuping can %% be found in section~\ref{backup}. \titem{import-file, import-dir} \ind{migration from other software} @@ -3741,70 +3748,70 @@ for example using: \term{echo \$?} \ejabberd{} is an Erlang/OTP application that runs inside an Erlang runtime system. This system is configured using environment variables and command line parameters. The \term{ejabberdctl} administration script uses many of those possibilities. -You can configure some of them with the file \term{ejabberdctl.cfg}, +You can configure some of them with the file \term{ejabberdctl.cfg}, which includes detailed description about them. -This section describes for reference purposes +This section describes for reference purposes all the environment variables and command line parameters. The environment variables: \begin{description} - \titem{EJABBERD\_CONFIG\_PATH} + \titem{EJABBERD\_CONFIG\_PATH} Path to the ejabberd configuration file. - \titem{EJABBERD\_MSGS\_PATH} + \titem{EJABBERD\_MSGS\_PATH} Path to the directory with translated strings. - \titem{EJABBERD\_LOG\_PATH} + \titem{EJABBERD\_LOG\_PATH} Path to the ejabberd service log file. - \titem{EJABBERD\_SO\_PATH} + \titem{EJABBERD\_SO\_PATH} Path to the directory with binary system libraries. - \titem{HOME} + \titem{HOME} Path to the directory that is considered \ejabberd{}'s home. This path is used to read the file \term{.erlang.cookie}. - \titem{ERL\_CRASH\_DUMP} + \titem{ERL\_CRASH\_DUMP} Path to the file where crash reports will be dumped. - \titem{ERL\_INETRC} + \titem{ERL\_INETRC} Indicates which IP name resolution to use. If using \term{-sname}, specify either this option or \term{-kernel inetrc filepath}. - \titem{ERL\_MAX\_PORTS} + \titem{ERL\_MAX\_PORTS} Maximum number of simultaneously open Erlang ports. - \titem{ERL\_MAX\_ETS\_TABLES} + \titem{ERL\_MAX\_ETS\_TABLES} Maximum number of ETS and Mnesia tables. \end{description} The command line parameters: \begin{description} - \titem{-sname ejabberd} + \titem{-sname ejabberd} The Erlang node will be identified using only the first part of the host name, i.\,e. other Erlang nodes outside this domain cannot contact this node. This is the preferable option in most cases. - \titem{-name ejabberd} + \titem{-name ejabberd} The Erlang node will be fully identified. This is only useful if you plan to setup an \ejabberd{} cluster with nodes in different networks. - \titem{-kernel inetrc "/etc/ejabberd/inetrc"} - Indicates which IP name resolution to use. + \titem{-kernel inetrc "/etc/ejabberd/inetrc"} + Indicates which IP name resolution to use. If using \term{-sname}, specify either this option or \term{ERL\_INETRC}. - \titem{-kernel inet\_dist\_listen\_min 4200 inet\_dist\_listen\_min 4210} + \titem{-kernel inet\_dist\_listen\_min 4200 inet\_dist\_listen\_min 4210} Define the first and last ports that \term{epmd} (section \ref{epmd}) can listen to. - \titem{-detached} - Starts the Erlang system detached from the system console. - Useful for running daemons and backgrounds processes. - \titem{-noinput} + \titem{-detached} + Starts the Erlang system detached from the system console. + Useful for running daemons and backgrounds processes. + \titem{-noinput} Ensures that the Erlang system never tries to read any input. - Useful for running daemons and backgrounds processes. - \titem{-pa /var/lib/ejabberd/ebin} + Useful for running daemons and backgrounds processes. + \titem{-pa /var/lib/ejabberd/ebin} Specify the directory where Erlang binary files (*.beam) are located. - \titem{-s ejabberd} + \titem{-s ejabberd} Tell Erlang runtime system to start the \ejabberd{} application. \titem{-mnesia dir "/var/lib/ejabberd/"} Specify the Mnesia database directory. \titem{-sasl sasl\_error\_logger \{file, "/var/log/ejabberd/sasl.log"\}} Path to the Erlang/OTP system log file. - \titem{+K [true|false]} + \titem{+K [true|false]} Kernel polling. - \titem{-smp [auto|enable|disable]} + \titem{-smp [auto|enable|disable]} SMP support. - \titem{+P 250000} + \titem{+P 250000} Maximum number of Erlang processes. - \titem{-remsh ejabberd@localhost} + \titem{-remsh ejabberd@localhost} Open an Erlang shell in a remote Erlang node. \end{description} Note that some characters need to be escaped when used in shell scripts, for instance \verb|"| and \verb|{}|. @@ -3818,7 +3825,7 @@ The \ejabberd{} Web Admin allows to administer most of \ejabberd{} using a web b This feature is enabled by default: a \term{ejabberd\_http} listener with the option \term{web\_admin} (see -section~\ref{listened}) is included in the listening ports. Then you can open +section~\ref{listened}) is included in the listening ports. Then you can open \verb|http://server:port/admin/| in your favourite web browser. You will be asked to enter the username (the \emph{full} \Jabber{} ID) and password of an \ejabberd{} user with administrator rights. After authentication @@ -3894,7 +3901,7 @@ an account with proper privileges. \makesection{changeerlangnodename}{Change Computer Hostname} -\ejabberd{} uses the distributed Mnesia database. +\ejabberd{} uses the distributed Mnesia database. Being distributed, Mnesia enforces consistency of its file, so it stores the name of the Erlang node in it (see section \ref{nodename}). The name of an Erlang node includes the hostname of the computer. @@ -3906,7 +3913,7 @@ So, if you want to change the computer hostname where \ejabberd{} is installed, you must follow these instructions: \begin{enumerate} \item In the old server, backup the Mnesia database using the Web Admin or \term{ejabberdctl}. - For example: + For example: \begin{verbatim} ejabberdctl backup /tmp/ejabberd-oldhost.backup \end{verbatim} @@ -3940,15 +3947,15 @@ You need to take the following TCP ports in mind when configuring your firewall: \makesection{epmd}{epmd} \footahref{http://www.erlang.org/doc/man/epmd.html}{epmd (Erlang Port Mapper Daemon)} -is a small name server included in Erlang/OTP -and used by Erlang programs when establishing distributed Erlang communications. -\ejabberd{} needs \term{epmd} to use \term{ejabberdctl} and also when clustering \ejabberd{} nodes. +is a small name server included in Erlang/OTP +and used by Erlang programs when establishing distributed Erlang communications. +\ejabberd{} needs \term{epmd} to use \term{ejabberdctl} and also when clustering \ejabberd{} nodes. This small program is automatically started by Erlang, and is never stopped. -If \ejabberd{} is stopped, and there aren't any other Erlang programs +If \ejabberd{} is stopped, and there aren't any other Erlang programs running in the system, you can safely stop \term{epmd} if you want. -\ejabberd{} runs inside an Erlang node. -To communicate with \ejabberd{}, the script \term{ejabberdctl} starts a new Erlang node +\ejabberd{} runs inside an Erlang node. +To communicate with \ejabberd{}, the script \term{ejabberdctl} starts a new Erlang node and connects to the Erlang node that holds \ejabberd{}. In order for this communication to work, \term{epmd} must be running and listening for name requests in the port 4369. @@ -3965,7 +3972,7 @@ Remember to block the port so Internet doesn't have access to it. Once an Erlang node solved the node name of another Erlang node using EPMD and port 4369, the nodes communicate directly. -The ports used in this case by default are random, +The ports used in this case by default are random, but can be configured in the file \term{ejabberdctl.cfg}. The Erlang command-line parameter used internally is, for example: \begin{verbatim} @@ -3975,12 +3982,12 @@ erl ... -kernel inet_dist_listen_min 4370 inet_dist_listen_max 4375 \makesection{cookie}{Erlang Cookie} -The Erlang cookie is a string with numbers and letters. +The Erlang cookie is a string with numbers and letters. An Erlang node reads the cookie at startup from the command-line parameter \term{-setcookie}. If not indicated, the cookie is read from the cookie file \term{\$HOME/.erlang.cookie}. If this file does not exist, it is created immediately with a random cookie. Two Erlang nodes communicate only if they have the same cookie. -Setting a cookie on the Erlang node allows you to structure your Erlang network +Setting a cookie on the Erlang node allows you to structure your Erlang network and define which nodes are allowed to connect to which. Thanks to Erlang cookies, you can prevent access to the Erlang node by mistake, @@ -3988,7 +3995,7 @@ for example when there are several Erlang nodes running different programs in th Setting a secret cookie is a simple method to difficult unauthorized access to your Erlang node. -However, the cookie system is not ultimately effective +However, the cookie system is not ultimately effective to prevent unauthorized access or intrusion to an Erlang node. The communication between Erlang nodes are not encrypted, so the cookie could be read sniffing the traffic on the network. @@ -3998,14 +4005,14 @@ The recommended way to secure the Erlang node is to block the port 4369. \makesection{nodename}{Erlang node name} An Erlang node may have a node name. -The name can be short (if indicated with the command-line parameter \term{-sname}) -or long (if indicated with the parameter \term{-name}). +The name can be short (if indicated with the command-line parameter \term{-sname}) +or long (if indicated with the parameter \term{-name}). Starting an Erlang node with -sname limits the communication between Erlang nodes to the LAN. -Using the option \term{-sname} instead of \term{-name} is a simple method +Using the option \term{-sname} instead of \term{-name} is a simple method to difficult unauthorized access to your Erlang node. However, it is not ultimately effective to prevent access to the Erlang node, -because it may be possible to fake the fact that you are on another network +because it may be possible to fake the fact that you are on another network using a modified version of Erlang \term{epmd}. The recommended way to secure the Erlang node is to block the port 4369. @@ -4194,7 +4201,7 @@ The default distribution algorithm try to deliver to a local instance of a compo If you need a different behaviour, you can change the load balancing behaviour with the option \option{domain\_balancing}. The syntax of the option is the following: \begin{verbatim} -{domain_balancing, "component.example.com", }. +{domain_balancing, "component.example.com", }. \end{verbatim} Several balancing criteria are available: @@ -4281,7 +4288,7 @@ With this Erlang shell, an experienced administrator can perform complex tasks. This shell gives complete control over the \ejabberd{} server, so it is important to use it with extremely care. -There are some simple and safe examples in the article +There are some simple and safe examples in the article \footahref{http://www.ejabberd.im/interconnect-erl-nodes}{Interconnecting Erlang Nodes} To exit the shell, close the window or press the keys: control+c control+c. @@ -4293,8 +4300,8 @@ To exit the shell, close the window or press the keys: control+c control+c. \ind{xml:lang}\ind{internationalization}\ind{localization}\ind{i18n}\ind{l10n} The source code of \ejabberd{} supports localization. -The translators can edit the -\footahref{http://www.gnu.org/software/gettext/}{gettext} .po files +The translators can edit the +\footahref{http://www.gnu.org/software/gettext/}{gettext} .po files using any capable program (KBabel, Lokalize, Poedit...) or a simple text editor. Then gettext @@ -4327,7 +4334,7 @@ The Web Admin also supports the \verb|Accept-Language| HTTP header. \begin{figure}[htbp] \centering \insimg{webadmmainru.png} - \caption{Web Admin showing a virtual host when the web browser provides the + \caption{Web Admin showing a virtual host when the web browser provides the HTTP header `Accept-Language: ru'} \label{fig:webadmmainru} \end{figure} @@ -4382,7 +4389,7 @@ Street, Fifth Floor, Boston, MA 02110-1301, USA. %\ind{glossary} %\begin{description} -%\titem{c2s} +%\titem{c2s} %\titem{s2s} %\titem{STARTTLS} %\titem{XEP} (\XMPP{} Extension Protocol) diff --git a/src/ejabberd_rdbms.erl b/src/ejabberd_rdbms.erl index 0eff6c3ca..fcbe16cbb 100644 --- a/src/ejabberd_rdbms.erl +++ b/src/ejabberd_rdbms.erl @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -52,14 +52,21 @@ start_hosts() -> %% Start the ODBC module on the given host start_odbc(Host) -> + Supervisor_name = gen_mod:get_module_proc(Host, ejabberd_odbc_sup), ChildSpec = - {gen_mod:get_module_proc(Host, ejabberd_odbc_sup), + {Supervisor_name, {ejabberd_odbc_sup, start_link, [Host]}, - temporary, + transient, infinity, supervisor, [ejabberd_odbc_sup]}, - supervisor:start_child(ejabberd_sup, ChildSpec). + case supervisor:start_child(ejabberd_sup, ChildSpec) of + {ok, _PID} -> + ok; + _Error -> + ?ERROR_MSG("Start of supervisor ~p failed:~n~p~nRetrying...~n", [Supervisor_name, _Error]), + start_odbc(Host) + end. %% Returns true if we have configured odbc_server for the given host needs_odbc(Host) -> diff --git a/src/ejabberd_zlib/Makefile.win32 b/src/ejabberd_zlib/Makefile.win32 index bd9c9d561..c13383fa8 100644 --- a/src/ejabberd_zlib/Makefile.win32 +++ b/src/ejabberd_zlib/Makefile.win32 @@ -4,8 +4,7 @@ include ..\Makefile.inc EFLAGS = -I .. -pz .. OUTDIR = .. -SOURCES = $(wildcard *.erl) -BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam)) +BEAMS = ..\ejabberd_zlib.beam SOURCE = ejabberd_zlib_drv.c OBJECT = ejabberd_zlib_drv.o diff --git a/src/eldap/Makefile.win32 b/src/eldap/Makefile.win32 index b5bdbcf14..9733055f9 100644 --- a/src/eldap/Makefile.win32 +++ b/src/eldap/Makefile.win32 @@ -4,8 +4,7 @@ include ..\Makefile.inc EFLAGS = -I .. -pz .. OUTDIR = .. -SOURCES = $(wildcard *.erl) -BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam)) +BEAMS = ..\eldap.beam ..\eldap_filter.beam ..\eldap_pool.beam ..\eldap_utils.beam ALL : $(BEAMS) diff --git a/src/mod_configure.erl b/src/mod_configure.erl index b1cb0cced..47c6e1336 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -1240,7 +1240,7 @@ get_form(Host, ?NS_ADMINL("get-registered-users-num"), Lang) -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "jid-single"}, + [#xmlattr{name = 'type', value = "text-single"}, #xmlattr{name = 'label', value = ?T(Lang, "Number of registered users")}, #xmlattr{name = 'var', value = "registeredusersnum"}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Num)}]}] @@ -1252,7 +1252,7 @@ get_form(Host, ?NS_ADMINL("get-online-users-num"), Lang) -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "jid-single"}, + [#xmlattr{name = 'type', value = "text-single"}, #xmlattr{name = 'label', value = ?T(Lang, "Number of online users")}, #xmlattr{name = 'var', value = "onlineusersnum"}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Num)}]}] diff --git a/src/mod_irc/Makefile.win32 b/src/mod_irc/Makefile.win32 index 28fc15e9c..9c22f43f1 100644 --- a/src/mod_irc/Makefile.win32 +++ b/src/mod_irc/Makefile.win32 @@ -4,8 +4,7 @@ include ..\Makefile.inc EFLAGS = -I .. -pz .. OUTDIR = .. -SOURCES = $(wildcard *.erl) -BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam)) +BEAMS = ..\iconv.beam ..\mod_irc.beam ..\mod_irc_connection.beam SOURCE = iconv_erl.c OBJECT = iconv_erl.o diff --git a/src/mod_muc/Makefile.win32 b/src/mod_muc/Makefile.win32 index e53f9b7f5..5107b1069 100644 --- a/src/mod_muc/Makefile.win32 +++ b/src/mod_muc/Makefile.win32 @@ -4,8 +4,7 @@ include ..\Makefile.inc EFLAGS = -I .. -pz .. OUTDIR = .. -SOURCES = $(wildcard *.erl) -BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam)) +BEAMS = ..\mod_muc.beam ..\mod_muc_log.beam ..\mod_muc_room.beam ALL : $(BEAMS) diff --git a/src/mod_proxy65/Makefile.win32 b/src/mod_proxy65/Makefile.win32 index 718dd0c70..7683097d3 100644 --- a/src/mod_proxy65/Makefile.win32 +++ b/src/mod_proxy65/Makefile.win32 @@ -4,8 +4,7 @@ include ..\Makefile.inc EFLAGS = -I .. -pz .. OUTDIR = .. -SOURCES = $(wildcard *.erl) -BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam)) +BEAMS = ..\mod_proxy65.beam ..\mod_proxy65_lib.beam ..\mod_proxy65_service.beam ..\mod_proxy65_sm.beam ..\mod_proxy65_stream.beam ALL : $(BEAMS) @@ -19,7 +18,7 @@ $(OUTDIR)\mod_proxy65_service.beam : mod_proxy65_service.erl erlc -W $(EFLAGS) -o $(OUTDIR) mod_proxy65_service.erl $(OUTDIR)\mod_proxy65_sm.beam : mod_proxy65_sm.erl - erlc -W $(EFLAGS) -o $(OUTDIR) mod_mod_proxy65_sm.erl + erlc -W $(EFLAGS) -o $(OUTDIR) mod_proxy65_sm.erl $(OUTDIR)\mod_proxy65_stream.beam : mod_proxy65_stream.erl erlc -W $(EFLAGS) -o $(OUTDIR) mod_proxy65_stream.erl diff --git a/src/mod_pubsub/Makefile.win32 b/src/mod_pubsub/Makefile.win32 index f68375ccd..f981329c9 100644 --- a/src/mod_pubsub/Makefile.win32 +++ b/src/mod_pubsub/Makefile.win32 @@ -4,8 +4,7 @@ include ..\Makefile.inc EFLAGS = -I .. -pz .. OUTDIR = .. -SOURCES = $(wildcard *.erl) -BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam)) +BEAMS = ..\gen_pubsub_node.beam ..\gen_pubsub_nodetree.beam ..\mod_pubsub.beam ..\nodetree_default.beam ..\nodetree_virtual.beam ..\node_buddy.beam ..\node_club.beam ..\node_default.beam ..\node_dispatch.beam ..\node_pep.beam ..\node_private.beam ..\node_public.beam ALL : $(BEAMS) @@ -27,9 +26,23 @@ $(OUTDIR)\nodetree_default.beam : nodetree_default.erl $(OUTDIR)\nodetree_virtual.beam : nodetree_virtual.erl erlc -W $(EFLAGS) -o $(OUTDIR) nodetree_virtual.erl +$(OUTDIR)\node_buddy.beam : node_buddy.erl + erlc -W $(EFLAGS) -o $(OUTDIR) node_buddy.erl + +$(OUTDIR)\node_club.beam : node_club.erl + erlc -W $(EFLAGS) -o $(OUTDIR) node_club.erl + $(OUTDIR)\node_default.beam : node_default.erl erlc -W $(EFLAGS) -o $(OUTDIR) node_default.erl +$(OUTDIR)\node_dispatch.beam : node_dispatch.erl + erlc -W $(EFLAGS) -o $(OUTDIR) node_dispatch.erl + $(OUTDIR)\node_pep.beam : node_pep.erl erlc -W $(EFLAGS) -o $(OUTDIR) node_pep.erl +$(OUTDIR)\node_private.beam : node_private.erl + erlc -W $(EFLAGS) -o $(OUTDIR) node_private.erl + +$(OUTDIR)\node_public.beam : node_public.erl + erlc -W $(EFLAGS) -o $(OUTDIR) node_public.erl diff --git a/src/mod_pubsub/gen_pubsub_node.erl b/src/mod_pubsub/gen_pubsub_node.erl index a193a51cc..f3fc16ff8 100644 --- a/src/mod_pubsub/gen_pubsub_node.erl +++ b/src/mod_pubsub/gen_pubsub_node.erl @@ -63,7 +63,7 @@ behaviour_info(callbacks) -> {get_state, 3}, {set_state, 1}, {get_items, 7}, - {get_items, 2}, + {get_items, 3}, {get_item, 8}, {get_item, 3}, {set_item, 1}, diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index dd86b91bb..a7084fad6 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -77,7 +77,8 @@ delete_item/4, get_configure/4, set_configure/5, - get_items/2, + get_items/3, + tree_action/3, node_action/3, node_action/4 ]). @@ -114,6 +115,7 @@ -record(state, {server_host, host, access, + pep_mapping = [], nodetree = ?STDTREE, plugins = [?STDNODE]}). @@ -175,7 +177,7 @@ init([ServerHost, Opts]) -> {?NS_PUBSUB, ejabberd_sm, iq_sm}, {?NS_PUBSUB_OWNER, ejabberd_sm, iq_sm}]), ejabberd_router:register_route(Host), - {Plugins, NodeTree} = init_plugins(Host, ServerHost, Opts), + {Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts), update_database(Host), ets:new(gen_mod:get_module_proc(Host, pubsub_state), [set, named_table]), ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {nodetree, NodeTree}), @@ -183,10 +185,12 @@ init([ServerHost, Opts]) -> ets:new(gen_mod:get_module_proc(ServerHost, pubsub_state), [set, named_table]), ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {nodetree, NodeTree}), ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {plugins, Plugins}), + ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {pep_mapping, PepMapping}), init_nodes(Host, ServerHost), {ok, #state{host = Host, server_host = ServerHost, access = Access, + pep_mapping = PepMapping, nodetree = NodeTree, plugins = Plugins}}. @@ -209,12 +213,14 @@ init_plugins(Host, ServerHost, Opts) -> ?DEBUG("** tree plugin is ~p",[TreePlugin]), TreePlugin:init(Host, ServerHost, Opts), Plugins = lists:usort(gen_mod:get_opt(plugins, Opts, []) ++ [?STDNODE]), + PepMapping = lists:usort(gen_mod:get_opt(pep_mapping, Opts, [])), + ?DEBUG("** PEP Mapping : ~p~n",[PepMapping]), lists:foreach(fun(Name) -> ?DEBUG("** init ~s plugin",[Name]), Plugin = list_to_atom(?PLUGIN_PREFIX ++ Name), Plugin:init(Host, ServerHost, Opts) end, Plugins), - {Plugins, TreePlugin}. + {Plugins, TreePlugin, PepMapping}. terminate_plugins(Host, ServerHost, Plugins, TreePlugin) -> lists:foreach(fun(Name) -> @@ -371,11 +377,11 @@ disco_sm_items(Acc, _From, To, [], _Lang) -> {result, NodeItems ++ Items} end; -disco_sm_items(Acc, _From, To, Node, _Lang) -> +disco_sm_items(Acc, From, To, Node, _Lang) -> %% TODO, use iq_disco_items(Host, Node, From) Host = To#jid.lserver, LJID = jlib:jid_tolower(jlib:jid_remove_resource(To)), - case get_items(Host, Node) of + case get_items(Host, Node, From) of [] -> Acc; AllItems -> @@ -430,6 +436,8 @@ handle_call(server_host, _From, State) -> {reply, State#state.server_host, State}; handle_call(plugins, _From, State) -> {reply, State#state.plugins, State}; +handle_call(pep_mapping, _From, State) -> + {reply, State#state.pep_mapping, State}; handle_call(nodetree, _From, State) -> {reply, State#state.nodetree, State}; handle_call(stop, _From, State) -> @@ -717,7 +725,7 @@ node_disco_info(Host, Node, From, Identity, Features) -> [] -> ["leaf"]; %% No sub-nodes: it's a leaf node _ -> - case node_call(Type, get_items, [Host, Node]) of + case node_call(Type, get_items, [Host, Node, From]) of {result, []} -> ["collection"]; {result, _} -> ["leaf", "collection"]; _ -> [] @@ -782,7 +790,7 @@ iq_disco_items(Host, Item, From) -> %% TODO That is, remove name attribute Action = fun(#pubsub_node{type = Type}) -> - NodeItems = case node_call(Type, get_items, [Host, Node]) of + NodeItems = case node_call(Type, get_items, [Host, Node, From]) of {result, I} -> I; _ -> [] end, @@ -1183,10 +1191,7 @@ create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) -> {error, extended_error(?ERR_NOT_ACCEPTABLE, "nodeid-required")} end; create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> - Type = case Host of - {_User, _Server, _Resource} -> ?PEPNODE; - _ -> GivenType - end, + Type = select_type(ServerHost, Host, Node, GivenType), Parent = lists:sublist(Node, length(Node) - 1), %% TODO, check/set node_type = Type ParseOptions = case xml:remove_cdata(Configuration) of @@ -1488,12 +1493,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> %% handles auto-create feature %% for automatic node creation. we'll take the default node type: %% first listed into the plugins configuration option, or pep - Type = case Host of - {_User, _Server, _Resource} -> - ?PEPNODE; - _ -> - hd(plugins(ServerHost)) - end, + Type = select_type(ServerHost, Host, Node), case lists:member("auto-create", features(Type)) of true -> case create_node(Host, ServerHost, Node, Publisher, Type) of @@ -1712,8 +1712,8 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> end end. -get_items(Host, Node) -> - case node_action(Host, Node, get_items, [Host, Node]) of +get_items(Host, Node, From) -> + case node_action(Host, Node, get_items, [Host, Node, From]) of {result, Items} -> Items; _ -> [] end. @@ -1723,15 +1723,15 @@ get_items(Host, Node) -> %% Node = pubsubNode() %% LJID = {U, S, []} %% @doc

      Resend the items of a node to the user.

      -send_all_items(Host, Node, LJID) -> - send_items(Host, Node, LJID, all). +%send_all_items(Host, Node, LJID) -> +% send_items(Host, Node, LJID, all). send_last_item(Host, Node, LJID) -> send_items(Host, Node, LJID, last). %% TODO use cache-last-item feature send_items(Host, Node, LJID, Number) -> - ToSend = case get_items(Host, Node) of + ToSend = case get_items(Host, Node, LJID) of [] -> []; Items -> @@ -2411,11 +2411,8 @@ get_configure(Host, Node, From, Lang) -> end, transaction(Host, Node, Action, sync_dirty). -get_default(Host, _Node, _From, Lang) -> - Type = case Host of - {_, _, _} -> ?PEPNODE; - _ -> hd(plugins(Host)) - end, +get_default(Host, Node, _From, Lang) -> + Type=select_type(Host, Host, Node), Options = node_options(Type), {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB_OWNER}], [{xmlelement, "default", [], @@ -2663,6 +2660,19 @@ plugins(Host) -> [{plugins, PL}] -> PL; _ -> [?STDNODE] end. +select_type(ServerHost, Host, Node, Type)-> + ?DEBUG("SELECT_TYPE : ~p~n", [Node]), + case Host of + {_User, _Server, _Resource} -> + case ets:lookup(gen_mod:get_module_proc(ServerHost, pubsub_state), pep_mapping) of + [{pep_mapping, PM}] -> ?DEBUG("SELECT_TYPE : ~p~n", [PM]), proplists:get_value(Node, PM,?PEPNODE); + R -> ?DEBUG("SELECT_TYPE why ?: ~p~n", [R]), ?PEPNODE + end; + _ -> + Type + end. +select_type(ServerHost, Host, Node) -> + select_type(ServerHost, Host, Node,hd(plugins(ServerHost))). features() -> [ @@ -2811,3 +2821,4 @@ uniqid() -> get_item_name(Host, Node, Id) -> {result, Name} = node_action(Host, Node, get_item_name, [Host, Node, Id]), Name. + diff --git a/src/mod_pubsub/node.template b/src/mod_pubsub/node.template index 9c2344ae1..b98322d0d 100644 --- a/src/mod_pubsub/node.template +++ b/src/mod_pubsub/node.template @@ -62,7 +62,7 @@ get_state/3, set_state/1, get_items/7, - get_items/2, + get_items/3, get_item/8, get_item/3, set_item/1 @@ -168,8 +168,8 @@ get_state(Host, Node, JID) -> set_state(State) -> node_default:set_state(State). -get_items(Host, Node) -> - node_default:get_items(Host, Node). +get_items(Host, Node, From) -> + node_default:get_items(Host, Node, From). get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl index 8bca962d3..6cdd6118b 100644 --- a/src/mod_pubsub/node_buddy.erl +++ b/src/mod_pubsub/node_buddy.erl @@ -63,7 +63,7 @@ get_state/3, set_state/1, get_items/7, - get_items/2, + get_items/3, get_item/8, get_item/3, set_item/1, @@ -171,8 +171,8 @@ get_state(Host, Node, JID) -> set_state(State) -> node_default:set_state(State). -get_items(Host, Node) -> - node_default:get_items(Host, Node). +get_items(Host, Node, From) -> + node_default:get_items(Host, Node, From). get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl index 978f6f39d..ae8ab9cf1 100644 --- a/src/mod_pubsub/node_club.erl +++ b/src/mod_pubsub/node_club.erl @@ -63,7 +63,7 @@ get_state/3, set_state/1, get_items/7, - get_items/2, + get_items/3, get_item/8, get_item/3, set_item/1, @@ -170,8 +170,8 @@ get_state(Host, Node, JID) -> set_state(State) -> node_default:set_state(State). -get_items(Host, Node) -> - node_default:get_items(Host, Node). +get_items(Host, Node, From) -> + node_default:get_items(Host, Node, From). get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index ddda469c6..9b30269e0 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -70,7 +70,7 @@ get_state/3, set_state/1, get_items/7, - get_items/2, + get_items/3, get_item/8, get_item/3, set_item/1, @@ -705,9 +705,9 @@ set_state(_) -> %% relational database), or they can even decide not to persist any items.

      %%

      If a PubSub plugin wants to delegate the item storage to the default node, %% they can implement this function like this: -%% ```get_items(Host, Node) -> -%% node_default:get_items(Host, Node).'''

      -get_items(Host, Node) -> +%% ```get_items(Host, Node, From) -> +%% node_default:get_items(Host, Node, From).'''

      +get_items(Host, Node, _From) -> Items = mnesia:match_object( #pubsub_item{itemid = {'_', {Host, Node}}, _ = '_'}), {result, Items}. @@ -747,7 +747,7 @@ get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubI %% % Payment is required for a subscription %% {error, ?ERR_PAYMENT_REQUIRED}; true -> - get_items(Host, Node) + get_items(Host, Node, JID) end. %% @spec (Host, Node, ItemId) -> [Item] | [] diff --git a/src/mod_pubsub/node_dispatch.erl b/src/mod_pubsub/node_dispatch.erl index 0d9e1dcd9..98a396cbf 100644 --- a/src/mod_pubsub/node_dispatch.erl +++ b/src/mod_pubsub/node_dispatch.erl @@ -61,7 +61,7 @@ get_state/3, set_state/1, get_items/7, - get_items/2, + get_items/3, get_item/8, get_item/3, set_item/1, @@ -173,8 +173,8 @@ get_state(Host, Node, JID) -> set_state(State) -> node_default:set_state(State). -get_items(Host, Node) -> - node_default:get_items(Host, Node). +get_items(Host, Node, From) -> + node_default:get_items(Host, Node, From). get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). diff --git a/src/mod_pubsub/node_mb.erl b/src/mod_pubsub/node_mb.erl new file mode 100644 index 000000000..f2498071c --- /dev/null +++ b/src/mod_pubsub/node_mb.erl @@ -0,0 +1,197 @@ +%%% ==================================================================== +%%% ``The contents of this file are subject to the Erlang Public License, +%%% Version 1.1, (the "License"); you may not use this file except in +%%% compliance with the License. You should have received a copy of the +%%% Erlang Public License along with this software. If not, it can be +%%% retrieved via the world wide web at http://www.erlang.org/. +%%% +%%% Software distributed under the License is distributed on an "AS IS" +%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%%% the License for the specific language governing rights and limitations +%%% under the License. +%%% +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% All Rights Reserved.'' +%%% This software is copyright 2006-2008, ProcessOne. +%%% +%%% +%%% @copyright 2006-2008 ProcessOne +%%% @author Eric Cestari +%%% @version {@vsn}, {@date} {@time} +%%% @end +%%% ==================================================================== + + +%%% @doc The module {@module} is the pep microblog PubSub plugin. +%%%

      To be used, mod_pubsub must be configured : +%%% {mod_pubsub, [ % requires mod_caps +%%% {access_createnode, pubsub_createnode}, +%%% {plugins, ["default", "pep","mb"]}, +%%% {pep_mapping, [{"urn:xmpp:microblog", "mb"}]} +%%% ]}, +%%%

      PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.

      + +-module(node_mb). +-author('eric@ohmforce.com'). + +-include("ejabberd.hrl"). +-include("pubsub.hrl"). +-include("jlib.hrl"). + +-behaviour(gen_pubsub_node). + +%% API definition +-export([init/3, terminate/2, + options/0, features/0, + create_node_permission/6, + create_node/3, + delete_node/2, + purge_node/3, + subscribe_node/8, + unsubscribe_node/5, + publish_item/7, + delete_item/4, + remove_extra_items/4, + get_entity_affiliations/2, + get_node_affiliations/2, + get_affiliation/3, + set_affiliation/4, + get_entity_subscriptions/2, + get_node_subscriptions/2, + get_subscription/3, + set_subscription/4, + get_states/2, + get_state/3, + set_state/1, + get_items/7, + get_items/3, + get_item/8, + get_item/3, + set_item/1, + get_item_name/3 + ]). + +init(Host, ServerHost, Opts) -> + node_pep:init(Host, ServerHost, Opts). + +terminate(Host, ServerHost) -> + node_pep:terminate(Host, ServerHost), + ok. + +options() -> + [{node_type, pep}, + {deliver_payloads, true}, + {notify_config, false}, + {notify_delete, false}, + {notify_retract, false}, + {persist_items, true}, + {max_items, ?MAXITEMS}, + {subscribe, true}, + {access_model, presence}, + {roster_groups_allowed, []}, + {publish_model, publishers}, + {max_payload_size, ?MAX_PAYLOAD_SIZE}, + {send_last_published_item, on_sub_and_presence}, + {deliver_notifications, true}, + {presence_based_delivery, true}]. + +features() -> + ["create-nodes", %* + "auto-create", %* + "auto-subscribe", %* + "delete-nodes", %* + "filtered-notifications", %* + "modify-affiliations", + "outcast-affiliation", + "persistent-items", + "publish", %* + "purge-nodes", + "retract-items", + "retrieve-affiliations", + "retrieve-items", %* + "retrieve-subscriptions", + "subscribe" %* + ]. + +create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> + node_pep:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). + +create_node(Host, Node, Owner) -> + node_pep:create_node(Host, Node, Owner). + +delete_node(Host, Removed) -> + node_pep:delete_node(Host, Removed). + +subscribe_node(Host, Node, Sender, Subscriber, AccessModel, + SendLast, PresenceSubscription, RosterGroup) -> + node_pep:subscribe_node( + Host, Node, Sender, Subscriber, AccessModel, SendLast, + PresenceSubscription, RosterGroup). + +unsubscribe_node(Host, Node, Sender, Subscriber, SubID) -> + node_pep:unsubscribe_node(Host, Node, Sender, Subscriber, SubID). + +publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) -> + node_pep:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload). + +remove_extra_items(Host, Node, MaxItems, ItemIds) -> + node_pep:remove_extra_items(Host, Node, MaxItems, ItemIds). + +delete_item(Host, Node, JID, ItemId) -> + node_pep:delete_item(Host, Node, JID, ItemId). + +purge_node(Host, Node, Owner) -> + node_pep:purge_node(Host, Node, Owner). + +get_entity_affiliations(Host, Owner) -> + node_pep:get_entity_affiliations(Host, Owner). + +get_node_affiliations(Host, Node) -> + node_pep:get_node_affiliations(Host, Node). + +get_affiliation(Host, Node, Owner) -> + node_pep:get_affiliation(Host, Node, Owner). + +set_affiliation(Host, Node, Owner, Affiliation) -> + node_pep:set_affiliation(Host, Node, Owner, Affiliation). + +get_entity_subscriptions(Host,Owner) -> + node_pep:get_entity_subscriptions(Host, Owner). + +get_node_subscriptions(Host, Node) -> + node_pep:get_node_subscriptions(Host, Node). + +get_subscription(Host,Node,Owner) -> + node_pep:get_subscription(Host,Node,Owner). + +set_subscription(Host, Node, Owner, Subscription) -> + node_pep:set_subscription(Host, Node, Owner, Subscription). + +get_states(Host, Node) -> + node_pep:get_states(Host, Node). + +get_state(Host, Node, JID) -> + node_pep:get_state(Host, Node, JID). + +set_state(State) -> + node_pep:set_state(State). + +get_items(Host, Node, From) -> + node_pep:get_items(Host, Node, From). + +get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_pep:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + +get_item(Host, Node, ItemId) -> + node_pep:get_item(Host, Node, ItemId). + +get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_pep:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + +set_item(Item) -> + node_pep:set_item(Item). + +get_item_name(Host, Node, Id) -> + node_pep:get_item_name(Host, Node, Id). + diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index ddbf13b4b..6d2d2709e 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -59,7 +59,7 @@ get_state/3, set_state/1, get_items/7, - get_items/2, + get_items/3, get_item/8, get_item/3, set_item/1, @@ -123,7 +123,8 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> {User, Server, _} -> true; _ -> false end; - _ -> + E -> + ?DEBUG("Create not allowed : ~p~n", [E]), false end end, @@ -215,8 +216,8 @@ get_state(Host, Node, JID) -> set_state(State) -> node_default:set_state(State). -get_items(Host, Node) -> - node_default:get_items(Host, Node). +get_items(Host, Node, From) -> + node_default:get_items(Host, Node, From). get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl index 08d6abd85..5d87ec181 100644 --- a/src/mod_pubsub/node_private.erl +++ b/src/mod_pubsub/node_private.erl @@ -63,7 +63,7 @@ get_state/3, set_state/1, get_items/7, - get_items/2, + get_items/3, get_item/8, get_item/3, set_item/1, @@ -173,8 +173,8 @@ get_state(Host, Node, JID) -> set_state(State) -> node_default:set_state(State). -get_items(Host, Node) -> - node_default:get_items(Host, Node). +get_items(Host, Node, From) -> + node_default:get_items(Host, Node, From). get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl index 08559e423..7fda56e22 100644 --- a/src/mod_pubsub/node_public.erl +++ b/src/mod_pubsub/node_public.erl @@ -63,7 +63,7 @@ get_state/3, set_state/1, get_items/7, - get_items/2, + get_items/3, get_item/8, get_item/3, set_item/1, @@ -170,8 +170,8 @@ get_state(Host, Node, JID) -> set_state(State) -> node_default:set_state(State). -get_items(Host, Node) -> - node_default:get_items(Host, Node). +get_items(Host, Node, From) -> + node_default:get_items(Host, Node, From). get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). diff --git a/src/mod_pubsub/node_zoo.erl b/src/mod_pubsub/node_zoo.erl index a0d8afb09..12a69c58f 100644 --- a/src/mod_pubsub/node_zoo.erl +++ b/src/mod_pubsub/node_zoo.erl @@ -54,7 +54,7 @@ get_state/3, set_state/1, get_items/7, - get_items/2, + get_items/3, get_item/8, get_item/3, set_item/1, @@ -163,8 +163,8 @@ get_state(Host, Node, JID) -> set_state(State) -> node_default:set_state(State). -get_items(Host, Node) -> - node_default:get_items(Host, Node). +get_items(Host, Node, From) -> + node_default:get_items(Host, Node, From). get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 88d0b8667..8f329f7ab 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -638,7 +638,7 @@ set_items(User, Server, #xmlel{children = Els}) -> LServer = exmpp_stringprep:nameprep(Server), catch odbc_queries:sql_transaction( LServer, - lists:map(fun(El) -> + lists:flatmap(fun(El) -> process_item_set_t(LUser, LServer, El) end, Els)) catch @@ -877,7 +877,7 @@ groups_to_string(#roster{us = {User, _Server}, %% Empty groups do not need to be converted to string to be inserted in %% the database lists:foldl(fun([], Acc) -> Acc; - (Group, Acc) -> + (Group, Acc) -> String = ["'", Username, "'," "'", SJID, "'," "'", ejabberd_odbc:escape(binary_to_list(Group)), "'"], @@ -1060,4 +1060,3 @@ us_to_list({User, Server}) -> webadmin_user(Acc, _User, _Server, Lang) -> Acc ++ [?XE("h3", [?ACT("roster/", "Roster")])]. - diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 8b436f137..69ff2e395 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -161,6 +161,7 @@ get_user_roster(Items, US) -> process_item(RosterItem, Host) -> USFrom = {UserFrom, ServerFrom} = RosterItem#roster.us, {UserTo, ServerTo, ResourceTo} = RosterItem#roster.jid, + NameTo = RosterItem#roster.name, USTo = {UserTo, ServerTo}, DisplayedGroups = get_user_displayed_groups(USFrom), CommonGroups = lists:filter(fun(Group) -> @@ -188,24 +189,24 @@ process_item(RosterItem, Host) -> PersonalGroups -> %% Store roster items in From and To rosters set_new_rosteritems(UserFrom, ServerFrom, - UserTo, ServerTo, ResourceTo, + UserTo, ServerTo, ResourceTo, NameTo, PersonalGroups) end end. -build_roster_record(User1, Server1, User2, Server2, Groups) -> +build_roster_record(User1, Server1, User2, Server2, Name2, Groups) -> USR2 = {User2, Server2, undefined}, #roster{usj = {User1, Server1, USR2}, us = {User1, Server1}, jid = USR2, - name = User2, + name = Name2, subscription = both, ask = none, groups = Groups }. set_new_rosteritems(UserFrom, ServerFrom, - UserTo, ServerTo, ResourceTo, GroupsFrom) -> + UserTo, ServerTo, ResourceTo, NameTo, GroupsFrom) -> Mod = case lists:member(mod_roster_odbc, gen_mod:loaded_modules(ServerFrom)) of true -> mod_roster_odbc; @@ -213,13 +214,13 @@ set_new_rosteritems(UserFrom, ServerFrom, end, RIFrom = build_roster_record(UserFrom, ServerFrom, - UserTo, ServerTo, GroupsFrom), + UserTo, ServerTo, NameTo, GroupsFrom), set_item(UserFrom, ServerFrom, ResourceTo, RIFrom), JIDTo = exmpp_jid:make_bare_jid(UserTo, ServerTo), JIDFrom = exmpp_jid:make_bare_jid(UserFrom, ServerFrom), RITo = build_roster_record(UserTo, ServerTo, - UserFrom, ServerFrom, []), + UserFrom, ServerFrom, UserFrom,[]), set_item(UserTo, ServerTo, undefined, RITo), %% From requests diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl index 980d8d608..6dcfc506c 100644 --- a/src/mod_vcard_odbc.erl +++ b/src/mod_vcard_odbc.erl @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -97,7 +97,7 @@ stop(Host) -> get_sm_features({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; - + get_sm_features(Acc, _From, _To, Node, _Lang) -> case Node of [] -> @@ -131,10 +131,7 @@ process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> #jid{lnode = LUser, ldomain = LServer} = To, Username = ejabberd_odbc:escape(LUser), - case catch ejabberd_odbc:sql_query( - LServer, - ["select vcard from vcard " - "where username='", Username, "';"]) of + case catch odbc_queries:get_vcard(LServer, Username) of {selected, ["vcard"], [{SVCARD}]} -> try exmpp_xml:parse_document(SVCARD, [namespace, name_as_atom, autoload_known]) of @@ -233,30 +230,13 @@ set_vcard(User, LServer, VCARD) -> SOrgUnit = ejabberd_odbc:escape(OrgUnit), SLOrgUnit = ejabberd_odbc:escape(LOrgUnit), - ejabberd_odbc:sql_transaction( - LServer, - [["delete from vcard where username='", LUsername, "';"], - ["insert into vcard(username, vcard) " - "values ('", LUsername, "', '", SVCARD, "');"], - ["delete from vcard_search where lusername='", LUsername, "';"], - ["insert into vcard_search(" - " username, lusername, fn, lfn, family, lfamily," - " given, lgiven, middle, lmiddle, nickname, lnickname," - " bday, lbday, ctry, lctry, locality, llocality," - " email, lemail, orgname, lorgname, orgunit, lorgunit)" - "values (", - " '", Username, "', '", LUsername, "'," - " '", SFN, "', '", SLFN, "'," - " '", SFamily, "', '", SLFamily, "'," - " '", SGiven, "', '", SLGiven, "'," - " '", SMiddle, "', '", SLMiddle, "'," - " '", SNickname, "', '", SLNickname, "'," - " '", SBDay, "', '", SLBDay, "'," - " '", SCTRY, "', '", SLCTRY, "'," - " '", SLocality, "', '", SLLocality, "'," - " '", SEMail, "', '", SLEMail, "'," - " '", SOrgName, "', '", SLOrgName, "'," - " '", SOrgUnit, "', '", SLOrgUnit, "');"]]) + odbc_queries:set_vcard(LServer, LUsername, SBDay, SCTRY, SEMail, + SFN, SFamily, SGiven, SLBDay, SLCTRY, + SLEMail, SLFN, SLFamily, SLGiven, + SLLocality, SLMiddle, SLNickname, + SLOrgName, SLOrgUnit, SLocality, + SMiddle, SNickname, SOrgName, + SOrgUnit, SVCARD, Username) catch _ -> {error, badarg} @@ -612,18 +592,18 @@ make_val(Match, Field, Val) -> % true -> % mnesia:write( % #vcard_search{us = US, -% user = User, luser = LUser, -% fn = FN, lfn = LFN, -% family = Family, lfamily = LFamily, -% given = Given, lgiven = LGiven, -% middle = Middle, lmiddle = LMiddle, -% nickname = Nickname, lnickname = LNickname, -% bday = BDay, lbday = LBDay, -% ctry = CTRY, lctry = LCTRY, -% locality = Locality, llocality = LLocality, -% email = EMail, lemail = LEMail, -% orgname = OrgName, lorgname = LOrgName, -% orgunit = OrgUnit, lorgunit = LOrgUnit +% user = User, luser = LUser, +% fn = FN, lfn = LFN, +% family = Family, lfamily = LFamily, +% given = Given, lgiven = LGiven, +% middle = Middle, lmiddle = LMiddle, +% nickname = Nickname, lnickname = LNickname, +% bday = BDay, lbday = LBDay, +% ctry = CTRY, lctry = LCTRY, +% locality = Locality, llocality = LLocality, +% email = EMail, lemail = LEMail, +% orgname = OrgName, lorgname = LOrgName, +% orgunit = OrgUnit, lorgunit = LOrgUnit % }) % end. % @@ -643,5 +623,3 @@ remove_user(User, Server) -> LServer, [["delete from vcard where username='", Username, "';"], ["delete from vcard_search where lusername='", Username, "';"]]). - - diff --git a/src/odbc/Makefile.win32 b/src/odbc/Makefile.win32 index 13b54fb2f..2775468b7 100644 --- a/src/odbc/Makefile.win32 +++ b/src/odbc/Makefile.win32 @@ -4,8 +4,7 @@ include ..\Makefile.inc EFLAGS = -I .. -pz .. OUTDIR = .. -SOURCES = $(wildcard *.erl) -BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam)) +BEAMS = ..\ejabberd_odbc.beam ..\ejabberd_odbc_sup.beam ..\odbc_queries.beam ALL : $(BEAMS) diff --git a/src/odbc/ejabberd_odbc.erl b/src/odbc/ejabberd_odbc.erl index a373cc2d1..da1b01e2c 100644 --- a/src/odbc/ejabberd_odbc.erl +++ b/src/odbc/ejabberd_odbc.erl @@ -30,7 +30,7 @@ -behaviour(gen_server). %% External exports --export([start/1, start_link/1, +-export([start/1, start_link/2, sql_query/2, sql_query_t/1, sql_transaction/2, @@ -63,8 +63,8 @@ start(Host) -> gen_server:start(ejabberd_odbc, [Host], []). -start_link(Host) -> - gen_server:start_link(ejabberd_odbc, [Host], []). +start_link(Host, StartInterval) -> + gen_server:start_link(ejabberd_odbc, [Host, StartInterval], []). sql_query(Host, Query) -> gen_server:call(ejabberd_odbc_sup:get_random_pid(Host), @@ -131,10 +131,10 @@ escape_like(C) -> odbc_queries:escape(C). %% ignore | %% {stop, Reason} %%---------------------------------------------------------------------- -init([Host]) -> +init([Host, StartInterval]) -> case ejabberd_config:get_local_option({odbc_keepalive_interval, Host}) of - Interval when is_integer(Interval) -> - timer:apply_interval(Interval*1000, ?MODULE, keep_alive, [self()]); + KeepaliveInterval when is_integer(KeepaliveInterval) -> + timer:apply_interval(KeepaliveInterval*1000, ?MODULE, keep_alive, [self()]); undefined -> ok; _Other -> @@ -144,16 +144,16 @@ init([Host]) -> case SQLServer of %% Default pgsql port {pgsql, Server, DB, Username, Password} -> - pgsql_connect(Server, ?PGSQL_PORT, DB, Username, Password); + pgsql_connect(Server, ?PGSQL_PORT, DB, Username, Password, StartInterval); {pgsql, Server, Port, DB, Username, Password} when is_integer(Port) -> - pgsql_connect(Server, Port, DB, Username, Password); + pgsql_connect(Server, Port, DB, Username, Password, StartInterval); %% Default mysql port {mysql, Server, DB, Username, Password} -> - mysql_connect(Server, ?MYSQL_PORT, DB, Username, Password); + mysql_connect(Server, ?MYSQL_PORT, DB, Username, Password, StartInterval); {mysql, Server, Port, DB, Username, Password} when is_integer(Port) -> - mysql_connect(Server, Port, DB, Username, Password); + mysql_connect(Server, Port, DB, Username, Password, StartInterval); _ when is_list(SQLServer) -> - odbc_connect(SQLServer) + odbc_connect(SQLServer, StartInterval) end. %%---------------------------------------------------------------------- @@ -259,7 +259,7 @@ execute_transaction(State, F, NRestarts) -> %% part of init/1 %% Open an ODBC database connection -odbc_connect(SQLServer) -> +odbc_connect(SQLServer, StartInterval) -> application:start(odbc), case odbc:connect(SQLServer,[{scrollable_cursors, off}]) of {ok, Ref} -> @@ -268,8 +268,8 @@ odbc_connect(SQLServer) -> {error, Reason} -> ?ERROR_MSG("ODBC connection (~s) failed: ~p~n", [SQLServer, Reason]), - %% If we can't connect we wait for 30 seconds before retrying - timer:sleep(30000), + %% If we can't connect we wait before retrying + timer:sleep(StartInterval), {stop, odbc_connection_failed} end. @@ -278,15 +278,15 @@ odbc_connect(SQLServer) -> %% part of init/1 %% Open a database connection to PostgreSQL -pgsql_connect(Server, Port, DB, Username, Password) -> +pgsql_connect(Server, Port, DB, Username, Password, StartInterval) -> case pgsql:connect(Server, DB, Username, Password, Port) of {ok, Ref} -> erlang:monitor(process, Ref), {ok, #state{db_ref = Ref, db_type = pgsql}}; {error, Reason} -> ?ERROR_MSG("PostgreSQL connection failed: ~p~n", [Reason]), - %% If we can't connect we wait for 30 seconds before retrying - timer:sleep(30000), + %% If we can't connect we wait before retrying + timer:sleep(StartInterval), {stop, pgsql_connection_failed} end. @@ -317,7 +317,7 @@ pgsql_item_to_odbc(_) -> %% part of init/1 %% Open a database connection to MySQL -mysql_connect(Server, Port, DB, Username, Password) -> +mysql_connect(Server, Port, DB, Username, Password, StartInterval) -> NoLogFun = fun(_Level,_Format,_Argument) -> ok end, case mysql_conn:start(Server, Port, Username, Password, DB, NoLogFun) of {ok, Ref} -> @@ -330,9 +330,10 @@ mysql_connect(Server, Port, DB, Username, Password) -> "SERIALIZABLE;"], self()), {ok, #state{db_ref = Ref, db_type = mysql}}; {error, Reason} -> - ?ERROR_MSG("MySQL connection failed: ~p~n", [Reason]), - %% If we can't connect we wait for 30 seconds before retrying - timer:sleep(30000), + ?ERROR_MSG("MySQL connection failed: ~p~nWaiting ~p seconds before retrying...~n", + [Reason, StartInterval div 1000]), + %% If we can't connect we wait before retrying + timer:sleep(StartInterval), {stop, mysql_connection_failed} end. diff --git a/src/odbc/ejabberd_odbc_sup.erl b/src/odbc/ejabberd_odbc_sup.erl index c007da527..80f0a36ca 100644 --- a/src/odbc/ejabberd_odbc_sup.erl +++ b/src/odbc/ejabberd_odbc_sup.erl @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -37,32 +37,44 @@ -include("ejabberd.hrl"). -define(DEFAULT_POOL_SIZE, 10). +-define(DEFAULT_ODBC_START_INTERVAL, 30). % 30 seconds start_link(Host) -> supervisor:start_link({local, gen_mod:get_module_proc(Host, ?MODULE)}, ?MODULE, [Host]). init([Host]) -> - N = case ejabberd_config:get_local_option({odbc_pool_size, Host}) of - I when is_integer(I) -> - I; + PoolSize = case ejabberd_config:get_local_option({odbc_pool_size, Host}) of + I when is_integer(I) -> + I; undefined -> - ?DEFAULT_POOL_SIZE; - Other -> - ?ERROR_MSG("Wrong odbc_pool_size definition '~p' for host ~p, default to ~p~n", - [Other, Host, ?DEFAULT_POOL_SIZE]), - ?DEFAULT_POOL_SIZE - end, - {ok, {{one_for_one, 10, 6}, + ?DEFAULT_POOL_SIZE; + Other -> + ?ERROR_MSG("Wrong odbc_pool_size definition '~p' for host ~p, default to ~p~n", + [Other, Host, ?DEFAULT_POOL_SIZE]), + ?DEFAULT_POOL_SIZE + end, + StartInterval = case ejabberd_config:get_local_option({odbc_start_interval, Host}) of + Interval when is_integer(Interval) -> + Interval; + undefined -> + ?DEFAULT_ODBC_START_INTERVAL; + _Other2 -> + ?ERROR_MSG("Wrong odbc_start_interval definition '~p' for host ~p" + ", defaulting to ~p~n", + [_Other2, Host, ?DEFAULT_ODBC_START_INTERVAL]), + ?DEFAULT_ODBC_START_INTERVAL + end, + {ok, {{one_for_one, PoolSize+1, StartInterval}, lists:map( fun(I) -> {I, - {ejabberd_odbc, start_link, [Host]}, + {ejabberd_odbc, start_link, [Host, StartInterval*1000]}, transient, brutal_kill, worker, [?MODULE]} - end, lists:seq(1, N))}}. + end, lists:seq(1, PoolSize))}}. get_pids(Host) -> Proc = gen_mod:get_module_proc(Host, ?MODULE), diff --git a/src/odbc/mssql2005.sql b/src/odbc/mssql2005.sql index ca5007f15..f61980c0a 100644 --- a/src/odbc/mssql2005.sql +++ b/src/odbc/mssql2005.sql @@ -10,7 +10,7 @@ * 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., 59 Temple Place, Suite 330, Boston, MA @@ -104,6 +104,10 @@ if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[vcard]') a drop table [dbo].[vcard] GO +if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[vcard_search]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) +drop table [dbo].[vcard_search] +GO + if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[private_storage]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table [dbo].[private_storage] GO @@ -119,7 +123,7 @@ GO CREATE TABLE [dbo].[rostergroups] ( [username] [varchar] (250) NOT NULL , [jid] [varchar] (250) NOT NULL , - [grp] [varchar] (100) NOT NULL + [grp] [varchar] (100) NOT NULL ) ON [PRIMARY] GO @@ -133,7 +137,7 @@ CREATE TABLE [dbo].[rosterusers] ( [server] [char] (1) NOT NULL , [subscribe] [varchar] (200) NULL , [type] [varchar] (50) NULL , -CONSTRAINT [PK_rosterusers] PRIMARY KEY NONCLUSTERED +CONSTRAINT [PK_rosterusers] PRIMARY KEY NONCLUSTERED ( [username] ASC, [jid] ASC @@ -154,31 +158,41 @@ GO CREATE TABLE [dbo].[users] ( [username] [varchar] (250) NOT NULL , [password] [varchar] (50) NOT NULL , - [created] [datetime] NULL + [created] [datetime] NULL ) ON [PRIMARY] GO CREATE TABLE [dbo].[vcard] ( [username] [varchar] (250) NOT NULL , - [full_name] [varchar] (250) NULL , - [first_name] [varchar] (50) NULL , - [last_name] [varchar] (50) NULL , - [nick_name] [varchar] (50) NULL , - [url] [varchar] (1024) NULL , - [address1] [varchar] (50) NULL , - [address2] [varchar] (50) NULL , - [locality] [varchar] (50) NULL , - [region] [varchar] (50) NULL , - [pcode] [varchar] (50) NULL , - [country] [varchar] (50) NULL , - [telephone] [varchar] (50) NULL , - [email] [varchar] (250) NULL , - [orgname] [varchar] (50) NULL , - [orgunit] [varchar] (50) NULL , - [title] [varchar] (50) NULL , - [role] [varchar] (50) NULL , - [b_day] [datetime] NULL , - [descr] [varchar] (500) NULL + [vcard] [text] NOT NULL +) ON [PRIMARY] +GO + +CREATE TABLE [dbo].[vcard_search] ( + [username] [varchar] (250) NOT NULL , + [lusername] [varchar] (250) NOT NULL , + [fn] [text] NOT NULL , + [lfn] [varchar] (250) NOT NULL , + [family] [text] NOT NULL , + [lfamily] [varchar] (250) NOT NULL , + [given] [text] NOT NULL , + [lgiven] [varchar] (250) NOT NULL , + [middle] [text] NOT NULL , + [lmiddle] [varchar] (250) NOT NULL , + [nickname] [text] NOT NULL , + [lnickname] [varchar] (250) NOT NULL , + [bday] [text] NOT NULL , + [lbday] [varchar] (250) NOT NULL , + [ctry] [text] NOT NULL , + [lctry] [varchar] (250) NOT NULL , + [locality] [text] NOT NULL , + [llocality] [varchar] (250) NOT NULL , + [email] [text] NOT NULL , + [lemail] [varchar] (250) NOT NULL , + [orgname] [text] NOT NULL , + [lorgname] [varchar] (250) NOT NULL , + [orgunit] [text] NOT NULL , + [lorgunit] [varchar] (250) NOT NULL ) ON [PRIMARY] GO @@ -199,7 +213,7 @@ CREATE TABLE [dbo].[privacy_list]( [username] [varchar](250) NOT NULL, [name] [varchar](250) NOT NULL, [id] [bigint] IDENTITY(1,1) NOT NULL, - CONSTRAINT [PK_privacy_list] PRIMARY KEY CLUSTERED + CONSTRAINT [PK_privacy_list] PRIMARY KEY CLUSTERED ( [id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] @@ -224,73 +238,98 @@ GO - id in privacy_list is a SERIAL autogenerated number - id in privacy_list_data must exist in the table privacy_list */ -ALTER TABLE [dbo].[last] WITH NOCHECK ADD - CONSTRAINT [PK_last] PRIMARY KEY CLUSTERED +ALTER TABLE [dbo].[last] WITH NOCHECK ADD + CONSTRAINT [PK_last] PRIMARY KEY CLUSTERED ( [username] - ) WITH FILLFACTOR = 90 ON [PRIMARY] + ) WITH FILLFACTOR = 90 ON [PRIMARY] GO -ALTER TABLE [dbo].[rostergroups] WITH NOCHECK ADD - CONSTRAINT [PK_rostergroups] PRIMARY KEY CLUSTERED +ALTER TABLE [dbo].[rostergroups] WITH NOCHECK ADD + CONSTRAINT [PK_rostergroups] PRIMARY KEY CLUSTERED ( [username], [jid], [grp] - ) WITH FILLFACTOR = 90 ON [PRIMARY] + ) WITH FILLFACTOR = 90 ON [PRIMARY] GO -ALTER TABLE [dbo].[spool] WITH NOCHECK ADD - CONSTRAINT [PK_spool] PRIMARY KEY CLUSTERED +ALTER TABLE [dbo].[spool] WITH NOCHECK ADD + CONSTRAINT [PK_spool] PRIMARY KEY CLUSTERED ( [username], [id] - ) WITH FILLFACTOR = 90 ON [PRIMARY] + ) WITH FILLFACTOR = 90 ON [PRIMARY] GO -ALTER TABLE [dbo].[users] WITH NOCHECK ADD - CONSTRAINT [PK_users] PRIMARY KEY CLUSTERED +ALTER TABLE [dbo].[users] WITH NOCHECK ADD + CONSTRAINT [PK_users] PRIMARY KEY CLUSTERED ( [username] - ) WITH FILLFACTOR = 90 ON [PRIMARY] + ) WITH FILLFACTOR = 90 ON [PRIMARY] GO -ALTER TABLE [dbo].[vcard] WITH NOCHECK ADD - CONSTRAINT [PK_vcard] PRIMARY KEY CLUSTERED +ALTER TABLE [dbo].[vcard] WITH NOCHECK ADD + CONSTRAINT [PK_vcard] PRIMARY KEY CLUSTERED ( [username] - ) WITH FILLFACTOR = 90 ON [PRIMARY] + ) WITH FILLFACTOR = 90 ON [PRIMARY] GO + +CREATE INDEX [IX_vcard_search_lfn] ON [dbo].[vcard_search]([lfn]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO +CREATE INDEX [IX_vcard_search_lfamily] ON [dbo].[vcard_search]([lfamily]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO +CREATE INDEX [IX_vcard_search_lgiven] ON [dbo].[vcard_search]([lgiven]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO +CREATE INDEX [IX_vcard_search_lmiddle] ON [dbo].[vcard_search]([lmiddle]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO +CREATE INDEX [IX_vcard_search_lnickname] ON [dbo].[vcard_search]([lnickname]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO +CREATE INDEX [IX_vcard_search_lbday] ON [dbo].[vcard_search]([lbday]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO +CREATE INDEX [IX_vcard_search_lctry] ON [dbo].[vcard_search]([lctry]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO +CREATE INDEX [IX_vcard_search_llocality] ON [dbo].[vcard_search]([llocality]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO +CREATE INDEX [IX_vcard_search_lemail] ON [dbo].[vcard_search]([lemail]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO +CREATE INDEX [IX_vcard_search_lorgname] ON [dbo].[vcard_search]([lorgname]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO +CREATE INDEX [IX_vcard_search_lorgunit] ON [dbo].[vcard_search]([lorgunit]) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + + CREATE CLUSTERED INDEX [IX_rosterusers_user] ON [dbo].[rosterusers]([username]) WITH FILLFACTOR = 90 ON [PRIMARY] GO -ALTER TABLE [dbo].[last] WITH NOCHECK ADD +ALTER TABLE [dbo].[last] WITH NOCHECK ADD CONSTRAINT [DF_last_updated] DEFAULT (getdate()) FOR [Modify_Date] GO -ALTER TABLE [dbo].[spool] WITH NOCHECK ADD +ALTER TABLE [dbo].[spool] WITH NOCHECK ADD CONSTRAINT [DF_spool_notifyprocessed] DEFAULT (0) FOR [notifyprocessed], CONSTRAINT [DF_spool_created] DEFAULT (getdate()) FOR [created], CONSTRAINT [DF_spool_MustDelete] DEFAULT (0) FOR [MustDelete] GO -ALTER TABLE [dbo].[users] WITH NOCHECK ADD +ALTER TABLE [dbo].[users] WITH NOCHECK ADD CONSTRAINT [DF_users_created] DEFAULT (getdate()) FOR [created] GO -ALTER TABLE [dbo].[privacy_default_list] WITH NOCHECK ADD - CONSTRAINT [PK_privacy_defaut_list] PRIMARY KEY CLUSTERED +ALTER TABLE [dbo].[privacy_default_list] WITH NOCHECK ADD + CONSTRAINT [PK_privacy_defaut_list] PRIMARY KEY CLUSTERED ( [username] - ) WITH FILLFACTOR = 90 ON [PRIMARY] + ) WITH FILLFACTOR = 90 ON [PRIMARY] GO CREATE INDEX [IX_rostergroups_jid] ON [dbo].[rostergroups]([jid]) WITH FILLFACTOR = 90 ON [PRIMARY] GO CREATE INDEX [IX_rostergroups_user] ON [dbo].[rostergroups]([username]) WITH FILLFACTOR = 90 ON [PRIMARY] -GO +GO CREATE INDEX [IX_spool_user] ON [dbo].[spool]([username]) WITH FILLFACTOR = 90 ON [PRIMARY] GO @@ -385,7 +424,7 @@ BEGIN @Type ); END - + --- Update Roster Groups if exist else add group entry IF NOT EXISTS (SELECT username FROM rostergroups WITH (NOLOCK) WHERE rostergroups.username=@Username AND rostergroups.jid=@JID AND rostergroups.grp=@Grp) BEGIN @@ -543,12 +582,12 @@ CREATE PROCEDURE [dbo].[add_user] @Password varchar(50) AS BEGIN - INSERT INTO users - ( [username], + INSERT INTO users + ( [username], [password] - ) - VALUES - ( @Username, + ) + VALUES + ( @Username, @Password ); END @@ -559,7 +598,7 @@ GO /** Update users password **/ /******************************************************************/ CREATE PROCEDURE [dbo].[set_password] - @Username varchar(200), + @Username varchar(200), @Password varchar(50) AS BEGIN @@ -582,7 +621,7 @@ CREATE PROCEDURE [dbo].[get_password] @Username varchar(200) AS BEGIN - SELECT users.password as password + SELECT users.password as password FROM users WITH (NOLOCK) WHERE username=@Username; END @@ -594,7 +633,7 @@ GO /***************************************************************/ CREATE PROCEDURE [dbo].[clean_spool_msg] AS -DECLARE +DECLARE @dt datetime, @myRowCount int BEGIN @@ -606,7 +645,7 @@ BEGIN BEGIN BEGIN TRANSACTION SELECT @dt = DATEADD(d, -3, GETDATE()) - DELETE FROM spool + DELETE FROM spool WITH (ROWLOCK) WHERE (MustDelete=1) OR (Created < @dt); @@ -640,11 +679,11 @@ CREATE PROCEDURE [dbo].[del_roster] AS BEGIN BEGIN TRANSACTION - DELETE FROM rosterusers + DELETE FROM rosterusers WITH (ROWLOCK) WHERE (rosterusers.username = @Username) AND (rosterusers.jid = @JID); - - DELETE FROM rostergroups + + DELETE FROM rostergroups WITH (ROWLOCK) WHERE (rostergroups.username = @Username) AND (rostergroups.jid = @JID); COMMIT @@ -660,7 +699,7 @@ CREATE PROCEDURE [dbo].[del_spool_msg] @Username varchar(250) AS BEGIN - DELETE FROM spool + DELETE FROM spool WITH (ROWLOCK) WHERE spool.username=@Username; END @@ -674,7 +713,7 @@ CREATE PROCEDURE [dbo].[del_user] @Username varchar(200) AS BEGIN - DELETE FROM users + DELETE FROM users WITH (ROWLOCK) WHERE username=@Username; END @@ -691,7 +730,7 @@ DECLARE @Pwd varchar(50) BEGIN EXECUTE @Pwd = dbo.get_password @Username - DELETE FROM users + DELETE FROM users WITH (ROWLOCK) WHERE username=@Username @@ -709,11 +748,11 @@ CREATE PROCEDURE [dbo].[del_user_roster] AS BEGIN BEGIN TRANSACTION - DELETE FROM rosterusers + DELETE FROM rosterusers WITH (ROWLOCK) WHERE rosterusers.username = @Username; - - DELETE FROM rostergroups + + DELETE FROM rostergroups WITH (ROWLOCK) WHERE rostergroups.username = @Username; COMMIT @@ -739,9 +778,9 @@ BEGIN FROM spool WITH (NOLOCK) WHERE spool.username=@Username; - DELETE spool + DELETE spool WITH (ROWLOCK) - WHERE spool.username=@Username + WHERE spool.username=@Username END ELSE BEGIN @@ -758,7 +797,7 @@ CREATE PROCEDURE [dbo].[get_last] @Username varchar(250) AS BEGIN - SELECT last.seconds AS seconds, + SELECT last.seconds AS seconds, last.state AS state FROM last WITH (NOLOCK) WHERE last.username=@Username; @@ -773,26 +812,26 @@ CREATE PROCEDURE [dbo].[get_roster] @Username varchar(250) AS DECLARE - @vRosterusers table( username varchar(1), - jid varchar(1), - nick varchar(1), - subscription varchar(1), - ask varchar(1), - askmessage varchar(1), - server varchar(1), - subscribe varchar(1), + @vRosterusers table( username varchar(1), + jid varchar(1), + nick varchar(1), + subscription varchar(1), + ask varchar(1), + askmessage varchar(1), + server varchar(1), + subscribe varchar(1), type varchar(1)) BEGIN IF EXISTS (SELECT username FROM rosterusers with (nolock) WHERE rosterusers.username = @Username) BEGIN - SELECT rosterusers.username AS username, - rosterusers.jid AS jid, - rosterusers.nick AS nick, - rosterusers.subscription AS subscription, + SELECT rosterusers.username AS username, + rosterusers.jid AS jid, + rosterusers.nick AS nick, + rosterusers.subscription AS subscription, rosterusers.ask AS ask, rosterusers.askmessage AS askmessage, - rosterusers.server AS server, - rosterusers.subscribe AS subscribe, + rosterusers.server AS server, + rosterusers.subscribe AS subscribe, rosterusers.type AS type FROM rosterusers WITH (NOLOCK) WHERE rosterusers.username = @Username; @@ -813,26 +852,26 @@ CREATE PROCEDURE [dbo].[get_roster_by_jid] @JID varchar(250) AS DECLARE - @vRosterusers table( username varchar(1), - jid varchar(1), - nick varchar(1), - subscription varchar(1), + @vRosterusers table( username varchar(1), + jid varchar(1), + nick varchar(1), + subscription varchar(1), ask varchar(1), askmessage varchar(1), - server varchar(1), - subscribe varchar(1), + server varchar(1), + subscribe varchar(1), type varchar(1)) BEGIN IF EXISTS (SELECT username FROM rosterusers with (nolock) WHERE (rosterusers.username = @Username) AND (rosterusers.jid = @JID)) BEGIN - SELECT rosterusers.username AS username, - rosterusers.jid AS jid, - rosterusers.nick AS nick, - rosterusers.subscription AS subscription, + SELECT rosterusers.username AS username, + rosterusers.jid AS jid, + rosterusers.nick AS nick, + rosterusers.subscription AS subscription, rosterusers.ask AS ask, rosterusers.askmessage AS askmessage, - rosterusers.server AS server, - rosterusers.subscribe AS subscribe, + rosterusers.server AS server, + rosterusers.subscribe AS subscribe, rosterusers.type AS type FROM rosterusers WITH (NOLOCK) WHERE (rosterusers.username = @Username) AND (rosterusers.jid = @JID); @@ -852,12 +891,12 @@ CREATE PROCEDURE [dbo].[get_roster_jid_groups] @Username varchar(200) AS DECLARE - @vrostergroups table( jid varchar(1), + @vrostergroups table( jid varchar(1), grp varchar(1)) BEGIN IF EXISTS (SELECT username FROM rostergroups with (nolock) WHERE rostergroups.username = @Username) BEGIN - SELECT rostergroups.jid AS jid, + SELECT rostergroups.jid AS jid, rostergroups.grp AS grp FROM rostergroups WITH (NOLOCK) WHERE rostergroups.username = @Username; @@ -930,7 +969,7 @@ DECLARE BEGIN IF EXISTS (SELECT username FROM rosterusers with (nolock) WHERE rosterusers.username=@Username AND rosterusers.jid=@JID) BEGIN - SELECT rosterusers.subscription AS subscription + SELECT rosterusers.subscription AS subscription FROM rosterusers WITH (NOLOCK) WHERE rosterusers.username=@Username AND rosterusers.jid=@JID; END @@ -958,7 +997,7 @@ GO /******************************************************************/ CREATE PROCEDURE [dbo].[set_last] @Username varchar(250), - @Seconds varchar(50), + @Seconds varchar(50), @State varchar(100) AS BEGIN @@ -1050,4 +1089,151 @@ END GO +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[set_vcard] **/ +/** Set the user's vCard **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[set_vcard] + @VCard varchar(8000), + @Username varchar(250), + @Lusername varchar(250), + @Fn varchar(8000), + @Lfn varchar(250), + @Family varchar(8000), + @Lfamily varchar(250), + @Given varchar(8000), + @Lgiven varchar(250), + @Middle varchar(8000), + @Lmiddle varchar(250), + @Nickname varchar(8000), + @Lnickname varchar(250), + @Bday varchar(8000), + @Lbday varchar(250), + @Ctry varchar(8000), + @Lctry varchar(250), + @Locality varchar(8000), + @Llocality varchar(250), + @Email varchar(8000), + @Lemail varchar(250), + @Orgname varchar(8000), + @Lorgname varchar(250), + @Orgunit varchar(8000), + @Lorgunit varchar(250) +AS +BEGIN + IF EXISTS (SELECT username FROM vcard with (nolock) WHERE vcard.username = @Username) + BEGIN + UPDATE [vcard] + SET [vcard].username = @LUsername, + [vcard].vcard = @Vcard + WHERE vcard.username = @LUsername; + UPDATE [vcard_search] + SET [vcard_search].username = @Username, + [vcard_search].lusername = @Lusername, + [vcard_search].fn = @Fn, + [vcard_search].lfn = @Lfn, + [vcard_search].family = @Family, + [vcard_search].lfamily = @Lfamily, + [vcard_search].given = @Given, + [vcard_search].lgiven = @Lgiven, + [vcard_search].middle = @Middle, + [vcard_search].lmiddle = @Lmiddle, + [vcard_search].nickname = @Nickname, + [vcard_search].lnickname = @Lnickname, + [vcard_search].bday = @Bday, + [vcard_search].lbday = @Lbday, + [vcard_search].ctry = @Ctry, + [vcard_search].lctry = @Lctry, + [vcard_search].locality = @Locality, + [vcard_search].llocality = @Llocality, + [vcard_search].email = @Email, + [vcard_search].lemail = @Lemail, + [vcard_search].orgname = @Orgname, + [vcard_search].lorgname = @Lorgname, + [vcard_search].orgunit = @Orgunit, + [vcard_search].lorgunit = @Lorgunit + WHERE vcard_search.lusername = @LUsername; + END + ELSE + BEGIN + INSERT INTO [vcard] + ( [vcard].username, + [vcard].vcard + ) + VALUES + ( @lUsername, + @Vcard + ); + + INSERT INTO [vcard_search] + ( + [vcard_search].username , + [vcard_search].lusername , + [vcard_search].fn , + [vcard_search].lfn , + [vcard_search].family , + [vcard_search].lfamily , + [vcard_search].given , + [vcard_search].lgiven , + [vcard_search].middle , + [vcard_search].lmiddle , + [vcard_search].nickname, + [vcard_search].lnickname, + [vcard_search].bday, + [vcard_search].lbday, + [vcard_search].ctry, + [vcard_search].lctry, + [vcard_search].locality, + [vcard_search].llocality, + [vcard_search].email, + [vcard_search].lemail, + [vcard_search].orgname, + [vcard_search].lorgname, + [vcard_search].orgunit, + [vcard_search].lorgunit + ) + VALUES + ( + @Username, + @Lusername, + @Fn, + @Lfn, + @Family, + @Lfamily, + @Given, + @Lgiven, + @Middle, + @Lmiddle, + @Nickname, + @Lnickname, + @Bday, + @Lbday, + @Ctry, + @Lctry, + @Locality, + @Llocality, + @Email, + @Lemail, + @Orgname, + @Lorgname, + @Orgunit, + @Lorgunit + ) + END +END +GO + +/******************************************************************/ +/****** Object: StoredProcedure [dbo].[get_vcard] **/ +/** Retrive the user's vCard **/ +/******************************************************************/ +CREATE PROCEDURE [dbo].[get_vcard] + @Username varchar(250) +AS +BEGIN + SELECT vcard.vcard as vcard + FROM vcard WITH (NOLOCK) + WHERE username=@Username; +END +GO diff --git a/src/odbc/odbc_queries.erl b/src/odbc/odbc_queries.erl index 33caa71d1..c9f6819be 100644 --- a/src/odbc/odbc_queries.erl +++ b/src/odbc/odbc_queries.erl @@ -61,6 +61,8 @@ set_private_data_sql/3, get_private_data/3, del_user_private_storage/2, + set_vcard/26, + get_vcard/2, escape/1, count_records_where/3]). @@ -327,11 +329,11 @@ update_roster_sql(Username, SJID, ItemVals, ItemGroups) -> " values (", ItemVals, ");"], ["delete from rostergroups " " where username='", Username, "' " - " and jid='", SJID, "';"], + " and jid='", SJID, "';"]] ++ [["insert into rostergroups(" " username, jid, grp) " " values (", ItemGroup, ");"] || - ItemGroup <- ItemGroups]]. + ItemGroup <- ItemGroups]. roster_subscribe(_LServer, Username, SJID, ItemVals) -> ejabberd_odbc:sql_query_t( @@ -378,6 +380,42 @@ del_user_private_storage(LServer, Username) -> LServer, ["delete from private_storage where username='", Username, "';"]). + +set_vcard(LServer, LUsername, SBDay, SCTRY, SEMail, SFN, SFamily, SGiven, + SLBDay, SLCTRY, SLEMail, SLFN, SLFamily, SLGiven, SLLocality, + SLMiddle, SLNickname, SLOrgName, SLOrgUnit, SLocality, SMiddle, + SNickname, SOrgName, SOrgUnit, SVCARD, Username) -> + ejabberd_odbc:sql_transaction( + LServer, + [["delete from vcard where username='", LUsername, "';"], + ["insert into vcard(username, vcard) " + "values ('", LUsername, "', '", SVCARD, "');"], + ["delete from vcard_search where lusername='", LUsername, "';"], + ["insert into vcard_search(" + " username, lusername, fn, lfn, family, lfamily," + " given, lgiven, middle, lmiddle, nickname, lnickname," + " bday, lbday, ctry, lctry, locality, llocality," + " email, lemail, orgname, lorgname, orgunit, lorgunit)" + "values (", + " '", Username, "', '", LUsername, "'," + " '", SFN, "', '", SLFN, "'," + " '", SFamily, "', '", SLFamily, "'," + " '", SGiven, "', '", SLGiven, "'," + " '", SMiddle, "', '", SLMiddle, "'," + " '", SNickname, "', '", SLNickname, "'," + " '", SBDay, "', '", SLBDay, "'," + " '", SCTRY, "', '", SLCTRY, "'," + " '", SLocality, "', '", SLLocality, "'," + " '", SEMail, "', '", SLEMail, "'," + " '", SOrgName, "', '", SLOrgName, "'," + " '", SOrgUnit, "', '", SLOrgUnit, "');"]]). + +get_vcard(LServer, Username) -> + ejabberd_odbc:sql_query( + LServer, + ["select vcard from vcard " + "where username='", Username, "';"]). + %% Characters to escape escape($\0) -> "\\0"; escape($\n) -> "\\n"; @@ -597,6 +635,25 @@ del_user_private_storage(LServer, Username) -> LServer, ["EXECUTE dbo.del_user_storage '", Username, "'"]). +set_vcard(LServer, LUsername, SBDay, SCTRY, SEMail, SFN, SFamily, SGiven, + SLBDay, SLCTRY, SLEMail, SLFN, SLFamily, SLGiven, SLLocality, + SLMiddle, SLNickname, SLOrgName, SLOrgUnit, SLocality, SMiddle, + SNickname, SOrgName, SOrgUnit, SVCARD, Username) -> + ejabberd_odbc:sql_query( + LServer, + ["EXECUTE dbo.set_vcard '", SVCARD, "' , '", Username, "' , '", LUsername, "' , '", + SFN, "' , '", SLFN, "' , '", SFamily, "' , '", SLFamily, "' , '", + SGiven, "' , '", SLGiven, "' , '", SMiddle, "' , '", SLMiddle, "' , '", + SNickname, "' , '", SLNickname, "' , '", SBDay, "' , '", SLBDay, "' , '", + SCTRY, "' , '", SLCTRY, "' , '", SLocality, "' , '", SLLocality, "' , '", + SEMail, "' , '", SLEMail, "' , '", SOrgName, "' , '", SLOrgName, "' , '", + SOrgUnit, "' , '", SLOrgUnit, "'"]). + +get_vcard(LServer, Username) -> + ejabberd_odbc:sql_query( + LServer, + ["EXECUTE dbo.get_vcard '", Username, "'"]). + %% Characters to escape escape($\0) -> "\\0"; escape($\t) -> "\\t"; diff --git a/src/stringprep/Makefile.win32 b/src/stringprep/Makefile.win32 index 23f493ff6..60ccb416c 100644 --- a/src/stringprep/Makefile.win32 +++ b/src/stringprep/Makefile.win32 @@ -4,8 +4,7 @@ include ..\Makefile.inc EFLAGS = -I .. -pz .. OUTDIR = .. -SOURCES = $(wildcard *.erl) -BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam)) +BEAMS = ..\stringprep.beam ..\stringprep_sup.beam SOURCE = stringprep_drv.c AUXIL = uni_data.c uni_norm.c diff --git a/src/tls/Makefile.win32 b/src/tls/Makefile.win32 index 576112e20..93ec8471d 100644 --- a/src/tls/Makefile.win32 +++ b/src/tls/Makefile.win32 @@ -4,8 +4,7 @@ include ..\Makefile.inc EFLAGS = -I .. -pz .. OUTDIR = .. -SOURCES = $(wildcard *.erl) -BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam)) +BEAMS = ..\tls.beam SOURCE = tls_drv.c OBJECT = tls_drv.o diff --git a/src/web/Makefile.win32 b/src/web/Makefile.win32 index 3fc9ce2a1..411d57ce8 100644 --- a/src/web/Makefile.win32 +++ b/src/web/Makefile.win32 @@ -4,8 +4,7 @@ include ..\Makefile.inc EFLAGS = -I .. -pz .. OUTDIR = .. -SOURCES = $(wildcard *.erl) -BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam)) +BEAMS = ..\ejabberd_http.beam ..\ejabberd_http_bind.beam ..\ejabberd_http_poll.beam ..\ejabberd_web.beam ..\ejabberd_web_admin.beam ..\mod_http_bind.beam ..\mod_http_fileserver.beam ALL : $(BEAMS) @@ -21,5 +20,14 @@ $(OUTDIR)\ejabberd_web.beam : ejabberd_web.erl $(OUTDIR)\ejabberd_web_admin.beam : ejabberd_web_admin.erl erlc -W $(EFLAGS) -o $(OUTDIR) ejabberd_web_admin.erl +$(OUTDIR)\ejabberd_http_bind.beam : ejabberd_http_bind.erl + erlc -W $(EFLAGS) -o $(OUTDIR) ejabberd_http_bind.erl + $(OUTDIR)\ejabberd_http_poll.beam : ejabberd_http_poll.erl erlc -W $(EFLAGS) -o $(OUTDIR) ejabberd_http_poll.erl + +$(OUTDIR)\mod_http_bind.beam : mod_http_bind.erl + erlc -W $(EFLAGS) -o $(OUTDIR) mod_http_bind.erl + +$(OUTDIR)\mod_http_fileserver.beam : mod_http_fileserver.erl + erlc -W $(EFLAGS) -o $(OUTDIR) mod_http_fileserver.erl From 6ab7e339bd2eaaa6deaccac04737a52c5e0e6caf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 9 Oct 2008 11:54:42 +0000 Subject: [PATCH 102/582] Fix handling of unauthenticated stanzas which are not request IQ. PR: EJABP-1 Submitted by: Pablo Polvorin SVN Revision: 1615 --- ChangeLog | 5 +++++ src/ejabberd_c2s.erl | 15 ++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9353205f7..f7ad8b2f4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-10-09 Jean-Sébastien Pédron + + * src/ejabberd_c2s.erl: Fix handling of unauthenticated stanzas which + are not request IQ. Thanks to Pablo Polvorin! + 2008-10-08 Jean-Sébastien Pédron Merge from trunk (r1563 to r1613). diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index abf2cd75c..75779cc44 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1285,7 +1285,7 @@ new_id() -> randoms:get_string(). -is_auth_packet(El) -> +is_auth_packet(El) when ?IS_IQ(El) -> case exmpp_iq:is_request(El) of true -> {auth, exmpp_stanza:get_id(El), exmpp_iq:get_type(El), @@ -1293,7 +1293,9 @@ is_auth_packet(El) -> undefined, undefined, undefined, undefined)}; false -> false - end. + end; +is_auth_packet(_El) -> + false. get_auth_tags([#xmlel{ns = ?NS_LEGACY_AUTH, name = Name, children = Els} | L], @@ -1828,7 +1830,7 @@ resend_subscription_requests(#state{user = User, end, PendingSubscriptions). -process_unauthenticated_stanza(StateData, El) -> +process_unauthenticated_stanza(StateData, El) when ?IS_IQ(El) -> case exmpp_iq:get_kind(El) of request -> IQ_Rec = exmpp_iq:xmlel_to_iq(El), @@ -1851,9 +1853,12 @@ process_unauthenticated_stanza(StateData, El) -> send_element(StateData, Res) end; _ -> - % Drop any stanza, which isn't IQ stanza + % Drop any stanza, which isn't an IQ request stanza ok - end. + end; +process_unauthenticated_stanza(_StateData,_El) -> + ok. + peerip(SockMod, Socket) -> IP = case SockMod of From e1b3bd611ddcacb054c37f6259a2eb91a8eda271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 10 Oct 2008 08:14:08 +0000 Subject: [PATCH 103/582] Fix a bug where legacy authentication informations were not search among the query children but among the IQ children. PR: EJABP-1 Submitted by: Pablo Polvorin SVN Revision: 1616 --- ChangeLog | 6 ++++++ src/ejabberd_c2s.erl | 15 ++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index f7ad8b2f4..3c3009b8c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-10-10 Jean-Sébastien Pédron + + * src/ejabberd_c2s.erl (is_auth_packet/1): Fix a bug where + legacy authentication informations were not search among the query + children but among the IQ children. Thanks to Pablo Polvorin! + 2008-10-09 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Fix handling of unauthenticated stanzas which diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 75779cc44..25dc1352a 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1286,13 +1286,14 @@ new_id() -> is_auth_packet(El) when ?IS_IQ(El) -> - case exmpp_iq:is_request(El) of - true -> - {auth, exmpp_stanza:get_id(El), exmpp_iq:get_type(El), - get_auth_tags(El#xmlel.children, - undefined, undefined, undefined, undefined)}; - false -> - false + case exmpp_iq:xmlel_to_iq(El) of + #iq{ns = ?NS_LEGACY_AUTH, kind = 'request'} = IQ_Rec -> + Children = exmpp_xml:get_child_elements(IQ_Rec#iq.payload), + {auth, IQ_Rec#iq.id, IQ_Rec#iq.type, + get_auth_tags(Children , undefined, undefined, + undefined, undefined)}; + _ -> + false end; is_auth_packet(_El) -> false. From ccd94bb734c712af0f001ea50f46326509fa4d7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 10 Oct 2008 08:16:29 +0000 Subject: [PATCH 104/582] Fix a buf where a tuple was passed to exmpp_jid:jid_to_list/1 instead of a #jid. Now we use exmpp_jid:jid_to_list/3. PR: EJABP-1 Submitted by: Pablo Polvorin SVN Revision: 1617 --- ChangeLog | 4 ++++ src/mod_privacy_odbc.erl | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 3c3009b8c..f9e13ee73 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,10 @@ legacy authentication informations were not search among the query children but among the IQ children. Thanks to Pablo Polvorin! + * src/mod_privacy_odbc.erl (item_to_raw/1): Fix a buf where a tuple + was passed to exmpp_jid:jid_to_list/1 instead of a #jid. Now we use + exmpp_jid:jid_to_list/3. Thanks to Pablo Polvorin! + 2008-10-09 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Fix handling of unauthenticated stanzas which diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 00269d0e9..57af4fc30 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -727,7 +727,8 @@ item_to_raw(#listitem{type = Type, none -> {"n", ""}; jid -> - {"j", exmpp_jid:jid_to_list(Value)}; + {N0, D0, R0} = Value, + {"j", exmpp_jid:jid_to_list(N0, D0, R0)}; group -> {"g", Value}; subscription -> From c0e4af9ac0dbc632776197a724289e1b35a44373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 10 Oct 2008 14:33:16 +0000 Subject: [PATCH 105/582] Replace jlib:nameprep/1 by exmpp_stringprep:nameprep/1 and change the error handling. PR: EJABP-1 SVN Revision: 1618 --- ChangeLog | 4 ++++ src/ejabberd_s2s_in.erl | 34 +++++++++++++++++----------------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index f9e13ee73..1c0625c24 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,10 @@ was passed to exmpp_jid:jid_to_list/1 instead of a #jid. Now we use exmpp_jid:jid_to_list/3. Thanks to Pablo Polvorin! + * src/ejabberd_s2s_in.erl (wait_for_feature_request/2): Replace + jlib:nameprep/1 by exmpp_stringprep:nameprep/1 and change the error + handling. + 2008-10-09 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Fix handling of unauthenticated stanzas which diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 8ac32bf63..29bd85bdf 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -255,35 +255,35 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> #xmlel{ns = ?NS_SASL, name = 'auth'} when TLSEnabled -> case exmpp_server_sasl:next_step(El) of {auth, "EXTERNAL", Auth} -> - AuthDomain = jlib:nameprep(Auth), - AuthRes = - case (StateData#state.sockmod):get_peer_certificate( + {AuthDomain, AuthRes} = try + AuthDomain0 = exmpp_stringprep:nameprep(Auth), + AuthRes0 = case (StateData#state.sockmod):get_peer_certificate( StateData#state.socket) of {ok, Cert} -> case (StateData#state.sockmod):get_verify_result( StateData#state.socket) of 0 -> - case AuthDomain of - error -> + case idna:domain_utf8_to_ascii(AuthDomain0) of + false -> false; - _ -> - case idna:domain_utf8_to_ascii(AuthDomain) of - false -> - false; - PCAuthDomain -> - lists:any( - fun(D) -> - match_domain( - PCAuthDomain, D) - end, get_cert_domains(Cert)) - end + PCAuthDomain -> + lists:any( + fun(D) -> + match_domain( + PCAuthDomain, D) + end, get_cert_domains(Cert)) end; _ -> false end; error -> - false + {undefined, false} end, + {AuthDomain0, AuthRes0} + catch + _ -> + false + end, if AuthRes -> (StateData#state.sockmod):reset_stream( From 129b0e99cf581baf6f68f7264e6e3cbbdb5bb973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 10 Oct 2008 14:35:17 +0000 Subject: [PATCH 106/582] Replace jlib:nodeprep/1 by exmpp_stringprep:nodeprep/1 and change the error handling. PR: EJABP-1 SVN Revision: 1619 --- ChangeLog | 3 +++ src/ejabberd_config.erl | 11 ++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1c0625c24..64b64feb2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,9 @@ jlib:nameprep/1 by exmpp_stringprep:nameprep/1 and change the error handling. + * src/ejabberd_config.erl (normalize_hosts/2): Replace jlib:nodeprep/1 + by exmpp_stringprep:nodeprep/1 and change the error handling. + 2008-10-09 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Fix handling of unauthenticated stanzas which diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 182b4a216..51b228c4f 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -154,13 +154,14 @@ normalize_hosts(Hosts) -> normalize_hosts([], PrepHosts) -> lists:reverse(PrepHosts); normalize_hosts([Host|Hosts], PrepHosts) -> - case jlib:nodeprep(Host) of - error -> + try + PrepHost = exmpp_stringprep:nodeprep(Host), + normalize_hosts(Hosts, [PrepHost|PrepHosts]) + catch + _ -> ?ERROR_MSG("Can't load config file: " "invalid host name [~p]", [Host]), - exit("invalid hostname"); - PrepHost -> - normalize_hosts(Hosts, [PrepHost|PrepHosts]) + exit("invalid hostname") end. From 53bea055aac42ede3c3ae8ef122703982d38bcb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 10 Oct 2008 14:36:25 +0000 Subject: [PATCH 107/582] Remove a remaining jlib:jid_remove_resource/1 call. PR: EJABP-1 SVN Revision: 1620 --- ChangeLog | 3 +++ src/ejabberd_c2s.erl | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 64b64feb2..ee33d6557 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,6 +15,9 @@ * src/ejabberd_config.erl (normalize_hosts/2): Replace jlib:nodeprep/1 by exmpp_stringprep:nodeprep/1 and change the error handling. + * src/ejabberd_c2s.erl (handle_sync_event/4): Remove a remaining + jlib:jid_remove_resource/1 call. + 2008-10-09 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Fix handling of unauthenticated stanzas which diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 25dc1352a..4c2f93a22 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -940,10 +940,10 @@ handle_sync_event({get_presence}, _From, StateName, StateData) -> handle_sync_event(get_subscribed, _From, StateName, StateData) -> Subscribed = StateData#state.pres_f, Online = StateData#state.pres_available, - Pred = fun(User, _Caps) -> - ?SETS:is_element(jlib:jid_remove_resource(User), + Pred = fun({U, S, _} = User, _Caps) -> + ?SETS:is_element({U, S, undefined}, Subscribed) orelse - ?SETS:is_element(User, Subscribed) + ?SETS:is_element(User, Subscribed) end, SubscribedAndOnline = ?DICT:filter(Pred, Online), SubscribedWithCaps = ?SETS:fold(fun(User, Acc) -> @@ -957,7 +957,7 @@ handle_sync_event(get_subscribed_and_online, _From, StateName, StateData) -> Pred = fun({U, S, _R} = User, _Caps) -> ?SETS:is_element({U, S, undefined}, Subscribed) orelse - ?SETS:is_element(User, Subscribed) + ?SETS:is_element(User, Subscribed) end, SubscribedAndOnline = ?DICT:filter(Pred, Online), {reply, ?DICT:to_list(SubscribedAndOnline), StateName, StateData}; From 285b3858dda08635cf0ca050f358b19d066c6c5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 10 Oct 2008 14:37:26 +0000 Subject: [PATCH 108/582] Replace jlib:*prep/1 by exmpp_stringprep:*prep/1 and change the error handling. PR: EJABP-1 SVN Revision: 1621 --- ChangeLog | 3 + src/ejabberd_auth_internal.erl | 121 ++++++++++++++++++++------------- 2 files changed, 76 insertions(+), 48 deletions(-) diff --git a/ChangeLog b/ChangeLog index ee33d6557..763974dc2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,6 +18,9 @@ * src/ejabberd_c2s.erl (handle_sync_event/4): Remove a remaining jlib:jid_remove_resource/1 call. + * src/ejabberd_auth_internal.erl: Replace jlib:*prep/1 by + exmpp_stringprep:*prep/1 and change the error handling. + 2008-10-09 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Fix handling of unauthenticated stanzas which diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index cec18b319..1abc9f77c 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -207,71 +207,96 @@ get_vh_registered_users_number(Server, _) -> get_vh_registered_users_number(Server). get_password(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - US = {LUser, LServer}, - case catch mnesia:dirty_read(passwd, US) of - [#passwd{password = Password}] -> - Password; + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + case catch mnesia:dirty_read(passwd, US) of + [#passwd{password = Password}] -> + Password; + _ -> + false + end + catch _ -> false end. get_password_s(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - US = {LUser, LServer}, - case catch mnesia:dirty_read(passwd, US) of - [#passwd{password = Password}] -> - Password; + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + case catch mnesia:dirty_read(passwd, US) of + [#passwd{password = Password}] -> + Password; + _ -> + [] + end + catch _ -> [] end. is_user_exists(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - US = {LUser, LServer}, - case catch mnesia:dirty_read({passwd, US}) of - [] -> - false; - [_] -> - true; + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + case catch mnesia:dirty_read({passwd, US}) of + [] -> + false; + [_] -> + true; + _ -> + false + end + catch _ -> false end. remove_user(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - US = {LUser, LServer}, - F = fun() -> - mnesia:delete({passwd, US}) - end, - mnesia:transaction(F), - ejabberd_hooks:run(remove_user, LServer, [User, Server]). + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + F = fun() -> + mnesia:delete({passwd, US}) + end, + mnesia:transaction(F), + ejabberd_hooks:run(remove_user, LServer, [User, Server]) + catch + _ -> + ok + end. remove_user(User, Server, Password) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - US = {LUser, LServer}, - F = fun() -> - case mnesia:read({passwd, US}) of - [#passwd{password = Password}] -> - mnesia:delete({passwd, US}), - ok; - [_] -> - not_allowed; - _ -> - not_exists - end - end, - case mnesia:transaction(F) of - {atomic, ok} -> - ejabberd_hooks:run(remove_user, LServer, [User, Server]), - ok; - {atomic, Res} -> - Res; + try + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + US = {LUser, LServer}, + F = fun() -> + case mnesia:read({passwd, US}) of + [#passwd{password = Password}] -> + mnesia:delete({passwd, US}), + ok; + [_] -> + not_allowed; + _ -> + not_exists + end + end, + case mnesia:transaction(F) of + {atomic, ok} -> + ejabberd_hooks:run(remove_user, LServer, [User, Server]), + ok; + {atomic, Res} -> + Res; + _ -> + bad_request + end + catch _ -> bad_request end. From 5224a796cceac56d4e1e9a65c97cad1cb89cebf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 10 Oct 2008 14:38:52 +0000 Subject: [PATCH 109/582] Replace jlib:iq_to_xml/1 by exmpp_iq:iq_to_xmlel/1. PR: EJABP-1 SVN Revision: 1622 --- ChangeLog | 3 +++ src/mod_vcard_odbc.erl | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 763974dc2..1096acc02 100644 --- a/ChangeLog +++ b/ChangeLog @@ -21,6 +21,9 @@ * src/ejabberd_auth_internal.erl: Replace jlib:*prep/1 by exmpp_stringprep:*prep/1 and change the error handling. + * src/mod_vcard_odbc.erl (do_route/4): Replace jlib:iq_to_xml/1 by + exmpp_iq:iq_to_xmlel/1. + 2008-10-09 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Fix handling of unauthenticated stanzas which diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl index 6dcfc506c..db0b1fd9b 100644 --- a/src/mod_vcard_odbc.erl +++ b/src/mod_vcard_odbc.erl @@ -317,7 +317,7 @@ do_route(ServerHost, From, To, Packet) -> ResIQ = exmpp_iq:result(Packet, Result), ejabberd_router:route( - To, From, jlib:iq_to_xml(ResIQ)) + To, From, exmpp_iq:iq_to_xmlel(ResIQ)) end end; {get, ?NS_SEARCH} -> From e3100110f09b315c29531d63d4443155440b7451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 10 Oct 2008 14:40:04 +0000 Subject: [PATCH 110/582] Replace jlib:nameprep/1 by exmpp_stringprep:nameprep/1 and change the error handling. PR: EJABP-1 SVN Revision: 1623 --- ChangeLog | 7 +- src/ejabberd_router.erl | 166 ++++++++++++++++++++-------------------- 2 files changed, 88 insertions(+), 85 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1096acc02..7b106efc2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,9 +8,10 @@ was passed to exmpp_jid:jid_to_list/1 instead of a #jid. Now we use exmpp_jid:jid_to_list/3. Thanks to Pablo Polvorin! - * src/ejabberd_s2s_in.erl (wait_for_feature_request/2): Replace - jlib:nameprep/1 by exmpp_stringprep:nameprep/1 and change the error - handling. + * src/ejabberd_s2s_in.erl (wait_for_feature_request/2), + src/ejabberd_router.erl (register_route/2, unregister_route/1): + Replace jlib:nameprep/1 by exmpp_stringprep:nameprep/1 and change the + error handling. * src/ejabberd_config.erl (normalize_hosts/2): Replace jlib:nodeprep/1 by exmpp_stringprep:nodeprep/1 and change the error handling. diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index 658f674fc..b3f387e72 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -87,51 +87,52 @@ register_route(Domain) -> register_route(Domain, undefined). register_route(Domain, LocalHint) -> - case jlib:nameprep(Domain) of - error -> - erlang:error({invalid_domain, Domain}); - LDomain -> - Pid = self(), - case get_component_number(LDomain) of - undefined -> - F = fun() -> - mnesia:write(#route{domain = LDomain, - pid = Pid, - local_hint = LocalHint}) - end, - mnesia:transaction(F); - N -> - F = fun() -> - case mnesia:read({route, LDomain}) of - [] -> - mnesia:write( - #route{domain = LDomain, - pid = Pid, - local_hint = 1}), - lists:foreach( - fun(I) -> - mnesia:write( - #route{domain = LDomain, - pid = undefined, - local_hint = I}) - end, lists:seq(2, N)); - Rs -> - lists:any( - fun(#route{pid = undefined, - local_hint = I} = R) -> - mnesia:write( - #route{domain = LDomain, - pid = Pid, - local_hint = I}), - mnesia:delete_object(R), - true; - (_) -> - false - end, Rs) - end - end, - mnesia:transaction(F) - end + try + LDomain = exmpp_stringprep:nameprep(Domain), + Pid = self(), + case get_component_number(LDomain) of + undefined -> + F = fun() -> + mnesia:write(#route{domain = LDomain, + pid = Pid, + local_hint = LocalHint}) + end, + mnesia:transaction(F); + N -> + F = fun() -> + case mnesia:read({route, LDomain}) of + [] -> + mnesia:write( + #route{domain = LDomain, + pid = Pid, + local_hint = 1}), + lists:foreach( + fun(I) -> + mnesia:write( + #route{domain = LDomain, + pid = undefined, + local_hint = I}) + end, lists:seq(2, N)); + Rs -> + lists:any( + fun(#route{pid = undefined, + local_hint = I} = R) -> + mnesia:write( + #route{domain = LDomain, + pid = Pid, + local_hint = I}), + mnesia:delete_object(R), + true; + (_) -> + false + end, Rs) + end + end, + mnesia:transaction(F) + end + catch + _ -> + erlang:error({invalid_domain, Domain}) end. register_routes(Domains) -> @@ -140,43 +141,44 @@ register_routes(Domains) -> end, Domains). unregister_route(Domain) -> - case jlib:nameprep(Domain) of - error -> - erlang:error({invalid_domain, Domain}); - LDomain -> - Pid = self(), - case get_component_number(LDomain) of - undefined -> - F = fun() -> - case mnesia:match_object( - #route{domain = LDomain, - pid = Pid, - _ = '_'}) of - [R] -> - mnesia:delete_object(R); - _ -> - ok - end - end, - mnesia:transaction(F); - _ -> - F = fun() -> - case mnesia:match_object(#route{domain=LDomain, - pid = Pid, - _ = '_'}) of - [R] -> - I = R#route.local_hint, - mnesia:write( - #route{domain = LDomain, - pid = undefined, - local_hint = I}), - mnesia:delete_object(R); - _ -> - ok - end - end, - mnesia:transaction(F) - end + try + LDomain = exmpp_stringprep:nameprep(Domain), + Pid = self(), + case get_component_number(LDomain) of + undefined -> + F = fun() -> + case mnesia:match_object( + #route{domain = LDomain, + pid = Pid, + _ = '_'}) of + [R] -> + mnesia:delete_object(R); + _ -> + ok + end + end, + mnesia:transaction(F); + _ -> + F = fun() -> + case mnesia:match_object(#route{domain=LDomain, + pid = Pid, + _ = '_'}) of + [R] -> + I = R#route.local_hint, + mnesia:write( + #route{domain = LDomain, + pid = undefined, + local_hint = I}), + mnesia:delete_object(R); + _ -> + ok + end + end, + mnesia:transaction(F) + end + catch + _ -> + erlang:error({invalid_domain, Domain}) end. unregister_routes(Domains) -> From 3adb238b31556e7b8d21cc6caa87df4bd8bb81ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 10 Oct 2008 14:41:26 +0000 Subject: [PATCH 111/582] Fix a bug where the wrong module was called (jlib instead of exmpp_jid). PR: EJABP-1 SVN Revision: 1624 --- ChangeLog | 3 +++ src/mod_roster_odbc.erl | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7b106efc2..997cedfe0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -25,6 +25,9 @@ * src/mod_vcard_odbc.erl (do_route/4): Replace jlib:iq_to_xml/1 by exmpp_iq:iq_to_xmlel/1. + * src/mod_roster_odbc.erl (user_roster_subscribe_jid/3): Fix a bug + where the wrong module was called (jlib instead of exmpp_jid). + 2008-10-09 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Fix handling of unauthenticated stanzas which diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 8f329f7ab..cd4a32c49 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -1009,7 +1009,7 @@ user_roster_parse_query(User, Server, Items, Query) -> user_roster_subscribe_jid(User, Server, JID) -> out_subscription(User, Server, JID, subscribe), - UJID = jlib:make_bare_jid(User, Server), + UJID = exmpp_jid:make_bare_jid(User, Server), ejabberd_router:route( UJID, JID, exmpp_presence:subscribe()). @@ -1032,7 +1032,7 @@ user_roster_item_parse_query(User, Server, Items, Query) -> case lists:keysearch( "remove" ++ ejabberd_web_admin:term_to_id(JID), 1, Query) of {value, _} -> - UJID = jlib:make_bare_jid(User, Server), + UJID = exmpp_jid:make_bare_jid(User, Server), Attrs1 = exmpp_xml:set_attribute_in_list([], 'jid', exmpp_jid:jid_to_list(JID)), Attrs2 = exmpp_xml:set_attribute_in_list(Attrs1, From 02449639358d00c68ea724b2120d8d4f6983e3ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 10 Oct 2008 14:57:44 +0000 Subject: [PATCH 112/582] Replace jlib:nameprep/1 by exmpp_stringprep:nameprep/1 and change the error handling. PR: EJABP-1 SVN Revision: 1625 --- ChangeLog | 7 ++++--- src/ejabberd_ctl.erl | 25 +++++++++++++------------ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index 997cedfe0..c0da44308 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,9 +9,9 @@ exmpp_jid:jid_to_list/3. Thanks to Pablo Polvorin! * src/ejabberd_s2s_in.erl (wait_for_feature_request/2), - src/ejabberd_router.erl (register_route/2, unregister_route/1): - Replace jlib:nameprep/1 by exmpp_stringprep:nameprep/1 and change the - error handling. + src/ejabberd_router.erl (register_route/2, unregister_route/1), + src/ejabberd_ctl.erl (process/1): Replace jlib:nameprep/1 by + exmpp_stringprep:nameprep/1 and change the error handling. * src/ejabberd_config.erl (normalize_hosts/2): Replace jlib:nodeprep/1 by exmpp_stringprep:nodeprep/1 and change the error handling. @@ -28,6 +28,7 @@ * src/mod_roster_odbc.erl (user_roster_subscribe_jid/3): Fix a bug where the wrong module was called (jlib instead of exmpp_jid). + * src/ejabberd_ctl.erl (process/1): 2008-10-09 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Fix handling of unauthenticated stanzas which diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl index c66b93a38..adc54c44d 100644 --- a/src/ejabberd_ctl.erl +++ b/src/ejabberd_ctl.erl @@ -243,19 +243,20 @@ process(["delete-old-messages", Days]) -> end; process(["vhost", H | Args]) -> - case jlib:nameprep(H) of - false -> + try + Host = exmpp_stringprep:nameprep(H), + case ejabberd_hooks:run_fold( + ejabberd_ctl_process, Host, false, [Host, Args]) of + false -> + print_vhost_usage(Host), + ?STATUS_USAGE; + Status -> + Status + end + catch + _ -> ?PRINT("Bad hostname: ~p~n", [H]), - ?STATUS_ERROR; - Host -> - case ejabberd_hooks:run_fold( - ejabberd_ctl_process, Host, false, [Host, Args]) of - false -> - print_vhost_usage(Host), - ?STATUS_USAGE; - Status -> - Status - end + ?STATUS_ERROR end; process(Args) -> From 071c858055070d20bda847ee8865b0f546fc7b22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 10 Oct 2008 14:58:35 +0000 Subject: [PATCH 113/582] Don't start stringprep_sup. PR: EJABP-1 SVN Revision: 1626 --- ChangeLog | 3 ++- src/ejabberd_app.erl | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index c0da44308..4a9fb0909 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,7 +28,8 @@ * src/mod_roster_odbc.erl (user_roster_subscribe_jid/3): Fix a bug where the wrong module was called (jlib instead of exmpp_jid). - * src/ejabberd_ctl.erl (process/1): + * src/ejabberd_app.erl (start/2): Don't start stringprep_sup. + 2008-10-09 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Fix handling of unauthenticated stanzas which diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index e64c58635..75e026c66 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -44,7 +44,6 @@ start(normal, _Args) -> randoms:start(), db_init(), sha:start(), - stringprep_sup:start_link(), translate:start(), acl:start(), ejabberd_ctl:init(), From 71bfefa78831402e6ebfe20de611481313cfd7b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 10 Oct 2008 15:23:58 +0000 Subject: [PATCH 114/582] Convert to exmpp. PR: EJABP-1 SVN Revision: 1627 --- ChangeLog | 2 ++ src/ejabberd_system_monitor.erl | 41 ++++++++++++++++++--------------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4a9fb0909..5b0339c16 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,6 +30,8 @@ * src/ejabberd_app.erl (start/2): Don't start stringprep_sup. + * src/ejabberd_system_monitor.erl: Convert to exmpp. + 2008-10-09 Jean-Sébastien Pédron * src/ejabberd_c2s.erl: Fix handling of unauthenticated stanzas which diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl index e9a1a8ba3..a975d4473 100644 --- a/src/ejabberd_system_monitor.erl +++ b/src/ejabberd_system_monitor.erl @@ -38,8 +38,9 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -record(state, {}). @@ -55,15 +56,14 @@ start_link() -> process_command(From, To, Packet) -> case To of - #jid{luser = "", lresource = "watchdog"} -> - {xmlelement, Name, _Attrs, _Els} = Packet, - case Name of - "message" -> - LFrom = jlib:jid_tolower(jlib:jid_remove_resource(From)), + #jid{lnode = undefined, lresource = "watchdog"} -> + case Packet#xmlel.name of + 'message' -> + LFrom = jlib:short_prepd_bare_jid(From), case lists:member(LFrom, get_admin_jids()) of true -> - Body = xml:get_path_s( - Packet, [{elem, "body"}, cdata]), + Body = exmpp_xml:get_path( + Packet, [{element, 'body'}, cdata_as_list]), spawn(fun() -> process_flag(priority, high), process_command1(From, To, Body) @@ -168,13 +168,15 @@ process_large_heap(Pid, Info) -> "(~w) The process ~w is consuming too much memory: ~w.~n" "~s", [node(), Pid, Info, DetailedInfo]), - From = jlib:make_jid("", Host, "watchdog"), + From = exmpp_jid:make_jid(undefined, Host, "watchdog"), lists:foreach( fun(S) -> - case jlib:string_to_jid(S) of - error -> ok; - JID -> - send_message(From, JID, Body) + try + JID = exmpp_jid:list_to_jid(S), + send_message(From, JID, Body) + catch + _ -> + ok end end, JIDs); _ -> @@ -184,18 +186,19 @@ process_large_heap(Pid, Info) -> send_message(From, To, Body) -> ejabberd_router:route( From, To, - {xmlelement, "message", [{"type", "chat"}], - [{xmlelement, "body", [], - [{xmlcdata, lists:flatten(Body)}]}]}). + exmpp_message:chat(lists:flatten(Body))). get_admin_jids() -> case ejabberd_config:get_local_option(watchdog_admins) of JIDs when is_list(JIDs) -> lists:flatmap( fun(S) -> - case jlib:string_to_jid(S) of - error -> []; - JID -> [jlib:jid_tolower(JID)] + try + JID = exmpp_jid:list_to_jid(S), + [jlib:short_prepd_jid(JID)] + catch + _ -> + [] end end, JIDs); _ -> From 4a9892fa156efec0c0c9143e2a5450132d4c8174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 10 Oct 2008 15:24:47 +0000 Subject: [PATCH 115/582] Replace jlib:nameprep/1 by exmpp_stringprep:nameprep/1 and change the error handling. PR: EJABP-1 SVN Revision: 1628 --- ChangeLog | 5 +++-- src/ejabberd_rdbms.erl | 15 ++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5b0339c16..3878b0a8e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,8 +10,9 @@ * src/ejabberd_s2s_in.erl (wait_for_feature_request/2), src/ejabberd_router.erl (register_route/2, unregister_route/1), - src/ejabberd_ctl.erl (process/1): Replace jlib:nameprep/1 by - exmpp_stringprep:nameprep/1 and change the error handling. + src/ejabberd_ctl.erl (process/1), src/ejabberd_rdbms.erl + (needs_odbc/1): Replace jlib:nameprep/1 by exmpp_stringprep:nameprep/1 + and change the error handling. * src/ejabberd_config.erl (normalize_hosts/2): Replace jlib:nodeprep/1 by exmpp_stringprep:nodeprep/1 and change the error handling. diff --git a/src/ejabberd_rdbms.erl b/src/ejabberd_rdbms.erl index fcbe16cbb..d57a1ad54 100644 --- a/src/ejabberd_rdbms.erl +++ b/src/ejabberd_rdbms.erl @@ -70,9 +70,14 @@ start_odbc(Host) -> %% Returns true if we have configured odbc_server for the given host needs_odbc(Host) -> - LHost = jlib:nameprep(Host), - case ejabberd_config:get_local_option({odbc_server, LHost}) of - undefined -> - false; - _ -> true + try + LHost = exmpp_stringprep:nameprep(Host), + case ejabberd_config:get_local_option({odbc_server, LHost}) of + undefined -> + false; + _ -> true + end + catch + _ -> + false end. From 0211c8145df31ab93a0bae5e113f8823c2a260ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 13 Oct 2008 09:37:48 +0000 Subject: [PATCH 116/582] Replace jlib:nameprep/1 by exmpp_stringprep:nameprep/1. PR: EJABP-1 SVN Revision: 1646 --- ChangeLog | 5 +++++ src/extauth.erl | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 3878b0a8e..ed73c2cba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-10-13 Jean-Sébastien Pédron + + * src/extauth.erl (call_port/2): Replace jlib:nameprep/1 by + exmpp_stringprep:nameprep/1. + 2008-10-10 Jean-Sébastien Pédron * src/ejabberd_c2s.erl (is_auth_packet/1): Fix a bug where diff --git a/src/extauth.erl b/src/extauth.erl index c4acb305d..86445ec1b 100644 --- a/src/extauth.erl +++ b/src/extauth.erl @@ -56,7 +56,7 @@ set_password(User, Server, Password) -> call_port(Server, ["setpass", User, Server, Password]). call_port(Server, Msg) -> - LServer = jlib:nameprep(Server), + LServer = exmpp_stringprep:nameprep(Server), gen_mod:get_module_proc(LServer, eauth) ! {call, self(), Msg}, receive {eauth,Result} -> From 01ef834b82b81f63bd676a6b48a5876adca5084b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 13 Oct 2008 09:38:34 +0000 Subject: [PATCH 117/582] Remove the deprecated list of converted modules. PR: EJABP-1 SVN Revision: 1647 --- ChangeLog | 3 +++ src/gen_iq_handler.erl | 16 ---------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index ed73c2cba..29c948026 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,9 @@ * src/extauth.erl (call_port/2): Replace jlib:nameprep/1 by exmpp_stringprep:nameprep/1. + * src/gen_iq_handler.erl: Remove the deprecated list of converted + modules. + 2008-10-10 Jean-Sébastien Pédron * src/ejabberd_c2s.erl (is_auth_packet/1): Fix a bug where diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index a1f100c45..0a4de407f 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -49,22 +49,6 @@ module, function}). -% XXX OLD FORMAT: modules not in the following list will receive -% old format strudctures. --define(CONVERTED_MODULES, [ - mod_adhoc, - mod_annouce, - mod_caps, - mod_configure, - mod_configure2, - mod_disco, - mod_echo, - mod_offline, - mod_offline_odbc, - mod_roster, - mod_vcard -]). - %%==================================================================== %% API %%==================================================================== From 461a5eb31535ff06453fee1607693c65e650c952 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 13 Oct 2008 09:39:18 +0000 Subject: [PATCH 118/582] Convert to exmpp. PR: EJABP-1 SVN Revision: 1648 --- ChangeLog | 2 + src/jd2ejd.erl | 115 ++++++++++++++++++++++++++----------------------- 2 files changed, 62 insertions(+), 55 deletions(-) diff --git a/ChangeLog b/ChangeLog index 29c948026..e4aae94ef 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,8 @@ * src/gen_iq_handler.erl: Remove the deprecated list of converted modules. + * src/jd2ejd.erl: Convert to exmpp. + 2008-10-10 Jean-Sébastien Pédron * src/ejabberd_c2s.erl (is_auth_packet/1): Fix a bug where diff --git a/src/jd2ejd.erl b/src/jd2ejd.erl index 193566cde..c5c4a3d8b 100644 --- a/src/jd2ejd.erl +++ b/src/jd2ejd.erl @@ -31,8 +31,9 @@ -export([import_file/1, import_dir/1]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). @@ -43,26 +44,28 @@ import_file(File) -> User = filename:rootname(filename:basename(File)), Server = filename:basename(filename:dirname(File)), - case (jlib:nodeprep(User) /= error) andalso - (jlib:nameprep(Server) /= error) of + case exmpp_stringprep:is_node(User) andalso + exmpp_stringprep:is_name(Server) of true -> case file:read_file(File) of {ok, Text} -> - case xml_stream:parse_element(Text) of - El when element(1, El) == xmlelement -> - case catch process_xdb(User, Server, El) of - {'EXIT', Reason} -> - ?ERROR_MSG( - "Error while processing file \"~s\": ~p~n", - [File, Reason]), - {error, Reason}; - _ -> - ok - end; - {error, Reason} -> + try + [El] = exmpp_xml:parse_document(Text, + [namespace, name_as_atom]), + case catch process_xdb(User, Server, El) of + {'EXIT', Reason} -> + ?ERROR_MSG( + "Error while processing file \"~s\": ~p~n", + [File, Reason]), + {error, Reason}; + _ -> + ok + end + catch + _:Reason1 -> ?ERROR_MSG("Can't parse file \"~s\": ~p~n", - [File, Reason]), - {error, Reason} + [File, Reason1]), + {error, Reason1} end; {error, Reason} -> ?ERROR_MSG("Can't read file \"~s\": ~p~n", [File, Reason]), @@ -100,26 +103,23 @@ import_dir(Dir) -> %%% Internal functions %%%---------------------------------------------------------------------- -process_xdb(User, Server, {xmlelement, Name, _Attrs, Els}) -> - case Name of - "xdb" -> - lists:foreach( - fun(El) -> - xdb_data(User, Server, El) - end, Els); - _ -> - ok - end. +process_xdb(User, Server, #xmlel{name = "xdb", children = Els}) -> + lists:foreach( + fun(El) -> + xdb_data(User, Server, El) + end, Els); +process_xdb(_User, _Server, _El) -> + ok. -xdb_data(_User, _Server, {xmlcdata, _CData}) -> +xdb_data(_User, _Server, #xmlcdata{}) -> ok; -xdb_data(User, Server, {xmlelement, _Name, Attrs, _Els} = El) -> - From = jlib:make_jid(User, Server, ""), - LServer = jlib:nameprep(Server), - case xml:get_attr_s("xmlns", Attrs) of - ?NS_AUTH -> - Password = xml:get_tag_cdata(El), +xdb_data(User, Server, #xmlel{ns = NS} = El) -> + From = exmpp_jid:make_bare_jid(User, Server), + LServer = exmpp_stringprep:nameprep(Server), + case NS of + ?NS_LEGACY_AUTH -> + Password = exmpp_xml:get_cdata(El), ejabberd_auth:set_password(User, Server, Password), ok; ?NS_ROSTER -> @@ -131,9 +131,9 @@ xdb_data(User, Server, {xmlelement, _Name, Attrs, _Els} = El) -> catch mod_roster:set_items(User, Server, El) end, ok; - ?NS_LAST -> - TimeStamp = xml:get_attr_s("last", Attrs), - Status = xml:get_tag_cdata(El), + ?NS_LAST_ACTIVITY -> + TimeStamp = exmpp_xml:get_attribute(El, 'last', ""), + Status = exmpp_xml:get_cdata(El), case lists:member(mod_last_odbc, gen_mod:loaded_modules(LServer)) of true -> @@ -156,29 +156,29 @@ xdb_data(User, Server, {xmlelement, _Name, Attrs, _Els} = El) -> true -> catch mod_vcard_odbc:process_sm_iq( From, - jlib:make_jid("", Server, ""), - #iq{type = set, xmlns = ?NS_VCARD, sub_el = El}); + exmpp_jid:make_bare_jid(Server), + #iq{kind = request, type = set, ns = ?NS_VCARD, payload = El, iq_ns = ?NS_JABBER_CLIENT}); false -> catch mod_vcard:process_sm_iq( From, - jlib:make_jid("", Server, ""), - #iq{type = set, xmlns = ?NS_VCARD, sub_el = El}) + exmpp_jid:make_bare_jid(Server), + #iq{kind = request, type = set, ns = ?NS_VCARD, payload = El, iq_ns = ?NS_JABBER_CLIENT}) end, ok; "jabber:x:offline" -> process_offline(Server, From, El), ok; XMLNS -> - case xml:get_attr_s("j_private_flag", Attrs) of + case exmpp_xml:get_attribute(El, "j_private_flag", "") of "1" -> catch mod_private:process_sm_iq( From, - jlib:make_jid("", Server, ""), - #iq{type = set, xmlns = ?NS_PRIVATE, - sub_el = {xmlelement, "query", [], - [jlib:remove_attr( - "j_private_flag", - jlib:remove_attr("xdbns", El))]}}); + exmpp_jid:make_bare_jid(Server), + #iq{kind = request, type = set, ns = ?NS_PRIVATE, + iq_ns = ?NS_JABBER_CLIENT, + payload = #xmlel{name = 'query', children = + [exmpp_xml:remove_attribute( + exmpp_xml:remove_attribute(El, "xdbns"), "j_private_flag")]}}); _ -> ?DEBUG("jd2ejd: Unknown namespace \"~s\"~n", [XMLNS]) end, @@ -186,15 +186,20 @@ xdb_data(User, Server, {xmlelement, _Name, Attrs, _Els} = El) -> end. -process_offline(Server, To, {xmlelement, _, _, Els}) -> - LServer = jlib:nameprep(Server), - lists:foreach(fun({xmlelement, _, Attrs, _} = El) -> - FromS = xml:get_attr_s("from", Attrs), +process_offline(Server, To, #xmlel{children = Els}) -> + LServer = exmpp_stringprep:nameprep(Server), + lists:foreach(fun(#xmlel{} = El) -> + FromS = exmpp_stanza:get_sender(El), From = case FromS of - "" -> - jlib:make_jid("", Server, ""); + undefined -> + exmpp_jid:make_bare_jid(Server); _ -> - jlib:string_to_jid(FromS) + try + exmpp_jid:list_to_jid(FromS) + catch + _ -> + error + end end, case From of error -> From 3190c0ed6c4ab3fa51c2f2138068d2be35495233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 13 Oct 2008 09:39:58 +0000 Subject: [PATCH 119/582] Convert to exmpp. PR: EJABP-1 SVN Revision: 1649 --- ChangeLog | 2 +- src/ejd2odbc.erl | 39 ++++++++++++++++++--------------------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index e4aae94ef..e9de2947d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,7 +6,7 @@ * src/gen_iq_handler.erl: Remove the deprecated list of converted modules. - * src/jd2ejd.erl: Convert to exmpp. + * src/ejd2odbc.erl, src/jd2ejd.erl: Convert to exmpp. 2008-10-10 Jean-Sébastien Pédron diff --git a/src/ejd2odbc.erl b/src/ejd2odbc.erl index c1399f987..86b42679a 100644 --- a/src/ejd2odbc.erl +++ b/src/ejd2odbc.erl @@ -36,8 +36,9 @@ export_vcard_search/2, export_private_storage/2]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("mod_roster.hrl"). -record(offline_msg, {us, timestamp, expire, from, to, packet}). @@ -88,10 +89,10 @@ export_passwd(Server, Output) -> export_roster(Server, Output) -> export_common( Server, roster, Output, - fun(Host, #roster{usj = {LUser, LServer, LJID}} = R) + fun(Host, #roster{usj = {LUser, LServer, {N, D, Res} = _LJID}} = R) when LServer == Host -> Username = ejabberd_odbc:escape(LUser), - SJID = ejabberd_odbc:escape(jlib:jid_to_string(LJID)), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(N, D, Res)), ItemVals = record_to_string(R), ItemGroups = groups_to_string(R), ["delete from rosterusers " @@ -123,19 +124,15 @@ export_offline(Server, Output) -> packet = Packet}) when LServer == Host -> Username = ejabberd_odbc:escape(LUser), - {xmlelement, Name, Attrs, Els} = Packet, - Attrs2 = jlib:replace_from_to_attrs( - jlib:jid_to_string(From), - jlib:jid_to_string(To), - Attrs), - NewPacket = {xmlelement, Name, Attrs2, - Els ++ - [jlib:timestamp_to_xml( - calendar:now_to_universal_time(TimeStamp))]}, + Packet0 = exmpp_stanza:set_jids(Packet, + exmpp_jid:jid_to_list(From), + exmpp_jid:jid_to_list(To)), + Packet1 = exmpp_xml:append_child(Packet0, + jlib:timestamp_to_xml( + calendar:now_to_universal_time(TimeStamp))), XML = ejabberd_odbc:escape( - lists:flatten( - xml:element_to_string(NewPacket))), + exmpp_xml:document_to_list(Packet1)), ["insert into spool(username, xml) " "values ('", Username, "', '", XML, @@ -169,7 +166,7 @@ export_vcard(Server, Output) -> when LServer == Host -> Username = ejabberd_odbc:escape(LUser), SVCARD = ejabberd_odbc:escape( - lists:flatten(xml:element_to_string(VCARD))), + exmpp_xml:document_to_list(VCARD)), ["delete from vcard where username='", Username, "';" "insert into vcard(username, vcard) " "values ('", Username, "', '", SVCARD, "');"]; @@ -253,7 +250,7 @@ export_private_storage(Server, Output) -> Username = ejabberd_odbc:escape(LUser), LXMLNS = ejabberd_odbc:escape(XMLNS), SData = ejabberd_odbc:escape( - lists:flatten(xml:element_to_string(Data))), + exmpp_xml:document_to_list(Data)), odbc_queries:set_private_data_sql(Username, LXMLNS, SData); (_Host, _R) -> [] @@ -274,7 +271,7 @@ export_common(Server, Table, Output, ConvertFun) -> mnesia:transaction( fun() -> mnesia:read_lock_table(Table), - LServer = jlib:nameprep(Server), + LServer = exmpp_stringprep:nameprep(Server), {_N, SQLs} = mnesia:foldl( fun(R, {N, SQLs} = Acc) -> @@ -310,13 +307,13 @@ output(LServer, IO, SQL) -> file:write(IO, [SQL, $;, $\n]) end. -record_to_string(#roster{usj = {User, _Server, JID}, +record_to_string(#roster{usj = {User, _Server, {N, D, R} = _JID}, name = Name, subscription = Subscription, ask = Ask, askmessage = AskMessage}) -> Username = ejabberd_odbc:escape(User), - SJID = ejabberd_odbc:escape(jlib:jid_to_string(JID)), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(N, D, R)), Nick = ejabberd_odbc:escape(Name), SSubscription = case Subscription of both -> "B"; @@ -349,10 +346,10 @@ record_to_string(#roster{usj = {User, _Server, JID}, "'", SAskMessage, "'," "'N', '', 'item')"]. -groups_to_string(#roster{usj = {User, _Server, JID}, +groups_to_string(#roster{usj = {User, _Server, {N, D, R} = _JID}, groups = Groups}) -> Username = ejabberd_odbc:escape(User), - SJID = ejabberd_odbc:escape(jlib:jid_to_string(JID)), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(N, D, R)), [["(" "'", Username, "'," "'", SJID, "'," From ab2b70f189eb470979b57514d5d762dc4b71f3d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 13 Oct 2008 10:11:19 +0000 Subject: [PATCH 120/582] Merge from trunk (r1613 to 1649). PR: EJABP-1 SVN Revision: 1650 --- ChangeLog | 71 ++ doc/guide.html | 7 +- doc/guide.tex | 5 +- src/ejabberd_admin.erl | 300 +++++++- src/ejabberd_app.erl | 6 +- src/ejabberd_auth.erl | 13 +- src/ejabberd_auth_internal.erl | 6 +- src/ejabberd_auth_ldap.erl | 11 +- src/ejabberd_auth_odbc.erl | 6 +- src/ejabberd_commands.erl | 328 ++++++++ src/ejabberd_commands.hrl | 52 ++ src/ejabberd_ctl.erl | 945 ++++++++++++++++-------- src/ejabberd_listener.erl | 57 +- src/ejabberd_s2s.erl | 50 +- src/ejabberd_sm.erl | 72 +- src/ejabberd_socket.erl | 2 + src/ejabberd_sup.erl | 26 - src/ejabberdctl.template | 34 +- src/jlib.erl | 474 +----------- src/mod_configure.erl | 2 +- src/mod_offline.erl | 29 +- src/mod_offline_odbc.erl | 24 +- src/mod_proxy65/mod_proxy65.erl | 2 + src/mod_proxy65/mod_proxy65_service.erl | 47 +- src/mod_pubsub/mod_pubsub.erl | 2 +- src/web/ejabberd_web_admin.erl | 335 ++++++--- 26 files changed, 1866 insertions(+), 1040 deletions(-) create mode 100644 src/ejabberd_commands.erl create mode 100644 src/ejabberd_commands.hrl diff --git a/ChangeLog b/ChangeLog index e9de2947d..34bbb8cb0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2008-10-13 Jean-Sébastien Pédron + + Merge from trunk (r1613 to 1649). + 2008-10-13 Jean-Sébastien Pédron * src/extauth.erl (call_port/2): Replace jlib:nameprep/1 by @@ -8,6 +12,68 @@ * src/ejd2odbc.erl, src/jd2ejd.erl: Convert to exmpp. +2008-10-13 Badlop + + * src/web/ejabberd_web_admin.erl: When requesting page of + nonexistent user, show 'Not Found' page (EJAB-771) + +2008-10-12 Badlop + + * src/web/ejabberd_web_admin.erl: Run new hook + webadmin_user_parse_query when POST in web admin user + page (thanks to Oleg Palij)(EJAB-747) + * src/mod_offline.erl: Add button "Remove All Offline Messages" in + a user page (thanks to Oleg Palij)(EJAB-747) + * src/mod_offline_odbc.erl: Likewise + + * src/web/ejabberd_web_admin.erl: Improve Web Admin navigation + menu for vhosts and nodes (EJAB-734) + + * doc/guide.tex: Explain the new ejabberdctl command 'help' + * doc/guide.html: Likewise + + * src/mod_configure.erl: Update calls from ctl to + commands (EJAB-694) + * src/web/ejabberd_web_admin.erl: Likewise + + * src/ejabberd_sm.erl: Update from ctl to commands (EJAB-694) + * src/ejabberd_s2s.erl: Likewise + + * src/ejabberd_auth.erl: Update from ctl to commands (EJAB-694) + * src/ejabberd_auth_internal.erl: Likewise + * src/ejabberd_auth_ldap.erl: Likewise + * src/ejabberd_auth_odbc.erl: Likewise + + * src/ejabberdctl.template: Move help print to a separate + function (EJAB-694) + + * src/ejabberd_ctl.erl: Add frontend support for + commands (EJAB-694). Categorization and sorting of commands in + ejabberd_ctl help (EJAB-313). Lines in command line help of length + 80, and text formatting (EJAB-473) + + * src/ejabberd_app.erl: Initialize ejabberd_commands and start + ejabbed_admin (EJAB-694) + + * src/ejabberd_admin.erl: Implement commands from old + ejabberd_ctl (EJAB-694) + + * src/ejabberd_commands.erl: New 'ejabberd commands': separate + command definition and calling interface (EJAB-694) + * src/ejabberd_commands.hrl: Likewise + + * src/mod_proxy65/mod_proxy65.erl: Update so the listener starts + correctly (EJAB-303) + * src/mod_proxy65/mod_proxy65_service.erl: Likewise + + * src/ejabberd_app.erl: Start listeners explicitely at server + start after everything else (EJAB-303). Implement support in + ejabberd for 'independent listeners', which handle their + connections themselves: gen_tcp:listen, etc. + * src/ejabberd_listener.erl: Likewise + * src/ejabberd_socket.erl: Likewise + * src/ejabberd_sup.erl: Likewise + 2008-10-10 Jean-Sébastien Pédron * src/ejabberd_c2s.erl (is_auth_packet/1): Fix a bug where @@ -63,6 +129,11 @@ * src/mod_private.erl, src/mod_private_odbc.erl, src/mod_version.erl: Convert to exmpp. Thanks to Pablo Polvorin! +2008-10-07 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: uncomment pubsub_publish_item hook + call (EJAB-765) + 2008-10-07 Jerome Sautret * src/mod_roster_odbc.erl: fix MySQL multiple requests issue. diff --git a/doc/guide.html b/doc/guide.html index 320d0db62..c28115c21 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -413,8 +413,8 @@ you can execute ejabberdctl with either that system account or root.

      ejabberdctl start
       
       ejabberdctl status
      -Node ejabberd@localhost is started. Status: started
      -ejabberd is running
      +The node ejabberd@localhost is started with status: started
      +ejabberd is running in that node
       
       ejabberdctl stop
       

      If ejabberd doesn’t start correctly and a crash dump is generated, @@ -2894,7 +2894,8 @@ the available parameters are: ejabberdctl shows all the available commands in that server. The more interesting ones are:

      -status
      Check the status of the ejabberd server. +help
      Get help about ejabberdctl or any available command. Try ejabberdctl help help. +
      status
      Check the status of the ejabberd server.
      stop
      Stop the ejabberd server which is running in the machine.
      reopen-log
      If you use a tool to rotate logs, you have to configure it so that this command is executed after each rotation. diff --git a/doc/guide.tex b/doc/guide.tex index 6c62769ae..14cc4c627 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -425,8 +425,8 @@ Usage example: ejabberdctl start ejabberdctl status -Node ejabberd@localhost is started. Status: started -ejabberd is running +The node ejabberd@localhost is started with status: started +ejabberd is running in that node ejabberdctl stop \end{verbatim} @@ -3712,6 +3712,7 @@ If there is an \ejabberd{} server running in the system, \term{ejabberdctl} shows all the available commands in that server. The more interesting ones are: \begin{description} +\titem{help} Get help about ejabberdctl or any available command. Try \term{ejabberdctl help help}. \titem{status} Check the status of the \ejabberd{} server. \titem{stop} Stop the \ejabberd{} server which is running in the machine. \titem{reopen-log} If you use a tool to rotate logs, you have to configure it diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl index a0f101703..e08765fff 100644 --- a/src/ejabberd_admin.erl +++ b/src/ejabberd_admin.erl @@ -1,11 +1,7 @@ %%%------------------------------------------------------------------- %%% File : ejabberd_admin.erl %%% Author : Mickael Remond -%%% Description : This module gathers admin functions used by different -%%% access method: -%%% - ejabberdctl command-line tool -%%% - web admin interface -%%% - adhoc mode +%%% Purpose : Administrative functions and commands %%% Created : 7 May 2006 by Mickael Remond %%% %%% @@ -31,9 +27,237 @@ -module(ejabberd_admin). -author('mickael.remond@process-one.net'). --export([restore/1]). +-export([start/0, stop/0, + %% Server + status/0, reopen_log/0, + %% Accounts + register/3, unregister/2, + registered_users/1, + %% Migration + import_file/1, import_dir/1, + %% Purge DB + delete_expired_messages/0, delete_old_messages/1, + %% Mnesia + backup_mnesia/1, restore_mnesia/1, + dump_mnesia/1, load_mnesia/1, + install_fallback_mnesia/1, + dump_to_textfile/1, + restore/1 % Still used by some modules + ]). -include("ejabberd.hrl"). +-include("ejabberd_commands.hrl"). + +start() -> + ejabberd_commands:register_commands(commands()). + +stop() -> + ejabberd_commands:unregister_commands(commands()). + +%%% +%%% ejabberd commands +%%% + +commands() -> + [ + %% The commands status, stop and restart are implemented also in ejabberd_ctl + %% They are defined here so that other interfaces can use them too + #ejabberd_commands{name = status, tags = [server], + desc = "Get status of the ejabberd server", + module = ?MODULE, function = status, + args = [], result = {res, restuple}}, + #ejabberd_commands{name = stop, tags = [server], + desc = "Stop ejabberd gracefully", + module = init, function = stop, + args = [], result = {res, rescode}}, + #ejabberd_commands{name = restart, tags = [server], + desc = "Restart ejabberd gracefully", + module = init, function = restart, + args = [], result = {res, rescode}}, + #ejabberd_commands{name = reopen_log, tags = [logs, server], + desc = "Reopen the log files", + module = ?MODULE, function = reopen_log, + args = [], result = {res, rescode}}, + + #ejabberd_commands{name = register, tags = [accounts], + desc = "Register a user", + module = ?MODULE, function = register, + args = [{user, string}, {host, string}, {password, string}], + result = {res, restuple}}, + #ejabberd_commands{name = unregister, tags = [accounts], + desc = "Unregister a user", + module = ?MODULE, function = unregister, + args = [{user, string}, {host, string}], + result = {res, restuple}}, + #ejabberd_commands{name = registered_users, tags = [accounts], + desc = "List all registered users in HOST", + module = ?MODULE, function = registered_users, + args = [{host, string}], + result = {users, {list, {username, string}}}}, + + #ejabberd_commands{name = import_file, tags = [mnesia], + desc = "Import user data from jabberd-1.4 spool file", + module = ?MODULE, function = import_file, + args = [{file, string}], result = {res, restuple}}, + #ejabberd_commands{name = import_dir, tags = [mnesia], + desc = "Import user data from jabberd-1.4 spool dir", + module = ?MODULE, function = import_dir, + args = [{file, string}], + result = {res, restuple}}, + + #ejabberd_commands{name = delete_expired_messages, tags = [purge], + desc = "Delete expired offline messages from database", + module = ?MODULE, function = delete_expired_messages, + args = [], result = {res, rescode}}, + #ejabberd_commands{name = delete_old_messages, tags = [purge], + desc = "Delete offline messages older than DAYS", + module = ?MODULE, function = delete_old_messages, + args = [{days, integer}], result = {res, rescode}}, + + #ejabberd_commands{name = backup, tags = [mnesia], + desc = "Store the database to backup file", + module = ?MODULE, function = backup_mnesia, + args = [{file, string}], result = {res, restuple}}, + #ejabberd_commands{name = restore, tags = [mnesia], + desc = "Restore the database from backup file", + module = ?MODULE, function = restore_mnesia, + args = [{file, string}], result = {res, restuple}}, + #ejabberd_commands{name = dump, tags = [mnesia], + desc = "Dump the database to text file", + module = ?MODULE, function = dump_mnesia, + args = [{file, string}], result = {res, restuple}}, + #ejabberd_commands{name = load, tags = [mnesia], + desc = "Restore the database from text file", + module = ?MODULE, function = load_mnesia, + args = [{file, string}], result = {res, restuple}}, + #ejabberd_commands{name = install_fallback, tags = [mnesia], + desc = "Install the database from a fallback file", + module = ?MODULE, function = install_fallback_mnesia, + args = [{file, string}], result = {res, restuple}} + ]. + + +%%% +%%% Server management +%%% + +status() -> + {InternalStatus, ProvidedStatus} = init:get_status(), + String1 = io_lib:format("The node ~p is ~p. Status: ~p", + [node(), InternalStatus, ProvidedStatus]), + {Is_running, String2} = + case lists:keysearch(ejabberd, 1, application:which_applications()) of + false -> + {ejabberd_not_running, "ejabberd is not running in that node."}; + {value, {_, _, Version}} -> + {ok, io_lib:format("ejabberd ~s is running in that node", [Version])} + end, + {Is_running, String1 ++ String2}. + +reopen_log() -> + ejabberd_hooks:run(reopen_log_hook, []), + %% TODO: Use the Reopen log API for logger_h ? + ejabberd_logger_h:reopen_log(), + ok. + + +%%% +%%% Account management +%%% + +register(User, Host, Password) -> + case ejabberd_auth:try_register(User, Host, Password) of + {atomic, ok} -> + {ok, io_lib:format("User ~s@~s succesfully registered", [User, Host])}; + {atomic, exists} -> + String = io_lib:format("User ~s@~s already registered at node ~p", + [User, Host, node()]), + {exists, String}; + {error, Reason} -> + String = io_lib:format("Can't register user ~s@~s at node ~p: ~p", + [User, Host, node(), Reason]), + {cannot_register, String} + end. + +unregister(User, Host) -> + ejabberd_auth:remove_user(User, Host), + {ok, ""}. + +registered_users(Host) -> + Users = ejabberd_auth:get_vh_registered_users(Host), + SUsers = lists:sort(Users), + lists:map(fun({U, _S}) -> U end, SUsers). + + +%%% +%%% Migration management +%%% + +import_file(Path) -> + case jd2ejd:import_file(Path) of + ok -> + {ok, ""}; + {error, Reason} -> + String = io_lib:format("Can't import jabberd 1.4 spool file ~p at node ~p: ~p", + [filename:absname(Path), node(), Reason]), + {cannot_import_file, String} + end. + +import_dir(Path) -> + case jd2ejd:import_dir(Path) of + ok -> + {ok, ""}; + {error, Reason} -> + String = io_lib:format("Can't import jabberd 1.4 spool dir ~p at node ~p: ~p", + [filename:absname(Path), node(), Reason]), + {cannot_import_dir, String} + end. + + +%%% +%%% Purge DB +%%% + +delete_expired_messages() -> + {atomic, ok} = mod_offline:remove_expired_messages(), + ok. + +delete_old_messages(Days) -> + {atomic, _} = mod_offline:remove_old_messages(Days), + ok. + + +%%% +%%% Mnesia management +%%% + +backup_mnesia(Path) -> + case mnesia:backup(Path) of + ok -> + {ok, ""}; + {error, Reason} -> + String = io_lib:format("Can't store backup in ~p at node ~p: ~p", + [filename:absname(Path), node(), Reason]), + {cannot_backup, String} + end. + +restore_mnesia(Path) -> + case ejabberd_admin:restore(Path) of + {atomic, _} -> + {ok, ""}; + {error, Reason} -> + String = io_lib:format("Can't restore backup from ~p at node ~p: ~p", + [filename:absname(Path), node(), Reason]), + {cannot_restore, String}; + {aborted,{no_exists,Table}} -> + String = io_lib:format("Can't restore backup from ~p at node ~p: Table ~p does not exist.", + [filename:absname(Path), node(), Table]), + {table_not_exists, String}; + {aborted,enoent} -> + String = io_lib:format("Can't restore backup from ~p at node ~p: File not found.", + [filename:absname(Path), node()]), + {file_not_found, String} + end. %% Mnesia database restore %% This function is called from ejabberd_ctl, ejabberd_web_admin and @@ -71,3 +295,67 @@ module_tables(mod_roster) -> [roster]; module_tables(mod_shared_roster) -> [sr_group, sr_user]; module_tables(mod_vcard) -> [vcard, vcard_search]; module_tables(_Other) -> []. + +dump_mnesia(Path) -> + case dump_to_textfile(Path) of + ok -> + {ok, ""}; + {error, Reason} -> + String = io_lib:format("Can't store dump in ~p at node ~p: ~p", + [filename:absname(Path), node(), Reason]), + {cannot_dump, String} + end. + +dump_to_textfile(File) -> + dump_to_textfile(mnesia:system_info(is_running), file:open(File, [write])). +dump_to_textfile(yes, {ok, F}) -> + Tabs1 = lists:delete(schema, mnesia:system_info(local_tables)), + Tabs = lists:filter( + fun(T) -> + case mnesia:table_info(T, storage_type) of + disc_copies -> true; + disc_only_copies -> true; + _ -> false + end + end, Tabs1), + Defs = lists:map( + fun(T) -> {T, [{record_name, mnesia:table_info(T, record_name)}, + {attributes, mnesia:table_info(T, attributes)}]} + end, + Tabs), + io:format(F, "~p.~n", [{tables, Defs}]), + lists:foreach(fun(T) -> dump_tab(F, T) end, Tabs), + file:close(F); +dump_to_textfile(_, {ok, F}) -> + file:close(F), + {error, mnesia_not_running}; +dump_to_textfile(_, {error, Reason}) -> + {error, Reason}. + +dump_tab(F, T) -> + W = mnesia:table_info(T, wild_pattern), + {atomic,All} = mnesia:transaction( + fun() -> mnesia:match_object(T, W, read) end), + lists:foreach( + fun(Term) -> io:format(F,"~p.~n", [setelement(1, Term, T)]) end, All). + +load_mnesia(Path) -> + case mnesia:load_textfile(Path) of + {atomic, ok} -> + {ok, ""}; + {error, Reason} -> + String = io_lib:format("Can't load dump in ~p at node ~p: ~p", + [filename:absname(Path), node(), Reason]), + {cannot_load, String} + end. + +install_fallback_mnesia(Path) -> + case mnesia:install_fallback(Path) of + ok -> + {ok, ""}; + {error, Reason} -> + String = io_lib:format("Can't install fallback from ~p at node ~p: ~p", + [filename:absname(Path), node(), Reason]), + {cannot_fallback, String} + end. + diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index 75e026c66..928dd696c 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -29,7 +29,7 @@ -behaviour(application). --export([start/2, prep_stop/1, stop/1, init/0]). +-export([start_modules/0,start/2, prep_stop/1, stop/1, init/0]). -include("ejabberd.hrl"). @@ -47,6 +47,8 @@ start(normal, _Args) -> translate:start(), acl:start(), ejabberd_ctl:init(), + ejabberd_commands:init(), + ejabberd_admin:start(), gen_mod:start(), ejabberd_config:start(), ejabberd_check:config(), @@ -61,6 +63,7 @@ start(normal, _Args) -> %eprof:profile([self()]), %fprof:trace(start, "/tmp/fprof"), start_modules(), + ejabberd_listener:start_listeners(), Sup; start(_, _) -> {error, badarg}. @@ -70,6 +73,7 @@ start(_, _) -> %% before shutting down the processes of the application. prep_stop(State) -> stop_modules(), + ejabberd_admin:stop(), State. %% All the processes were killed when this function is called diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 33a575e30..2cefb6eab 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -49,14 +49,12 @@ is_user_exists_in_other_modules/3, remove_user/2, remove_user/3, - plain_password_required/1, - ctl_process_get_registered/3 + plain_password_required/1 ]). -export([auth_modules/1]). -include("ejabberd.hrl"). --include("ejabberd_ctl.hrl"). %%%---------------------------------------------------------------------- %%% API @@ -265,15 +263,6 @@ remove_user(User, Server, Password) -> M:remove_user(User, Server, Password) end, auth_modules(Server)). -ctl_process_get_registered(_Val, Host, ["registered-users"]) -> - Users = ejabberd_auth:get_vh_registered_users(Host), - NewLine = io_lib:format("~n", []), - SUsers = lists:sort(Users), - FUsers = lists:map(fun({U, _S}) -> [U, NewLine] end, SUsers), - ?PRINT("~s", [FUsers]), - {stop, ?STATUS_SUCCESS}; -ctl_process_get_registered(Val, _Host, _Args) -> - Val. %%%---------------------------------------------------------------------- %%% Internal functions diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index 1abc9f77c..ab49f89f9 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -53,14 +53,10 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- -start(Host) -> +start(_Host) -> mnesia:create_table(passwd, [{disc_copies, [node()]}, {attributes, record_info(fields, passwd)}]), update_table(), - ejabberd_ctl:register_commands( - Host, - [{"registered-users", "list all registered users"}], - ejabberd_auth, ctl_process_get_registered), ok. plain_password_required() -> diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl index 303300e48..b4128a9d1 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -112,11 +112,8 @@ start_link(Host) -> Proc = gen_mod:get_module_proc(Host, ?MODULE), gen_server:start_link({local, Proc}, ?MODULE, Host, []). -terminate(_Reason, State) -> - ejabberd_ctl:unregister_commands( - State#state.host, - [{"registered-users", "list all registered users"}], - ejabberd_auth, ctl_process_get_registered). +terminate(_Reason, _State) -> + ok. init(Host) -> State = parse_options(Host), @@ -132,10 +129,6 @@ init(Host) -> State#state.port, State#state.dn, State#state.password), - ejabberd_ctl:register_commands( - Host, - [{"registered-users", "list all registered users"}], - ejabberd_auth, ctl_process_get_registered), {ok, State}. plain_password_required() -> diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index 0daa24f8f..1938427fb 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -51,11 +51,7 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- -start(Host) -> - ejabberd_ctl:register_commands( - Host, - [{"registered-users", "list all registered users"}], - ejabberd_auth, ctl_process_get_registered), +start(_Host) -> ok. plain_password_required() -> diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl new file mode 100644 index 000000000..6440959a4 --- /dev/null +++ b/src/ejabberd_commands.erl @@ -0,0 +1,328 @@ +%%%---------------------------------------------------------------------- +%%% File : ejabberd_commands.erl +%%% Author : Badlop +%%% Purpose : Management of ejabberd commands +%%% Created : 20 May 2008 by Badlop +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2008 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%%---------------------------------------------------------------------- + +%%% @headerfile "ejabberd_commands.hrl" + +%%% @doc Management of ejabberd commands. +%%% +%%% An ejabberd command is an abstract function identified by a name, +%%% with a defined number and type of calling arguments and type of +%%% result, that can be defined in any Erlang module and executed +%%% using any valid frontend. +%%% +%%% +%%% == Define a new ejabberd command == +%%% +%%% ejabberd commands can be defined and registered in +%%% any Erlang module. +%%% +%%% Some commands are procedures; and their purpose is to perform an +%%% action in the server, so the command result is only some result +%%% code or result tuple. Other commands are inspectors, and their +%%% purpose is to gather some information about the server and return +%%% a detailed response: it can be integer, string, atom, tuple, list +%%% or a mix of those ones. +%%% +%%% The arguments and result of an ejabberd command are strictly +%%% defined. The number and format of the arguments provided when +%%% calling an ejabberd command must match the definition of that +%%% command. The format of the result provided by an ejabberd command +%%% must be exactly its definition. For example, if a command is said +%%% to return an integer, it must always return an integer (except in +%%% case of a crash). +%%% +%%% If you are developing an Erlang module that will run inside +%%% ejabberd and you want to provide a new ejabberd command to +%%% administer some task related to your module, you only need to: +%%% implement a function, define the command, and register it. +%%% +%%% +%%% === Define a new ejabberd command === +%%% +%%% An ejabberd command is defined using the Erlang record +%%% 'ejabberd_commands'. This record has several elements that you +%%% must define. Note that 'tags', 'desc' and 'longdesc' are optional. +%%% +%%% For example let's define an ejabberd command 'pow' that gets the +%%% integers 'base' and 'exponent'. Its result will be an integer +%%% 'power': +%%% +%%%
      #ejabberd_commands{name = pow, tags = [test],
      +%%%                 desc = "Return the power of base for exponent",
      +%%%                 longdesc = "This is an example command. The formula is:\n"
      +%%%                 "  power = base ^ exponent",
      +%%%                 module = ?MODULE, function = pow,
      +%%%                 args = [{base, integer}, {exponent, integer}],
      +%%%                 result = {power, integer}}
      +%%% +%%% +%%% === Implement the function associated to the command === +%%% +%%% Now implement a function in your module that matches the arguments +%%% and result of the ejabberd command. +%%% +%%% For example the function calc_power gets two integers Base and +%%% Exponent. It calculates the power and rounds to an integer: +%%% +%%%
      calc_power(Base, Exponent) ->
      +%%%    PowFloat = math:pow(Base, Exponent),
      +%%%    round(PowFloat).
      +%%% +%%% Since this function will be called by ejabberd_commands, it must be exported. +%%% Add to your module: +%%%
      -export([calc_power/2]).
      +%%% +%%% Only some types of result formats are allowed. +%%% If the format is defined as 'rescode', then your function must return: +%%% ok | true | atom() +%%% where the atoms ok and true as considered positive answers, +%%% and any other response atom is considered negative. +%%% +%%% If the format is defined as 'restuple', then the command must return: +%%% {rescode(), string()} +%%% +%%% If the format is defined as '{list, something()}', then the command +%%% must return a list of something(). +%%% +%%% +%%% === Register the command === +%%% +%%% Define this function and put inside the #ejabberd_command you +%%% defined in the beginning: +%%% +%%%
      commands() ->
      +%%%    [
      +%%%
      +%%%    ].
      +%%% +%%% You need to include this header file in order to use the record: +%%% +%%%
      -include("ejabberd_commands.hrl").
      +%%% +%%% When your module is initialized or started, register your commands: +%%% +%%%
      ejabberd_commands:register_commands(commands()),
      +%%% +%%% And when your module is stopped, unregister your commands: +%%% +%%%
      ejabberd_commands:unregister_commands(commands()),
      +%%% +%%% That's all! Now when your module is started, the command will be +%%% registered and any frontend can access it. For example: +%%% +%%%
      $ ejabberdctl help pow
      +%%%
      +%%%   Command Name: pow
      +%%%
      +%%%   Arguments: base::integer
      +%%%              exponent::integer
      +%%%
      +%%%   Returns: power::integer
      +%%%
      +%%%   Tags: test
      +%%%
      +%%%   Description: Return the power of base for exponent
      +%%%
      +%%% This is an example command. The formula is:
      +%%%  power = base ^ exponent
      +%%%
      +%%% $ ejabberdctl pow 3 4
      +%%% 81
      +%%% 
      +%%% +%%% +%%% == Execute an ejabberd command == +%%% +%%% ejabberd commands are mean to be executed using any valid +%%% frontend. An ejabberd commands is implemented in a regular Erlang +%%% function, so it is also possible to execute this function in any +%%% Erlang module, without dealing with the associated ejabberd +%%% commands. +%%% +%%% +%%% == Frontend to ejabberd commands == +%%% +%%% Currently there are two frontends to ejabberd commands: the shell +%%% script {@link ejabberd_ctl. ejabberdctl}, and the XML-RPC server +%%% ejabberd_xmlrpc. +%%% +%%% +%%% === ejabberdctl as a frontend to ejabberd commands === +%%% +%%% It is possible to use ejabberdctl to get documentation of any +%%% command. But ejabberdctl does not support all the argument types +%%% allowed in ejabberd commands, so there are some ejabberd commands +%%% that cannot be executed using ejabberdctl. +%%% +%%% Also note that the ejabberdctl shell administration script also +%%% manages ejabberdctl commands, which are unrelated to ejabberd +%%% commands and can only be executed using ejabberdctl. +%%% +%%% +%%% === ejabberd_xmlrpc as a frontend to ejabberd commands === +%%% +%%% ejabberd_xmlrpc provides an XML-RPC server to execute ejabberd commands. +%%% ejabberd_xmlrpc is a contributed module published in ejabberd-modules SVN. +%%% +%%% Since ejabberd_xmlrpc does not provide any method to get documentation +%%% of the ejabberd commands, please use ejabberdctl to know which +%%% commands are available, and their usage. +%%% +%%% The number and format of the arguments provided when calling an +%%% ejabberd command must match the definition of that command. Please +%%% make sure the XML-RPC call provides the required arguments, with +%%% the specified format. The order of the arguments in an XML-RPC +%%% call is not important, because all the data is tagged and will be +%%% correctly prepared by ejabberd_xmlrpc before executing the ejabberd +%%% command. + +%%% TODO: consider this feature: +%%% All commands are catched. If an error happens, return the restuple: +%%% {error, flattened error string} +%%% This means that ecomm call APIs (ejabberd_ctl, ejabberd_xmlrpc) need to allows this. +%%% And ejabberd_xmlrpc must be prepared to handle such an unexpected response. + + +-module(ejabberd_commands). +-author('badlop@process-one.net'). + +-export([init/0, + list_commands/0, + get_command_format/1, + get_command_definition/1, + get_tags_commands/0, + register_commands/1, + unregister_commands/1, + execute_command/2 + ]). + +-include("ejabberd_commands.hrl"). +-include("ejabberd.hrl"). + + +init() -> + ets:new(ejabberd_commands, [named_table, set, public, + {keypos, #ejabberd_commands.name}]). + +%% @spec ([ejabberd_commands()]) -> ok +%% @doc Register ejabberd commands. +%% If a command is already registered, a warning is printed and the old command is preserved. +register_commands(Commands) -> + lists:foreach( + fun(Command) -> + case ets:insert_new(ejabberd_commands, Command) of + true -> + ok; + false -> + ?WARNING_MSG("This command is already defined:~n~p", [Command]) + end + end, + Commands). + +%% @spec ([ejabberd_commands()]) -> ok +%% @doc Unregister ejabberd commands. +unregister_commands(Commands) -> + lists:foreach( + fun(Command) -> + ets:delete_object(ejabberd_commands, Command) + end, + Commands). + +%% @spec () -> [{Name::atom(), Args::[aterm()], Desc::string()}] +%% @doc Get a list of all the available commands, arguments and description. +list_commands() -> + Commands = ets:match(ejabberd_commands, + #ejabberd_commands{name = '$1', + args = '$2', + desc = '$3', + _ = '_'}), + [{A, B, C} || [A, B, C] <- Commands]. + +%% @spec (Name::atom()) -> {Args::[aterm()], Result::rterm()} | {error, command_unknown} +%% @doc Get the format of arguments and result of a command. +get_command_format(Name) -> + Matched = ets:match(ejabberd_commands, + #ejabberd_commands{name = Name, + args = '$1', + result = '$2', + _ = '_'}), + case Matched of + [] -> + {error, command_unknown}; + [[Args, Result]] -> + {Args, Result} + end. + +%% @spec (Name::atom()) -> ejabberd_commands() | command_not_found +%% @doc Get the definition record of a command. +get_command_definition(Name) -> + case ets:lookup(ejabberd_commands, Name) of + [E] -> E; + [] -> command_not_found + end. + +%% @spec (Name::atom(), Arguments) -> ResultTerm | {error, command_unknown} +%% @doc Execute a command. +execute_command(Name, Arguments) -> + case ets:lookup(ejabberd_commands, Name) of + [Command] -> + execute_command2(Command, Arguments); + [] -> + {error, command_unknown} + end. + +execute_command2(Command, Arguments) -> + Module = Command#ejabberd_commands.module, + Function = Command#ejabberd_commands.function, + apply(Module, Function, Arguments). + +%% @spec () -> [{Tag::string(), [CommandName::string()]}] +%% @doc Get all the tags and associated commands. +get_tags_commands() -> + CommandTags = ets:match(ejabberd_commands, + #ejabberd_commands{ + name = '$1', + tags = '$2', + _ = '_'}), + Dict = lists:foldl( + fun([CommandNameAtom, CTags], D) -> + CommandName = atom_to_list(CommandNameAtom), + case CTags of + [] -> + orddict:append("untagged", CommandName, D); + _ -> + lists:foldl( + fun(TagAtom, DD) -> + Tag = atom_to_list(TagAtom), + orddict:append(Tag, CommandName, DD) + end, + D, + CTags) + end + end, + orddict:new(), + CommandTags), + orddict:to_list(Dict). diff --git a/src/ejabberd_commands.hrl b/src/ejabberd_commands.hrl new file mode 100644 index 000000000..ce7aadb9b --- /dev/null +++ b/src/ejabberd_commands.hrl @@ -0,0 +1,52 @@ +%%%---------------------------------------------------------------------- +%%% +%%% ejabberd, Copyright (C) 2002-2008 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%%---------------------------------------------------------------------- + +-record(ejabberd_commands, {name, tags = [], + desc = "", longdesc = "", + module, function, + args = [], result = rescode}). + +%% @type ejabberd_commands() = #ejabberd_commands{ +%% name = atom(), +%% tags = [atom()], +%% desc = string(), +%% longdesc = string(), +%% module = atom(), +%% function = atom(), +%% args = [aterm()], +%% result = rterm() +%% }. +%% desc: Description of the command +%% args: Describe the accepted arguments. +%% This way the function that calls the command can format the +%% arguments before calling. + +%% @type atype() = integer | string | {tuple, [aterm()]} | {list, aterm()}. +%% Allowed types for arguments are integer, string, tuple and list. + +%% @type rtype() = integer | string | atom | {tuple, [rterm()]} | {list, rterm()} | rescode | restuple. +%% A rtype is either an atom or a tuple with two elements. + +%% @type aterm() = {Name::atom(), Type::atype()}. +%% An argument term is a tuple with the term name and the term type. + +%% @type rterm() = {Name::atom(), Type::rtype()}. +%% A result term is a tuple with the term name and the term type. diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl index adc54c44d..362d12c91 100644 --- a/src/ejabberd_ctl.erl +++ b/src/ejabberd_ctl.erl @@ -1,7 +1,7 @@ %%%---------------------------------------------------------------------- %%% File : ejabberd_ctl.erl %%% Author : Alexey Shchepin -%%% Purpose : Ejabberd admin tool +%%% Purpose : ejabberd command line admin tool %%% Created : 11 Jan 2004 by Alexey Shchepin %%% %%% @@ -24,43 +24,68 @@ %%% %%%---------------------------------------------------------------------- +%%% @headerfile "ejabberd_ctl.hrl" + +%%% @doc Management of ejabberdctl commands and frontend to ejabberd commands. +%%% +%%% An ejabberdctl command is an abstract function identified by a +%%% name, with a defined number of calling arguments, that can be +%%% defined in any Erlang module and executed using ejabberdctl +%%% administration script. +%%% +%%% Note: strings cannot have blankspaces +%%% +%%% Does not support commands that have arguments with ctypes: list, tuple +%%% +%%% TODO: Update the guide +%%% TODO: Mention this in the release notes +%%% Note: the commands with several words use now the underline: _ +%%% It is still possible to call the commands with dash: - +%%% but this is deprecated, and may be removed in a future version. + + -module(ejabberd_ctl). -author('alexey@process-one.net'). -export([start/0, init/0, process/1, - dump_to_textfile/1, + process2/1, register_commands/3, - register_commands/4, - unregister_commands/3, - unregister_commands/4]). + unregister_commands/3]). -include("ejabberd_ctl.hrl"). +-include("ejabberd_commands.hrl"). -include("ejabberd.hrl"). + +%%----------------------------- +%% Module +%%----------------------------- + start() -> case init:get_plain_arguments() of [SNode | Args] -> SNode1 = case string:tokens(SNode, "@") of - [_Node, _Server] -> - SNode; - _ -> - case net_kernel:longnames() of - true -> - SNode ++ "@" ++ inet_db:gethostname() ++ - "." ++ inet_db:res_option(domain); - false -> - SNode ++ "@" ++ inet_db:gethostname(); + [_Node, _Server] -> + SNode; _ -> - SNode - end - end, + case net_kernel:longnames() of + true -> + SNode ++ "@" ++ inet_db:gethostname() ++ + "." ++ inet_db:res_option(domain); + false -> + SNode ++ "@" ++ inet_db:gethostname(); + _ -> + SNode + end + end, Node = list_to_atom(SNode1), Status = case rpc:call(Node, ?MODULE, process, [Args]) of {badrpc, Reason} -> - ?PRINT("RPC failed on the node ~p: ~p~n", - [Node, Reason]), + ?PRINT("Failed RPC connection to the node ~p: ~p~n", + [Node, Reason]), + %% TODO: show minimal start help ?STATUS_BADRPC; S -> S @@ -76,16 +101,41 @@ init() -> ets:new(ejabberd_ctl_host_cmds, [named_table, set, public]). +%%----------------------------- +%% ejabberdctl Command managment +%%----------------------------- + +register_commands(CmdDescs, Module, Function) -> + ets:insert(ejabberd_ctl_cmds, CmdDescs), + ejabberd_hooks:add(ejabberd_ctl_process, + Module, Function, 50), + ok. + +unregister_commands(CmdDescs, Module, Function) -> + lists:foreach(fun(CmdDesc) -> + ets:delete_object(ejabberd_ctl_cmds, CmdDesc) + end, CmdDescs), + ejabberd_hooks:delete(ejabberd_ctl_process, + Module, Function, 50), + ok. + + +%%----------------------------- +%% Process +%%----------------------------- + +%% The commands status, stop and restart are defined here to ensure +%% they are usable even if ejabberd is completely stopped. process(["status"]) -> {InternalStatus, ProvidedStatus} = init:get_status(), - ?PRINT("Node ~p is ~p. Status: ~p~n", - [node(), InternalStatus, ProvidedStatus]), + ?PRINT("The node ~p is ~p with status: ~p~n", + [node(), InternalStatus, ProvidedStatus]), case lists:keysearch(ejabberd, 1, application:which_applications()) of false -> - ?PRINT("ejabberd is not running~n", []), + ?PRINT("ejabberd is not running in that node~n", []), ?STATUS_ERROR; - {value,_Version} -> - ?PRINT("ejabberd is running~n", []), + {value, {_, _, Version}} -> + ?PRINT("ejabberd ~s is running in that node~n", [Version]), ?STATUS_SUCCESS end; @@ -97,121 +147,6 @@ process(["restart"]) -> init:restart(), ?STATUS_SUCCESS; -process(["reopen-log"]) -> - ejabberd_hooks:run(reopen_log_hook, []), - lists:foreach(fun(Host) -> - ejabberd_hooks:run(reopen_log_hook, Host, [Host]) - end, ?MYHOSTS), - %% TODO: Use the Reopen log API for logger_h ? - ejabberd_logger_h:reopen_log(), - ?STATUS_SUCCESS; - -process(["register", User, Server, Password]) -> - case ejabberd_auth:try_register(User, Server, Password) of - {atomic, ok} -> - ?STATUS_SUCCESS; - {atomic, exists} -> - ?PRINT("User ~p already registered at node ~p~n", - [User ++ "@" ++ Server, node()]), - ?STATUS_ERROR; - {error, Reason} -> - ?PRINT("Can't register user ~p at node ~p: ~p~n", - [User ++ "@" ++ Server, node(), Reason]), - ?STATUS_ERROR - end; - -process(["unregister", User, Server]) -> - case ejabberd_auth:remove_user(User, Server) of - {error, Reason} -> - ?PRINT("Can't unregister user ~p at node ~p: ~p~n", - [User ++ "@" ++ Server, node(), Reason]), - ?STATUS_ERROR; - _ -> - ?STATUS_SUCCESS - end; - -process(["backup", Path]) -> - case mnesia:backup(Path) of - ok -> - ?STATUS_SUCCESS; - {error, Reason} -> - ?PRINT("Can't store backup in ~p at node ~p: ~p~n", - [filename:absname(Path), node(), Reason]), - ?STATUS_ERROR - end; - -process(["dump", Path]) -> - case dump_to_textfile(Path) of - ok -> - ?STATUS_SUCCESS; - {error, Reason} -> - ?PRINT("Can't store dump in ~p at node ~p: ~p~n", - [filename:absname(Path), node(), Reason]), - ?STATUS_ERROR - end; - -process(["load", Path]) -> - case mnesia:load_textfile(Path) of - {atomic, ok} -> - ?STATUS_SUCCESS; - {error, Reason} -> - ?PRINT("Can't load dump in ~p at node ~p: ~p~n", - [filename:absname(Path), node(), Reason]), - ?STATUS_ERROR - end; - -process(["restore", Path]) -> - case ejabberd_admin:restore(Path) of - {atomic, _} -> - ?STATUS_SUCCESS; - {error, Reason} -> - ?PRINT("Can't restore backup from ~p at node ~p: ~p~n", - [filename:absname(Path), node(), Reason]), - ?STATUS_ERROR; - {aborted,{no_exists,Table}} -> - ?PRINT("Can't restore backup from ~p at node ~p: Table ~p does not exist.~n", - [filename:absname(Path), node(), Table]), - ?STATUS_ERROR; - {aborted,enoent} -> - ?PRINT("Can't restore backup from ~p at node ~p: File not found.~n", - [filename:absname(Path), node()]), - ?STATUS_ERROR - end; - -process(["install-fallback", Path]) -> - case mnesia:install_fallback(Path) of - ok -> - ?STATUS_SUCCESS; - {error, Reason} -> - ?PRINT("Can't install fallback from ~p at node ~p: ~p~n", - [filename:absname(Path), node(), Reason]), - ?STATUS_ERROR - end; - -process(["import-file", Path]) -> - case jd2ejd:import_file(Path) of - ok -> - ?STATUS_SUCCESS; - {error, Reason} -> - ?PRINT("Can't import jabberd 1.4 spool file ~p at node ~p: ~p~n", - [filename:absname(Path), node(), Reason]), - ?STATUS_ERROR - end; - -process(["import-dir", Path]) -> - case jd2ejd:import_dir(Path) of - ok -> - ?STATUS_SUCCESS; - {error, Reason} -> - ?PRINT("Can't import jabberd 1.4 spool dir ~p at node ~p: ~p~n", - [filename:absname(Path), node(), Reason]), - ?STATUS_ERROR - end; - -process(["delete-expired-messages"]) -> - mod_offline:remove_expired_messages(), - ?STATUS_SUCCESS; - process(["mnesia"]) -> ?PRINT("~p~n", [mnesia:system_info(all)]), ?STATUS_SUCCESS; @@ -227,183 +162,589 @@ process(["mnesia", Arg]) when is_list(Arg) -> end, ?STATUS_SUCCESS; -process(["delete-old-messages", Days]) -> - case catch list_to_integer(Days) of - {'EXIT',{Reason, _Stack}} -> - ?PRINT("Can't delete old messages (~p). Please pass an integer as parameter.~n", - [Reason]), - ?STATUS_ERROR; - Integer when Integer >= 0 -> - {atomic, _} = mod_offline:remove_old_messages(Integer), - ?PRINT("Removed messages older than ~s days~n", [Days]), +%% The arguments --long and --dual are not documented because they are +%% automatically selected depending in the number of columns of the shell +process(["help" | Mode]) -> + {MaxC, ShCode} = get_shell_info(), + case Mode of + [] -> + print_usage(dual, MaxC, ShCode), + ?STATUS_USAGE; + ["--dual"] -> + print_usage(dual, MaxC, ShCode), + ?STATUS_USAGE; + ["--long"] -> + print_usage(long, MaxC, ShCode), + ?STATUS_USAGE; + ["--tags"] -> + print_usage_tags(MaxC, ShCode), ?STATUS_SUCCESS; - _Integer -> - ?PRINT("Can't delete old messages. Please pass a positive integer as parameter.~n", []), - ?STATUS_ERROR - end; - -process(["vhost", H | Args]) -> - try - Host = exmpp_stringprep:nameprep(H), - case ejabberd_hooks:run_fold( - ejabberd_ctl_process, Host, false, [Host, Args]) of - false -> - print_vhost_usage(Host), - ?STATUS_USAGE; - Status -> - Status - end - catch - _ -> - ?PRINT("Bad hostname: ~p~n", [H]), - ?STATUS_ERROR + ["--tags", Tag] -> + print_usage_tags(Tag, MaxC, ShCode), + ?STATUS_SUCCESS; + ["help"] -> + print_usage_help(MaxC, ShCode), + ?STATUS_SUCCESS; + [CommandString | _] -> + print_usage_commands(CommandString, MaxC, ShCode), + ?STATUS_SUCCESS end; process(Args) -> - case ejabberd_hooks:run_fold(ejabberd_ctl_process, false, [Args]) of - false -> - print_usage(), - ?STATUS_USAGE; - Status -> - Status + {String, Code} = process2(Args), + io:format(String), + io:format("\n"), + Code. + +%% @spec (Args::[string()]) -> {String::string(), Code::integer()} +process2(Args) -> + case try_run_ctp(Args) of + {String, wrong_command_arguments} + when is_list(String) -> + io:format(lists:flatten(["\n" | String]++["\n"])), + [CommandString | _] = Args, + process(["help" | [CommandString]]), + {lists:flatten(String), ?STATUS_ERROR}; + {String, Code} + when is_list(String) and is_integer(Code) -> + {lists:flatten(String), Code}; + String + when is_list(String) -> + {lists:flatten(String), ?STATUS_SUCCESS}; + Code + when is_integer(Code) -> + {"", Code}; + Other -> + {"Erroneous result: " ++ io_lib:format("~p", [Other]), ?STATUS_ERROR} end. +%%----------------------------- +%% Command calling +%%----------------------------- + +%% @spec (Args::[string()]) -> +%% String::string() | Code::integer() | {String::string(), Code::integer()} +try_run_ctp(Args) -> + try ejabberd_hooks:run_fold(ejabberd_ctl_process, false, [Args]) of + false when Args /= [] -> + try_call_command(Args); + false -> + print_usage(), + {"", ?STATUS_USAGE}; + Status -> + {"", Status} + catch + exit:Why -> + print_usage(), + {io_lib:format("Error in ejabberd ctl process: ~p", [Why]), ?STATUS_USAGE} + end. + +%% @spec (Args::[string()]) -> +%% String::string() | Code::integer() | {String::string(), Code::integer()} +try_call_command(Args) -> + try call_command(Args) of + {error, command_unknown} -> + {io_lib:format("Error: command ~p not known.", [hd(Args)]), ?STATUS_ERROR}; + {error, wrong_number_parameters} -> + {"Error: wrong number of parameters", ?STATUS_ERROR}; + Res -> + Res + catch + A:Why -> + Stack = erlang:get_stacktrace(), + {io_lib:format("Problem '~p ~p' occurred executing the command.~nStacktrace: ~p", [A, Why, Stack]), ?STATUS_ERROR} + end. + +%% @spec (Args::[string()]) -> +%% String::string() | Code::integer() | {String::string(), Code::integer()} | {error, ErrorType} +call_command([CmdString | Args]) -> + {ok, CmdStringU, _} = regexp:gsub(CmdString, "-", "_"), + Command = list_to_atom(CmdStringU), + case ejabberd_commands:get_command_format(Command) of + {error, command_unknown} -> + {error, command_unknown}; + {ArgsFormat, ResultFormat} -> + case (catch format_args(Args, ArgsFormat)) of + ArgsFormatted when is_list(ArgsFormatted) -> + Result = ejabberd_commands:execute_command(Command, + ArgsFormatted), + format_result(Result, ResultFormat); + {'EXIT', {function_clause,[{lists,zip,[A1, A2]} | _]}} -> + {NumCompa, TextCompa} = + case {length(A1), length(A2)} of + {L1, L2} when L1 < L2 -> {L2-L1, "less argument"}; + {L1, L2} when L1 > L2 -> {L1-L2, "more argument"} + end, + {io_lib:format("Error: the command ~p requires ~p ~s.", + [CmdString, NumCompa, TextCompa]), + wrong_command_arguments} + end + end. + + +%%----------------------------- +%% Format arguments +%%----------------------------- + +format_args(Args, ArgsFormat) -> + lists:foldl( + fun({{_ArgName, ArgFormat}, Arg}, Res) -> + Formatted = format_arg(Arg, ArgFormat), + Res ++ [Formatted] + end, + [], + lists:zip(ArgsFormat, Args)). + +format_arg(Arg, Format) -> + Parse = case Format of + integer -> + "~d"; + string -> + NumChars = integer_to_list(string:len(Arg)), + "~" ++ NumChars ++ "c" + end, + {ok, [Arg2], _RemainingArguments} = io_lib:fread(Parse, Arg), + Arg2. + + +%%----------------------------- +%% Format result +%%----------------------------- + +format_result(Atom, {_Name, atom}) -> + io_lib:format("~p", [Atom]); + +format_result(Int, {_Name, integer}) -> + io_lib:format("~p", [Int]); + +format_result(String, {_Name, string}) -> + io_lib:format("~s", [String]); + +format_result(Code, {_Name, rescode}) -> + make_status(Code); + +format_result({Code, Text}, {_Name, restuple}) -> + {io_lib:format("~s", [Text]), make_status(Code)}; + +%% The result is a list of something: [something()] +format_result([], {_Name, {list, _ElementsDef}}) -> + ""; +format_result([FirstElement | Elements], {_Name, {list, ElementsDef}}) -> + %% Start formatting the first element + [format_result(FirstElement, ElementsDef) | + %% If there are more elements, put always first a newline character + lists:map( + fun(Element) -> + ["\n" | format_result(Element, ElementsDef)] + end, + Elements)]; + +%% The result is a tuple with several elements: {something1(), something2(),...} +%% NOTE: the elements in the tuple are separated with tabular characters, +%% if a string is empty, it will be difficult to notice in the shell, +%% maybe a different separation character should be used, like ;;? +format_result(ElementsTuple, {_Name, {tuple, ElementsDef}}) -> + ElementsList = tuple_to_list(ElementsTuple), + [{FirstE, FirstD} | ElementsAndDef] = lists:zip(ElementsList, ElementsDef), + [format_result(FirstE, FirstD) | + lists:map( + fun({Element, ElementDef}) -> + ["\t" | format_result(Element, ElementDef)] + end, + ElementsAndDef)]. + +make_status(ok) -> ?STATUS_SUCCESS; +make_status(true) -> ?STATUS_SUCCESS; +make_status(_Error) -> ?STATUS_ERROR. + +get_list_commands() -> + try ejabberd_commands:list_commands() of + Commands -> + [tuple_command_help(Command) + || {N,_,_}=Command <- Commands, + %% Don't show again those commands, because they are already + %% announced by ejabberd_ctl itself + N /= status, N /= stop, N /= restart] + catch + exit:_ -> + [] + end. + +%% Return: {string(), [string()], string()} +tuple_command_help({Name, Args, Desc}) -> + Arguments = [atom_to_list(ArgN) || {ArgN, _ArgF} <- Args], + Prepend = case is_supported_args(Args) of + true -> ""; + false -> "*" + end, + CallString = atom_to_list(Name), + {CallString, Arguments, Prepend ++ Desc}. + +is_supported_args(Args) -> + lists:all( + fun({_Name, Format}) -> + (Format == integer) + or (Format == string) + end, + Args). + +get_list_ctls() -> + case catch ets:tab2list(ejabberd_ctl_cmds) of + {'EXIT', _} -> []; + Cs -> [{NameArgs, [], Desc} || {NameArgs, Desc} <- Cs] + end. + + +%%----------------------------- +%% Print help +%%----------------------------- + +%% Bold +-define(B1, "\e[1m"). +-define(B2, "\e[22m"). +-define(B(S), case ShCode of true -> [?B1, S, ?B2]; false -> S end). + +%% Underline +-define(U1, "\e[4m"). +-define(U2, "\e[24m"). +-define(U(S), case ShCode of true -> [?U1, S, ?U2]; false -> S end). + print_usage() -> - CmdDescs = - [{"status", "get ejabberd status"}, - {"stop", "stop ejabberd"}, - {"restart", "restart ejabberd"}, - {"reopen-log", "reopen log file"}, - {"register user server password", "register a user"}, - {"unregister user server", "unregister a user"}, - {"backup file", "store a database backup to file"}, - {"restore file", "restore a database backup from file"}, - {"install-fallback file", "install a database fallback from file"}, - {"dump file", "dump a database to a text file"}, - {"load file", "restore a database from a text file"}, - {"import-file file", "import user data from jabberd 1.4 spool file"}, - {"import-dir dir", "import user data from jabberd 1.4 spool directory"}, - {"delete-expired-messages", "delete expired offline messages from database"}, - {"delete-old-messages n", "delete offline messages older than n days from database"}, - {"mnesia [info]", "show information of Mnesia system"}, - {"vhost host ...", "execute host-specific commands"}] ++ - ets:tab2list(ejabberd_ctl_cmds), - MaxCmdLen = - lists:max(lists:map( - fun({Cmd, _Desc}) -> - length(Cmd) - end, CmdDescs)), - NewLine = io_lib:format("~n", []), - FmtCmdDescs = - lists:map( - fun({Cmd, Desc}) -> - [" ", Cmd, string:chars($\s, MaxCmdLen - length(Cmd) + 2), - Desc, NewLine] - end, CmdDescs), + {MaxC, ShCode} = get_shell_info(), + print_usage(dual, MaxC, ShCode). +print_usage(HelpMode, MaxC, ShCode) -> + AllCommands = + [ + {"status", [], "Get ejabberd status"}, + {"stop", [], "Stop ejabberd"}, + {"restart", [], "Restart ejabberd"}, + {"help", ["[--tags [tag] | com?*]"], "Show help (try: ejabberdctl help help)"}, + {"mnesia", ["[info]"], "show information of Mnesia system"}] ++ + get_list_commands() ++ + get_list_ctls(), + ?PRINT( - "Usage: ejabberdctl [--node nodename] command [options]~n" - "~n" - "Available commands in this ejabberd node:~n" - ++ FmtCmdDescs ++ - "~n" - "Examples:~n" - " ejabberdctl restart~n" - " ejabberdctl --node ejabberd@host restart~n" - " ejabberdctl vhost jabber.example.org ...~n", - []). - -print_vhost_usage(Host) -> - CmdDescs = - ets:select(ejabberd_ctl_host_cmds, - [{{{Host, '$1'}, '$2'}, [], [{{'$1', '$2'}}]}]), - MaxCmdLen = - if - CmdDescs == [] -> - 0; - true -> - lists:max(lists:map( - fun({Cmd, _Desc}) -> - length(Cmd) - end, CmdDescs)) - end, - NewLine = io_lib:format("~n", []), - FmtCmdDescs = - lists:map( - fun({Cmd, Desc}) -> - [" ", Cmd, string:chars($\s, MaxCmdLen - length(Cmd) + 2), - Desc, NewLine] - end, CmdDescs), + ["Usage: ", ?B("ejabberdctl"), " [--node ", ?U("nodename"), "] ", ?U("command"), " [options]\n" + "\n" + "Available commands in this ejabberd node:\n"], []), + print_usage_commands(HelpMode, MaxC, ShCode, AllCommands), ?PRINT( - "Usage: ejabberdctl [--node nodename] vhost hostname command [options]~n" - "~n" - "Available commands in this ejabberd node and this vhost:~n" - ++ FmtCmdDescs ++ - "~n" - "Examples:~n" - " ejabberdctl vhost "++Host++" registered-users~n", - []). + ["\n" + "Examples:\n" + " ejabberdctl restart\n" + " ejabberdctl --node ejabberd@host restart\n"], + []). -register_commands(CmdDescs, Module, Function) -> - ets:insert(ejabberd_ctl_cmds, CmdDescs), - ejabberd_hooks:add(ejabberd_ctl_process, - Module, Function, 50), - ok. +print_usage_commands(HelpMode, MaxC, ShCode, Commands) -> + CmdDescsSorted = lists:keysort(1, Commands), -register_commands(Host, CmdDescs, Module, Function) -> - ets:insert(ejabberd_ctl_host_cmds, - [{{Host, Cmd}, Desc} || {Cmd, Desc} <- CmdDescs]), - ejabberd_hooks:add(ejabberd_ctl_process, Host, - Module, Function, 50), - ok. + %% What is the length of the largest command? + {CmdArgsLenDescsSorted, Lens} = + lists:mapfoldl( + fun({Cmd, Args, Desc}, Lengths) -> + Len = + length(Cmd) + + lists:foldl(fun(Arg, R) -> + R + 1 + length(Arg) + end, + 0, + Args), + {{Cmd, Args, Len, Desc}, [Len | Lengths]} + end, + [], + CmdDescsSorted), + MaxCmdLen = case Lens of + [] -> 80; + _ -> lists:max(Lens) + end, -unregister_commands(CmdDescs, Module, Function) -> - lists:foreach(fun(CmdDesc) -> - ets:delete_object(ejabberd_ctl_cmds, CmdDesc) - end, CmdDescs), - ejabberd_hooks:delete(ejabberd_ctl_process, - Module, Function, 50), - ok. + %% For each command in the list of commands + %% Convert its definition to a line + FmtCmdDescs = format_command_lines(CmdArgsLenDescsSorted, MaxCmdLen, MaxC, ShCode, HelpMode), -unregister_commands(Host, CmdDescs, Module, Function) -> - lists:foreach(fun({Cmd, Desc}) -> - ets:delete_object(ejabberd_ctl_host_cmds, - {{Host, Cmd}, Desc}) - end, CmdDescs), - ejabberd_hooks:delete(ejabberd_ctl_process, - Module, Function, 50), - ok. - -dump_to_textfile(File) -> - dump_to_textfile(mnesia:system_info(is_running), file:open(File, write)). -dump_to_textfile(yes, {ok, F}) -> - Tabs1 = lists:delete(schema, mnesia:system_info(local_tables)), - Tabs = lists:filter( - fun(T) -> - case mnesia:table_info(T, storage_type) of - disc_copies -> true; - disc_only_copies -> true; - _ -> false - end - end, Tabs1), - Defs = lists:map( - fun(T) -> {T, [{record_name, mnesia:table_info(T, record_name)}, - {attributes, mnesia:table_info(T, attributes)}]} - end, - Tabs), - io:format(F, "~p.~n", [{tables, Defs}]), - lists:foreach(fun(T) -> dump_tab(F, T) end, Tabs), - file:close(F); -dump_to_textfile(_, {ok, F}) -> - file:close(F), - {error, mnesia_not_running}; -dump_to_textfile(_, {error, Reason}) -> - {error, Reason}. + ?PRINT([FmtCmdDescs], []). -dump_tab(F, T) -> - W = mnesia:table_info(T, wild_pattern), - {atomic,All} = mnesia:transaction( - fun() -> mnesia:match_object(T, W, read) end), +%% Get some info about the shell: +%% how many columns of width +%% and guess if it supports text formatting codes. +get_shell_info() -> + %% This function was introduced in OTP R12B-0 + try io:columns() of + {ok, C} -> {C-2, true}; + {error, enotsup} -> {78, false} + catch + _:_ -> {78, false} + end. + +%% Split this command description in several lines of proper length +prepare_description(DescInit, MaxC, Desc) -> + Words = string:tokens(Desc, " "), + prepare_long_line(DescInit, MaxC, Words). + +prepare_long_line(DescInit, MaxC, Words) -> + MaxSegmentLen = MaxC - DescInit, + MarginString = lists:duplicate(DescInit, $\s), % Put spaces + [FirstSegment | MoreSegments] = split_desc_segments(MaxSegmentLen, Words), + MoreSegmentsMixed = mix_desc_segments(MarginString, MoreSegments), + [FirstSegment | MoreSegmentsMixed]. + +mix_desc_segments(MarginString, Segments) -> + [["\n", MarginString, Segment] || Segment <- Segments]. + +split_desc_segments(MaxL, Words) -> + join(MaxL, Words). + +%% Join words in a segment, +%% but stop adding to a segment if adding this word would pass L +join(L, Words) -> + join(L, Words, 0, [], []). + +join(_L, [], _LenLastSeg, LastSeg, ResSeg) -> + ResSeg2 = [lists:reverse(LastSeg) | ResSeg], + lists:reverse(ResSeg2); +join(L, [Word | Words], LenLastSeg, LastSeg, ResSeg) -> + LWord = length(Word), + case LWord + LenLastSeg < L of + true -> + %% This word fits in the last segment + %% If this word ends with "\n", reset column counter + case string:str(Word, "\n") of + 0 -> + join(L, Words, LenLastSeg+LWord+1, [" ", Word | LastSeg], ResSeg); + _ -> + join(L, Words, LWord+1, [" ", Word | LastSeg], ResSeg) + end; + false -> + join(L, Words, LWord, [" ", Word], [lists:reverse(LastSeg) | ResSeg]) + end. + +format_command_lines(CALD, MaxCmdLen, MaxC, ShCode, dual) + when MaxC - MaxCmdLen < 40 -> + %% If the space available for descriptions is too narrow, enforce long help mode + format_command_lines(CALD, MaxCmdLen, MaxC, ShCode, long); + +format_command_lines(CALD, MaxCmdLen, MaxC, ShCode, dual) -> + lists:map( + fun({Cmd, Args, CmdArgsL, Desc}) -> + DescFmt = prepare_description(MaxCmdLen+4, MaxC, Desc), + [" ", ?B(Cmd), " ", [[?U(Arg), " "] || Arg <- Args], string:chars($\s, MaxCmdLen - CmdArgsL + 1), + DescFmt, "\n"] + end, CALD); + +format_command_lines(CALD, _MaxCmdLen, MaxC, ShCode, long) -> + lists:map( + fun({Cmd, Args, _CmdArgsL, Desc}) -> + DescFmt = prepare_description(8, MaxC, Desc), + ["\n ", ?B(Cmd), " ", [[?U(Arg), " "] || Arg <- Args], "\n", " ", + DescFmt, "\n"] + end, CALD). + + +%%----------------------------- +%% Print Tags +%%----------------------------- + +print_usage_tags(MaxC, ShCode) -> + ?PRINT("Available tags and commands:", []), + TagsCommands = ejabberd_commands:get_tags_commands(), lists:foreach( - fun(Term) -> io:format(F,"~p.~n", [setelement(1, Term, T)]) end, All). + fun({Tag, Commands} = _TagCommands) -> + ?PRINT(["\n\n ", ?B(Tag), "\n "], []), + Words = lists:sort(Commands), + Desc = prepare_long_line(5, MaxC, Words), + ?PRINT(Desc, []) + end, + TagsCommands), + ?PRINT("\n\n", []). + +print_usage_tags(Tag, MaxC, ShCode) -> + ?PRINT(["Available commands with tag ", ?B(Tag), ":", "\n"], []), + HelpMode = long, + TagsCommands = ejabberd_commands:get_tags_commands(), + CommandsNames = case lists:keysearch(Tag, 1, TagsCommands) of + {value, {Tag, CNs}} -> CNs; + false -> [] + end, + CommandsList = lists:map( + fun(NameString) -> + C = ejabberd_commands:get_command_definition(list_to_atom(NameString)), + #ejabberd_commands{name = Name, + args = Args, + desc = Desc} = C, + tuple_command_help({Name, Args, Desc}) + end, + CommandsNames), + print_usage_commands(HelpMode, MaxC, ShCode, CommandsList), + ?PRINT("\n", []). + + +%%----------------------------- +%% Print usage of 'help' command +%%----------------------------- + +print_usage_help(MaxC, ShCode) -> + LongDesc = + ["The special 'help' ejabberdctl command provides help of ejabberd commands.\n\n" + "The format is:\n ", ?B("ejabberdctl"), " ", ?B("help"), " [", ?B("--tags"), " ", ?U("[tag]"), " | ", ?U("com?*"), "]\n\n" + "The optional arguments:\n" + " ",?B("--tags")," Show all tags and the names of commands in each tag\n" + " ",?B("--tags"), " ", ?U("tag")," Show description of commands in this tag\n" + " ",?U("command")," Show detailed description of the command\n" + " ",?U("com?*")," Show detailed description of commands that match this glob.\n" + " You can use ? to match a simple character,\n" + " and * to match several characters.\n" + "\n", + "Some example usages:\n", + " ejabberdctl help\n", + " ejabberdctl help --tags\n", + " ejabberdctl help --tags accounts\n", + " ejabberdctl help register\n", + " ejabberdctl help regist*\n", + "\n", + "Please note that 'ejabberdctl help' shows all ejabberd commands,\n", + "even those that cannot be used in the shell with ejabberdctl.\n", + "Those commands can be identified because the description starts with: *"], + ArgsDef = [], + C = #ejabberd_commands{ + desc = "Show help of ejabberd commands", + longdesc = LongDesc, + args = ArgsDef, + result = {help, string}}, + print_usage_command("help", C, MaxC, ShCode). + + +%%----------------------------- +%% Print usage command +%%----------------------------- + +%% @spec (CmdSubString::string(), MaxC::integer(), ShCode::boolean()) -> ok +print_usage_commands(CmdSubString, MaxC, ShCode) -> + %% Get which command names match this substring + AllCommandsNames = [atom_to_list(Name) || {Name, _, _} <- ejabberd_commands:list_commands()], + Cmds = filter_commands(AllCommandsNames, CmdSubString), + case Cmds of + [] -> io:format("Error: not command found that match: ~p~n", [CmdSubString]); + _ -> print_usage_commands2(lists:sort(Cmds), MaxC, ShCode) + end. + +print_usage_commands2(Cmds, MaxC, ShCode) -> + %% Then for each one print it + lists:mapfoldl( + fun(Cmd, Remaining) -> + print_usage_command(Cmd, MaxC, ShCode), + case Remaining > 1 of + true -> ?PRINT([" ", lists:duplicate(MaxC, 126), " \n"], []); + false -> ok + end, + {ok, Remaining-1} + end, + length(Cmds), + Cmds). + +filter_commands(All, SubString) -> + case lists:member(SubString, All) of + true -> [SubString]; + false -> filter_commands_regexp(All, SubString) + end. + +filter_commands_regexp(All, Glob) -> + RegExp = regexp:sh_to_awk(Glob), + lists:filter( + fun(Command) -> + case regexp:first_match(Command, RegExp) of + {match, _, _} -> + true; + _ -> + false + end + end, + All). + +%% @spec (Cmd::string(), MaxC::integer(), ShCode::boolean()) -> ok +print_usage_command(Cmd, MaxC, ShCode) -> + Name = list_to_atom(Cmd), + case ejabberd_commands:get_command_definition(Name) of + command_not_found -> + io:format("Error: command ~p not known.~n", [Cmd]); + C -> + print_usage_command(Cmd, C, MaxC, ShCode) + end. + +print_usage_command(Cmd, C, MaxC, ShCode) -> + #ejabberd_commands{ + tags = TagsAtoms, + desc = Desc, + longdesc = LongDesc, + args = ArgsDef, + result = ResultDef} = C, + + NameFmt = [" ", ?B("Command Name"), ": ", Cmd, "\n"], + + %% Initial indentation of result is 13 = length(" Arguments: ") + Args = [format_usage_ctype(ArgDef, 13) || ArgDef <- ArgsDef], + ArgsMargin = lists:duplicate(13, $\s), + ArgsListFmt = case Args of + [] -> "\n"; + _ -> [ [Arg, "\n", ArgsMargin] || Arg <- Args] + end, + ArgsFmt = [" ", ?B("Arguments"), ": ", ArgsListFmt], + + %% Initial indentation of result is 11 = length(" Returns: ") + ResultFmt = format_usage_ctype(ResultDef, 11), + ReturnsFmt = [" ",?B("Returns"),": ", ResultFmt], + + XmlrpcFmt = "", %%+++ [" ",?B("XML-RPC"),": ", format_usage_xmlrpc(ArgsDef, ResultDef), "\n\n"], + + TagsFmt = [" ",?B("Tags"),": ", prepare_long_line(8, MaxC, [atom_to_list(TagA) || TagA <- TagsAtoms])], + + DescFmt = [" ",?B("Description"),": ", prepare_description(15, MaxC, Desc)], + + LongDescFmt = case LongDesc of + "" -> ""; + _ -> ["", prepare_description(0, MaxC, LongDesc), "\n\n"] + end, + + NoteEjabberdctl = case is_supported_args(ArgsDef) of + true -> ""; + false -> [" ", ?B("Note:"), " This command cannot be executed using ejabberdctl. Try ejabberd_xmlrpc.\n\n"] + end, + + ?PRINT(["\n", NameFmt, "\n", ArgsFmt, "\n", ReturnsFmt, "\n\n", XmlrpcFmt, TagsFmt, "\n\n", DescFmt, "\n\n", LongDescFmt, NoteEjabberdctl], []). + +format_usage_ctype({Name, Type}, _Indentation) + when (Type==atom) or (Type==integer) or (Type==string) or (Type==rescode) or (Type==restuple)-> + io_lib:format("~p::~p", [Name, Type]); + +format_usage_ctype({Name, {list, ElementDef}}, Indentation) -> + NameFmt = atom_to_list(Name), + Indentation2 = Indentation + length(NameFmt) + 4, + ElementFmt = format_usage_ctype(ElementDef, Indentation2), + [NameFmt, "::[ ", ElementFmt, " ]"]; + +format_usage_ctype({Name, {tuple, ElementsDef}}, Indentation) -> + NameFmt = atom_to_list(Name), + Indentation2 = Indentation + length(NameFmt) + 4, + ElementsFmt = format_usage_tuple(ElementsDef, Indentation2), + [NameFmt, "::{ " | ElementsFmt]. + +format_usage_tuple([], _Indentation) -> + []; +format_usage_tuple([ElementDef], Indentation) -> + [format_usage_ctype(ElementDef, Indentation) , " }"]; +format_usage_tuple([ElementDef | ElementsDef], Indentation) -> + ElementFmt = format_usage_ctype(ElementDef, Indentation), + MarginString = lists:duplicate(Indentation, $\s), % Put spaces + [ElementFmt, ",\n", MarginString, format_usage_tuple(ElementsDef, Indentation)]. + + +%%----------------------------- +%% Command managment +%%----------------------------- + +%%+++ +%% Struct(Integer res) create_account(Struct(String user, String server, String password)) +%%format_usage_xmlrpc(ArgsDef, ResultDef) -> +%% ["aaaa bbb ccc"]. + diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index e8bddf00e..b3753cc84 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -29,10 +29,11 @@ -export([start_link/0, init/1, start/3, init/3, + start_listeners/0, start_listener/3, - stop_listener/1, + stop_listener/2, add_listener/3, - delete_listener/1 + delete_listener/2 ]). -include("ejabberd.hrl"). @@ -42,24 +43,27 @@ start_link() -> init(_) -> + {ok, {{one_for_one, 10, 1}, []}}. + +start_listeners() -> case ejabberd_config:get_local_option(listen) of undefined -> ignore; Ls -> - {ok, {{one_for_one, 10, 1}, - lists:map( - fun({Port, Module, Opts}) -> - {Port, - {?MODULE, start, [Port, Module, Opts]}, - transient, - brutal_kill, - worker, - [?MODULE]} - end, Ls)}} + lists:map( + fun({Port, Module, Opts}) -> + start_listener(Port, Module, Opts) + end, Ls) end. - start(Port, Module, Opts) -> + %% Check if the module is an ejabberd listener or an independent listener + case Module:socket_type() of + independent -> Module:start_listener(Port, Opts); + _ -> start_dependent(Port, Module, Opts) + end. + +start_dependent(Port, Module, Opts) -> case includes_deprecated_ssl_option(Opts) of false -> {ok, proc_lib:spawn_link(?MODULE, init, @@ -130,6 +134,21 @@ accept(ListenSocket, Module, Opts) -> end. start_listener(Port, Module, Opts) -> + start_module_sup(Port, Module), + start_listener_sup(Port, Module, Opts). + +start_module_sup(_Port, Module) -> + Proc1 = gen_mod:get_module_proc("sup", Module), + ChildSpec1 = + {Proc1, + {ejabberd_tmp_sup, start_link, [Proc1, Module]}, + permanent, + infinity, + supervisor, + [ejabberd_tmp_sup]}, + catch supervisor:start_child(ejabberd_sup, ChildSpec1). + +start_listener_sup(Port, Module, Opts) -> ChildSpec = {Port, {?MODULE, start, [Port, Module, Opts]}, transient, @@ -138,9 +157,13 @@ start_listener(Port, Module, Opts) -> [?MODULE]}, supervisor:start_child(ejabberd_listeners, ChildSpec). -stop_listener(Port) -> +stop_listener(Port, Module) -> supervisor:terminate_child(ejabberd_listeners, Port), - supervisor:delete_child(ejabberd_listeners, Port). + supervisor:delete_child(ejabberd_listeners, Port), + + Proc1 = gen_mod:get_module_proc("sup", Module), + supervisor:terminate_child(ejabberd_sup, Proc1), + supervisor:delete_child(ejabberd_sup, Proc1). add_listener(Port, Module, Opts) -> Ports = case ejabberd_config:get_local_option(listen) of @@ -154,7 +177,7 @@ add_listener(Port, Module, Opts) -> ejabberd_config:add_local_option(listen, Ports2), start_listener(Port, Module, Opts). -delete_listener(Port) -> +delete_listener(Port, Module) -> Ports = case ejabberd_config:get_local_option(listen) of undefined -> []; @@ -163,5 +186,5 @@ delete_listener(Port) -> end, Ports1 = lists:keydelete(Port, 1, Ports), ejabberd_config:add_local_option(listen, Ports1), - stop_listener(Port). + stop_listener(Port, Module). diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index 53cc65e28..0806ffe5a 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -39,7 +39,8 @@ remove_connection/3, dirty_get_connections/0, allow_host/2, - ctl_process/2 + incoming_s2s_number/0, + outgoing_s2s_number/0 ]). %% gen_server callbacks @@ -49,7 +50,7 @@ -include_lib("exmpp/include/exmpp.hrl"). -include("ejabberd.hrl"). --include("ejabberd_ctl.hrl"). +-include("ejabberd_commands.hrl"). -define(DEFAULT_MAX_S2S_CONNECTIONS_NUMBER, 1). -define(DEFAULT_MAX_S2S_CONNECTIONS_NUMBER_PER_NODE, 1). @@ -182,10 +183,7 @@ init([]) -> {attributes, record_info(fields, s2s)}]), mnesia:add_table_copy(s2s, node(), ram_copies), mnesia:subscribe(system), - ejabberd_ctl:register_commands( - [{"incoming-s2s-number", "print number of incoming s2s connections on the node"}, - {"outgoing-s2s-number", "print number of outgoing s2s connections on the node"}], - ?MODULE, ctl_process), + ejabberd_commands:register_commands(commands()), {ok, #state{}}. %%-------------------------------------------------------------------- @@ -249,6 +247,7 @@ handle_info(_Info, State) -> %% The return value is ignored. %%-------------------------------------------------------------------- terminate(_Reason, _State) -> + ejabberd_commands:unregister_commands(commands()), ok. %%-------------------------------------------------------------------- @@ -453,16 +452,35 @@ is_subdomain(Domain1, Domain2) -> send_element(Pid, El) -> Pid ! {send_element, El}. -ctl_process(_Val, ["incoming-s2s-number"]) -> - N = length(supervisor:which_children(ejabberd_s2s_in_sup)), - ?PRINT("~p~n", [N]), - {stop, ?STATUS_SUCCESS}; -ctl_process(_Val, ["outgoing-s2s-number"]) -> - N = length(supervisor:which_children(ejabberd_s2s_out_sup)), - ?PRINT("~p~n", [N]), - {stop, ?STATUS_SUCCESS}; -ctl_process(Val, _Args) -> - Val. + +%%%---------------------------------------------------------------------- +%%% ejabberd commands + +commands() -> + [ + #ejabberd_commands{name = incoming_s2s_number, + tags = [stats, s2s], + desc = "Number of incoming s2s connections on the node", + module = ?MODULE, function = incoming_s2s_number, + args = [], + result = {s2s_incoming, integer}}, + #ejabberd_commands{name = outgoing_s2s_number, + tags = [stats, s2s], + desc = "Number of outgoing s2s connections on the node", + module = ?MODULE, function = outgoing_s2s_number, + args = [], + result = {s2s_outgoing, integer}} + ]. + +incoming_s2s_number() -> + length(supervisor:which_children(ejabberd_s2s_in_sup)). + +outgoing_s2s_number() -> + length(supervisor:which_children(ejabberd_s2s_out_sup)). + + +%%%---------------------------------------------------------------------- +%%% Update Mnesia tables update_tables() -> case catch mnesia:table_info(s2s, type) of diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 0ce7505bf..f4f1b0923 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -46,7 +46,9 @@ register_iq_handler/4, register_iq_handler/5, unregister_iq_handler/2, - ctl_process/2, + connected_users/0, + connected_users_number/0, + user_resources/2, get_session_pid/3, get_user_info/3, get_user_ip/3 @@ -59,7 +61,7 @@ -include_lib("exmpp/include/exmpp.hrl"). -include("ejabberd.hrl"). --include("ejabberd_ctl.hrl"). +-include("ejabberd_commands.hrl"). -record(session, {sid, usr, us, priority, info}). -record(state, {}). @@ -269,11 +271,7 @@ init([]) -> ejabberd_hooks:add(remove_user, Host, ejabberd_sm, disconnect_removed_user, 100) end, ?MYHOSTS), - ejabberd_ctl:register_commands( - [{"connected-users", "list all established sessions"}, - {"connected-users-number", "print a number of established sessions"}, - {"user-resources user server", "print user's connected resources"}], - ?MODULE, ctl_process), + ejabberd_commands:register_commands(commands()), {ok, #state{}}. @@ -353,6 +351,7 @@ handle_info(_Info, State) -> %% The return value is ignored. %%-------------------------------------------------------------------- terminate(_Reason, _State) -> + ejabberd_commands:unregister_commands(commands()), ok. %%-------------------------------------------------------------------- @@ -670,27 +669,46 @@ process_iq(From, To, Packet) -> end. -ctl_process(_Val, ["connected-users"]) -> - USRs = dirty_get_sessions_list(), - NewLine = io_lib:format("~n", []), - SUSRs = lists:sort(USRs), - FUSRs = lists:map(fun({U, S, R}) -> [U, $@, S, $/, R, NewLine] end, SUSRs), - ?PRINT("~s", [FUSRs]), - {stop, ?STATUS_SUCCESS}; -ctl_process(_Val, ["connected-users-number"]) -> - N = length(dirty_get_sessions_list()), - ?PRINT("~p~n", [N]), - {stop, ?STATUS_SUCCESS}; -ctl_process(_Val, ["user-resources", User, Server]) -> - Resources = get_user_resources(User, Server), - NewLine = io_lib:format("~n", []), - SResources = lists:sort(Resources), - FResources = lists:map(fun(R) -> [R, NewLine] end, SResources), - ?PRINT("~s", [FResources]), - {stop, ?STATUS_SUCCESS}; -ctl_process(Val, _Args) -> - Val. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% ejabberd commands +commands() -> + [ + #ejabberd_commands{name = connected_users, + tags = [session], + desc = "List all established sessions", + module = ?MODULE, function = connected_users, + args = [], + result = {connected_users, {list, {sessions, string}}}}, + #ejabberd_commands{name = connected_users_number, + tags = [session, stats], + desc = "Get the number of established sessions", + module = ?MODULE, function = connected_users_number, + args = [], + result = {num_sessions, integer}}, + #ejabberd_commands{name = user_resources, + tags = [session], + desc = "List user's connected resources", + module = ?MODULE, function = user_resources, + args = [{user, string}, {host, string}], + result = {resources, {list, {resource, string}}}} + ]. + +connected_users() -> + USRs = dirty_get_sessions_list(), + SUSRs = lists:sort(USRs), + lists:map(fun({U, S, R}) -> [U, $@, S, $/, R] end, SUSRs). + +connected_users_number() -> + length(dirty_get_sessions_list()). + +user_resources(User, Server) -> + Resources = get_user_resources(User, Server), + lists:sort(Resources). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Update Mnesia tables update_tables() -> case catch mnesia:table_info(session, attributes) of diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl index 115ffc750..ba706e4e8 100644 --- a/src/ejabberd_socket.erl +++ b/src/ejabberd_socket.erl @@ -77,6 +77,8 @@ start(Module, SockMod, Socket, Opts) -> {error, _Reason} -> SockMod:close(Socket) end; + independent -> + ok; raw -> case Module:start({SockMod, Socket}, Opts) of {ok, Pid} -> diff --git a/src/ejabberd_sup.erl b/src/ejabberd_sup.erl index 01efbfd76..8475e2592 100644 --- a/src/ejabberd_sup.erl +++ b/src/ejabberd_sup.erl @@ -99,21 +99,6 @@ init([]) -> infinity, supervisor, [ejabberd_tmp_sup]}, - C2SSupervisor = - {ejabberd_c2s_sup, - {ejabberd_tmp_sup, start_link, [ejabberd_c2s_sup, ejabberd_c2s]}, - permanent, - infinity, - supervisor, - [ejabberd_tmp_sup]}, - S2SInSupervisor = - {ejabberd_s2s_in_sup, - {ejabberd_tmp_sup, start_link, - [ejabberd_s2s_in_sup, ejabberd_s2s_in]}, - permanent, - infinity, - supervisor, - [ejabberd_tmp_sup]}, S2SOutSupervisor = {ejabberd_s2s_out_sup, {ejabberd_tmp_sup, start_link, @@ -130,14 +115,6 @@ init([]) -> infinity, supervisor, [ejabberd_tmp_sup]}, - HTTPSupervisor = - {ejabberd_http_sup, - {ejabberd_tmp_sup, start_link, - [ejabberd_http_sup, ejabberd_http]}, - permanent, - infinity, - supervisor, - [ejabberd_tmp_sup]}, HTTPPollSupervisor = {ejabberd_http_poll_sup, {ejabberd_tmp_sup, start_link, @@ -171,11 +148,8 @@ init([]) -> S2S, Local, ReceiverSupervisor, - C2SSupervisor, - S2SInSupervisor, S2SOutSupervisor, ServiceSupervisor, - HTTPSupervisor, HTTPPollSupervisor, IQSupervisor, FrontendSocketSupervisor, diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template index 02ebd56b5..15e252cdf 100644 --- a/src/ejabberdctl.template +++ b/src/ejabberdctl.template @@ -163,6 +163,23 @@ live () $ERLANG_OPTS $ARGS \"$@\"" } +help () +{ + echo "" + echo "Commands to start an ejabberd node:" + echo " start Start an ejabberd node in server mode" + echo " debug Attach an interactive Erlang shell to a running ejabberd node" + echo " live Start an ejabberd node in live (interactive) mode" + echo "" + echo "Optional parameters when starting an ejabberd node:" + echo " --config file Config ejabberd: $EJABBERD_CONFIG_PATH" + echo " --ctl-config file Config ejabberdctl: $EJABBERDCTL_CONFIG_PATH" + echo " --logs dir Directory for logs: $LOGS_DIR" + echo " --spool dir Database spool dir: $SPOOLDIR" + echo " --node nodename ejabberd node name: $ERLANG_NODE" + echo "" +} + # common control function ctl () { @@ -175,20 +192,9 @@ ctl () result=$? case $result in 0) :;; - *) - echo "" - echo "Commands to start an ejabberd node:" - echo " start Start an ejabberd node in server mode" - echo " debug Attach an interactive Erlang shell to a running ejabberd node" - echo " live Start an ejabberd node in live (interactive) mode" - echo "" - echo "Optional parameters when starting an ejabberd node:" - echo " --config file Config file of ejabberd: $EJABBERD_CONFIG_PATH" - echo " --ctl-config file Config file of ejabberdctl: $EJABBERDCTL_CONFIG_PATH" - echo " --logs dir Directory for logs: $LOGS_DIR" - echo " --spool dir Database spool dir: $SPOOLDIR" - echo " --node nodename ejabberd node name: $ERLANG_NODE" - echo "";; + 1) :;; + 2) help;; + 3) help;; esac return $result } diff --git a/src/jlib.erl b/src/jlib.erl index 73fc5fc0f..18c1c4e1a 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -27,32 +27,7 @@ -module(jlib). -author('alexey@process-one.net'). --export([make_result_iq_reply/1, - make_error_reply/3, - make_error_reply/2, - make_error_element/2, - make_correct_from_to_attrs/3, - replace_from_to_attrs/3, - replace_from_to/3, - remove_attr/2, - make_jid/3, - make_jid/1, - string_to_jid/1, - jid_to_string/1, - is_nodename/1, - tolower/1, - nodeprep/1, - nameprep/1, - resourceprep/1, - jid_tolower/1, - jid_remove_resource/1, - jid_replace_resource/2, - get_iq_namespace/1, - iq_query_info/1, - iq_query_or_response_info/1, - is_iq_request_type/1, - iq_to_xml/1, - parse_xdata_submit/1, +-export([parse_xdata_submit/1, timestamp_to_iso/1, timestamp_to_xml/1, now_to_utc_string/1, @@ -68,410 +43,21 @@ short_prepd_jid/1, short_prepd_bare_jid/1]). --include_lib("exmpp/include/exmpp_xml.hrl"). - --include("jlib.hrl"). - -%send_iq(From, To, ID, SubTags) -> -% ok. - -make_result_iq_reply({xmlelement, Name, Attrs, SubTags}) -> - NewAttrs = make_result_iq_reply_attrs(Attrs), - {xmlelement, Name, NewAttrs, SubTags}. - -make_result_iq_reply_attrs(Attrs) -> - To = xml:get_attr("to", Attrs), - From = xml:get_attr("from", Attrs), - Attrs1 = lists:keydelete("to", 1, Attrs), - Attrs2 = lists:keydelete("from", 1, Attrs1), - Attrs3 = case To of - {value, ToVal} -> - [{"from", ToVal} | Attrs2]; - _ -> - Attrs2 - end, - Attrs4 = case From of - {value, FromVal} -> - [{"to", FromVal} | Attrs3]; - _ -> - Attrs3 - end, - Attrs5 = lists:keydelete("type", 1, Attrs4), - Attrs6 = [{"type", "result"} | Attrs5], - Attrs6. - -make_error_reply({xmlelement, Name, Attrs, SubTags}, Code, Desc) -> - NewAttrs = make_error_reply_attrs(Attrs), - {xmlelement, Name, NewAttrs, SubTags ++ [{xmlelement, "error", - [{"code", Code}], - [{xmlcdata, Desc}]}]}. - -make_error_reply({xmlelement, Name, Attrs, SubTags}, Error) -> - NewAttrs = make_error_reply_attrs(Attrs), - {xmlelement, Name, NewAttrs, SubTags ++ [Error]}. - -make_error_reply_attrs(Attrs) -> - To = xml:get_attr("to", Attrs), - From = xml:get_attr("from", Attrs), - Attrs1 = lists:keydelete("to", 1, Attrs), - Attrs2 = lists:keydelete("from", 1, Attrs1), - Attrs3 = case To of - {value, ToVal} -> - [{"from", ToVal} | Attrs2]; - _ -> - Attrs2 - end, - Attrs4 = case From of - {value, FromVal} -> - [{"to", FromVal} | Attrs3]; - _ -> - Attrs3 - end, - Attrs5 = lists:keydelete("type", 1, Attrs4), - Attrs6 = [{"type", "error"} | Attrs5], - Attrs6. - -make_error_element(Code, Desc) -> - {xmlelement, "error", - [{"code", Code}], - [{xmlcdata, Desc}]}. - -make_correct_from_to_attrs(From, To, Attrs) -> - Attrs1 = lists:keydelete("from", 1, Attrs), - Attrs2 = case xml:get_attr("to", Attrs) of - {value, _} -> - Attrs1; - _ -> - [{"to", To} | Attrs1] - end, - Attrs3 = [{"from", From} | Attrs2], - Attrs3. +-include_lib("exmpp/include/exmpp.hrl"). -replace_from_to_attrs(From, To, Attrs) -> - Attrs1 = lists:keydelete("to", 1, Attrs), - Attrs2 = lists:keydelete("from", 1, Attrs1), - Attrs3 = [{"to", To} | Attrs2], - Attrs4 = [{"from", From} | Attrs3], - Attrs4. - -replace_from_to(From, To, {xmlelement, Name, Attrs, Els}) -> - NewAttrs = replace_from_to_attrs(jlib:jid_to_string(From), - jlib:jid_to_string(To), - Attrs), - {xmlelement, Name, NewAttrs, Els}. - - -remove_attr(Attr, {xmlelement, Name, Attrs, Els}) -> - NewAttrs = lists:keydelete(Attr, 1, Attrs), - {xmlelement, Name, NewAttrs, Els}. - - -make_jid(User, Server, Resource) -> - case nodeprep(User) of - error -> error; - LUser -> - case nameprep(Server) of - error -> error; - LServer -> - case resourceprep(Resource) of - error -> error; - LResource -> - #jid{user = User, - server = Server, - resource = Resource, - luser = LUser, - lserver = LServer, - lresource = LResource} - end - end - end. - -make_jid({User, Server, Resource}) -> - make_jid(User, Server, Resource). - -string_to_jid(J) -> - string_to_jid1(J, ""). - -string_to_jid1([$@ | _J], "") -> - error; -string_to_jid1([$@ | J], N) -> - string_to_jid2(J, lists:reverse(N), ""); -string_to_jid1([$/ | _J], "") -> - error; -string_to_jid1([$/ | J], N) -> - string_to_jid3(J, "", lists:reverse(N), ""); -string_to_jid1([C | J], N) -> - string_to_jid1(J, [C | N]); -string_to_jid1([], "") -> - error; -string_to_jid1([], N) -> - make_jid("", lists:reverse(N), ""). - -%% Only one "@" is admitted per JID -string_to_jid2([$@ | _J], _N, _S) -> - error; -string_to_jid2([$/ | _J], _N, "") -> - error; -string_to_jid2([$/ | J], N, S) -> - string_to_jid3(J, N, lists:reverse(S), ""); -string_to_jid2([C | J], N, S) -> - string_to_jid2(J, N, [C | S]); -string_to_jid2([], _N, "") -> - error; -string_to_jid2([], N, S) -> - make_jid(N, lists:reverse(S), ""). - -string_to_jid3([C | J], N, S, R) -> - string_to_jid3(J, N, S, [C | R]); -string_to_jid3([], N, S, R) -> - make_jid(N, S, lists:reverse(R)). - -jid_to_string(#jid{user = User, server = Server, resource = Resource}) -> - jid_to_string({User, Server, Resource}); -jid_to_string({Node, Server, Resource}) -> - S1 = case Node of - "" -> - ""; - _ -> - Node ++ "@" - end, - S2 = S1 ++ Server, - S3 = case Resource of - "" -> - S2; - _ -> - S2 ++ "/" ++ Resource - end, - S3. - - -is_nodename([]) -> - false; -is_nodename(J) -> - nodeprep(J) /= error. - - -%tolower_c(C) when C >= $A, C =< $Z -> -% C + 32; -%tolower_c(C) -> -% C. - --define(LOWER(Char), - if - Char >= $A, Char =< $Z -> - Char + 32; - true -> - Char - end). - -%tolower(S) -> -% lists:map(fun tolower_c/1, S). - -%tolower(S) -> -% [?LOWER(Char) || Char <- S]. - -% Not tail-recursive but it seems works faster than variants above -tolower([C | Cs]) -> - if - C >= $A, C =< $Z -> - [C + 32 | tolower(Cs)]; - true -> - [C | tolower(Cs)] - end; -tolower([]) -> - []. - -%tolower([C | Cs]) when C >= $A, C =< $Z -> -% [C + 32 | tolower(Cs)]; -%tolower([C | Cs]) -> -% [C | tolower(Cs)]; -%tolower([]) -> -% []. - - -nodeprep(S) when length(S) < 1024 -> - R = stringprep:nodeprep(S), - if - length(R) < 1024 -> R; - true -> error - end; -nodeprep(_) -> - error. - -nameprep(S) when length(S) < 1024 -> - R = stringprep:nameprep(S), - if - length(R) < 1024 -> R; - true -> error - end; -nameprep(_) -> - error. - -resourceprep(S) when length(S) < 1024 -> - R = stringprep:resourceprep(S), - if - length(R) < 1024 -> R; - true -> error - end; -resourceprep(_) -> - error. - - -jid_tolower(#jid{luser = U, lserver = S, lresource = R}) -> - {U, S, R}; -jid_tolower({U, S, R}) -> - case nodeprep(U) of - error -> error; - LUser -> - case nameprep(S) of - error -> error; - LServer -> - case resourceprep(R) of - error -> error; - LResource -> - {LUser, LServer, LResource} - end - end - end. - -jid_remove_resource(#jid{} = JID) -> - JID#jid{resource = "", lresource = ""}; -jid_remove_resource({U, S, _R}) -> - {U, S, ""}. - -jid_replace_resource(JID, Resource) -> - case resourceprep(Resource) of - error -> error; - LResource -> - JID#jid{resource = Resource, lresource = LResource} - end. - - -get_iq_namespace({xmlelement, Name, _Attrs, Els}) when Name == "iq" -> - case xml:remove_cdata(Els) of - [{xmlelement, _Name2, Attrs2, _Els2}] -> - xml:get_attr_s("xmlns", Attrs2); - _ -> - "" - end; -get_iq_namespace(_) -> - "". - -iq_query_info(El) -> - iq_info_internal(El, request). - -iq_query_or_response_info(El) -> - iq_info_internal(El, any). - -iq_info_internal({xmlel, NS, _, _, _, _} = El, Filter) -> - ElOld = exmpp_xml:xmlel_to_xmlelement(El, [NS], - [{'http://etherx.jabber.org/streams', "stream"}]), - iq_info_internal2(ElOld, Filter); -iq_info_internal(El, Filter) -> - catch throw(for_stacktrace), - io:format("~nJLIB: old #xmlelement:~n~p~n~p~n~n", - [El, erlang:get_stacktrace()]), - iq_info_internal2(El, Filter). - -iq_info_internal2({xmlelement, Name, Attrs, Els}, Filter) when Name == "iq" -> - %% Filter is either request or any. If it is request, any replies - %% are converted to the atom reply. - ID = xml:get_attr_s("id", Attrs), - Type = xml:get_attr_s("type", Attrs), - Lang = xml:get_attr_s("xml:lang", Attrs), - {Type1, Class} = case Type of - "set" -> {set, request}; - "get" -> {get, request}; - "result" -> {result, reply}; - "error" -> {error, reply}; - _ -> {invalid, invalid} - end, - if - Type1 == invalid -> - invalid; - Class == request; Filter == any -> - %% The iq record is a bit strange. The sub_el field is an - %% XML tuple for requests, but a list of XML tuples for - %% responses. - FilteredEls = xml:remove_cdata(Els), - {XMLNS, SubEl} = - case {Class, FilteredEls} of - {request, [{xmlelement, _Name2, Attrs2, _Els2}]} -> - {xml:get_attr_s("xmlns", Attrs2), - hd(FilteredEls)}; - {reply, _} -> - %% Find the namespace of the first non-error - %% element, if there is one. - NonErrorEls = [El || - {xmlelement, SubName, _, _} = El - <- FilteredEls, - SubName /= "error"], - {case NonErrorEls of - [NonErrorEl] -> xml:get_tag_attr_s("xmlns", NonErrorEl); - _ -> invalid - end, - FilteredEls}; - _ -> - {invalid, invalid} - end, - if XMLNS == "", Class == request -> - invalid; - true -> - #iq{id = ID, - type = Type1, - xmlns = XMLNS, - lang = Lang, - sub_el = SubEl} - end; - Class == reply, Filter /= any -> - reply - end; -iq_info_internal2(_, _) -> - not_iq. - -is_iq_request_type(set) -> true; -is_iq_request_type(get) -> true; -is_iq_request_type(_) -> false. - -iq_type_to_string(set) -> "set"; -iq_type_to_string(get) -> "get"; -iq_type_to_string(result) -> "result"; -iq_type_to_string(error) -> "error"; -iq_type_to_string(_) -> invalid. - - -iq_to_xml(#iq{id = ID, type = Type, sub_el = SubEl}) -> - if - ID /= "" -> - {xmlelement, "iq", - [{"id", ID}, {"type", iq_type_to_string(Type)}], SubEl}; - true -> - {xmlelement, "iq", - [{"type", iq_type_to_string(Type)}], SubEl} - end. - - -parse_xdata_submit({xmlel, _, _, _, Attrs, Els}) -> +parse_xdata_submit(#xmlel{attrs = Attrs, children = Els}) -> case exmpp_xml:get_attribute_from_list(Attrs, 'type', "") of "submit" -> lists:reverse(parse_xdata_fields(Els, [])); _ -> invalid - end; -parse_xdata_submit(El) -> - {xmlelement, _Name, Attrs, Els} = El, - case xml:get_attr_s("type", Attrs) of - "submit" -> - lists:reverse(parse_xdata_fields(Els, [])); - _ -> - invalid end. parse_xdata_fields([], Res) -> Res; -parse_xdata_fields([{xmlel, _, _, 'field', Attrs, SubEls} | Els], - Res) -> +parse_xdata_fields([#xmlel{name = 'field', attrs = Attrs, children = SubEls} | + Els], Res) -> case exmpp_xml:get_attribute_from_list(Attrs, 'var', "") of "" -> parse_xdata_fields(Els, Res); @@ -479,36 +65,14 @@ parse_xdata_fields([{xmlel, _, _, 'field', Attrs, SubEls} | Els], Field = {Var, lists:reverse(parse_xdata_values(SubEls, []))}, parse_xdata_fields(Els, [Field | Res]) end; -parse_xdata_fields([{xmlelement, Name, Attrs, SubEls} | Els], Res) -> - case Name of - "field" -> - case xml:get_attr_s("var", Attrs) of - "" -> - parse_xdata_fields(Els, Res); - Var -> - Field = - {Var, lists:reverse(parse_xdata_values(SubEls, []))}, - parse_xdata_fields(Els, [Field | Res]) - end; - _ -> - parse_xdata_fields(Els, Res) - end; parse_xdata_fields([_ | Els], Res) -> parse_xdata_fields(Els, Res). parse_xdata_values([], Res) -> Res; -parse_xdata_values([{xmlel, _, _, 'value', _, SubEls} | Els], Res) -> +parse_xdata_values([#xmlel{name = 'value', children = SubEls} | Els], Res) -> Val = exmpp_xml:get_cdata_from_list_as_list(SubEls), parse_xdata_values(Els, [Val | Res]); -parse_xdata_values([{xmlelement, Name, _Attrs, SubEls} | Els], Res) -> - case Name of - "value" -> - Val = xml:get_cdata(SubEls), - parse_xdata_values(Els, [Val | Res]); - _ -> - parse_xdata_values(Els, Res) - end; parse_xdata_values([_ | Els], Res) -> parse_xdata_values(Els, Res). @@ -522,7 +86,7 @@ timestamp_to_xml({{Year, Month, Day}, {Hour, Minute, Second}}) -> Timestamp = lists:flatten( io_lib:format("~4..0w~2..0w~2..0wT~2..0w:~2..0w:~2..0w", [Year, Month, Day, Hour, Minute, Second])), - exmpp_xml:set_attribute(#xmlel{ns = ?NS_DELAY, name = 'x'}, + exmpp_xml:set_attribute(#xmlel{ns = ?NS_DELAY_OLD, name = 'x'}, 'stamp', Timestamp). now_to_utc_string({MegaSecs, Secs, MicroSecs}) -> @@ -731,8 +295,8 @@ ip_to_list({A,B,C,D}) -> %% %% Empty fields are set to `undefined', not the empty string. -from_old_jid(#jid{user = Node, resource = Resource, - luser = LNode, lresource = LResource} = JID) -> +from_old_jid(#jid{node = Node, resource = Resource, + lnode = LNode, lresource = LResource} = JID) -> {Node1, LNode1} = case Node of "" -> {undefined, undefined}; _ -> {Node, LNode} @@ -741,8 +305,8 @@ from_old_jid(#jid{user = Node, resource = Resource, "" -> {undefined, undefined}; _ -> {Resource, LResource} end, - JID#jid{user = Node1, resource = Resource1, - luser = LNode1, lresource = LResource1}. + JID#jid{node = Node1, resource = Resource1, + lnode = LNode1, lresource = LResource1}. %% @spec (JID) -> New_JID %% JID = jid() @@ -751,8 +315,8 @@ from_old_jid(#jid{user = Node, resource = Resource, %% %% Empty fields are set to the empty string, not `undefined'. -to_old_jid(#jid{user = Node, resource = Resource, - luser = LNode, lresource = LResource} = JID) -> +to_old_jid(#jid{node = Node, resource = Resource, + lnode = LNode, lresource = LResource} = JID) -> {Node1, LNode1} = case Node of undefined -> {"", ""}; _ -> {Node, LNode} @@ -761,19 +325,19 @@ to_old_jid(#jid{user = Node, resource = Resource, undefined -> {"", ""}; _ -> {Resource, LResource} end, - JID#jid{user = Node1, resource = Resource1, - luser = LNode1, lresource = LResource1}. + JID#jid{node = Node1, resource = Resource1, + lnode = LNode1, lresource = LResource1}. short_jid(JID) -> - {JID#jid.user, JID#jid.server, JID#jid.resource}. + {JID#jid.node, JID#jid.domain, JID#jid.resource}. short_bare_jid(JID) -> Bare_JID = exmpp_jid:jid_to_bare_jid(JID), - {Bare_JID#jid.user, Bare_JID#jid.server, Bare_JID#jid.resource}. + {Bare_JID#jid.node, Bare_JID#jid.domain, Bare_JID#jid.resource}. short_prepd_jid(JID) -> - {JID#jid.luser, JID#jid.lserver, JID#jid.lresource}. + {JID#jid.lnode, JID#jid.ldomain, JID#jid.lresource}. short_prepd_bare_jid(JID) -> Bare_JID = exmpp_jid:jid_to_bare_jid(JID), - {Bare_JID#jid.luser, Bare_JID#jid.lserver, Bare_JID#jid.lresource}. + {Bare_JID#jid.lnode, Bare_JID#jid.ldomain, Bare_JID#jid.lresource}. diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 47c6e1336..5a760972e 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -1406,7 +1406,7 @@ set_form(_From, _Host, ["running nodes", ENode, "backup", "textfile"], _Lang, XD false -> {error, 'bad-request'}; {value, {_, [String]}} -> - case rpc:call(Node, ejabberd_ctl, dump_to_textfile, [String]) of + case rpc:call(Node, ejabberd_admin, dump_to_textfile, [String]) of {badrpc, _Reason} -> {error, 'internal-server-error'}; {error, _Reason} -> diff --git a/src/mod_offline.erl b/src/mod_offline.erl index ecabbf5c5..129c41b52 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -39,7 +39,8 @@ remove_old_messages/1, remove_user/2, webadmin_page/3, - webadmin_user/4]). + webadmin_user/4, + webadmin_user_parse_query/5]). -include_lib("exmpp/include/exmpp.hrl"). @@ -75,6 +76,8 @@ start(Host, Opts) -> ?MODULE, webadmin_page, 50), ejabberd_hooks:add(webadmin_user, Host, ?MODULE, webadmin_user, 50), + ejabberd_hooks:add(webadmin_user_parse_query, Host, + ?MODULE, webadmin_user_parse_query, 50), MaxOfflineMsgs = gen_mod:get_opt(user_max_messages, Opts, infinity), register(gen_mod:get_module_proc(Host, ?PROCNAME), spawn(?MODULE, init, [MaxOfflineMsgs])). @@ -143,6 +146,8 @@ stop(Host) -> ?MODULE, webadmin_page, 50), ejabberd_hooks:delete(webadmin_user, Host, ?MODULE, webadmin_user, 50), + ejabberd_hooks:delete(webadmin_user_parse_query, Host, + ?MODULE, webadmin_user_parse_query, 50), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), exit(whereis(Proc), stop), {wait, Proc}. @@ -642,4 +647,24 @@ webadmin_user(Acc, User, Server, Lang) -> _ -> [?C("?")] end, - Acc ++ [?XCT("h3", "Offline Messages:")] ++ FQueueLen. + Acc ++ [?XCT("h3", "Offline Messages:")] ++ FQueueLen ++ [?C(" "), ?INPUTT("submit", "removealloffline", "Remove All Offline Messages")]. + +webadmin_user_parse_query(_, "removealloffline", User, Server, _Query) -> + US = {User, Server}, + F = fun() -> + mnesia:write_lock_table(offline_msg), + lists:foreach( + fun(Msg) -> + mnesia:delete_object(Msg) + end, mnesia:dirty_read({offline_msg, US})) + end, + case mnesia:transaction(F) of + {aborted, Reason} -> + ?ERROR_MSG("Failed to remove offline messages: ~p", [Reason]), + {stop, error}; + {atomic, ok} -> + ?INFO_MSG("Removed all offline messages for ~s@~s", [User, Server]), + {stop, ok} + end; +webadmin_user_parse_query(Acc, _Action, _User, _Server, _Query) -> + Acc. diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index bc6a57ee7..a5db7a9c5 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -38,7 +38,8 @@ pop_offline_messages/3, remove_user/2, webadmin_page/3, - webadmin_user/4]). + webadmin_user/4, + webadmin_user_parse_query/5]). -include_lib("exmpp/include/exmpp.hrl"). @@ -69,6 +70,8 @@ start(Host, Opts) -> ?MODULE, webadmin_page, 50), ejabberd_hooks:add(webadmin_user, Host, ?MODULE, webadmin_user, 50), + ejabberd_hooks:add(webadmin_user_parse_query, Host, + ?MODULE, webadmin_user_parse_query, 50), MaxOfflineMsgs = gen_mod:get_opt(user_max_messages, Opts, infinity), register(gen_mod:get_module_proc(Host, ?PROCNAME), spawn(?MODULE, init, [Host, MaxOfflineMsgs])). @@ -151,6 +154,8 @@ stop(Host) -> ?MODULE, webadmin_page, 50), ejabberd_hooks:delete(webadmin_user, Host, ?MODULE, webadmin_user, 50), + ejabberd_hooks:delete(webadmin_user_parse_query, Host, + ?MODULE, webadmin_user_parse_query, 50), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), exit(whereis(Proc), stop), ok. @@ -446,7 +451,22 @@ webadmin_user(Acc, User, Server, Lang) -> _ -> [?C("?")] end, - Acc ++ [?XCT("h3", "Offline Messages:")] ++ FQueueLen. + Acc ++ [?XCT("h3", "Offline Messages:")] ++ FQueueLen ++ [?C(" "), ?INPUTT("submit", "removealloffline", "Remove All Offline Messages")]. + +webadmin_user_parse_query(_, "removealloffline", User, Server, _Query) -> + case catch odbc_queries:del_spool_msg(Server, User) of + {'EXIT', Reason} -> + ?ERROR_MSG("Failed to remove offline messages: ~p", [Reason]), + {stop, error}; + {error, Reason} -> + ?ERROR_MSG("Failed to remove offline messages: ~p", [Reason]), + {stop, error}; + _ -> + ?INFO_MSG("Removed all offline messages for ~s@~s", [User, Server]), + {stop, ok} + end; +webadmin_user_parse_query(Acc, _Action, _User, _Server, _Query) -> + Acc. %% ------------------------------------------------ %% mod_offline: number of messages quota management diff --git a/src/mod_proxy65/mod_proxy65.erl b/src/mod_proxy65/mod_proxy65.erl index 67f900520..cf00777af 100644 --- a/src/mod_proxy65/mod_proxy65.erl +++ b/src/mod_proxy65/mod_proxy65.erl @@ -42,6 +42,7 @@ -define(PROCNAME, ejabberd_mod_proxy65). start(Host, Opts) -> + mod_proxy65_service:add_listener(Host, Opts), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), ChildSpec = { Proc, {?MODULE, start_link, [Host, Opts]}, @@ -50,6 +51,7 @@ start(Host, Opts) -> supervisor:start_child(ejabberd_sup, ChildSpec). stop(Host) -> + mod_proxy65_service:delete_listener(Host), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), supervisor:terminate_child(ejabberd_sup, Proc), supervisor:delete_child(ejabberd_sup, Proc). diff --git a/src/mod_proxy65/mod_proxy65_service.erl b/src/mod_proxy65/mod_proxy65_service.erl index 36d01b9c3..2b252c122 100644 --- a/src/mod_proxy65/mod_proxy65_service.erl +++ b/src/mod_proxy65/mod_proxy65_service.erl @@ -39,7 +39,7 @@ ]). %% API. --export([start_link/2]). +-export([start_link/2, add_listener/2, delete_listener/1]). -include("ejabberd.hrl"). -include("jlib.hrl"). @@ -55,28 +55,21 @@ acl }). -%% Unused callbacks. -handle_cast(_Request, State) -> - {noreply, State}. -code_change(_OldVsn, State, _Extra) -> - {ok, State}. -handle_call(_Request, _From, State) -> - {reply, ok, State}. -%%---------------- + +%%%------------------------ +%%% gen_server callbacks +%%%------------------------ start_link(Host, Opts) -> Proc = gen_mod:get_module_proc(Host, ?PROCNAME), gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []). init([Host, Opts]) -> - {IP, State} = parse_options(Host, Opts), - NewOpts = [Host, {ip, IP} | Opts], - ejabberd_listener:add_listener(State#state.port, mod_proxy65_stream, NewOpts), + {_IP, State} = parse_options(Host, Opts), ejabberd_router:register_route(State#state.myhost), {ok, State}. -terminate(_Reason, #state{myhost=MyHost, port=Port}) -> - catch ejabberd_listener:delete_listener(Port), +terminate(_Reason, #state{myhost=MyHost}) -> ejabberd_router:unregister_route(MyHost), ok. @@ -93,10 +86,34 @@ handle_info({route, From, To, {xmlelement, "iq", _, _} = Packet}, State) -> ok end, {noreply, State}; - handle_info(_Info, State) -> {noreply, State}. +handle_call(get_port, _From, State) -> + {reply, {port, State#state.port}, State}; +handle_call(_Request, _From, State) -> + {reply, ok, State}. + +handle_cast(_Request, State) -> + {noreply, State}. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%%------------------------ +%%% Listener management +%%%------------------------ + +add_listener(Host, Opts) -> + {IP, State} = parse_options(Host, Opts), + NewOpts = [Host, {ip, IP} | Opts], + ejabberd_listener:add_listener(State#state.port,mod_proxy65_stream,NewOpts). + +delete_listener(Host) -> + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + {port, Port} = gen_server:call(Proc, get_port), + catch ejabberd_listener:delete_listener(Port, mod_proxy65_stream). + %%%------------------------ %%% IQ Processing %%%------------------------ diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index a7084fad6..f140d6e9d 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -1486,7 +1486,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> node_call(Type, publish_item, [Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload]) end end, - %%ejabberd_hooks:run(pubsub_publish_item, Host, [Host, Node, JID, service_jid(Host), ItemId, Payload]), + ejabberd_hooks:run(pubsub_publish_item, Host, [Host, Node, Publisher, service_jid(Host), ItemId, Payload]), Reply = [], case transaction(Host, Node, Action, sync_dirty) of {error, ?ERR_ITEM_NOT_FOUND} -> diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 9497efeb9..c7da8cf69 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -104,60 +104,15 @@ get_auth(Auth) -> unauthorized end. -make_xhtml(Els, global, Lang) -> - MenuItems1 = ejabberd_hooks:run_fold(webadmin_menu_main, [], [Lang]), - MenuItems2 = [?LI([?AC("/admin/"++MI_uri++"/", MI_name)]) || {MI_uri, MI_name} <- MenuItems1], - {200, [html], - {xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}, - {"xml:lang", Lang}, - {"lang", Lang}], - [{xmlelement, "head", [], - [?XCT("title", "ejabberd Web Admin"), - {xmlelement, "meta", [{"http-equiv", "Content-Type"}, - {"content", "text/html; charset=utf-8"}], []}, - {xmlelement, "link", [{"href", "/admin/favicon.ico"}, - {"type", "image/x-icon"}, - {"rel", "shortcut icon"}], []}, - {xmlelement, "link", [{"href", "/admin/style.css"}, - {"type", "text/css"}, - {"rel", "stylesheet"}], []}]}, - ?XE("body", - [?XAE("div", - [{"id", "container"}], - [?XAE("div", - [{"id", "header"}], - [?XE("h1", - [?ACT("/admin/", "Administration")] - )]), - ?XAE("div", - [{"id", "navigation"}], - [?XE("ul", - [?LI([?ACT("/admin/acls/", "Access Control Lists")]), - ?LI([?ACT("/admin/access/", "Access Rules")]), - ?LI([?ACT("/admin/vhosts/", "Virtual Hosts")]), - ?LI([?ACT("/admin/nodes/", "Nodes")]), - ?LI([?ACT("/admin/stats/", "Statistics")]) - ] ++ MenuItems2 - )]), - ?XAE("div", - [{"id", "content"}], - Els), - ?XAE("div", - [{"id", "clearcopyright"}], - [{xmlcdata, ""}])]), - ?XAE("div", - [{"id", "copyrightouter"}], - [?XAE("div", - [{"id", "copyright"}], - [?XC("p", - "ejabberd (c) 2002-2008 ProcessOne") - ])])]) - ]}}; - make_xhtml(Els, Host, Lang) -> - Base = "/admin/server/" ++ Host ++ "/", - MenuItems1 = ejabberd_hooks:run_fold(webadmin_menu_host, Host, [], [Host, Lang]), - MenuItems2 = [?LI([?AC(Base ++ MI_uri ++ "/", MI_name)]) || {MI_uri, MI_name} <- MenuItems1], + make_xhtml(Els, Host, cluster, Lang). + +%% @spec (Els, Host, Node, Lang) +%% where Host = global | string() +%% Node = cluster | atom() +make_xhtml(Els, Host, Node, Lang) -> + Base = get_base_path(Host, cluster), %% Enforcing 'cluster' on purpose here + MenuItems = make_navigation(Host, Node, Lang), {200, [html], {xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}, {"xml:lang", Lang}, @@ -166,7 +121,7 @@ make_xhtml(Els, Host, Lang) -> [?XCT("title", "ejabberd Web Admin"), {xmlelement, "meta", [{"http-equiv", "Content-Type"}, {"content", "text/html; charset=utf-8"}], []}, - {xmlelement, "link", [{"href", "/admin/favicon.ico"}, + {xmlelement, "link", [{"href", Base ++ "favicon.ico"}, {"type", "image/x-icon"}, {"rel", "shortcut icon"}], []}, {xmlelement, "link", [{"href", Base ++ "style.css"}, @@ -183,18 +138,7 @@ make_xhtml(Els, Host, Lang) -> ?XAE("div", [{"id", "navigation"}], [?XE("ul", - [?LI([?XAE("div", - [{"id", "navheadhost"}], - [?AC(Base, Host)] - )]), - ?LI([?ACT(Base ++ "acls/", "Access Control Lists")]), - ?LI([?ACT(Base ++ "access/", "Access Rules")]), - ?LI([?ACT(Base ++ "users/", "Users")]), - ?LI([?ACT(Base ++ "online-users/", "Online Users")]), - ?LI([?ACT(Base ++ "last-activity/", "Last Activity")]), - ?LI([?ACT(Base ++ "nodes/", "Nodes")]), - ?LI([?ACT(Base ++ "stats/", "Statistics")]) - ] ++ MenuItems2 + MenuItems )]), ?XAE("div", [{"id", "content"}], @@ -211,13 +155,13 @@ make_xhtml(Els, Host, Lang) -> ])])]) ]}}. +get_base_path(global, cluster) -> "/admin/"; +get_base_path(Host, cluster) -> "/admin/server/" ++ Host ++ "/"; +get_base_path(global, Node) -> "/admin/node/" ++ atom_to_list(Node) ++ "/"; +get_base_path(Host, Node) -> "/admin/server/" ++ Host ++ "/node/" ++ atom_to_list(Node) ++ "/". + css(Host) -> - Base = case Host of - global -> - "/admin/"; - _ -> - "/admin/server/" ++ Host ++ "/" - end, + Base = get_base_path(Host, cluster), " html,body { background: white; @@ -298,7 +242,7 @@ html>body #container { #navigation ul { position: absolute; - top: 54px; + top: 65px; left: 0; padding: 0 1px 1px 1px; margin: 0; @@ -306,7 +250,7 @@ html>body #container { font-size: 8pt; font-weight: bold; background: #d47911; - width: 13em; + width: 17em; } #navigation ul li { @@ -340,9 +284,20 @@ html>body #container { background: #332; } -#navheadhost { - text-align: left; - border-bottom: 2px solid #d47911; +ul li #navhead a, ul li #navheadsub a, ul li #navheadsubsub a { + text-align: center; + border-top: 2px solid #d47911; + border-bottom: 1px solid #d47911; +} + +#navheadsub, #navitemsub { + border-left: 7px solid white; + margin-left: 2px solid #d47911; +} + +#navheadsubsub, #navitemsubsub { + border-left: 14px solid white; + margin-left: 4px solid #d47911; } #lastactivity li { @@ -550,7 +505,7 @@ h3 { #content { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10pt; - padding-left: 13em; + padding-left: 17em; padding-top: 5px; } @@ -595,11 +550,12 @@ logo_fill() -> "1c5dvhSU2BpKqBXl6R0ljYGS50R5zVC+tVD+vfE6YyUexE9x7g4AAAAASUVO" "RK5CYII="). + process_admin(global, #request{path = [], lang = Lang}) -> - MenuItems1 = ejabberd_hooks:run_fold(webadmin_menu_main, [], [Lang]), - MenuItems2 = [?LI([?AC("/admin/"++MI_uri++"/", MI_name)]) || {MI_uri, MI_name} <- MenuItems1], + Base = get_base_path(global, cluster), + MenuItems2 = make_menu_items(global, cluster, Base, Lang), make_xhtml([?XCT("h1", "Administration"), ?XE("ul", [?LI([?ACT("/admin/acls/", "Access Control Lists"), ?C(" "), @@ -616,9 +572,8 @@ process_admin(global, process_admin(Host, #request{path = [], lang = Lang}) -> - Base = "/admin/server/" ++ Host ++ "/", - MenuItems1 = ejabberd_hooks:run_fold(webadmin_menu_host, Host, [], [Host, Lang]), - MenuItems2 = [?LI([?AC(Base ++ MI_uri ++ "/", MI_name)]) || {MI_uri, MI_name} <- MenuItems1], + Base = get_base_path(Host, cluster), + MenuItems2 = make_menu_items(Host, cluster, Base, Lang), make_xhtml([?XCT("h1", "Administration"), ?XE("ul", [?LI([?ACT(Base ++ "acls/", "Access Control Lists"), ?C(" "), @@ -953,8 +908,13 @@ process_admin(Host, #request{path = ["user", U], q = Query, lang = Lang}) -> - Res = user_info(U, Host, Query, Lang), - make_xhtml(Res, Host, Lang); + case ejabberd_auth:is_user_exists(U, Host) of + true -> + Res = user_info(U, Host, Query, Lang), + make_xhtml(Res, Host, Lang); + false -> + make_xhtml([?XCT("h1", "Not Found")], Host, Lang) + end; process_admin(Host, #request{path = ["nodes"], @@ -971,7 +931,7 @@ process_admin(Host, make_xhtml([?XCT("h1", "Node not found")], Host, Lang); Node -> Res = get_node(Host, Node, NPath, Query, Lang), - make_xhtml(Res, Host, Lang) + make_xhtml(Res, Host, Node, Lang) end; process_admin(Host, #request{lang = Lang} = Request) -> @@ -1515,25 +1475,31 @@ user_info(User, Server, Query, Lang) -> user_parse_query(User, Server, Query) -> - case lists:keysearch("chpassword", 1, Query) of - {value, _} -> - case lists:keysearch("password", 1, Query) of - {value, {_, undefined}} -> - error; - {value, {_, Password}} -> - ejabberd_auth:set_password(User, Server, Password), - ok; - _ -> - error - end; - _ -> - case lists:keysearch("removeuser", 1, Query) of - {value, _} -> - ejabberd_auth:remove_user(User, Server), - ok; - false -> - nothing - end + lists:foldl(fun({Action, _Value}, Acc) when Acc == nothing -> + user_parse_query1(Action, User, Server, Query); + ({_Action, _Value}, Acc) -> + Acc + end, nothing, Query). + +user_parse_query1("password", _User, _Server, _Query) -> + nothing; +user_parse_query1("chpassword", User, Server, Query) -> + case lists:keysearch("password", 1, Query) of + {value, {_, undefined}} -> + error; + {value, {_, Password}} -> + ejabberd_auth:set_password(User, Server, Password), + ok; + _ -> + error + end; +user_parse_query1("removeuser", User, Server, _Query) -> + ejabberd_auth:remove_user(User, Server), + ok; +user_parse_query1(Action, User, Server, Query) -> + case ejabberd_hooks:run_fold(webadmin_user_parse_query, Server, [], [Action, User, Server, Query]) of + [] -> nothing; + Res -> Res end. @@ -1661,8 +1627,8 @@ search_running_node(SNode, [Node | Nodes]) -> get_node(global, Node, [], Query, Lang) -> Res = node_parse_query(Node, Query), - MenuItems1 = ejabberd_hooks:run_fold(webadmin_menu_node, [], [Node, Lang]), - MenuItems2 = [?LI([?AC(MI_uri++"/", MI_name)]) || {MI_uri, MI_name} <- MenuItems1], + Base = get_base_path(global, Node), + MenuItems2 = make_menu_items(global, Node, Base, Lang), [?XC("h1", ?T("Node ") ++ atom_to_list(Node))] ++ case Res of ok -> [?CT("Submitted"), ?P]; @@ -1670,11 +1636,11 @@ get_node(global, Node, [], Query, Lang) -> nothing -> [] end ++ [?XE("ul", - [?LI([?ACT("db/", "Database")]), - ?LI([?ACT("backup/", "Backup")]), - ?LI([?ACT("ports/", "Listened Ports")]), - ?LI([?ACT("stats/", "Statistics")]), - ?LI([?ACT("update/", "Update")]) + [?LI([?ACT(Base ++ "db/", "Database")]), + ?LI([?ACT(Base ++ "backup/", "Backup")]), + ?LI([?ACT(Base ++ "ports/", "Listened Ports")]), + ?LI([?ACT(Base ++ "stats/", "Statistics")]), + ?LI([?ACT(Base ++ "update/", "Update")]) ] ++ MenuItems2), ?XAE("form", [{"action", ""}, {"method", "post"}], [?INPUTT("submit", "restart", "Restart"), @@ -1683,11 +1649,11 @@ get_node(global, Node, [], Query, Lang) -> ]; get_node(Host, Node, [], _Query, Lang) -> - MenuItems1 = ejabberd_hooks:run_fold(webadmin_menu_hostnode, Host, [], [Host, Node, Lang]), - MenuItems2 = [?LI([?AC(MI_uri++"/", MI_name)]) || {MI_uri, MI_name} <- MenuItems1], + Base = get_base_path(Host, Node), + MenuItems2 = make_menu_items(global, Node, Base, Lang), [?XC("h1", ?T("Node ") ++ atom_to_list(Node)), ?XE("ul", - [?LI([?ACT("modules/", "Modules")])] ++ MenuItems2) + [?LI([?ACT(Base ++ "modules/", "Modules")])] ++ MenuItems2) ]; get_node(global, Node, ["db"], Query, Lang) -> @@ -2022,7 +1988,7 @@ node_backup_parse_query(Node, Query) -> rpc:call(Node, mnesia, install_fallback, [Path]); "dump" -> - rpc:call(Node, ejabberd_ctl, + rpc:call(Node, ejabberd_admin, dump_to_textfile, [Path]); "load" -> rpc:call(Node, mnesia, @@ -2087,7 +2053,7 @@ node_ports_to_xhtml(Ports, Lang) -> node_ports_parse_query(Node, Ports, Query) -> lists:foreach( - fun({Port, _Module1, _Opts1}) -> + fun({Port, Module1, _Opts1}) -> SPort = integer_to_list(Port), case lists:keysearch("add" ++ SPort, 1, Query) of {value, _} -> @@ -2097,13 +2063,13 @@ node_ports_parse_query(Node, Ports, Query) -> Module = list_to_atom(SModule), {ok, Tokens, _} = erl_scan:string(SOpts ++ "."), {ok, Opts} = erl_parse:parse_term(Tokens), - rpc:call(Node, ejabberd_listener, delete_listener, [Port]), + rpc:call(Node, ejabberd_listener, delete_listener, [Port, Module]), rpc:call(Node, ejabberd_listener, add_listener, [Port, Module, Opts]), throw(submitted); _ -> case lists:keysearch("delete" ++ SPort, 1, Query) of {value, _} -> - rpc:call(Node, ejabberd_listener, delete_listener, [Port]), + rpc:call(Node, ejabberd_listener, delete_listener, [Port, Module1]), throw(submitted); _ -> ok @@ -2276,3 +2242,134 @@ last_modified() -> {"Last-Modified", "Mon, 25 Feb 2008 13:23:30 GMT"}. cache_control_public() -> {"Cache-Control", "public"}. + + +%%% +%%% Navigation Menu +%%% + +%% @spec (Host, Node, Lang) -> [LI] +make_navigation(Host, Node, Lang) -> + HostNodeMenu = make_host_node_menu(Host, Node, Lang), + HostMenu = make_host_menu(Host, HostNodeMenu, Lang), + NodeMenu = make_node_menu(Host, Node, Lang), + Menu = make_server_menu(HostMenu, NodeMenu, Lang), + make_menu_items(Lang, Menu). + +%% @spec (Host, Node, Base, Lang) -> [LI] +make_menu_items(global, cluster, Base, Lang) -> + HookItems = get_menu_items_hook(server, Lang), + make_menu_items(Lang, {Base, "", HookItems}); + +make_menu_items(global, _Node, Base, Lang) -> + HookItems = get_menu_items_hook(node, Lang), + make_menu_items(Lang, {Base, "", HookItems}); + +make_menu_items(Host, cluster, Base, Lang) -> + HookItems = get_menu_items_hook({host, Host}, Lang), + make_menu_items(Lang, {Base, "", HookItems}); + +make_menu_items(Host, _Node, Base, Lang) -> + HookItems = get_menu_items_hook({hostnode, Host}, Lang), + make_menu_items(Lang, {Base, "", HookItems}). + + +make_host_node_menu(global, _, _Lang) -> + {"", "", []}; +make_host_node_menu(_, cluster, _Lang) -> + {"", "", []}; +make_host_node_menu(Host, Node, Lang) -> + HostNodeBase = get_base_path(Host, Node), + HostNodeFixed = [{"modules/", "Modules"}], + HostNodeHook = get_menu_items_hook({hostnode, Host}, Lang), + {HostNodeBase, atom_to_list(Node), HostNodeFixed ++ HostNodeHook}. + +make_host_menu(global, _HostNodeMenu, _Lang) -> + {"", "", []}; +make_host_menu(Host, HostNodeMenu, Lang) -> + HostBase = get_base_path(Host, cluster), + HostFixed = [{"acls", "Access Control Lists"}, + {"access", "Access Rules"}, + {"users", "Users"}, + {"online-users", "Online Users"}, + {"last-activity", "Last Activity"}, + {"nodes", "Nodes", HostNodeMenu}, + {"stats", "Statistics"}], + HostHook = get_menu_items_hook({host, Host}, Lang), + {HostBase, Host, HostFixed ++ HostHook}. + +make_node_menu(_Host, cluster, _Lang) -> + {"", "", []}; +make_node_menu(global, Node, Lang) -> + NodeBase = get_base_path(global, Node), + NodeFixed = [{"db/", "Database"}, + {"backup/", "Backup"}, + {"ports/", "Listened Ports"}, + {"stats/", "Statistics"}, + {"update/", "Update"}], + NodeHook = get_menu_items_hook(node, Lang), + {NodeBase, atom_to_list(Node), NodeFixed ++ NodeHook}; +make_node_menu(_Host, _Node, _Lang) -> + {"", "", []}. + +make_server_menu(HostMenu, NodeMenu, Lang) -> + Base = get_base_path(global, cluster), + Fixed = [{"acls", "Access Control Lists"}, + {"access", "Access Rules"}, + {"vhosts", "Virtual Hosts", HostMenu}, + {"nodes", "Nodes", NodeMenu}, + {"stats", "Statistics"}], + Hook = get_menu_items_hook(server, Lang), + {Base, "ejabberd", Fixed ++ Hook}. + + +get_menu_items_hook({hostnode, Host}, Lang) -> + ejabberd_hooks:run_fold(webadmin_menu_hostnode, Host, [], [Host, Lang]); +get_menu_items_hook({host, Host}, Lang) -> + ejabberd_hooks:run_fold(webadmin_menu_host, Host, [], [Host, Lang]); +get_menu_items_hook(node, Lang) -> + ejabberd_hooks:run_fold(webadmin_menu_node, [], [Lang]); +get_menu_items_hook(server, Lang) -> + ejabberd_hooks:run_fold(webadmin_menu_main, [], [Lang]). + + +%% @spec (Lang::string(), Menu) -> [LI] +%% where Menu = {MURI::string(), MName::string(), Items::[Item]} +%% Item = {IURI::string(), IName::string()} | {IURI::string(), IName::string(), Menu} +make_menu_items(Lang, Menu) -> + lists:reverse(make_menu_items2(Lang, 1, Menu)). + +make_menu_items2(Lang, Deep, {MURI, MName, _} = Menu) -> + Res = case MName of + "" -> []; + _ -> [make_menu_item(header, Deep, MURI, MName, Lang) ] + end, + make_menu_items2(Lang, Deep, Menu, Res). + +make_menu_items2(_, _Deep, {_, _, []}, Res) -> + Res; + +make_menu_items2(Lang, Deep, {MURI, MName, [Item | Items]}, Res) -> + Res2 = case Item of + {IURI, IName} -> + [make_menu_item(item, Deep, MURI++IURI++"/", IName, Lang) | Res]; + {IURI, IName, SubMenu} -> + %%ResTemp = [?LI([?ACT(MURI ++ IURI ++ "/", IName)]) | Res], + ResTemp = [make_menu_item(item, Deep, MURI++IURI++"/", IName, Lang) | Res], + ResSubMenu = make_menu_items2(Lang, Deep+1, SubMenu), + ResSubMenu ++ ResTemp + end, + make_menu_items2(Lang, Deep, {MURI, MName, Items}, Res2). + +make_menu_item(header, 1, URI, Name, _Lang) -> + ?LI([?XAE("div", [{"id", "navhead"}], [?AC(URI, "~ "++Name++" ~")] )]); +make_menu_item(header, 2, URI, Name, _Lang) -> + ?LI([?XAE("div", [{"id", "navheadsub"}], [?AC(URI, "~ "++Name++" ~")] )]); +make_menu_item(header, 3, URI, Name, _Lang) -> + ?LI([?XAE("div", [{"id", "navheadsubsub"}], [?AC(URI, "~ "++Name++" ~")] )]); +make_menu_item(item, 1, URI, Name, Lang) -> + ?LI([?XAE("div", [{"id", "navitem"}], [?ACT(URI, Name)] )]); +make_menu_item(item, 2, URI, Name, Lang) -> + ?LI([?XAE("div", [{"id", "navitemsub"}], [?ACT(URI, Name)] )]); +make_menu_item(item, 3, URI, Name, Lang) -> + ?LI([?XAE("div", [{"id", "navitemsubsub"}], [?ACT(URI, Name)] )]). From a94caf218fa9ce6afb7a896f32f80eb8940e6b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 13 Oct 2008 11:43:33 +0000 Subject: [PATCH 121/582] Remove all deprecated functions from jlib. This was accidentally committed with the merge. PR: EJABP-1 SVN Revision: 1651 --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 34bbb8cb0..36cb6ebb1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,8 @@ Merge from trunk (r1613 to 1649). + * src/jlib.erl: Remove all deprecated functions. + 2008-10-13 Jean-Sébastien Pédron * src/extauth.erl (call_port/2): Replace jlib:nameprep/1 by From 50b1e4c36fc0ecf6d21dab0143aca7e925aee00f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 13 Oct 2008 15:36:43 +0000 Subject: [PATCH 122/582] Convert to exmpp. The admin web interface is working but HTTP polling seems broken in the trunk. PR: EJABP-1 SVN Revision: 1654 --- ChangeLog | 7 + src/web/ejabberd_http.erl | 57 +-- src/web/ejabberd_http_poll.erl | 33 +- src/web/ejabberd_web.erl | 53 +-- src/web/ejabberd_web_admin.erl | 707 ++++++++++++++++----------------- src/web/ejabberd_web_admin.hrl | 36 +- 6 files changed, 424 insertions(+), 469 deletions(-) diff --git a/ChangeLog b/ChangeLog index 36cb6ebb1..183259f56 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2008-10-13 Jean-Sébastien Pédron + + * src/web/ejabberd_http.erl, src/web/ejabberd_http_poll.erl, + src/web/ejabberd_web.erl, src/web/ejabberd_web_admin.erl, + src/web/ejabberd_web_admin.hrl: Convert to exmpp. The admin web + interface is working but HTTP polling seems broken in the trunk. + 2008-10-13 Jean-Sébastien Pédron Merge from trunk (r1613 to 1649). diff --git a/src/web/ejabberd_http.erl b/src/web/ejabberd_http.erl index 5c15fcd16..be87a56fd 100644 --- a/src/web/ejabberd_http.erl +++ b/src/web/ejabberd_http.erl @@ -35,8 +35,9 @@ receive_headers/1, url_encode/1]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("ejabberd_http.hrl"). -record(state, {sockmod, @@ -202,7 +203,7 @@ process_header(State, Data) -> request_path = Path, request_keepalive = KeepAlive}; {ok, {http_header, _, 'Connection', _, Conn}} -> - KeepAlive1 = case jlib:tolower(Conn) of + KeepAlive1 = case exmpp_stringprep:to_lower(Conn) of "keep-alive" -> true; "close" -> @@ -349,10 +350,9 @@ process_request(#state{request_method = Method, %% procedure (process) that handles dispatching based on %% URL path prefix. case process(RequestHandlers, Request) of - El when element(1, El) == xmlelement -> + El when is_record(El, xmlel) -> make_xhtml_output(State, 200, [], El); - {Status, Headers, El} when - element(1, El) == xmlelement -> + {Status, Headers, El} when is_record(El, xmlel) -> make_xhtml_output(State, Status, Headers, El); Output when is_list(Output) or is_binary(Output) -> make_text_output(State, 200, [], Output); @@ -412,10 +412,9 @@ process_request(#state{request_method = Method, headers = RequestHeaders, ip = IP}, case process(RequestHandlers, Request) of - El when element(1, El) == xmlelement -> + El when is_record(El, xmlel) -> make_xhtml_output(State, 200, [], El); - {Status, Headers, El} when - element(1, El) == xmlelement -> + {Status, Headers, El} when is_record(El, xmlel) -> make_xhtml_output(State, Status, Headers, El); Output when is_list(Output) or is_binary(Output) -> make_text_output(State, 200, [], Output); @@ -428,8 +427,8 @@ process_request(State) -> make_xhtml_output(State, 400, [], - ejabberd_web:make_xhtml([{xmlelement, "h1", [], - [{xmlcdata, "400 Bad Request"}]}])). + ejabberd_web:make_xhtml([#xmlel{ns = ?NS_XHTML, name = 'h1', children = + [#xmlcdata{cdata = <<"400 Bad Request">>}]}])). recv_data(State, Len) -> @@ -459,10 +458,10 @@ make_xhtml_output(State, Status, Headers, XHTML) -> Data = case lists:member(html, Headers) of true -> list_to_binary([?HTML_DOCTYPE, - element_to_string(XHTML)]); + exmpp_xml:document_to_list(exmpp_xml:indent_document(XHTML, <<>>))]); _ -> list_to_binary([?XHTML_DOCTYPE, - element_to_string(XHTML)]) + exmpp_xml:document_to_list(exmpp_xml:indent_document(XHTML, <<>>))]) end, Headers1 = case lists:keysearch("Content-Type", 1, Headers) of {value, _} -> @@ -544,40 +543,6 @@ parse_lang(Langs) -> "en" end. -element_to_string(El) -> - case El of - {xmlelement, Name, Attrs, Els} -> - if - Els /= [] -> - [$<, Name, attrs_to_list(Attrs), $>, - [element_to_string(E) || E <- Els], - $<, $/, Name, $>]; - true -> - [$<, Name, attrs_to_list(Attrs), $/, $>] - end; - {xmlcdata, CData} -> - crypt(CData) - end. - -attrs_to_list(Attrs) -> - [attr_to_list(A) || A <- Attrs]. - -attr_to_list({Name, Value}) -> - [$\s, crypt(Name), $=, $", crypt(Value), $"]. - -crypt(S) when is_list(S) -> - [case C of - $& -> "&"; - $< -> "<"; - $> -> ">"; - $" -> """; - $' -> "'"; - _ -> C - end || C <- S]; -crypt(S) when is_binary(S) -> - crypt(binary_to_list(S)). - - % Code below is taken (with some modifications) from the yaws webserver, which % is distributed under the folowing license: % diff --git a/src/web/ejabberd_http_poll.erl b/src/web/ejabberd_http_poll.erl index 9c2cdee46..370217998 100644 --- a/src/web/ejabberd_http_poll.erl +++ b/src/web/ejabberd_http_poll.erl @@ -44,8 +44,9 @@ close/1, process/2]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("ejabberd_http.hrl"). -record(http_poll, {id, pid}). @@ -71,6 +72,11 @@ -define(CT, {"Content-Type", "text/xml; charset=utf-8"}). -define(BAD_REQUEST, [?CT, {"Set-Cookie", "ID=-3:0; expires=-1"}]). +-define(PARSER_OPTIONS, [ + {namespace, true}, + {name_as_atom, true}, + {autoload_known, true} +]). %%%---------------------------------------------------------------------- %%% API @@ -156,8 +162,8 @@ process([], #request{data = Data, {200, [?CT, {"Set-Cookie", "ID=-2:0; expires=-1"}], ""} end; process(_, _Request) -> - {400, [], {xmlelement, "h1", [], - [{xmlcdata, "400 Bad Request"}]}}. + {400, [], #xmlel{ns = ?NS_XHTML, name = 'h1', children = + [#xmlcdata{cdata = <<"400 Bad Request">>}]}}. %%%---------------------------------------------------------------------- %%% Callback functions from gen_fsm @@ -397,7 +403,7 @@ resend_messages(Messages) -> %% This function is used to resend messages that have been polled but not %% delivered. resend_message(Packet) -> - ParsedPacket = xml_stream:parse_element(Packet), + [ParsedPacket] = exmpp_xml:parse_document(Packet, ?PARSER_OPTIONS), From = get_jid("from", ParsedPacket), To = get_jid("to", ParsedPacket), ?DEBUG("Resend ~p ~p ~p~n",[From,To, ParsedPacket]), @@ -405,10 +411,17 @@ resend_message(Packet) -> %% Type can be "from" or "to" %% Parsed packet is a parsed Jabber packet. -get_jid(Type, ParsedPacket) -> - case xml:get_tag_attr(Type, ParsedPacket) of - {value, StringJid} -> - jlib:string_to_jid(StringJid); - false -> - jlib:make_jid("","","") +get_jid("from", ParsedPacket) -> + case exmpp_stanza:get_sender(ParsedPacket) of + undefined -> + #jid{}; + From -> + exmpp_jid:list_to_jid(From) + end; +get_jid("to", ParsedPacket) -> + case exmpp_stanza:get_recipient(ParsedPacket) of + undefined -> + #jid{}; + From -> + exmpp_jid:list_to_jid(From) end. diff --git a/src/web/ejabberd_web.erl b/src/web/ejabberd_web.erl index 166d430ff..fc5ce9a40 100644 --- a/src/web/ejabberd_web.erl +++ b/src/web/ejabberd_web.erl @@ -31,8 +31,9 @@ -export([make_xhtml/1, make_xhtml/2, error/1]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("ejabberd_http.hrl"). @@ -45,36 +46,40 @@ make_xhtml(Els) -> make_xhtml([], Els). make_xhtml(HeadEls, Els) -> - {xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}, - {"xml:lang", "en"}, - {"lang", "en"}], - [{xmlelement, "head", [], - [{xmlelement, "meta", [{"http-equiv", "Content-Type"}, - {"content", "text/html; charset=utf-8"}], []} - | HeadEls]}, - {xmlelement, "body", [], Els} - ]}. + #xmlel{ns = ?NS_XHTML, name = 'html', attrs = [ + #xmlattr{ns = ?NS_XML, name = 'lang', value = "en"}, + #xmlattr{name = 'lang', value = "en"}], children = [ + #xmlel{ns = ?NS_XHTML, name = 'head', children = [ + #xmlel{ns = ?NS_XHTML, name = 'meta', attrs = [ + #xmlattr{name = 'http-equiv', value = "Content-Type"}, + #xmlattr{name = 'content', value = "text/html; charset=utf-8"} + ]} + | HeadEls + ]}, + #xmlel{ns = ?NS_XHTML, name = 'body', children = Els} + ]}. --define(X(Name), {xmlelement, Name, [], []}). --define(XA(Name, Attrs), {xmlelement, Name, Attrs, []}). --define(XE(Name, Els), {xmlelement, Name, [], Els}). --define(XAE(Name, Attrs, Els), {xmlelement, Name, Attrs, Els}). --define(C(Text), {xmlcdata, Text}). +-define(X(Name), #xmlel{ns = ?NS_XHTML, name = Name}). +-define(XA(Name, Attrs), #xmlel{ns = ?NS_XHTML, name = Name, attrs = Attrs}). +-define(XE(Name, Els), #xmlel{ns = ?NS_XHTML, name = Name, children = Els}). +-define(XAE(Name, Attrs, Els), #xmlel{ns = ?NS_XHTML, name = Name, + attrs = Attrs, children = Els}). +-define(C(Text), #xmlcdata{cdata = list_to_binary(Text)}). -define(XC(Name, Text), ?XE(Name, [?C(Text)])). -define(XAC(Name, Attrs, Text), ?XAE(Name, Attrs, [?C(Text)])). --define(LI(Els), ?XE("li", Els)). --define(A(URL, Els), ?XAE("a", [{"href", URL}], Els)). +-define(LI(Els), ?XE('li', Els)). +-define(A(URL, Els), ?XAE('a', [#xmlattr{name = 'href', value = URL}], Els)). -define(AC(URL, Text), ?A(URL, [?C(Text)])). --define(P, ?X("p")). --define(BR, ?X("br")). +-define(P, ?X('p')). +-define(BR, ?X('br')). -define(INPUT(Type, Name, Value), - ?XA("input", [{"type", Type}, - {"name", Name}, - {"value", Value}])). + ?XA('input', [#xmlattr{name = 'type', value = Type}, + #xmlattr{name = 'name', value = Name}, + #xmlattr{name = 'value', value = Value}])). error(not_found) -> - {404, [], make_xhtml([?XC("h1", "404 Not Found")])}; + {404, [], make_xhtml([?XC('h1', "404 Not Found")])}; error(not_allowed) -> - {401, [], make_xhtml([?XC("h1", "401 Unauthorized")])}. + {401, [], make_xhtml([?XC('h1', "401 Unauthorized")])}. diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index c7da8cf69..6f004b7e5 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -31,25 +31,25 @@ -export([process/2, list_users/4, list_users_in_diapason/4, - pretty_print_xml/1, term_to_id/1]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -include("ejabberd_http.hrl"). -include("ejabberd_web_admin.hrl"). process(["server", SHost | RPath], #request{auth = Auth} = Request) -> - Host = jlib:nameprep(SHost), + Host = exmpp_stringprep:nameprep(SHost), case lists:member(Host, ?MYHOSTS) of true -> case get_auth(Auth) of {User, Server} -> case acl:match_rule( - Host, configure, jlib:make_jid(User, Server, "")) of + Host, configure, exmpp_jid:make_bare_jid(User, Server)) of deny -> - ejabberd_web:error(not_allowed); + ejabberd_web:error(not_allowed); allow -> process_admin( Host, Request#request{path = RPath, @@ -58,50 +58,51 @@ process(["server", SHost | RPath], #request{auth = Auth} = Request) -> unauthorized -> {401, [{"WWW-Authenticate", "basic realm=\"ejabberd\""}], - ejabberd_web:make_xhtml([{xmlelement, "h1", [], - [{xmlcdata, "401 Unauthorized"}]}])} + ejabberd_web:make_xhtml([#xmlel{ns = ?NS_XHTML, name = 'h1', children = + [#xmlcdata{cdata = <<"401 Unauthorized">>}]}])} end; false -> - ejabberd_web:error(not_found) + ejabberd_web:error(not_found) end; process(RPath, #request{auth = Auth} = Request) -> case get_auth(Auth) of {User, Server} -> case acl:match_rule( - global, configure, jlib:make_jid(User, Server, "")) of + global, configure, exmpp_jid:make_bare_jid(User, Server)) of deny -> - ejabberd_web:error(not_allowed); + ejabberd_web:error(not_allowed); allow -> process_admin( global, Request#request{path = RPath, us = {User, Server}}) end; unauthorized -> - %% XXX bard: any reason to send this data now and not - %% always in case of an 401? ought to check http specs... + %% XXX bard: any reason to send this data now and not + %% always in case of an 401? ought to check http specs... {401, [{"WWW-Authenticate", "basic realm=\"ejabberd\""}], - ejabberd_web:make_xhtml([{xmlelement, "h1", [], - [{xmlcdata, "401 Unauthorized"}]}])} + ejabberd_web:make_xhtml([#xmlel{ns = ?NS_XHTML, name = 'h1', children = + [#xmlcdata{cdata = <<"401 Unauthorized">>}]}])} end. get_auth(Auth) -> case Auth of - {SJID, P} -> - case jlib:string_to_jid(SJID) of - error -> - unauthorized; - #jid{user = U, server = S} -> - case ejabberd_auth:check_password(U, S, P) of - true -> - {U, S}; - false -> - unauthorized - end - end; - _ -> - unauthorized + {SJID, P} -> + try + #jid{node = U, domain = S} = exmpp_jid:list_to_jid(SJID), + case ejabberd_auth:check_password(U, S, P) of + true -> + {U, S}; + false -> + unauthorized + end + catch + _ -> + unauthorized + end; + _ -> + unauthorized end. make_xhtml(Els, Host, Lang) -> @@ -114,43 +115,46 @@ make_xhtml(Els, Host, Node, Lang) -> Base = get_base_path(Host, cluster), %% Enforcing 'cluster' on purpose here MenuItems = make_navigation(Host, Node, Lang), {200, [html], - {xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}, - {"xml:lang", Lang}, - {"lang", Lang}], - [{xmlelement, "head", [], - [?XCT("title", "ejabberd Web Admin"), - {xmlelement, "meta", [{"http-equiv", "Content-Type"}, - {"content", "text/html; charset=utf-8"}], []}, - {xmlelement, "link", [{"href", Base ++ "favicon.ico"}, - {"type", "image/x-icon"}, - {"rel", "shortcut icon"}], []}, - {xmlelement, "link", [{"href", Base ++ "style.css"}, - {"type", "text/css"}, - {"rel", "stylesheet"}], []}]}, - ?XE("body", - [?XAE("div", - [{"id", "container"}], - [?XAE("div", - [{"id", "header"}], - [?XE("h1", + #xmlel{ns = ?NS_XHTML, name = 'html', attrs = [ + #xmlattr{ns = ?NS_XML, name = 'lang', value = Lang}, + #xmlattr{name = 'lang', value = Lang}], children = + [#xmlel{ns = ?NS_XHTML, name = 'head', children = + [?XCT('title', "ejabberd Web Admin"), + #xmlel{ns = ?NS_XHTML, name = 'meta', attrs = [ + #xmlattr{name = 'http-equiv', value = "Content-Type"}, + #xmlattr{name = 'content', value = "text/html; charset=utf-8"}]}, + #xmlel{ns = ?NS_XHTML, name = 'link', attrs = [ + #xmlattr{name = 'href', value = Base ++ "favicon.ico"}, + #xmlattr{name = 'type', value = "image/x-icon"}, + #xmlattr{name = 'rel', value = "shortcut icon"}]}, + #xmlel{ns = ?NS_XHTML, name = 'link', attrs = [ + #xmlattr{name = 'href', value = Base ++ "style.css"}, + #xmlattr{name = 'type', value = "text/css"}, + #xmlattr{name = 'rel', value = "stylesheet"}]}]}, + ?XE('body', + [?XAE('div', + [#xmlattr{name = 'id', value = "container"}], + [?XAE('div', + [#xmlattr{name = 'id', value = "header"}], + [?XE('h1', [?ACT("/admin/", "Administration")] )]), - ?XAE("div", - [{"id", "navigation"}], - [?XE("ul", + ?XAE('div', + [#xmlattr{name = 'id', value = "navigation"}], + [?XE('ul', MenuItems )]), - ?XAE("div", - [{"id", "content"}], + ?XAE('div', + [#xmlattr{name = 'id', value = "content"}], Els), - ?XAE("div", - [{"id", "clearcopyright"}], - [{xmlcdata, ""}])]), - ?XAE("div", - [{"id", "copyrightouter"}], - [?XAE("div", - [{"id", "copyright"}], - [?XC("p", + ?XAE('div', + [#xmlattr{name = 'id', value = "clearcopyright"}], + [#xmlcdata{cdata = <<>>}])]), + ?XAE('div', + [#xmlattr{name = 'id', value = "copyrightouter"}], + [?XAE('div', + [#xmlattr{name = 'id', value = "copyright"}], + [?XC('p', "ejabberd (c) 2002-2008 ProcessOne") ])])]) ]}}. @@ -556,8 +560,8 @@ process_admin(global, lang = Lang}) -> Base = get_base_path(global, cluster), MenuItems2 = make_menu_items(global, cluster, Base, Lang), - make_xhtml([?XCT("h1", "Administration"), - ?XE("ul", + make_xhtml([?XCT('h1', "Administration"), + ?XE('ul', [?LI([?ACT("/admin/acls/", "Access Control Lists"), ?C(" "), ?ACT("/admin/acls-raw/", "(Raw)")]), ?LI([?ACT("/admin/access/", "Access Rules"), ?C(" "), @@ -574,8 +578,8 @@ process_admin(Host, lang = Lang}) -> Base = get_base_path(Host, cluster), MenuItems2 = make_menu_items(Host, cluster, Base, Lang), - make_xhtml([?XCT("h1", "Administration"), - ?XE("ul", + make_xhtml([?XCT('h1', "Administration"), + ?XE('ul', [?LI([?ACT(Base ++ "acls/", "Access Control Lists"), ?C(" "), ?ACT(Base ++ "acls-raw/", "(Raw)")]), ?LI([?ACT(Base ++ "access/", "Access Rules"), ?C(" "), @@ -631,16 +635,16 @@ process_admin(Host, "~p.", [lists:keysort( 2, ets:select(acl, [{{acl, {'$1', Host}, '$2'}, [], [{{acl, '$1', '$2'}}]}]))])), - make_xhtml([?XCT("h1", "Access Control Lists")] ++ + make_xhtml([?XCT('h1', "Access Control Lists")] ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; nothing -> [] end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], - [?XAC("textarea", [{"name", "acls"}, - {"rows", "16"}, - {"cols", "80"}], + [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XAC('textarea', [#xmlattr{name = 'name', value = "acls"}, + #xmlattr{name = 'rows', value = "16"}, + #xmlattr{name = 'cols', value = "80"}], ACLs), ?BR, ?INPUTT("submit", "submit", "Submit") @@ -674,14 +678,14 @@ process_admin(Host, ACLs = lists:keysort( 2, ets:select(acl, [{{acl, {'$1', Host}, '$2'}, [], [{{acl, '$1', '$2'}}]}])), - make_xhtml([?XCT("h1", "Access Control Lists")] ++ + make_xhtml([?XCT('h1', "Access Control Lists")] ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; nothing -> [] end ++ - [?XE("p", [?ACT("../acls-raw/", "Raw")])] ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], + [?XE('p', [?ACT("../acls-raw/", "Raw")])] ++ + [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], [acls_to_xhtml(ACLs), ?BR, ?INPUTT("submit", "delete", "Delete Selected"), @@ -742,16 +746,16 @@ process_admin(Host, [{{config, {access, '$1', Host}, '$2'}, [], [{{access, '$1', '$2'}}]}])])), - make_xhtml([?XCT("h1", "Access Rules")] ++ + make_xhtml([?XCT('h1', "Access Rules")] ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; nothing -> [] end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], - [?XAC("textarea", [{"name", "access"}, - {"rows", "16"}, - {"cols", "80"}], + [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XAC('textarea', [#xmlattr{name = 'name', value = "access"}, + #xmlattr{name = 'rows', value = "16"}, + #xmlattr{name = 'cols', value = "80"}], Access), ?BR, ?INPUTT("submit", "submit", "Submit") @@ -780,14 +784,14 @@ process_admin(Host, [{{config, {access, '$1', Host}, '$2'}, [], [{{access, '$1', '$2'}}]}]), - make_xhtml([?XCT("h1", "Access Rules")] ++ + make_xhtml([?XCT('h1', "Access Rules")] ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; nothing -> [] end ++ - [?XE("p", [?ACT("../access-raw/", "Raw")])] ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], + [?XE('p', [?ACT("../access-raw/", "Raw")])] ++ + [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], [access_rules_to_xhtml(AccessRules, Lang), ?BR, ?INPUTT("submit", "delete", "Delete Selected") @@ -819,14 +823,14 @@ process_admin(Host, Rs1 -> Rs1 end, - make_xhtml([?XC("h1", + make_xhtml([?XC('h1', io_lib:format(?T("~s access rule configuration"), [SName]))] ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; nothing -> [] end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], + [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], [access_rule_to_xhtml(Rules), ?BR, ?INPUTT("submit", "submit", "Submit") @@ -837,27 +841,27 @@ process_admin(global, #request{path = ["vhosts"], lang = Lang}) -> Res = list_vhosts(Lang), - make_xhtml([?XCT("h1", "ejabberd virtual hosts")] ++ Res, global, Lang); + make_xhtml([?XCT('h1', "ejabberd virtual hosts")] ++ Res, global, Lang); process_admin(Host, #request{path = ["users"], q = Query, lang = Lang}) when is_list(Host) -> Res = list_users(Host, Query, Lang, fun url_func/1), - make_xhtml([?XCT("h1", "Users")] ++ Res, Host, Lang); + make_xhtml([?XCT('h1', "Users")] ++ Res, Host, Lang); process_admin(Host, #request{path = ["users", Diap], lang = Lang}) when is_list(Host) -> Res = list_users_in_diapason(Host, Diap, Lang, fun url_func/1), - make_xhtml([?XCT("h1", "Users")] ++ Res, Host, Lang); + make_xhtml([?XCT('h1', "Users")] ++ Res, Host, Lang); process_admin(Host, #request{ path = ["online-users"], lang = Lang}) when is_list(Host) -> Res = list_online_users(Host, Lang), - make_xhtml([?XCT("h1", "Online Users")] ++ Res, Host, Lang); + make_xhtml([?XCT('h1', "Online Users")] ++ Res, Host, Lang); process_admin(Host, #request{path = ["last-activity"], @@ -876,18 +880,18 @@ process_admin(Host, _ -> list_last_activity(Host, Lang, true, Month) end, - make_xhtml([?XCT("h1", "Users Last Activity")] ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], + make_xhtml([?XCT('h1', "Users Last Activity")] ++ + [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], [?CT("Period: "), - ?XAE("select", [{"name", "period"}], + ?XAE('select', [#xmlattr{name = 'name', value = "period"}], lists:map( fun({O, V}) -> Sel = if - O == Month -> [{"selected", "selected"}]; + O == Month -> [#xmlattr{name = 'selected', value = "selected"}]; true -> [] end, - ?XAC("option", - Sel ++ [{"value", O}], V) + ?XAC('option', + Sel ++ [#xmlattr{name = 'value', value = O}], V) end, [{"month", ?T("Last month")}, {"year", ?T("Last year")}, {"all", ?T("All activity")}])), @@ -902,7 +906,7 @@ process_admin(Host, #request{path = ["stats"], lang = Lang}) -> Res = get_stats(Host, Lang), - make_xhtml([?XCT("h1", "Statistics")] ++ Res, Host, Lang); + make_xhtml([?XCT('h1', "Statistics")] ++ Res, Host, Lang); process_admin(Host, #request{path = ["user", U], @@ -913,7 +917,7 @@ process_admin(Host, Res = user_info(U, Host, Query, Lang), make_xhtml(Res, Host, Lang); false -> - make_xhtml([?XCT("h1", "Not Found")], Host, Lang) + make_xhtml([?XCT('h1', "Not Found")], Host, Lang) end; process_admin(Host, @@ -928,7 +932,7 @@ process_admin(Host, lang = Lang}) -> case search_running_node(SNode) of false -> - make_xhtml([?XCT("h1", "Node not found")], Host, Lang); + make_xhtml([?XCT('h1', "Node not found")], Host, Lang); Node -> Res = get_node(Host, Node, NPath, Query, Lang), make_xhtml(Res, Host, Node, Lang) @@ -940,28 +944,28 @@ process_admin(Host, #request{lang = Lang} = Request) -> Host -> {webadmin_page_host, [Host, Request]} end, case ejabberd_hooks:run_fold(Hook, Host, [], Opts) of - [] -> setelement(1, make_xhtml([?XC("h1", "Not Found")], Host, Lang), 404); + [] -> setelement(1, make_xhtml([?XC('h1', "Not Found")], Host, Lang), 404); Res -> make_xhtml(Res, Host, Lang) end. acls_to_xhtml(ACLs) -> - ?XAE("table", [], - [?XE("tbody", + ?XAE('table', [], + [?XE('tbody', lists:map( fun({acl, Name, Spec} = ACL) -> SName = atom_to_list(Name), ID = term_to_id(ACL), - ?XE("tr", - [?XE("td", [?INPUT("checkbox", "selected", ID)]), - ?XC("td", SName)] ++ + ?XE('tr', + [?XE('td', [?INPUT("checkbox", "selected", ID)]), + ?XC('td', SName)] ++ acl_spec_to_xhtml(ID, Spec) ) end, ACLs) ++ - [?XE("tr", - [?X("td"), - ?XE("td", [?INPUT("text", "namenew", "")]) + [?XE('tr', + [?X('td'), + ?XE('td', [?INPUT("text", "namenew", "")]) ] ++ acl_spec_to_xhtml("new", {user, ""}) )] @@ -1011,16 +1015,16 @@ acl_spec_to_xhtml(ID, Spec) -> [acl_spec_select(ID, Type), ?ACLINPUT(Str)]. acl_spec_select(ID, Opt) -> - ?XE("td", - [?XAE("select", [{"name", "type" ++ ID}], + ?XE('td', + [?XAE('select', [#xmlattr{name = 'name', value = "type" ++ ID}], lists:map( fun(O) -> Sel = if - O == Opt -> [{"selected", "selected"}]; + O == Opt -> [#xmlattr{name = 'selected', value = "selected"}]; true -> [] end, - ?XAC("option", - Sel ++ [{"value", atom_to_list(O)}], + ?XAC('option', + Sel ++ [#xmlattr{name = 'value', value = atom_to_list(O)}], atom_to_list(O)) end, [user, server, user_regexp, server_regexp, node_regexp, user_glob, server_glob, node_glob, all, raw]))]). @@ -1093,14 +1097,14 @@ string_to_spec("user_regexp", Val) -> string_to_spec("server_regexp", Val) -> {server_regexp, Val}; string_to_spec("node_regexp", Val) -> - #jid{luser = U, lserver = S, resource = ""} = jlib:string_to_jid(Val), + #jid{lnode = U, ldomain = S, resource = undefined} = exmpp_jid:list_to_jid(Val), {node_regexp, U, S}; string_to_spec("user_glob", Val) -> string_to_spec2(user_glob, Val); string_to_spec("server_glob", Val) -> {server_glob, Val}; string_to_spec("node_glob", Val) -> - #jid{luser = U, lserver = S, resource = ""} = jlib:string_to_jid(Val), + #jid{lnode = U, ldomain = S, resource = undefined} = exmpp_jid:list_to_jid(Val), {node_glob, U, S}; string_to_spec("all", _) -> all; @@ -1110,7 +1114,7 @@ string_to_spec("raw", Val) -> NewSpec. string_to_spec2(ACLName, Val) -> - #jid{luser = U, lserver = S, resource = ""} = jlib:string_to_jid(Val), + #jid{lnode = U, ldomain = S, resource = undefined} = exmpp_jid:list_to_jid(Val), case U of "" -> {ACLName, S}; @@ -1130,23 +1134,23 @@ acl_parse_delete(ACLs, Query) -> access_rules_to_xhtml(AccessRules, Lang) -> - ?XAE("table", [], - [?XE("tbody", + ?XAE('table', [], + [?XE('tbody', lists:map( fun({access, Name, Rules} = Access) -> SName = atom_to_list(Name), ID = term_to_id(Access), - ?XE("tr", - [?XE("td", [?INPUT("checkbox", "selected", ID)]), - ?XE("td", [?AC(SName ++ "/", SName)]), - ?XC("td", term_to_string(Rules)) + ?XE('trr', + [?XE('td', [?INPUT("checkbox", "selected", ID)]), + ?XE('td', [?AC(SName ++ "/", SName)]), + ?XC('td', term_to_string(Rules)) ] ) end, AccessRules) ++ - [?XE("tr", - [?X("td"), - ?XE("td", [?INPUT("text", "namenew", "")]), - ?XE("td", [?INPUTT("submit", "addnew", "Add New")]) + [?XE('tr', + [?X('td'), + ?XE('td', [?INPUT("text", "namenew", "")]), + ?XE('td', [?INPUTT("submit", "addnew", "Add New")]) ] )] )]). @@ -1201,7 +1205,7 @@ access_rule_to_xhtml(Rules) -> SACL = atom_to_list(ACL), SAccess ++ "\t" ++ SACL ++ "\n" end, Rules), - ?XAC("textarea", [{"name", "rules"}, + ?XAC('textarea', [{"name", "rules"}, {"rows", "16"}, {"cols", "80"}], Text). @@ -1227,24 +1231,24 @@ parse_access_rule(Text) -> list_vhosts(Lang) -> Hosts = ?MYHOSTS, SHosts = lists:sort(Hosts), - [?XE("table", - [?XE("thead", - [?XE("tr", - [?XCT("td", "Host"), - ?XCT("td", "Registered Users"), - ?XCT("td", "Online Users") + [?XE('table', + [?XE('thead', + [?XE('tr', + [?XCT('td', "Host"), + ?XCT('td', "Registered Users"), + ?XCT('td', "Online Users") ])]), - ?XE("tbody", + ?XE('tbody', lists:map( fun(Host) -> OnlineUsers = length(ejabberd_sm:get_vh_session_list(Host)), RegisteredUsers = ejabberd_auth:get_vh_registered_users_number(Host), - ?XE("tr", - [?XE("td", [?AC("../server/" ++ Host ++ "/", Host)]), - ?XC("td", integer_to_list(RegisteredUsers)), - ?XC("td", integer_to_list(OnlineUsers)) + ?XE('tr', + [?XE('td', [?AC("../server/" ++ Host ++ "/", Host)]), + ?XC('td', integer_to_list(RegisteredUsers)), + ?XC('td', integer_to_list(OnlineUsers)) ]) end, SHosts) )])]. @@ -1280,23 +1284,23 @@ list_users(Host, Query, Lang, URLFunc) -> error -> [?CT("Bad format"), ?P]; nothing -> [] end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], - [?XE("table", - [?XE("tr", - [?XC("td", ?T("User") ++ ":"), - ?XE("td", [?INPUT("text", "newusername", "")]), - ?XE("td", [?C([" @ ", Host])]) + [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XE('table', + [?XE('tr', + [?XC('td', ?T("User") ++ ":"), + ?XE('td', [?INPUT("text", "newusername", "")]), + ?XE('td', [?C([" @ ", Host])]) ]), - ?XE("tr", - [?XC("td", ?T("Password") ++ ":"), - ?XE("td", [?INPUT("password", "newuserpassword", "")]), - ?X("td") + ?XE('tr', + [?XC('td', ?T("Password") ++ ":"), + ?XE('td', [?INPUT("password", "newuserpassword", "")]), + ?X('td') ]), - ?XE("tr", - [?X("td"), - ?XAE("td", [{"class", "alignright"}], + ?XE('tr', + [?X('td'), + ?XAE('td', [#xmlattr{name = 'class', value = "alignright"}], [?INPUTT("submit", "addnewuser", "Add User")]), - ?X("td") + ?X('td') ])]), ?P] ++ FUsers)]. @@ -1309,16 +1313,17 @@ list_users_parse_query(Query, Host) -> lists:keysearch("newusername", 1, Query), {value, {_, Password}} = lists:keysearch("newuserpassword", 1, Query), - case jlib:string_to_jid(Username++"@"++Host) of - error -> - error; - #jid{user = User, server = Server} -> - case ejabberd_auth:try_register(User, Server, Password) of - {error, _Reason} -> - error; - _ -> - ok - end + try + #jid{node = User, domain = Server} = exmpp_jid:list_to_jid(Username++"@"++Host), + case ejabberd_auth:try_register(User, Server, Password) of + {error, _Reason} -> + error; + _ -> + ok + end + catch + _ -> + error end; false -> nothing @@ -1335,13 +1340,13 @@ list_users_in_diapason(Host, Diap, Lang, URLFunc) -> [list_given_users(Sub, "../../", Lang, URLFunc)]. list_given_users(Users, Prefix, Lang, URLFunc) -> - ?XE("table", - [?XE("thead", - [?XE("tr", - [?XCT("td", "User"), - ?XCT("td", "Offline Messages"), - ?XCT("td", "Last Activity")])]), - ?XE("tbody", + ?XE('table', + [?XE('thead', + [?XE('tr', + [?XCT('td', "User"), + ?XCT('td', "Offline Messages"), + ?XCT('td', "Last Activity")])]), + ?XE('tbody', lists:map( fun(_SU = {Server, User}) -> US = {User, Server}, @@ -1370,22 +1375,22 @@ list_given_users(Users, Prefix, Lang, URLFunc) -> _ -> ?T("Online") end, - ?XE("tr", - [?XE("td", + ?XE('tr', + [?XE('td', [?AC(URLFunc({user, Prefix, ejabberd_http:url_encode(User), Server}), us_to_list(US))]), - ?XE("td", FQueueLen), - ?XC("td", FLast)]) + ?XE('td', FQueueLen), + ?XC('td', FLast)]) end, Users) )]). us_to_list({User, Server}) -> - jlib:jid_to_string({User, Server, ""}). + exmpp_jid:jid_to_list(User, Server, undefined). su_to_list({Server, User}) -> - jlib:jid_to_string({User, Server, ""}). + exmpp_jid:jid_to_list(User, Server, undefined). get_stats(global, Lang) -> @@ -1394,28 +1399,28 @@ get_stats(global, Lang) -> S2SConns = ejabberd_s2s:dirty_get_connections(), S2SConnections = length(S2SConns), S2SServers = length(lists:usort([element(2, C) || C <- S2SConns])), - [?XAE("table", [], - [?XE("tbody", - [?XE("tr", [?XCT("td", "Registered Users:"), - ?XC("td", integer_to_list(RegisteredUsers))]), - ?XE("tr", [?XCT("td", "Online Users:"), - ?XC("td", integer_to_list(OnlineUsers))]), - ?XE("tr", [?XCT("td", "Outgoing s2s Connections:"), - ?XC("td", integer_to_list(S2SConnections))]), - ?XE("tr", [?XCT("td", "Outgoing s2s Servers:"), - ?XC("td", integer_to_list(S2SServers))]) + [?XAE('table', [], + [?XE('tbody', + [?XE('tr', [?XCT('td', "Registered Users:"), + ?XC('td', integer_to_list(RegisteredUsers))]), + ?XE('tr', [?XCT('td', "Online Users:"), + ?XC('td', integer_to_list(OnlineUsers))]), + ?XE('tr', [?XCT('td', "Outgoing s2s Connections:"), + ?XC('td', integer_to_list(S2SConnections))]), + ?XE('tr', [?XCT('td', "Outgoing s2s Servers:"), + ?XC('td', integer_to_list(S2SServers))]) ]) ])]; get_stats(Host, Lang) -> OnlineUsers = length(ejabberd_sm:get_vh_session_list(Host)), RegisteredUsers = ejabberd_auth:get_vh_registered_users_number(Host), - [?XAE("table", [], - [?XE("tbody", - [?XE("tr", [?XCT("td", "Registered Users:"), - ?XC("td", integer_to_list(RegisteredUsers))]), - ?XE("tr", [?XCT("td", "Online Users:"), - ?XC("td", integer_to_list(OnlineUsers))]) + [?XAE('table', [], + [?XE('tbody', + [?XE('tr', [?XCT('td', "Registered Users:"), + ?XC('td', integer_to_list(RegisteredUsers))]), + ?XE('tr', [?XCT('td', "Online Users:"), + ?XC('td', integer_to_list(OnlineUsers))]) ]) ])]. @@ -1431,8 +1436,8 @@ list_online_users(Host, _Lang) -> end, SUsers). user_info(User, Server, Query, Lang) -> - LServer = jlib:nameprep(Server), - US = {jlib:nodeprep(User), LServer}, + LServer = exmpp_stringprep:nameprep(Server), + US = {exmpp_stringprep:nodeprep(User), LServer}, Res = user_parse_query(User, Server, Query), Resources = ejabberd_sm:get_user_resources(User, Server), FResources = @@ -1440,7 +1445,7 @@ user_info(User, Server, Query, Lang) -> [] -> [?CT("None")]; _ -> - [?XE("ul", + [?XE('ul', lists:map(fun(R) -> FIP = case ejabberd_sm:get_user_ip( User, Server, R) of @@ -1461,15 +1466,15 @@ user_info(User, Server, Query, Lang) -> ?INPUTT("submit", "chpassword", "Change Password")], UserItems = ejabberd_hooks:run_fold(webadmin_user, LServer, [], [User, Server, Lang]), - [?XC("h1", ?T("User ") ++ us_to_list(US))] ++ + [?XC('h1', ?T("User ") ++ us_to_list(US))] ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; nothing -> [] end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], - [?XCT("h3", "Connected Resources:")] ++ FResources ++ - [?XCT("h3", "Password:")] ++ FPassword ++ + [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XCT('h3', "Connected Resources:")] ++ FResources ++ + [?XCT('h3', "Password:")] ++ FPassword ++ UserItems ++ [?P, ?INPUTT("submit", "removeuser", "Remove User")])]. @@ -1545,13 +1550,13 @@ list_last_activity(Host, Lang, Integral, Period) -> lists:duplicate(Left, 0) end, Max = lists:max(Hist), - [?XAE("ol", - [{"id", "lastactivity"}, {"start", "0"}], - [?XAE("li", - [{"style", + [?XAE('ol', + [#xmlattr{name = 'id', value = "lastactivity"}, #xmlattr{name = 'start', value = "0"}], + [?XAE('li', + [#xmlattr{name = 'style', value = "width:" ++ integer_to_list( trunc(90 * V / Max)) ++ "%;"}], - [{xmlcdata, integer_to_list(V)}]) + [#xmlcdata{cdata = list_to_binary(integer_to_list(V))}]) || V <- Hist ++ Tail])] end end. @@ -1588,7 +1593,7 @@ get_nodes(Lang) -> RunningNodes == [] -> ?CT("None"); true -> - ?XE("ul", + ?XE('ul', lists:map( fun(N) -> S = atom_to_list(N), @@ -1599,17 +1604,17 @@ get_nodes(Lang) -> StoppedNodes == [] -> ?CT("None"); true -> - ?XE("ul", + ?XE('ul', lists:map( fun(N) -> S = atom_to_list(N), ?LI([?C(S)]) end, lists:sort(StoppedNodes))) end, - [?XCT("h1", "Nodes"), - ?XCT("h3", "Running Nodes"), + [?XCT('h1', "Nodes"), + ?XCT('h3', "Running Nodes"), FRN, - ?XCT("h3", "Stopped Nodes"), + ?XCT('h3', "Stopped Nodes"), FSN]. search_running_node(SNode) -> @@ -1629,37 +1634,37 @@ get_node(global, Node, [], Query, Lang) -> Res = node_parse_query(Node, Query), Base = get_base_path(global, Node), MenuItems2 = make_menu_items(global, Node, Base, Lang), - [?XC("h1", ?T("Node ") ++ atom_to_list(Node))] ++ + [?XC('h1', ?T("Node ") ++ atom_to_list(Node))] ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; nothing -> [] end ++ - [?XE("ul", + [?XE('ul', [?LI([?ACT(Base ++ "db/", "Database")]), ?LI([?ACT(Base ++ "backup/", "Backup")]), ?LI([?ACT(Base ++ "ports/", "Listened Ports")]), ?LI([?ACT(Base ++ "stats/", "Statistics")]), ?LI([?ACT(Base ++ "update/", "Update")]) ] ++ MenuItems2), - ?XAE("form", [{"action", ""}, {"method", "post"}], - [?INPUTT("submit", "restart", "Restart"), + ?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?INPUTT('submit', "restart", "Restart"), ?C(" "), - ?INPUTT("submit", "stop", "Stop")]) + ?INPUTT('submit', "stop", "Stop")]) ]; get_node(Host, Node, [], _Query, Lang) -> Base = get_base_path(Host, Node), MenuItems2 = make_menu_items(global, Node, Base, Lang), - [?XC("h1", ?T("Node ") ++ atom_to_list(Node)), - ?XE("ul", + [?XC('h1', ?T("Node ") ++ atom_to_list(Node)), + ?XE('ul', [?LI([?ACT(Base ++ "modules/", "Modules")])] ++ MenuItems2) ]; get_node(global, Node, ["db"], Query, Lang) -> case rpc:call(Node, mnesia, system_info, [tables]) of {badrpc, _Reason} -> - [?XCT("h1", "RPC Call Error")]; + [?XCT('h1', "RPC Call Error")]; Tables -> node_db_parse_query(Node, Tables, Query), STables = lists:sort(Tables), @@ -1687,32 +1692,32 @@ get_node(global, Node, ["db"], Query, Lang) -> _ -> {unknown, 0, 0} end, - ?XE("tr", - [?XC("td", STable), - ?XE("td", [db_storage_select( + ?XE('tr', + [?XC('td', STable), + ?XE('td', [db_storage_select( STable, Type, Lang)]), - ?XAC("td", [{"class", "alignright"}], + ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], integer_to_list(Size)), - ?XAC("td", [{"class", "alignright"}], + ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], integer_to_list(Memory)) ]) end, STables), - [?XC("h1", ?T("Database Tables at ") ++ atom_to_list(Node))] ++ + [?XC('h1', ?T("Database Tables at ") ++ atom_to_list(Node))] ++ [?CT("Submitted"), ?P] ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], - [?XAE("table", [], - [?XE("thead", - [?XE("tr", - [?XCT("td", "Name"), - ?XCT("td", "Storage Type"), - ?XCT("td", "Size"), - ?XCT("td", "Memory") + [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XAE('table', [], + [?XE('thead', + [?XE('tr', + [?XCT('td', "Name"), + ?XCT('td', "Storage Type"), + ?XCT('td', "Size"), + ?XCT('td', "Memory") ])]), - ?XE("tbody", + ?XE('tbody', Rows ++ - [?XE("tr", - [?XAE("td", [{"colspan", "4"}, - {"class", "alignright"}], + [?XE('tr', + [?XAE('td', [#xmlattr{name = 'colspan', value = "4"}, + #xmlattr{name = 'class', value = "alignright"}], [?INPUTT("submit", "submit", "Submit")]) ])] @@ -1721,45 +1726,45 @@ get_node(global, Node, ["db"], Query, Lang) -> get_node(global, Node, ["backup"], Query, Lang) -> _Res = node_backup_parse_query(Node, Query), - [?XC("h1", ?T("Backup of ") ++ atom_to_list(Node)), - ?XCT("p", "Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately."), - ?XAE("form", [{"action", ""}, {"method", "post"}], - [?XAE("table", [], - [?XE("tbody", - [?XE("tr", - [?XCT("td", "Store binary backup:"), - ?XE("td", [?INPUT("text", "storepath", + [?XC('h1', ?T("Backup of ") ++ atom_to_list(Node)), + ?XCT('p', "Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately."), + ?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XAE('table', [], + [?XE('tbody', + [?XE('tr', + [?XCT('td', "Store binary backup:"), + ?XE('td', [?INPUT("text", "storepath", "ejabberd.backup")]), - ?XE("td", [?INPUTT("submit", "store", + ?XE('td', [?INPUTT("submit", "store", "OK")]) ]), - ?XE("tr", - [?XCT("td", "Restore binary backup immediately:"), - ?XE("td", [?INPUT("text", "restorepath", + ?XE('tr', + [?XCT('td', "Restore binary backup immediately:"), + ?XE('td', [?INPUT("text", "restorepath", "ejabberd.backup")]), - ?XE("td", [?INPUTT("submit", "restore", + ?XE('td', [?INPUTT("submit", "restore", "OK")]) ]), - ?XE("tr", - [?XCT("td", + ?XE('tr', + [?XCT('td', "Restore binary backup after next ejabberd restart (requires less memory):"), - ?XE("td", [?INPUT("text", "fallbackpath", + ?XE('td', [?INPUT("text", "fallbackpath", "ejabberd.backup")]), - ?XE("td", [?INPUTT("submit", "fallback", + ?XE('td', [?INPUTT("submit", "fallback", "OK")]) ]), - ?XE("tr", - [?XCT("td", "Store plain text backup:"), - ?XE("td", [?INPUT("text", "dumppath", + ?XE('tr', + [?XCT('td', "Store plain text backup:"), + ?XE('td', [?INPUT("text", "dumppath", "ejabberd.dump")]), - ?XE("td", [?INPUTT("submit", "dump", + ?XE('td', [?INPUTT("submit", "dump", "OK")]) ]), - ?XE("tr", - [?XCT("td", "Restore plain text backup immediately:"), - ?XE("td", [?INPUT("text", "loadpath", + ?XE('tr', + [?XCT('td', "Restore plain text backup immediately:"), + ?XE('td', [?INPUT("text", "loadpath", "ejabberd.dump")]), - ?XE("td", [?INPUTT("submit", "load", + ?XE('td', [?INPUTT("submit", "load", "OK")]) ]) ]) @@ -1777,13 +1782,13 @@ get_node(global, Node, ["ports"], Query, Lang) -> end, NewPorts = lists:sort( rpc:call(Node, ejabberd_config, get_local_option, [listen])), - [?XC("h1", ?T("Listened Ports at ") ++ atom_to_list(Node))] ++ + [?XC('h1', ?T("Listened Ports at ") ++ atom_to_list(Node))] ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; nothing -> [] end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], + [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], [node_ports_to_xhtml(NewPorts, Lang)]) ]; @@ -1800,13 +1805,13 @@ get_node(Host, Node, ["modules"], Query, Lang) when is_list(Host) -> end, NewModules = lists:sort( rpc:call(Node, gen_mod, loaded_modules_with_opts, [Host])), - [?XC("h1", ?T("Modules at ") ++ atom_to_list(Node))] ++ + [?XC('h1', ?T("Modules at ") ++ atom_to_list(Node))] ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; nothing -> [] end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], + [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], [node_modules_to_xhtml(NewModules, Lang)]) ]; @@ -1825,29 +1830,29 @@ get_node(global, Node, ["stats"], _Query, Lang) -> TransactionsLogged = rpc:call(Node, mnesia, system_info, [transaction_log_writes]), - [?XC("h1", io_lib:format(?T("Statistics of ~p"), [Node])), - ?XAE("table", [], - [?XE("tbody", - [?XE("tr", [?XCT("td", "Uptime:"), - ?XAC("td", [{"class", "alignright"}], + [?XC('h1', io_lib:format(?T("Statistics of ~p"), [Node])), + ?XAE('table', [], + [?XE('tbody', + [?XE('tr', [?XCT('td', "Uptime:"), + ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], UpTimeS)]), - ?XE("tr", [?XCT("td", "CPU Time:"), - ?XAC("td", [{"class", "alignright"}], + ?XE('tr', [?XCT('td', "CPU Time:"), + ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], CPUTimeS)]), - ?XE("tr", [?XCT("td", "Online Users:"), - ?XAC("td", [{"class", "alignright"}], + ?XE('tr', [?XCT('td', "Online Users:"), + ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], integer_to_list(OnlineUsers))]), - ?XE("tr", [?XCT("td", "Transactions Commited:"), - ?XAC("td", [{"class", "alignright"}], + ?XE('tr', [?XCT('td', "Transactions Commited:"), + ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], integer_to_list(TransactionsCommited))]), - ?XE("tr", [?XCT("td", "Transactions Aborted:"), - ?XAC("td", [{"class", "alignright"}], + ?XE('tr', [?XCT('td', "Transactions Aborted:"), + ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], integer_to_list(TransactionsAborted))]), - ?XE("tr", [?XCT("td", "Transactions Restarted:"), - ?XAC("td", [{"class", "alignright"}], + ?XE('tr', [?XCT('td', "Transactions Restarted:"), + ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], integer_to_list(TransactionsRestarted))]), - ?XE("tr", [?XCT("td", "Transactions Logged:"), - ?XAC("td", [{"class", "alignright"}], + ?XE('tr', [?XCT('td', "Transactions Logged:"), + ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], integer_to_list(TransactionsLogged))]) ]) ])]; @@ -1863,25 +1868,25 @@ get_node(global, Node, ["update"], Query, Lang) -> [] -> ?CT("None"); _ -> - ?XE("ul", + ?XE('ul', [?LI([?C(atom_to_list(Beam))]) || Beam <- UpdatedBeams]) end, - FmtScript = ?XC("pre", io_lib:format("~p", [Script])), - FmtLowLevelScript = ?XC("pre", io_lib:format("~p", [LowLevelScript])), - [?XC("h1", ?T("Update ") ++ atom_to_list(Node))] ++ + FmtScript = ?XC('pre', io_lib:format("~p", [Script])), + FmtLowLevelScript = ?XC('pre', io_lib:format("~p", [LowLevelScript])), + [?XC('h1', ?T("Update ") ++ atom_to_list(Node))] ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; nothing -> [] end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], + [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], [?INPUTT("submit", "update", "Update"), - ?XCT("h2", "Update plan"), - ?XCT("h3", "Updated modules"), Mods, - ?XCT("h3", "Update script"), FmtScript, - ?XCT("h3", "Low level update script"), FmtLowLevelScript, - ?XCT("h3", "Script check"), ?C(atom_to_list(Check))]) + ?XCT('h2', "Update plan"), + ?XCT('h3', "Updated modules"), Mods, + ?XCT('h3', "Update script"), FmtScript, + ?XCT('h3', "Low level update script"), FmtLowLevelScript, + ?XCT('h3', "Script check"), ?C(atom_to_list(Check))]) ]; get_node(Host, Node, NPath, Query, Lang) -> @@ -1890,7 +1895,7 @@ get_node(Host, Node, NPath, Query, Lang) -> Host -> {webadmin_page_hostnode, [Host, Node, NPath, Query, Lang]} end, case ejabberd_hooks:run_fold(Hook, Host, [], Opts) of - [] -> [?XC("h1", "Not Found")]; + [] -> [?XC('h1', "Not Found")]; Res -> Res end. @@ -1921,15 +1926,15 @@ node_parse_query(Node, Query) -> db_storage_select(ID, Opt, Lang) -> - ?XAE("select", [{"name", "table" ++ ID}], + ?XAE('select', [#xmlattr{name = 'name', value = "table" ++ ID}], lists:map( fun({O, Desc}) -> Sel = if - O == Opt -> [{"selected", "selected"}]; + O == Opt -> [#xmlattr{name = 'selected', value = "selected"}]; true -> [] end, - ?XACT("option", - Sel ++ [{"value", atom_to_list(O)}], + ?XACT('option', + Sel ++ [#xmlattr{name = 'value', value = atom_to_list(O)}], Desc) end, [{ram_copies, "RAM copy"}, {disc_copies, "RAM and disc copy"}, @@ -2014,37 +2019,37 @@ node_backup_parse_query(Node, Query) -> node_ports_to_xhtml(Ports, Lang) -> - ?XAE("table", [], - [?XE("thead", - [?XE("tr", - [?XCT("td", "Port"), - ?XCT("td", "Module"), - ?XCT("td", "Options") + ?XAE('table', [], + [?XE('thead', + [?XE('tr', + [?XCT('td', "Port"), + ?XCT('td', "Module"), + ?XCT('td', "Options") ])]), - ?XE("tbody", + ?XE('tbody', lists:map( fun({Port, Module, Opts} = _E) -> SPort = integer_to_list(Port), SModule = atom_to_list(Module), %%ID = term_to_id(E), - ?XE("tr", - [?XC("td", SPort), - ?XE("td", [?INPUT("text", "module" ++ SPort, + ?XE('tr', + [?XC('td', SPort), + ?XE('td', [?INPUT("text", "module" ++ SPort, SModule)]), - ?XE("td", [?INPUTS("text", "opts" ++ SPort, + ?XE('td', [?INPUTS("text", "opts" ++ SPort, term_to_string(Opts), "40")]), - ?XE("td", [?INPUTT("submit", "add" ++ SPort, + ?XE('td', [?INPUTT("submit", "add" ++ SPort, "Update")]), - ?XE("td", [?INPUTT("submit", "delete" ++ SPort, + ?XE('td', [?INPUTT("submit", "delete" ++ SPort, "Delete")]) ] ) end, Ports) ++ - [?XE("tr", - [?XE("td", [?INPUTS("text", "portnew", "", "6")]), - ?XE("td", [?INPUT("text", "modulenew", "")]), - ?XE("td", [?INPUTS("text", "optsnew", "", "40")]), - ?XAE("td", [{"colspan", "2"}], + [?XE('tr', + [?XE('td', [?INPUTS("text", "portnew", "", "6")]), + ?XE('td', [?INPUT("text", "modulenew", "")]), + ?XE('td', [?INPUTS("text", "optsnew", "", "40")]), + ?XAE('td', [#xmlattr{name = 'colspan', value = "2"}], [?INPUTT("submit", "addnew", "Add New")]) ] )] @@ -2095,32 +2100,32 @@ node_ports_parse_query(Node, Ports, Query) -> end. node_modules_to_xhtml(Modules, Lang) -> - ?XAE("table", [], - [?XE("thead", - [?XE("tr", - [?XCT("td", "Module"), - ?XCT("td", "Options") + ?XAE('table', [], + [?XE('thead', + [?XE('tr', + [?XCT('td', "Module"), + ?XCT('td', "Options") ])]), - ?XE("tbody", + ?XE('tbody', lists:map( fun({Module, Opts} = _E) -> SModule = atom_to_list(Module), %%ID = term_to_id(E), - ?XE("tr", - [?XC("td", SModule), - ?XE("td", [?INPUTS("text", "opts" ++ SModule, + ?XE('tr', + [?XC('td', SModule), + ?XE('td', [?INPUTS("text", "opts" ++ SModule, term_to_string(Opts), "40")]), - ?XE("td", [?INPUTT("submit", "restart" ++ SModule, + ?XE('td', [?INPUTT("submit", "restart" ++ SModule, "Restart")]), - ?XE("td", [?INPUTT("submit", "stop" ++ SModule, + ?XE('td', [?INPUTT("submit", "stop" ++ SModule, "Stop")]) ] ) end, Modules) ++ - [?XE("tr", - [?XE("td", [?INPUT("text", "modulenew", "")]), - ?XE("td", [?INPUTS("text", "optsnew", "", "40")]), - ?XAE("td", [{"colspan", "2"}], + [?XE('tr', + [?XE('td', [?INPUT("text", "modulenew", "")]), + ?XE('td', [?INPUTS("text", "optsnew", "", "40")]), + ?XAE('td', [#xmlattr{name = 'colspan', value = "2"}], [?INPUTT("submit", "start", "Start")]) ] )] @@ -2181,48 +2186,6 @@ node_update_parse_query(Node, Query) -> end. -pretty_print_xml(El) -> - lists:flatten(pretty_print_xml(El, "")). - -pretty_print_xml({xmlcdata, CData}, Prefix) -> - [Prefix, CData, $\n]; -pretty_print_xml({xmlelement, Name, Attrs, Els}, Prefix) -> - [Prefix, $<, Name, - case Attrs of - [] -> - []; - [{Attr, Val} | RestAttrs] -> - AttrPrefix = [Prefix, - string:copies(" ", length(Name) + 2)], - [$\s, Attr, $=, $', xml:crypt(Val), $' | - lists:map(fun({Attr1, Val1}) -> - [$\n, AttrPrefix, - Attr1, $=, $', xml:crypt(Val1), $'] - end, RestAttrs)] - end, - if - Els == [] -> - "/>\n"; - true -> - OnlyCData = lists:all(fun({xmlcdata, _}) -> true; - ({xmlelement, _, _, _}) -> false - end, Els), - if - OnlyCData -> - [$>, - xml:get_cdata(Els), - $<, $/, Name, $>, $\n - ]; - true -> - [$>, $\n, - lists:map(fun(E) -> - pretty_print_xml(E, [Prefix, " "]) - end, Els), - Prefix, $<, $/, Name, $>, $\n - ] - end - end]. - element_to_list(X) when is_atom(X) -> atom_to_list(X); element_to_list(X) when is_integer(X) -> integer_to_list(X). @@ -2362,14 +2325,14 @@ make_menu_items2(Lang, Deep, {MURI, MName, [Item | Items]}, Res) -> make_menu_items2(Lang, Deep, {MURI, MName, Items}, Res2). make_menu_item(header, 1, URI, Name, _Lang) -> - ?LI([?XAE("div", [{"id", "navhead"}], [?AC(URI, "~ "++Name++" ~")] )]); + ?LI([?XAE('div', [#xmlattr{name = 'id', value = "navhead"}], [?AC(URI, "~ "++Name++" ~")] )]); make_menu_item(header, 2, URI, Name, _Lang) -> - ?LI([?XAE("div", [{"id", "navheadsub"}], [?AC(URI, "~ "++Name++" ~")] )]); + ?LI([?XAE('div', [#xmlattr{name = 'id', value = "navheadsub"}], [?AC(URI, "~ "++Name++" ~")] )]); make_menu_item(header, 3, URI, Name, _Lang) -> - ?LI([?XAE("div", [{"id", "navheadsubsub"}], [?AC(URI, "~ "++Name++" ~")] )]); + ?LI([?XAE('div', [#xmlattr{name = 'id', value = "navheadsubsub"}], [?AC(URI, "~ "++Name++" ~")] )]); make_menu_item(item, 1, URI, Name, Lang) -> - ?LI([?XAE("div", [{"id", "navitem"}], [?ACT(URI, Name)] )]); + ?LI([?XAE('div', [#xmlattr{name = 'id', value = "navitem"}], [?ACT(URI, Name)] )]); make_menu_item(item, 2, URI, Name, Lang) -> - ?LI([?XAE("div", [{"id", "navitemsub"}], [?ACT(URI, Name)] )]); + ?LI([?XAE('div', [#xmlattr{name = 'id', value = "navitemsub"}], [?ACT(URI, Name)] )]); make_menu_item(item, 3, URI, Name, Lang) -> - ?LI([?XAE("div", [{"id", "navitemsubsub"}], [?ACT(URI, Name)] )]). + ?LI([?XAE('div', [#xmlattr{name = 'id', value = "navitemsubsub"}], [?ACT(URI, Name)] )]). diff --git a/src/web/ejabberd_web_admin.hrl b/src/web/ejabberd_web_admin.hrl index ddceaa1ee..bfa7475e1 100644 --- a/src/web/ejabberd_web_admin.hrl +++ b/src/web/ejabberd_web_admin.hrl @@ -19,11 +19,12 @@ %%% %%%---------------------------------------------------------------------- --define(X(Name), {xmlelement, Name, [], []}). --define(XA(Name, Attrs), {xmlelement, Name, Attrs, []}). --define(XE(Name, Els), {xmlelement, Name, [], Els}). --define(XAE(Name, Attrs, Els), {xmlelement, Name, Attrs, Els}). --define(C(Text), {xmlcdata, Text}). +-define(X(Name), #xmlel{ns = ?NS_XHTML, name = Name}). +-define(XA(Name, Attrs), #xmlel{ns = ?NS_XHTML, name = Name, attrs = Attrs}). +-define(XE(Name, Els), #xmlel{ns = ?NS_XHTML, name = Name, children = Els}). +-define(XAE(Name, Attrs, Els), #xmlel{ns = ?NS_XHTML, name = Name, + attrs = Attrs, children = Els}). +-define(C(Text), #xmlcdata{cdata = list_to_binary(Text)}). -define(XC(Name, Text), ?XE(Name, [?C(Text)])). -define(XAC(Name, Attrs, Text), ?XAE(Name, Attrs, [?C(Text)])). @@ -32,21 +33,22 @@ -define(XCT(Name, Text), ?XC(Name, ?T(Text))). -define(XACT(Name, Attrs, Text), ?XAC(Name, Attrs, ?T(Text))). --define(LI(Els), ?XE("li", Els)). --define(A(URL, Els), ?XAE("a", [{"href", URL}], Els)). +-define(LI(Els), ?XE('li', Els)). +-define(A(URL, Els), ?XAE('a', [#xmlattr{name = 'href', value = URL}], Els)). -define(AC(URL, Text), ?A(URL, [?C(Text)])). -define(ACT(URL, Text), ?AC(URL, ?T(Text))). --define(P, ?X("p")). --define(BR, ?X("br")). +-define(P, ?X('p')). +-define(BR, ?X('br')). -define(INPUT(Type, Name, Value), - ?XA("input", [{"type", Type}, - {"name", Name}, - {"value", Value}])). + ?XA('input', [#xmlattr{name = 'type', value = Type}, + #xmlattr{name = 'name', value = Name}, + #xmlattr{name = 'value', value = Value}])). + -define(INPUTT(Type, Name, Value), ?INPUT(Type, Name, ?T(Value))). -define(INPUTS(Type, Name, Value, Size), - ?XA("input", [{"type", Type}, - {"name", Name}, - {"value", Value}, - {"size", Size}])). + ?XA('input', [#xmlattr{name = 'type', value = Type}, + #xmlattr{name = 'name', value = Name}, + #xmlattr{name = 'value', value = Value}, + #xmlattr{name = 'size', value = Size}])). -define(INPUTST(Type, Name, Value, Size), ?INPUT(Type, Name, ?T(Value), Size)). --define(ACLINPUT(Text), ?XE("td", [?INPUT("text", "value" ++ ID, Text)])). +-define(ACLINPUT(Text), ?XE('td', [?INPUT("text", "value" ++ ID, Text)])). From 0313adaec6eec23531ec3365556e8ccd7426ba41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 20 Oct 2008 10:34:00 +0000 Subject: [PATCH 123/582] Convert to exmpp. PR: EJABP-1 SVN Revision: 1663 --- ChangeLog | 5 + src/mod_irc/mod_irc.erl | 312 ++++++++++++------------- src/mod_irc/mod_irc_connection.erl | 360 +++++++++++++---------------- 3 files changed, 315 insertions(+), 362 deletions(-) diff --git a/ChangeLog b/ChangeLog index 183259f56..f46777ed2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-10-20 Jean-Sébastien Pédron + + * src/mod_irc/mod_irc.erl, src/mod_irc/mod_irc_connection.erl: Convert + to exmpp. + 2008-10-13 Jean-Sébastien Pédron * src/web/ejabberd_http.erl, src/web/ejabberd_http_poll.erl, diff --git a/src/mod_irc/mod_irc.erl b/src/mod_irc/mod_irc.erl index dd86037b9..3ef7f8ca5 100644 --- a/src/mod_irc/mod_irc.erl +++ b/src/mod_irc/mod_irc.erl @@ -40,8 +40,9 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -record(irc_connection, {jid_server_host, pid}). -record(irc_custom, {us_host, data}). @@ -193,60 +194,55 @@ do_route(Host, ServerHost, Access, From, To, Packet, DefEnc) -> allow -> do_route1(Host, ServerHost, From, To, Packet, DefEnc); _ -> - {xmlelement, _Name, Attrs, _Els} = Packet, - Lang = xml:get_attr_s("xml:lang", Attrs), - ErrText = "Access denied by service policy", - Err = jlib:make_error_reply(Packet, - ?ERRT_FORBIDDEN(Lang, ErrText)), + Lang = exmpp_stanza:get_lang(Packet), + ErrText = translate:translate(Lang, + "Access denied by service policy"), + Err = exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, + 'forbidden', {Lang, ErrText})), ejabberd_router:route(To, From, Err) end. do_route1(Host, ServerHost, From, To, Packet, DefEnc) -> - #jid{user = ChanServ, resource = Resource} = To, - {xmlelement, _Name, _Attrs, _Els} = Packet, + #jid{node = ChanServ, resource = Resource} = To, case ChanServ of - "" -> + undefined -> case Resource of - "" -> - case jlib:iq_query_info(Packet) of - #iq{type = get, xmlns = ?NS_DISCO_INFO = XMLNS, - sub_el = _SubEl, lang = Lang} = IQ -> - Res = IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", XMLNS}], - iq_disco(Lang)}]}, + undefined -> + case exmpp_iq:xmlel_to_iq(Packet) of + #iq{type = get, ns = ?NS_DISCO_INFO = XMLNS, + lang = Lang} = IQ_Rec -> + Result = #xmlel{ns = XMLNS, name = 'query', + children = iq_disco(Lang)}, + Res = exmpp_iq:result(IQ_Rec, Result), ejabberd_router:route(To, From, - jlib:iq_to_xml(Res)); - #iq{type = get, xmlns = ?NS_DISCO_ITEMS = XMLNS} = IQ -> - Res = IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", XMLNS}], - []}]}, + exmpp_iq:iq_to_xmlel(Res)); + #iq{type = get, ns = ?NS_DISCO_ITEMS = XMLNS} = IQ_Rec -> + Result = #xmlel{ns = XMLNS, name = 'query'}, + Res = exmpp_iq:result(IQ_Rec, Result), ejabberd_router:route(To, From, - jlib:iq_to_xml(Res)); - #iq{xmlns = ?NS_REGISTER} = IQ -> - process_register(Host, From, To, DefEnc, IQ); - #iq{type = get, xmlns = ?NS_VCARD = XMLNS, - lang = Lang} = IQ -> - Res = IQ#iq{type = result, - sub_el = - [{xmlelement, "vCard", - [{"xmlns", XMLNS}], - iq_get_vcard(Lang)}]}, + exmpp_iq:iq_to_xmlel(Res)); + #iq{kind = request, ns = ?NS_INBAND_REGISTER} = IQ_Rec -> + process_register(Host, From, To, DefEnc, IQ_Rec); + #iq{type = get, ns = ?NS_VCARD = XMLNS, + lang = Lang} = IQ_Rec -> + Result = #xmlel{ns = XMLNS, name = 'vCard', + children = iq_get_vcard(Lang)}, + Res = exmpp_iq:result(IQ_Rec, Result), ejabberd_router:route(To, From, - jlib:iq_to_xml(Res)); - #iq{} = _IQ -> - Err = jlib:make_error_reply( - Packet, ?ERR_FEATURE_NOT_IMPLEMENTED), + exmpp_iq:iq_to_xmlel(Res)); + #iq{} = _IQ_Rec -> + Err = exmpp_iq:error( + Packet, 'feature-not-implemented'), ejabberd_router:route(To, From, Err); _ -> ok end; _ -> - Err = jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST), + Err = exmpp_stanza:reply_with_error(Packet, 'bad-request'), ejabberd_router:route(To, From, Err) end; _ -> @@ -280,8 +276,8 @@ do_route1(Host, ServerHost, From, To, Packet, DefEnc) -> [[_ | _] = Nick, [_ | _] = Server] -> case ets:lookup(irc_connection, {From, Server, Host}) of [] -> - Err = jlib:make_error_reply( - Packet, ?ERR_SERVICE_UNAVAILABLE), + Err = exmpp_stanza:reply_with_error( + Packet, 'service-unavailable'), ejabberd_router:route(To, From, Err); [R] -> Pid = R#irc_connection.pid, @@ -292,8 +288,8 @@ do_route1(Host, ServerHost, From, To, Packet, DefEnc) -> ok end; _ -> - Err = jlib:make_error_reply( - Packet, ?ERR_BAD_REQUEST), + Err = exmpp_stanza:reply_with_error( + Packet, 'bad-request'), ejabberd_router:route(To, From, Err) end end @@ -305,164 +301,148 @@ closed_connection(Host, From, Server) -> iq_disco(Lang) -> - [{xmlelement, "identity", - [{"category", "conference"}, - {"type", "irc"}, - {"name", translate:translate(Lang, "IRC Transport")}], []}, - {xmlelement, "feature", - [{"var", ?NS_MUC}], []}, - {xmlelement, "feature", - [{"var", ?NS_REGISTER}], []}, - {xmlelement, "feature", - [{"var", ?NS_VCARD}], []}]. + [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = + [#xmlattr{name = 'category', value = "conference"}, + #xmlattr{name = 'type', value = "irc"}, + #xmlattr{name = 'name', value = translate:translate(Lang, "IRC Transport")}]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = + [#xmlattr{name = 'var', value = ?NS_MUC_s}]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = + [#xmlattr{name = 'var', value = ?NS_INBAND_REGISTER_s}]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = + [#xmlattr{name = 'var', value = ?NS_VCARD_s}]}]. iq_get_vcard(Lang) -> - [{xmlelement, "FN", [], - [{xmlcdata, "ejabberd/mod_irc"}]}, - {xmlelement, "URL", [], - [{xmlcdata, ?EJABBERD_URI}]}, - {xmlelement, "DESC", [], - [{xmlcdata, translate:translate(Lang, "ejabberd IRC module") ++ - "\nCopyright (c) 2003-2008 Alexey Shchepin"}]}]. + [#xmlel{ns = ?NS_VCARD, name = 'FN', children = + [#xmlcdata{cdata = <<"ejabberd/mod_irc">>}]}, + #xmlel{ns = ?NS_VCARD, name = 'URL', children = + [#xmlcdata{cdata = list_to_binary(?EJABBERD_URI)}]}, + #xmlel{ns = ?NS_VCARD, name = 'DESC', children = + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "ejabberd IRC module") ++ + "\nCopyright (c) 2003-2008 Alexey Shchepin")}]}]. -process_register(Host, From, To, DefEnc, #iq{} = IQ) -> - case catch process_irc_register(Host, From, To, DefEnc, IQ) of +process_register(Host, From, To, DefEnc, #iq{} = IQ_Rec) -> + case catch process_irc_register(Host, From, To, DefEnc, IQ_Rec) of {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); ResIQ -> if ResIQ /= ignore -> ejabberd_router:route(To, From, - jlib:iq_to_xml(ResIQ)); + exmpp_iq:iq_to_xmlel(ResIQ)); true -> ok end end. -find_xdata_el({xmlelement, _Name, _Attrs, SubEls}) -> +find_xdata_el(#xmlel{children = SubEls}) -> find_xdata_el1(SubEls). find_xdata_el1([]) -> false; -find_xdata_el1([{xmlelement, Name, Attrs, SubEls} | Els]) -> - case xml:get_attr_s("xmlns", Attrs) of - ?NS_XDATA -> - {xmlelement, Name, Attrs, SubEls}; - _ -> - find_xdata_el1(Els) - end; +find_xdata_el1([#xmlel{ns = ?NS_DATA_FORMS} = El | _Els]) -> + El; find_xdata_el1([_ | Els]) -> find_xdata_el1(Els). process_irc_register(Host, From, _To, DefEnc, - #iq{type = Type, xmlns = XMLNS, - lang = Lang, sub_el = SubEl} = IQ) -> - case Type of - set -> - XDataEl = find_xdata_el(SubEl), - case XDataEl of - false -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ACCEPTABLE]}; - {xmlelement, _Name, Attrs, _SubEls} -> - case xml:get_attr_s("type", Attrs) of - "cancel" -> - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", XMLNS}], []}]}; - "submit" -> - XData = jlib:parse_xdata_submit(XDataEl), - case XData of - invalid -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_BAD_REQUEST]}; - _ -> - Node = string:tokens( - xml:get_tag_attr_s("node", SubEl), - "/"), - case set_form( - Host, From, Node, Lang, XData) of - {result, Res} -> - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", XMLNS}], - Res - }]}; - {error, Error} -> - IQ#iq{type = error, - sub_el = [SubEl, Error]} - end - end; + #iq{type = get, ns = XMLNS, + lang = Lang, payload = SubEl} = IQ_Rec) -> + Node = + string:tokens(exmpp_xml:get_attribute(SubEl, 'node', ""), "/"), + case get_form(Host, From, Node, Lang ,DefEnc) of + {result, Res} -> + Result = #xmlel{ns = XMLNS, name = 'query', children = Res}, + exmpp_iq:result(IQ_Rec, Result); + {error, Error} -> + exmpp_iq:error(IQ_Rec, Error) + end; +process_irc_register(Host, From, _To, _DefEnc, + #iq{type = set, ns = XMLNS, + lang = Lang, payload = SubEl} = IQ_Rec) -> + XDataEl = find_xdata_el(SubEl), + case XDataEl of + false -> + exmpp_iq:error(IQ_Rec, 'not-acceptable'); + _ -> + case exmpp_stanza:get_type(XDataEl) of + "cancel" -> + Result = #xmlel{ns = XMLNS, name = 'query'}, + exmpp_iq:result(IQ_Rec, Result); + "submit" -> + XData = jlib:parse_xdata_submit(XDataEl), + case XData of + invalid -> + exmpp_iq:error(IQ_Rec, 'bad-request'); _ -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_BAD_REQUEST]} - end - end; - get -> - Node = - string:tokens(xml:get_tag_attr_s("node", SubEl), "/"), - case get_form(Host, From, Node, Lang ,DefEnc) of - {result, Res} -> - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", XMLNS}], - Res - }]}; - {error, Error} -> - IQ#iq{type = error, - sub_el = [SubEl, Error]} + Node = string:tokens( + exmpp_xml:get_attribute(SubEl, "node", ""), + "/"), + case set_form( + Host, From, Node, Lang, XData) of + {result, Res} -> + Result = #xmlel{ns = XMLNS, name = 'query', + children = Res}, + exmpp_iq:result(IQ_Rec, Result); + {error, Error} -> + exmpp_iq:error(IQ_Rec, Error) + end + end; + _ -> + exmpp_iq:error(IQ_Rec, 'bad-request') end end. get_form(Host, From, [], Lang, DefEnc) -> - #jid{user = User, server = Server, - luser = LUser, lserver = LServer} = From, + #jid{node = User, domain = Server, + lnode = LUser, ldomain = LServer} = From, US = {LUser, LServer}, Customs = case catch mnesia:dirty_read({irc_custom, {US, Host}}) of {'EXIT', _Reason} -> - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, 'internal-server-error'}; [] -> {User, []}; [#irc_custom{data = Data}] -> - {xml:get_attr_s(username, Data), - xml:get_attr_s(encodings, Data)} + {proplists:get_value(username, Data, ""), + proplists:get_value(encodings, Data, "")} end, case Customs of {error, _Error} -> Customs; {Username, Encodings} -> {result, - [{xmlelement, "instructions", [], - [{xmlcdata, + [#xmlel{ns = ?NS_INBAND_REGISTER, name = 'instructions', children = + [#xmlcdata{cdata = list_to_binary( translate:translate( Lang, "You need an x:data capable client " - "to configure mod_irc settings")}]}, - {xmlelement, "x", [{"xmlns", ?NS_XDATA}], - [{xmlelement, "title", [], - [{xmlcdata, + "to configure mod_irc settings"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary( translate:translate( Lang, - "Registration in mod_irc for ") ++ User ++ "@" ++ Server}]}, - {xmlelement, "instructions", [], - [{xmlcdata, + "Registration in mod_irc for ") ++ User ++ "@" ++ Server)}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = + [#xmlcdata{cdata = list_to_binary( translate:translate( Lang, "Enter username and encodings you wish to use for " - "connecting to IRC servers")}]}, - {xmlelement, "field", [{"type", "text-single"}, - {"label", + "connecting to IRC servers"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = "text-single"}, + #xmlattr{name = 'label', value = translate:translate( Lang, "IRC Username")}, - {"var", "username"}], - [{xmlelement, "value", [], [{xmlcdata, Username}]}]}, - {xmlelement, "field", [{"type", "fixed"}], - [{xmlelement, "value", [], - [{xmlcdata, + #xmlattr{name = 'var', value = "username"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Username)}]}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = "fixed"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = + [#xmlcdata{cdata = list_to_binary( lists:flatten( io_lib:format( translate:translate( @@ -471,22 +451,22 @@ get_form(Host, From, [], Lang, DefEnc) -> "for IRC servers, fill this list with values " "in format '{\"irc server\", \"encoding\"}'. " "By default this service use \"~s\" encoding."), - [DefEnc]))}]}]}, - {xmlelement, "field", [{"type", "fixed"}], - [{xmlelement, "value", [], - [{xmlcdata, + [DefEnc])))}]}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = "fixed"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = + [#xmlcdata{cdata = list_to_binary( translate:translate( Lang, "Example: [{\"irc.lucky.net\", \"koi8-r\"}, " "{\"vendetta.fef.net\", \"iso8859-1\"}]." - )}]}]}, - {xmlelement, "field", [{"type", "text-multi"}, - {"label", + ))}]}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = "text-multi"}, + #xmlattr{name = 'label', value = translate:translate(Lang, "Encodings")}, - {"var", "encodings"}], + #xmlattr{name = 'var', value = "encodings"}], children = lists:map( fun(S) -> - {xmlelement, "value", [], [{xmlcdata, S}]} + #xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(S)}]} end, string:tokens( lists:flatten( @@ -497,13 +477,13 @@ get_form(Host, From, [], Lang, DefEnc) -> end; get_form(_Host, _, _, _Lang, _) -> - {error, ?ERR_SERVICE_UNAVAILABLE}. + {error, 'service-unavailable'}. set_form(Host, From, [], _Lang, XData) -> - {LUser, LServer, _} = jlib:jid_tolower(From), + {LUser, LServer, _} = jlib:short_prepd_jid(From), US = {LUser, LServer}, case {lists:keysearch("username", 1, XData), lists:keysearch("encodings", 1, XData)} of @@ -529,26 +509,26 @@ set_form(Host, From, [], _Lang, XData) -> {atomic, _} -> {result, []}; _ -> - {error, ?ERR_NOT_ACCEPTABLE} + {error, 'not-acceptable'} end; _ -> - {error, ?ERR_NOT_ACCEPTABLE} + {error, 'not-acceptable'} end; _ -> - {error, ?ERR_NOT_ACCEPTABLE} + {error, 'not-acceptable'} end; _ -> - {error, ?ERR_NOT_ACCEPTABLE} + {error, 'not-acceptable'} end; set_form(_Host, _, _, _Lang, _XData) -> - {error, ?ERR_SERVICE_UNAVAILABLE}. + {error, 'service-unavailable'}. get_user_and_encoding(Host, From, IRCServer, DefEnc) -> - #jid{user = User, server = _Server, - luser = LUser, lserver = LServer} = From, + #jid{node = User, domain = _Server, + lnode = LUser, ldomain = LServer} = From, US = {LUser, LServer}, case catch mnesia:dirty_read({irc_custom, {US, Host}}) of {'EXIT', _Reason} -> @@ -556,8 +536,8 @@ get_user_and_encoding(Host, From, IRCServer, DefEnc) -> [] -> {User, DefEnc}; [#irc_custom{data = Data}] -> - {xml:get_attr_s(username, Data), - case xml:get_attr_s(IRCServer, xml:get_attr_s(encodings, Data)) of + {proplists:get_value(username, Data, ""), + case proplists:get_value(IRCServer, proplists:get_value(encodings, Data, ""), "") of "" -> DefEnc; E -> E end} diff --git a/src/mod_irc/mod_irc_connection.erl b/src/mod_irc/mod_irc_connection.erl index 244f5300d..3548effa2 100644 --- a/src/mod_irc/mod_irc_connection.erl +++ b/src/mod_irc/mod_irc_connection.erl @@ -43,8 +43,9 @@ terminate/3, code_change/4]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -define(SETS, gb_sets). @@ -122,8 +123,8 @@ open_socket(init, StateData) -> {error, Reason} -> ?DEBUG("connect return ~p~n", [Reason]), Text = case Reason of - timeout -> "Server Connect Timeout"; - _ -> "Server Connect Failed" + timeout -> <<"Server Connect Timeout">>; + _ -> <<"Server Connect Failed">> end, bounce_messages(Text), {stop, normal, StateData} @@ -197,22 +198,22 @@ code_change(_OldVsn, StateName, StateData, _Extra) -> %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- handle_info({route_chan, Channel, Resource, - {xmlelement, "presence", Attrs, _Els}}, - StateName, StateData) -> + El}, + StateName, StateData) when ?IS_PRESENCE(El) -> NewStateData = - case xml:get_attr_s("type", Attrs) of - "unavailable" -> + case exmpp_presence:get_type(El) of + 'unavailable' -> S1 = ?SEND(io_lib:format("PART #~s\r\n", [Channel])), S1#state{channels = dict:erase(Channel, S1#state.channels)}; - "subscribe" -> StateData; - "subscribed" -> StateData; - "unsubscribe" -> StateData; - "unsubscribed" -> StateData; - "error" -> stop; + 'subscribe' -> StateData; + 'subscribed' -> StateData; + 'unsubscribe' -> StateData; + 'unsubscribed' -> StateData; + 'error' -> stop; _ -> Nick = case Resource of - "" -> + undefined -> StateData#state.nick; _ -> Resource @@ -243,20 +244,20 @@ handle_info({route_chan, Channel, Resource, end; handle_info({route_chan, Channel, Resource, - {xmlelement, "message", Attrs, _Els} = El}, - StateName, StateData) -> + El}, + StateName, StateData) when ?IS_MESSAGE(El) -> NewStateData = - case xml:get_attr_s("type", Attrs) of - "groupchat" -> - case xml:get_path_s(El, [{elem, "subject"}, cdata]) of - "" -> + case exmpp_message:get_type(El) of + 'groupchat' -> + case exmpp_message:get_subject(El) of + undefined -> ejabberd_router:route( - jlib:make_jid( + exmpp_jid:make_jid( lists:concat( [Channel, "%", StateData#state.server]), StateData#state.host, StateData#state.nick), StateData#state.user, El), - Body = xml:get_path_s(El, [{elem, "body"}, cdata]), + Body = binary_to_list(exmpp_message:get_body(El)), case Body of "/quote " ++ Rest -> ?SEND(Rest ++ "\r\n"); @@ -309,8 +310,8 @@ handle_info({route_chan, Channel, Resource, end, Strings)), ?SEND(Res) end; - Type when Type == "chat"; Type == ""; Type == "normal" -> - Body = xml:get_path_s(El, [{elem, "body"}, cdata]), + Type when Type == 'chat'; Type == 'normal' -> + Body = binary_to_list(exmpp_message:get_body(El)), case Body of "/quote " ++ Rest -> ?SEND(Rest ++ "\r\n"); @@ -351,7 +352,7 @@ handle_info({route_chan, Channel, Resource, end, Strings)), ?SEND(Res) end; - "error" -> + 'error' -> stop; _ -> StateData @@ -365,38 +366,34 @@ handle_info({route_chan, Channel, Resource, handle_info({route_chan, Channel, Resource, - {xmlelement, "iq", _Attrs, _Els} = El}, - StateName, StateData) -> + El}, + StateName, StateData) when ?IS_IQ(El) -> From = StateData#state.user, - To = jlib:make_jid(lists:concat([Channel, "%", StateData#state.server]), + To = exmpp_jid:make_jid(lists:concat([Channel, "%", StateData#state.server]), StateData#state.host, StateData#state.nick), - case jlib:iq_query_info(El) of - #iq{xmlns = ?NS_MUC_ADMIN} = IQ -> - iq_admin(StateData, Channel, From, To, IQ); - #iq{xmlns = ?NS_VERSION} -> + case exmpp_iq:xmlel_to_iq(El) of + #iq{kind = request, ns = ?NS_MUC_ADMIN} = IQ_Rec -> + iq_admin(StateData, Channel, From, To, IQ_Rec); + #iq{kind = request, ns = ?NS_SOFT_VERSION} -> Res = io_lib:format("PRIVMSG ~s :\001VERSION\001\r\n", [Resource]), ?SEND(Res), - Err = jlib:make_error_reply( - El, ?ERR_FEATURE_NOT_IMPLEMENTED), + Err = exmpp_iq:error(El, 'feature-not-implemented'), ejabberd_router:route(To, From, Err); - #iq{xmlns = ?NS_TIME} -> + #iq{kind = request, ns = ?NS_TIME_OLD} -> Res = io_lib:format("PRIVMSG ~s :\001TIME\001\r\n", [Resource]), ?SEND(Res), - Err = jlib:make_error_reply( - El, ?ERR_FEATURE_NOT_IMPLEMENTED), + Err = exmpp_iq:error(El, 'feature-not-implemented'), ejabberd_router:route(To, From, Err); - #iq{xmlns = ?NS_VCARD} -> + #iq{kind = request, ns = ?NS_VCARD} -> Res = io_lib:format("WHOIS ~s \r\n", [Resource]), ?SEND(Res), - Err = jlib:make_error_reply( - El, ?ERR_FEATURE_NOT_IMPLEMENTED), + Err = exmpp_iq:error(El, 'feature-not-implemented'), ejabberd_router:route(To, From, Err); #iq{} -> - Err = jlib:make_error_reply( - El, ?ERR_FEATURE_NOT_IMPLEMENTED), + Err = exmpp_iq:error(El, 'feature-not-implemented'), ejabberd_router:route(To, From, Err); _ -> ok @@ -408,12 +405,12 @@ handle_info({route_chan, _Channel, _Resource, _Packet}, StateName, StateData) -> handle_info({route_nick, Nick, - {xmlelement, "message", Attrs, _Els} = El}, - StateName, StateData) -> + El}, + StateName, StateData) when ?IS_MESSAGE(El) -> NewStateData = - case xml:get_attr_s("type", Attrs) of - "chat" -> - Body = xml:get_path_s(El, [{elem, "body"}, cdata]), + case exmpp_message:get_type(El) of + 'chat' -> + Body = binary_to_list(exmpp_message:get_body(El)), case Body of "/quote " ++ Rest -> ?SEND(Rest ++ "\r\n"); @@ -451,7 +448,7 @@ handle_info({route_nick, Nick, end, Strings)), ?SEND(Res) end; - "error" -> + 'error' -> stop; _ -> StateData @@ -585,17 +582,17 @@ terminate(_Reason, _StateName, StateData) -> mod_irc:closed_connection(StateData#state.host, StateData#state.user, StateData#state.server), - bounce_messages("Server Connect Failed"), + bounce_messages(<<"Server Connect Failed">>), lists:foreach( fun(Chan) -> ejabberd_router:route( - jlib:make_jid( + exmpp_jid:make_jid( lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, StateData#state.nick), StateData#state.user, - {xmlelement, "presence", [{"type", "error"}], - [{xmlelement, "error", [{"code", "502"}], - [{xmlcdata, "Server Connect Failed"}]}]}) + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = "error"}], children = + [#xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', attrs = [#xmlattr{name = 'code', value = "502"}], children = + [#xmlcdata{cdata = <<"Server Connect Failed">>}]}]}) end, dict:fetch_keys(StateData#state.channels)), case StateData#state.socket of undefined -> @@ -627,15 +624,16 @@ send_text(#state{socket = Socket, encoding = Encoding}, Text) -> bounce_messages(Reason) -> receive {send_element, El} -> - {xmlelement, _Name, Attrs, _SubTags} = El, - case xml:get_attr_s("type", Attrs) of + case exmpp_stanza:get_type(El) of "error" -> ok; _ -> - Err = jlib:make_error_reply(El, - "502", Reason), - From = jlib:string_to_jid(xml:get_attr_s("from", Attrs)), - To = jlib:string_to_jid(xml:get_attr_s("to", Attrs)), + Error = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', + attrs = [#xmlattr{name = 'code', value = "502"}], + children = [#xmlcdata{cdata = Reason}]}, + Err = exmpp_stanza:reply_with_error(El, Error), + From = exmpp_jid:list_to_jid(exmpp_stanza:get_sender(El)), + To = exmpp_jid:list_to_jid(exmpp_stanza:get_recipient(El)), ejabberd_router:route(To, From, Err) end, bounce_messages(Reason) @@ -688,15 +686,14 @@ process_channel_list_user(StateData, Chan, User) -> _ -> {User1, "member", "participant"} end, ejabberd_router:route( - jlib:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, User2), StateData#state.user, - {xmlelement, "presence", [], - [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], - [{xmlelement, "item", - [{"affiliation", Affiliation}, - {"role", Role}], - []}]}]}), + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = + [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = + [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = + [#xmlattr{name = 'affiliation', value = Affiliation}, + #xmlattr{name = 'role', value = Role}]}]}]}), case catch dict:update(Chan, fun(Ps) -> ?SETS:add_element(User2, Ps) @@ -712,14 +709,11 @@ process_channel_topic(StateData, Chan, String) -> {ok, Msg, _} = regexp:sub(String, ".*332[^:]*:", ""), Msg1 = filter_message(Msg), ejabberd_router:route( - jlib:make_jid( + exmpp_jid:make_jid( lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, ""), StateData#state.user, - {xmlelement, "message", [{"type", "groupchat"}], - [{xmlelement, "subject", [], [{xmlcdata, Msg1}]}, - {xmlelement, "body", [], [{xmlcdata, "Topic for #" ++ Chan ++ ": " ++ Msg1}]} - ]}). + exmpp_message:groupchat(Msg1, "Topic for #" ++ Chan ++ ": " ++ Msg1)). process_channel_topic_who(StateData, Chan, String) -> Words = string:tokens(String, " "), @@ -740,55 +734,47 @@ process_channel_topic_who(StateData, Chan, String) -> Msg2 = filter_message(Msg1), ejabberd_router:route( - jlib:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, ""), StateData#state.user, - {xmlelement, "message", [{"type", "groupchat"}], - [{xmlelement, "body", [], [{xmlcdata, Msg2}]}]}). + exmpp_message:groupchat(Msg2)). process_endofwhois(StateData, _String, Nick) -> ejabberd_router:route( - jlib:make_jid(lists:concat([Nick, "!", StateData#state.server]), + exmpp_jid:make_jid(lists:concat([Nick, "!", StateData#state.server]), StateData#state.host, ""), StateData#state.user, - {xmlelement, "message", [{"type", "chat"}], - [{xmlelement, "body", [], [{xmlcdata, "End of WHOIS"}]}]}). + exmpp_message:chat("End of WHOIS")). process_whois311(StateData, String, Nick, Ident, Irchost) -> {ok, Fullname, _} = regexp:sub(String, ".*311[^:]*:", ""), ejabberd_router:route( - jlib:make_jid(lists:concat([Nick, "!", StateData#state.server]), + exmpp_jid:make_jid(lists:concat([Nick, "!", StateData#state.server]), StateData#state.host, ""), StateData#state.user, - {xmlelement, "message", [{"type", "chat"}], - [{xmlelement, "body", [], - [{xmlcdata, lists:concat( + exmpp_message:chat(lists:concat( ["WHOIS: ", Nick, " is ", - Ident, "@" , Irchost, " : " , Fullname])}]}]}). + Ident, "@" , Irchost, " : " , Fullname]))). process_whois312(StateData, String, Nick, Ircserver) -> {ok, Ircserverdesc, _} = regexp:sub(String, ".*312[^:]*:", ""), ejabberd_router:route( - jlib:make_jid(lists:concat([Nick, "!", StateData#state.server]), + exmpp_jid:make_jid(lists:concat([Nick, "!", StateData#state.server]), StateData#state.host, ""), StateData#state.user, - {xmlelement, "message", [{"type", "chat"}], - [{xmlelement, "body", [], - [{xmlcdata, lists:concat(["WHOIS: ", Nick, " use ", - Ircserver, " : ", Ircserverdesc])}]}]}). + exmpp_message:chat(lists:concat(["WHOIS: ", Nick, " use ", + Ircserver, " : ", Ircserverdesc]))). process_whois319(StateData, String, Nick) -> {ok, Chanlist, _} = regexp:sub(String, ".*319[^:]*:", ""), ejabberd_router:route( - jlib:make_jid(lists:concat([Nick, "!", StateData#state.server]), + exmpp_jid:make_jid(lists:concat([Nick, "!", StateData#state.server]), StateData#state.host, ""), StateData#state.user, - {xmlelement, "message", [{"type", "chat"}], - [{xmlelement, "body", [], - [{xmlcdata, lists:concat(["WHOIS: ", Nick, " is on ", - Chanlist])}]}]}). + exmpp_message:chat(lists:concat(["WHOIS: ", Nick, " is on ", + Chanlist]))). @@ -803,11 +789,10 @@ process_chanprivmsg(StateData, Chan, From, String) -> end, Msg2 = filter_message(Msg1), ejabberd_router:route( - jlib:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, - {xmlelement, "message", [{"type", "groupchat"}], - [{xmlelement, "body", [], [{xmlcdata, Msg2}]}]}). + exmpp_message:groupchat(Msg2)). @@ -822,11 +807,10 @@ process_channotice(StateData, Chan, From, String) -> end, Msg2 = filter_message(Msg1), ejabberd_router:route( - jlib:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, - {xmlelement, "message", [{"type", "groupchat"}], - [{xmlelement, "body", [], [{xmlcdata, Msg2}]}]}). + exmpp_message:groupchat(Msg2)). @@ -842,11 +826,10 @@ process_privmsg(StateData, _Nick, From, String) -> end, Msg2 = filter_message(Msg1), ejabberd_router:route( - jlib:make_jid(lists:concat([FromUser, "!", StateData#state.server]), - StateData#state.host, ""), + exmpp_jid:make_jid(lists:concat([FromUser, "!", StateData#state.server]), + StateData#state.host, undefined), StateData#state.user, - {xmlelement, "message", [{"type", "chat"}], - [{xmlelement, "body", [], [{xmlcdata, Msg2}]}]}). + exmpp_message:chat(Msg2)). process_notice(StateData, _Nick, From, String) -> @@ -860,11 +843,10 @@ process_notice(StateData, _Nick, From, String) -> end, Msg2 = filter_message(Msg1), ejabberd_router:route( - jlib:make_jid(lists:concat([FromUser, "!", StateData#state.server]), - StateData#state.host, ""), + exmpp_jid:make_jid(lists:concat([FromUser, "!", StateData#state.server]), + StateData#state.host, undefined), StateData#state.user, - {xmlelement, "message", [{"type", "chat"}], - [{xmlelement, "body", [], [{xmlcdata, Msg2}]}]}). + exmpp_message:chat(Msg2)). process_version(StateData, _Nick, From) -> @@ -889,7 +871,7 @@ process_userinfo(StateData, _Nick, From) -> "xmpp:~s" "\001\r\n", [FromUser, - jlib:jid_to_string(StateData#state.user)])). + exmpp_jid:jid_to_list(StateData#state.user)])). process_topic(StateData, Chan, From, String) -> @@ -897,31 +879,27 @@ process_topic(StateData, Chan, From, String) -> {ok, Msg, _} = regexp:sub(String, ".*TOPIC[^:]*:", ""), Msg1 = filter_message(Msg), ejabberd_router:route( - jlib:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, - {xmlelement, "message", [{"type", "groupchat"}], - [{xmlelement, "subject", [], [{xmlcdata, Msg1}]}, - {xmlelement, "body", [], - [{xmlcdata, "/me has changed the subject to: " ++ - Msg1}]}]}). + exmpp_message:groupchat(Msg1, + "/me has changed the subject to: " ++ Msg1)). process_part(StateData, Chan, From, String) -> [FromUser | FromIdent] = string:tokens(From, "!"), {ok, Msg, _} = regexp:sub(String, ".*PART[^:]*:", ""), Msg1 = filter_message(Msg), ejabberd_router:route( - jlib:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, - {xmlelement, "presence", [{"type", "unavailable"}], - [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], - [{xmlelement, "item", - [{"affiliation", "member"}, - {"role", "none"}], - []}]}, - {xmlelement, "status", [], - [{xmlcdata, Msg1 ++ " (" ++ FromIdent ++ ")"}]}] + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = "unavailable"}], children = + [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = + [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = + [#xmlattr{name = 'affiliation', value = "member"}, + #xmlattr{name = 'role', value = "none"}]}]}, + #xmlel{ns = ?NS_MUC_USER, name = 'status', children = + [#xmlcdata{cdata = list_to_binary(Msg1 ++ " (" ++ FromIdent ++ ")")}]}] }), case catch dict:update(Chan, fun(Ps) -> @@ -945,18 +923,17 @@ process_quit(StateData, From, String) -> case ?SETS:is_member(FromUser, Ps) of true -> ejabberd_router:route( - jlib:make_jid( + exmpp_jid:make_jid( lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, - {xmlelement, "presence", [{"type", "unavailable"}], - [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], - [{xmlelement, "item", - [{"affiliation", "member"}, - {"role", "none"}], - []}]}, - {xmlelement, "status", [], - [{xmlcdata, Msg1 ++ " (" ++ FromIdent ++ ")"}]} + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = "unavailable"}], children = + [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = + [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = + [#xmlattr{name = 'affiliation', value = "member"}, + #xmlattr{name = 'role', value = "none"}]}]}, + #xmlel{ns = ?NS_MUC_USER, name = 'status', children = + [#xmlcdata{cdata = list_to_binary(Msg1 ++ " (" ++ FromIdent ++ ")")}]} ]}), remove_element(FromUser, Ps); _ -> @@ -970,17 +947,16 @@ process_join(StateData, Channel, From, _String) -> [FromUser | FromIdent] = string:tokens(From, "!"), Chan = lists:subtract(Channel, ":#"), ejabberd_router:route( - jlib:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, - {xmlelement, "presence", [], - [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], - [{xmlelement, "item", - [{"affiliation", "member"}, - {"role", "participant"}], - []}]}, - {xmlelement, "status", [], - [{xmlcdata, FromIdent}]}]}), + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = + [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = + [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = + [#xmlattr{name = 'affiliation', value = "member"}, + #xmlattr{name = 'role', value = "participant"}]}]}, + #xmlel{ns = ?NS_MUC_USER, name = 'status', children = + [#xmlcdata{cdata = list_to_binary(FromIdent)}]}]}), case catch dict:update(Chan, fun(Ps) -> @@ -997,36 +973,33 @@ process_join(StateData, Channel, From, _String) -> process_mode_o(StateData, Chan, _From, Nick, Affiliation, Role) -> %Msg = lists:last(string:tokens(String, ":")), ejabberd_router:route( - jlib:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, Nick), StateData#state.user, - {xmlelement, "presence", [], - [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], - [{xmlelement, "item", - [{"affiliation", Affiliation}, - {"role", Role}], - []}]}]}). + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = + [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = + [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = + [#xmlattr{name = 'affiliation', value = Affiliation}, + #xmlattr{name = 'role', value = Role}]}]}]}). process_kick(StateData, Chan, From, Nick, String) -> Msg = lists:last(string:tokens(String, ":")), Msg2 = Nick ++ " kicked by " ++ From ++ " (" ++ filter_message(Msg) ++ ")", ejabberd_router:route( - jlib:make_jid(lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, ""), + exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), + StateData#state.host, undefined), StateData#state.user, - {xmlelement, "message", [{"type", "groupchat"}], - [{xmlelement, "body", [], [{xmlcdata, Msg2}]}]}), + exmpp_message:groupchat(Msg2)), ejabberd_router:route( - jlib:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, Nick), StateData#state.user, - {xmlelement, "presence", [{"type", "unavailable"}], - [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], - [{xmlelement, "item", - [{"affiliation", "none"}, - {"role", "none"}], - []}, - {xmlelement, "status", [{"code", "307"}], []} + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = "unavailable"}], children = + [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = + [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = + [#xmlattr{name = 'affiliation', value = "none"}, + #xmlattr{name = 'role', value = "none"}]}, + #xmlel{ns = ?NS_MUC_USER, name = 'status', attrs = [#xmlattr{name = 'code', value = "307"}]} ]}]}). process_nick(StateData, From, NewNick) -> @@ -1038,30 +1011,28 @@ process_nick(StateData, From, NewNick) -> case ?SETS:is_member(FromUser, Ps) of true -> ejabberd_router:route( - jlib:make_jid( + exmpp_jid:make_jid( lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, - {xmlelement, "presence", [{"type", "unavailable"}], - [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], - [{xmlelement, "item", - [{"affiliation", "member"}, - {"role", "participant"}, - {"nick", Nick}], - []}, - {xmlelement, "status", [{"code", "303"}], []} + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = "unavailable"}], children = + [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = + [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = + [#xmlattr{name = 'affiliation', value = "member"}, + #xmlattr{name = 'role', value = "participant"}, + #xmlattr{name = 'nick', value = Nick}]}, + #xmlel{ns = ?NS_MUC_USER, name = 'status', attrs = [#xmlattr{name = 'code', value = "303"}]} ]}]}), ejabberd_router:route( - jlib:make_jid( + exmpp_jid:make_jid( lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, Nick), StateData#state.user, - {xmlelement, "presence", [], - [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], - [{xmlelement, "item", - [{"affiliation", "member"}, - {"role", "participant"}], - []} + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = + [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = + [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = + [#xmlattr{name = 'affiliation', value = "member"}, + #xmlattr{name = 'role', value = "participant"}]} ]}]}), ?SETS:add_element(Nick, remove_element(FromUser, Ps)); @@ -1076,13 +1047,13 @@ process_error(StateData, String) -> lists:foreach( fun(Chan) -> ejabberd_router:route( - jlib:make_jid( + exmpp_jid:make_jid( lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, StateData#state.nick), StateData#state.user, - {xmlelement, "presence", [{"type", "error"}], - [{xmlelement, "error", [{"code", "502"}], - [{xmlcdata, String}]}]}) + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = "error"}], children = + [#xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', attrs = [#xmlattr{name = 'code', value = "502"}], children = + [#xmlcdata{cdata = list_to_binary(String)}]}]}) end, dict:fetch_keys(StateData#state.channels)). @@ -1099,7 +1070,7 @@ remove_element(E, Set) -> iq_admin(StateData, Channel, From, To, - #iq{type = Type, xmlns = XMLNS, sub_el = SubEl} = IQ) -> + #iq{type = Type, ns = XMLNS, payload = SubEl} = IQ_Rec) -> case catch process_iq_admin(StateData, Channel, Type, SubEl) of {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); @@ -1108,17 +1079,14 @@ iq_admin(StateData, Channel, From, To, Res /= ignore -> ResIQ = case Res of {result, ResEls} -> - IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", XMLNS}], - ResEls - }]}; + Result = #xmlel{ns = XMLNS, name = 'query', + children = ResEls}, + exmpp_iq:result(IQ_Rec, Result); {error, Error} -> - IQ#iq{type = error, - sub_el = [SubEl, Error]} + exmpp_iq:error(IQ_Rec, Error) end, ejabberd_router:route(To, From, - jlib:iq_to_xml(ResIQ)); + exmpp_iq:iq_to_xmlel(ResIQ)); true -> ok end @@ -1126,23 +1094,23 @@ iq_admin(StateData, Channel, From, To, process_iq_admin(StateData, Channel, set, SubEl) -> - case xml:get_subtag(SubEl, "item") of + case exmpp_xml:get_element(SubEl, 'item') of false -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; ItemEl -> - Nick = xml:get_tag_attr_s("nick", ItemEl), - Affiliation = xml:get_tag_attr_s("affiliation", ItemEl), - Role = xml:get_tag_attr_s("role", ItemEl), - Reason = xml:get_path_s(ItemEl, [{elem, "reason"}, cdata]), + Nick = exmpp_xml:get_attribute(ItemEl, 'nick', ""), + Affiliation = exmpp_xml:get_attribute(ItemEl, 'affiliation', ""), + Role = exmpp_xml:get_attribute(ItemEl, 'role', ""), + Reason = exmpp_xml:get_path(ItemEl, [{element, 'reason'}, cdata_as_list]), process_admin(StateData, Channel, Nick, Affiliation, Role, Reason) end; process_iq_admin(_StateData, _Channel, get, _SubEl) -> - {error, ?ERR_FEATURE_NOT_IMPLEMENTED}. + {error, 'feature-not-implemented'}. process_admin(_StateData, _Channel, "", _Affiliation, _Role, _Reason) -> - {error, ?ERR_FEATURE_NOT_IMPLEMENTED}; + {error, 'feature-not-implemented'}; process_admin(StateData, Channel, Nick, _Affiliation, "none", Reason) -> case Reason of @@ -1160,7 +1128,7 @@ process_admin(StateData, Channel, Nick, _Affiliation, "none", Reason) -> process_admin(_StateData, _Channel, _Nick, _Affiliation, _Role, _Reason) -> - {error, ?ERR_FEATURE_NOT_IMPLEMENTED}. + {error, 'feature-not-implemented'}. From 7088ba88a95c94e18af59d9dde544af9c118ced4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 1 Dec 2008 12:16:41 +0000 Subject: [PATCH 124/582] o In store_last_info/4, fix a bug where the status was not converted to list before calling ejabberd_odbc:escape/1. o In get_last_info/2, fix a bug where the status was returned as a list instead of a binary. SVN Revision: 1690 --- ChangeLog | 8 ++++++++ src/mod_last_odbc.erl | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index f46777ed2..c3cabe035 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2008-10-31 Jean-Sébastien Pédron + + * src/mod_last_odbc.erl (store_last_info/4): Fix a bug where the + status was not converted to list before calling + ejabberd_odbc:escape/1. + (get_last_info/2): Fix a bug where the status was returned as a list + instead of a binary. + 2008-10-20 Jean-Sébastien Pédron * src/mod_irc/mod_irc.erl, src/mod_irc/mod_irc_connection.erl: Convert diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 077a6ee52..64569fd69 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -135,7 +135,7 @@ store_last_info(User, Server, TimeStamp, Status) -> LServer = exmpp_stringprep:nameprep(Server), Username = ejabberd_odbc:escape(LUser), Seconds = ejabberd_odbc:escape(integer_to_list(TimeStamp)), - State = ejabberd_odbc:escape(Status), + State = ejabberd_odbc:escape(binary_to_list(Status)), odbc_queries:set_last_t(LServer, Username, Seconds, State) catch _ -> @@ -151,7 +151,7 @@ get_last_info(LUser, LServer) -> {selected, ["seconds","state"], [{STimeStamp, Status}]} -> case catch list_to_integer(STimeStamp) of TimeStamp when is_integer(TimeStamp) -> - {ok, TimeStamp, Status}; + {ok, TimeStamp, list_to_binary(Status)}; _ -> not_found end; From e06f533f6ba50b6ea1e2a1f535f056426a44ed9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 1 Dec 2008 15:00:36 +0000 Subject: [PATCH 125/582] Start the exmpp application. PR: EJABP-1 Submitted by: Pablo Polvorin SVN Revision: 1691 --- ChangeLog | 4 ++++ src/ejabberd_app.erl | 1 + 2 files changed, 5 insertions(+) diff --git a/ChangeLog b/ChangeLog index c3cabe035..c1db8a3f6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2008-11-03 Pablo Polvorin + + * src/ejabberd_app.erl: Start the exmpp application. + 2008-10-31 Jean-Sébastien Pédron * src/mod_last_odbc.erl (store_last_info/4): Fix a bug where the diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index 928dd696c..f9bf8378c 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -41,6 +41,7 @@ start(normal, _Args) -> ejabberd_loglevel:set(4), application:start(sasl), + application:start(exmpp), randoms:start(), db_init(), sha:start(), From bd300e870c67eeeab4dd73f25f4cf0fc10358051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 1 Dec 2008 15:01:27 +0000 Subject: [PATCH 126/582] Convert mod_muc to Exmpp. PR: EJABP-1 Submitted by: Pablo Polvorin SVN Revision: 1692 --- ChangeLog | 11 + src/mod_muc/mod_muc.erl | 293 ++++---- src/mod_muc/mod_muc_log.erl | 45 +- src/mod_muc/mod_muc_room.erl | 1325 ++++++++++++++++++---------------- 4 files changed, 903 insertions(+), 771 deletions(-) diff --git a/ChangeLog b/ChangeLog index c1db8a3f6..b4537022c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,18 @@ +2008-11-04 Pablo Polvorin + + * src/mod_muc/mod_muc_log.erl: Convert to exmpp, fix recursive + directory creation. + + * src/mod_muc/mod_muc_room.erl: Default values as binary() instead of + list(). + 2008-11-03 Pablo Polvorin * src/ejabberd_app.erl: Start the exmpp application. + * src/mod_muc/mod_muc.erl, src/mod_muc/mod_muc_room.erl: Convert to + exmpp. + 2008-10-31 Jean-Sébastien Pédron * src/mod_last_odbc.erl (store_last_info/4): Fix a bug where the diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index 812c8de97..e83bedeba 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -45,8 +45,9 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -record(muc_room, {name_host, opts}). @@ -123,20 +124,19 @@ forget_room(Host, Name) -> end, mnesia:transaction(F). -process_iq_disco_items(Host, From, To, #iq{lang = Lang} = IQ) -> - Res = IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", ?NS_DISCO_ITEMS}], - iq_disco_items(Host, From, Lang)}]}, +process_iq_disco_items(Host, From, To, #iq{} = IQ) -> + Lang = exmpp_stanza:get_lang(IQ), + Res = exmpp_iq:result(IQ, #xmlel{ns = ?NS_DISCO_ITEMS, + name = 'query', + children = iq_disco_items(Host, From, Lang)}), ejabberd_router:route(To, From, - jlib:iq_to_xml(Res)). + exmpp_iq:iq_to_xmlel(Res)). can_use_nick(_Host, _JID, "") -> false; can_use_nick(Host, JID, Nick) -> - {LUser, LServer, _} = jlib:jid_tolower(JID), - LUS = {LUser, LServer}, + LUS = {JID#jid.lnode, JID#jid.ldomain}, case catch mnesia:dirty_select( muc_registered, [{#muc_registered{us_host = '$1', @@ -300,11 +300,11 @@ do_route(Host, ServerHost, Access, HistorySize, RoomShaper, do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, From, To, Packet, DefRoomOpts); _ -> - {xmlelement, _Name, Attrs, _Els} = Packet, - Lang = xml:get_attr_s("xml:lang", Attrs), - ErrText = "Access denied by service policy", - Err = jlib:make_error_reply(Packet, - ?ERRT_FORBIDDEN(Lang, ErrText)), + Lang = exmpp_stanza:get_lang(Packet), + ErrText = "Access denied by service policy", + Err = exmpp_iq:error(Packet,exmpp_stanza:error(Packet#xmlel.ns, + 'forbidden', + {Lang,ErrText})), ejabberd_router:route(To, From, Err) end. @@ -312,124 +312,109 @@ do_route(Host, ServerHost, Access, HistorySize, RoomShaper, do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, From, To, Packet, DefRoomOpts) -> {_AccessRoute, AccessCreate, AccessAdmin, _AccessPersistent} = Access, - {Room, _, Nick} = jlib:jid_tolower(To), - {xmlelement, Name, Attrs, _Els} = Packet, + Room = To#jid.lnode, + Nick = To#jid.lresource, + #xmlel{name = Name} = Packet, case Room of - "" -> + 'undefined' -> case Nick of - "" -> + 'undefined' -> case Name of - "iq" -> - case jlib:iq_query_info(Packet) of - #iq{type = get, xmlns = ?NS_DISCO_INFO = XMLNS, - sub_el = _SubEl, lang = Lang} = IQ -> - Res = IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", XMLNS}], - iq_disco_info(Lang)}]}, + 'iq' -> + case exmpp_iq:xmlel_to_iq(Packet) of + #iq{type = get, ns = ?NS_DISCO_INFO = XMLNS, + payload = _SubEl, lang = Lang} = IQ -> + + ResPayload = #xmlel{ns = XMLNS, name = 'query', + children = iq_disco_info(Lang)}, + Res = exmpp_iq:result(IQ, ResPayload), ejabberd_router:route(To, From, - jlib:iq_to_xml(Res)); + exmpp_iq:iq_to_xmlel(Res)); #iq{type = get, - xmlns = ?NS_DISCO_ITEMS} = IQ -> + ns = ?NS_DISCO_ITEMS} = IQ -> spawn(?MODULE, process_iq_disco_items, [Host, From, To, IQ]); #iq{type = get, - xmlns = ?NS_REGISTER = XMLNS, - lang = Lang, - sub_el = _SubEl} = IQ -> - Res = IQ#iq{type = result, - sub_el = - [{xmlelement, "query", - [{"xmlns", XMLNS}], - iq_get_register_info( - Host, From, Lang)}]}, + ns = ?NS_INBAND_REGISTER = XMLNS, + lang = Lang} = IQ -> + ResPayload = #xmlel{ns = XMLNS, name = 'query', + children = iq_get_register_info(Host, + From, + Lang)}, + Res = exmpp_iq:result(IQ,ResPayload), ejabberd_router:route(To, From, - jlib:iq_to_xml(Res)); + exmpp_iq:iq_to_xmlel(Res)); #iq{type = set, - xmlns = ?NS_REGISTER = XMLNS, + ns = ?NS_INBAND_REGISTER , lang = Lang, - sub_el = SubEl} = IQ -> + payload = SubEl} = IQ -> case process_iq_register_set(Host, From, SubEl, Lang) of - {result, IQRes} -> - Res = IQ#iq{type = result, - sub_el = - [{xmlelement, "query", - [{"xmlns", XMLNS}], - IQRes}]}, + ok -> + Res = exmpp_iq:result(IQ), ejabberd_router:route( - To, From, jlib:iq_to_xml(Res)); + To, From, exmpp_iq:iq_to_xmlel(Res)); {error, Error} -> - Err = jlib:make_error_reply( - Packet, Error), + Err = exmpp_iq:error(IQ,Error), ejabberd_router:route( - To, From, Err) + To, From, exmpp_iq:iq_to_xmlel(Err)) end; #iq{type = get, - xmlns = ?NS_VCARD = XMLNS, - lang = Lang, - sub_el = _SubEl} = IQ -> - Res = IQ#iq{type = result, - sub_el = - [{xmlelement, "vCard", - [{"xmlns", XMLNS}], - iq_get_vcard(Lang)}]}, + ns = ?NS_VCARD, + lang = Lang} = IQ -> + Res = exmpp_iq:result(IQ,iq_get_vcard(Lang)), ejabberd_router:route(To, From, - jlib:iq_to_xml(Res)); - #iq{} -> - Err = jlib:make_error_reply( - Packet, - ?ERR_FEATURE_NOT_IMPLEMENTED), + exmpp_iq:iq_to_xmlel(Res)); + #iq{} = IQ -> + Err = exmpp_iq:error(IQ,'feature-not-implemented'), ejabberd_router:route(To, From, Err); _ -> ok end; - "message" -> - case xml:get_attr_s("type", Attrs) of + 'message' -> + case exmpp_xml:get_attribute(Packet,type, "chat") of "error" -> ok; _ -> case acl:match_rule(ServerHost, AccessAdmin, From) of allow -> - Msg = xml:get_path_s( - Packet, - [{elem, "body"}, cdata]), + Msg = exmpp_xml:get_path(Packet, + [{element,'body'},cdata]), broadcast_service_message(Host, Msg); _ -> - Lang = xml:get_attr_s("xml:lang", Attrs), + Lang = exmpp_stanza:get_lang(Packet), ErrText = "Only service administrators " "are allowed to send service messages", - Err = jlib:make_error_reply( - Packet, - ?ERRT_FORBIDDEN(Lang, ErrText)), + Err = exmpp_iq:error(Packet,exmpp_stanza:error(Packet#xmlel.ns, + 'forbidden', + {Lang,ErrText})), ejabberd_router:route( To, From, Err) end end; - "presence" -> + 'presence' -> ok end; _ -> - case xml:get_attr_s("type", Attrs) of + case exmpp_stanza:get_type(Packet) of "error" -> ok; "result" -> ok; _ -> - Err = jlib:make_error_reply( - Packet, ?ERR_ITEM_NOT_FOUND), + Err = exmpp_iq:error(Packet,'item-not-found'), ejabberd_router:route(To, From, Err) end end; _ -> case mnesia:dirty_read(muc_online_room, {Room, Host}) of [] -> - Type = xml:get_attr_s("type", Attrs), + Type = exmpp_stanza:get_type(Packet), case {Name, Type} of - {"presence", ""} -> + {'presence', 'undefined'} -> case acl:match_rule(ServerHost, AccessCreate, From) of allow -> ?DEBUG("MUC: open new room '~s'~n", [Room]), @@ -442,17 +427,20 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, mod_muc_room:route(Pid, From, Nick, Packet), ok; _ -> - Lang = xml:get_attr_s("xml:lang", Attrs), + Lang = exmpp_stanza:get_lang(Packet), ErrText = "Room creation is denied by service policy", - Err = jlib:make_error_reply( - Packet, ?ERRT_FORBIDDEN(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error(Packet,exmpp_stanza:error(Packet#xmlel.ns, + 'forbidden', + {Lang,ErrText})), ejabberd_router:route(To, From, Err) end; _ -> - Lang = xml:get_attr_s("xml:lang", Attrs), + Lang = exmpp_stanza:get_lang(Packet), ErrText = "Conference room does not exist", - Err = jlib:make_error_reply( - Packet, ?ERRT_ITEM_NOT_FOUND(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, + 'item-not-found', + {Lang,ErrText})), ejabberd_router:route(To, From, Err) end; [R] -> @@ -504,13 +492,23 @@ register_room(Host, Room, Pid) -> iq_disco_info(Lang) -> - [{xmlelement, "identity", - [{"category", "conference"}, - {"type", "text"}, - {"name", translate:translate(Lang, "Chatrooms")}], []}, - {xmlelement, "feature", [{"var", ?NS_MUC}], []}, - {xmlelement, "feature", [{"var", ?NS_REGISTER}], []}, - {xmlelement, "feature", [{"var", ?NS_VCARD}], []}]. + [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', + attrs = [#xmlattr{name = 'category', + value = "conference"}, + #xmlattr{name = 'type', + value = "text"}, + #xmlattr{name = 'name', + value = translate:translate(Lang, "Chatrooms")}]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = + [#xmlattr{name = 'var', + value = ?NS_MUC_s}]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = + [#xmlattr{name = 'var', + value = ?NS_INBAND_REGISTER_s}]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = + [#xmlattr{name = 'var', + value = ?NS_VCARD_s}]}]. + iq_disco_items(Host, From, Lang) -> @@ -520,9 +518,13 @@ iq_disco_items(Host, From, Lang) -> {item, Desc} -> flush(), {true, - {xmlelement, "item", - [{"jid", jlib:jid_to_string({Name, Host, ""})}, - {"name", Desc}], []}}; + #xmlel{name = 'item', + attrs = [#xmlattr{name = 'jid', + value = exmpp_jid:jid_to_list(Name, + Host, + "")}, + #xmlattr{name = 'name', + value = Desc}]}}; _ -> false end @@ -537,13 +539,17 @@ flush() -> end. -define(XFIELD(Type, Label, Var, Val), - {xmlelement, "field", [{"type", Type}, - {"label", translate:translate(Lang, Label)}, - {"var", Var}], - [{xmlelement, "value", [], [{xmlcdata, Val}]}]}). + #xmlel{name = "field", + attrs = [#xmlattr{name = 'type', value = Type}, + #xmlattr{name = 'label', + value = translate:translate(Lang, Label)}, + #xmlattr{name = 'var', value = Var}], + children = [#xmlel{name = 'value', + children = [#xmlcdata{cdata = Val}]}]}). iq_get_register_info(Host, From, Lang) -> - {LUser, LServer, _} = jlib:jid_tolower(From), + LUser = From#jid.lnode, + LServer = From#jid.ldomain, LUS = {LUser, LServer}, {Nick, Registered} = case catch mnesia:dirty_read(muc_registered, {LUS, Host}) of @@ -552,27 +558,28 @@ iq_get_register_info(Host, From, Lang) -> [] -> {"", []}; [#muc_registered{nick = N}] -> - {N, [{xmlelement, "registered", [], []}]} + {N, [#xmlel{name = 'registered'}]} end, Registered ++ - [{xmlelement, "instructions", [], - [{xmlcdata, - translate:translate( - Lang, "You need an x:data capable client to register nickname")}]}, - {xmlelement, "x", - [{"xmlns", ?NS_XDATA}], - [{xmlelement, "title", [], - [{xmlcdata, - translate:translate( - Lang, "Nickname Registration at ") ++ Host}]}, - {xmlelement, "instructions", [], - [{xmlcdata, - translate:translate( - Lang, "Enter nickname you want to register")}]}, + [#xmlel{name = 'instructions' , + children = [#xmlcdata{cdata = + translate:translate(Lang, + "You need an x:data capable client to register nickname")}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'x', + children = [ + #xmlel{ns = ?NS_DATA_FORMS, name = 'title', + children = [#xmlcdata{cdata = + translate:translate(Lang, "Nickname Registration at ") ++ Host}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', + children = [#xmlcdata{cdata = + translate:translate(Lang, "Enter nickname you want to register")}]}, ?XFIELD("text-single", "Nickname", "nick", Nick)]}]. + + iq_set_register_info(Host, From, Nick, Lang) -> - {LUser, LServer, _} = jlib:jid_tolower(From), + LUser = From#jid.lnode, + LServer = From#jid.ldomain, LUS = {LUser, LServer}, F = fun() -> case Nick of @@ -606,56 +613,64 @@ iq_set_register_info(Host, From, Nick, Lang) -> end, case mnesia:transaction(F) of {atomic, ok} -> - {result, []}; + ok; {atomic, false} -> ErrText = "Specified nickname is already registered", - {error, ?ERRT_CONFLICT(Lang, ErrText)}; + %%TODO: Always in the jabber:client namespace? + {error,exmpp_stanza:error(?NS_JABBER_CLIENT, + 'conflict', + {Lang, ErrText})}; _ -> - {error, ?ERR_INTERNAL_SERVER_ERROR} + {error, 'internal-server-error'} end. process_iq_register_set(Host, From, SubEl, Lang) -> - {xmlelement, _Name, _Attrs, Els} = SubEl, - case xml:get_subtag(SubEl, "remove") of - false -> - case xml:remove_cdata(Els) of - [{xmlelement, "x", _Attrs1, _Els1} = XEl] -> - case {xml:get_tag_attr_s("xmlns", XEl), - xml:get_tag_attr_s("type", XEl)} of - {?NS_XDATA, "cancel"} -> - {result, []}; - {?NS_XDATA, "submit"} -> +% {xmlelement, _Name, _Attrs, Els} = SubEl, + case exmpp_xml:get_element(SubEl,'remove') of + undefined -> + case exmpp_xml:get_child_elements(SubEl) of + [#xmlel{ns= NS, name = 'x'} = XEl] -> + case {NS, exmpp_stanza:get_type(XEl)} of + {?NS_DATA_FORMS, "cancel"} -> + ok; + {?NS_DATA_FORMS, "submit"} -> XData = jlib:parse_xdata_submit(XEl), case XData of invalid -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; _ -> case lists:keysearch("nick", 1, XData) of false -> ErrText = "You must fill in field \"Nickname\" in the form", - {error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)}; + Err = exmpp_stanza:error(SubEl#xmlel.ns, + 'not-acceptable', + {Lang, translate:translate(Lang,ErrText)}), + {error, Err}; {value, {_, [Nick]}} -> iq_set_register_info(Host, From, Nick, Lang) end end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; _ -> iq_set_register_info(Host, From, "", Lang) end. iq_get_vcard(Lang) -> - [{xmlelement, "FN", [], - [{xmlcdata, "ejabberd/mod_muc"}]}, - {xmlelement, "URL", [], - [{xmlcdata, ?EJABBERD_URI}]}, - {xmlelement, "DESC", [], - [{xmlcdata, translate:translate(Lang, "ejabberd MUC module") ++ - "\nCopyright (c) 2003-2008 Alexey Shchepin"}]}]. + #xmlel{ns = ?NS_VCARD, name = 'vCard', + children = + [#xmlel{ns = ?NS_VCARD, name = 'FN', + children = [#xmlcdata{cdata = <<"ejabberd/mod_muc">>}]}, + #xmlel{ns = ?NS_VCARD, name = 'URL', + children = [#xmlcdata{cdata = ?EJABBERD_URI}]}, + #xmlel{ns = ?NS_VCARD, name = 'DESC', + children = [#xmlcdata{cdata = + translate:translate(Lang, "ejabberd MUC module") ++ + "\nCopyright (c) 2003-2008 Alexey Shchepin"}]}]}. broadcast_service_message(Host, Msg) -> diff --git a/src/mod_muc/mod_muc_log.erl b/src/mod_muc/mod_muc_log.erl index e76904193..2c4dc8c70 100644 --- a/src/mod_muc/mod_muc_log.erl +++ b/src/mod_muc/mod_muc_log.erl @@ -41,8 +41,9 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -define(T(Text), translate:translate(Lang, Text)). -define(PROCNAME, ejabberd_mod_muc_log). @@ -204,14 +205,15 @@ code_change(_OldVsn, State, _Extra) -> %%% Internal functions %%-------------------------------------------------------------------- add_to_log2(text, {Nick, Packet}, Room, Opts, State) -> - case {xml:get_subtag(Packet, "subject"), xml:get_subtag(Packet, "body")} of - {false, false} -> + case {exmpp_xml:get_element(Packet, 'subject'), + exmpp_xml:get_element(Packet, 'body')} of + {'undefined', 'undefined'} -> ok; - {false, SubEl} -> - Message = {body, xml:get_tag_cdata(SubEl)}, + {'undefined', SubEl} -> + Message = {body, exmpp_xml:get_cdata_as_list(SubEl)}, add_message_to_log(Nick, Message, Room, Opts, State); {SubEl, _} -> - Message = {subject, xml:get_tag_cdata(SubEl)}, + Message = {subject, exmpp_xml:get_cdata_as_list(SubEl)}, add_message_to_log(Nick, Message, Room, Opts, State) end; @@ -225,13 +227,13 @@ add_to_log2(join, Nick, Room, Opts, State) -> add_message_to_log(Nick, join, Room, Opts, State); add_to_log2(leave, {Nick, Reason}, Room, Opts, State) -> - case Reason of + case binary_to_list(Reason) of "" -> add_message_to_log(Nick, leave, Room, Opts, State); - _ -> add_message_to_log(Nick, {leave, Reason}, Room, Opts, State) + R -> add_message_to_log(Nick, {leave, R}, Room, Opts, State) end; add_to_log2(kickban, {Nick, Reason, Code}, Room, Opts, State) -> - add_message_to_log(Nick, {kickban, Code, Reason}, Room, Opts, State). + add_message_to_log(Nick, {kickban, Code, binary_to_list(Reason)}, Room, Opts, State). %%---------------------------------------------------------------------- @@ -269,8 +271,8 @@ build_filename_string(TimeStamp, OutDir, RoomJID, DirType, DirName, FileFormat) {Fd, Fn, Fnrel}. get_room_name(RoomJID) -> - JID = jlib:string_to_jid(RoomJID), - JID#jid.user. + JID = exmpp_jid:list_to_jid(RoomJID), + JID#jid.node. %% calculate day before get_timestamp_daydiff(TimeStamp, Daydiff) -> @@ -458,16 +460,27 @@ get_dateweek(Date, Lang) -> end. make_dir_rec(Dir) -> + Path = filename:split(Dir), + inc_foreach(Path,fun make_dir_if_not_exists/1). + + +make_dir_if_not_exists(DirPath) -> + Dir = filename:join(DirPath), case file:read_file_info(Dir) of {ok, _} -> ok; {error, enoent} -> - DirS = filename:split(Dir), - DirR = lists:sublist(DirS, length(DirS)-1), - make_dir_rec(filename:join(DirR)), file:make_dir(Dir) end. +inc_foreach(Lists, F) -> + lists:foldl(fun(Item, Accum) -> + New = Accum ++ [Item], + F(New), + New + end,[],Lists). + + %% {ok, F1}=file:open("valid-xhtml10.png", [read]). %% {ok, F1b}=file:read(F1, 1000000). @@ -723,6 +736,8 @@ put_room_config(F, RoomConfig, Lang, _FileFormat) -> %% htmlize %% The default behaviour is to ignore the nofollow spam prevention on links %% (NoFollow=false) + + htmlize(S1) -> htmlize(S1, html). @@ -779,7 +794,7 @@ get_room_info(RoomJID, Opts) -> {value, {_, SA}} -> SA; false -> "" end, - #room{jid = jlib:jid_to_string(RoomJID), + #room{jid = exmpp_jid:jid_to_list(RoomJID), title = Title, subject = Subject, subject_author = SubjectAuthor, diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 16268196f..8982cd832 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -46,8 +46,9 @@ terminate/3, code_change/4]). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). --include("jlib.hrl"). -define(MAX_USERS_DEFAULT, 200). -define(MAX_USERS_DEFAULT_LIST, @@ -134,6 +135,12 @@ Creator, Nick, DefRoomOpts])). -endif. + +-define(ERR(Packet,Type, Lang, ErrText), + exmpp_stanza:error(Packet#xmlel.ns, + Type, + {Lang, translate:translate(Lang, ErrText)})). + %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- @@ -178,12 +185,12 @@ init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Creator, _Nick, D access = Access, room = Room, history = lqueue_new(HistorySize), - jid = jlib:make_jid(Room, Host, ""), + jid = exmpp_jid:make_jid(Room, Host), just_created = true, room_shaper = Shaper}), State1 = set_opts(DefRoomOpts, State), ?INFO_MSG("Created MUC room ~s@~s by ~s", - [Room, Host, jlib:jid_to_string(Creator)]), + [Room, Host, exmpp_jid:jid_to_list(Creator)]), {ok, normal_state, State1}; init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts]) -> process_flag(trap_exit, true), @@ -193,7 +200,7 @@ init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts]) -> access = Access, room = Room, history = lqueue_new(HistorySize), - jid = jlib:make_jid(Room, Host, ""), + jid = exmpp_jid:make_jid(Room, Host), room_shaper = Shaper}), {ok, normal_state, State}. @@ -203,32 +210,33 @@ init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts]) -> %% {next_state, NextStateName, NextStateData, Timeout} | %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- -normal_state({route, From, "", - {xmlelement, "message", Attrs, Els} = Packet}, +normal_state({route, From, undefined, + #xmlel{name = 'message'} = Packet}, StateData) -> - Lang = xml:get_attr_s("xml:lang", Attrs), + Lang = exmpp_stanza:get_lang(Packet), case is_user_online(From, StateData) orelse is_user_allowed_message_nonparticipant(From, StateData) of true -> - case xml:get_attr_s("type", Attrs) of - "groupchat" -> + case exmpp_message:get_type(Packet) of + groupchat -> Activity = get_user_activity(From, StateData), Now = now_to_usec(now()), MinMessageInterval = trunc(gen_mod:get_module_opt( StateData#state.server_host, mod_muc, min_message_interval, 0) * 1000000), - Size = lists:flatlength(xml:element_to_string(Packet)), + Size = lists:flatlength(exmpp_xml:document_to_list(Packet)), {MessageShaper, MessageShaperInterval} = shaper:update(Activity#activity.message_shaper, Size), if Activity#activity.message /= undefined -> ErrText = "Traffic rate limit is exceeded", - Err = jlib:make_error_reply( - Packet, ?ERRT_RESOURCE_CONSTRAINT(Lang, ErrText)), + Err = exmpp_stanza:error(Packet#xmlel.ns, + 'resource-constraint', + {Lang, translate:translate(Lang, ErrText)}), ejabberd_router:route( StateData#state.jid, - From, Err), + From, exmpp_stanza:reply_with_error(Packet, Err)), {next_state, normal_state, StateData}; Now >= Activity#activity.message_time + MinMessageInterval, MessageShaperInterval == 0 -> @@ -245,7 +253,7 @@ normal_state({route, From, "", StateData1 = StateData#state{ activity = ?DICT:store( - jlib:jid_tolower(From), + jlib:short_prepd_jid(From), NewActivity, StateData#state.activity), room_shaper = RoomShaper}, @@ -272,7 +280,7 @@ normal_state({route, From, "", StateData2 = StateData1#state{ activity = ?DICT:store( - jlib:jid_tolower(From), + jlib:short_prepd_jid(From), NewActivity, StateData#state.activity), room_queue = RoomQueue}, @@ -292,12 +300,12 @@ normal_state({route, From, "", StateData1 = StateData#state{ activity = ?DICT:store( - jlib:jid_tolower(From), + jlib:short_prepd_jid(From), NewActivity, StateData#state.activity)}, {next_state, normal_state, StateData1} end; - "error" -> + error -> case is_user_online(From, StateData) of true -> ErrorText = "This participant is kicked from the room because " @@ -308,19 +316,22 @@ normal_state({route, From, "", _ -> {next_state, normal_state, StateData} end; - "chat" -> + chat -> ErrText = "It is not allowed to send private messages to the conference", - Err = jlib:make_error_reply( - Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), + Err = exmpp_stanza:error(Packet#xmlel.ns, + 'not-acceptable', + {Lang, translate:translate(Lang, ErrText)}), ejabberd_router:route( StateData#state.jid, - From, Err), + From, exmpp_stanza:reply_with_error(Packet, Err)), {next_state, normal_state, StateData}; - Type when (Type == "") or (Type == "normal") -> - case catch check_invitation(From, Els, Lang, StateData) of + normal -> + case catch check_invitation(From, + exmpp_xml:get_child_elements(Packet), + Lang, + StateData) of {error, Error} -> - Err = jlib:make_error_reply( - Packet, Error), + Err = exmpp_stanza:reply_with_error(Packet, Error), ejabberd_router:route( StateData#state.jid, From, Err), @@ -355,28 +366,29 @@ normal_state({route, From, "", end; _ -> ErrText = "Improper message type", - Err = jlib:make_error_reply( - Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), + Err = exmpp_stanza:error(Packet#xmlel.ns, + 'not-acceptable', + {Lang, translate:translate(Lang, ErrText)}), ejabberd_router:route( StateData#state.jid, - From, Err), + From, exmpp_stanza:reply_with_error(Packet, Err)), {next_state, normal_state, StateData} end; _ -> - case xml:get_attr_s("type", Attrs) of - "error" -> + case exmpp_stanza:is_stanza_error(Packet) of + true -> ok; - _ -> + false -> handle_roommessage_from_nonparticipant(Packet, Lang, StateData, From) end, {next_state, normal_state, StateData} end; -normal_state({route, From, "", - {xmlelement, "iq", _Attrs, _Els} = Packet}, +normal_state({route, From, undefined, + #xmlel{name = 'iq'} = Packet}, StateData) -> - case jlib:iq_query_info(Packet) of - #iq{type = Type, xmlns = XMLNS, lang = Lang, sub_el = SubEl} = IQ when + case exmpp_iq:xmlel_to_iq(Packet) of + #iq{type = Type, ns = XMLNS, lang = Lang, payload = SubEl} = IQ when (XMLNS == ?NS_MUC_ADMIN) or (XMLNS == ?NS_MUC_OWNER) or (XMLNS == ?NS_DISCO_INFO) or @@ -393,21 +405,18 @@ normal_state({route, From, "", end, {IQRes, NewStateData} = case Res1 of + {result, [], SD} -> + {exmpp_iq:result(IQ), SD}; {result, Res, SD} -> - {IQ#iq{type = result, - sub_el = [{xmlelement, "query", - [{"xmlns", XMLNS}], - Res - }]}, - SD}; + {exmpp_iq:result(IQ,#xmlel{ns = XMLNS, + name = 'query', + children = Res}), SD}; {error, Error} -> - {IQ#iq{type = error, - sub_el = [SubEl, Error]}, - StateData} + {exmpp_iq:error(IQ, Error), StateData} end, ejabberd_router:route(StateData#state.jid, From, - jlib:iq_to_xml(IQRes)), + exmpp_iq:iq_to_xmlel(IQRes)), case NewStateData of stop -> {stop, normal, StateData}; @@ -417,14 +426,13 @@ normal_state({route, From, "", reply -> {next_state, normal_state, StateData}; _ -> - Err = jlib:make_error_reply( - Packet, ?ERR_FEATURE_NOT_IMPLEMENTED), + Err = exmpp_stanza:reply_with_error(Packet, 'feature-not-implemented'), ejabberd_router:route(StateData#state.jid, From, Err), {next_state, normal_state, StateData} end; normal_state({route, From, Nick, - {xmlelement, "presence", _Attrs, _Els} = Packet}, + #xmlel{name = 'presence'} = Packet}, StateData) -> Activity = get_user_activity(From, StateData), Now = now_to_usec(now()), @@ -439,7 +447,7 @@ normal_state({route, From, Nick, StateData1 = StateData#state{ activity = ?DICT:store( - jlib:jid_tolower(From), + jlib:short_prepd_jid(From), NewActivity, StateData#state.activity)}, process_presence(From, Nick, Packet, StateData1); @@ -457,17 +465,17 @@ normal_state({route, From, Nick, StateData1 = StateData#state{ activity = ?DICT:store( - jlib:jid_tolower(From), + jlib:short_prepd_jid(From), NewActivity, StateData#state.activity)}, {next_state, normal_state, StateData1} end; normal_state({route, From, ToNick, - {xmlelement, "message", Attrs, _} = Packet}, + #xmlel{name = 'message'} = Packet}, StateData) -> - Type = xml:get_attr_s("type", Attrs), - Lang = xml:get_attr_s("xml:lang", Attrs), + Type = exmpp_message:get_type(Packet), + Lang = exmpp_stanza:get_lang(Packet), case decide_fate_message(Type, Packet, From, StateData) of {expulse_sender, Reason} -> ?DEBUG(Reason, []), @@ -486,10 +494,11 @@ normal_state({route, From, ToNick, "groupchat" -> ErrText = "It is not allowed to send private " "messages of type \"groupchat\"", - Err = jlib:make_error_reply( - Packet, ?ERRT_BAD_REQUEST(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, 'bad-request', + {Lang, translate:translate(Lang, ErrText)})), ejabberd_router:route( - jlib:jid_replace_resource( + jid_replace_resource( StateData#state.jid, ToNick), From, Err); @@ -497,19 +506,20 @@ normal_state({route, From, ToNick, case find_jid_by_nick(ToNick, StateData) of false -> ErrText = "Recipient is not in the conference room", - Err = jlib:make_error_reply( - Packet, ?ERRT_ITEM_NOT_FOUND(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, 'item-not-found', + {Lang, translate:translate(Lang, ErrText)})), ejabberd_router:route( - jlib:jid_replace_resource( + jid_replace_resource( StateData#state.jid, ToNick), From, Err); ToJID -> {ok, #user{nick = FromNick}} = - ?DICT:find(jlib:jid_tolower(From), + ?DICT:find(jlib:short_prepd_jid(From), StateData#state.users), ejabberd_router:route( - jlib:jid_replace_resource( + jid_replace_resource( StateData#state.jid, FromNick), ToJID, Packet) @@ -517,19 +527,21 @@ normal_state({route, From, ToNick, end; {true, false} -> ErrText = "Only occupants are allowed to send messages to the conference", - Err = jlib:make_error_reply( - Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, 'not-acceptable', + {Lang, translate:translate(Lang, ErrText)})), ejabberd_router:route( - jlib:jid_replace_resource( + jid_replace_resource( StateData#state.jid, ToNick), From, Err); {false, _} -> ErrText = "It is not allowed to send private messages", - Err = jlib:make_error_reply( - Packet, ?ERRT_FORBIDDEN(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, 'forbidden', + {Lang, translate:translate(Lang, ErrText)})), ejabberd_router:route( - jlib:jid_replace_resource( + jid_replace_resource( StateData#state.jid, ToNick), From, Err) @@ -538,56 +550,65 @@ normal_state({route, From, ToNick, end; normal_state({route, From, ToNick, - {xmlelement, "iq", Attrs, _Els} = Packet}, + #xmlel{name = 'iq'} = Packet}, StateData) -> - Lang = xml:get_attr_s("xml:lang", Attrs), + Lang = exmpp_stanza:get_lang(Packet), case {(StateData#state.config)#config.allow_query_users, is_user_online(From, StateData)} of {true, true} -> case find_jid_by_nick(ToNick, StateData) of false -> - case jlib:iq_query_info(Packet) of - reply -> + case exmpp_iq:get_type(Packet) of + result -> + ok; + error -> ok; _ -> ErrText = "Recipient is not in the conference room", - Err = jlib:make_error_reply( - Packet, ?ERRT_ITEM_NOT_FOUND(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, 'item-not-found', + {Lang, translate:translate(Lang, ErrText)})), ejabberd_router:route( - jlib:jid_replace_resource( + jid_replace_resource( StateData#state.jid, ToNick), From, Err) end; ToJID -> {ok, #user{nick = FromNick}} = - ?DICT:find(jlib:jid_tolower(From), + ?DICT:find(jlib:short_prepd_jid(From), StateData#state.users), ejabberd_router:route( - jlib:jid_replace_resource(StateData#state.jid, FromNick), + jid_replace_resource(StateData#state.jid, FromNick), ToJID, Packet) end; {_, false} -> - case jlib:iq_query_info(Packet) of - reply -> + case exmpp_iq:get_type(Packet) of + result -> + ok; + error -> ok; _ -> ErrText = "Only occupants are allowed to send queries to the conference", - Err = jlib:make_error_reply( - Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, 'not-acceptable', + {Lang, translate:translate(Lang, ErrText)})), ejabberd_router:route( - jlib:jid_replace_resource(StateData#state.jid, ToNick), + jid_replace_resource(StateData#state.jid, ToNick), From, Err) end; _ -> - case jlib:iq_query_info(Packet) of - reply -> + case exmpp_iq:get_type(Packet) of + result -> + ok; + error -> ok; _ -> ErrText = "Queries to the conference members are not allowed in this room", - Err = jlib:make_error_reply( - Packet, ?ERRT_NOT_ALLOWED(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, 'not-allowed', + {Lang, translate:translate(Lang, ErrText)})), ejabberd_router:route( - jlib:jid_replace_resource(StateData#state.jid, ToNick), + jid_replace_resource(StateData#state.jid, ToNick), From, Err) end end, @@ -605,9 +626,10 @@ normal_state(_Event, StateData) -> %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- handle_event({service_message, Msg}, _StateName, StateData) -> - MessagePkt = {xmlelement, "message", - [{"type", "groupchat"}], - [{xmlelement, "body", [], [{xmlcdata, Msg}]}]}, + MessagePkt = #xmlel{name = 'message', + attrs = [#xmlattr{name = 'type', value = "groupchat"}], + children = [#xmlel{name = 'body', + children = [#xmlcdata{cdata = Msg}]}]}, lists:foreach( fun({_LJID, Info}) -> ejabberd_router:route( @@ -623,21 +645,20 @@ handle_event({service_message, Msg}, _StateName, StateData) -> handle_event({destroy, Reason}, _StateName, StateData) -> {result, [], stop} = - destroy_room( - {xmlelement, "destroy", - [{"xmlns", ?NS_MUC_OWNER}], - case Reason of - none -> []; - _Else -> - [{xmlelement, "reason", - [], [{xmlcdata, Reason}]}] - end}, StateData), + destroy_room( + #xmlel{ns = ?NS_MUC_OWNER, name = 'destroy', + children = case Reason of + none -> []; + _Else -> [#xmlel{name = 'reason', + children = [#xmlcdata{cdata = Reason}]}] + end}, StateData), + ?INFO_MSG("Destroyed MUC room ~s with reason: ~p", - [jlib:jid_to_string(StateData#state.jid), Reason]), + [exmpp_jid:jid_to_list(StateData#state.jid), Reason]), {stop, normal, StateData}; handle_event(destroy, StateName, StateData) -> ?INFO_MSG("Destroyed MUC room ~s", - [jlib:jid_to_string(StateData#state.jid)]), + [exmpp_jid:jid_to_list(StateData#state.jid)]), handle_event({destroy, none}, StateName, StateData); handle_event({set_affiliations, Affiliations}, StateName, StateData) -> @@ -676,7 +697,7 @@ handle_sync_event({get_disco_item, JID, Lang}, _From, StateName, StateData) -> _ -> " (n/a)" end, - Reply = case ((StateData#state.config)#config.public == true) orelse + Reply = case ((StateData#state.config)#config.public == true) orelse (FRole /= none) orelse (FAffiliation == admin) orelse (FAffiliation == owner) of @@ -739,7 +760,7 @@ handle_info(process_room_queue, normal_state = StateName, StateData) -> StateData1 = StateData#state{ activity = ?DICT:store( - jlib:jid_tolower(From), + jlib:short_prepd_jid(From), NewActivity, StateData#state.activity), room_queue = RoomQueue}, @@ -752,7 +773,7 @@ handle_info(process_room_queue, normal_state = StateName, StateData) -> StateData1 = StateData#state{ activity = ?DICT:store( - jlib:jid_tolower(From), + jlib:short_prepd_jid(From), NewActivity, StateData#state.activity), room_queue = RoomQueue}, @@ -785,9 +806,9 @@ terminate(_Reason, _StateName, StateData) -> route(Pid, From, ToNick, Packet) -> gen_fsm:send_event(Pid, {route, From, ToNick, Packet}). -process_groupchat_message(From, {xmlelement, "message", Attrs, _Els} = Packet, +process_groupchat_message(From, #xmlel{name = 'message'} = Packet, StateData) -> - Lang = xml:get_attr_s("xml:lang", Attrs), + Lang = exmpp_stanza:get_lang(Packet), case is_user_online(From, StateData) orelse is_user_allowed_message_nonparticipant(From, StateData) of true -> @@ -827,7 +848,7 @@ process_groupchat_message(From, {xmlelement, "message", Attrs, _Els} = Packet, lists:foreach( fun({_LJID, Info}) -> ejabberd_router:route( - jlib:jid_replace_resource( + jid_replace_resource( StateData#state.jid, FromNick), Info#user.jid, @@ -843,26 +864,29 @@ process_groupchat_message(From, {xmlelement, "message", Attrs, _Els} = Packet, Err = case (StateData#state.config)#config.allow_change_subj of true -> - ?ERRT_FORBIDDEN( - Lang, - "Only moderators and participants " - "are allowed to change subject in this room"); + exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, 'forbidden', + {Lang, translate:translate(Lang, + "Only moderators and participants " + "are allowed to change subject in this room")})); _ -> - ?ERRT_FORBIDDEN( - Lang, - "Only moderators " - "are allowed to change subject in this room") + exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, 'forbidden', + {Lang, translate:translate(Lang, + "Only moderators " + "are allowed to change subject in this room")})) end, ejabberd_router:route( StateData#state.jid, From, - jlib:make_error_reply(Packet, Err)), + Err), {next_state, normal_state, StateData} end; true -> ErrText = "Visitors are not allowed to send messages to all occupants", - Err = jlib:make_error_reply( - Packet, ?ERRT_FORBIDDEN(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, 'forbidden', + {Lang, translate:translate(Lang, ErrText)})), ejabberd_router:route( StateData#state.jid, From, Err), @@ -870,8 +894,9 @@ process_groupchat_message(From, {xmlelement, "message", Attrs, _Els} = Packet, end; false -> ErrText = "Only occupants are allowed to send messages to the conference", - Err = jlib:make_error_reply( - Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, 'not-acceptable', + {Lang, translate:translate(Lang, ErrText)})), ejabberd_router:route(StateData#state.jid, From, Err), {next_state, normal_state, StateData} end. @@ -897,7 +922,7 @@ is_user_allowed_message_nonparticipant(JID, StateData) -> %% @doc Get information of this participant, or default values. %% If the JID is not a participant, return values for a service message. get_participant_data(From, StateData) -> - case ?DICT:find(jlib:jid_tolower(From), StateData#state.users) of + case ?DICT:find(jlib:short_prepd_jid(From), StateData#state.users) of {ok, #user{nick = FromNick, role = Role}} -> {FromNick, Role}; error -> @@ -905,27 +930,27 @@ get_participant_data(From, StateData) -> end. -process_presence(From, Nick, {xmlelement, "presence", Attrs, _Els} = Packet, +process_presence(From, Nick, #xmlel{name = 'presence'} = Packet, StateData) -> - Type = xml:get_attr_s("type", Attrs), - Lang = xml:get_attr_s("xml:lang", Attrs), + Type = exmpp_presence:get_type(Packet), + Lang = exmpp_stanza:get_lang(Packet), StateData1 = case Type of - "unavailable" -> + unavailable -> case is_user_online(From, StateData) of true -> NewState = add_user_presence_un(From, Packet, StateData), send_new_presence(From, NewState), - Reason = case xml:get_subtag(Packet, "status") of - false -> ""; - Status_el -> xml:get_tag_cdata(Status_el) + Reason = case exmpp_xml:get_element(Packet, 'status') of + undefined -> <<>>; + Status_el -> exmpp_xml:get_cdata(Status_el) end, remove_online_user(From, NewState, Reason); _ -> StateData end; - "error" -> + error -> case is_user_online(From, StateData) of true -> ErrorText = "This participant is kicked from the room because " @@ -935,7 +960,7 @@ process_presence(From, Nick, {xmlelement, "presence", Attrs, _Els} = Packet, _ -> StateData end; - "" -> + available -> case is_user_online(From, StateData) of true -> case is_nick_change(From, Nick, StateData) of @@ -943,40 +968,40 @@ process_presence(From, Nick, {xmlelement, "presence", Attrs, _Els} = Packet, case {is_nick_exists(Nick, StateData), mod_muc:can_use_nick( StateData#state.host, From, Nick), - {(StateData#state.config)#config.allow_visitor_nickchange, - is_visitor(From, StateData)}} of - {_, _, {false, true}} -> + {(StateData#state.config)#config.allow_visitor_nickchange, + is_visitor(From, StateData)}} of + {_, _, {false, true}} -> ErrText = "Visitors are not allowed to change their nicknames in this room", - Err = jlib:make_error_reply( - Packet, - ?ERRT_NOT_ALLOWED(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, 'not-allowed', + {Lang, translate:translate(Lang, ErrText)})), ejabberd_router:route( % TODO: s/Nick/""/ - jlib:jid_replace_resource( + jid_replace_resource( StateData#state.jid, Nick), From, Err), StateData; {true, _, _} -> - Lang = xml:get_attr_s("xml:lang", Attrs), + Lang = exmpp_stanza:get_lang(Packet), ErrText = "Nickname is already in use by another occupant", - Err = jlib:make_error_reply( - Packet, - ?ERRT_CONFLICT(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, 'conflict', + {Lang, translate:translate(Lang, ErrText)})), ejabberd_router:route( - jlib:jid_replace_resource( + jid_replace_resource( StateData#state.jid, Nick), % TODO: s/Nick/""/ From, Err), StateData; {_, false, _} -> ErrText = "Nickname is registered by another person", - Err = jlib:make_error_reply( - Packet, - ?ERRT_CONFLICT(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, 'conflict', + {Lang, translate:translate(Lang, ErrText)})), ejabberd_router:route( % TODO: s/Nick/""/ - jlib:jid_replace_resource( + jid_replace_resource( StateData#state.jid, Nick), From, Err), @@ -1006,14 +1031,14 @@ process_presence(From, Nick, {xmlelement, "presence", Attrs, _Els} = Packet, (?DICT:to_list(StateData1#state.users) == []) of true -> ?INFO_MSG("Destroyed MUC room ~s because it's temporary and empty", - [jlib:jid_to_string(StateData#state.jid)]), + [exmpp_jid:jid_to_list(StateData#state.jid)]), {stop, normal, StateData1}; _ -> {next_state, normal_state, StateData1} end. is_user_online(JID, StateData) -> - LJID = jlib:jid_tolower(JID), + LJID = jlib:short_prepd_jid(JID), ?DICT:is_key(LJID, StateData#state.users). role_to_list(Role) -> @@ -1052,13 +1077,13 @@ list_to_affiliation(Affiliation) -> %% Decide the fate of the message and its sender %% Returns: continue_delivery | forget_message | {expulse_sender, Reason} -decide_fate_message("error", Packet, From, StateData) -> +decide_fate_message(error, Packet, From, StateData) -> %% Make a preliminary decision PD = case check_error_kick(Packet) of %% If this is an error stanza and its condition matches a criteria true -> Reason = io_lib:format("This participant is considered a ghost and is expulsed: ~s", - [jlib:jid_to_string(From)]), + [exmpp_jid:jid_to_list(From)]), {expulse_sender, Reason}; false -> continue_delivery @@ -1083,47 +1108,39 @@ decide_fate_message(_, _, _, _) -> %% If so, return true to kick the participant. check_error_kick(Packet) -> case get_error_condition(Packet) of - "gone" -> true; - "internal-server-error" -> true; - "item-not-found" -> true; - "jid-malformed" -> true; - "recipient-unavailable" -> true; - "redirect" -> true; - "remote-server-not-found" -> true; - "remote-server-timeout" -> true; - "service-unavailable" -> true; + 'gone' -> true; + 'internal-server-error' -> true; + 'item-not-found' -> true; + 'jid-malformed' -> true; + 'recipient-unavailable' -> true; + 'redirect' -> true; + 'remote-server-not-found' -> true; + 'remote-server-timeout' -> true; + 'service-unavailable' -> true; _ -> false end. get_error_condition(Packet) -> - case catch get_error_condition2(Packet) of - {condition, ErrorCondition} -> - ErrorCondition; - {'EXIT', _} -> - "badformed error stanza" + try exmpp_stanza:get_condition(Packet) of + ErrorCondition -> ErrorCondition + catch + _:_ -> + 'badformed-error-stanza' end. -get_error_condition2(Packet) -> - {xmlelement, _, _, EEls} = xml:get_subtag(Packet, "error"), - [Condition] = [Name || {xmlelement, Name, [{"xmlns", ?NS_STANZAS}], []} <- EEls], - {condition, Condition}. expulse_participant(Packet, From, StateData, Reason1) -> ErrorCondition = get_error_condition(Packet), Reason2 = io_lib:format(Reason1 ++ ": " ++ "~s", [ErrorCondition]), NewState = add_user_presence_un( From, - {xmlelement, "presence", - [{"type", "unavailable"}], - [{xmlelement, "status", [], - [{xmlcdata, Reason2}] - }]}, + exmpp_presence:presence('unavailable',Reason2), StateData), send_new_presence(From, NewState), remove_online_user(From, NewState). set_affiliation(JID, Affiliation, StateData) -> - LJID = jlib:jid_remove_resource(jlib:jid_tolower(JID)), + LJID = jlib:short_prepd_bare_jid(JID), Affiliations = case Affiliation of none -> ?DICT:erase(LJID, @@ -1136,7 +1153,7 @@ set_affiliation(JID, Affiliation, StateData) -> StateData#state{affiliations = Affiliations}. set_affiliation_and_reason(JID, Affiliation, Reason, StateData) -> - LJID = jlib:jid_remove_resource(jlib:jid_tolower(JID)), + LJID = jlib:short_prepd_bare_jid(JID), Affiliations = case Affiliation of none -> ?DICT:erase(LJID, @@ -1155,22 +1172,22 @@ get_affiliation(JID, StateData) -> allow -> owner; _ -> - LJID = jlib:jid_tolower(JID), + LJID = jlib:short_prepd_jid(JID), case ?DICT:find(LJID, StateData#state.affiliations) of {ok, Affiliation} -> Affiliation; _ -> - LJID1 = jlib:jid_remove_resource(LJID), + LJID1 = jlib:short_prepd_bare_jid(JID), case ?DICT:find(LJID1, StateData#state.affiliations) of {ok, Affiliation} -> Affiliation; _ -> - LJID2 = setelement(1, LJID, ""), + LJID2 = setelement(1, LJID, undefined), case ?DICT:find(LJID2, StateData#state.affiliations) of {ok, Affiliation} -> Affiliation; _ -> - LJID3 = jlib:jid_remove_resource(LJID2), + LJID3 = setelement(1,jlib:short_prepd_bare_jid(JID),undefined), case ?DICT:find(LJID3, StateData#state.affiliations) of {ok, Affiliation} -> Affiliation; @@ -1199,9 +1216,9 @@ get_service_affiliation(JID, StateData) -> end. set_role(JID, Role, StateData) -> - LJID = jlib:jid_tolower(JID), + LJID = jlib:short_prepd_jid(JID), LJIDs = case LJID of - {U, S, ""} -> + {U, S, undefined} -> ?DICT:fold( fun(J, _, Js) -> case J of @@ -1236,7 +1253,7 @@ set_role(JID, Role, StateData) -> StateData#state{users = Users}. get_role(JID, StateData) -> - LJID = jlib:jid_tolower(JID), + LJID = jlib:short_prepd_jid(JID), case ?DICT:find(LJID, StateData#state.users) of {ok, #user{role = Role}} -> Role; @@ -1284,7 +1301,7 @@ get_max_users_admin_threshold(StateData) -> mod_muc, max_users_admin_threshold, 5). get_user_activity(JID, StateData) -> - case ?DICT:find(jlib:jid_tolower(JID), + case ?DICT:find(jlib:short_prepd_jid(JID), StateData#state.activity) of {ok, A} -> A; error -> @@ -1305,7 +1322,7 @@ prepare_room_queue(StateData) -> {{value, {message, From}}, _RoomQueue} -> Activity = get_user_activity(From, StateData), Packet = Activity#activity.message, - Size = lists:flatlength(xml:element_to_string(Packet)), + Size = lists:flatlength(exmpp_xml:documenent_to_list(Packet)), {RoomShaper, RoomShaperInterval} = shaper:update(StateData#state.room_shaper, Size), erlang:send_after( @@ -1316,7 +1333,7 @@ prepare_room_queue(StateData) -> {{value, {presence, From}}, _RoomQueue} -> Activity = get_user_activity(From, StateData), {_Nick, Packet} = Activity#activity.presence, - Size = lists:flatlength(xml:element_to_string(Packet)), + Size = lists:flatlength(exmpp_xml:document_to_list(Packet)), {RoomShaper, RoomShaperInterval} = shaper:update(StateData#state.room_shaper, Size), erlang:send_after( @@ -1330,7 +1347,7 @@ prepare_room_queue(StateData) -> add_online_user(JID, Nick, Role, StateData) -> - LJID = jlib:jid_tolower(JID), + LJID = jlib:short_prepd_jid(JID), Users = ?DICT:store(LJID, #user{jid = JID, nick = Nick, @@ -1341,10 +1358,10 @@ add_online_user(JID, Nick, Role, StateData) -> StateData#state{users = Users}. remove_online_user(JID, StateData) -> - remove_online_user(JID, StateData, ""). + remove_online_user(JID, StateData, <<>>). remove_online_user(JID, StateData, Reason) -> - LJID = jlib:jid_tolower(JID), + LJID = jlib:short_prepd_jid(JID), {ok, #user{nick = Nick}} = ?DICT:find(LJID, StateData#state.users), add_to_log(leave, {Nick, Reason}, StateData), @@ -1353,34 +1370,31 @@ remove_online_user(JID, StateData, Reason) -> StateData#state{users = Users}. -filter_presence({xmlelement, "presence", Attrs, Els}) -> +filter_presence(#xmlel{name = 'presence'} = Packet) -> FEls = lists:filter( fun(El) -> - case El of - {xmlcdata, _} -> - false; - {xmlelement, _Name1, Attrs1, _Els1} -> - XMLNS = xml:get_attr_s("xmlns", Attrs1), - case XMLNS of - ?NS_MUC ++ _ -> + case El of + #xmlel{ns = XMLNS} -> + case atom_to_list(XMLNS) of + ?NS_MUC_s ++ _ -> false; _ -> true end end - end, Els), - {xmlelement, "presence", Attrs, FEls}. + end, exmpp_xml:get_child_elements(Packet)), + exmpp_xml:set_children(Packet, FEls). -strip_status({xmlelement, "presence", Attrs, Els}) -> +strip_status(#xmlel{name = 'presence', children = Children} = Packet) -> FEls = lists:filter( - fun({xmlelement, "status", _Attrs1, _Els1}) -> + fun(#xmlel{name = 'status'}) -> false; (_) -> true - end, Els), - {xmlelement, "presence", Attrs, FEls}. + end, Children), + exmpp_xml:set_children(Packet,FEls). add_user_presence(JID, Presence, StateData) -> - LJID = jlib:jid_tolower(JID), + LJID = jlib:short_prepd_jid(JID), FPresence = filter_presence(Presence), Users = ?DICT:update( @@ -1391,7 +1405,7 @@ add_user_presence(JID, Presence, StateData) -> StateData#state{users = Users}. add_user_presence_un(JID, Presence, StateData) -> - LJID = jlib:jid_tolower(JID), + LJID = jlib:short_prepd_jid(JID), FPresence = filter_presence(Presence), Users = ?DICT:update( @@ -1417,7 +1431,7 @@ find_jid_by_nick(Nick, StateData) -> end, false, StateData#state.users). is_nick_change(JID, Nick, StateData) -> - LJID = jlib:jid_tolower(JID), + LJID = jlib:short_prepd_jid(JID), case Nick of "" -> false; @@ -1427,8 +1441,8 @@ is_nick_change(JID, Nick, StateData) -> Nick /= OldNick end. -add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) -> - Lang = xml:get_attr_s("xml:lang", Attrs), +add_new_user(From, Nick, Packet, StateData) -> + Lang = exmpp_stanza:get_lang(Packet), MaxUsers = get_max_users(StateData), MaxAdminUsers = MaxUsers + get_max_users_admin_threshold(StateData), NUsers = dict:fold(fun(_, _, Acc) -> Acc + 1 end, 0, @@ -1450,59 +1464,70 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) -> get_default_role(Affiliation, StateData)} of {false, _, _, _} -> % max user reached and user is not admin or owner - Err = jlib:make_error_reply( + Err = exmpp_stanza:reply_with_error( Packet, - ?ERR_SERVICE_UNAVAILABLE), + 'service-unavailable'), ejabberd_router:route( % TODO: s/Nick/""/ - jlib:jid_replace_resource(StateData#state.jid, Nick), + jid_replace_resource(StateData#state.jid, Nick), From, Err), StateData; {_, _, _, none} -> - Err = jlib:make_error_reply( + Err = exmpp_stanza:reply_with_error( Packet, case Affiliation of outcast -> ErrText = "You have been banned from this room", - ?ERRT_FORBIDDEN(Lang, ErrText); + exmpp_stanza:error(Packet#xmlel.ns, + 'forbidden', + {Lang, translate:translate(Lang, ErrText)}); _ -> ErrText = "Membership required to enter this room", - ?ERRT_REGISTRATION_REQUIRED(Lang, ErrText) + exmpp_stanza:error(Packet#xmlel.ns, + 'registration-required', + {Lang, translate:translate(Lang, ErrText)}) end), ejabberd_router:route( % TODO: s/Nick/""/ - jlib:jid_replace_resource(StateData#state.jid, Nick), + jid_replace_resource(StateData#state.jid, Nick), From, Err), StateData; {_, true, _, _} -> ErrText = "Nickname is already in use by another occupant", - Err = jlib:make_error_reply(Packet, ?ERRT_CONFLICT(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error(Packet, + exmpp_stanza:error(Packet#xmlel.ns, + 'conflict', + {Lang, translate:translate(Lang, ErrText)})), ejabberd_router:route( % TODO: s/Nick/""/ - jlib:jid_replace_resource(StateData#state.jid, Nick), + jid_replace_resource(StateData#state.jid, Nick), From, Err), StateData; {_, _, false, _} -> ErrText = "Nickname is registered by another person", - Err = jlib:make_error_reply(Packet, ?ERRT_CONFLICT(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error(Packet, + ?ERR(Packet, 'conflict', Lang, ErrText)), ejabberd_router:route( % TODO: s/Nick/""/ - jlib:jid_replace_resource(StateData#state.jid, Nick), + jid_replace_resource(StateData#state.jid, Nick), From, Err), StateData; {_, _, _, Role} -> - case check_password(Affiliation, Els, StateData) of + case check_password(Affiliation, + exmpp_xml:get_child_elements(Packet), + StateData) of true -> NewState = add_user_presence( From, Packet, add_online_user(From, Nick, Role, StateData)), if not (NewState#state.config)#config.anonymous -> - WPacket = {xmlelement, "message", [{"type", "groupchat"}], - [{xmlelement, "body", [], - [{xmlcdata, translate:translate( - Lang, - "This room is not anonymous")}]}, - {xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], - [{xmlelement, "status", [{"code", "100"}], []}]}]}, + WPacket = + #xmlel{name = 'message', + attrs = [#xmlattr{name = 'type', value = "groupchat"}], + children = [ + #xmlel{name = 'body', + children = [#xmlcdata{cdata = + translate:translate(Lang, + "This room is not anonymous")}]}]}, ejabberd_router:route( StateData#state.jid, From, WPacket); @@ -1511,7 +1536,9 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) -> end, send_existing_presences(From, NewState), send_new_presence(From, NewState), - Shift = count_stanza_shift(Nick, Els, NewState), + Shift = count_stanza_shift(Nick, + exmpp_xml:get_child_elements(Packet), + NewState), case send_history(From, Shift, NewState) of true -> ok; @@ -1526,19 +1553,19 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) -> end; nopass -> ErrText = "Password required to enter this room", - Err = jlib:make_error_reply( - Packet, ?ERRT_NOT_AUTHORIZED(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error( + Packet, ?ERR(Packet, 'not-authorized', Lang, ErrText)), ejabberd_router:route( % TODO: s/Nick/""/ - jlib:jid_replace_resource( + jid_replace_resource( StateData#state.jid, Nick), From, Err), StateData; _ -> ErrText = "Incorrect password", - Err = jlib:make_error_reply( - Packet, ?ERRT_NOT_AUTHORIZED(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error( + Packet, ?ERR(Packet, 'not-authorized', Lang, ErrText)), ejabberd_router:route( % TODO: s/Nick/""/ - jlib:jid_replace_resource( + jid_replace_resource( StateData#state.jid, Nick), From, Err), StateData @@ -1568,14 +1595,14 @@ check_password(_Affiliation, Els, StateData) -> extract_password([]) -> false; -extract_password([{xmlelement, _Name, Attrs, _SubEls} = El | Els]) -> - case xml:get_attr_s("xmlns", Attrs) of +extract_password([#xmlel{ns = XMLNS} = El | Els]) -> + case XMLNS of ?NS_MUC -> - case xml:get_subtag(El, "password") of - false -> + case exmpp_xml:get_element(El, 'password') of + undefined -> false; SubEl -> - xml:get_tag_cdata(SubEl) + exmpp_xml:get_cdata(SubEl) end; _ -> extract_password(Els) @@ -1664,11 +1691,11 @@ calc_shift(MaxSize, Size, Shift, [S | TSizes]) -> extract_history([], _Type) -> false; -extract_history([{xmlelement, _Name, Attrs, _SubEls} = El | Els], Type) -> - case xml:get_attr_s("xmlns", Attrs) of +extract_history([#xmlel{ns = XMLNS} = El | Els], Type) -> + case XMLNS of ?NS_MUC -> - AttrVal = xml:get_path_s(El, - [{elem, "history"}, {attr, Type}]), + AttrVal = exmpp_xml:get_path(El, + [{element, 'history'}, {attribute, Type,""}]), case Type of "since" -> case jlib:datetime_string_to_timestamp(AttrVal) of @@ -1696,9 +1723,9 @@ send_update_presence(JID, StateData) -> send_update_presence(JID, "", StateData). send_update_presence(JID, Reason, StateData) -> - LJID = jlib:jid_tolower(JID), + LJID = jlib:short_prepd_jid(JID), LJIDs = case LJID of - {U, S, ""} -> + {U, S, undefined} -> ?DICT:fold( fun(J, _, Js) -> case J of @@ -1728,7 +1755,7 @@ send_new_presence(NJID, Reason, StateData) -> nick = Nick, role = Role, last_presence = Presence}} = - ?DICT:find(jlib:jid_tolower(NJID), StateData#state.users), + ?DICT:find(jlib:short_prepd_jid(NJID), StateData#state.users), Affiliation = get_affiliation(NJID, StateData), SAffiliation = affiliation_to_list(Affiliation), SRole = role_to_list(Role), @@ -1738,39 +1765,41 @@ send_new_presence(NJID, Reason, StateData) -> case (Info#user.role == moderator) orelse ((StateData#state.config)#config.anonymous == false) of true -> - [{"jid", jlib:jid_to_string(RealJID)}, - {"affiliation", SAffiliation}, - {"role", SRole}]; + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(RealJID)}, + #xmlattr{name = 'affiliation', value = SAffiliation}, + #xmlattr{name = 'role', value = SRole}]; _ -> - [{"affiliation", SAffiliation}, - {"role", SRole}] + [#xmlattr{name = 'affiliation', value = SAffiliation}, + #xmlattr{name = 'role', value = SRole}] end, ItemEls = case Reason of "" -> []; _ -> - [{xmlelement, "reason", [], - [{xmlcdata, Reason}]}] + [#xmlel{name = 'reason', + children = [#xmlcdata{cdata = Reason}]}] end, Status = case StateData#state.just_created of true -> - [{xmlelement, "status", [{"code", "201"}], []}]; + [#xmlel{name = 'status', + attrs = [#xmlattr{name = 'code', value = "201"}]}]; false -> [] end, - Packet = append_subtags( - Presence, - [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], - [{xmlelement, "item", ItemAttrs, ItemEls} | Status]}]), + Packet = exmpp_xml:append_child(Presence, + #xmlel{ns = ?NS_MUC_USER, name = 'x', + children = [#xmlel{ns = ?NS_MUC_USER, name ='item', + attrs = ItemAttrs, + children = ItemEls} | Status]}), ejabberd_router:route( - jlib:jid_replace_resource(StateData#state.jid, Nick), + jid_replace_resource(StateData#state.jid, Nick), Info#user.jid, Packet) end, ?DICT:to_list(StateData#state.users)). send_existing_presences(ToJID, StateData) -> - LToJID = jlib:jid_tolower(ToJID), + LToJID = jlib:short_prepd_jid(ToJID), {ok, #user{jid = RealToJID, role = Role}} = ?DICT:find(LToJID, StateData#state.users), @@ -1784,27 +1813,29 @@ send_existing_presences(ToJID, StateData) -> FromJID -> ok; _ -> - FromAffiliation = get_affiliation(LJID, StateData), + {N,D,R} = LJID, + FromAffiliation = get_affiliation(exmpp_jid:make_jid(N,D,R), + StateData), ItemAttrs = case (Role == moderator) orelse ((StateData#state.config)#config.anonymous == false) of true -> - [{"jid", jlib:jid_to_string(FromJID)}, - {"affiliation", - affiliation_to_list(FromAffiliation)}, - {"role", role_to_list(FromRole)}]; + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(FromJID)}, + #xmlattr{name = 'affiliation', + value = affiliation_to_list(FromAffiliation)}, + #xmlattr{name = 'role', value = role_to_list(FromRole)}]; _ -> - [{"affiliation", - affiliation_to_list(FromAffiliation)}, - {"role", role_to_list(FromRole)}] + [#xmlattr{name = 'affiliation', + value = affiliation_to_list(FromAffiliation)}, + #xmlattr{name = 'role', value = role_to_list(FromRole)}] end, - Packet = append_subtags( - Presence, - [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], - [{xmlelement, "item", ItemAttrs, []}]}]), + Packet = exmpp_xml:append_child(Presence, + #xmlel{ns = ?NS_MUC_USER, name = 'x', + children = [#xmlel{ns = ?NS_MUC_USER, name ='item', + attrs = ItemAttrs}]}), ejabberd_router:route( - jlib:jid_replace_resource( + jid_replace_resource( StateData#state.jid, FromNick), RealToJID, Packet) @@ -1812,16 +1843,13 @@ send_existing_presences(ToJID, StateData) -> end, ?DICT:to_list(StateData#state.users)). -append_subtags({xmlelement, Name, Attrs, SubTags1}, SubTags2) -> - {xmlelement, Name, Attrs, SubTags1 ++ SubTags2}. - now_to_usec({MSec, Sec, USec}) -> (MSec*1000000 + Sec)*1000000 + USec. change_nick(JID, Nick, StateData) -> - LJID = jlib:jid_tolower(JID), + LJID = jlib:short_prepd_jid(JID), {ok, #user{nick = OldNick}} = ?DICT:find(LJID, StateData#state.users), Users = @@ -1840,7 +1868,7 @@ send_nick_changing(JID, OldNick, StateData) -> nick = Nick, role = Role, last_presence = Presence}} = - ?DICT:find(jlib:jid_tolower(JID), StateData#state.users), + ?DICT:find(jlib:short_prepd_jid(JID), StateData#state.users), Affiliation = get_affiliation(JID, StateData), SAffiliation = affiliation_to_list(Affiliation), SRole = role_to_list(Role), @@ -1850,41 +1878,51 @@ send_nick_changing(JID, OldNick, StateData) -> case (Info#user.role == moderator) orelse ((StateData#state.config)#config.anonymous == false) of true -> - [{"jid", jlib:jid_to_string(RealJID)}, - {"affiliation", SAffiliation}, - {"role", SRole}, - {"nick", Nick}]; + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(RealJID)}, + #xmlattr{name = 'affiliation', value = SAffiliation}, + #xmlattr{name = 'role', value = SRole}, + #xmlattr{name = 'nick', value = Nick}]; _ -> - [{"affiliation", SAffiliation}, - {"role", SRole}, - {"nick", Nick}] + [#xmlattr{name = 'affiliation', value = SAffiliation}, + #xmlattr{name = 'role', value = SRole}, + #xmlattr{name = 'nick', value = Nick}] end, ItemAttrs2 = case (Info#user.role == moderator) orelse ((StateData#state.config)#config.anonymous == false) of true -> - [{"jid", jlib:jid_to_string(RealJID)}, - {"affiliation", SAffiliation}, - {"role", SRole}]; + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(RealJID)}, + #xmlattr{name = 'affiliation', value = SAffiliation}, + #xmlattr{name = 'role', value = SRole}]; _ -> - [{"affiliation", SAffiliation}, - {"role", SRole}] + [#xmlattr{name = 'affiliation', value = SAffiliation}, + #xmlattr{name = 'role', value = SRole}] end, Packet1 = - {xmlelement, "presence", [{"type", "unavailable"}], - [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], - [{xmlelement, "item", ItemAttrs1, []}, - {xmlelement, "status", [{"code", "303"}], []}]}]}, - Packet2 = append_subtags( + #xmlel{ns = ?NS_JABBER_CLIENT, + name = 'presence', + attrs = [#xmlattr{name = 'type', value = "unavailable"}], + children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', + children = [ + #xmlel{ns = ?NS_MUC_USER, name = 'item', + attrs = ItemAttrs1}, + #xmlel{ns = ?NS_MUC_USER, name = 'status', + attrs = [#xmlattr{name = 'code', + value = "303"}]}]}]}, + + Packet2 = exmpp_xml:append_child( Presence, - [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], - [{xmlelement, "item", ItemAttrs2, []}]}]), + #xmlel{ns = ?NS_MUC_USER, name = 'x', + children =[#xmlel{ns = ?NS_MUC_USER, + name = 'item', + attrs = ItemAttrs2}]}), + ejabberd_router:route( - jlib:jid_replace_resource(StateData#state.jid, OldNick), + jid_replace_resource(StateData#state.jid, OldNick), Info#user.jid, Packet1), ejabberd_router:route( - jlib:jid_replace_resource(StateData#state.jid, Nick), + jid_replace_resource(StateData#state.jid, Nick), Info#user.jid, Packet2) end, ?DICT:to_list(StateData#state.users)). @@ -1920,20 +1958,16 @@ lqueue_to_list(#lqueue{queue = Q1}) -> add_message_to_history(FromNick, Packet, StateData) -> - HaveSubject = case xml:get_subtag(Packet, "subject") of - false -> - false; - _ -> - true - end, + HaveSubject = exmpp_xml:has_element(Packet, 'subject'), TimeStamp = calendar:now_to_universal_time(now()), - TSPacket = append_subtags(Packet, - [jlib:timestamp_to_xml(TimeStamp)]), - SPacket = jlib:replace_from_to( - jlib:jid_replace_resource(StateData#state.jid, FromNick), - StateData#state.jid, - TSPacket), - Size = lists:flatlength(xml:element_to_string(SPacket)), + TSPacket = exmpp_xml:append_child(Packet, + jlib:timestamp_to_xml(TimeStamp)), + SPacket = exmpp_stanza:set_recipient( + exmpp_stanza:set_sender(TSPacket, + jid_replace_resource(StateData#state.jid, FromNick)), + StateData#state.jid), + + Size = lists:flatlength(exmpp_xml:document_to_list(SPacket)), Q1 = lqueue_in({FromNick, TSPacket, HaveSubject, TimeStamp, Size}, StateData#state.history), add_to_log(text, {FromNick, Packet}, StateData), @@ -1943,7 +1977,7 @@ send_history(JID, Shift, StateData) -> lists:foldl( fun({Nick, Packet, HaveSubject, _TimeStamp, _Size}, B) -> ejabberd_router:route( - jlib:jid_replace_resource(StateData#state.jid, Nick), + jid_replace_resource(StateData#state.jid, Nick), JID, Packet), B or HaveSubject @@ -1956,14 +1990,9 @@ send_subject(JID, Lang, StateData) -> ok; Nick -> Subject = StateData#state.subject, - Packet = {xmlelement, "message", [{"type", "groupchat"}], - [{xmlelement, "subject", [], [{xmlcdata, Subject}]}, - {xmlelement, "body", [], - [{xmlcdata, - Nick ++ - translate:translate(Lang, - " has set the subject to: ") ++ - Subject}]}]}, + Packet = exmpp_message:groupchat(Subject, + Nick ++ translate:translate(Lang, + " has set the subject to: ") ++ Subject), ejabberd_router:route( StateData#state.jid, JID, @@ -1971,11 +2000,11 @@ send_subject(JID, Lang, StateData) -> end. check_subject(Packet) -> - case xml:get_subtag(Packet, "subject") of - false -> + case exmpp_message:get_subject(Packet) of + undefined -> false; - SubjEl -> - xml:get_tag_cdata(SubjEl) + Subj -> + Subj end. can_change_subject(Role, StateData) -> @@ -1990,25 +2019,25 @@ can_change_subject(Role, StateData) -> % Admin stuff process_iq_admin(From, set, Lang, SubEl, StateData) -> - {xmlelement, _, _, Items} = SubEl, + #xmlel{children = Items} = SubEl, process_admin_items_set(From, Items, Lang, StateData); process_iq_admin(From, get, Lang, SubEl, StateData) -> - case xml:get_subtag(SubEl, "item") of - false -> - {error, ?ERR_BAD_REQUEST}; + case exmpp_xml:get_element(SubEl, 'item') of + 'undefined' -> + {error, 'bad-request'}; Item -> FAffiliation = get_affiliation(From, StateData), FRole = get_role(From, StateData), - case xml:get_tag_attr("role", Item) of + case exmpp_xml:get_attribute(Item, 'role', false) of false -> - case xml:get_tag_attr("affiliation", Item) of + case exmpp_xml:get_attribute(Item, 'affiliation', false) of false -> - {error, ?ERR_BAD_REQUEST}; - {value, StrAffiliation} -> + {error, 'bad-request'}; + StrAffiliation -> case catch list_to_affiliation(StrAffiliation) of {'EXIT', _} -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; SAffiliation -> if (FAffiliation == owner) or @@ -2018,14 +2047,14 @@ process_iq_admin(From, get, Lang, SubEl, StateData) -> {result, Items, StateData}; true -> ErrText = "Administrator privileges required", - {error, ?ERRT_FORBIDDEN(Lang, ErrText)} + {error, ?ERR(SubEl, 'forbidden', Lang, ErrText)} end end end; - {value, StrRole} -> + StrRole -> case catch list_to_role(StrRole) of {'EXIT', _} -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; SRole -> if FRole == moderator -> @@ -2033,7 +2062,7 @@ process_iq_admin(From, get, Lang, SubEl, StateData) -> {result, Items, StateData}; true -> ErrText = "Moderator privileges required", - {error, ?ERRT_FORBIDDEN(Lang, ErrText)} + {error, ?ERR(SubEl, 'forbidden', Lang, ErrText)} end end end @@ -2049,15 +2078,22 @@ items_with_role(SRole, StateData) -> items_with_affiliation(SAffiliation, StateData) -> lists:map( fun({JID, {Affiliation, Reason}}) -> - {xmlelement, "item", - [{"affiliation", affiliation_to_list(Affiliation)}, - {"jid", jlib:jid_to_string(JID)}], - [{xmlelement, "reason", [], [{xmlcdata, Reason}]}]}; + {N, D, R} = JID, + #xmlel{name = 'item', + attrs = [#xmlattr{name = 'affiliation', + value = affiliation_to_list(Affiliation)}, + #xmlattr{name = 'jid', + value = exmpp_jid:jid_to_list(N, D, R)}], + children = [ #xmlel{name = 'reason', + children = [#xmlcdata{cdata = Reason}]}]}; + ({JID, Affiliation}) -> - {xmlelement, "item", - [{"affiliation", affiliation_to_list(Affiliation)}, - {"jid", jlib:jid_to_string(JID)}], - []} + {N, D, R} = JID, + #xmlel{name = 'item', + attrs = [#xmlattr{name = 'affiliation', + value = affiliation_to_list(Affiliation)}, + #xmlattr{name = 'jid', + value = exmpp_jid:jid_to_list(N, D, R)}]} end, search_affiliation(SAffiliation, StateData)). user_to_item(#user{role = Role, @@ -2065,12 +2101,13 @@ user_to_item(#user{role = Role, jid = JID }, StateData) -> Affiliation = get_affiliation(JID, StateData), - {xmlelement, "item", - [{"role", role_to_list(Role)}, - {"affiliation", affiliation_to_list(Affiliation)}, - {"nick", Nick}, - {"jid", jlib:jid_to_string(JID)}], - []}. + #xmlel{name = 'item', + attrs = [ + #xmlattr{name = 'role', value = role_to_list(Role)}, + #xmlattr{name = 'affiliation', value = affiliation_to_list(Affiliation)}, + #xmlattr{name = 'nick', value = Nick}, + #xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(JID)}] + }. search_role(Role, StateData) -> lists:filter( @@ -2096,14 +2133,14 @@ process_admin_items_set(UJID, Items, Lang, StateData) -> case find_changed_items(UJID, UAffiliation, URole, Items, Lang, StateData, []) of {result, Res} -> ?INFO_MSG("Processing MUC admin query from ~s in room ~s:~n ~p", - [jlib:jid_to_string(UJID), jlib:jid_to_string(StateData#state.jid), Res]), + [exmpp_jid:jid_to_list(UJID), exmpp_jid:jid_to_list(StateData#state.jid), Res]), NSD = lists:foldl( fun(E, SD) -> case catch ( case E of {JID, affiliation, owner, _} - when (JID#jid.luser == "") -> + when (JID#jid.lnode == "") -> %% If the provided JID does not have username, %% forget the affiliation completely SD; @@ -2174,27 +2211,28 @@ process_admin_items_set(UJID, Items, Lang, StateData) -> find_changed_items(_UJID, _UAffiliation, _URole, [], _Lang, _StateData, Res) -> {result, Res}; -find_changed_items(UJID, UAffiliation, URole, [{xmlcdata, _} | Items], +find_changed_items(UJID, UAffiliation, URole, [#xmlcdata{} | Items], Lang, StateData, Res) -> find_changed_items(UJID, UAffiliation, URole, Items, Lang, StateData, Res); find_changed_items(UJID, UAffiliation, URole, - [{xmlelement, "item", Attrs, _Els} = Item | Items], + [#xmlel{name = 'item'} = Item | Items], Lang, StateData, Res) -> - TJID = case xml:get_attr("jid", Attrs) of - {value, S} -> - case jlib:string_to_jid(S) of - error -> + TJID = case exmpp_xml:get_attribute(Item, 'jid',false) of + S when S =/= false -> + try exmpp_jid:list_to_jid(S) of + J -> + {value, J} + catch + _:_ -> ErrText = io_lib:format( translate:translate( Lang, "JID ~s is invalid"), [S]), - {error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)}; - J -> - {value, J} + {error, ?ERR(Item, 'not-acceptable', Lang, ErrText)} end; _ -> - case xml:get_attr("nick", Attrs) of - {value, N} -> + case exmpp_xml:get_attribute(Item, 'nick', false) of + N when N =/= false -> case find_jid_by_nick(N, StateData) of false -> ErrText = @@ -2203,24 +2241,24 @@ find_changed_items(UJID, UAffiliation, URole, Lang, "Nickname ~s does not exist in the room"), [N]), - {error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)}; + {error, ?ERR(Item, 'not-acceptable', Lang, ErrText)}; J -> {value, J} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end end, case TJID of {value, JID} -> TAffiliation = get_affiliation(JID, StateData), TRole = get_role(JID, StateData), - case xml:get_attr("role", Attrs) of + case exmpp_xml:get_attribute(Item, 'role',false) of false -> - case xml:get_attr("affiliation", Attrs) of + case exmpp_xml:get_attribute(Item, 'affiliation', false) of false -> - {error, ?ERR_BAD_REQUEST}; - {value, StrAffiliation} -> + {error, 'bad-request'}; + StrAffiliation -> case catch list_to_affiliation(StrAffiliation) of {'EXIT', _} -> ErrText1 = @@ -2229,7 +2267,7 @@ find_changed_items(UJID, UAffiliation, URole, Lang, "Invalid affiliation: ~s"), [StrAffiliation]), - {error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText1)}; + {error, ?ERR(Item, 'not-acceptable', Lang, ErrText1)}; SAffiliation -> ServiceAf = get_service_affiliation(JID, StateData), CanChangeRA = @@ -2246,8 +2284,8 @@ find_changed_items(UJID, UAffiliation, URole, case search_affiliation( owner, StateData) of [{OJID, _}] -> - jlib:jid_remove_resource(OJID) /= - jlib:jid_tolower(jlib:jid_remove_resource(UJID)); + jlib:short_bare_jid(OJID) /= + jlib:short_prepd_bare_jid(UJID); _ -> true end; @@ -2266,18 +2304,18 @@ find_changed_items(UJID, UAffiliation, URole, UJID, UAffiliation, URole, Items, Lang, StateData, - [{jlib:jid_remove_resource(JID), + [{exmpp_jid:jid_to_bare_jid(JID), affiliation, SAffiliation, - xml:get_path_s( - Item, [{elem, "reason"}, + exmpp_xml:get_path( + Item, [{element, 'reason'}, cdata])} | Res]); false -> - {error, ?ERR_NOT_ALLOWED} + {error, 'not-allowed'} end end end; - {value, StrRole} -> + StrRole -> case catch list_to_role(StrRole) of {'EXIT', _} -> ErrText1 = @@ -2286,7 +2324,7 @@ find_changed_items(UJID, UAffiliation, URole, Lang, "Invalid role: ~s"), [StrRole]), - {error, ?ERRT_BAD_REQUEST(Lang, ErrText1)}; + {error, ?ERR(Item, 'bad-request', Lang, ErrText1)}; SRole -> ServiceAf = get_service_affiliation(JID, StateData), CanChangeRA = @@ -2303,8 +2341,8 @@ find_changed_items(UJID, UAffiliation, URole, case search_affiliation( owner, StateData) of [{OJID, _}] -> - jlib:jid_remove_resource(OJID) /= - jlib:jid_tolower(jlib:jid_remove_resource(UJID)); + jlib:short_bare_jid(OJID) /= + jlib:short_prepd_bare_jid(UJID); _ -> true end; @@ -2324,11 +2362,11 @@ find_changed_items(UJID, UAffiliation, URole, UAffiliation, URole, Items, Lang, StateData, [{JID, role, SRole, - xml:get_path_s( - Item, [{elem, "reason"}, + exmpp_xml:get_path( + Item, [{element, 'reason'}, cdata])} | Res]); _ -> - {error, ?ERR_NOT_ALLOWED} + {error, 'not-allowed'} end end end; @@ -2337,7 +2375,7 @@ find_changed_items(UJID, UAffiliation, URole, end; find_changed_items(_UJID, _UAffiliation, _URole, _Items, _Lang, _StateData, _Res) -> - {error, ?ERR_BAD_REQUEST}. + {error, 'bad-request'}. can_change_ra(_FAffiliation, _FRole, @@ -2487,9 +2525,9 @@ can_change_ra(_FAffiliation, _FRole, send_kickban_presence(JID, Reason, Code, StateData) -> - LJID = jlib:jid_tolower(JID), + LJID = jlib:short_prepd_jid(JID), LJIDs = case LJID of - {U, S, ""} -> + {U, S, undefined} -> ?DICT:fold( fun(J, _, Js) -> case J of @@ -2517,27 +2555,35 @@ send_kickban_presence(JID, Reason, Code, StateData) -> send_kickban_presence1(UJID, Reason, Code, StateData) -> {ok, #user{jid = _RealJID, - nick = Nick}} = - ?DICT:find(jlib:jid_tolower(UJID), StateData#state.users), - Affiliation = get_affiliation(UJID, StateData), + nick = Nick}} = ?DICT:find(UJID, StateData#state.users), + {N,D,R} = UJID, + Affiliation = get_affiliation(exmpp_jid:make_jid(N,D,R), StateData), SAffiliation = affiliation_to_list(Affiliation), lists:foreach( fun({_LJID, Info}) -> - ItemAttrs = [{"affiliation", SAffiliation}, - {"role", "none"}], + ItemAttrs = [#xmlattr{name = 'affiliation', value = SAffiliation}, + #xmlattr{name = 'role', value = "none"}], ItemEls = case Reason of - "" -> + <<>> -> []; _ -> - [{xmlelement, "reason", [], - [{xmlcdata, Reason}]}] - end, - Packet = {xmlelement, "presence", [{"type", "unavailable"}], - [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], - [{xmlelement, "item", ItemAttrs, ItemEls}, - {xmlelement, "status", [{"code", Code}], []}]}]}, + [#xmlel{name = 'reason', + children = [#xmlcdata{cdata = Reason}]}] + end, + Packet = + #xmlel{ns = ?NS_JABBER_CLIENT, + name = 'presence', + attrs = [#xmlattr{name = 'type', value = "unavailable"}], + children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', + children = [ + #xmlel{ns = ?NS_MUC_USER, name = 'item', + attrs = ItemAttrs, + children = ItemEls}, + #xmlel{ns = ?NS_MUC_USER, name = 'status', + attrs = [#xmlattr{name='code', + value = Code}]}]}]}, ejabberd_router:route( - jlib:jid_replace_resource(StateData#state.jid, Nick), + jid_replace_resource(StateData#state.jid, Nick), Info#user.jid, Packet) end, ?DICT:to_list(StateData#state.users)). @@ -2551,47 +2597,44 @@ process_iq_owner(From, set, Lang, SubEl, StateData) -> FAffiliation = get_affiliation(From, StateData), case FAffiliation of owner -> - {xmlelement, _Name, _Attrs, Els} = SubEl, - case xml:remove_cdata(Els) of - [{xmlelement, "x", _Attrs1, _Els1} = XEl] -> - case {xml:get_tag_attr_s("xmlns", XEl), - xml:get_tag_attr_s("type", XEl)} of - {?NS_XDATA, "cancel"} -> + case exmpp_xml:get_child_elements(SubEl) of + [#xmlel{ns = XMLNS, name = 'x'} = XEl] -> + case {XMLNS, exmpp_xml:get_attribute(XEl, 'type',false)} of + {?NS_DATA_FORMS, "cancel"} -> {result, [], StateData}; - {?NS_XDATA, "submit"} -> + {?NS_DATA_FORMS, "submit"} -> case {check_allowed_log_change(XEl, StateData, From), check_allowed_persistent_change(XEl, StateData, From)} of {allow, allow} -> set_config(XEl, StateData); - _ -> {error, ?ERR_BAD_REQUEST} + _ -> {error, 'bad-request'} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; - [{xmlelement, "destroy", _Attrs1, _Els1} = SubEl1] -> + [#xmlel{name = 'destroy'} = SubEl1] -> ?INFO_MSG("Destroyed MUC room ~s by the owner ~s", - [jlib:jid_to_string(StateData#state.jid), jlib:jid_to_string(From)]), + [exmpp_jid:jid_to_list(StateData#state.jid), exmpp_jid:jid_to_list(From)]), destroy_room(SubEl1, StateData); Items -> process_admin_items_set(From, Items, Lang, StateData) end; _ -> ErrText = "Owner privileges required", - {error, ?ERRT_FORBIDDEN(Lang, ErrText)} + {error, ?ERR(SubEl, 'forbidden', Lang, ErrText)} end; process_iq_owner(From, get, Lang, SubEl, StateData) -> FAffiliation = get_affiliation(From, StateData), case FAffiliation of owner -> - {xmlelement, _Name, _Attrs, Els} = SubEl, - case xml:remove_cdata(Els) of + case exmpp_xml:get_child_elements(SubEl) of [] -> get_config(Lang, StateData, From); [Item] -> - case xml:get_tag_attr("affiliation", Item) of + case exmpp_xml:get_attribute(Item, 'affiliation',false) of false -> - {error, ?ERR_BAD_REQUEST}; - {value, StrAffiliation} -> + {error, 'bad-request'}; + StrAffiliation -> case catch list_to_affiliation(StrAffiliation) of {'EXIT', _} -> ErrText = @@ -2600,7 +2643,7 @@ process_iq_owner(From, get, Lang, SubEl, StateData) -> Lang, "Invalid affiliation: ~s"), [StrAffiliation]), - {error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)}; + {error, ?ERR(SubEl, 'not-acceptable', Lang, ErrText)}; SAffiliation -> Items = items_with_affiliation( SAffiliation, StateData), @@ -2608,11 +2651,11 @@ process_iq_owner(From, get, Lang, SubEl, StateData) -> end end; _ -> - {error, ?ERR_FEATURE_NOT_IMPLEMENTED} + {error, 'feature-not-implemented'} end; _ -> ErrText = "Owner privileges required", - {error, ?ERRT_FORBIDDEN(Lang, ErrText)} + {error, ?ERR(SubEl, 'forbidden', Lang, ErrText)} end. check_allowed_log_change(XEl, StateData, From) -> @@ -2636,10 +2679,13 @@ check_allowed_persistent_change(XEl, StateData, From) -> end. -define(XFIELD(Type, Label, Var, Val), - {xmlelement, "field", [{"type", Type}, - {"label", translate:translate(Lang, Label)}, - {"var", Var}], - [{xmlelement, "value", [], [{xmlcdata, Val}]}]}). + #xmlel{name = 'field', + attrs = [#xmlattr{name = 'type', value = Type}, + #xmlattr{name = 'label', value = translate:translate(Lang, Label)}, + #xmlattr{name = 'var', value = Var}], + children = [#xmlel{name = 'value', + children = [#xmlcdata{cdata = Val} ]}]}). + -define(BOOLXFIELD(Label, Var, Val), ?XFIELD("boolean", Label, Var, @@ -2654,19 +2700,19 @@ check_allowed_persistent_change(XEl, StateData, From) -> -define(PRIVATEXFIELD(Label, Var, Val), ?XFIELD("text-private", Label, Var, Val)). - get_config(Lang, StateData, From) -> {_AccessRoute, _AccessCreate, _AccessAdmin, AccessPersistent} = StateData#state.access, ServiceMaxUsers = get_service_max_users(StateData), Config = StateData#state.config, Res = - [{xmlelement, "title", [], - [{xmlcdata, translate:translate(Lang, "Configuration for ") ++ - jlib:jid_to_string(StateData#state.jid)}]}, - {xmlelement, "field", [{"type", "hidden"}, - {"var", "FORM_TYPE"}], - [{xmlelement, "value", [], - [{xmlcdata, "http://jabber.org/protocol/muc#roomconfig"}]}]}, + [#xmlel{name = 'title', children = [ #xmlcdata{cdata = + translate:translate(Lang, "Configuration for ") ++ + exmpp_jid:jid_to_list(StateData#state.jid)}]}, + #xmlel{name = 'field', attrs = [#xmlattr{name = 'type', value = "hidden"}, + #xmlattr{name = 'var', value = "FORM_TYPE"}], + children = [#xmlel{name = 'value', children = [#xmlcdata{cdata = + <<"http://jabber.org/protocol/muc#roomconfig">> + }]}]}, ?STRINGXFIELD("Room title", "muc#roomconfig_roomname", Config#config.title), @@ -2697,73 +2743,85 @@ get_config(Lang, StateData, From) -> true -> Config#config.password; false -> "" end), - {xmlelement, "field", - [{"type", "list-single"}, - {"label", translate:translate(Lang, "Maximum Number of Occupants")}, - {"var", "muc#roomconfig_maxusers"}], - [{xmlelement, "value", [], [{xmlcdata, - case get_max_users(StateData) of - N when is_integer(N) -> - erlang:integer_to_list(N); - _ -> "none" - end - }]}] ++ + #xmlel{name = 'field', attrs = [ + #xmlattr{name = 'type', value = "list-single"}, + #xmlattr{name = 'label', value = translate:translate(Lang, + "Maximum Number of Occupants")}, + #xmlattr{name = 'var', value = "muc#roomconfig_maxusers"}], + children = [#xmlel{name = 'value', + children = [#xmlcdata{cdata = + case get_max_users(StateData) of + N when is_integer(N) -> + erlang:integer_to_list(N); + _ -> "none" + end}]}] ++ if is_integer(ServiceMaxUsers) -> []; true -> - [{xmlelement, "option", - [{"label", translate:translate(Lang, "No limit")}], - [{xmlelement, "value", [], [{xmlcdata, "none"}]}]}] + [#xmlel{name = 'option', attrs = [#xmlattr{name = 'label', + value = translate:translate(Lang, "No limit")}], + children = [#xmlel{name = 'value', children = [#xmlcdata{ + cdata = <<"none">>}]}]}] end ++ - [{xmlelement, "option", [{"label", erlang:integer_to_list(N)}], - [{xmlelement, "value", [], - [{xmlcdata, erlang:integer_to_list(N)}]}]} || - N <- ?MAX_USERS_DEFAULT_LIST, N =< ServiceMaxUsers] - }, - {xmlelement, "field", - [{"type", "list-single"}, - {"label", translate:translate(Lang, "Present real JIDs to")}, - {"var", "muc#roomconfig_whois"}], - [{xmlelement, "value", [], [{xmlcdata, - if Config#config.anonymous -> - "moderators"; - true -> - "anyone" - end}]}, - {xmlelement, "option", [{"label", translate:translate(Lang, "moderators only")}], - [{xmlelement, "value", [], [{xmlcdata, "moderators"}]}]}, - {xmlelement, "option", [{"label", translate:translate(Lang, "anyone")}], - [{xmlelement, "value", [], [{xmlcdata, "anyone"}]}]}]}, - ?BOOLXFIELD("Make room members-only", - "muc#roomconfig_membersonly", - Config#config.members_only), - ?BOOLXFIELD("Make room moderated", - "muc#roomconfig_moderatedroom", - Config#config.moderated), - ?BOOLXFIELD("Default users as participants", - "members_by_default", - Config#config.members_by_default), - ?BOOLXFIELD("Allow users to change subject", - "muc#roomconfig_changesubject", - Config#config.allow_change_subj), - ?BOOLXFIELD("Allow users to send private messages", - "allow_private_messages", - Config#config.allow_private_messages), - ?BOOLXFIELD("Allow users to query other users", - "allow_query_users", - Config#config.allow_query_users), - ?BOOLXFIELD("Allow users to send invites", - "muc#roomconfig_allowinvites", - Config#config.allow_user_invites), - ?BOOLXFIELD("Allow visitors to send status text in presence updates", - "muc#roomconfig_allowvisitorstatus", - Config#config.allow_visitor_status), - ?BOOLXFIELD("Allow visitors to change nickname", - "muc#roomconfig_allowvisitornickchange", - Config#config.allow_visitor_nickchange) - ] ++ + [#xmlel{name = 'option', attrs = [#xmlattr{name = 'label', + value = erlang:integer_to_list(N)}], + children = [#xmlel{name = 'value', children = [ + #xmlcdata{cdata = erlang:integer_to_list(N)}]}]} || + N <- ?MAX_USERS_DEFAULT_LIST, N =< ServiceMaxUsers]}, + #xmlel{name = 'field', attrs = [ + #xmlattr{name = 'type', value = "list-single"}, + #xmlattr{name = 'label', + value = translate:translate(Lang, "Present real JIDs to")}, + #xmlattr{name = 'var', value = "muc#roomconfig_whois"}], + children = [#xmlel{name = 'value', + children = [#xmlcdata{cdata = + if Config#config.anonymous -> <<"moderators">>; + true -> <<"anyone">> + end}]}, + #xmlel{name = 'option', attrs = [ + #xmlattr{name = 'label', value = + translate:translate(Lang, "moderators only")}], + children = [#xmlel{name = 'value', + children = [#xmlcdata{cdata = + <<"moderators">>}]}]}, + #xmlel{name = 'option', attrs = [ + #xmlattr{name = 'label', value = + translate:translate(Lang, "anyone")}], + children = [#xmlel{name = 'value', + children = [#xmlcdata{cdata = + <<"anyone">>}]}]}]}, + ?BOOLXFIELD("Make room members-only", + "muc#roomconfig_membersonly", + Config#config.members_only), + ?BOOLXFIELD("Make room moderated", + "muc#roomconfig_moderatedroom", + Config#config.moderated), + ?BOOLXFIELD("Default users as participants", + "members_by_default", + Config#config.members_by_default), + ?BOOLXFIELD("Allow users to change subject", + "muc#roomconfig_changesubject", + Config#config.allow_change_subj), + ?BOOLXFIELD("Allow users to send private messages", + "allow_private_messages", + Config#config.allow_private_messages), + ?BOOLXFIELD("Allow users to query other users", + "allow_query_users", + Config#config.allow_query_users), + ?BOOLXFIELD("Allow users to send invites", + "muc#roomconfig_allowinvites", + Config#config.allow_user_invites), + ?BOOLXFIELD("Allow visitors to send status text in presence updates", + "muc#roomconfig_allowvisitorstatus", + Config#config.allow_visitor_status), + ?BOOLXFIELD("Allow visitors to change nickname", + "muc#roomconfig_allowvisitornickchange", + Config#config.allow_visitor_nickchange) + ] ++ + + case mod_muc_log:check_access_log( - StateData#state.server_host, From) of + StateData#state.server_host, From) of allow -> [?BOOLXFIELD( "Enable logging", @@ -2771,14 +2829,13 @@ get_config(Lang, StateData, From) -> Config#config.logging)]; _ -> [] end, - {result, [{xmlelement, "instructions", [], - [{xmlcdata, - translate:translate( - Lang, "You need an x:data capable client to configure room")}]}, - {xmlelement, "x", [{"xmlns", ?NS_XDATA}, - {"type", "form"}], - Res}], - StateData}. + {result , [#xmlel{name = 'instructions', children = [ + #xmlcdata{cdata = translate:translate(Lang, + "You need an x:data capable client to configure room")}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'x', + attrs = [#xmlattr{name = 'type', value = "form"}], + children = Res}], + StateData}. @@ -2786,7 +2843,7 @@ set_config(XEl, StateData) -> XData = jlib:parse_xdata_submit(XEl), case XData of invalid -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; _ -> case set_xoption(XData, StateData#state.config) of #config{} = Config -> @@ -2805,7 +2862,7 @@ set_config(XEl, StateData) -> "false" -> set_xoption(Opts, Config#config{Opt = false}); "1" -> set_xoption(Opts, Config#config{Opt = true}); "true" -> set_xoption(Opts, Config#config{Opt = true}); - _ -> {error, ?ERR_BAD_REQUEST} + _ -> {error, 'bad-request'} end). -define(SET_NAT_XOPT(Opt, Val), @@ -2814,7 +2871,7 @@ set_config(XEl, StateData) -> I > 0 -> set_xoption(Opts, Config#config{Opt = I}); _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end). -define(SET_STRING_XOPT(Opt, Val), @@ -2864,7 +2921,7 @@ set_xoption([{"muc#roomconfig_whois", [Val]} | Opts], Config) -> "anyone" -> ?SET_BOOL_XOPT(anonymous, "0"); _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; set_xoption([{"muc#roomconfig_maxusers", [Val]} | Opts], Config) -> case Val of @@ -2879,7 +2936,7 @@ set_xoption([{"FORM_TYPE", _} | Opts], Config) -> %% Ignore our FORM_TYPE set_xoption(Opts, Config); set_xoption([_ | _Opts], _Config) -> - {error, ?ERR_BAD_REQUEST}. + {error, 'bad-request'}. change_config(Config, StateData) -> @@ -2997,13 +3054,18 @@ destroy_room(DEl, StateData) -> lists:foreach( fun({_LJID, Info}) -> Nick = Info#user.nick, - ItemAttrs = [{"affiliation", "none"}, - {"role", "none"}], - Packet = {xmlelement, "presence", [{"type", "unavailable"}], - [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], - [{xmlelement, "item", ItemAttrs, []}, DEl]}]}, + ItemAttrs = [#xmlattr{name = 'affiliation', value = "none"}, + #xmlattr{name = 'role', value = "none"}], + Packet = #xmlel{ns = ?NS_JABBER_CLIENT, + name = 'presence', + attrs = [#xmlattr{name = 'type', + value = "unavailable"}], + children = [ + #xmlel{ns = ?NS_MUC_USER, name = 'x', children = + [#xmlel{name = 'item', attrs = ItemAttrs}, + DEl]}]}, ejabberd_router:route( - jlib:jid_replace_resource(StateData#state.jid, Nick), + jid_replace_resource(StateData#state.jid, Nick), Info#user.jid, Packet) end, ?DICT:to_list(StateData#state.users)), @@ -3021,7 +3083,8 @@ destroy_room(DEl, StateData) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Disco --define(FEATURE(Var), {xmlelement, "feature", [{"var", Var}], []}). +-define(FEATURE(Var), #xmlel{name = 'feature', + attrs = [#xmlattr{name = 'var', value = Var}]}). -define(CONFIG_OPT_TO_FEATURE(Opt, Fiftrue, Fiffalse), case Opt of @@ -3032,16 +3095,19 @@ destroy_room(DEl, StateData) -> end). process_iq_disco_info(_From, set, _Lang, _StateData) -> - {error, ?ERR_NOT_ALLOWED}; + {error, 'not-allowed'}; process_iq_disco_info(_From, get, Lang, StateData) -> Config = StateData#state.config, - {result, [{xmlelement, "identity", - [{"category", "conference"}, - {"type", "text"}, - {"name", get_title(StateData)}], []}, - {xmlelement, "feature", - [{"var", ?NS_MUC}], []}, + {result, [ #xmlel{name = 'identity', + attrs = [#xmlattr{name = 'category', + value = "conference"}, + #xmlattr{name = 'type', value = "text"}, + #xmlattr{name = 'name', + value = get_title(StateData)}]}, + #xmlel{name = 'feature', + attrs = [#xmlattr{name = 'var', value = ?NS_MUC_s}]}, + ?CONFIG_OPT_TO_FEATURE(Config#config.public, "muc_public", "muc_hidden"), ?CONFIG_OPT_TO_FEATURE(Config#config.persistent, @@ -3057,18 +3123,24 @@ process_iq_disco_info(_From, get, Lang, StateData) -> ] ++ iq_disco_info_extras(Lang, StateData), StateData}. -define(RFIELDT(Type, Var, Val), - {xmlelement, "field", [{"type", Type}, {"var", Var}], - [{xmlelement, "value", [], [{xmlcdata, Val}]}]}). + #xmlel{name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, + #xmlattr{name = 'var', value = Var}], + children = [#xmlel{name = 'value', + children = [#xmlcdata{cdata = Val}]}]}). -define(RFIELD(Label, Var, Val), - {xmlelement, "field", [{"label", translate:translate(Lang, Label)}, - {"var", Var}], - [{xmlelement, "value", [], [{xmlcdata, Val}]}]}). + #xmlel{name = 'field', attrs = [#xmlattr{name = 'label', value = + translate:translate(Lang, Label)}, + #xmlattr{name = 'var', value = Var}], + children = [#xmlel{name = 'value', children = [ + #xmlcdata{cdata = Val}]}]}). iq_disco_info_extras(Lang, StateData) -> Len = length(?DICT:to_list(StateData#state.users)), RoomDescription = (StateData#state.config)#config.description, - [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "result"}], + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', + attrs = [#xmlattr{name = 'type', value = "result"}], + children = [?RFIELDT("hidden", "FORM_TYPE", "http://jabber.org/protocol/muc#roominfo"), ?RFIELD("Room description", "muc#roominfo_description", @@ -3078,7 +3150,7 @@ iq_disco_info_extras(Lang, StateData) -> ]}]. process_iq_disco_items(_From, set, _Lang, _StateData) -> - {error, ?ERR_NOT_ALLOWED}; + {error, 'not-allowed'}; process_iq_disco_items(From, get, _Lang, StateData) -> FAffiliation = get_affiliation(From, StateData), @@ -3092,17 +3164,18 @@ process_iq_disco_items(From, get, _Lang, StateData) -> lists:map( fun({_LJID, Info}) -> Nick = Info#user.nick, - {xmlelement, "item", - [{"jid", jlib:jid_to_string( - {StateData#state.room, - StateData#state.host, - Nick})}, - {"name", Nick}], []} + #xmlel{name = 'item', attrs = [#xmlattr{name = 'jid', + value = exmpp_jid:jid_to_list( + StateData#state.room, + StateData#state.host, + Nick)}, + #xmlattr{name = 'name', + value = Nick}]} end, ?DICT:to_list(StateData#state.users)), {result, UList, StateData}; _ -> - {error, ?ERR_FORBIDDEN} + {error, 'forbidden'} end. get_title(StateData) -> @@ -3121,72 +3194,72 @@ check_invitation(From, Els, Lang, StateData) -> FAffiliation = get_affiliation(From, StateData), CanInvite = (StateData#state.config)#config.allow_user_invites orelse (FAffiliation == admin) orelse (FAffiliation == owner), - InviteEl = case xml:remove_cdata(Els) of - [{xmlelement, "x", _Attrs1, Els1} = XEl] -> - case xml:get_tag_attr_s("xmlns", XEl) of - ?NS_MUC_USER -> - ok; - _ -> - throw({error, ?ERR_BAD_REQUEST}) - end, - case xml:remove_cdata(Els1) of - [{xmlelement, "invite", _Attrs2, _Els2} = InviteEl1] -> - InviteEl1; - _ -> - throw({error, ?ERR_BAD_REQUEST}) - end; - _ -> - throw({error, ?ERR_BAD_REQUEST}) - end, - JID = case jlib:string_to_jid( - xml:get_tag_attr_s("to", InviteEl)) of - error -> - throw({error, ?ERR_JID_MALFORMED}); - JID1 -> - JID1 - end, + InviteEl = case Els of + [#xmlel{ns = XMLNS, name = 'x'} = XEl] -> + case XMLNS of + ?NS_MUC_USER -> ok; + _ -> throw({error, 'bad-request'}) + end, + case exmpp_xml:get_child_elements(XEl) of + [#xmlel{name = 'invite'} = InviteEl1] -> + InviteEl1; + _ -> + throw({error, 'bad-request'}) + end; + _ -> + throw({error, 'bad-request'}) + end, + JID = try exmpp_jid:list_to_jid(exmpp_xml:get_attribute(InviteEl, + 'to', + false)) of + JID1 -> JID1 + catch + _:_ -> + throw({error, 'jid-malformed'}) + end, case CanInvite of false -> - throw({error, ?ERR_NOT_ALLOWED}); + throw({error, 'not-allowed'}); true -> Reason = - xml:get_path_s( + exmpp_xml:get_path( InviteEl, - [{elem, "reason"}, cdata]), + [{element, 'reason'}, cdata]), ContinueEl = - case xml:get_path_s( + case xml:get_path( InviteEl, - [{elem, "continue"}]) of + [{element, 'continue'}]) of [] -> []; Continue1 -> [Continue1] end, IEl = - [{xmlelement, "invite", - [{"from", - jlib:jid_to_string(From)}], - [{xmlelement, "reason", [], - [{xmlcdata, Reason}]}] ++ ContinueEl}], + [#xmlel{name = 'invite', + attrs = [#xmlattr{name = 'from', + value = exmpp_jid:jid_to_list(From)}], + children = [#xmlel{name = 'reason', + children = [#xmlcdata{cdata = Reason} ]}] + ++ ContinueEl}], PasswdEl = case (StateData#state.config)#config.password_protected of true -> - [{xmlelement, "password", [], - [{xmlcdata, (StateData#state.config)#config.password}]}]; + [#xmlel{name = 'password', + children = [#xmlcdata{cdata = + (StateData#state.config)#config.password}]}]; _ -> [] end, Body = - {xmlelement, "body", [], - [{xmlcdata, - lists:flatten( - io_lib:format( - translate:translate( - Lang, - "~s invites you to the room ~s"), - [jlib:jid_to_string(From), - jlib:jid_to_string({StateData#state.room, - StateData#state.host, - ""}) - ])) ++ + #xmlel{name = 'body', + children = [#xmlcdata{cdata = + lists:flatten( + io_lib:format( + translate:translate(Lang, + "~s invites you to the room ~s"), + [exmpp_jid:jid_to_list(From), + exmpp_jid:jid_to_list(StateData#state.room, + StateData#state.host, + "") + ])) ++ case (StateData#state.config)#config.password_protected of true -> ", " ++ @@ -3202,17 +3275,18 @@ check_invitation(From, Els, Lang, StateData) -> end }]}, Msg = - {xmlelement, "message", - [{"type", "normal"}], - [{xmlelement, "x", [{"xmlns", ?NS_MUC_USER}], IEl ++ PasswdEl}, - {xmlelement, "x", - [{"xmlns", ?NS_XCONFERENCE}, - {"jid", jlib:jid_to_string( - {StateData#state.room, - StateData#state.host, - ""})}], - [{xmlcdata, Reason}]}, - Body]}, + #xmlel{name = 'message', + attrs = [#xmlattr{name = 'type', value = "normal"}], + children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', + children = IEl ++ PasswdEl}, + #xmlel{ns = 'jabber:x:conference', name = 'x', + attrs = [#xmlattr{name = 'jid', + value = exmpp_jid:jid_to_list( + StateData#state.room, + StateData#state.host, + "")}], + children = [#xmlcdata{cdata = Reason}]}, + Body]}, ejabberd_router:route(StateData#state.jid, JID, Msg), JID end. @@ -3233,36 +3307,37 @@ handle_roommessage_from_nonparticipant(Packet, Lang, StateData, From) -> %% This function must be catched, %% because it crashes when the packet is not a decline message. check_decline_invitation(Packet) -> - {xmlelement, "message", _, _} = Packet, - XEl = xml:get_subtag(Packet, "x"), - ?NS_MUC_USER = xml:get_tag_attr_s("xmlns", XEl), - DEl = xml:get_subtag(XEl, "decline"), - ToString = xml:get_tag_attr_s("to", DEl), - ToJID = jlib:string_to_jid(ToString), + #xmlel{name = 'message'} = Packet, + #xmlel{ns = ?NS_MUC_USER} = XEl = exmpp_xml:get_element(Packet, 'x'), + DEl = exmpp_xml:get_element(XEl, 'decline'), + ToString = exmpp_xml:get_attribute(DEl, 'to', false), + ToJID = exmpp_jid:list_to_jid(ToString), {true, {Packet, XEl, DEl, ToJID}}. %% Send the decline to the inviter user. %% The original stanza must be slightly modified. -send_decline_invitation({Packet, XEl, DEl, ToJID}, RoomJID, FromJID) -> - FromString = jlib:jid_to_string(FromJID), - {xmlelement, "decline", DAttrs, DEls} = DEl, - DAttrs2 = lists:keydelete("to", 1, DAttrs), - DAttrs3 = [{"from", FromString} | DAttrs2], - DEl2 = {xmlelement, "decline", DAttrs3, DEls}, - XEl2 = replace_subelement(XEl, DEl2), - Packet2 = replace_subelement(Packet, XEl2), +send_decline_invitation({Packet, XEl, DEl = #xmlel{name='decline'}, ToJID}, + RoomJID, FromJID) -> + FromString = exmpp_jid:jid_to_list(FromJID), + + DEl1 = exmpp_xml:remove_attribute(DEl, 'to'), + DEl2 = exmpp_xml:set_attribute(DEl1, 'from',FromString), + XEl2 = replace_subelement(XEl,DEl2), + Packet2 = replace_subelement(Packet,XEl2), ejabberd_router:route(RoomJID, ToJID, Packet2). %% Given an element and a new subelement, %% replace the instance of the subelement in element with the new subelement. -replace_subelement({xmlelement, Name, Attrs, SubEls}, NewSubEl) -> - {_, NameNewSubEl, _, _} = NewSubEl, - SubEls2 = lists:keyreplace(NameNewSubEl, 2, SubEls, NewSubEl), - {xmlelement, Name, Attrs, SubEls2}. +replace_subelement(#xmlel{children = Els} = El, #xmlel{name = Name} = NewSubEl) -> + Els2 = lists:map(fun(#xmlel{name = Name2}) when Name2 =:= Name -> NewSubEl; + (S) -> S + end, Els), + exmpp_xml:set_children(El, Els2). send_error_only_occupants(Packet, Lang, RoomJID, From) -> ErrText = "Only occupants are allowed to send messages to the conference", - Err = jlib:make_error_reply(Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), + Err = exmpp_stanza:reply_with_error( + Packet, ?ERR(Packet, 'not-acceptable', Lang, ErrText)), ejabberd_router:route(RoomJID, From, Err). @@ -3283,7 +3358,8 @@ add_to_log(Type, Data, StateData) -> %% Users number checking tab_add_online_user(JID, StateData) -> - {LUser, LServer, _} = jlib:jid_tolower(JID), + LUser = JID#jid.lnode, + LServer = JID#jid.ldomain, US = {LUser, LServer}, Room = StateData#state.room, Host = StateData#state.host, @@ -3292,8 +3368,11 @@ tab_add_online_user(JID, StateData) -> #muc_online_users{us = US, room = Room, host = Host}). -tab_remove_online_user(JID, StateData) -> - {LUser, LServer, _} = jlib:jid_tolower(JID), + +tab_remove_online_user(#jid{lnode = LUser, ldomain = LServer}, StateData) -> + tab_remove_online_user({LUser, LServer, none},StateData); + +tab_remove_online_user({LUser, LServer,_}, StateData) -> US = {LUser, LServer}, Room = StateData#state.room, Host = StateData#state.host, @@ -3302,7 +3381,8 @@ tab_remove_online_user(JID, StateData) -> #muc_online_users{us = US, room = Room, host = Host}). tab_count_user(JID) -> - {LUser, LServer, _} = jlib:jid_tolower(JID), + LUser = JID#jid.lnode, + LServer = JID#jid.ldomain, US = {LUser, LServer}, case catch ets:select( muc_online_users, @@ -3312,3 +3392,14 @@ tab_count_user(JID) -> _ -> 0 end. + + +jid_replace_resource(JID, Resource) -> + case exmpp_stringprep:resourceprep(Resource) of + error -> error; + LResource -> + JID#jid{resource = Resource, lresource = LResource} + end. + + + From 9e960432553a0bd39b7cb7e4b1f8025f8a44db91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 1 Dec 2008 15:53:30 +0000 Subject: [PATCH 127/582] Merge from trunk (r1649 to r1692). PR: EJABP-1 SVN Revision: 1695 --- ChangeLog | 132 ++++++++++++ doc/guide.html | 15 +- doc/guide.tex | 15 +- src/Makefile.in | 4 +- src/ejabberd_app.erl | 39 ++-- src/ejabberd_c2s.erl | 3 + src/ejabberd_ctl.erl | 12 +- src/ejabberd_frontend_socket.erl | 63 ++++-- src/ejabberd_listener.erl | 26 ++- src/ejabberd_receiver.erl | 34 +-- src/ejabberd_s2s_out.erl | 3 +- src/ejabberd_sup.erl | 26 +++ src/ejabberdctl.template | 28 ++- src/eldap/Makefile.in | 4 +- src/eldap/Makefile.win32 | 4 +- src/extauth.erl | 21 +- src/gen_mod.erl | 12 +- src/mod_irc/mod_irc.erl | 2 + src/mod_muc/mod_muc.erl | 6 + src/mod_muc/mod_muc_room.erl | 175 +++++++++++----- src/mod_proxy65/mod_proxy65_service.erl | 1 - src/mod_pubsub/mod_pubsub.erl | 19 +- src/mod_pubsub/node_default.erl | 6 +- src/mod_pubsub/node_pep.erl | 11 +- src/mod_roster.erl | 3 +- src/mod_roster_odbc.erl | 3 +- src/mod_shared_roster.erl | 6 +- src/mod_vcard.erl | 8 +- src/odbc/ejabberd_odbc.erl | 14 +- src/tls/tls_drv.c | 267 +++++++++++++++++++++--- src/translate.erl | 10 +- src/web/ejabberd_http.erl | 63 +++--- 32 files changed, 801 insertions(+), 234 deletions(-) diff --git a/ChangeLog b/ChangeLog index b4537022c..d6a2addfb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,74 @@ +2008-12-01 Jean-Sébastien Pédron + + Merge from trunk (r1649 to r1692). + +2008-11-28 Alexey Shchepin + + * src/mod_muc/mod_muc_room.erl: Clean user activity after timeout + (EJAB-804) + +2008-11-26 Badlop + + * src/ejabberdctl.template: Fix detection of ejabberdctl.cfg path + + * src/mod_irc/mod_irc.erl: Announce disco#info (thanks to Spike) + * src/mod_muc/mod_muc.erl: Announce disco#info disco#items + * src/mod_proxy65/mod_proxy65_service.erl: No announce disco#items + * src/mod_pubsub/mod_pubsub.erl: Announce disco#info disco#items + * src/mod_vcard.erl: Announce disco#info + + * src/gen_mod.erl: First store module options in ETS and Mnesia, + then start the module. In case of failure, remove options from + ETS. Until now the module was started before the options were + stored in database, and some modules started incorrectly because + they couldn't access the options from database; for instance + mod_muc_room required this for reading max_users option. + + * src/mod_muc/mod_muc_room.erl: Include the value of max_users + service option and the current max_users room option in the list + of allowed room limit values. + +2008-10-17 Christophe Romain + + * src/mod_pubsub/node_pep.erl: Fix get_node_affiliations resultset to + owner (Thanks to Michal Schmidt) + +2008-11-24 Evgeniy Khramtsov + + * src/eldap/Makefile.in: added +optimize and +driver + compilation options + * src/eldap/Makefile.win32: Likewise + +2008-11-23 Alexey Shchepin + + * src/ejabberd_receiver.erl: Hibernate after timeout + * src/ejabberd_frontend_socket.erl: Likewise + +2008-11-12 Badlop + + * src/web/ejabberd_http.erl: Include recognized headers in + request_headers as atoms, and others as strings (EJAB-778). + URL path should be tokenized by / and then decoded (EJAB-786). + + * doc/guide.tex: Improve legibility of mod_irc example config + +2008-11-10 Alexey Shchepin + + * src/tls/tls_drv.c: Don't create a SSL context on every + connection and disable SSLv2 on outgoing connections (EJAB-781) + +2008-11-08 Mickael Remond + + * src/ejabberd_s2s_out.erl: exports the DNS resolution + function. + +2008-11-06 Badlop + + * src/extauth.erl: When the extauth call fails or timeouts, deny + authorization. Use two timeouts: 60s for script initialization and + 10s for regular calls. (thanks to Kevin Crosbie from + Ravenpack) (EJAB-627) + 2008-11-04 Pablo Polvorin * src/mod_muc/mod_muc_log.erl: Convert to exmpp, fix recursive @@ -13,6 +84,10 @@ * src/mod_muc/mod_muc.erl, src/mod_muc/mod_muc_room.erl: Convert to exmpp. +2008-11-03 Alexey Shchepin + + * src/ejabberd_c2s.erl: Disable zlib when STARTTLS is required + 2008-10-31 Jean-Sébastien Pédron * src/mod_last_odbc.erl (store_last_info/4): Fix a bug where the @@ -21,11 +96,64 @@ (get_last_info/2): Fix a bug where the status was returned as a list instead of a binary. +2008-10-27 Badlop + + * src/Makefile.in (clean-local): Delete also ejabberdctl.example + +2008-10-25 Badlop + + * src/translate.erl: When a translation file can't be loaded, show + detailed error message + + * src/ejabberd_ctl.erl: If ejabberd didn't start correctly: + 'ejabberdctl status' suggests to look in log files; any other + ejabberdctl command shows 'status'. + + * src/ejabberd_app.erl: Open ejabberd.log sooner, so errors during + ejabberd initialization are logged in that file (EJAB-777). Write + a log message when ejabberd finishes the start or stop. + +2008-10-24 Badlop + + * src/ejabberd_c2s.erl: Ensure unique ID in roster push (EJAB-721) + * src/mod_roster.erl: Likewise + * src/mod_roster_odbc.erl: Likewise + * src/mod_shared_roster.erl: Likewise + + * src/ejabberd_listener.erl: Fix listeners + * src/ejabberd_sup.erl: Likewise + * src/gen_mod.erl: Likewise + +2008-10-23 Alexey Shchepin + + * src/ejabberd_frontend_socket.erl: Fixed SSL sockets + 2008-10-20 Jean-Sébastien Pédron * src/mod_irc/mod_irc.erl, src/mod_irc/mod_irc_connection.erl: Convert to exmpp. +2008-10-17 Badlop + + * src/Makefile.in: docdir should be prefixed with DESTDIR (thanks + to Jack Moffitt)(EJAB-775) + +2008-10-17 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: fix badarg issue on get_roster_info + when allowed roster groups is not defined + + * src/mod_pubsub/mod_pubsub.erl: fix remove_user not unsubscribing + user (EJAB-684) + + * src/mod_pubsub/node_default.erl: does not write item when max_items + set to 0 (solves EJAB-768) + +2008-10-14 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: fix pubsub_publish_item hook + ServerHost parameter (EJAB-772) + 2008-10-13 Jean-Sébastien Pédron * src/web/ejabberd_http.erl, src/web/ejabberd_http_poll.erl, @@ -49,6 +177,10 @@ * src/ejd2odbc.erl, src/jd2ejd.erl: Convert to exmpp. +2008-10-13 Jerome Sautret + + * src/odbc/ejabberd_odbc.erl: log MySQL driver messages. + 2008-10-13 Badlop * src/web/ejabberd_web_admin.erl: When requesting page of diff --git a/doc/guide.html b/doc/guide.html index c28115c21..c15a76df7 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -1928,19 +1928,18 @@ able to use the transport. The default encoding is set to "iso8859-15". ... ]}.
    • In next example the IRC transport is available with JIDs with prefix irc-t.net. -Moreover, the transport is only accessible by paying customers registered on -our domains and on other servers. -
      {acl, paying_customers, {user, "customer1", "example.net"}}.
      -{acl, paying_customers, {user, "customer2", "example.com"}}.
      -{acl, paying_customers, {user, "customer3", "example.org"}}.
      +Moreover, the transport is only accessible to two users 
      +of example.org, and any user of example.com:
      +
      {acl, paying_customers, {user, "customer1", "example.org"}}.
      +{acl, paying_customers, {user, "customer2", "example.org"}}.
      +{acl, paying_customers, {server, "example.com"}}.
       
      -{access, paying_customers, [{allow, paying_customers},
      -                              {deny, all}]}.
      +{access, irc_users, [{allow, paying_customers}, {deny, all}]}.
       
       {modules,
        [
         ...
      -  {mod_irc, [{access, paying_customers},
      +  {mod_irc, [{access, irc_users},
                    {host, "irc.example.net"}]},
         ...
        ]}.
      diff --git a/doc/guide.tex b/doc/guide.tex
      index 14cc4c627..6702880f3 100644
      --- a/doc/guide.tex
      +++ b/doc/guide.tex
      @@ -2543,20 +2543,19 @@ Examples:
        ]}.
       \end{verbatim}
       \item In next example the IRC transport is available with JIDs with prefix \jid{irc-t.net}.
      -  Moreover, the transport is only accessible by paying customers registered on
      -  our domains and on other servers.
      +  Moreover, the transport is only accessible to two users 
      +  of \term{example.org}, and any user of \term{example.com}:
       \begin{verbatim}
      -{acl, paying_customers, {user, "customer1", "example.net"}}.
      -{acl, paying_customers, {user, "customer2", "example.com"}}.
      -{acl, paying_customers, {user, "customer3", "example.org"}}.
      +{acl, paying_customers, {user, "customer1", "example.org"}}.
      +{acl, paying_customers, {user, "customer2", "example.org"}}.
      +{acl, paying_customers, {server, "example.com"}}.
       
      -{access, paying_customers, [{allow, paying_customers},
      -                              {deny, all}]}.
      +{access, irc_users, [{allow, paying_customers}, {deny, all}]}.
       
       {modules,
        [
         ...
      -  {mod_irc, [{access, paying_customers},
      +  {mod_irc, [{access, irc_users},
                    {host, "irc.example.net"}]},
         ...
        ]}.
      diff --git a/src/Makefile.in b/src/Makefile.in
      index 93d29fc60..096af8b5a 100644
      --- a/src/Makefile.in
      +++ b/src/Makefile.in
      @@ -85,7 +85,7 @@ EJABBERDDIR = $(DESTDIR)@libdir@/ejabberd
       # /share/doc/ejabberd
       PACKAGE_TARNAME = @PACKAGE_TARNAME@
       datarootdir = @datarootdir@
      -DOCDIR = @docdir@
      +DOCDIR = $(DESTDIR)@docdir@
       
       # /usr/lib/ejabberd/ebin/
       BEAMDIR = $(EJABBERDDIR)/ebin
      @@ -257,7 +257,7 @@ uninstall-all: uninstall-binary
       clean: clean-recursive clean-local
       
       clean-local:
      -	rm -f *.beam $(ERLSHLIBS) epam
      +	rm -f *.beam $(ERLSHLIBS) epam ejabberdctl.example
       	rm -f XmppAddr.asn1db XmppAddr.erl XmppAddr.hrl
       
       distclean: distclean-recursive clean-local
      diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl
      index f9bf8378c..afe700a76 100644
      --- a/src/ejabberd_app.erl
      +++ b/src/ejabberd_app.erl
      @@ -29,7 +29,7 @@
       
       -behaviour(application).
       
      --export([start_modules/0,start/2, prep_stop/1, stop/1, init/0]).
      +-export([start_modules/0,start/2, get_log_path/0, prep_stop/1, stop/1, init/0]).
       
       -include("ejabberd.hrl").
       
      @@ -45,6 +45,7 @@ start(normal, _Args) ->
           randoms:start(),
           db_init(),
           sha:start(),
      +    start(),
           translate:start(),
           acl:start(),
           ejabberd_ctl:init(),
      @@ -53,7 +54,6 @@ start(normal, _Args) ->
           gen_mod:start(),
           ejabberd_config:start(),
           ejabberd_check:config(),
      -    start(),
           connect_nodes(),
           Sup = ejabberd_sup:start_link(),
           ejabberd_rdbms:start(),
      @@ -65,12 +65,13 @@ start(normal, _Args) ->
           %fprof:trace(start, "/tmp/fprof"),
           start_modules(),
           ejabberd_listener:start_listeners(),
      +    ?INFO_MSG("ejabberd ~s is started in the node ~p", [?VERSION, node()]),
           Sup;
       start(_, _) ->
           {error, badarg}.
       
       %% Prepare the application for termination.
      -%% This function is called when an application is about to be stopped, 
      +%% This function is called when an application is about to be stopped,
       %% before shutting down the processes of the application.
       prep_stop(State) ->
           stop_modules(),
      @@ -79,6 +80,7 @@ prep_stop(State) ->
       
       %% All the processes were killed when this function is called
       stop(_State) ->
      +    ?INFO_MSG("ejabberd ~s is stopped in the node ~p", [?VERSION, node()]),
           ok.
       
       
      @@ -93,18 +95,7 @@ init() ->
           register(ejabberd, self()),
           %erlang:system_flag(fullsweep_after, 0),
           %error_logger:logfile({open, ?LOG_PATH}),
      -    LogPath =
      -	case application:get_env(log_path) of
      -            {ok, Path} ->
      -		Path;
      -	    undefined ->
      -		case os:getenv("EJABBERD_LOG_PATH") of
      -		    false ->
      -			?LOG_PATH;
      -		    Path ->
      -			Path
      -		end
      -	end,
      +    LogPath = get_log_path(),
           error_logger:add_report_handler(ejabberd_logger_h, LogPath),
           erl_ddll:load_driver(ejabberd:get_so_path(), tls_drv),
           case erl_ddll:load_driver(ejabberd:get_so_path(), expat_erl) of
      @@ -171,3 +162,21 @@ connect_nodes() ->
       			  end, Nodes)
           end.
       
      +%% @spec () -> string()
      +%% Returns the full path to the ejabberd log file.
      +%% It first checks for application configuration parameter 'log_path'.
      +%% If not defined it checks the environment variable EJABBERD_LOG_PATH.
      +%% And if that one is neither defined, returns the default value:
      +%% "ejabberd.log" in current directory.
      +get_log_path() ->
      +    case application:get_env(log_path) of
      +	{ok, Path} ->
      +	    Path;
      +	undefined ->
      +	    case os:getenv("EJABBERD_LOG_PATH") of
      +		false ->
      +		    ?LOG_PATH;
      +		Path ->
      +		    Path
      +	    end
      +    end.
      diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
      index 4c2f93a22..7fa38ae98 100644
      --- a/src/ejabberd_c2s.erl
      +++ b/src/ejabberd_c2s.erl
      @@ -63,6 +63,8 @@
       -define(SETS, gb_sets).
       -define(DICT, dict).
       
      +%% pres_a contains all the presence available send (either through roster mechanism or directed).
      +%% Directed presence unavailable remove user from pres_a.
       -record(state, {socket,
       		sockmod,
       		socket_monitor,
      @@ -170,6 +172,7 @@ init([{SockMod, Socket}, Opts]) ->
           TLSOpts = lists:filter(fun({certfile, _}) -> true;
       			      (_) -> false
       			   end, Opts),
      +    Zlib = lists:member(zlib, Opts) andalso (not StartTLSRequired),
           IP = peerip(SockMod, Socket),
           %% Check if IP is blacklisted:
           case is_ip_blacklisted(IP) of
      diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl
      index 362d12c91..328974189 100644
      --- a/src/ejabberd_ctl.erl
      +++ b/src/ejabberd_ctl.erl
      @@ -132,7 +132,10 @@ process(["status"]) ->
       	   [node(), InternalStatus, ProvidedStatus]),
           case lists:keysearch(ejabberd, 1, application:which_applications()) of
               false ->
      -            ?PRINT("ejabberd is not running in that node~n", []),
      +            EjabberdLogPath = ejabberd_app:get_log_path(),
      +            ?PRINT("ejabberd is not running in that node~n"
      +		   "Check for error messages: ~s~n"
      +		   "or other files in that directory.~n", [EjabberdLogPath]),
                   ?STATUS_ERROR;
               {value, {_, _, Version}} ->
                   ?PRINT("ejabberd ~s is running in that node~n", [Version]),
      @@ -237,7 +240,12 @@ try_run_ctp(Args) ->
           catch
       	exit:Why ->
       	    print_usage(),
      -	    {io_lib:format("Error in ejabberd ctl process: ~p", [Why]), ?STATUS_USAGE}
      +	    {io_lib:format("Error in ejabberd ctl process: ~p", [Why]), ?STATUS_USAGE};
      +	Error:Why ->
      +            %% In this case probably ejabberd is not started, so let's show Status
      +            process(["status"]),
      +            ?PRINT("~n", []),
      +	    {io_lib:format("Error in ejabberd ctl process: '~p' ~p", [Error, Why]), ?STATUS_USAGE}
           end.
       
       %% @spec (Args::[string()]) ->
      diff --git a/src/ejabberd_frontend_socket.erl b/src/ejabberd_frontend_socket.erl
      index 320968f70..df604ccc3 100644
      --- a/src/ejabberd_frontend_socket.erl
      +++ b/src/ejabberd_frontend_socket.erl
      @@ -53,6 +53,8 @@
       
       -record(state, {sockmod, socket, receiver}).
       
      +-define(HIBERNATE_TIMEOUT, 90000).
      +
       %%====================================================================
       %% API
       %%====================================================================
      @@ -93,7 +95,7 @@ start(Module, SockMod, Socket, Opts) ->
           end.
       
       starttls(FsmRef, TLSOpts) ->
      -    gen_server:call(FsmRef, {starttls, TLSOpts}),
      +    %gen_server:call(FsmRef, {starttls, TLSOpts}),
           FsmRef.
       
       starttls(FsmRef, TLSOpts, Data) ->
      @@ -136,7 +138,8 @@ sockname(FsmRef) ->
           gen_server:call(FsmRef, sockname).
       
       peername(FsmRef) ->
      -    gen_server:call(FsmRef, peername).
      +    %gen_server:call(FsmRef, peername).
      +    {ok, {{0, 0, 0, 0}, 0}}.
       
       
       %%====================================================================
      @@ -153,11 +156,12 @@ peername(FsmRef) ->
       init([Module, SockMod, Socket, Opts, Receiver]) ->
           %% TODO: monitor the receiver
           Node = ejabberd_node_groups:get_closest_node(backend),
      +    {SockMod2, Socket2} = check_starttls(SockMod, Socket, Receiver, Opts),
           {ok, Pid} =
       	rpc:call(Node, Module, start, [{?MODULE, self()}, Opts]),
           ejabberd_receiver:become_controller(Receiver, Pid),
      -    {ok, #state{sockmod = SockMod,
      -		socket = Socket,
      +    {ok, #state{sockmod = SockMod2,
      +		socket = Socket2,
       		receiver = Receiver}}.
       
       %%--------------------------------------------------------------------
      @@ -173,7 +177,8 @@ handle_call({starttls, TLSOpts}, _From, State) ->
           {ok, TLSSocket} = tls:tcp_to_tls(State#state.socket, TLSOpts),
           ejabberd_receiver:starttls(State#state.receiver, TLSSocket),
           Reply = ok,
      -    {reply, Reply, State#state{socket = TLSSocket, sockmod = tls}};
      +    {reply, Reply, State#state{socket = TLSSocket, sockmod = tls},
      +     ?HIBERNATE_TIMEOUT};
       
       handle_call({starttls, TLSOpts, Data}, _From, State) ->
           {ok, TLSSocket} = tls:tcp_to_tls(State#state.socket, TLSOpts),
      @@ -181,7 +186,8 @@ handle_call({starttls, TLSOpts, Data}, _From, State) ->
           catch (State#state.sockmod):send(
       	    State#state.socket, Data),
           Reply = ok,
      -    {reply, Reply, State#state{socket = TLSSocket, sockmod = tls}};
      +    {reply, Reply, State#state{socket = TLSSocket, sockmod = tls},
      +     ?HIBERNATE_TIMEOUT};
       
       handle_call(compress, _From, State) ->
           {ok, ZlibSocket} = ejabberd_zlib:enable_zlib(
      @@ -189,7 +195,8 @@ handle_call(compress, _From, State) ->
       			 State#state.socket),
           ejabberd_receiver:compress(State#state.receiver, ZlibSocket),
           Reply = ok,
      -    {reply, Reply, State#state{socket = ZlibSocket, sockmod = ejabberd_zlib}};
      +    {reply, Reply, State#state{socket = ZlibSocket, sockmod = ejabberd_zlib},
      +     ?HIBERNATE_TIMEOUT};
       
       handle_call({compress, Data}, _From, State) ->
           {ok, ZlibSocket} = ejabberd_zlib:enable_zlib(
      @@ -199,35 +206,36 @@ handle_call({compress, Data}, _From, State) ->
           catch (State#state.sockmod):send(
       	    State#state.socket, Data),
           Reply = ok,
      -    {reply, Reply, State#state{socket = ZlibSocket, sockmod = ejabberd_zlib}};
      +    {reply, Reply, State#state{socket = ZlibSocket, sockmod = ejabberd_zlib},
      +     ?HIBERNATE_TIMEOUT};
       
       handle_call(reset_stream, _From, State) ->
           ejabberd_receiver:reset_stream(State#state.receiver),
           Reply = ok,
      -    {reply, Reply, State};
      +    {reply, Reply, State, ?HIBERNATE_TIMEOUT};
       
       handle_call({send, Data}, _From, State) ->
           catch (State#state.sockmod):send(
       	    State#state.socket, Data),
           Reply = ok,
      -    {reply, Reply, State};
      +    {reply, Reply, State, ?HIBERNATE_TIMEOUT};
       
       handle_call({change_shaper, Shaper}, _From, State) ->
           ejabberd_receiver:change_shaper(State#state.receiver, Shaper),
           Reply = ok,
      -    {reply, Reply, State};
      +    {reply, Reply, State, ?HIBERNATE_TIMEOUT};
       
       handle_call(get_sockmod, _From, State) ->
           Reply = State#state.sockmod,
      -    {reply, Reply, State};
      +    {reply, Reply, State, ?HIBERNATE_TIMEOUT};
       
       handle_call(get_peer_certificate, _From, State) ->
           Reply = tls:get_peer_certificate(State#state.socket),
      -    {reply, Reply, State};
      +    {reply, Reply, State, ?HIBERNATE_TIMEOUT};
       
       handle_call(get_verify_result, _From, State) ->
           Reply = tls:get_verify_result(State#state.socket),
      -    {reply, Reply, State};
      +    {reply, Reply, State, ?HIBERNATE_TIMEOUT};
       
       handle_call(close, _From, State) ->
           ejabberd_receiver:close(State#state.receiver),
      @@ -243,7 +251,7 @@ handle_call(sockname, _From, State) ->
       	    _ ->
       		SockMod:sockname(Socket)
       	end,
      -    {reply, Reply, State};
      +    {reply, Reply, State, ?HIBERNATE_TIMEOUT};
       
       handle_call(peername, _From, State) ->
           #state{sockmod = SockMod, socket = Socket} = State,
      @@ -254,11 +262,11 @@ handle_call(peername, _From, State) ->
       	    _ ->
       		SockMod:peername(Socket)
       	end,
      -    {reply, Reply, State};
      +    {reply, Reply, State, ?HIBERNATE_TIMEOUT};
       
       handle_call(_Request, _From, State) ->
           Reply = ok,
      -    {reply, Reply, State}.
      +    {reply, Reply, State, ?HIBERNATE_TIMEOUT}.
       
       %%--------------------------------------------------------------------
       %% Function: handle_cast(Msg, State) -> {noreply, State} |
      @@ -267,7 +275,7 @@ handle_call(_Request, _From, State) ->
       %% Description: Handling cast messages
       %%--------------------------------------------------------------------
       handle_cast(_Msg, State) ->
      -    {noreply, State}.
      +    {noreply, State, ?HIBERNATE_TIMEOUT}.
       
       %%--------------------------------------------------------------------
       %% Function: handle_info(Info, State) -> {noreply, State} |
      @@ -275,8 +283,11 @@ handle_cast(_Msg, State) ->
       %%                                       {stop, Reason, State}
       %% Description: Handling all non call/cast messages
       %%--------------------------------------------------------------------
      +handle_info(timeout, State) ->
      +    proc_lib:hibernate(gen_server, enter_loop, [?MODULE, [], State]),
      +    {noreply, State, ?HIBERNATE_TIMEOUT};
       handle_info(_Info, State) ->
      -    {noreply, State}.
      +    {noreply, State, ?HIBERNATE_TIMEOUT}.
       
       %%--------------------------------------------------------------------
       %% Function: terminate(Reason, State) -> void()
      @@ -298,3 +309,17 @@ code_change(_OldVsn, State, _Extra) ->
       %%--------------------------------------------------------------------
       %%% Internal functions
       %%--------------------------------------------------------------------
      +check_starttls(SockMod, Socket, Receiver, Opts) ->
      +    TLSEnabled = lists:member(tls, Opts),
      +    TLSOpts = lists:filter(fun({certfile, _}) -> true;
      +			      (_) -> false
      +			   end, Opts),
      +    if
      +	TLSEnabled ->
      +	    {ok, TLSSocket} = tls:tcp_to_tls(Socket, TLSOpts),
      +	    ejabberd_receiver:starttls(Receiver, TLSSocket),
      +	    {tls, TLSSocket};
      +	true ->
      +	    {SockMod, Socket}
      +    end.
      +
      diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl
      index b3753cc84..9c46f6d4c 100644
      --- a/src/ejabberd_listener.erl
      +++ b/src/ejabberd_listener.erl
      @@ -58,8 +58,9 @@ start_listeners() ->
       
       start(Port, Module, Opts) ->
           %% Check if the module is an ejabberd listener or an independent listener
      -    case Module:socket_type() of
      -	independent -> Module:start_listener(Port, Opts);
      +    ModuleRaw = strip_frontend(Module),
      +    case ModuleRaw:socket_type() of
      +	independent -> ModuleRaw:start_listener(Port, Opts);
       	_ -> start_dependent(Port, Module, Opts)
           end.
       
      @@ -120,12 +121,11 @@ accept(ListenSocket, Module, Opts) ->
       		_ ->
       		    ok
       	    end,
      -	    case Module of
      -		{frontend, Mod} ->
      -		    ejabberd_frontend_socket:start(Mod, gen_tcp, Socket, Opts);
      -		_ ->
      -		    ejabberd_socket:start(Module, gen_tcp, Socket, Opts)
      -	    end,
      +	    CallMod = case is_frontend(Module) of
      +			  true -> ejabberd_frontend_socket;
      +			  false -> ejabberd_socket
      +		      end,
      +	    CallMod:start(strip_frontend(Module), gen_tcp, Socket, Opts),
       	    accept(ListenSocket, Module, Opts);
       	{error, Reason} ->
       	    ?INFO_MSG("(~w) Failed TCP accept: ~w",
      @@ -137,11 +137,12 @@ start_listener(Port, Module, Opts) ->
           start_module_sup(Port, Module),
           start_listener_sup(Port, Module, Opts).
       
      +%% Only required for some listeners, but doing for all doesn't hurt
       start_module_sup(_Port, Module) ->
           Proc1 = gen_mod:get_module_proc("sup", Module),
           ChildSpec1 =
       	{Proc1,
      -	 {ejabberd_tmp_sup, start_link, [Proc1, Module]},
      +	 {ejabberd_tmp_sup, start_link, [Proc1, strip_frontend(Module)]},
       	 permanent,
       	 infinity,
       	 supervisor,
      @@ -188,3 +189,10 @@ delete_listener(Port, Module) ->
           ejabberd_config:add_local_option(listen, Ports1),
           stop_listener(Port, Module).
       
      +is_frontend({frontend, _Module}) -> true;
      +is_frontend(_) -> false.
      +
      +%% @doc(FrontMod) -> atom()
      +%% where FrontMod = atom() | {frontend, atom()}
      +strip_frontend({frontend, Module}) -> Module;
      +strip_frontend(Module) when is_atom(Module) -> Module.
      diff --git a/src/ejabberd_receiver.erl b/src/ejabberd_receiver.erl
      index adf2634a0..37cf38b98 100644
      --- a/src/ejabberd_receiver.erl
      +++ b/src/ejabberd_receiver.erl
      @@ -54,6 +54,8 @@
       		xml_stream_state,
       		timeout}).
       
      +-define(HIBERNATE_TIMEOUT, 90000).
      +
       %%====================================================================
       %% API
       %%====================================================================
      @@ -138,7 +140,7 @@ handle_call({starttls, TLSSocket}, _From,
       			   xml_stream_state = NewXMLStreamState},
           case tls:recv_data(TLSSocket, "") of
       	{ok, TLSData} ->
      -	    {reply, ok, process_data(TLSData, NewState)};
      +	    {reply, ok, process_data(TLSData, NewState), ?HIBERNATE_TIMEOUT};
       	{error, _Reason} ->
       	    {stop, normal, ok, NewState}
           end;
      @@ -150,7 +152,7 @@ handle_call({compress, ZlibSocket}, _From,
       			   xml_stream_state = NewXMLStreamState},
           case ejabberd_zlib:recv_data(ZlibSocket, "") of
       	{ok, ZlibData} ->
      -	    {reply, ok, process_data(ZlibData, NewState)};
      +	    {reply, ok, process_data(ZlibData, NewState), ?HIBERNATE_TIMEOUT};
       	{error, _Reason} ->
       	    {stop, normal, ok, NewState}
           end;
      @@ -158,7 +160,8 @@ handle_call(reset_stream, _From,
       	    #state{xml_stream_state = XMLStreamState} = State) ->
           NewXMLStreamState = exmpp_xmlstream:reset(XMLStreamState),
           Reply = ok,
      -    {reply, Reply, State#state{xml_stream_state = NewXMLStreamState}};
      +    {reply, Reply, State#state{xml_stream_state = NewXMLStreamState},
      +     ?HIBERNATE_TIMEOUT};
       handle_call({become_controller, C2SPid}, _From, State) ->
           Parser = exmpp_xml:start_parser([
             {namespace, true},
      @@ -174,10 +177,10 @@ handle_call({become_controller, C2SPid}, _From, State) ->
       			   xml_stream_state = XMLStreamState},
           activate_socket(NewState),
           Reply = ok,
      -    {reply, Reply, NewState};
      +    {reply, Reply, NewState, ?HIBERNATE_TIMEOUT};
       handle_call(_Request, _From, State) ->
           Reply = ok,
      -    {reply, Reply, State}.
      +    {reply, Reply, State, ?HIBERNATE_TIMEOUT}.
       
       %%--------------------------------------------------------------------
       %% Function: handle_cast(Msg, State) -> {noreply, State} |
      @@ -187,11 +190,11 @@ handle_call(_Request, _From, State) ->
       %%--------------------------------------------------------------------
       handle_cast({change_shaper, Shaper}, State) ->
           NewShaperState = shaper:new(Shaper),
      -    {noreply, State#state{shaper_state = NewShaperState}};
      +    {noreply, State#state{shaper_state = NewShaperState}, ?HIBERNATE_TIMEOUT};
       handle_cast(close, State) ->
           {stop, normal, State};
       handle_cast(_Msg, State) ->
      -    {noreply, State}.
      +    {noreply, State, ?HIBERNATE_TIMEOUT}.
       
       %%--------------------------------------------------------------------
       %% Function: handle_info(Info, State) -> {noreply, State} |
      @@ -207,19 +210,21 @@ handle_info({Tag, _TCPSocket, Data},
       	tls ->
       	    case tls:recv_data(Socket, Data) of
       		{ok, TLSData} ->
      -		    {noreply, process_data(TLSData, State)};
      +		    {noreply, process_data(TLSData, State),
      +		     ?HIBERNATE_TIMEOUT};
       		{error, _Reason} ->
       		    {stop, normal, State}
       	    end;
       	ejabberd_zlib ->
       	    case ejabberd_zlib:recv_data(Socket, Data) of
       		{ok, ZlibData} ->
      -		    {noreply, process_data(ZlibData, State)};
      +		    {noreply, process_data(ZlibData, State),
      +		     ?HIBERNATE_TIMEOUT};
       		{error, _Reason} ->
       		    {stop, normal, State}
       	    end;
       	_ ->
      -	    {noreply, process_data(Data, State)}
      +	    {noreply, process_data(Data, State), ?HIBERNATE_TIMEOUT}
           end;
       handle_info({Tag, _TCPSocket}, State)
         when (Tag == tcp_closed) or (Tag == ssl_closed) ->
      @@ -228,15 +233,18 @@ handle_info({Tag, _TCPSocket, Reason}, State)
         when (Tag == tcp_error) or (Tag == ssl_error) ->
           case Reason of
       	timeout ->
      -	    {noreply, State};
      +	    {noreply, State, ?HIBERNATE_TIMEOUT};
       	_ ->
       	    {stop, normal, State}
           end;
       handle_info({timeout, _Ref, activate}, State) ->
           activate_socket(State),
      -    {noreply, State};
      +    {noreply, State, ?HIBERNATE_TIMEOUT};
      +handle_info(timeout, State) ->
      +    proc_lib:hibernate(gen_server, enter_loop, [?MODULE, [], State]),
      +    {noreply, State, ?HIBERNATE_TIMEOUT};
       handle_info(_Info, State) ->
      -    {noreply, State}.
      +    {noreply, State, ?HIBERNATE_TIMEOUT}.
       
       %%--------------------------------------------------------------------
       %% Function: terminate(Reason, State) -> void()
      diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl
      index b73336245..88f2e8aad 100644
      --- a/src/ejabberd_s2s_out.erl
      +++ b/src/ejabberd_s2s_out.erl
      @@ -52,7 +52,8 @@
       	 handle_info/3,
       	 terminate/3,
       	 code_change/4,
      -	 test_get_addr_port/1]).
      +	 test_get_addr_port/1,
      +	 get_addr_port/1]).
       
       -include_lib("exmpp/include/exmpp.hrl").
       
      diff --git a/src/ejabberd_sup.erl b/src/ejabberd_sup.erl
      index 8475e2592..01efbfd76 100644
      --- a/src/ejabberd_sup.erl
      +++ b/src/ejabberd_sup.erl
      @@ -99,6 +99,21 @@ init([]) ->
       	 infinity,
       	 supervisor,
       	 [ejabberd_tmp_sup]},
      +    C2SSupervisor =
      +	{ejabberd_c2s_sup,
      +	 {ejabberd_tmp_sup, start_link, [ejabberd_c2s_sup, ejabberd_c2s]},
      +	 permanent,
      +	 infinity,
      +	 supervisor,
      +	 [ejabberd_tmp_sup]},
      +    S2SInSupervisor =
      +	{ejabberd_s2s_in_sup,
      +	 {ejabberd_tmp_sup, start_link,
      +	  [ejabberd_s2s_in_sup, ejabberd_s2s_in]},
      +	 permanent,
      +	 infinity,
      +	 supervisor,
      +	 [ejabberd_tmp_sup]},
           S2SOutSupervisor =
       	{ejabberd_s2s_out_sup,
       	 {ejabberd_tmp_sup, start_link,
      @@ -115,6 +130,14 @@ init([]) ->
       	 infinity,
       	 supervisor,
       	 [ejabberd_tmp_sup]},
      +    HTTPSupervisor =
      +	{ejabberd_http_sup,
      +	 {ejabberd_tmp_sup, start_link,
      +	  [ejabberd_http_sup, ejabberd_http]},
      +	 permanent,
      +	 infinity,
      +	 supervisor,
      +	 [ejabberd_tmp_sup]},
           HTTPPollSupervisor =
       	{ejabberd_http_poll_sup,
       	 {ejabberd_tmp_sup, start_link,
      @@ -148,8 +171,11 @@ init([]) ->
       	   S2S,
       	   Local,
       	   ReceiverSupervisor,
      +	   C2SSupervisor,
      +	   S2SInSupervisor,
       	   S2SOutSupervisor,
       	   ServiceSupervisor,
      +	   HTTPSupervisor,
       	   HTTPPollSupervisor,
       	   IQSupervisor,
       	   FrontendSocketSupervisor,
      diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template
      index 15e252cdf..b71531c19 100644
      --- a/src/ejabberdctl.template
      +++ b/src/ejabberdctl.template
      @@ -13,14 +13,6 @@ HOST=localhost
       ERLANG_NODE=$NODE@$HOST
       ERL=@erl@
       INSTALLUSER=@installuser@
      -ETCDIR=@SYSCONFDIR@/ejabberd
      -EJABBERD_CONFIG_PATH=$ETCDIR/ejabberd.cfg
      -LOGS_DIR=@LOCALSTATEDIR@/log/ejabberd
      -SPOOLDIR=@LOCALSTATEDIR@/lib/ejabberd
      -
      -# read custom configuration
      -EJABBERDCTL_CONFIG_PATH=$ETCDIR/ejabberdctl.cfg
      -[ -f "$EJABBERDCTL_CONFIG_PATH" ] && . "$EJABBERDCTL_CONFIG_PATH"
       
       # parse command line parameters
       ARGS=
      @@ -30,6 +22,7 @@ while [ $# -ne 0 ] ; do
           case $PARAM in
               --) break ;;
               --node) ERLANG_NODE=$1; shift ;;
      +        --config-dir) ETCDIR=$1 ; shift ;;
               --config) EJABBERD_CONFIG_PATH=$1 ; shift ;;
               --ctl-config) EJABBERDCTL_CONFIG_PATH=$1 ; shift ;;
               --logs) LOGS_DIR=$1 ; shift ;;
      @@ -38,6 +31,24 @@ while [ $# -ne 0 ] ; do
           esac
       done
       
      +# Define ejabberd variable if they have not been defined from the command line
      +if [ "$ETCDIR" = "" ] ; then
      +    ETCDIR=@SYSCONFDIR@/ejabberd
      +fi
      +if [ "$EJABBERD_CONFIG_PATH" = "" ] ; then
      +    EJABBERD_CONFIG_PATH=$ETCDIR/ejabberd.cfg
      +fi
      +if [ "$EJABBERDCTL_CONFIG_PATH" = "" ] ; then
      +    EJABBERDCTL_CONFIG_PATH=$ETCDIR/ejabberdctl.cfg
      +fi
      +[ -f "$EJABBERDCTL_CONFIG_PATH" ] && . "$EJABBERDCTL_CONFIG_PATH"
      +if [ "$LOGS_DIR" = "" ] ; then
      +    LOGS_DIR=@LOCALSTATEDIR@/log/ejabberd
      +fi
      +if [ "$SPOOLDIR" = "" ] ; then
      +    SPOOLDIR=@LOCALSTATEDIR@/lib/ejabberd
      +fi
      +
       # check the proper system user is used
       ID=`id -g`
       EJID=`id -g $INSTALLUSER`
      @@ -172,6 +183,7 @@ help ()
           echo "  live   Start an ejabberd node in live (interactive) mode"
           echo ""
           echo "Optional parameters when starting an ejabberd node:"
      +    echo "  --config-dir dir   Config ejabberd:    $ETCDIR"
           echo "  --config file      Config ejabberd:    $EJABBERD_CONFIG_PATH"
           echo "  --ctl-config file  Config ejabberdctl: $EJABBERDCTL_CONFIG_PATH"
           echo "  --logs dir         Directory for logs: $LOGS_DIR"
      diff --git a/src/eldap/Makefile.in b/src/eldap/Makefile.in
      index 22cdad48b..50794018c 100644
      --- a/src/eldap/Makefile.in
      +++ b/src/eldap/Makefile.in
      @@ -6,6 +6,8 @@ CPPFLAGS = @CPPFLAGS@
       LDFLAGS = @LDFLAGS@
       LIBS = @LIBS@
       
      +ASN_FLAGS = -bber_bin +optimize +driver
      +
       ERLANG_CFLAGS = @ERLANG_CFLAGS@
       ERLANG_LIBS = @ERLANG_LIBS@
       
      @@ -27,7 +29,7 @@ all:    $(BEAMS) ELDAPv3.beam
       ELDAPv3.beam: ELDAPv3.erl
       
       ELDAPv3.erl:       ELDAPv3.asn
      -	@ERLC@ -bber_bin -W $(EFLAGS) $<
      +	@ERLC@ $(ASN_FLAGS) -W $(EFLAGS) $<
       
       $(OUTDIR)/%.beam:	%.erl ELDAPv3.erl
       	@ERLC@ -W $(EFLAGS) -o $(OUTDIR) $<
      diff --git a/src/eldap/Makefile.win32 b/src/eldap/Makefile.win32
      index 9733055f9..396880a86 100644
      --- a/src/eldap/Makefile.win32
      +++ b/src/eldap/Makefile.win32
      @@ -6,6 +6,8 @@ EFLAGS = -I .. -pz ..
       OUTDIR = ..
       BEAMS = ..\eldap.beam ..\eldap_filter.beam ..\eldap_pool.beam ..\eldap_utils.beam
       
      +ASN_FLAGS = -bber_bin +optimize +driver
      +
       ALL : $(BEAMS)
       
       Clean :
      @@ -16,7 +18,7 @@ Clean :
       	-@erase $(BEAMS)
       
       ELDAPv3.erl : ELDAPv3.asn
      -	erlc -bber_bin -W $(EFLAGS) ELDAPv3.asn
      +	erlc $(ASN_FLAGS) -W $(EFLAGS) ELDAPv3.asn
       
       $(OUTDIR)\eldap.beam : eldap.erl ELDAPv3.erl
       	erlc -W $(EFLAGS) -o $(OUTDIR) eldap.erl
      diff --git a/src/extauth.erl b/src/extauth.erl
      index 86445ec1b..9a239d732 100644
      --- a/src/extauth.erl
      +++ b/src/extauth.erl
      @@ -32,7 +32,8 @@
       
       -include("ejabberd.hrl").
       
      --define(CALL_TIMEOUT, 30000). % Timeout is in milliseconds: 30 seconds == 30000
      +-define(INIT_TIMEOUT, 60000). % Timeout is in milliseconds: 60 seconds == 60000
      +-define(CALL_TIMEOUT, 10000). % Timeout is in milliseconds: 10 seconds == 10000
       
       start(Host, ExtPrg) ->
           spawn(?MODULE, init, [Host, ExtPrg]).
      @@ -41,7 +42,7 @@ init(Host, ExtPrg) ->
           register(gen_mod:get_module_proc(Host, eauth), self()),
           process_flag(trap_exit,true),
           Port = open_port({spawn, ExtPrg}, [{packet,2}]),
      -    loop(Port).
      +    loop(Port, ?INIT_TIMEOUT).
       
       stop(Host) ->
           gen_mod:get_module_proc(Host, eauth) ! stop.
      @@ -63,21 +64,23 @@ call_port(Server, Msg) ->
       	    Result
           end.
       
      -loop(Port) ->
      +loop(Port, Timeout) ->
           receive
       	{call, Caller, Msg} ->
       	    Port ! {self(), {command, encode(Msg)}},
       	    receive
       		{Port, {data, Data}} ->
                           ?DEBUG("extauth call '~p' received data response:~n~p", [Msg, Data]),
      -		    Caller ! {eauth, decode(Data)};
      -                {Port, Other} ->
      -                    ?ERROR_MSG("extauth call '~p' received strange response:~n~p", [Msg, Other])
      +                    Caller ! {eauth, decode(Data)};
      +		{Port, Other} ->
      +                    ?ERROR_MSG("extauth call '~p' received strange response:~n~p", [Msg, Other]),
      +                    Caller ! {eauth, false}
                   after
      -                ?CALL_TIMEOUT ->
      -                    ?ERROR_MSG("extauth call '~p' didn't receive response~n", [Msg])
      +                Timeout ->
      +                    ?ERROR_MSG("extauth call '~p' didn't receive response", [Msg]),
      +                    Caller ! {eauth, false}
       	    end,
      -	    loop(Port);
      +	    loop(Port, ?CALL_TIMEOUT);
       	stop ->
       	    Port ! {self(), close},
       	    receive
      diff --git a/src/gen_mod.erl b/src/gen_mod.erl
      index bbc4e860d..49f4991a7 100644
      --- a/src/gen_mod.erl
      +++ b/src/gen_mod.erl
      @@ -62,14 +62,16 @@ start() ->
       
       
       start_module(Host, Module, Opts) ->
      +    set_module_opts_mnesia(Host, Module, Opts),
      +    ets:insert(ejabberd_modules,
      +	       #ejabberd_module{module_host = {Module, Host},
      +				opts = Opts}),
           case catch Module:start(Host, Opts) of
       	{'EXIT', Reason} ->
      +	    del_module_mnesia(Host, Module),
      +	    ets:delete(ejabberd_modules, {Module, Host}),
       	    ?ERROR_MSG("~p", [Reason]);
       	_ ->
      -	    set_module_opts_mnesia(Host, Module, Opts),
      -	    ets:insert(ejabberd_modules,
      -		       #ejabberd_module{module_host = {Module, Host},
      -					opts = Opts}),
       	    ok
           end.
       
      @@ -224,6 +226,8 @@ get_hosts(Opts, Prefix) ->
       	    Hosts
           end.
       
      +get_module_proc(Host, {frontend, Base}) ->
      +    get_module_proc("frontend_" ++ Host, Base);
       get_module_proc(Host, Base) ->
           list_to_atom(atom_to_list(Base) ++ "_" ++ Host).
       
      diff --git a/src/mod_irc/mod_irc.erl b/src/mod_irc/mod_irc.erl
      index 3ef7f8ca5..2f2e37780 100644
      --- a/src/mod_irc/mod_irc.erl
      +++ b/src/mod_irc/mod_irc.erl
      @@ -305,6 +305,8 @@ iq_disco(Lang) ->
             [#xmlattr{name = 'category', value = "conference"},
              #xmlattr{name = 'type', value = "irc"},
              #xmlattr{name = 'name', value = translate:translate(Lang, "IRC Transport")}]},
      +     #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs =
      +      [#xmlattr{name = 'var', value = ?NS_DISCO_INFO_s}]},
            #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs =
             [#xmlattr{name = 'var', value = ?NS_MUC_s}]},
            #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs =
      diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl
      index e83bedeba..57232f994 100644
      --- a/src/mod_muc/mod_muc.erl
      +++ b/src/mod_muc/mod_muc.erl
      @@ -499,6 +499,12 @@ iq_disco_info(Lang) ->
                                    value = "text"},
                           #xmlattr{name = 'name', 
                                    value = translate:translate(Lang, "Chatrooms")}]},
      +     #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = 
      +                              [#xmlattr{name = 'var', 
      +                                       value = ?NS_DISCO_INFO_s}]},
      +     #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = 
      +                              [#xmlattr{name = 'var', 
      +                                       value = ?NS_DISCO_ITEMS_s}]},
            #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = 
                                     [#xmlattr{name = 'var', 
                                              value = ?NS_MUC_s}]},
      diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl
      index 8982cd832..6096375fd 100644
      --- a/src/mod_muc/mod_muc_room.erl
      +++ b/src/mod_muc/mod_muc_room.erl
      @@ -104,7 +104,7 @@
       		subject = "",
       		subject_author = "",
       		just_created = false,
      -		activity = ?DICT:new(),
      +		activity = treap:empty(),
       		room_shaper,
       		room_queue = queue:new()}).
       
      @@ -251,13 +251,12 @@ normal_state({route, From, undefined,
       						    message_time = Now,
       						    message_shaper = MessageShaper},
       				    StateData1 =
      -					StateData#state{
      -					  activity = ?DICT:store(
      -							jlib:short_prepd_jid(From),
      -							NewActivity,
      -							StateData#state.activity),
      +					store_user_activity(
      +					  From, NewActivity, StateData),
      +				    StateData2 =
      +					StateData1#state{
       					  room_shaper = RoomShaper},
      -				    process_groupchat_message(From, Packet, StateData1);
      +				    process_groupchat_message(From, Packet, StateData2);
       				true ->
       				    StateData1 =
       					if
      @@ -278,13 +277,12 @@ normal_state({route, From, undefined,
       						  {message, From},
       						  StateData#state.room_queue),
       				    StateData2 =
      -					StateData1#state{
      -					  activity = ?DICT:store(
      -							jlib:short_prepd_jid(From),
      -							NewActivity,
      -							StateData#state.activity),
      +					store_user_activity(
      +					  From, NewActivity, StateData1),
      +				    StateData3 =
      +					StateData2#state{
       					  room_queue = RoomQueue},
      -				    {next_state, normal_state, StateData2}
      +				    {next_state, normal_state, StateData3}
       			    end;
       			true ->
       			    MessageInterval =
      @@ -298,11 +296,8 @@ normal_state({route, From, undefined,
       					    message = Packet,
       					    message_shaper = MessageShaper},
       			    StateData1 =
      -				StateData#state{
      -				  activity = ?DICT:store(
      -						jlib:short_prepd_jid(From),
      -						NewActivity,
      -						StateData#state.activity)},
      +				store_user_activity(
      +				  From, NewActivity, StateData),
       			    {next_state, normal_state, StateData1}
       		    end;
       		error ->
      @@ -444,12 +439,7 @@ normal_state({route, From, Nick,
       	(Now >= Activity#activity.presence_time + MinPresenceInterval) and
       	(Activity#activity.presence == undefined) ->
       	    NewActivity = Activity#activity{presence_time = Now},
      -	    StateData1 =
      -		StateData#state{
      -		  activity = ?DICT:store(
      -				jlib:short_prepd_jid(From),
      -				NewActivity,
      -				StateData#state.activity)},
      +	    StateData1 = store_user_activity(From, NewActivity, StateData),
       	    process_presence(From, Nick, Packet, StateData1);
       	true ->
       	    if
      @@ -462,12 +452,7 @@ normal_state({route, From, Nick,
       		    ok
       	    end,
       	    NewActivity = Activity#activity{presence = {Nick, Packet}},
      -	    StateData1 =
      -		StateData#state{
      -		  activity = ?DICT:store(
      -				jlib:short_prepd_jid(From),
      -				NewActivity,
      -				StateData#state.activity)},
      +	    StateData1 = store_user_activity(From, NewActivity, StateData),
       	    {next_state, normal_state, StateData1}
           end;
       
      @@ -758,27 +743,25 @@ handle_info(process_room_queue, normal_state = StateName, StateData) ->
       	    Packet = Activity#activity.message,
       	    NewActivity = Activity#activity{message = undefined},
       	    StateData1 =
      -		StateData#state{
      -		  activity = ?DICT:store(
      -				jlib:short_prepd_jid(From),
      -				NewActivity,
      -				StateData#state.activity),
      +		store_user_activity(
      +		  From, NewActivity, StateData),
      +	    StateData2 =
      +		StateData1#state{
       		  room_queue = RoomQueue},
      -	    StateData2 = prepare_room_queue(StateData1),
      -	    process_groupchat_message(From, Packet, StateData2);
      +	    StateData3 = prepare_room_queue(StateData2),
      +	    process_groupchat_message(From, Packet, StateData3);
       	{{value, {presence, From}}, RoomQueue} ->
       	    Activity = get_user_activity(From, StateData),
       	    {Nick, Packet} = Activity#activity.presence,
       	    NewActivity = Activity#activity{presence = undefined},
       	    StateData1 =
      -		StateData#state{
      -		  activity = ?DICT:store(
      -				jlib:short_prepd_jid(From),
      -				NewActivity,
      -				StateData#state.activity),
      +		store_user_activity(
      +		  From, NewActivity, StateData),
      +	    StateData2 =
      +		StateData1#state{
       		  room_queue = RoomQueue},
      -	    StateData2 = prepare_room_queue(StateData1),
      -	    process_presence(From, Nick, Packet, StateData2);
      +	    StateData3 = prepare_room_queue(StateData2),
      +	    process_presence(From, Nick, Packet, StateData3);
       	{empty, _} ->
       	    {next_state, StateName, StateData}
           end;
      @@ -1301,9 +1284,9 @@ get_max_users_admin_threshold(StateData) ->
       			   mod_muc, max_users_admin_threshold, 5).
       
       get_user_activity(JID, StateData) ->
      -    case ?DICT:find(jlib:short_prepd_jid(JID),
      -		    StateData#state.activity) of
      -	{ok, A} -> A;
      +    case treap:lookup(jlib:short_prepd_jid(JID),
      +		      StateData#state.activity) of
      +	{ok, _P, A} -> A;
       	error ->
       	    MessageShaper =
       		shaper:new(gen_mod:get_module_opt(
      @@ -1317,6 +1300,82 @@ get_user_activity(JID, StateData) ->
       		      presence_shaper = PresenceShaper}
           end.
       
      +store_user_activity(JID, UserActivity, StateData) ->
      +    MinMessageInterval =
      +	gen_mod:get_module_opt(
      +	  StateData#state.server_host,
      +	  mod_muc, min_message_interval, 0),
      +    MinPresenceInterval =
      +	gen_mod:get_module_opt(
      +	  StateData#state.server_host,
      +	  mod_muc, min_presence_interval, 0),
      +    Key = jlib:short_prepd_jid(JID),
      +    Now = now_to_usec(now()),
      +    Activity1 = clean_treap(StateData#state.activity, {1, -Now}),
      +    Activity =
      +	case treap:lookup(Key, Activity1) of
      +	    {ok, _P, _A} ->
      +		treap:delete(Key, Activity1);
      +	    error ->
      +		Activity1
      +	end,
      +    StateData1 =
      +	case (MinMessageInterval == 0) andalso
      +	    (MinPresenceInterval == 0) andalso
      +	    (UserActivity#activity.message_shaper == none) andalso
      +	    (UserActivity#activity.presence_shaper == none) andalso
      +	    (UserActivity#activity.message == undefined) andalso
      +	    (UserActivity#activity.presence == undefined) of
      +	    true ->
      +		StateData#state{activity = Activity};
      +	    false ->
      +		case (UserActivity#activity.message == undefined) andalso
      +		    (UserActivity#activity.presence == undefined) of
      +		    true ->
      +			{_, MessageShaperInterval} =
      +			    shaper:update(UserActivity#activity.message_shaper,
      +					  100000),
      +			{_, PresenceShaperInterval} =
      +			    shaper:update(UserActivity#activity.presence_shaper,
      +					  100000),
      +			Delay = lists:max([MessageShaperInterval,
      +					   PresenceShaperInterval,
      +					   MinMessageInterval * 1000,
      +					   MinPresenceInterval * 1000]) * 1000,
      +			Priority = {1, -(Now + Delay)},
      +			StateData#state{
      +			  activity = treap:insert(
      +				       Key,
      +				       Priority,
      +				       UserActivity,
      +				       Activity)};
      +		    false ->
      +			Priority = {0, 0},
      +			StateData#state{
      +			  activity = treap:insert(
      +				       Key,
      +				       Priority,
      +				       UserActivity,
      +				       Activity)}
      +		end
      +	end,
      +    StateData1.
      +
      +clean_treap(Treap, CleanPriority) ->
      +    case treap:is_empty(Treap) of
      +	true ->
      +	    Treap;
      +	false ->
      +	    {_Key, Priority, _Value} = treap:get_root(Treap),
      +	    if
      +		Priority > CleanPriority ->
      +		    clean_treap(treap:delete_root(Treap), CleanPriority);
      +		true ->
      +		    Treap
      +	    end
      +    end.
      +
      +
       prepare_room_queue(StateData) ->
           case queue:out(StateData#state.room_queue) of
       	{{value, {message, From}}, _RoomQueue} ->
      @@ -2700,10 +2759,23 @@ check_allowed_persistent_change(XEl, StateData, From) ->
       -define(PRIVATEXFIELD(Label, Var, Val),
       	?XFIELD("text-private", Label, Var, Val)).
       
      +
      +get_default_room_maxusers(RoomState) ->
      +    DefRoomOpts = gen_mod:get_module_opt(RoomState#state.server_host, mod_muc, default_room_options, ?MAX_USERS_DEFAULT),
      +    RoomState2 = set_opts(DefRoomOpts, RoomState),
      +    (RoomState2#state.config)#config.max_users.
      +
       get_config(Lang, StateData, From) ->
           {_AccessRoute, _AccessCreate, _AccessAdmin, AccessPersistent} = StateData#state.access,
           ServiceMaxUsers = get_service_max_users(StateData),
      +    DefaultRoomMaxUsers = get_default_room_maxusers(StateData),
           Config = StateData#state.config,
      +    {MaxUsersRoomInteger, MaxUsersRoomString} =
      +	case get_max_users(StateData) of
      +	    N when is_integer(N) ->
      +		{N, erlang:integer_to_list(N)};
      +	    _ -> {0, "none"}
      +	end,
           Res =
       	[#xmlel{name = 'title', children = [ #xmlcdata{cdata =
                       translate:translate(Lang, "Configuration for ") ++
      @@ -2750,11 +2822,7 @@ get_config(Lang, StateData, From) ->
                       #xmlattr{name = 'var', value = "muc#roomconfig_maxusers"}],
                   children = [#xmlel{name = 'value',
                                      children = [#xmlcdata{cdata = 
      -                                case get_max_users(StateData) of
      -                                    N when is_integer(N) ->
      -                                        erlang:integer_to_list(N);
      -                                    _ -> "none"
      -                                end}]}] ++
      +                                MaxUsersRoomString}]}] ++
       	  if
       	      is_integer(ServiceMaxUsers) -> [];
       	      true ->
      @@ -2767,7 +2835,8 @@ get_config(Lang, StateData, From) ->
                                           value = erlang:integer_to_list(N)}],
                     children = [#xmlel{name = 'value', children = [
                       #xmlcdata{cdata = erlang:integer_to_list(N)}]}]} ||
      -              N <- ?MAX_USERS_DEFAULT_LIST, N =< ServiceMaxUsers]}, 
      +              N <- lists:usort([ServiceMaxUsers, DefaultRoomMaxUsers, MaxUsersRoomInteger |
      +                               ?MAX_USERS_DEFAULT_LIST]), N =< ServiceMaxUsers]}, 
           #xmlel{name = 'field', attrs = [
                       #xmlattr{name = 'type', value = "list-single"},
                       #xmlattr{name = 'label', 
      diff --git a/src/mod_proxy65/mod_proxy65_service.erl b/src/mod_proxy65/mod_proxy65_service.erl
      index 2b252c122..23f41d4ef 100644
      --- a/src/mod_proxy65/mod_proxy65_service.erl
      +++ b/src/mod_proxy65/mod_proxy65_service.erl
      @@ -196,7 +196,6 @@ iq_disco_info(Lang, Name) ->
              {"type", "bytestreams"},
              {"name", translate:translate(Lang, Name)}], []},
            ?FEATURE(?NS_DISCO_INFO),
      -     ?FEATURE(?NS_DISCO_ITEMS),
            ?FEATURE(?NS_VCARD),
            ?FEATURE(?NS_BYTESTREAMS)].
       
      diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl
      index f140d6e9d..a1d6febf2 100644
      --- a/src/mod_pubsub/mod_pubsub.erl
      +++ b/src/mod_pubsub/mod_pubsub.erl
      @@ -496,7 +496,7 @@ handle_cast({presence, JID, Pid}, State) ->
       					    whitelist -> false; % subscribers are added manually
       					    authorize -> false; % likewise
       					    roster ->
      -						Grps = get_option(Options, roster_groups_allowed),
      +						Grps = get_option(Options, roster_groups_allowed, []),
       						element(2, get_roster_info(User, Server, LJID, Grps))
       					end,
       					if Subscribed ->
      @@ -518,8 +518,9 @@ handle_cast({presence, JID, Pid}, State) ->
           end,
           {noreply, State};
       
      -handle_cast({remove_user, User, Host}, State) ->
      -    Owner = jlib:make_jid(User, Host, ""),
      +handle_cast({remove_user, LUser, LServer}, State) ->
      +    Host = State#state.host,
      +    Owner = jlib:make_jid(LUser, LServer, ""),
           OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
           %% remove user's subscriptions
           lists:foreach(fun(Type) ->
      @@ -537,7 +538,7 @@ handle_cast({remove_user, User, Host}, State) ->
       	delete_node(NodeKey, NodeName, Owner)
           end, tree_action(Host, get_nodes, [OwnerKey])),
           %% remove user's nodes
      -    delete_node(Host, ["home", Host, User], Owner),
      +    delete_node(Host, ["home", LServer, LUser], Owner),
           {noreply, State}; 
       
       handle_cast(_Msg, State) ->
      @@ -759,6 +760,8 @@ iq_disco_info(Host, SNode, From, Lang) ->
       	       [{"category", "pubsub"},
       		{"type", "service"},
       		{"name", translate:translate(Lang, "Publish-Subscribe")}], []},
      +	      {xmlelement, "feature", [{"var", ?NS_DISCO_INFO}], []},
      +	      {xmlelement, "feature", [{"var", ?NS_DISCO_ITEMS}], []},
       	      {xmlelement, "feature", [{"var", ?NS_PUBSUB}], []},
       	      {xmlelement, "feature", [{"var", ?NS_VCARD}], []}] ++
       	     lists:map(fun(Feature) ->
      @@ -1349,7 +1352,7 @@ subscribe_node(Host, Node, From, JID) ->
       		     SubscribeConfig = get_option(Options, subscribe),
       		     AccessModel = get_option(Options, access_model),
       		     SendLast = get_option(Options, send_last_published_item),
      -		     AllowedGroups = get_option(Options, roster_groups_allowed),
      +		     AllowedGroups = get_option(Options, roster_groups_allowed, []),
       		     {PresenceSubscription, RosterGroup} =
       			 case Host of
       			     {OUser, OServer, _} ->
      @@ -1486,7 +1489,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
       			     node_call(Type, publish_item, [Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload])
       		     end
       	     end,
      -    ejabberd_hooks:run(pubsub_publish_item, Host, [Host, Node, Publisher, service_jid(Host), ItemId, Payload]),
      +    ejabberd_hooks:run(pubsub_publish_item, ServerHost, [ServerHost, Node, Publisher, service_jid(Host), ItemId, Payload]),
           Reply = [],
           case transaction(Host, Node, Action, sync_dirty) of
       	{error, ?ERR_ITEM_NOT_FOUND} ->
      @@ -1660,7 +1663,7 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) ->
       		     RetreiveFeature = lists:member("retrieve-items", Features),
       		     PersistentFeature = lists:member("persistent-items", Features),
       		     AccessModel = get_option(Options, access_model),
      -		     AllowedGroups = get_option(Options, roster_groups_allowed),
      +		     AllowedGroups = get_option(Options, roster_groups_allowed, []),
       		     {PresenceSubscription, RosterGroup} =
       			 case Host of
       			     {OUser, OServer, _} ->
      @@ -2507,7 +2510,7 @@ get_configure_xfields(_Type, Options, Lang, _Owners) ->
       			    {"label", translate:translate(Lang, "Roster groups allowed to subscribe")},
       			    {"var", "pubsub#roster_groups_allowed"}],
             [{xmlelement, "value", [], [{xmlcdata, Value}]} ||
      -	  Value <- get_option(Options, roster_groups_allowed)]},
      +	  Value <- get_option(Options, roster_groups_allowed, [])]},
            ?ALIST_CONFIG_FIELD("Specify the publisher model", publish_model,
       			 [publishers, subscribers, open]),
            ?INTEGER_CONFIG_FIELD("Max payload size in bytes", max_payload_size),
      diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl
      index 9b30269e0..97e363f79 100644
      --- a/src/mod_pubsub/node_default.erl
      +++ b/src/mod_pubsub/node_default.erl
      @@ -455,10 +455,12 @@ publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
       			   OldItem#pubsub_item{modification = PubId,
       					       payload = Payload}
       		   end,
      -	    Items = [ItemId | State#pubsub_state.items],
      +	    Items = [ItemId | State#pubsub_state.items--[ItemId]],
       	    {result, {NI, OI}} = remove_extra_items(
       				   Host, Node, MaxItems, Items),
      -	    set_item(Item),
      +	    if MaxItems > 0 -> set_item(Item);
      +	       true -> ok
      +	    end,
       	    set_state(State#pubsub_state{items = NI}),
       	    {result, {default, broadcast, OI}}
           end.
      diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl
      index 6d2d2709e..1c1bff7d7 100644
      --- a/src/mod_pubsub/node_pep.erl
      +++ b/src/mod_pubsub/node_pep.erl
      @@ -170,14 +170,9 @@ get_entity_affiliations(_Host, Owner) ->
           OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
           node_default:get_entity_affiliations(OwnerKey, Owner).
       
      -get_node_affiliations(_Host, Node) ->
      -    States = mnesia:match_object(
      -	#pubsub_state{stateid = {'_', {'_', Node}},
      -	_ = '_'}),
      -    Tr = fun(#pubsub_state{stateid = {J, {_, _}}, affiliation = A}) ->
      -	{J, A}
      -	end,
      -    {result, lists:map(Tr, States)}.
      +get_node_affiliations(Host, Node) ->
      +    OwnerKey = jlib:jid_remove_resource(Host),
      +    node_default:get_node_affiliations(OwnerKey, Node).
       
       get_affiliation(_Host, Node, Owner) ->
           OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
      diff --git a/src/mod_roster.erl b/src/mod_roster.erl
      index a18fc0d03..91a038223 100644
      --- a/src/mod_roster.erl
      +++ b/src/mod_roster.erl
      @@ -320,7 +320,8 @@ push_item(User, Server, From, Item) ->
       push_item(User, Server, Resource, From, Item) ->
           Request = #xmlel{ns = ?NS_ROSTER, name = 'query',
             children = [item_to_xml(Item)]},
      -    ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request, "push"),
      +    ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request,
      +      "push" ++ randoms:get_string()),
           ejabberd_router:route(
             From,
             exmpp_jid:make_jid(User, Server, Resource),
      diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl
      index cd4a32c49..639803c60 100644
      --- a/src/mod_roster_odbc.erl
      +++ b/src/mod_roster_odbc.erl
      @@ -355,7 +355,8 @@ push_item(User, Server, From, Item) ->
       push_item(User, Server, Resource, From, Item) ->
           Request = #xmlel{ns = ?NS_ROSTER, name = 'query',
             children = [item_to_xml(Item)]},
      -    ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request, "push"),
      +    ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request,
      +      "push" ++ randoms:get_string()),
           ejabberd_router:route(
             From,
             exmpp_jid:make_jid(User, Server, Resource),
      diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl
      index 69ff2e395..e6b35fdd7 100644
      --- a/src/mod_shared_roster.erl
      +++ b/src/mod_shared_roster.erl
      @@ -244,7 +244,8 @@ set_new_rosteritems(UserFrom, ServerFrom,
       set_item(User, Server, Resource, Item) ->
           Request = #xmlel{ns = ?NS_ROSTER, name = 'query',
             children = [mod_roster:item_to_xml(Item)]},
      -    ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request, "push"),
      +    ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request,
      +      "push" ++ randoms:get_string()),
           ejabberd_router:route(
             exmpp_jid:make_jid(User, Server, Resource),
             exmpp_jid:make_bare_jid(Server),
      @@ -567,7 +568,8 @@ push_item(User, Server, From, Item) ->
       			 Item#roster.subscription}]}),
           Request = #xmlel{ns = ?NS_ROSTER, name = 'query',
             children = [item_to_xml(Item)]},
      -    Stanza = exmpp_iq:set(?NS_JABBER_CLIENT, Request, "push"),
      +    Stanza = exmpp_iq:set(?NS_JABBER_CLIENT, Request,
      +      "push" ++ randoms:get_string()),
           lists:foreach(
             fun(Resource) ->
       	      JID = exmpp_jid:make_jid(User, Server, Resource),
      diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl
      index 16967fbb0..c015b1500 100644
      --- a/src/mod_vcard.erl
      +++ b/src/mod_vcard.erl
      @@ -141,9 +141,9 @@ get_sm_features(Acc, _From, _To, Node, _Lang) ->
       	[] ->
       	    case Acc of
       		{result, Features} ->
      -		    {result, [?NS_VCARD_s | Features]};
      +		    {result, [?NS_DISCO_INFO_s, ?NS_VCARD_s | Features]};
       		empty ->
      -		    {result, [?NS_VCARD_s]}
      +		    {result, [?NS_DISCO_INFO_s, ?NS_VCARD_s]}
       	    end;
        	_ ->
       	    Acc
      @@ -372,6 +372,10 @@ do_route(ServerHost, From, To, Packet) ->
       				#xmlattr{name = 'name',
       				  value = translate:translate(Lang,
       				    "vCard User Search")}]},
      +			    #xmlel{ns = ?NS_DISCO_INFO, name = 'feature',
      +			      attrs = [
      +				#xmlattr{name = 'var',
      +				  value = ?NS_DISCO_INFO_s}]},
       			    #xmlel{ns = ?NS_DISCO_INFO, name = 'feature',
       			      attrs = [
       				#xmlattr{name = 'var',
      diff --git a/src/odbc/ejabberd_odbc.erl b/src/odbc/ejabberd_odbc.erl
      index da1b01e2c..dfc1ee6c8 100644
      --- a/src/odbc/ejabberd_odbc.erl
      +++ b/src/odbc/ejabberd_odbc.erl
      @@ -318,8 +318,7 @@ pgsql_item_to_odbc(_) ->
       %% part of init/1
       %% Open a database connection to MySQL
       mysql_connect(Server, Port, DB, Username, Password, StartInterval) ->
      -    NoLogFun = fun(_Level,_Format,_Argument) -> ok end,
      -    case mysql_conn:start(Server, Port, Username, Password, DB, NoLogFun) of
      +    case mysql_conn:start(Server, Port, Username, Password, DB, fun log/3) of
       	{ok, Ref} ->
       	    erlang:monitor(process, Ref),
                   mysql_conn:fetch(Ref, ["set names 'utf8';"], self()),
      @@ -359,3 +358,14 @@ mysql_item_to_odbc(Columns, Recs) ->
       % perform a harmless query on all opened connexions to avoid connexion close.
       keep_alive(PID) ->
           gen_server:call(PID, {sql_query, ?KEEPALIVE_QUERY}, 60000).
      +
      +% log function used by MySQL driver
      +log(Level, Format, Args) ->
      +    case Level of
      +	debug ->
      +	    ?DEBUG(Format, Args);
      +	normal ->
      +	    ?INFO_MSG(Format, Args);
      +	error ->
      +	    ?ERROR_MSG(Format, Args)
      +    end.
      diff --git a/src/tls/tls_drv.c b/src/tls/tls_drv.c
      index 3efe72cf7..b90cab87c 100644
      --- a/src/tls/tls_drv.c
      +++ b/src/tls/tls_drv.c
      @@ -23,24 +23,185 @@
       #include 
       #include 
       #include 
      +#include 
      +#include 
      +#include 
      +#include 
       
       
       #define BUF_SIZE 1024
       
       typedef struct {
             ErlDrvPort port;
      -      SSL_CTX *ctx;
             BIO *bio_read;
             BIO *bio_write;
             SSL *ssl;
       } tls_data;
       
      +#ifdef _WIN32
      +typedef unsigned __int32 uint32_t;
      +#endif
      +
      +/*
      + * str_hash is based on the public domain code from
      + * http://www.burtleburtle.net/bob/hash/doobs.html
      + */
      +static uint32_t str_hash(char *s)
      +{
      +   unsigned char *key = (unsigned char *)s;
      +   uint32_t hash = 0;
      +   size_t i;
      +
      +   for (i = 0; key[i] != 0; i++) {
      +      hash += key[i];
      +      hash += (hash << 10);
      +      hash ^= (hash >> 6);
      +   }
      +   hash += (hash << 3);
      +   hash ^= (hash >> 11);
      +   hash += (hash << 15);
      +   return hash;
      +}
      +
      +/* Linear hashing */
      +
      +#define MIN_LEVEL 8
      +#define MAX_LEVEL 20
      +
      +struct bucket {
      +      uint32_t hash;
      +      char *key_file;
      +      time_t mtime;
      +      SSL_CTX *ssl_ctx;
      +      struct bucket *next;
      +};
      +
      +struct hash_table {
      +      int split;
      +      int level;
      +      struct bucket **buckets;
      +      int size;
      +};
      +
      +struct hash_table ht;
      +
      +static void init_hash_table()
      +{
      +   size_t size = 1 << (MIN_LEVEL + 1);
      +   size_t i;
      +   ht.buckets = (struct bucket **)driver_alloc(sizeof(struct bucket *) * size);
      +   ht.split = 0;
      +   ht.level = MIN_LEVEL;
      +   for (i = 0; i < size; i++)
      +      ht.buckets[i] = NULL;
      +   
      +}
      +
      +static void hash_table_insert(char *key_file, time_t mtime,
      +			     SSL_CTX *ssl_ctx)
      +{
      +   int level, split;
      +   uint32_t hash = str_hash(key_file);
      +   size_t bucket;
      +   int do_split = 0;
      +   struct bucket *el;
      +   struct bucket *new_bucket_el;
      +
      +   split = ht.split;
      +   level = ht.level;
      +
      +   bucket = hash & ((1 << level) - 1);
      +   if (bucket < split)
      +      bucket = hash & ((1 << (level + 1)) - 1);
      +
      +   el = ht.buckets[bucket];
      +   while (el != NULL) {
      +      if (el->hash == hash && strcmp(el->key_file, key_file) == 0) {
      +	 el->mtime = mtime;
      +	 if (el->ssl_ctx != NULL)
      +	    SSL_CTX_free(el->ssl_ctx);
      +	 el->ssl_ctx = ssl_ctx;
      +	 break;
      +      }
      +      el = el->next;
      +   }
      +
      +   if (el == NULL) {
      +      if (ht.buckets[bucket] != NULL)
      +	 do_split = !0;
      +
      +      new_bucket_el = (struct bucket *)driver_alloc(sizeof(struct bucket));
      +      new_bucket_el->hash = hash;
      +      new_bucket_el->key_file = (char *)driver_alloc(strlen(key_file) + 1);
      +      strcpy(new_bucket_el->key_file, key_file);
      +      new_bucket_el->mtime = mtime;
      +      new_bucket_el->ssl_ctx = ssl_ctx;
      +      new_bucket_el->next = ht.buckets[bucket];
      +      ht.buckets[bucket] = new_bucket_el;
      +   }
      +
      +   if (do_split) {
      +      struct bucket **el_ptr = &ht.buckets[split];
      +      size_t new_bucket = split + (1 << level);
      +      while (*el_ptr != NULL) {
      +	 uint32_t hash = (*el_ptr)->hash;
      +	 if ((hash & ((1 << (level + 1)) - 1)) == new_bucket) {
      +	    struct bucket *moved_el = *el_ptr;
      +	    *el_ptr = (*el_ptr)->next;
      +	    moved_el->next = ht.buckets[new_bucket];
      +	    ht.buckets[new_bucket] = moved_el;
      +	 } else
      +	    el_ptr = &(*el_ptr)->next;
      +      }
      +      split++;
      +      if (split == 1 << level) {
      +	 size_t size;
      +	 size_t i;
      +	 split = 0;
      +	 level++;
      +	 size = 1 << (level + 1);
      +	 ht.split = split;
      +	 ht.level = level;
      +	 ht.buckets = (struct bucket **)
      +	    driver_realloc(ht.buckets, sizeof(struct bucket *) * size);
      +	 for (i = 1 << level; i < size; i++)
      +	    ht.buckets[i] = NULL;
      +      } else
      +	 ht.split = split;
      +   }
      +}
      +
      +static SSL_CTX *hash_table_lookup(char *key_file, time_t *pmtime)
      +{
      +   int level, split;
      +   uint32_t hash = str_hash(key_file);
      +   size_t bucket;
      +   struct bucket *el;
      +
      +   split = ht.split;
      +   level = ht.level;
      +
      +   bucket = hash & ((1 << level) - 1);
      +   if (bucket < split)
      +      bucket = hash & ((1 << (level + 1)) - 1);
      +
      +   el = ht.buckets[bucket];
      +   while (el != NULL) {
      +      if (el->hash == hash && strcmp(el->key_file, key_file) == 0) {
      +	 *pmtime = el->mtime;
      +	 return el->ssl_ctx;
      +      }
      +      el = el->next;
      +   }
      +
      +   return NULL;
      +}
      +
       
       static ErlDrvData tls_drv_start(ErlDrvPort port, char *buff)
       {
          tls_data *d = (tls_data *)driver_alloc(sizeof(tls_data));
          d->port = port;
      -   d->ctx = NULL;
          d->bio_read = NULL;
          d->bio_write = NULL;
          d->ssl = NULL;
      @@ -57,12 +218,46 @@ static void tls_drv_stop(ErlDrvData handle)
          if (d->ssl != NULL)
             SSL_free(d->ssl);
       
      -   if (d->ctx != NULL)
      -      SSL_CTX_free(d->ctx);
      -
          driver_free((char *)handle);
       }
       
      +static void tls_drv_finish()
      +{
      +   int level;
      +   struct bucket *el;
      +   int i;
      +
      +   level = ht.level;
      +   for (i = 0; i < 1 << (level + 1); i++) {
      +      el = ht.buckets[i];
      +      while (el != NULL) {
      +	 if (el->ssl_ctx != NULL)
      +	    SSL_CTX_free(el->ssl_ctx);
      +	 driver_free(el->key_file);
      +	 el = el->next;
      +      }
      +   }
      +
      +   driver_free(ht.buckets);
      +}
      +
      +static int is_key_file_modified(char *file, time_t *key_file_mtime)
      +{
      +   struct stat file_stat;
      +
      +   if (stat(file, &file_stat))
      +   {
      +      *key_file_mtime = 0;
      +      return 1;
      +   } else {
      +      if (*key_file_mtime != file_stat.st_mtime)
      +      {
      +	 *key_file_mtime = file_stat.st_mtime;
      +	 return 1;
      +      } else
      +	 return 0;
      +   }
      +}
       
       static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
       {
      @@ -122,29 +317,41 @@ static int tls_drv_control(ErlDrvData handle,
          switch (command)
          {
             case SET_CERTIFICATE_FILE_ACCEPT:
      -      case SET_CERTIFICATE_FILE_CONNECT:
      -	 d->ctx = SSL_CTX_new(SSLv23_method());
      -	 die_unless(d->ctx, "SSL_CTX_new failed");
      -
      -	 res = SSL_CTX_use_certificate_chain_file(d->ctx, buf);
      -	 die_unless(res > 0, "SSL_CTX_use_certificate_file failed");
      -
      -	 res = SSL_CTX_use_PrivateKey_file(d->ctx, buf, SSL_FILETYPE_PEM);
      -	 die_unless(res > 0, "SSL_CTX_use_PrivateKey_file failed");
      -
      -	 res = SSL_CTX_check_private_key(d->ctx);
      -	 die_unless(res > 0, "SSL_CTX_check_private_key failed");
      -
      -	 SSL_CTX_set_default_verify_paths(d->ctx);
      -
      -	 if (command == SET_CERTIFICATE_FILE_ACCEPT)
      +      case SET_CERTIFICATE_FILE_CONNECT: {
      +	 time_t mtime = 0;
      +	 SSL_CTX *ssl_ctx = hash_table_lookup(buf, &mtime);
      +	 if (is_key_file_modified(buf, &mtime) || ssl_ctx == NULL)
       	 {
      -	    SSL_CTX_set_verify(d->ctx,
      -			       SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,
      -			       verify_callback);
      +	    SSL_CTX *ctx;
      +
      +	    hash_table_insert(buf, mtime, NULL);
      +
      +	    ctx = SSL_CTX_new(SSLv23_method());
      +	    die_unless(ctx, "SSL_CTX_new failed");
      +
      +	    res = SSL_CTX_use_certificate_chain_file(ctx, buf);
      +	    die_unless(res > 0, "SSL_CTX_use_certificate_file failed");
      +
      +	    res = SSL_CTX_use_PrivateKey_file(ctx, buf, SSL_FILETYPE_PEM);
      +	    die_unless(res > 0, "SSL_CTX_use_PrivateKey_file failed");
      +
      +	    res = SSL_CTX_check_private_key(ctx);
      +	    die_unless(res > 0, "SSL_CTX_check_private_key failed");
      +
      +	    SSL_CTX_set_default_verify_paths(ctx);
      +
      +	    if (command == SET_CERTIFICATE_FILE_ACCEPT)
      +	    {
      +	       SSL_CTX_set_verify(ctx,
      +				  SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,
      +				  verify_callback);
      +	    }
      +
      +	    ssl_ctx = ctx;
      +	    hash_table_insert(buf, mtime, ssl_ctx);
       	 }
      -	 
      -	 d->ssl = SSL_new(d->ctx);
      +
      +	 d->ssl = SSL_new(ssl_ctx);
       	 die_unless(d->ssl, "SSL_new failed");
       
       	 d->bio_read = BIO_new(BIO_s_mem());
      @@ -154,9 +361,12 @@ static int tls_drv_control(ErlDrvData handle,
       
       	 if (command == SET_CERTIFICATE_FILE_ACCEPT)
       	    SSL_set_accept_state(d->ssl);
      -	 else
      +	 else {
      +	    SSL_set_options(d->ssl, SSL_OP_NO_SSLv2);
       	    SSL_set_connect_state(d->ssl);
      +	 }
       	 break;
      +      }
             case SET_ENCRYPTED_INPUT:
       	 die_unless(d->ssl, "SSL not initialized");
       	 BIO_write(d->bio_read, buf, len);
      @@ -282,7 +492,7 @@ ErlDrvEntry tls_driver_entry = {
          NULL,			/* F_PTR ready_input, called when input descriptor ready */
          NULL,			/* F_PTR ready_output, called when output descriptor ready */
          "tls_drv",			/* char *driver_name, the argument to open_port */
      -   NULL,			/* F_PTR finish, called when unloaded */
      +   tls_drv_finish,		/* F_PTR finish, called when unloaded */
          NULL,			/* handle */
          tls_drv_control,		/* F_PTR control, port_command callback */
          NULL,			/* F_PTR timeout, reserved */
      @@ -293,6 +503,7 @@ DRIVER_INIT(tls_drv) /* must match name in driver_entry */
       {
          OpenSSL_add_ssl_algorithms();
          SSL_load_error_strings();
      +   init_hash_table();
          return &tls_driver_entry;
       }
       
      diff --git a/src/translate.erl b/src/translate.erl
      index c3b5b63cd..a5513ce64 100644
      --- a/src/translate.erl
      +++ b/src/translate.erl
      @@ -89,8 +89,16 @@ load_file(Lang, File) ->
       			      ets:insert(translations,
       					     {{Lang, Orig}, Trans1})
       			  end, Terms);
      +        %% Code copied from ejabberd_config.erl
      +	{error, {_LineNumber, erl_parse, _ParseMessage} = Reason} ->
      +	    ExitText = lists:flatten(File ++ " approximately in the line "
      +				     ++ file:format_error(Reason)),
      +	    ?ERROR_MSG("Problem loading translation file ~n~s", [ExitText]),
      +	    exit(ExitText);
       	{error, Reason} ->
      -	    exit(file:format_error(Reason))
      +	    ExitText = lists:flatten(File ++ ": " ++ file:format_error(Reason)),
      +	    ?ERROR_MSG("Problem loading translation file ~n~s", [ExitText]),
      +	    exit(ExitText)
           end.
       
       translate(Lang, Msg) ->
      diff --git a/src/web/ejabberd_http.erl b/src/web/ejabberd_http.erl
      index be87a56fd..bd7f7db98 100644
      --- a/src/web/ejabberd_http.erl
      +++ b/src/web/ejabberd_http.erl
      @@ -202,7 +202,7 @@ process_header(State, Data) ->
       			request_version = Version,
       			request_path = Path,
       			request_keepalive = KeepAlive};
      -	{ok, {http_header, _, 'Connection', _, Conn}} ->
      +	{ok, {http_header, _, 'Connection'=Name, _, Conn}} ->
       	    KeepAlive1 = case exmpp_stringprep:to_lower(Conn) of
       			     "keep-alive" ->
       				 true;
      @@ -211,23 +211,27 @@ process_header(State, Data) ->
       			     _ ->
       				 State#state.request_keepalive
       			 end,
      -	    State#state{request_keepalive = KeepAlive1};
      -	{ok, {http_header, _, 'Authorization', _, Auth}} ->
      -	    State#state{request_auth = parse_auth(Auth)};
      -	{ok, {http_header, _, 'Content-Length', _, SLen}} ->
      +	    State#state{request_keepalive = KeepAlive1,
      +			request_headers=add_header(Name, Conn, State)};
      +	{ok, {http_header, _, 'Authorization'=Name, _, Auth}} ->
      +	    State#state{request_auth = parse_auth(Auth),
      +			request_headers=add_header(Name, Auth, State)};
      +	{ok, {http_header, _, 'Content-Length'=Name, _, SLen}} ->
       	    case catch list_to_integer(SLen) of
       		Len when is_integer(Len) ->
      -		    State#state{request_content_length = Len};
      +		    State#state{request_content_length = Len,
      +				request_headers=add_header(Name, SLen, State)};
       		_ ->
       		    State
       	    end;
      -	{ok, {http_header, _, 'Accept-Language', _, Langs}} ->
      -	    State#state{request_lang = parse_lang(Langs)};
      -	{ok, {http_header, _, 'Host', _, Host}} ->
      -		State#state{request_host = Host};
      +	{ok, {http_header, _, 'Accept-Language'=Name, _, Langs}} ->
      +	    State#state{request_lang = parse_lang(Langs),
      +			request_headers=add_header(Name, Langs, State)};
      +	{ok, {http_header, _, 'Host'=Name, _, Host}} ->
      +	    State#state{request_host = Host,
      +			request_headers=add_header(Name, Host, State)};
       	{ok, {http_header, _, Name, _, Value}} ->
      -		Headers = [{Name, Value} | State#state.request_headers],
      -		State#state{request_headers=Headers};
      +	    State#state{request_headers=add_header(Name, Value, State)};
       	{ok, http_eoh} ->
       	    ?DEBUG("(~w) http query: ~w ~s~n",
       		   [State#state.socket,
      @@ -263,6 +267,9 @@ process_header(State, Data) ->
       		   request_handlers = State#state.request_handlers}
           end.
       
      +add_header(Name, Value, State) ->
      +    [{Name, Value} | State#state.request_headers].
      +
       %% @spec (SockMod, HostPort) -> {Host::string(), Port::integer(), TP}
       %% where
       %%       SockMod = gen_tcp | tls
      @@ -321,13 +328,13 @@ process_request(#state{request_method = Method,
       	{'EXIT', _} ->
       	    process_request(false);
       	{NPath, Query} ->
      +	    LPath = [path_decode(NPE) || NPE <- string:tokens(NPath, "/")],
       	    LQuery = case (catch parse_urlencoded(Query)) of
       			 {'EXIT', _Reason} ->
       			     [];
       			 LQ ->
       			     LQ
       		     end,
      -	    LPath = string:tokens(NPath, "/"),
       	    {ok, IP} =
       		case SockMod of
       		    gen_tcp ->
      @@ -386,7 +393,7 @@ process_request(#state{request_method = Method,
       	{'EXIT', _} ->
       	    process_request(false);
       	{NPath, _Query} ->
      -	    LPath = string:tokens(NPath, "/"),
      +	    LPath = [path_decode(NPE) || NPE <- string:tokens(NPath, "/")],
       	    LQuery = case (catch parse_urlencoded(Data)) of
       			 {'EXIT', _Reason} ->
       			     [];
      @@ -557,24 +564,30 @@ parse_lang(Langs) ->
       %    notice as well as this list of conditions.
       
       
      -%% url decode the path and return {Path, QueryPart}
      -
      +%% @doc Split the URL and return {Path, QueryPart}
       url_decode_q_split(Path) ->
           url_decode_q_split(Path, []).
      +url_decode_q_split([$?|T], Ack) ->
      +    %% Don't decode the query string here, that is parsed separately.
      +    {path_norm_reverse(Ack), T};
      +url_decode_q_split([H|T], Ack) when H /= 0 ->
      +    url_decode_q_split(T, [H|Ack]);
      +url_decode_q_split([], Ack) ->
      +    {path_norm_reverse(Ack), []}.
       
      -url_decode_q_split([$%, Hi, Lo | Tail], Ack) ->
      +%% @doc Decode a part of the URL and return string()
      +path_decode(Path) ->
      +    path_decode(Path, []).
      +path_decode([$%, Hi, Lo | Tail], Ack) ->
           Hex = hex_to_integer([Hi, Lo]),
           if Hex  == 0 -> exit(badurl);
              true -> ok
           end,
      -    url_decode_q_split(Tail, [Hex|Ack]);
      -url_decode_q_split([$?|T], Ack) ->
      -    %% Don't decode the query string here, that is parsed separately.
      -    {path_norm_reverse(Ack), T};
      -url_decode_q_split([H|T], Ack) when H /= 0 -> 
      -    url_decode_q_split(T, [H|Ack]);
      -url_decode_q_split([], Ack) ->
      -    {path_norm_reverse(Ack), []}.
      +    path_decode(Tail, [Hex|Ack]);
      +path_decode([H|T], Ack) when H /= 0 ->
      +    path_decode(T, [H|Ack]);
      +path_decode([], Ack) ->
      +    lists:reverse(Ack).
       
       path_norm_reverse("/" ++ T) -> start_dir(0, "/", T);
       path_norm_reverse(       T) -> start_dir(0,  "", T).
      
      From f30d2b9f1cbb34233e3b5993e0e48dbef810067a Mon Sep 17 00:00:00 2001
      From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?=
       
      Date: Mon, 1 Dec 2008 15:54:57 +0000
      Subject: [PATCH 128/582] Fix two warnings about unused variables.
      
      PR:		EJABP-1
      
      SVN Revision: 1696
      ---
       ChangeLog                        | 5 ++++-
       src/ejabberd_frontend_socket.erl | 4 ++--
       2 files changed, 6 insertions(+), 3 deletions(-)
      
      diff --git a/ChangeLog b/ChangeLog
      index d6a2addfb..ecd0a3ad7 100644
      --- a/ChangeLog
      +++ b/ChangeLog
      @@ -2,6 +2,9 @@
       
       	Merge from trunk (r1649 to r1692).
       
      +	* src/ejabberd_frontend_socket.erl: Fix two warnings about unused
      +	variables.
      +
       2008-11-28  Alexey Shchepin  
       
       	* src/mod_muc/mod_muc_room.erl: Clean user activity after timeout
      @@ -163,7 +166,7 @@
       
       2008-10-13  Jean-Sébastien Pédron  
       
      -	Merge from trunk (r1613 to 1649).
      +	Merge from trunk (r1613 to r1649).
       
       	* src/jlib.erl: Remove all deprecated functions.
       
      diff --git a/src/ejabberd_frontend_socket.erl b/src/ejabberd_frontend_socket.erl
      index df604ccc3..99f0b1964 100644
      --- a/src/ejabberd_frontend_socket.erl
      +++ b/src/ejabberd_frontend_socket.erl
      @@ -94,7 +94,7 @@ start(Module, SockMod, Socket, Opts) ->
       	    todo
           end.
       
      -starttls(FsmRef, TLSOpts) ->
      +starttls(FsmRef, _TLSOpts) ->
           %gen_server:call(FsmRef, {starttls, TLSOpts}),
           FsmRef.
       
      @@ -137,7 +137,7 @@ close(FsmRef) ->
       sockname(FsmRef) ->
           gen_server:call(FsmRef, sockname).
       
      -peername(FsmRef) ->
      +peername(_FsmRef) ->
           %gen_server:call(FsmRef, peername).
           {ok, {{0, 0, 0, 0}, 0}}.
       
      
      From b425093813444f8860c9b8fb59b2ea4569341610 Mon Sep 17 00:00:00 2001
      From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?=
       
      Date: Wed, 3 Dec 2008 14:34:43 +0000
      Subject: [PATCH 129/582] Convert mod_proxy65 to exmpp.
      
      SVN Revision: 1701
      ---
       ChangeLog                               |   5 ++
       src/mod_proxy65/mod_proxy65_service.erl | 114 +++++++++++++-----------
       src/mod_proxy65/mod_proxy65_stream.erl  |   4 +-
       3 files changed, 68 insertions(+), 55 deletions(-)
      
      diff --git a/ChangeLog b/ChangeLog
      index ecd0a3ad7..bb2f27900 100644
      --- a/ChangeLog
      +++ b/ChangeLog
      @@ -1,3 +1,8 @@
      +2008-12-03  Jean-Sébastien Pédron  
      +
      +	* src/mod_proxy65/mod_proxy65_stream.erl,
      +	src/mod_proxy65/mod_proxy65_service.erl: Convert mod_proxy65 to exmpp.
      +
       2008-12-01  Jean-Sébastien Pédron  
       
       	Merge from trunk (r1649 to r1692).
      diff --git a/src/mod_proxy65/mod_proxy65_service.erl b/src/mod_proxy65/mod_proxy65_service.erl
      index 23f41d4ef..0e1734480 100644
      --- a/src/mod_proxy65/mod_proxy65_service.erl
      +++ b/src/mod_proxy65/mod_proxy65_service.erl
      @@ -41,8 +41,9 @@
       %% API.
       -export([start_link/2, add_listener/2, delete_listener/1]).
       
      +-include_lib("exmpp/include/exmpp.hrl").
      +
       -include("ejabberd.hrl").
      --include("jlib.hrl").
       
       -define(PROCNAME, ejabberd_mod_proxy65_service).
       
      @@ -73,14 +74,15 @@ terminate(_Reason, #state{myhost=MyHost}) ->
           ejabberd_router:unregister_route(MyHost),
           ok.
       
      -handle_info({route, From, To, {xmlelement, "iq", _, _} = Packet}, State) ->
      -    IQ = jlib:iq_query_info(Packet),
      -    case catch process_iq(From, IQ, State) of
      -	Result when is_record(Result, iq) ->
      -	    ejabberd_router:route(To, From, jlib:iq_to_xml(Result));
      +handle_info({route, From, To, Packet}, State) when ?IS_IQ(Packet) ->
      +    IQ_Rec = exmpp_iq:xmlel_to_iq(Packet),
      +    case catch process_iq(From, IQ_Rec, State) of
      +	Result when ?IS_IQ_RECORD(Result) ->
      +	    ejabberd_router:route(To, From,
      +	      exmpp_iq:iq_to_xmlel(Result, To, From));
       	{'EXIT', Reason} ->
       	    ?ERROR_MSG("Error when processing IQ stanza: ~p", [Reason]),
      -	    Err = jlib:make_error_reply(Packet, ?ERR_INTERNAL_SERVER_ERROR),
      +	    Err = exmpp_iq:error(Packet, 'internal-server-error'),
       	    ejabberd_router:route(To, From, Err);
       	_ ->
       	    ok
      @@ -119,67 +121,72 @@ delete_listener(Host) ->
       %%%------------------------
       
       %% disco#info request
      -process_iq(_, #iq{type = get, xmlns = ?NS_DISCO_INFO, lang = Lang} = IQ, #state{name=Name}) ->
      -    IQ#iq{type = result, sub_el =
      -	  [{xmlelement, "query", [{"xmlns", ?NS_DISCO_INFO}], iq_disco_info(Lang, Name)}]};
      +process_iq(_, #iq{type = get, ns = ?NS_DISCO_INFO, lang = Lang} = IQ_Rec, #state{name=Name}) ->
      +    Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query',
      +      children = iq_disco_info(Lang, Name)},
      +    exmpp_iq:result(IQ_Rec, Result);
       
       %% disco#items request
      -process_iq(_, #iq{type = get, xmlns = ?NS_DISCO_ITEMS} = IQ, _) ->
      -    IQ#iq{type = result, sub_el =
      -	  [{xmlelement, "query", [{"xmlns", ?NS_DISCO_ITEMS}], []}]};
      +process_iq(_, #iq{type = get, ns = ?NS_DISCO_ITEMS} = IQ_Rec, _) ->
      +    Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query',
      +      children = []},
      +    exmpp_iq:result(IQ_Rec, Result);
       
       %% vCard request
      -process_iq(_, #iq{type = get, xmlns = ?NS_VCARD, lang = Lang} = IQ, _) ->
      -    IQ#iq{type = result, sub_el =
      -	  [{xmlelement, "vCard", [{"xmlns", ?NS_VCARD}], iq_vcard(Lang)}]};
      +process_iq(_, #iq{type = get, ns = ?NS_VCARD, lang = Lang} = IQ_Rec, _) ->
      +    Result = #xmlel{ns = ?NS_VCARD, name = 'vCard',
      +      children = iq_vcard(Lang)},
      +    exmpp_iq:result(IQ_Rec, Result);
       
       %% bytestreams info request
      -process_iq(JID, #iq{type = get, sub_el = SubEl, xmlns = ?NS_BYTESTREAMS} = IQ,
      +process_iq(JID, #iq{type = get, ns = ?NS_BYTESTREAMS} = IQ_Rec,
       	   #state{acl = ACL, stream_addr = StreamAddr, serverhost = ServerHost}) ->
           case acl:match_rule(ServerHost, ACL, JID) of
       	allow ->
      -	    StreamHostEl = [{xmlelement, "streamhost", StreamAddr, []}],
      -	    IQ#iq{type = result, sub_el =
      -		  [{xmlelement, "query", [{"xmlns", ?NS_BYTESTREAMS}], StreamHostEl}]};
      +	    StreamHostEl = [#xmlel{ns = ?NS_BYTESTREAMS, name = 'streamhost',
      +		attrs = StreamAddr}],
      +	    Result = #xmlel{ns = ?NS_BYTESTREAMS, name = 'query',
      +	      children = StreamHostEl},
      +	    exmpp_iq:result(IQ_Rec, Result);
       	deny ->
      -	    IQ#iq{type = error, sub_el = [SubEl, ?ERR_FORBIDDEN]}
      +	    exmpp_iq:error(IQ_Rec, 'forbidden')
           end;
       
       %% bytestream activation request
      -process_iq(InitiatorJID, #iq{type = set, sub_el = SubEl, xmlns = ?NS_BYTESTREAMS} = IQ,
      +process_iq(InitiatorJID, #iq{type = set, payload = SubEl, ns = ?NS_BYTESTREAMS} = IQ_Rec,
       	   #state{acl = ACL, serverhost = ServerHost}) ->
           case acl:match_rule(ServerHost, ACL, InitiatorJID) of
       	allow ->
      -	    ActivateEl = xml:get_path_s(SubEl, [{elem, "activate"}]),
      -	    SID = xml:get_tag_attr_s("sid", SubEl),
      -	    case catch jlib:string_to_jid(xml:get_tag_cdata(ActivateEl)) of
      -		TargetJID when is_record(TargetJID, jid), SID /= "",
      +	    ActivateEl = exmpp_xml:get_path(SubEl, [{element, 'activate'}]),
      +	    SID = exmpp_xml:get_attribute(SubEl, 'sid', ""),
      +	    case catch exmpp_jid:list_to_jid(exmpp_xml:get_cdata_as_string(ActivateEl)) of
      +		TargetJID when ?IS_JID(TargetJID), SID /= "",
       		               length(SID) =< 128, TargetJID /= InitiatorJID ->
      -		    Target = jlib:jid_to_string(jlib:jid_tolower(TargetJID)),
      -		    Initiator = jlib:jid_to_string(jlib:jid_tolower(InitiatorJID)),
      +		    Target = exmpp_jid:prepd_jid_to_list(TargetJID),
      +		    Initiator = exmpp_jid:prepd_jid_to_list(InitiatorJID),
       		    SHA1 = sha:sha(SID ++ Initiator ++ Target),
       		    case mod_proxy65_sm:activate_stream(SHA1, InitiatorJID, TargetJID, ServerHost) of
       			ok ->
      -			    IQ#iq{type = result, sub_el = []};
      +			    exmpp_iq:result(IQ_Rec);
       			false ->
      -			    IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]};
      +			    exmpp_iq:error(IQ_Rec, 'item-not-found');
       			limit ->
      -			    IQ#iq{type = error, sub_el = [SubEl, ?ERR_RESOURCE_CONSTRAINT]};
      +			    exmpp_iq:error(IQ_Rec, 'resource-constraint');
       			conflict ->
      -			    IQ#iq{type = error, sub_el = [SubEl, ?ERR_CONFLICT]};
      +			    exmpp_iq:error(IQ_Rec, 'conflict');
       			_ ->
      -			    IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}
      +			    exmpp_iq:error(IQ_Rec, 'internal-server-error')
       		    end;
       		_ ->
      -		    IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]}
      +		    exmpp_iq:error(IQ_Rec, 'bad-request')
       	    end;
       	deny ->
      -	    IQ#iq{type = error, sub_el = [SubEl, ?ERR_FORBIDDEN]}
      +	    exmpp_iq:error(IQ_Rec, 'forbidden')
           end;
       
       %% Unknown "set" or "get" request
      -process_iq(_, #iq{type=Type, sub_el=SubEl} = IQ, _) when Type==get; Type==set ->
      -    IQ#iq{type = error, sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]};
      +process_iq(_, #iq{kind=request} = IQ_Rec, _) ->
      +    exmpp_iq:error(IQ_Rec, 'service-unavailable');
       
       %% IQ "result" or "error".
       process_iq(_, _, _) ->
      @@ -188,25 +195,26 @@ process_iq(_, _, _) ->
       %%%-------------------------
       %%% Auxiliary functions.
       %%%-------------------------
      --define(FEATURE(Feat), {xmlelement,"feature",[{"var", Feat}],[]}).
      +-define(FEATURE(Feat), #xmlel{ns = ?NS_DISCO_INFO, name = 'feature',
      +    attrs = [#xmlattr{name = 'var', value = Feat}]}).
       
       iq_disco_info(Lang, Name) ->
      -    [{xmlelement, "identity",
      -      [{"category", "proxy"},
      -       {"type", "bytestreams"},
      -       {"name", translate:translate(Lang, Name)}], []},
      -     ?FEATURE(?NS_DISCO_INFO),
      -     ?FEATURE(?NS_VCARD),
      -     ?FEATURE(?NS_BYTESTREAMS)].
      +    [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs =
      +      [#xmlattr{name = 'category', value = "proxy"},
      +       #xmlattr{name = 'type', value = "bytestreams"},
      +       #xmlattr{name = 'name', value = translate:translate(Lang, Name)}]},
      +     ?FEATURE(?NS_DISCO_INFO_s),
      +     ?FEATURE(?NS_VCARD_s),
      +     ?FEATURE(?NS_BYTESTREAMS_s)].
       
       iq_vcard(Lang) ->
      -    [{xmlelement, "FN", [],
      -      [{xmlcdata, "ejabberd/mod_proxy65"}]},
      -     {xmlelement, "URL", [],
      -      [{xmlcdata, ?EJABBERD_URI}]},
      -     {xmlelement, "DESC", [],
      -      [{xmlcdata, translate:translate(Lang, "ejabberd SOCKS5 Bytestreams module") ++
      -       "\nCopyright (c) 2003-2008 Alexey Shchepin"}]}].
      +    [#xmlel{ns = ?NS_VCARD, name = 'FN', children =
      +      [#xmlcdata{cdata = <<"ejabberd/mod_proxy65">>}]},
      +     #xmlel{ns = ?NS_VCARD, name = 'URL', children =
      +      [#xmlcdata{cdata = list_to_binary(?EJABBERD_URI)}]},
      +     #xmlel{ns = ?NS_VCARD, name = 'DESC', children =
      +      [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "ejabberd SOCKS5 Bytestreams module") ++
      +       "\nCopyright (c) 2003-2008 Alexey Shchepin")}]}].
       
       parse_options(ServerHost, Opts) ->
           MyHost = gen_mod:get_opt_host(ServerHost, Opts, "proxy.@HOST@"),
      @@ -218,7 +226,7 @@ parse_options(ServerHost, Opts) ->
       	         Addr -> Addr
       	     end,
           StrIP = inet_parse:ntoa(IP),
      -    StreamAddr = [{"jid", MyHost}, {"host", StrIP}, {"port", integer_to_list(Port)}],
      +    StreamAddr = [#xmlattr{name = 'jid', value = MyHost}, #xmlattr{name = 'host', value = StrIP}, #xmlattr{name = 'port', value = integer_to_list(Port)}],
           {IP, #state{myhost      = MyHost,
       		serverhost  = ServerHost,
       		name        = Name,
      diff --git a/src/mod_proxy65/mod_proxy65_stream.erl b/src/mod_proxy65/mod_proxy65_stream.erl
      index 9d42dcaa3..38ca75147 100644
      --- a/src/mod_proxy65/mod_proxy65_stream.erl
      +++ b/src/mod_proxy65/mod_proxy65_stream.erl
      @@ -122,8 +122,8 @@ activate({P1, J1}, {P2, J2}) ->
       	{S1, S2} when is_port(S1), is_port(S2) ->
       	    P1 ! {activate, P2, S2, J1, J2},
       	    P2 ! {activate, P1, S1, J1, J2},
      -	    JID1 = jlib:jid_to_string(J1),
      -	    JID2 = jlib:jid_to_string(J2),
      +	    JID1 = exmpp_jid:jid_to_list(J1),
      +	    JID2 = exmpp_jid:jid_to_list(J2),
       	    ?INFO_MSG("(~w:~w) Activated bytestream for ~s -> ~s", [P1, P2, JID1, JID2]),
       	    ok;
       	_ ->
      
      From b82b66fdf07c5fe251418653bbca944edeb4ef53 Mon Sep 17 00:00:00 2001
      From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?=
       
      Date: Fri, 5 Dec 2008 15:06:49 +0000
      Subject: [PATCH 130/582] Update Exmpp XML parser options.
      
      SVN Revision: 1703
      ---
       ChangeLog                 | 6 ++++++
       src/ejabberd_receiver.erl | 6 ++----
       src/jd2ejd.erl            | 2 +-
       src/mod_offline_odbc.erl  | 6 +++---
       src/mod_private_odbc.erl  | 4 +---
       src/mod_vcard_odbc.erl    | 2 +-
       6 files changed, 14 insertions(+), 12 deletions(-)
      
      diff --git a/ChangeLog b/ChangeLog
      index bb2f27900..3c7fd187a 100644
      --- a/ChangeLog
      +++ b/ChangeLog
      @@ -1,3 +1,9 @@
      +2008-12-05  Jean-Sébastien Pédron  
      +
      +	* src/ejabberd_receiver.erl, src/mod_offline_odbc.erl,
      +	src/mod_vcard_odbc.erl, src/mod_private_odbc.erl, src/jd2ejd.erl:
      +	Update Exmpp XML parser options.
      +
       2008-12-03  Jean-Sébastien Pédron  
       
       	* src/mod_proxy65/mod_proxy65_stream.erl,
      diff --git a/src/ejabberd_receiver.erl b/src/ejabberd_receiver.erl
      index 37cf38b98..e6d56734c 100644
      --- a/src/ejabberd_receiver.erl
      +++ b/src/ejabberd_receiver.erl
      @@ -164,10 +164,8 @@ handle_call(reset_stream, _From,
            ?HIBERNATE_TIMEOUT};
       handle_call({become_controller, C2SPid}, _From, State) ->
           Parser = exmpp_xml:start_parser([
      -      {namespace, true},
      -      {name_as_atom, true},
      -      {autoload_known, true},
      -      {maxsize, State#state.max_stanza_size}
      +      names_as_atom,
      +      {max_size, State#state.max_stanza_size}
           ]),
           XMLStreamState = exmpp_xmlstream:start(
             {gen_fsm, C2SPid}, Parser,
      diff --git a/src/jd2ejd.erl b/src/jd2ejd.erl
      index c5c4a3d8b..67d489c81 100644
      --- a/src/jd2ejd.erl
      +++ b/src/jd2ejd.erl
      @@ -51,7 +51,7 @@ import_file(File) ->
       		{ok, Text} ->
       		    try
       			[El] = exmpp_xml:parse_document(Text,
      -			  [namespace, name_as_atom]),
      +			  [names_as_atom]),
       			case catch process_xdb(User, Server, El) of
       			    {'EXIT', Reason} ->
       				?ERROR_MSG(
      diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl
      index a5db7a9c5..bb54951d2 100644
      --- a/src/mod_offline_odbc.erl
      +++ b/src/mod_offline_odbc.erl
      @@ -251,7 +251,7 @@ pop_offline_messages(Ls, User, Server) ->
       		Ls ++ lists:flatmap(
       			fun({_, XML}) ->
       				try
      -				    [El] = exmpp_xml:parse_document(XML, [namespace, name_as_atom, autoload_known]),
      +				    [El] = exmpp_xml:parse_document(XML, [names_as_atom]),
       				    To = exmpp_jid:list_to_jid(
       				      exmpp_stanza:get_recipient(El)),
       				    From = exmpp_jid:list_to_jid(
      @@ -327,7 +327,7 @@ user_queue(User, Server, Query, Lang) ->
       		   {selected, ["username", "xml"], Rs} ->
       		       lists:flatmap(
       			 fun({_, XML}) ->
      -				 try exmpp_xml:parse_document(XML, [namespace, name_as_atom, autoload_known]) of
      +				 try exmpp_xml:parse_document(XML, [names_as_atom]) of
       				     [El] ->
       					 [El]
       				 catch
      @@ -394,7 +394,7 @@ user_queue_parse_query(Username, LServer, Query) ->
       		       {selected, ["xml", "seq"], Rs} ->
       			   lists:flatmap(
       			     fun({XML, Seq}) ->
      -				     try exmpp_xml:parse_document(XML, [namespace, name_as_atom, autoload_known]) of
      +				     try exmpp_xml:parse_document(XML, [names_as_atom]) of
       					 [El] ->
       					     [{El, Seq}]
       				     catch
      diff --git a/src/mod_private_odbc.erl b/src/mod_private_odbc.erl
      index 09dce943d..94e4b6eeb 100644
      --- a/src/mod_private_odbc.erl
      +++ b/src/mod_private_odbc.erl
      @@ -151,9 +151,7 @@ get_data(LUser, LServer, [El | Els], Res) ->
           LXMLNS = ejabberd_odbc:escape(XMLNS),
           case catch odbc_queries:get_private_data(LServer, Username, LXMLNS) of
           {selected, ["data"], [{SData}]} ->
      -	[Data] = exmpp_xml:parse_document(SData,[namespace,
      -						 name_as_atom,
      -						 autoload_known]),
      +	[Data] = exmpp_xml:parse_document(SData,[names_as_atom]),
       	get_data(LUser, LServer, Els, [Data | Res]);
           %% MREMOND: I wonder when the query could return a vcard ?
           {selected, ["vcard"], []} ->
      diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl
      index db0b1fd9b..dd1a59adb 100644
      --- a/src/mod_vcard_odbc.erl
      +++ b/src/mod_vcard_odbc.erl
      @@ -134,7 +134,7 @@ process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) ->
           case catch odbc_queries:get_vcard(LServer, Username) of
               {selected, ["vcard"], [{SVCARD}]} ->
                   try exmpp_xml:parse_document(SVCARD,
      -              [namespace, name_as_atom, autoload_known]) of
      +              [names_as_atom]) of
                       [VCARD] ->
                           exmpp_iq:result(IQ_Rec, VCARD)
                   catch
      
      From 6305ddca187a2f2c6041bce31cacba7356ee7f49 Mon Sep 17 00:00:00 2001
      From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?=
       
      Date: Fri, 5 Dec 2008 15:08:03 +0000
      Subject: [PATCH 131/582] Add the module and function names to the error
       message, when a module crash.
      
      SVN Revision: 1704
      ---
       ChangeLog              | 3 +++
       src/gen_iq_handler.erl | 3 ++-
       2 files changed, 5 insertions(+), 1 deletion(-)
      
      diff --git a/ChangeLog b/ChangeLog
      index 3c7fd187a..17685cbf8 100644
      --- a/ChangeLog
      +++ b/ChangeLog
      @@ -4,6 +4,9 @@
       	src/mod_vcard_odbc.erl, src/mod_private_odbc.erl, src/jd2ejd.erl:
       	Update Exmpp XML parser options.
       
      +	* src/gen_iq_handler.erl: Add the module and function names to the
      +	error message, when a module crash.
      +
       2008-12-03  Jean-Sébastien Pédron  
       
       	* src/mod_proxy65/mod_proxy65_stream.erl,
      diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl
      index 0a4de407f..130934ca3 100644
      --- a/src/gen_iq_handler.erl
      +++ b/src/gen_iq_handler.erl
      @@ -124,7 +124,8 @@ process_iq(_Host, Module, Function, From, To, IQ_Rec) ->
       	    ejabberd_router:route(To, From, Reply)
           catch
       	_Class:Reason ->
      -	    ?ERROR_MSG("~p~n~p~n", [Reason, erlang:get_stacktrace()])
      +	    ?ERROR_MSG("~s:~s/3 crashed: ~p~n~p~n",
      +              [Module, Function, Reason, erlang:get_stacktrace()])
           end.
       
       %%====================================================================
      
      From 163d185776c23b33db4854ab1683a7ac0c923be1 Mon Sep 17 00:00:00 2001
      From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?=
       
      Date: Fri, 5 Dec 2008 15:13:09 +0000
      Subject: [PATCH 132/582] First pass of Exmpp conversion for mod_pubsub.
      
      CAUTION:
      o  Several modules aren't converted yet.
      o  Existent Mnesia tables written to disc are not updated.
      o  There must be bugs, mostly because of the mix between #jid record
      and short JIDs.
      PR:		EJABP-1
      
      SVN Revision: 1705
      ---
       ChangeLog                           |   7 +
       src/mod_pubsub/mod_pubsub.erl       | 893 ++++++++++++++--------------
       src/mod_pubsub/node_default.erl     | 128 ++--
       src/mod_pubsub/node_pep.erl         |  17 +-
       src/mod_pubsub/nodetree_default.erl |  10 +-
       5 files changed, 528 insertions(+), 527 deletions(-)
      
      diff --git a/ChangeLog b/ChangeLog
      index 17685cbf8..be5e8d772 100644
      --- a/ChangeLog
      +++ b/ChangeLog
      @@ -7,6 +7,13 @@
       	* src/gen_iq_handler.erl: Add the module and function names to the
       	error message, when a module crash.
       
      +	* src/mod_pubsub/mod_pubsub.erl, src/mod_pubsub/nodetree_default.erl,
      +	src/mod_pubsub/node_default.erl, src/mod_pubsub/node_pep.erl: First
      +	pass of Exmpp conversion for mod_pubsub. Several modules aren't
      +	converted yet. Existent Mnesia tables written to disc are not
      +	updated. There must be bugs, mostly because of the mix between #jid
      +	record and short JIDs.
      +
       2008-12-03  Jean-Sébastien Pédron  
       
       	* src/mod_proxy65/mod_proxy65_stream.erl,
      diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl
      index a1d6febf2..fed1c3aff 100644
      --- a/src/mod_pubsub/mod_pubsub.erl
      +++ b/src/mod_pubsub/mod_pubsub.erl
      @@ -45,8 +45,9 @@
       -behaviour(gen_server).
       -behaviour(gen_mod).
       
      +-include_lib("exmpp/include/exmpp.hrl").
      +
       -include("ejabberd.hrl").
      --include("jlib.hrl").
       -include("pubsub.hrl").
       
       -define(STDTREE, "default").
      @@ -157,7 +158,7 @@ init([ServerHost, Opts]) ->
           ?DEBUG("pubsub init ~p ~p",[ServerHost,Opts]),
           Host = gen_mod:get_opt_host(ServerHost, Opts, "pubsub.@HOST@"),
           Access = gen_mod:get_opt(access_createnode, Opts, all),
      -    mod_disco:register_feature(ServerHost, ?NS_PUBSUB),
      +    mod_disco:register_feature(ServerHost, ?NS_PUBSUB_s),
           ejabberd_hooks:add(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75),
           ejabberd_hooks:add(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75),
           ejabberd_hooks:add(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75),
      @@ -305,24 +306,24 @@ update_database(Host) ->
       
       identity(Host) ->
           Identity = case lists:member(?PEPNODE, plugins(Host)) of
      -    true -> [{"category", "pubsub"}, {"type", "pep"}];
      -    false -> [{"category", "pubsub"}, {"type", "service"}]
      +    true -> [#xmlattr{name = 'category', value = "pubsub"}, #xmlattr{name = 'type', value = "pep"}];
      +    false -> [#xmlattr{name = 'category', value = "pubsub"}, #xmlattr{name = 'type', value = "service"}]
           end,
      -    {xmlelement, "identity", Identity, []}.
      +    #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = Identity}.
       
       disco_local_identity(Acc, _From, To, [], _Lang) ->
      -    Acc ++ [identity(To#jid.lserver)];
      +    Acc ++ [identity(To#jid.ldomain)];
       disco_local_identity(Acc, _From, _To, _Node, _Lang) ->
           Acc.
       
       disco_local_features(Acc, _From, To, [], _Lang) ->
      -    Host = To#jid.lserver,
      +    Host = To#jid.ldomain,
           Feats = case Acc of
       	{result, I} -> I;
       	_ -> []
           end,
           {result, Feats ++ lists:map(fun(Feature) ->
      -	?NS_PUBSUB++"#"++Feature
      +	?NS_PUBSUB_s++"#"++Feature
           end, features(Host, []))};
       disco_local_features(Acc, _From, _To, _Node, _Lang) ->
           Acc.
      @@ -333,9 +334,9 @@ disco_local_items(Acc, _From, _To, _Node, _Lang) ->
           Acc.
       
       disco_sm_identity(Acc, _From, To, [], _Lang) ->
      -    Acc ++ [identity(To#jid.lserver)];
      +    Acc ++ [identity(To#jid.ldomain)];
       disco_sm_identity(Acc, From, To, Node, _Lang) ->
      -    LOwner = jlib:jid_tolower(jlib:jid_remove_resource(To)),
      +    LOwner = jlib:short_prepd_bare_jid(To),
           Acc ++ case node_disco_identity(LOwner, From, Node) of
       	       {result, I} -> I;
       	       _ -> []
      @@ -344,7 +345,7 @@ disco_sm_identity(Acc, From, To, Node, _Lang) ->
       disco_sm_features(Acc, _From, _To, [], _Lang) ->
           Acc;
       disco_sm_features(Acc, From, To, Node, _Lang) ->
      -    LOwner = jlib:jid_tolower(jlib:jid_remove_resource(To)),
      +    LOwner = jlib:short_prepd_bare_jid(To),
           Features = node_disco_features(LOwner, From, Node),
           case {Acc, Features} of
       	{{result, AccFeatures}, {result, AddFeatures}} ->
      @@ -357,8 +358,8 @@ disco_sm_features(Acc, From, To, Node, _Lang) ->
       
       disco_sm_items(Acc, _From, To, [], _Lang) ->
           %% TODO, use iq_disco_items(Host, [], From)
      -    Host = To#jid.lserver,
      -    LJID = jlib:jid_tolower(jlib:jid_remove_resource(To)),
      +    Host = To#jid.ldomain,
      +    LJID = jlib:short_prepd_bare_jid(To),
           case tree_action(Host, get_nodes, [Host]) of
       	[] ->
       	    Acc;
      @@ -369,18 +370,17 @@ disco_sm_items(Acc, _From, To, [], _Lang) ->
       		    end,
       	    NodeItems = lists:map(
       			  fun(Node) ->
      -				  {xmlelement, "item",
      -				   [{"jid", jlib:jid_to_string(LJID)},
      -				    {"node", node_to_string(Node)}],
      -				   []}
      +				  #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs =
      +				   [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(LJID)},
      +				    #xmlattr{name = 'node', value = node_to_string(Node)}]}
       			  end, Nodes),
       	    {result, NodeItems ++ Items}
           end;
       
       disco_sm_items(Acc, From, To, Node, _Lang) ->
           %% TODO, use iq_disco_items(Host, Node, From)
      -    Host = To#jid.lserver,
      -    LJID = jlib:jid_tolower(jlib:jid_remove_resource(To)),
      +    Host = To#jid.ldomain,
      +    LJID = jlib:short_prepd_bare_jid(To),
           case get_items(Host, Node, From) of
       	[] ->
       	    Acc;
      @@ -393,10 +393,9 @@ disco_sm_items(Acc, From, To, Node, _Lang) ->
       			  fun(#pubsub_item{itemid = Id}) ->
       				  %% "jid" is required by XEP-0030, and
       				  %% "node" is forbidden by XEP-0060.
      -				  {xmlelement, "item",
      -				   [{"jid", jlib:jid_to_string(LJID)},
      -				    {"name", get_item_name(Host, Node, Id)}],
      -				   []}
      +				  #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs =
      +				   [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(LJID)},
      +				    #xmlattr{name = 'name', value = get_item_name(Host, Node, Id)}]}
       			  end, AllItems),
       	    {result, NodeItems ++ Items}
           end.
      @@ -405,7 +404,7 @@ disco_sm_items(Acc, From, To, Node, _Lang) ->
       %% presence hooks handling functions
       %%
       
      -presence_probe(#jid{lserver = Host} = JID, JID, Pid) ->
      +presence_probe(#jid{ldomain = Host} = JID, JID, Pid) ->
           Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
           gen_server:cast(Proc, {presence, JID, Pid});
       presence_probe(_, _, _) ->
      @@ -416,8 +415,8 @@ presence_probe(_, _, _) ->
       %%
       
       remove_user(User, Server) ->
      -    LUser = jlib:nodeprep(User),
      -    LServer = jlib:nameprep(Server),
      +    LUser = exmpp_stringprep:nodeprep(User),
      +    LServer = exmpp_stringprep:nameprep(Server),
           Proc = gen_mod:get_module_proc(Server, ?PROCNAME),
           gen_server:cast(Proc, {remove_user, LUser, LServer}).
       
      @@ -452,7 +451,7 @@ handle_call(stop, _From, State) ->
       %% @private
       handle_cast({presence, JID, Pid}, State) ->
           %% A new resource is available. send last published items
      -    LJID = jlib:jid_tolower(JID),
      +    LJID = jlib:short_prepd_jid(JID),
           Host = State#state.host,
           ServerHost = State#state.server_host,
           %% for each node From is subscribed to
      @@ -484,7 +483,7 @@ handle_cast({presence, JID, Pid}, State) ->
       				fun({{User, Server, _}, _}) -> {User, Server} end, ContactsWithCaps)),
       	    lists:foreach(
       		fun({User, Server}) ->
      -		    PepKey = {User, Server, ""},
      +		    PepKey = {User, Server, undefined},
       		    lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) ->
       			case get_option(Options, send_last_published_item) of
       			    on_sub_and_presence ->
      @@ -500,7 +499,7 @@ handle_cast({presence, JID, Pid}, State) ->
       						element(2, get_roster_info(User, Server, LJID, Grps))
       					end,
       					if Subscribed ->
      -					    ?DEBUG("send ~s's ~s event to ~s",[jlib:jid_to_string(PepKey),Node,jlib:jid_to_string(LJID)]),
      +					    ?DEBUG("send ~s's ~s event to ~s",[exmpp_jid:jid_to_list(User, Server),Node,exmpp_jid:jid_to_list(JID)]),
       					    send_last_item(PepKey, Node, LJID);
       					true ->
       					    ok
      @@ -520,14 +519,14 @@ handle_cast({presence, JID, Pid}, State) ->
       
       handle_cast({remove_user, LUser, LServer}, State) ->
           Host = State#state.host,
      -    Owner = jlib:make_jid(LUser, LServer, ""),
      -    OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
      +    Owner = exmpp_jid:make_bare_jid(LUser, LServer),
      +    OwnerKey = jlib:short_prepd_bare_jid(Owner),
           %% remove user's subscriptions
           lists:foreach(fun(Type) ->
       	{result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, Owner]),
       	lists:foreach(fun
       	    ({Node, subscribed}) ->
      -		JID = jlib:jid_to_string(Owner),
      +		JID = exmpp_jid:jid_to_list(LUser, LServer),
       		unsubscribe_node(Host, Node, Owner, JID, all);
       	    (_) ->  
       		ok
      @@ -555,7 +554,7 @@ handle_info({route, From, To, Packet},
       	    #state{server_host = ServerHost,
       		   access = Access,
       		   plugins = Plugins} = State) ->
      -    case catch do_route(ServerHost, Access, Plugins, To#jid.lserver, From, To, Packet) of
      +    case catch do_route(ServerHost, Access, Plugins, To#jid.ldomain, From, To, Packet) of
       	{'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]);
       	_ -> ok
           end,
      @@ -591,7 +590,7 @@ terminate(_Reason, #state{host = Host,
       			{?NS_PUBSUB_OWNER, ejabberd_local},
       			{?NS_PUBSUB, ejabberd_sm},
       			{?NS_PUBSUB_OWNER, ejabberd_sm}]),
      -    mod_disco:unregister_feature(ServerHost, ?NS_PUBSUB),
      +    mod_disco:unregister_feature(ServerHost, ?NS_PUBSUB_s),
           ok.
       
       %%--------------------------------------------------------------------
      @@ -606,89 +605,86 @@ code_change(_OldVsn, State, _Extra) ->
       %%% Internal functions
       %%--------------------------------------------------------------------
       do_route(ServerHost, Access, Plugins, Host, From, To, Packet) ->
      -    {xmlelement, Name, Attrs, _Els} = Packet,
      +    #xmlel{name = Name} = Packet,
           case To of
      -	#jid{luser = "", lresource = ""} ->
      +	#jid{lnode = undefined, lresource = undefined} ->
       	    case Name of
      -		"iq" ->
      -		    case jlib:iq_query_info(Packet) of
      -			#iq{type = get, xmlns = ?NS_DISCO_INFO,
      -			    sub_el = SubEl, lang = Lang} = IQ ->
      -			    {xmlelement, _, QAttrs, _} = SubEl,
      -			    Node = xml:get_attr_s("node", QAttrs),
      +		'iq' ->
      +		    case exmpp_iq:xmlel_to_iq(Packet) of
      +			#iq{type = get, ns = ?NS_DISCO_INFO,
      +			    payload = SubEl, lang = Lang} ->
      +			    QAttrs = SubEl#xmlel.attrs,
      +			    Node = exmpp_xml:get_attribute_from_list(QAttrs,
      +			      'node', ""),
       			    Res = case iq_disco_info(Host, Node, From, Lang) of
       				      {result, IQRes} ->
      -					  jlib:iq_to_xml(
      -					    IQ#iq{type = result,
      -						  sub_el = [{xmlelement, "query",
      -							     QAttrs, IQRes}]});
      +					  Result = #xmlel{ns = ?NS_DISCO_INFO,
      +					    name = 'query', attrs = QAttrs,
      +					    children = IQRes},
      +					  exmpp_iq:result(Packet, Result);
       				      {error, Error} ->
      -					  jlib:make_error_reply(Packet, Error)
      +					  exmpp_iq:error(Packet, Error)
       				  end,
       			    ejabberd_router:route(To, From, Res);
      -			#iq{type = get, xmlns = ?NS_DISCO_ITEMS,
      -			    sub_el = SubEl} = IQ ->
      -			    {xmlelement, _, QAttrs, _} = SubEl,
      -			    Node = xml:get_attr_s("node", QAttrs),
      +			#iq{type = get, ns = ?NS_DISCO_ITEMS,
      +			    payload = SubEl} ->
      +			    QAttrs = SubEl#xmlel.attrs,
      +			    Node = exmpp_xml:get_attribute_from_list(QAttrs,
      +			      'node', ""),
       			    Res = case iq_disco_items(Host, Node, From) of
       				      {result, IQRes} ->
      -					  jlib:iq_to_xml(
      -					    IQ#iq{type = result,
      -						  sub_el = [{xmlelement, "query",
      -							     QAttrs, IQRes}]});
      +					  Result = #xmlel{ns = ?NS_DISCO_ITEMS,
      +					    name = 'query', attrs = QAttrs,
      +					    children = IQRes},
      +					  exmpp_iq:result(Packet, Result);
       				      {error, Error} ->
      -					  jlib:make_error_reply(Packet, Error)
      +					  exmpp_iq:error(Packet, Error)
       				  end,
       			    ejabberd_router:route(To, From, Res);
      -			#iq{type = IQType, xmlns = ?NS_PUBSUB,
      -			    lang = Lang, sub_el = SubEl} = IQ ->
      +			#iq{type = IQType, ns = ?NS_PUBSUB,
      +			    lang = Lang, payload = SubEl} ->
       			    Res =
       				case iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) of
       				    {result, IQRes} ->
      -					jlib:iq_to_xml(
      -					  IQ#iq{type = result,
      -						sub_el = IQRes});
      +					exmpp_iq:result(Packet, IQRes);
       				    {error, Error} ->
      -					jlib:make_error_reply(Packet, Error)
      +					exmpp_iq:error(Packet, Error)
       				end,
       			    ejabberd_router:route(To, From, Res);
      -			#iq{type = IQType, xmlns = ?NS_PUBSUB_OWNER,
      -			    lang = Lang, sub_el = SubEl} = IQ ->
      +			#iq{type = IQType, ns = ?NS_PUBSUB_OWNER,
      +			    lang = Lang, payload = SubEl} ->
       			    Res =
       				case iq_pubsub_owner(Host, From, IQType, SubEl, Lang) of
       				    {result, IQRes} ->
      -					jlib:iq_to_xml(
      -					  IQ#iq{type = result,
      -						sub_el = IQRes});
      +					exmpp_iq:result(Packet, IQRes);
       				    {error, Error} ->
      -					jlib:make_error_reply(Packet, Error)
      +					exmpp_iq:error(Packet, Error)
       				end,
       			    ejabberd_router:route(To, From, Res);
      -			#iq{type = get, xmlns = ?NS_VCARD = XMLNS,
      -			    lang = Lang, sub_el = _SubEl} = IQ ->
      -			    Res = IQ#iq{type = result,
      -					sub_el = [{xmlelement, "vCard", [{"xmlns", XMLNS}],
      -						   iq_get_vcard(Lang)}]},
      -			    ejabberd_router:route(To, From, jlib:iq_to_xml(Res));
      +			#iq{type = get, ns = ?NS_VCARD = XMLNS,
      +			    lang = Lang} ->
      +			    VCard = #xmlel{ns = XMLNS, name = 'vCard',
      +			      children = iq_get_vcard(Lang)},
      +			    Res = exmpp_iq:result(Packet, VCard),
      +			    ejabberd_router:route(To, From, Res);
       			#iq{} ->
      -			    Err = jlib:make_error_reply(
      -				    Packet,
      -				    ?ERR_FEATURE_NOT_IMPLEMENTED),
      +			    Err = exmpp_iq:error(Packet,
      +			      'feature-not-implemented'),
       			    ejabberd_router:route(To, From, Err);
       			_ ->
       			    ok
       		    end;
      -		"message" ->
      -		    case xml:get_attr_s("type", Attrs) of
      -			"error" ->
      +		'message' ->
      +		    case exmpp_stanza:is_stanza_error(Packet) of
      +			true ->
       			    ok;
      -			_ ->
      +			false ->
       			    case find_authorization_response(Packet) of
       				none ->
       				    ok;
       				invalid ->
       				    ejabberd_router:route(To, From,
      -							  jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST));
      +							  exmpp_message:error(Packet, 'bad-request'));
       				XFields ->
       				    handle_authorization_response(Host, From, To, Packet, XFields)
       			    end
      @@ -697,13 +693,14 @@ do_route(ServerHost, Access, Plugins, Host, From, To, Packet) ->
       		    ok
       	    end;
       	_ ->
      -	    case xml:get_attr_s("type", Attrs) of
      +	    case exmpp_stanza:get_type(Packet) of
       		"error" ->
       		    ok;
       		"result" ->
       		    ok;
       		_ ->
      -		    Err = jlib:make_error_reply(Packet, ?ERR_ITEM_NOT_FOUND),
      +		    Err = exmpp_stanza:reply_with_error(Packet,
      +		      'item-not-found'),
       		    ejabberd_router:route(To, From, Err)
       	    end
           end.
      @@ -733,17 +730,17 @@ node_disco_info(Host, Node, From, Identity, Features) ->
       					end
       				end,
       			    lists:map(fun(T) ->
      -					      {xmlelement, "identity", [{"category", "pubsub"},
      -									{"type", T}], []}
      +					      #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [#xmlattr{name = 'category', value = "pubsub"},
      +									#xmlattr{name = 'type', value = T}]}
       				      end, Types)
       		    end,
       		F = case Features of
       			false ->
       			    [];
       			true ->
      -			    [{xmlelement, "feature", [{"var", ?NS_PUBSUB}], []} |
      +			    [#xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [#xmlattr{name = 'var', value = ?NS_PUBSUB_s}]} |
       			     lists:map(fun(T) ->
      -					       {xmlelement, "feature", [{"var", ?NS_PUBSUB++"#"++T}], []}
      +					       #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [#xmlattr{name = 'var', value = ?NS_PUBSUB_s++"#"++T}]}
       				       end, features(Type))]
       		    end,
       		%% TODO: add meta-data info (spec section 5.4)
      @@ -756,16 +753,16 @@ iq_disco_info(Host, SNode, From, Lang) ->
           case Node of
       	[] ->
       	    {result,
      -	     [{xmlelement, "identity",
      -	       [{"category", "pubsub"},
      -		{"type", "service"},
      -		{"name", translate:translate(Lang, "Publish-Subscribe")}], []},
      -	      {xmlelement, "feature", [{"var", ?NS_DISCO_INFO}], []},
      -	      {xmlelement, "feature", [{"var", ?NS_DISCO_ITEMS}], []},
      -	      {xmlelement, "feature", [{"var", ?NS_PUBSUB}], []},
      -	      {xmlelement, "feature", [{"var", ?NS_VCARD}], []}] ++
      +	     [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs =
      +	       [#xmlattr{name = 'category', value = "pubsub"},
      +		#xmlattr{name = 'type', value = "service"},
      +		#xmlattr{name = 'name', value = translate:translate(Lang, "Publish-Subscribe")}]},
      +	      #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [#xmlattr{name = 'var', value = ?NS_DISCO_INFO_s}]},
      +	      #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [#xmlattr{name = 'var', value = ?NS_DISCO_ITEMS_s}]},
      +	      #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [#xmlattr{name = 'var', value = ?NS_PUBSUB_s}]},
      +	      #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [#xmlattr{name = 'var', value = ?NS_VCARD_s}]}] ++
       	     lists:map(fun(Feature) ->
      -		 {xmlelement, "feature", [{"var", ?NS_PUBSUB++"#"++Feature}], []}
      +		 #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [#xmlattr{name = 'var', value = ?NS_PUBSUB_s++"#"++Feature}]}
       	     end, features(Host, SNode))};
       	_ ->
       	    node_disco_info(Host, Node, From)
      @@ -777,9 +774,9 @@ iq_disco_items(Host, [], From) ->
       		       SN = node_to_string(SubNode),
       		       RN = lists:last(SubNode),
       		       %% remove name attribute
      -		       {xmlelement, "item", [{"jid", Host},
      -					     {"node", SN},
      -					     {"name", RN}], []}
      +		       #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [#xmlattr{name = 'jid', value = Host},
      +					     #xmlattr{name = 'node', value = SN},
      +					     #xmlattr{name = 'name', value = RN}]}
       	       end, tree_action(Host, get_subnodes, [Host, [], From]))};
       iq_disco_items(Host, Item, From) ->
           case string:tokens(Item, "!") of
      @@ -801,14 +798,14 @@ iq_disco_items(Host, Item, From) ->
       				  fun(#pubsub_node{nodeid = {_, SubNode}}) ->
       					  SN = node_to_string(SubNode),
       					  RN = lists:last(SubNode),
      -					  {xmlelement, "item", [{"jid", Host}, {"node", SN}, 
      -								{"name", RN}], []}
      +					  #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [#xmlattr{name = 'jid', value = Host}, #xmlattr{name = 'node', value = SN}, 
      +								#xmlattr{name = 'name', value = RN}]}
       				  end, tree_call(Host, get_subnodes, [Host, Node, From])),
       			Items = lists:map(
       				  fun(#pubsub_item{itemid = {RN, _}}) ->
       					  SN = node_to_string(Node) ++ "!" ++ RN,
      -					  {xmlelement, "item", [{"jid", Host}, {"node", SN},
      -								{"name", get_item_name(Host, Node, RN)}], []}
      +					  #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [#xmlattr{name = 'jid', value = Host}, #xmlattr{name = 'node', value = SN},
      +								#xmlattr{name = 'name', value = get_item_name(Host, Node, RN)}]}
       				  end, NodeItems),
       			{result, Nodes ++ Items}
       		end,
      @@ -816,69 +813,70 @@ iq_disco_items(Host, Item, From) ->
           end.
       
       iq_local(From, To, #iq{type = Type,
      -		       sub_el = SubEl,
      -		       xmlns = XMLNS,
      -		       lang = Lang} = IQ) ->
      -    ServerHost = To#jid.lserver,
      +		       payload = SubEl,
      +		       ns = XMLNS,
      +		       lang = Lang} = IQ_Rec) ->
      +    ServerHost = To#jid.ldomain,
           %% Accept IQs to server only from our own users.
           if
      -	From#jid.lserver /= ServerHost ->
      -	    IQ#iq{type = error, sub_el = [?ERR_FORBIDDEN, SubEl]};
      +	From#jid.ldomain /= ServerHost ->
      +	    exmpp_iq:error(IQ_Rec, 'forbidden');
       	true ->
      -	    LOwner = jlib:jid_tolower(jlib:jid_remove_resource(From)),
      +	    LOwner = jlib:short_prepd_bare_jid(From),
       	    Res = case XMLNS of
       		      ?NS_PUBSUB -> iq_pubsub(LOwner, ServerHost, From, Type, SubEl, Lang);
       		      ?NS_PUBSUB_OWNER -> iq_pubsub_owner(LOwner, From, Type, SubEl, Lang)
       		  end,
       	    case Res of
      -		{result, IQRes} -> IQ#iq{type = result, sub_el = IQRes};
      -		{error, Error} -> IQ#iq{type = error, sub_el = [Error, SubEl]}
      +		{result, []}      -> exmpp_iq:result(IQ_Rec);
      +		{result, [IQRes]} -> exmpp_iq:result(IQ_Rec, IQRes);
      +		{error, Error}    -> exmpp_iq:error(IQ_Rec, Error)
       	    end
           end.
       
      -iq_sm(From, To, #iq{type = Type, sub_el = SubEl, xmlns = XMLNS, lang = Lang} = IQ) ->
      -    ServerHost = To#jid.lserver,
      -    LOwner = jlib:jid_tolower(jlib:jid_remove_resource(To)),
      +iq_sm(From, To, #iq{type = Type, payload = SubEl, ns = XMLNS, lang = Lang} = IQ_Rec) ->
      +    ServerHost = To#jid.ldomain,
      +    LOwner = jlib:short_prepd_bare_jid(To),
           Res = case XMLNS of
       	      ?NS_PUBSUB -> iq_pubsub(LOwner, ServerHost, From, Type, SubEl, Lang);
       	      ?NS_PUBSUB_OWNER -> iq_pubsub_owner(LOwner, From, Type, SubEl, Lang)
       	  end,
           case Res of
      -	{result, IQRes} -> IQ#iq{type = result, sub_el = IQRes};
      -	{error, Error} -> IQ#iq{type = error, sub_el = [Error, SubEl]}
      +	{result, []}      -> exmpp_iq:result(IQ_Rec);
      +	{result, [IQRes]} -> exmpp_iq:result(IQ_Rec, IQRes);
      +	{error, Error}    -> exmpp_iq:error(IQ_Rec, Error)
           end.
       
       iq_get_vcard(Lang) ->
      -    [{xmlelement, "FN", [], [{xmlcdata, "ejabberd/mod_pubsub"}]},
      -     {xmlelement, "URL", [], [{xmlcdata, ?EJABBERD_URI}]},
      -     {xmlelement, "DESC", [],
      -      [{xmlcdata,
      +    [#xmlel{ns = ?NS_VCARD, name = 'FN', children = [#xmlcdata{cdata = <<"ejabberd/mod_pubsub">>}]},
      +     #xmlel{ns = ?NS_VCARD, name = 'URL', children = [#xmlcdata{cdata = list_to_binary(?EJABBERD_URI)}]},
      +     #xmlel{ns = ?NS_VCARD, name = 'DESC', children =
      +      [#xmlcdata{cdata = list_to_binary(
       	translate:translate(Lang,
       			    "ejabberd Publish-Subscribe module") ++
      -			    "\nCopyright (c) 2004-2008 Process-One"}]}].
      +			    "\nCopyright (c) 2004-2008 Process-One")}]}].
       
       iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang) ->
           iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, all, plugins(ServerHost)).
       
       iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) ->
      -    {xmlelement, _, _, SubEls} = SubEl,
      -    WithoutCdata = xml:remove_cdata(SubEls),
      -    Configuration = lists:filter(fun({xmlelement, Name, _, _}) ->
      -					 Name == "configure"
      +    WithoutCdata = exmpp_xml:remove_cdata_from_list(SubEl#xmlel.children),
      +    Configuration = lists:filter(fun(#xmlel{name = 'configure'}) -> true;
      +				    (_) -> false
       				 end, WithoutCdata),
           Action = WithoutCdata -- Configuration,
           case Action of
      -	[{xmlelement, Name, Attrs, Els}] ->
      +	[#xmlel{name = Name, attrs = Attrs, children = Els}] ->
       	    Node = case Host of
      -		       {_, _, _} -> xml:get_attr_s("node", Attrs);
      -		       _ -> string_to_node(xml:get_attr_s("node", Attrs))
      +		       {_, _, _} -> exmpp_xml:get_attribute_from_list(Attrs, 'node', false);
      +		       _ -> string_to_node(exmpp_xml:get_attribute_from_list(Attrs, 'node', false))
       		   end,
       	    case {IQType, Name} of
      -		{set, "create"} ->
      +		{set, 'create'} ->
       		    case Configuration of
      -			[{xmlelement, "configure", _, Config}] ->
      +			[#xmlel{name = 'configure', children = Config}] ->
       			    %% Get the type of the node
      -			    Type = case xml:get_attr_s("type", Attrs) of
      +			    Type = case exmpp_xml:get_attribute_from_list(Attrs, 'type', "") of
       				       [] -> hd(Plugins);
       				       T -> T
       				   end,
      @@ -887,7 +885,7 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) ->
       			    case lists:member(Type, Plugins) of
       				false ->
       				    {error, extended_error(
      -					      ?ERR_FEATURE_NOT_IMPLEMENTED,
      +					      'feature-not-implemented',
       					      unsupported, "create-nodes")};
       				true ->
       				    create_node(Host, ServerHost, Node, From,
      @@ -898,139 +896,139 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) ->
       			    %% can not create node without 
       			    %% but this is the new spec anyway
       			    ?INFO_MSG("Node ~p ; invalid configuration: ~p", [Node, Configuration]),
      -			    {error, ?ERR_BAD_REQUEST}
      +			    {error, 'bad-request'}
       		    end;
      -		{set, "publish"} ->
      -		    case xml:remove_cdata(Els) of
      -			[{xmlelement, "item", ItemAttrs, Payload}] ->
      -			    ItemId = xml:get_attr_s("id", ItemAttrs),
      +		{set, 'publish'} ->
      +		    case exmpp_xml:remove_cdata_from_list(Els) of
      +			[#xmlel{name = 'item', attrs = ItemAttrs, children = Payload}] ->
      +			    ItemId = exmpp_xml:get_attribute_from_list(ItemAttrs, 'id', ""),
       			    publish_item(Host, ServerHost, Node, From, ItemId, Payload);
       			[] ->
       			    %% Publisher attempts to publish to persistent node with no item
      -			    {error, extended_error(?ERR_BAD_REQUEST,
      +			    {error, extended_error('bad-request',
       						   "item-required")};
       			_ ->
       			    %% Entity attempts to publish item with multiple payload elements or namespace does not match
      -			    {error, extended_error(?ERR_BAD_REQUEST,
      +			    {error, extended_error('bad-request',
       						   "invalid-payload")}
       		    end;
      -		{set, "retract"} ->
      -		    ForceNotify = case xml:get_attr_s("notify", Attrs) of
      +		{set, 'retract'} ->
      +		    ForceNotify = case exmpp_xml:get_attribute_from_list(Attrs, 'notify', "") of
       				      "1" -> true;
       				      "true" -> true;
       				      _ -> false
       				  end,
      -		    case xml:remove_cdata(Els) of
      -			[{xmlelement, "item", ItemAttrs, _}] ->
      -			    ItemId = xml:get_attr_s("id", ItemAttrs),
      +		    case exmpp_xml:remove_cdata_from_list(Els) of
      +			[#xmlel{name = 'item', attrs = ItemAttrs}] ->
      +			    ItemId = exmpp_xml:get_attribute_from_list(ItemAttrs, 'id', ""),
       			    delete_item(Host, Node, From, ItemId, ForceNotify);
       			_ ->
       			    %% Request does not specify an item
      -			    {error, extended_error(?ERR_BAD_REQUEST,
      +			    {error, extended_error('bad-request',
       						   "item-required")}
       		    end;
      -		{set, "subscribe"} ->
      -		    JID = xml:get_attr_s("jid", Attrs),
      +		{set, 'subscribe'} ->
      +		    JID = exmpp_xml:get_attribute_from_list(Attrs, 'jid', ""),
       		    subscribe_node(Host, Node, From, JID);
      -		{set, "unsubscribe"} ->
      -		    JID = xml:get_attr_s("jid", Attrs),
      -		    SubId = xml:get_attr_s("subid", Attrs),
      +		{set, 'unsubscribe'} ->
      +		    JID = exmpp_xml:get_attribute_from_list(Attrs, 'jid', ""),
      +		    SubId = exmpp_xml:get_attribute_from_list(Attrs, 'subid', ""),
       		    unsubscribe_node(Host, Node, From, JID, SubId);
      -		{get, "items"} ->
      -		    MaxItems = xml:get_attr_s("max_items", Attrs),
      -		    SubId = xml:get_attr_s("subid", Attrs),
      +		{get, 'items'} ->
      +		    MaxItems = exmpp_xml:get_attribute_from_list(Attrs, 'max_items', ""),
      +		    SubId = exmpp_xml:get_attribute_from_list(Attrs, 'subid', ""),
       		    ItemIDs = lists:foldl(fun
      -			({xmlelement, "item", ItemAttrs, _}, Acc) ->
      -			    case xml:get_attr_s("id", ItemAttrs) of
      +			(#xmlel{name = 'item', attrs = ItemAttrs}, Acc) ->
      +			    case exmpp_xml:get_attribute_from_list(ItemAttrs, 'id', "") of
       			    "" -> Acc;
       			    ItemID -> [ItemID|Acc]
       			    end;
       			(_, Acc) ->
       			    Acc
      -			end, [], xml:remove_cdata(Els)),
      +			end, [], exmpp_xml:remove_cdata_from_list(Els)),
       		    get_items(Host, Node, From, SubId, MaxItems, ItemIDs);
      -		{get, "subscriptions"} ->
      +		{get, 'subscriptions'} ->
       		    get_subscriptions(Host, From, Plugins);
      -		{get, "affiliations"} ->
      +		{get, 'affiliations'} ->
       		    get_affiliations(Host, From, Plugins);
       		_ ->
      -		    {error, ?ERR_FEATURE_NOT_IMPLEMENTED}
      +		    {error, 'feature-not-implemented'}
       	    end;
       	_ ->
       	    ?INFO_MSG("Too many actions: ~p", [Action]),
      -	    {error, ?ERR_BAD_REQUEST}
      +	    {error, 'bad-request'}
           end.
       
       iq_pubsub_owner(Host, From, IQType, SubEl, Lang) ->
      -    {xmlelement, _, _, SubEls} = SubEl,
      -    Action = xml:remove_cdata(SubEls),
      +    SubEls = SubEl#xmlel.children,
      +    Action = exmpp_xml:remove_cdata_from_list(SubEls),
           case Action of
      -	[{xmlelement, Name, Attrs, Els}] ->
      +	[#xmlel{name = Name, attrs = Attrs, children = Els}] ->
       	    Node = case Host of
      -		       {_, _, _} -> xml:get_attr_s("node", Attrs);
      -		       _ -> string_to_node(xml:get_attr_s("node", Attrs))
      +		       {_, _, _} -> exmpp_xml:get_attribute_from_list(Attrs, 'node', "");
      +		       _ -> string_to_node(exmpp_xml:get_attribute_from_list(Attrs, 'node', ""))
       		   end,
       	    case {IQType, Name} of
      -		{get, "configure"} ->
      +		{get, 'configure'} ->
       		    get_configure(Host, Node, From, Lang);
      -		{set, "configure"} ->
      +		{set, 'configure'} ->
       		    set_configure(Host, Node, From, Els, Lang);
      -		{get, "default"} ->
      +		{get, 'default'} ->
       		    get_default(Host, Node, From, Lang);
      -		{set, "delete"} ->
      +		{set, 'delete'} ->
       		    delete_node(Host, Node, From);
      -		{set, "purge"} ->
      +		{set, 'purge'} ->
       		    purge_node(Host, Node, From);
      -		{get, "subscriptions"} ->
      +		{get, 'subscriptions'} ->
       		    get_subscriptions(Host, Node, From);
      -		{set, "subscriptions"} ->
      -		    set_subscriptions(Host, Node, From, xml:remove_cdata(Els));
      -		{get, "affiliations"} ->
      +		{set, 'subscriptions'} ->
      +		    set_subscriptions(Host, Node, From, exmpp_xml:remove_cdata_from_list(Els));
      +		{get, 'affiliations'} ->
       		    get_affiliations(Host, Node, From);
      -		{set, "affiliations"} ->
      -		    set_affiliations(Host, Node, From, xml:remove_cdata(Els));
      +		{set, 'affiliations'} ->
      +		    set_affiliations(Host, Node, From, exmpp_xml:remove_cdata_from_list(Els));
       		_ ->
      -		    {error, ?ERR_FEATURE_NOT_IMPLEMENTED}
      +		    {error, 'feature-not-implemented'}
       	    end;
       	_ ->
       	    ?INFO_MSG("Too many actions: ~p", [Action]),
      -	    {error, ?ERR_BAD_REQUEST}
      +	    {error, 'bad-request'}
           end.
       
       %%% authorization handling
       
       send_authorization_request(Host, Node, Subscriber) ->
           Lang = "en", %% TODO fix
      -    Stanza = {xmlelement, "message",
      -	      [],
      -	      [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}],
      -		[{xmlelement, "title", [],
      -		  [{xmlcdata, translate:translate(Lang, "PubSub subscriber request")}]},
      -		 {xmlelement, "instructions", [],
      -		  [{xmlcdata, translate:translate(Lang, "Choose whether to approve this entity's subscription.")}]},
      -		 {xmlelement, "field",
      -		  [{"var", "FORM_TYPE"}, {"type", "hidden"}],
      -		  [{xmlelement, "value", [], [{xmlcdata, ?NS_PUBSUB_SUB_AUTH}]}]},
      -		 {xmlelement, "field",
      -		  [{"var", "pubsub#node"}, {"type", "text-single"},
      -		   {"label", translate:translate(Lang, "Node ID")}],
      -		  [{xmlelement, "value", [],
      -		    [{xmlcdata, node_to_string(Node)}]}]},
      -		 {xmlelement, "field", [{"var", "pubsub#subscriber_jid"},
      -					{"type", "jid-single"},
      -					{"label", translate:translate(Lang, "Subscriber Address")}],
      -		  [{xmlelement, "value", [],
      -		    [{xmlcdata, jlib:jid_to_string(Subscriber)}]}]},
      -		 {xmlelement, "field",
      -		  [{"var", "pubsub#allow"},
      -		   {"type", "boolean"},
      -		   {"label", translate:translate(Lang, "Allow this JID to subscribe to this pubsub node?")}],
      -		  [{xmlelement, "value", [], [{xmlcdata, "false"}]}]}]}]},
      +    {U, S, R} = Subscriber,
      +    Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children =
      +	      [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', value = "form"}], children =
      +		[#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children =
      +		  [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "PubSub subscriber request"))}]},
      +		 #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children =
      +		  [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Choose whether to approve this entity's subscription."))}]},
      +		 #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs =
      +		  [#xmlattr{name = 'var', value = "FORM_TYPE"}, #xmlattr{name = 'type', value = "hidden"}], children =
      +		  [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(?NS_PUBSUB_SUBSCRIBE_AUTH_s)}]}]},
      +		 #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs =
      +		  [#xmlattr{name = 'var', value = "pubsub#node"}, #xmlattr{name = 'type', value = "text-single"},
      +		   #xmlattr{name = 'label', value = translate:translate(Lang, "Node ID")}], children =
      +		  [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children =
      +		    [#xmlcdata{cdata = node_to_string(Node)}]}]},
      +		 #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'var', value = "pubsub#subscriber_jid"},
      +					#xmlattr{name = 'type', value = "jid-single"},
      +					#xmlattr{name = 'label', value = translate:translate(Lang, "Subscriber Address")}], children =
      +		  [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children =
      +		    [#xmlcdata{cdata = exmpp_jid:jid_to_binary(U, S, R)}]}]},
      +		 #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs =
      +		  [#xmlattr{name = 'var', value = "pubsub#allow"},
      +		   #xmlattr{name = 'type', value = "boolean"},
      +		   #xmlattr{name = 'label', value = translate:translate(Lang, "Allow this JID to subscribe to this pubsub node?")}], children =
      +		  [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"false">>}]}]}]}]},
           case tree_action(Host, get_node, [Host, Node]) of
       	#pubsub_node{owners = Owners} ->
       	    lists:foreach(
      -	      fun(Owner) ->
      -		      ejabberd_router ! {route, service_jid(Host), jlib:make_jid(Owner), Stanza}
      +	      fun({U1, S1, R1}) ->
      +		      ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(U1, S1, R1), Stanza}
       	      end, Owners),
       	    ok;
       	_ ->
      @@ -1038,29 +1036,24 @@ send_authorization_request(Host, Node, Subscriber) ->
           end.
       
       find_authorization_response(Packet) ->
      -    {xmlelement, _Name, _Attrs, Els} = Packet,
      -    XData1 = lists:map(fun({xmlelement, "x", XAttrs, _} = XEl) ->
      -			       case xml:get_attr_s("xmlns", XAttrs) of
      -				   ?NS_XDATA ->
      -				       case xml:get_attr_s("type", XAttrs) of
      -					   "cancel" ->
      -					       none;
      -					   _ ->
      -					       jlib:parse_xdata_submit(XEl)
      -				       end;
      +    Els = Packet#xmlel.children,
      +    XData1 = lists:map(fun(#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = XAttrs} = XEl) ->
      +			       case exmpp_xml:get_attribute_from_list(XAttrs, 'type', "") of
      +				   "cancel" ->
      +				       none;
       				   _ ->
      -				       none
      +				       jlib:parse_xdata_submit(XEl)
       			       end;
       			  (_) ->
       			       none
      -		       end, xml:remove_cdata(Els)),
      +		       end, exmpp_xml:remove_cdata(Els)),
           XData = lists:filter(fun(E) -> E /= none end, XData1),
           case XData of
       	[invalid] -> invalid;
       	[] -> none;
       	[XFields] when is_list(XFields) ->
       	    case lists:keysearch("FORM_TYPE", 1, XFields) of
      -		{value, {_, ?NS_PUBSUB_SUB_AUTH}} ->
      +		{value, {_, ?NS_PUBSUB_SUBSCRIBE_AUTH_s}} ->
       		    XFields;
       		_ ->
       		    invalid
      @@ -1077,7 +1070,7 @@ handle_authorization_response(Host, From, To, Packet, XFields) ->
       		       {_, _, _} -> [SNode];
       		       _ -> string:tokens(SNode, "/")
       		   end,
      -	    Subscriber = jlib:string_to_jid(SSubscriber),
      +	    Subscriber = exmpp_jid:list_to_jid(SSubscriber),
       	    Allow = case SAllow of
       			"1" -> true;
       			"true" -> true;
      @@ -1086,13 +1079,13 @@ handle_authorization_response(Host, From, To, Packet, XFields) ->
       	    Action = fun(#pubsub_node{type = Type,
       				      %%options = Options,
       				      owners = Owners}) ->
      -			     IsApprover = lists:member(jlib:jid_tolower(jlib:jid_remove_resource(From)), Owners),
      +			     IsApprover = lists:member(jlib:short_prepd_bare_jid(From), Owners),
       			     Subscription = node_call(Type, get_subscription, [Host, Node, Subscriber]),
       			     if
       				 not IsApprover ->
      -				     {error, ?ERR_FORBIDDEN};
      +				     {error, 'forbidden'};
       				 Subscription /= pending ->
      -				     {error, ?ERR_UNEXPECTED_REQUEST};
      +				     {error, 'unexpected-request'};
       				 true ->
       				     NewSubscription = case Allow of
       							   true -> subscribed;
      @@ -1105,26 +1098,26 @@ handle_authorization_response(Host, From, To, Packet, XFields) ->
       		{error, Error} ->
       		    ejabberd_router:route(
       		     To, From,
      -		     jlib:make_error_reply(Packet, Error));
      +		     exmpp_stanza:reply_with_error(Packet, Error));
       		{result, _NewSubscription} ->
       		    %% XXX: notify about subscription state change, section 12.11
       		    ok;
       		_ ->
       		    ejabberd_router:route(
       		      To, From,
      -		      jlib:make_error_reply(Packet, ?ERR_INTERNAL_SERVER_ERROR))
      +		      exmpp_stanza:reply_with_error(Packet, 'internal-server-error'))
       	    end;
       	_ ->
       	    ejabberd_router:route(
       	      To, From,
      -	      jlib:make_error_reply(Packet, ?ERR_NOT_ACCEPTABLE))
      +	      exmpp_stanza:reply_with_error(Packet, 'not-acceptable'))
           end.
       
       -define(XFIELD(Type, Label, Var, Val),
      -	{xmlelement, "field", [{"type", Type},
      -			       {"label", translate:translate(Lang, Label)},
      -			       {"var", Var}],
      -	 [{xmlelement, "value", [], [{xmlcdata, Val}]}]}).
      +	#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type},
      +			       #xmlattr{name = 'label', value = translate:translate(Lang, Label)},
      +			       #xmlattr{name = 'var', value = Var}], children =
      +	 [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Val)}]}]}).
       
       -define(BOOLXFIELD(Label, Var, Val),
       	?XFIELD("boolean", Label, Var,
      @@ -1137,15 +1130,15 @@ handle_authorization_response(Host, From, To, Packet, XFields) ->
       	?XFIELD("text-single", Label, Var, Val)).
       
       -define(XFIELDOPT(Type, Label, Var, Val, Opts),
      -	{xmlelement, "field", [{"type", Type},
      -			       {"label", translate:translate(Lang, Label)},
      -			       {"var", Var}],
      +	#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type},
      +			       #xmlattr{name = 'label', value = translate:translate(Lang, Label)},
      +			       #xmlattr{name = 'var', value = Var}], children =
       	 lists:map(fun(Opt) ->
      -			   {xmlelement, "option", [],
      -			    [{xmlelement, "value", [],
      -			      [{xmlcdata, Opt}]}]}
      +			   #xmlel{ns = ?NS_DATA_FORMS, name = 'option', children =
      +			    [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children =
      +			      [#xmlcdata{cdata = list_to_binary(Opt)}]}]}
       		   end, Opts) ++
      -	 [{xmlelement, "value", [], [{xmlcdata, Val}]}]}).
      +	 [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Val)}]}]}).
       
       -define(LISTXFIELD(Label, Var, Val, Opts),
       	?XFIELDOPT("list-single", Label, Var, Val, Opts)).
      @@ -1176,7 +1169,7 @@ create_node(Host, ServerHost, Node, Owner, Type) ->
       create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) ->
           case lists:member("instant-nodes", features(Type)) of
       	true ->
      -	    {LOU, LOS, _} = jlib:jid_tolower(Owner),
      +	    {LOU, LOS, _} = jlib:short_prepd_jid(Owner),
       	    HomeNode = ["home", LOS, LOU],
       	    create_node(Host, ServerHost,
       			HomeNode, Owner, Type, Access, Configuration),
      @@ -1185,25 +1178,25 @@ create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) ->
       			     NewNode, Owner, Type, Access, Configuration) of
       		{result, []} ->
       		    {result,
      -		     [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
      -		       [{xmlelement, "create", [{"node", node_to_string(NewNode)}], []}]}]};
      +		     [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children =
      +		       [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = [#xmlattr{name = 'node', value = node_to_string(NewNode)}]}]}]};
       		Error -> Error
       	    end;
       	false ->
       	    %% Service does not support instant nodes
      -	    {error, extended_error(?ERR_NOT_ACCEPTABLE, "nodeid-required")}
      +	    {error, extended_error('not-acceptable', "nodeid-required")}
           end;
       create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
           Type = select_type(ServerHost, Host, Node, GivenType),
           Parent = lists:sublist(Node, length(Node) - 1),
           %% TODO, check/set node_type = Type
      -    ParseOptions = case xml:remove_cdata(Configuration) of
      +    ParseOptions = case exmpp_xml:remove_cdata_from_list(Configuration) of
       		       [] ->
       			   {result, node_options(Type)};
      -		       [{xmlelement, "x", _Attrs, _SubEls} = XEl] ->
      +		       [#xmlel{name = 'x'} = XEl] ->
       			   case jlib:parse_xdata_submit(XEl) of
       			       invalid ->
      -				   {error, ?ERR_BAD_REQUEST};
      +				   {error, 'bad-request'};
       			       XData ->
       				   case set_xoption(XData, node_options(Type)) of
       				       NewOpts when is_list(NewOpts) ->
      @@ -1214,7 +1207,7 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
       			   end;
       		       _ ->
       			   ?INFO_MSG("Node ~p; bad configuration: ~p", [Node, Configuration]),
      -			   {error, ?ERR_BAD_REQUEST}
      +			   {error, 'bad-request'}
       		   end,
           case ParseOptions of
       	{result, NodeOptions} ->
      @@ -1225,21 +1218,20 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
       				case tree_call(Host, create_node, [Host, Node, Type, Owner, NodeOptions]) of
       				    ok ->
       					node_call(Type, create_node, [Host, Node, Owner]);
      -				    {error, ?ERR_CONFLICT} ->
      +				    {error, 'conflict'} ->
       					case ets:lookup(gen_mod:get_module_proc(ServerHost, pubsub_state), nodetree) of
       					    [{nodetree, nodetree_virtual}] -> node_call(Type, create_node, [Host, Node, Owner]);
      -					    _ -> {error, ?ERR_CONFLICT}
      +					    _ -> {error, 'conflict'}
       					end;
       				    Error ->
       					Error
       				end;
       			    _ ->
      -				{error, ?ERR_FORBIDDEN}
      +				{error, 'forbidden'}
       			end
       		end,
      -	    Reply = [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
      -		      [{xmlelement, "create", [{"node", node_to_string(Node)}],
      -			[]}]}],
      +	    Reply = [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children =
      +		      [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}]}]}],
       	    case transaction(CreateNode, transaction) of
       		{error, Error} ->
       		    %% in case we change transaction to sync_dirty...
      @@ -1251,7 +1243,7 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
       		    %%Lang = "en", %% TODO: fix
       		    %%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
       		    %%broadcast_publish_item(Host, Node, uniqid(), Owner,
      -		    %%	[{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "result"}],
      +		    %%	[{xmlelement, "x", [{"xmlns", ?NS_DATA_FORMS}, {"type", "result"}],
       		    %%		[?XFIELD("hidden", "", "FORM_TYPE", ?NS_PUBSUB_NMI),
       		    %%		?XFIELD("jid-single", "Node Creator", "creator", jlib:jid_to_string(OwnerKey))]}]),
       		    %% todo publish_item(Host, ServerHost, ["pubsub", "nodes"], node_to_string(Node)),
      @@ -1283,7 +1275,7 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
       %%
       delete_node(_Host, [], _Owner) ->
           %% Node is the root
      -    {error, ?ERR_NOT_ALLOWED};
      +    {error, 'not-allowed'};
       delete_node(Host, Node, Owner) ->
           Action = fun(#pubsub_node{type = Type}) ->
       		     case node_call(Type, get_affiliation, [Host, Node, Owner]) of
      @@ -1292,7 +1284,7 @@ delete_node(Host, Node, Owner) ->
       			     node_call(Type, delete_node, [Host, Removed]);
       			 _ ->
       			     %% Entity is not an owner
      -			     {error, ?ERR_FORBIDDEN}
      +			     {error, 'forbidden'}
       		     end
       	     end,
           Reply = [],
      @@ -1341,10 +1333,12 @@ delete_node(Host, Node, Owner) ->
       %%
    • The node does not exist.
    • %% subscribe_node(Host, Node, From, JID) -> - Subscriber = case jlib:string_to_jid(JID) of - error -> {"", "", ""}; - J -> jlib:jid_tolower(J) - end, + Subscriber = try + jlib:short_prepd_jid(exmpp_jid:list_to_jid(JID)) + catch + _:_ -> + {undefined, undefined, undefined} + end, SubId = uniqid(), Action = fun(#pubsub_node{options = Options, type = Type}) -> Features = features(Type), @@ -1364,10 +1358,10 @@ subscribe_node(Host, Node, From, JID) -> if not SubscribeFeature -> %% Node does not support subscriptions - {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "subscribe")}; + {error, extended_error('feature-not-implemented', unsupported, "subscribe")}; not SubscribeConfig -> %% Node does not support subscriptions - {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "subscribe")}; + {error, extended_error('feature-not-implemented', unsupported, "subscribe")}; true -> node_call(Type, subscribe_node, [Host, Node, From, Subscriber, @@ -1378,15 +1372,15 @@ subscribe_node(Host, Node, From, JID) -> Reply = fun(Subscription) -> %% TODO, this is subscription-notification, should depends on node features Fields = - [{"node", node_to_string(Node)}, - {"jid", jlib:jid_to_string(Subscriber)}, - {"subscription", subscription_to_string(Subscription)}], - [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], - [{xmlelement, "subscription", + [#xmlattr{name = 'node', value = node_to_string(Node)}, + #xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(Subscriber)}, + #xmlattr{name = 'subscription', value = subscription_to_string(Subscription)}], + [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = case Subscription of - subscribed -> [{"subid", SubId}|Fields]; + subscribed -> [#xmlattr{name = 'subid', value = SubId}|Fields]; _ -> Fields - end, []}]}] + end}]}] end, case transaction(Host, Node, Action, sync_dirty) of {error, Error} -> @@ -1428,10 +1422,12 @@ subscribe_node(Host, Node, From, JID) -> %%
    • The request specifies a subscription ID that is not valid or current.
    • %% unsubscribe_node(Host, Node, From, JID, SubId) -> - Subscriber = case jlib:string_to_jid(JID) of - error -> {"", "", ""}; - J -> jlib:jid_tolower(J) - end, + Subscriber = try + jlib:short_prepd_jid(exmpp_jid:list_to_jid(JID)) + catch + _:_ -> + {undefined, undefined, undefined} + end, case node_action(Host, Node, unsubscribe_node, [Host, Node, From, Subscriber, SubId]) of {error, Error} -> @@ -1470,21 +1466,21 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> if not PublishFeature -> %% Node does not support item publication - {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "publish")}; + {error, extended_error('feature-not-implemented', unsupported, "publish")}; PayloadSize > PayloadMaxSize -> %% Entity attempts to publish very large payload - {error, extended_error(?ERR_NOT_ACCEPTABLE, "payload-too-big")}; + {error, extended_error('not-acceptable', "payload-too-big")}; %%?? -> iq_pubsub just does that matchs %% % Entity attempts to publish item with multiple payload elements or namespace does not match - %% {error, extended_error(?ERR_BAD_REQUEST, "invalid-payload")}; + %% {error, extended_error('bad-request', "invalid-payload")}; %% % Publisher attempts to publish to persistent node with no item - %% {error, extended_error(?ERR_BAD_REQUEST, "item-required")}; + %% {error, extended_error('bad-request', "item-required")}; Payload == "" -> %% Publisher attempts to publish to payload node with no payload - {error, extended_error(?ERR_BAD_REQUEST, "payload-required")}; + {error, extended_error('bad-request', "payload-required")}; %%?? -> %% % Publisher attempts to publish to transient notification node with item - %% {error, extended_error(?ERR_BAD_REQUEST, "item-forbidden")}; + %% {error, extended_error('bad-request', "item-forbidden")}; true -> node_call(Type, publish_item, [Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload]) end @@ -1492,7 +1488,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> ejabberd_hooks:run(pubsub_publish_item, ServerHost, [ServerHost, Node, Publisher, service_jid(Host), ItemId, Payload]), Reply = [], case transaction(Host, Node, Action, sync_dirty) of - {error, ?ERR_ITEM_NOT_FOUND} -> + {error, 'item-not-found'} -> %% handles auto-create feature %% for automatic node creation. we'll take the default node type: %% first listed into the plugins configuration option, or pep @@ -1503,10 +1499,10 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> {result, _} -> publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload); _ -> - {error, ?ERR_ITEM_NOT_FOUND} + {error, 'item-not-found'} end; false -> - {error, ?ERR_ITEM_NOT_FOUND} + {error, 'item-not-found'} end; {error, Reason} -> {error, Reason}; @@ -1514,7 +1510,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> lists:foreach(fun(OldItem) -> broadcast_retract_item(Host, Node, OldItem) end, Removed), - broadcast_publish_item(Host, Node, ItemId, jlib:jid_tolower(Publisher), Payload), + broadcast_publish_item(Host, Node, ItemId, jlib:short_prepd_jid(Publisher), Payload), case Result of default -> {result, Reply}; _ -> {result, Result} @@ -1553,7 +1549,7 @@ delete_item(Host, Node, Publisher, ItemId) -> delete_item(Host, Node, Publisher, ItemId, false). delete_item(_, "", _, _, _) -> %% Request does not specify a node - {error, extended_error(?ERR_BAD_REQUEST, "node-required")}; + {error, extended_error('bad-request', "node-required")}; delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> Action = fun(#pubsub_node{type = Type}) -> Features = features(Type), @@ -1562,13 +1558,13 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> if %%?? -> iq_pubsub just does that matchs %% %% Request does not specify an item - %% {error, extended_error(?ERR_BAD_REQUEST, "item-required")}; + %% {error, extended_error('bad-request', "item-required")}; not PersistentFeature -> %% Node does not support persistent items - {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "persistent-items")}; + {error, extended_error('feature-not-implemented', unsupported, "persistent-items")}; not DeleteFeature -> %% Service does not support item deletion - {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "delete-nodes")}; + {error, extended_error('feature-not-implemented', unsupported, "delete-nodes")}; true -> node_call(Type, delete_item, [Host, Node, Publisher, ItemId]) end @@ -1612,13 +1608,13 @@ purge_node(Host, Node, Owner) -> if not PurgeFeature -> %% Service does not support node purging - {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "purge-nodes")}; + {error, extended_error('feature-not-implemented', unsupported, "purge-nodes")}; not PersistentFeature -> %% Node does not support persistent items - {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "persistent-items")}; + {error, extended_error('feature-not-implemented', unsupported, "persistent-items")}; not PersistentConfig -> %% Node is not configured for persistent items - {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "persistent-items")}; + {error, extended_error('feature-not-implemented', unsupported, "persistent-items")}; true -> node_call(Type, purge_node, [Host, Node, Owner]) end @@ -1650,7 +1646,7 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> SMaxItems == "" -> ?MAXITEMS; true -> case catch list_to_integer(SMaxItems) of - {'EXIT', _} -> {error, ?ERR_BAD_REQUEST}; + {'EXIT', _} -> {error, 'bad-request'}; Val -> Val end end, @@ -1668,17 +1664,17 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> case Host of {OUser, OServer, _} -> get_roster_info(OUser, OServer, - jlib:jid_tolower(From), AllowedGroups); + jlib:short_prepd_jid(From), AllowedGroups); _ -> {true, true} end, if not RetreiveFeature -> %% Item Retrieval Not Supported - {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "retrieve-items")}; + {error, extended_error('feature-not-implemented', unsupported, "retrieve-items")}; not PersistentFeature -> %% Persistent Items Not Supported - {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "persistent-items")}; + {error, extended_error('feature-not-implemented', unsupported, "persistent-items")}; true -> node_call(Type, get_items, [Host, Node, From, @@ -1705,12 +1701,12 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> payload = Payload}) -> ItemAttrs = case ItemId of "" -> []; - _ -> [{"id", ItemId}] + _ -> [#xmlattr{name = 'id', value = ItemId}] end, - {xmlelement, "item", ItemAttrs, Payload} + #xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = ItemAttrs, children = Payload} end, lists:sublist(SendItems, MaxItems)), - {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], - [{xmlelement, "items", [{"node", node_to_string(Node)}], + {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = ItemsEls}]}]} end end. @@ -1733,7 +1729,7 @@ send_last_item(Host, Node, LJID) -> send_items(Host, Node, LJID, last). %% TODO use cache-last-item feature -send_items(Host, Node, LJID, Number) -> +send_items(Host, Node, {LU, LS, LR} = LJID, Number) -> ToSend = case get_items(Host, Node, LJID) of [] -> []; @@ -1749,15 +1745,15 @@ send_items(Host, Node, LJID, Number) -> fun(#pubsub_item{itemid = {ItemId, _}, payload = Payload}) -> ItemAttrs = case ItemId of "" -> []; - _ -> [{"id", ItemId}] + _ -> [#xmlattr{name = 'id', value = ItemId}] end, - {xmlelement, "item", ItemAttrs, Payload} + #xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = ItemAttrs, children = Payload} end, ToSend), - Stanza = {xmlelement, "message", [], - [{xmlelement, "event", [{"xmlns", ?NS_PUBSUB_EVENT}], - [{xmlelement, "items", [{"node", node_to_string(Node)}], + Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = ItemsEls}]}]}, - ejabberd_router ! {route, service_jid(Host), jlib:make_jid(LJID), Stanza}. + ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(LU, LS, LR), Stanza}. %% @spec (Host, JID, Plugins) -> {error, Reason} | {result, Response} %% Host = host() @@ -1774,7 +1770,7 @@ get_affiliations(Host, JID, Plugins) when is_list(Plugins) -> if not RetrieveFeature -> %% Service does not support retreive affiliatons - {{error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "retrieve-affiliations")}, Acc}; + {{error, extended_error('feature-not-implemented', unsupported, "retrieve-affiliations")}, Acc}; true -> {result, Affiliations} = node_action(Type, get_entity_affiliations, [Host, JID]), {Status, [Affiliations|Acc]} @@ -1785,13 +1781,12 @@ get_affiliations(Host, JID, Plugins) when is_list(Plugins) -> Entities = lists:flatmap( fun({_, none}) -> []; ({Node, Affiliation}) -> - [{xmlelement, "affiliation", - [{"node", node_to_string(Node)}, - {"affiliation", affiliation_to_string(Affiliation)}], - []}] + [#xmlel{ns = ?NS_PUBSUB, name = 'affiliation', attrs = + [#xmlattr{name = 'node', value = node_to_string(Node)}, + #xmlattr{name = 'affiliation', value = affiliation_to_string(Affiliation)}]}] end, lists:usort(lists:flatten(Affiliations))), - {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], - [{xmlelement, "affiliations", [], + {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB, name = 'affiliations', children = Entities}]}]}; {Error, _} -> Error @@ -1804,10 +1799,10 @@ get_affiliations(Host, Node, JID) -> if not RetrieveFeature -> %% Service does not support modify affiliations - {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "modify-affiliations")}; + {error, extended_error('feature-not-implemented', unsupported, "modify-affiliations")}; Affiliation /= {result, owner} -> %% Entity is not an owner - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; true -> node_call(Type, get_node_affiliations, [Host, Node]) end @@ -1816,23 +1811,22 @@ get_affiliations(Host, Node, JID) -> {error, Reason} -> {error, Reason}; {result, []} -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; {result, Affiliations} -> Entities = lists:flatmap( fun({_, none}) -> []; - ({AJID, Affiliation}) -> - [{xmlelement, "affiliation", - [{"jid", jlib:jid_to_string(AJID)}, - {"affiliation", affiliation_to_string(Affiliation)}], - []}] + ({{AU, AS, AR}, Affiliation}) -> + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'affiliation', attrs = + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(AU, AS, AR)}, + #xmlattr{name = 'affiliation', value = affiliation_to_string(Affiliation)}]}] end, Affiliations), - {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB_OWNER}], - [{xmlelement, "affiliations", [{"node", node_to_string(Node)}], + {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'affiliations', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = Entities}]}]} end. set_affiliations(Host, Node, From, EntitiesEls) -> - Owner = jlib:jid_tolower(jlib:jid_remove_resource(From)), + Owner = jlib:short_prepd_bare_jid(From), Entities = lists:foldl( fun(El, Acc) -> @@ -1841,24 +1835,28 @@ set_affiliations(Host, Node, From, EntitiesEls) -> error; _ -> case El of - {xmlelement, "affiliation", Attrs, _} -> - JID = jlib:string_to_jid( - xml:get_attr_s("jid", Attrs)), + #xmlel{name = 'affiliation', attrs = Attrs} -> + JID = try + exmpp_jid:list_to_jid( + exmpp_xml:get_attribute_from_list(Attrs, 'jid', "")) + catch + _:_ -> error + end, Affiliation = string_to_affiliation( - xml:get_attr_s("affiliation", Attrs)), + exmpp_xml:get_attribute_from_list(Attrs, 'affiliation', false)), if (JID == error) or (Affiliation == false) -> error; true -> - [{jlib:jid_tolower(JID), Affiliation} | Acc] + [{jlib:short_prepd_jid(JID), Affiliation} | Acc] end end end end, [], EntitiesEls), case Entities of error -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; _ -> Action = fun(#pubsub_node{type = Type, owners = Owners}) -> case lists:member(Owner, Owners) of @@ -1871,7 +1869,7 @@ set_affiliations(Host, Node, From, EntitiesEls) -> end, Entities), {result, []}; _ -> - {error, ?ERR_FORBIDDEN} + {error, 'forbidden'} end end, transaction(Host, Node, Action, sync_dirty) @@ -1893,7 +1891,7 @@ get_subscriptions(Host, JID, Plugins) when is_list(Plugins) -> if not RetrieveFeature -> %% Service does not support retreive subscriptions - {{error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "retrieve-subscriptions")}, Acc}; + {{error, extended_error('feature-not-implemented', unsupported, "retrieve-subscriptions")}, Acc}; true -> {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, JID]), {Status, [Subscriptions|Acc]} @@ -1904,20 +1902,18 @@ get_subscriptions(Host, JID, Plugins) when is_list(Plugins) -> Entities = lists:flatmap( fun({_, none}) -> []; ({Node, Subscription}) -> - [{xmlelement, "subscription", - [{"node", node_to_string(Node)}, - {"subscription", subscription_to_string(Subscription)}], - []}]; + [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = + [#xmlattr{name = 'node', value = node_to_string(Node)}, + #xmlattr{name = 'subscription', value = subscription_to_string(Subscription)}]}]; ({_, none, _}) -> []; ({Node, Subscription, SubJID}) -> - [{xmlelement, "subscription", - [{"node", node_to_string(Node)}, - {"jid", jlib:jid_to_string(SubJID)}, - {"subscription", subscription_to_string(Subscription)}], - []}] + [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = + [#xmlattr{name = 'node', value = node_to_string(Node)}, + #xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(SubJID)}, + #xmlattr{name = 'subscription', value = subscription_to_string(Subscription)}]}] end, lists:usort(lists:flatten(Subscriptions))), - {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], - [{xmlelement, "subscriptions", [], + {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB, name = 'subscriptions', children = Entities}]}]}; {Error, _} -> Error @@ -1930,10 +1926,10 @@ get_subscriptions(Host, Node, JID) -> if not RetrieveFeature -> %% Service does not support manage subscriptions - {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "manage-affiliations")}; + {error, extended_error('feature-not-implemented', unsupported, "manage-affiliations")}; Affiliation /= {result, owner} -> %% Entity is not an owner - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; true -> node_call(Type, get_node_subscriptions, [Host, Node]) end @@ -1942,29 +1938,27 @@ get_subscriptions(Host, Node, JID) -> {error, Reason} -> {error, Reason}; {result, []} -> - {error, ?ERR_ITEM_NOT_FOUND}; + {error, 'item-not-found'}; {result, Subscriptions} -> Entities = lists:flatmap( fun({_, none}) -> []; - ({AJID, Subscription}) -> - [{xmlelement, "subscription", - [{"jid", jlib:jid_to_string(AJID)}, - {"subscription", subscription_to_string(Subscription)}], - []}]; - ({AJID, Subscription, SubId}) -> - [{xmlelement, "subscription", - [{"jid", jlib:jid_to_string(AJID)}, - {"subscription", subscription_to_string(Subscription)}, - {"subid", SubId}], - []}] + ({{AU, AS, AR}, Subscription}) -> + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscription', attrs = + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(AU, AS, AR)}, + #xmlattr{name = 'subscription', value = subscription_to_string(Subscription)}]}]; + ({{AU, AS, AR}, Subscription, SubId}) -> + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscription', attrs = + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(AU, AS, AR)}, + #xmlattr{name = 'subscription', value = subscription_to_string(Subscription)}, + #xmlattr{name = 'subid', value =SubId}]}] end, Subscriptions), - {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB_OWNER}], - [{xmlelement, "subscriptions", [{"node", node_to_string(Node)}], + {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscriptions', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = Entities}]}]} end. set_subscriptions(Host, Node, From, EntitiesEls) -> - Owner = jlib:jid_tolower(jlib:jid_remove_resource(From)), + Owner = jlib:short_prepd_bare_jid(From), Entities = lists:foldl( fun(El, Acc) -> @@ -1973,24 +1967,29 @@ set_subscriptions(Host, Node, From, EntitiesEls) -> error; _ -> case El of - {xmlelement, "subscription", Attrs, _} -> - JID = jlib:string_to_jid( - xml:get_attr_s("jid", Attrs)), + #xmlel{name = 'subscription', attrs = Attrs} -> + JID = try + exmpp_jid:list_to_jid( + exmpp_xml:get_attribute_from_list(Attrs, 'jid', "")) + catch + _:_ -> + error + end, Subscription = string_to_subscription( - xml:get_attr_s("subscription", Attrs)), + exmpp_xml:get_attribute_from_list(Attrs, 'subscription', false)), if (JID == error) or (Subscription == false) -> error; true -> - [{jlib:jid_tolower(JID), Subscription} | Acc] + [{jlib:short_prepd_jid(JID), Subscription} | Acc] end end end end, [], EntitiesEls), case Entities of error -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; _ -> Action = fun(#pubsub_node{type = Type, owners = Owners}) -> case lists:member(Owner, Owners) of @@ -2000,7 +1999,7 @@ set_subscriptions(Host, Node, From, EntitiesEls) -> end, Entities), {result, []}; _ -> - {error, ?ERR_FORBIDDEN} + {error, 'forbidden'} end end, transaction(Host, Node, Action, sync_dirty) @@ -2014,7 +2013,7 @@ get_roster_info(OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, _}, A ejabberd_hooks:run_fold( roster_get_jid_info, OwnerServer, {none, []}, - [OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, ""}]), + [OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, undefined}]), PresenceSubscription = (Subscription == both) orelse (Subscription == from) orelse ({OwnerUser, OwnerServer} == {SubscriberUser, SubscriberServer}), RosterGroup = lists:any(fun(Group) -> @@ -2078,8 +2077,8 @@ string_to_node(SNode) -> %% @doc

      Generate pubsub service JID.

      service_jid(Host) -> case Host of - {U,S,_} -> {jid, U, S, "", U, S, ""}; - _ -> {jid, "", Host, "", "", Host, ""} + {U,S,_} -> #jid{node = U, domain = S, lnode = U, ldomain = S}; + _ -> #jid{domain = Host, ldomain = Host} end. %% @spec (LJID, Subscription, PresenceDelivery) -> boolean() @@ -2116,7 +2115,7 @@ broadcast_publish_item(Host, Node, ItemId, _From, Payload) -> end, ItemAttrs = case ItemId of "" -> []; - _ -> [{"id", ItemId}] + _ -> [#xmlattr{name = 'id', value = ItemId}] end, Stanza = make_stanza(Node, ItemAttrs, Content), lists:foreach( @@ -2142,17 +2141,16 @@ broadcast_publish_item(Host, Node, ItemId, _From, Payload) -> %% ItemAttrs is a list of tuples: %% For example: [{"id", ItemId}] make_stanza(Node, ItemAttrs, Payload) -> - {xmlelement, "message", [], - [{xmlelement, "event", - [{"xmlns", ?NS_PUBSUB_EVENT}], - [{xmlelement, "items", [{"node", node_to_string(Node)}], - [{xmlelement, "item", ItemAttrs, Payload}]}]}]}. + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = ItemAttrs, children = Payload}]}]}]}. %% DestJIDs = [{LUser, LServer, LResource}] route_stanza(Host, DestJIDs, Stanza) -> lists:foreach( - fun(DestJID) -> - ejabberd_router ! {route, service_jid(Host), jlib:make_jid(DestJID), Stanza} + fun({DU, DS, DR}) -> + ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(DU, DS, DR), Stanza} end, DestJIDs). broadcast_retract_item(Host, Node, ItemId) -> @@ -2170,21 +2168,20 @@ broadcast_retract_item(Host, Node, ItemId, ForceNotify) -> end, ItemAttrs = case ItemId of "" -> []; - _ -> [{"id", ItemId}] + _ -> [#xmlattr{name = 'id', value = ItemId}] end, - Stanza = {xmlelement, "message", [], - [{xmlelement, "event", - [{"xmlns", ?NS_PUBSUB_EVENT}], - [{xmlelement, "items", [{"node", node_to_string(Node)}], - [{xmlelement, "retract", ItemAttrs, []}]}]}]}, + Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = ItemAttrs}]}]}]}, case Notify of true -> lists:foreach( - fun(#pubsub_state{stateid = {JID, _}, + fun(#pubsub_state{stateid = {{U, S, R}, _}, subscription = Subscription}) -> if (Subscription /= none) and (Subscription /= pending) -> - ejabberd_router ! {route, service_jid(Host), jlib:make_jid(JID), Stanza}; + ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(U, S, R), Stanza}; true -> ok end @@ -2205,19 +2202,17 @@ broadcast_purge_node(Host, Node) -> {error, _} -> {result, false}; {result, []} -> {result, false}; {result, States} -> - Stanza = {xmlelement, "message", [], - [{xmlelement, "event", - [{"xmlns", ?NS_PUBSUB_EVENT}], - [{xmlelement, "purge", [{"node", node_to_string(Node)}], - []}]}]}, + Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'purge', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}]}]}]}, case get_option(Options, notify_retract) of true -> lists:foreach( - fun(#pubsub_state{stateid = {JID,_}, + fun(#pubsub_state{stateid = {{U, S, R},_}, subscription = Subscription}) -> if (Subscription /= none) and (Subscription /= pending) -> - ejabberd_router ! {route, service_jid(Host), jlib:make_jid(JID), Stanza}; + ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(U, S, R), Stanza}; true -> ok end @@ -2236,20 +2231,19 @@ broadcast_removed_node(Host, Removed) -> fun(Node) -> Action = fun(#pubsub_node{options = Options, type = Type}) -> - Stanza = {xmlelement, "message", [], - [{xmlelement, "event", [{"xmlns", ?NS_PUBSUB_EVENT}], - [{xmlelement, "delete", [{"node", node_to_string(Node)}], - []}]}]}, + Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'delete', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}]}]}]}, case get_option(Options, notify_delete) of true -> case node_call(Type, get_states, [Host, Node]) of {result, States} -> lists:foreach( - fun(#pubsub_state{stateid = {JID, _}, + fun(#pubsub_state{stateid = {{U, S, R}, _}, subscription = Subscription}) -> if (Subscription /= none) and (Subscription /= pending) -> - ejabberd_router ! {route, service_jid(Host), jlib:make_jid(JID), Stanza}; + ejabberd_router ! {route, service_jid(Host), jlib:make_jid(U, S, R), Stanza}; true -> ok end @@ -2278,22 +2272,22 @@ broadcast_config_notification(Host, Node, Lang) -> PresenceDelivery = get_option(Options, presence_based_delivery), Content = case get_option(Options, deliver_payloads) of true -> - [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}], + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', value = "form"}], children = get_configure_xfields(Type, Options, Lang, Owners)}]; false -> [] end, - Stanza = {xmlelement, "message", [], - [{xmlelement, "event", [{"xmlns", ?NS_PUBSUB_EVENT}], - [{xmlelement, "items", [{"node", node_to_string(Node)}], - [{xmlelement, "item", [{"id", "configuration"}], + Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = [#xmlattr{name = 'id', value = "configuration"}], children = Content}]}]}]}, lists:foreach( - fun(#pubsub_state{stateid = {LJID, _}, + fun(#pubsub_state{stateid = {{U, S, R} = LJID, _}, subscription = Subscription}) -> case is_to_delivered(LJID, Subscription, PresenceDelivery) of true -> - ejabberd_router ! {route, service_jid(Host), jlib:make_jid(LJID), Stanza}; + ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(U, S, R), Stanza}; false -> ok end @@ -2333,19 +2327,19 @@ broadcast_by_caps({LUser, LServer, LResource}, Node, _Type, Stanza) -> ?DEBUG("looking for pid of ~p@~p/~p", [LUser, LServer, LResource]), %% We need to know the resource, so we can ask for presence data. SenderResource = case LResource of - "" -> + undefined -> %% If we don't know the resource, just pick one. case ejabberd_sm:get_user_resources(LUser, LServer) of [R|_] -> R; [] -> - "" + undefined end; _ -> LResource end, case SenderResource of - "" -> + undefined -> ?DEBUG("~p@~p is offline; can't deliver ~p to contacts", [LUser, LServer, Stanza]), ok; _ -> @@ -2354,16 +2348,16 @@ broadcast_by_caps({LUser, LServer, LResource}, Node, _Type, Stanza) -> %% set the from address on the notification to the bare JID of the account owner %% Also, add "replyto" if entity has presence subscription to the account owner %% See XEP-0163 1.1 section 4.3.1 - Sender = jlib:make_jid(LUser, LServer, ""), + Sender = exmpp_jid:make_jid(LUser, LServer), %%ReplyTo = jlib:make_jid(LUser, LServer, SenderResource), % This has to be used case catch ejabberd_c2s:get_subscribed_and_online(C2SPid) of ContactsWithCaps when is_list(ContactsWithCaps) -> ?DEBUG("found contacts with caps: ~p", [ContactsWithCaps]), lists:foreach( - fun({JID, Caps}) -> + fun({{U1, S1, R1}, Caps}) -> case is_caps_notify(LServer, Node, Caps) of true -> - To = jlib:make_jid(JID), + To = exmpp_jid:make_jid(U1, S1, R1), ejabberd_router ! {route, Sender, To, Stanza}; false -> ok @@ -2400,16 +2394,15 @@ get_configure(Host, Node, From, Lang) -> case node_call(Type, get_affiliation, [Host, Node, From]) of {result, owner} -> {result, - [{xmlelement, "pubsub", - [{"xmlns", ?NS_PUBSUB_OWNER}], - [{xmlelement, "configure", - [{"node", node_to_string(Node)}], - [{xmlelement, "x", - [{"xmlns", ?NS_XDATA}, {"type", "form"}], + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'configure', attrs = + [#xmlattr{name = 'node', value = node_to_string(Node)}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = + [#xmlattr{name = 'type', value = "form"}], children = get_configure_xfields(Type, Options, Lang, Owners) }]}]}]}; _ -> - {error, ?ERR_FORBIDDEN} + {error, 'forbidden'} end end, transaction(Host, Node, Action, sync_dirty). @@ -2417,9 +2410,9 @@ get_configure(Host, Node, From, Lang) -> get_default(Host, Node, _From, Lang) -> Type=select_type(Host, Host, Node), Options = node_options(Type), - {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB_OWNER}], - [{xmlelement, "default", [], - [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}], + {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'default', children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', value = "form"}], children = get_configure_xfields(Type, Options, Lang, []) }]}]}]}. @@ -2484,8 +2477,8 @@ max_items(Options) -> -define(JLIST_CONFIG_FIELD(Label, Var, Opts), ?LISTXFIELD(Label, "pubsub#" ++ atom_to_list(Var), - jlib:jid_to_string(get_option(Options, Var)), - [jlib:jid_to_string(O) || O <- Opts])). + exmpp_jid:jid_to_list(get_option(Options, Var)), + [exmpp_jid:jid_to_list(O) || O <- Opts])). -define(ALIST_CONFIG_FIELD(Label, Var, Opts), ?LISTXFIELD(Label, "pubsub#" ++ atom_to_list(Var), @@ -2493,7 +2486,7 @@ max_items(Options) -> [atom_to_list(O) || O <- Opts])). get_configure_xfields(_Type, Options, Lang, _Owners) -> - [?XFIELD("hidden", "", "FORM_TYPE", ?NS_PUBSUB_NODE_CONFIG), + [?XFIELD("hidden", "", "FORM_TYPE", ?NS_PUBSUB_NODE_CONFIG_s), ?BOOL_CONFIG_FIELD("Deliver payloads with event notifications", deliver_payloads), ?BOOL_CONFIG_FIELD("Deliver event notifications", deliver_notifications), ?BOOL_CONFIG_FIELD("Notify subscribers when the node configuration changes", notify_config), @@ -2506,10 +2499,10 @@ get_configure_xfields(_Type, Options, Lang, _Owners) -> ?ALIST_CONFIG_FIELD("Specify the access model", access_model, [open, authorize, presence, roster, whitelist]), %% XXX: change to list-multi, include current roster groups as options - {xmlelement, "field", [{"type", "text-multi"}, - {"label", translate:translate(Lang, "Roster groups allowed to subscribe")}, - {"var", "pubsub#roster_groups_allowed"}], - [{xmlelement, "value", [], [{xmlcdata, Value}]} || + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = "text-multi"}, + #xmlattr{name = 'label', value = translate:translate(Lang, "Roster groups allowed to subscribe")}, + #xmlattr{name = 'var', value = "pubsub#roster_groups_allowed"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Value)}]} || Value <- get_option(Options, roster_groups_allowed, [])]}, ?ALIST_CONFIG_FIELD("Specify the publisher model", publish_model, [publishers, subscribers, open]), @@ -2528,12 +2521,12 @@ get_configure_xfields(_Type, Options, Lang, _Owners) -> %%
    • The specified node does not exist.
    • %% set_configure(Host, Node, From, Els, Lang) -> - case xml:remove_cdata(Els) of - [{xmlelement, "x", _Attrs1, _Els1} = XEl] -> - case {xml:get_tag_attr_s("xmlns", XEl), xml:get_tag_attr_s("type", XEl)} of - {?NS_XDATA, "cancel"} -> + case exmpp_xml:remove_cdata_from_list(Els) of + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x'} = XEl] -> + case exmpp_xml:get_attribute(XEl, 'type', undefined) of + "cancel" -> {result, []}; - {?NS_XDATA, "submit"} -> + "submit" -> Action = fun(#pubsub_node{options = Options, type = Type}=N) -> case node_call(Type, get_affiliation, @@ -2541,7 +2534,7 @@ set_configure(Host, Node, From, Els, Lang) -> {result, owner} -> case jlib:parse_xdata_submit(XEl) of invalid -> - {error, ?ERR_BAD_REQUEST}; + {error, 'bad-request'}; XData -> OldOpts = case Options of [] -> node_options(Type); @@ -2557,7 +2550,7 @@ set_configure(Host, Node, From, Els, Lang) -> end end; _ -> - {error, ?ERR_FORBIDDEN} + {error, 'forbidden'} end end, case transaction(Host, Node, Action, transaction) of @@ -2568,10 +2561,10 @@ set_configure(Host, Node, From, Els, Lang) -> Other end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end; _ -> - {error, ?ERR_BAD_REQUEST} + {error, 'bad-request'} end. add_opt(Key, Value, Opts) -> @@ -2587,7 +2580,7 @@ add_opt(Key, Value, Opts) -> _ -> error end, case BoolVal of - error -> {error, ?ERR_NOT_ACCEPTABLE}; + error -> {error, 'not-acceptable'}; _ -> set_xoption(Opts, add_opt(Opt, BoolVal, NewOpts)) end). @@ -2601,13 +2594,13 @@ add_opt(Key, Value, Opts) -> IVal =< Max -> set_xoption(Opts, add_opt(Opt, IVal, NewOpts)); _ -> - {error, ?ERR_NOT_ACCEPTABLE} + {error, 'not-acceptable'} end). -define(SET_ALIST_XOPT(Opt, Val, Vals), case lists:member(Val, [atom_to_list(V) || V <- Vals]) of true -> set_xoption(Opts, add_opt(Opt, list_to_atom(Val), NewOpts)); - false -> {error, ?ERR_NOT_ACCEPTABLE} + false -> {error, 'not-acceptable'} end). -define(SET_LIST_XOPT(Opt, Val), @@ -2654,7 +2647,7 @@ set_xoption([{"pubsub#type", Value} | Opts], NewOpts) -> set_xoption([{"pubsub#body_xslt", Value} | Opts], NewOpts) -> ?SET_STRING_XOPT(body_xslt, Value); set_xoption([_ | _Opts], _NewOpts) -> - {error, ?ERR_NOT_ACCEPTABLE}. + {error, 'not-acceptable'}. %%%% plugin handling @@ -2793,27 +2786,27 @@ transaction(Fun, Trans) -> {atomic, {error, Error}} -> {error, Error}; {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, 'internal-server-error'}; {'EXIT', Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), - {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, 'internal-server-error'}; Other -> ?ERROR_MSG("transaction return internal error: ~p~n", [Other]), - {error, ?ERR_INTERNAL_SERVER_ERROR} + {error, 'internal-server-error'} end. %%%% helpers %% Add pubsub-specific error element extended_error(Error, Ext) -> - extended_error(Error, Ext, [{"xmlns", ?NS_PUBSUB_ERRORS}]). + extended_error(Error, Ext, []). extended_error(Error, unsupported, Feature) -> - extended_error(Error, "unsupported", - [{"xmlns", ?NS_PUBSUB_ERRORS}, - {"feature", Feature}]); -extended_error({xmlelement, Error, Attrs, SubEls}, Ext, ExtAttrs) -> - {xmlelement, Error, Attrs, - lists:reverse([{xmlelement, Ext, ExtAttrs, []} | SubEls])}. + extended_error(Error, unsupported, + [#xmlattr{name = 'feature', value = Feature}]); +extended_error(Error, Ext, ExtAttrs) -> + Pubsub_Err = #xmlel{ns = ?NS_PUBSUB_ERRORS, name = Ext, attrs = ExtAttrs}, + exmpp_xml:append_child(exmpp_stanza:error(?NS_JABBER_CLIENT, Error), + Pubsub_Err). %% Give a uniq identifier uniqid() -> diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 97e363f79..122b76e91 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -41,8 +41,9 @@ -module(node_default). -author('christophe.romain@process-one.net'). +-include_lib("exmpp/include/exmpp.hrl"). + -include("pubsub.hrl"). --include("jlib.hrl"). -behaviour(gen_pubsub_node). @@ -194,10 +195,10 @@ features() -> %% ```check_create_user_permission(Host, Node, Owner, Access) -> %% node_default:check_create_user_permission(Host, Node, Owner, Access).'''

      create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) -> - LOwner = jlib:jid_tolower(Owner), + LOwner = jlib:short_prepd_jid(Owner), {User, Server, _Resource} = LOwner, Allowed = case LOwner of - {"", Host, ""} -> + {undefined, Host, undefined} -> true; % pubsub service always allowed _ -> case acl:match_rule(ServerHost, Access, LOwner) of @@ -219,7 +220,7 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) -> %% Owner = mod_pubsub:jid() %% @doc

      create_node(Host, Node, Owner) -> - OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + OwnerKey = jlib:short_prepd_bare_jid(Owner), mnesia:write(#pubsub_state{stateid = {OwnerKey, {Host, Node}}, affiliation = owner, subscription = none}), {result, {default, broadcast}}. @@ -281,11 +282,10 @@ delete_node(Host, Removed) -> %%

      In the default plugin module, the record is unchanged.

      subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - SenderKey = jlib:jid_tolower(Sender), - Authorized = (jlib:jid_remove_resource(SenderKey) == jlib:jid_remove_resource(Subscriber)), + Authorized = (jlib:short_prepd_bare_jid(Sender) == jlib:short_bare_jid(Subscriber)), % TODO add some acl check for Authorized ? State = case get_state(Host, Node, Subscriber) of - {error, ?ERR_ITEM_NOT_FOUND} -> + {error, 'item-not-found'} -> #pubsub_state{stateid = {Subscriber, {Host, Node}}}; % TODO: bug on Key ? {result, S} -> S end, @@ -294,31 +294,31 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel, if not Authorized -> %% JIDs do not match - {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "invalid-jid")}; + {error, ?ERR_EXTENDED('bad-request', "invalid-jid")}; Affiliation == outcast -> %% Requesting entity is blocked - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; Subscription == pending -> %% Requesting entity has pending subscription - {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "pending-subscription")}; + {error, ?ERR_EXTENDED('not-authorized', "pending-subscription")}; (AccessModel == presence) and (not PresenceSubscription) -> %% Entity is not authorized to create a subscription (presence subscription required) - {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "presence-subscription-required")}; + {error, ?ERR_EXTENDED('not-authorized', "presence-subscription-required")}; (AccessModel == roster) and (not RosterGroup) -> %% Entity is not authorized to create a subscription (not in roster group) - {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "not-in-roster-group")}; + {error, ?ERR_EXTENDED('not-authorized', "not-in-roster-group")}; (AccessModel == whitelist) -> % TODO: to be done %% Node has whitelist access model - {error, ?ERR_EXTENDED(?ERR_NOT_ALLOWED, "closed-node")}; + {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; (AccessModel == authorize) -> % TODO: to be done %% Node has authorize access model - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; %%MustPay -> %% % Payment is required for a subscription %% {error, ?ERR_PAYMENT_REQUIRED}; %%ForbiddenAnonymous -> %% % Requesting entity is anonymous - %% {error, ?ERR_FORBIDDEN}; + %% {error, 'forbidden'}; true -> NewSubscription = if @@ -352,8 +352,8 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel, %% Reason = mod_pubsub:stanzaError() %% @doc

      Unsubscribe the Subscriber from the Node.

      unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> - SenderKey = jlib:jid_tolower(Sender), - Match = jlib:jid_remove_resource(SenderKey) == jlib:jid_remove_resource(Subscriber), + SenderKey = jlib:short_prepd_jid(Sender), + Match = jlib:short_prepd_bare_jid(Sender) == jlib:short_bare_jid(Subscriber), Authorized = case Match of true -> true; @@ -364,23 +364,23 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> end end, case get_state(Host, Node, Subscriber) of - {error, ?ERR_ITEM_NOT_FOUND} -> + {error, 'item-not-found'} -> %% Requesting entity is not a subscriber - {error, ?ERR_EXTENDED(?ERR_UNEXPECTED_REQUEST, "not-subscribed")}; + {error, ?ERR_EXTENDED('unexpected-request', "not-subscribed")}; {result, State} -> if %% Entity did not specify SubID %%SubID == "", ?? -> - %% {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}; + %% {error, ?ERR_EXTENDED('bad-request', "subid-required")}; %% Invalid subscription identifier %%InvalidSubID -> - %% {error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; + %% {error, ?ERR_EXTENDED('not-acceptable', "invalid-subid")}; %% Requesting entity is not a subscriber State#pubsub_state.subscription == none -> - {error, ?ERR_EXTENDED(?ERR_UNEXPECTED_REQUEST, "not-subscribed")}; + {error, ?ERR_EXTENDED('unexpected-request', "not-subscribed")}; %% Requesting entity is prohibited from unsubscribing entity not Authorized -> - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; true -> set_state(State#pubsub_state{subscription = none}), {result, default} @@ -427,9 +427,9 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> %%

      %%

      In the default plugin module, the record is unchanged.

      publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) -> - PublisherKey = jlib:jid_tolower(jlib:jid_remove_resource(Publisher)), + PublisherKey = jlib:short_prepd_bare_jid(Publisher), State = case get_state(Host, Node, PublisherKey) of - {error, ?ERR_ITEM_NOT_FOUND} -> #pubsub_state{stateid={PublisherKey, {Host, Node}}}; + {error, 'item-not-found'} -> #pubsub_state{stateid={PublisherKey, {Host, Node}}}; {result, S} -> S end, #pubsub_state{affiliation = Affiliation, @@ -441,12 +441,12 @@ publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) -> or ((PublishModel == subscribers) and (Subscription == subscribed))) -> %% Entity does not have sufficient privileges to publish to node - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; true -> PubId = {PublisherKey, now()}, %% TODO: check creation, presence, roster (EJAB-663) Item = case get_item(Host, Node, ItemId) of - {error, ?ERR_ITEM_NOT_FOUND} -> + {error, 'item-not-found'} -> #pubsub_item{itemid = {ItemId, {Host, Node}}, creation = PubId, modification = PubId, @@ -504,9 +504,9 @@ remove_extra_items(Host, Node, MaxItems, ItemIds) -> %%

      Default plugin: The user performing the deletion must be the node owner %% or a publisher.

      delete_item(Host, Node, Publisher, ItemId) -> - PublisherKey = jlib:jid_tolower(jlib:jid_remove_resource(Publisher)), + PublisherKey = jlib:short_prepd_bare_jid(Publisher), State = case get_state(Host, Node, PublisherKey) of - {error, ?ERR_ITEM_NOT_FOUND} -> + {error, 'item-not-found'} -> #pubsub_state{stateid = {PublisherKey, {Host, Node}}}; {result, S} -> S @@ -520,7 +520,7 @@ delete_item(Host, Node, Publisher, ItemId) -> if not Allowed -> %% Requesting entity does not have sufficient privileges - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; true -> case get_item(Host, Node, ItemId) of {result, _} -> @@ -530,7 +530,7 @@ delete_item(Host, Node, Publisher, ItemId) -> {result, {default, broadcast}}; _ -> %% Non-existent node or item - {error, ?ERR_ITEM_NOT_FOUND} + {error, 'item-not-found'} end end. @@ -541,7 +541,7 @@ delete_item(Host, Node, Publisher, ItemId) -> %% Node = mod_pubsub:pubsubNode() %% Owner = mod_pubsub:jid() purge_node(Host, Node, Owner) -> - OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + OwnerKey = jlib:short_prepd_bare_jid(Owner), case get_state(Host, Node, OwnerKey) of {result, #pubsub_state{items = Items, affiliation = owner}} -> lists:foreach(fun(ItemId) -> @@ -550,9 +550,9 @@ purge_node(Host, Node, Owner) -> {result, {default, broadcast}}; {result, _} -> %% Entity is not owner - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; _ -> - {error, ?ERR_ITEM_NOT_FOUND} + {error, 'item-not-found'} end. %% @spec (Host, JID) -> [{Node,Affiliation}] @@ -566,7 +566,7 @@ purge_node(Host, Node, Owner) -> %% that will be added to the affiliation stored in the main %% pubsub_state table.

      get_entity_affiliations(Host, Owner) -> - OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + OwnerKey = jlib:short_prepd_bare_jid(Owner), States = mnesia:match_object( #pubsub_state{stateid = {OwnerKey, {Host, '_'}}, _ = '_'}), @@ -585,7 +585,7 @@ get_node_affiliations(Host, Node) -> {result, lists:map(Tr, States)}. get_affiliation(Host, Node, Owner) -> - OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + OwnerKey = jlib:short_prepd_bare_jid(Owner), Affiliation = case get_state(Host, Node, OwnerKey) of {result, #pubsub_state{affiliation = A}} -> A; _ -> none @@ -593,9 +593,9 @@ get_affiliation(Host, Node, Owner) -> {result, Affiliation}. set_affiliation(Host, Node, Owner, Affiliation) -> - OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + OwnerKey = jlib:short_prepd_bare_jid(Owner), Record = case get_state(Host, Node, OwnerKey) of - {error, ?ERR_ITEM_NOT_FOUND} -> + {error, 'item-not-found'} -> #pubsub_state{stateid = {OwnerKey, {Host, Node}}, affiliation = Affiliation}; {result, State} -> @@ -616,7 +616,7 @@ set_affiliation(Host, Node, Owner, Affiliation) -> %% that will be added to the affiliation stored in the main %% pubsub_state table.

      get_entity_subscriptions(Host, Owner) -> - OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + OwnerKey = jlib:short_prepd_bare_jid(Owner), States = mnesia:match_object( #pubsub_state{stateid = {OwnerKey, {Host, '_'}}, _ = '_'}), @@ -635,7 +635,7 @@ get_node_subscriptions(Host, Node) -> {result, lists:map(Tr, States)}. get_subscription(Host, Node, Owner) -> - OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + OwnerKey = jlib:short_prepd_bare_jid(Owner), Subscription = case get_state(Host, Node, OwnerKey) of {result, #pubsub_state{subscription = S}} -> S; _ -> none @@ -643,9 +643,9 @@ get_subscription(Host, Node, Owner) -> {result, Subscription}. set_subscription(Host, Node, Owner, Subscription) -> - OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + OwnerKey = jlib:short_prepd_bare_jid(Owner), Record = case get_state(Host, Node, OwnerKey) of - {error, ?ERR_ITEM_NOT_FOUND} -> + {error, 'item-not-found'} -> #pubsub_state{stateid = {OwnerKey, {Host, Node}}, subscription = Subscription}; {result, State} -> @@ -684,7 +684,7 @@ get_state(Host, Node, JID) -> [State] when is_record(State, pubsub_state) -> {result, State}; _ -> - {error, ?ERR_ITEM_NOT_FOUND} + {error, 'item-not-found'} end. %% @spec (State) -> ok | {error, Reason::stanzaError()} @@ -693,7 +693,7 @@ get_state(Host, Node, JID) -> set_state(State) when is_record(State, pubsub_state) -> mnesia:write(State); set_state(_) -> - {error, ?ERR_INTERNAL_SERVER_ERROR}. + {error, 'internal-server-error'}. %% @spec (Host, Node) -> [Items] | [] %% Host = mod_pubsub:host() @@ -715,7 +715,7 @@ get_items(Host, Node, _From) -> {result, Items}. get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> {Affiliation, Subscription} = - case get_state(Host, Node, jlib:jid_tolower(jlib:jid_remove_resource(JID))) of + case get_state(Host, Node, jlib:short_prepd_bare_jid(JID)) of {result, #pubsub_state{affiliation = A, subscription = S}} -> {A, S}; _ -> {none, none} end, @@ -723,28 +723,28 @@ get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubI if %%SubID == "", ?? -> %% Entity has multiple subscriptions to the node but does not specify a subscription ID - %{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}; + %{error, ?ERR_EXTENDED('bad-request', "subid-required")}; %%InvalidSubID -> %% Entity is subscribed but specifies an invalid subscription ID - %{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; + %{error, ?ERR_EXTENDED('not-acceptable', "invalid-subid")}; Affiliation == outcast -> %% Requesting entity is blocked - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; (AccessModel == open) and (not Subscribed) -> %% Entity is not subscribed - {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "not-subscribed")}; + {error, ?ERR_EXTENDED('not-authorized', "not-subscribed")}; (AccessModel == presence) and (not PresenceSubscription) -> %% Entity is not authorized to create a subscription (presence subscription required) - {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "presence-subscription-required")}; + {error, ?ERR_EXTENDED('not-authorized', "presence-subscription-required")}; (AccessModel == roster) and (not RosterGroup) -> %% Entity is not authorized to create a subscription (not in roster group) - {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "not-in-roster-group")}; + {error, ?ERR_EXTENDED('not-authorized', "not-in-roster-group")}; (AccessModel == whitelist) -> % TODO: to be done %% Node has whitelist access model - {error, ?ERR_EXTENDED(?ERR_NOT_ALLOWED, "closed-node")}; + {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; (AccessModel == authorize) -> % TODO: to be done %% Node has authorize access model - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; %%MustPay -> %% % Payment is required for a subscription %% {error, ?ERR_PAYMENT_REQUIRED}; @@ -763,11 +763,11 @@ get_item(Host, Node, ItemId) -> [Item] when is_record(Item, pubsub_item) -> {result, Item}; _ -> - {error, ?ERR_ITEM_NOT_FOUND} + {error, 'item-not-found'} end. get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> {Affiliation, Subscription} = - case get_state(Host, Node, jlib:jid_tolower(jlib:jid_remove_resource(JID))) of + case get_state(Host, Node, jlib:short_prepd_bare_jid(JID)) of {result, #pubsub_state{affiliation = A, subscription = S}} -> {A, S}; _ -> {none, none} end, @@ -775,28 +775,28 @@ get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup if %%SubID == "", ?? -> %% Entity has multiple subscriptions to the node but does not specify a subscription ID - %{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}; + %{error, ?ERR_EXTENDED('bad-request', "subid-required")}; %%InvalidSubID -> %% Entity is subscribed but specifies an invalid subscription ID - %{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; + %{error, ?ERR_EXTENDED('not-acceptable', "invalid-subid")}; Affiliation == outcast -> %% Requesting entity is blocked - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; (AccessModel == open) and (not Subscribed) -> %% Entity is not subscribed - {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "not-subscribed")}; + {error, ?ERR_EXTENDED('not-authorized', "not-subscribed")}; (AccessModel == presence) and (not PresenceSubscription) -> %% Entity is not authorized to create a subscription (presence subscription required) - {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "presence-subscription-required")}; + {error, ?ERR_EXTENDED('not-authorized', "presence-subscription-required")}; (AccessModel == roster) and (not RosterGroup) -> %% Entity is not authorized to create a subscription (not in roster group) - {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "not-in-roster-group")}; + {error, ?ERR_EXTENDED('not-authorized', "not-in-roster-group")}; (AccessModel == whitelist) -> % TODO: to be done %% Node has whitelist access model - {error, ?ERR_EXTENDED(?ERR_NOT_ALLOWED, "closed-node")}; + {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; (AccessModel == authorize) -> % TODO: to be done %% Node has authorize access model - {error, ?ERR_FORBIDDEN}; + {error, 'forbidden'}; %%MustPay -> %% % Payment is required for a subscription %% {error, ?ERR_PAYMENT_REQUIRED}; @@ -810,7 +810,7 @@ get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup set_item(Item) when is_record(Item, pubsub_item) -> mnesia:write(Item); set_item(_) -> - {error, ?ERR_INTERNAL_SERVER_ERROR}. + {error, 'internal-server-error'}. %% @doc

      Return the name of the node if known: Default is to return %% node id.

      diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index 1c1bff7d7..28f20d5c3 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -29,9 +29,10 @@ -module(node_pep). -author('christophe.romain@process-one.net'). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). -include("pubsub.hrl"). --include("jlib.hrl"). -behaviour(gen_pubsub_node). @@ -111,10 +112,10 @@ features() -> ]. create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> - LOwner = jlib:jid_tolower(Owner), + LOwner = jlib:short_prepd_jid(Owner), {User, Server, _Resource} = LOwner, Allowed = case LOwner of - {"", Host, ""} -> + {undefined, Host, undefined} -> true; % pubsub service always allowed _ -> case acl:match_rule(ServerHost, Access, LOwner) of @@ -167,21 +168,21 @@ purge_node(Host, Node, Owner) -> node_default:purge_node(Host, Node, Owner). get_entity_affiliations(_Host, Owner) -> - OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + OwnerKey = jlib:short_prepd_bare_jid(Owner), node_default:get_entity_affiliations(OwnerKey, Owner). get_node_affiliations(Host, Node) -> - OwnerKey = jlib:jid_remove_resource(Host), + OwnerKey = jlib:short_bare_jid(Host), node_default:get_node_affiliations(OwnerKey, Node). get_affiliation(_Host, Node, Owner) -> - OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + OwnerKey = jlib:short_prepd_bare_jid(Owner), node_default:get_affiliation(OwnerKey, Node, Owner). set_affiliation(_Host, Node, Owner, Affiliation) -> - OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + OwnerKey = jlib:short_prepd_bare_jid(Owner), Record = case get_state(OwnerKey, Node, OwnerKey) of - {error, ?ERR_ITEM_NOT_FOUND} -> + {error, 'item-not-found'} -> #pubsub_state{stateid = {OwnerKey, {OwnerKey, Node}}, affiliation = Affiliation}; {result, State} -> diff --git a/src/mod_pubsub/nodetree_default.erl b/src/mod_pubsub/nodetree_default.erl index 700397edb..f3dea3eb9 100644 --- a/src/mod_pubsub/nodetree_default.erl +++ b/src/mod_pubsub/nodetree_default.erl @@ -92,7 +92,7 @@ options() -> set_node(Record) when is_record(Record, pubsub_node) -> mnesia:write(Record); set_node(_) -> - {error, ?ERR_INTERNAL_SERVER_ERROR}. + {error, 'internal-server-error'}. %% @spec (Host, Node) -> pubsubNode() | {error, Reason} %% Host = mod_pubsub:host() @@ -100,7 +100,7 @@ set_node(_) -> get_node(Host, Node) -> case catch mnesia:read({pubsub_node, {Host, Node}}) of [Record] when is_record(Record, pubsub_node) -> Record; - [] -> {error, ?ERR_ITEM_NOT_FOUND}; + [] -> {error, 'item-not-found'}; Error -> Error end. @@ -134,7 +134,7 @@ get_subnodes_tree(Host, Node) -> %% Owner = mod_pubsub:jid() %% Options = list() create_node(Key, Node, Type, Owner, Options) -> - OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + OwnerKey = jlib:short_prepd_bare_jid(Owner), case mnesia:read({pubsub_node, {Key, Node}}) of [] -> {ParentNode, ParentExists} = @@ -166,11 +166,11 @@ create_node(Key, Node, Type, Owner, Options) -> options = Options}); false -> %% Requesting entity is prohibited from creating nodes - {error, ?ERR_FORBIDDEN} + {error, 'forbidden'} end; _ -> %% NodeID already exists - {error, ?ERR_CONFLICT} + {error, 'conflict'} end. %% @spec (Key, Node) -> [mod_pubsub:node()] From d01c24bd233e8766f8118cac7d1d6ac2e4deb010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 8 Dec 2008 11:20:21 +0000 Subject: [PATCH 133/582] Fix acl:match_rule/3 call. It takes a #jid record, not a short JID. PR: EJABP-1 SVN Revision: 1708 --- ChangeLog | 5 +++++ src/mod_pubsub/node_default.erl | 3 ++- src/mod_pubsub/node_pep.erl | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index be5e8d772..34dc8f270 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-12-05 Jean-Sébastien Pédron + + * src/mod_pubsub/node_default.erl, src/mod_pubsub/node_pep.erl: Fix + acl:match_rule/3 call. It takes a #jid record, not a short JID. + 2008-12-05 Jean-Sébastien Pédron * src/ejabberd_receiver.erl, src/mod_offline_odbc.erl, diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 122b76e91..15d871300 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -201,7 +201,8 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) -> {undefined, Host, undefined} -> true; % pubsub service always allowed _ -> - case acl:match_rule(ServerHost, Access, LOwner) of + {LU, LS, LR} = LOwner, + case acl:match_rule(ServerHost, Access, exmpp_jid:make_jid(LU, LS, LR)) of allow -> case Node of ["home", Server, User | _] -> true; diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index 28f20d5c3..ec617abda 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -118,7 +118,8 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> {undefined, Host, undefined} -> true; % pubsub service always allowed _ -> - case acl:match_rule(ServerHost, Access, LOwner) of + {LU, LS, LR} = LOwner, + case acl:match_rule(ServerHost, Access, exmpp_jid:make_jid(LU, LS, LR)) of allow -> case Host of {User, Server, _} -> true; From 82b97b963949c674c4de512eeb3811b7a8ef4771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 8 Dec 2008 11:21:32 +0000 Subject: [PATCH 134/582] Finish the conversion of mod_pubsub to Exmpp. PR: EJABP-1 SVN Revision: 1709 --- ChangeLog | 7 +++++++ src/mod_pubsub/node_buddy.erl | 3 ++- src/mod_pubsub/node_club.erl | 3 ++- src/mod_pubsub/node_dispatch.erl | 11 ++++++----- src/mod_pubsub/node_mb.erl | 3 ++- src/mod_pubsub/node_private.erl | 3 ++- src/mod_pubsub/node_public.erl | 3 ++- src/mod_pubsub/node_zoo.erl | 10 ++++++---- src/mod_pubsub/nodetree_default.erl | 3 ++- src/mod_pubsub/nodetree_virtual.erl | 11 ++++++----- 10 files changed, 37 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index 34dc8f270..0befd051c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,13 @@ * src/mod_pubsub/node_default.erl, src/mod_pubsub/node_pep.erl: Fix acl:match_rule/3 call. It takes a #jid record, not a short JID. + * src/mod_pubsub/node_buddy.erl, src/mod_pubsub/node_club.erl, + src/mod_pubsub/node_dispatch.erl, src/mod_pubsub/node_mb.erl, + src/mod_pubsub/node_private.erl, src/mod_pubsub/node_public.erl, + src/mod_pubsub/node_zoo.erl, src/mod_pubsub/nodetree_default.erl, + src/mod_pubsub/nodetree_virtual.erl: Finish the conversion of + mod_pubsub to Exmpp. + 2008-12-05 Jean-Sébastien Pédron * src/ejabberd_receiver.erl, src/mod_offline_odbc.erl, diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl index 6cdd6118b..95fefe9a5 100644 --- a/src/mod_pubsub/node_buddy.erl +++ b/src/mod_pubsub/node_buddy.erl @@ -26,8 +26,9 @@ -module(node_buddy). -author('christophe.romain@process-one.net'). +-include_lib("exmpp/include/exmpp.hrl"). + -include("pubsub.hrl"). --include("jlib.hrl"). -behaviour(gen_pubsub_node). diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl index ae8ab9cf1..6ff3fd33a 100644 --- a/src/mod_pubsub/node_club.erl +++ b/src/mod_pubsub/node_club.erl @@ -26,8 +26,9 @@ -module(node_club). -author('christophe.romain@process-one.net'). +-include_lib("exmpp/include/exmpp.hrl"). + -include("pubsub.hrl"). --include("jlib.hrl"). -behaviour(gen_pubsub_node). diff --git a/src/mod_pubsub/node_dispatch.erl b/src/mod_pubsub/node_dispatch.erl index 98a396cbf..a646a3373 100644 --- a/src/mod_pubsub/node_dispatch.erl +++ b/src/mod_pubsub/node_dispatch.erl @@ -26,8 +26,9 @@ -module(node_dispatch). -author('christophe.romain@process-one.net'). +-include_lib("exmpp/include/exmpp.hrl"). + -include("pubsub.hrl"). --include("jlib.hrl"). -behaviour(gen_pubsub_node). @@ -119,10 +120,10 @@ delete_node(Host, Removed) -> subscribe_node(_Host, _Node, _Sender, _Subscriber, _AccessModel, _SendLast, _PresenceSubscription, _RosterGroup) -> - {error, ?ERR_FORBIDDEN}. + {error, 'forbidden'}. unsubscribe_node(_Host, _Node, _Sender, _Subscriber, _SubID) -> - {error, ?ERR_FORBIDDEN}. + {error, 'forbidden'}. publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) -> lists:foreach(fun(SubNode) -> @@ -135,10 +136,10 @@ remove_extra_items(_Host, _Node, _MaxItems, ItemIds) -> {result, {ItemIds, []}}. delete_item(_Host, _Node, _JID, _ItemId) -> - {error, ?ERR_ITEM_NOT_FOUND}. + {error, 'item-not-found'}. purge_node(_Host, _Node, _Owner) -> - {error, ?ERR_FORBIDDEN}. + {error, 'forbidden'}. get_entity_affiliations(_Host, _Owner) -> {result, []}. diff --git a/src/mod_pubsub/node_mb.erl b/src/mod_pubsub/node_mb.erl index f2498071c..15cc1d312 100644 --- a/src/mod_pubsub/node_mb.erl +++ b/src/mod_pubsub/node_mb.erl @@ -35,9 +35,10 @@ -module(node_mb). -author('eric@ohmforce.com'). +-include_lib("exmpp/include/exmpp.hrl"). + -include("ejabberd.hrl"). -include("pubsub.hrl"). --include("jlib.hrl"). -behaviour(gen_pubsub_node). diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl index 5d87ec181..20a8e5e01 100644 --- a/src/mod_pubsub/node_private.erl +++ b/src/mod_pubsub/node_private.erl @@ -26,8 +26,9 @@ -module(node_private). -author('christophe.romain@process-one.net'). +-include_lib("exmpp/include/exmpp.hrl"). + -include("pubsub.hrl"). --include("jlib.hrl"). -behaviour(gen_pubsub_node). diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl index 7fda56e22..c12e37187 100644 --- a/src/mod_pubsub/node_public.erl +++ b/src/mod_pubsub/node_public.erl @@ -26,8 +26,9 @@ -module(node_public). -author('christophe.romain@process-one.net'). +-include_lib("exmpp/include/exmpp.hrl"). + -include("pubsub.hrl"). --include("jlib.hrl"). -behaviour(gen_pubsub_node). diff --git a/src/mod_pubsub/node_zoo.erl b/src/mod_pubsub/node_zoo.erl index 12a69c58f..0fc6fb797 100644 --- a/src/mod_pubsub/node_zoo.erl +++ b/src/mod_pubsub/node_zoo.erl @@ -25,8 +25,9 @@ -module(node_zoo). -author('christophe.romain@process-one.net'). +-include_lib("exmpp/include/exmpp.hrl"). + -include("pubsub.hrl"). --include("jlib.hrl"). -behaviour(gen_pubsub_node). @@ -92,12 +93,13 @@ features() -> %% the home/localhost/user/... hierarchy %% any node is allowed create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> - LOwner = jlib:jid_tolower(Owner), + LOwner = jlib:short_prepd_jid(Owner), Allowed = case LOwner of - {"", Host, ""} -> + {undefined, Host, undefined} -> true; % pubsub service always allowed _ -> - case acl:match_rule(ServerHost, Access, LOwner) of + {LU, LS, LR} = LOwner, + case acl:match_rule(ServerHost, Access, exmpp_jid:make_jid(LU, LS, LR)) of allow -> true; _ -> diff --git a/src/mod_pubsub/nodetree_default.erl b/src/mod_pubsub/nodetree_default.erl index f3dea3eb9..0c3ce3082 100644 --- a/src/mod_pubsub/nodetree_default.erl +++ b/src/mod_pubsub/nodetree_default.erl @@ -36,8 +36,9 @@ -module(nodetree_default). -author('christophe.romain@process-one.net'). +-include_lib("exmpp/include/exmpp.hrl"). + -include("pubsub.hrl"). --include("jlib.hrl"). -behaviour(gen_pubsub_nodetree). diff --git a/src/mod_pubsub/nodetree_virtual.erl b/src/mod_pubsub/nodetree_virtual.erl index 7b057a0fd..80a6e745e 100644 --- a/src/mod_pubsub/nodetree_virtual.erl +++ b/src/mod_pubsub/nodetree_virtual.erl @@ -34,8 +34,9 @@ -module(nodetree_virtual). -author('christophe.romain@process-one.net'). +-include_lib("exmpp/include/exmpp.hrl"). + -include("pubsub.hrl"). --include("jlib.hrl"). -behaviour(gen_pubsub_nodetree). @@ -121,11 +122,11 @@ get_subnodes_tree(_Host, _Node) -> %% is considered as already created.

      %%

      default allowed nodes: /home/host/user/any/node/name

      create_node(_Host, Node, _Type, Owner, _Options) -> - UserName = Owner#jid.luser, - UserHost = Owner#jid.lserver, + UserName = Owner#jid.lnode, + UserHost = Owner#jid.ldomain, case Node of - ["home", UserHost, UserName | _] -> {error, ?ERR_CONFLICT}; - _ -> {error, ?ERR_NOT_ALLOWED} + ["home", UserHost, UserName | _] -> {error, 'conflict'}; + _ -> {error, 'not-allowed'} end. %% @spec (Host, Node) -> [mod_pubsub:node()] From 3bfb2b5cc1b0a5ae18e9326c5a90ec5d21bf3a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 8 Dec 2008 12:02:27 +0000 Subject: [PATCH 135/582] Merge from trunk (r1692 to r1709). PR: EJABP-1 SVN Revision: 1710 --- ChangeLog | 23 +++- doc/guide.html | 141 +++++++++++++----------- doc/guide.tex | 205 +++++++++++++++++++++-------------- src/Makefile.in | 2 + src/ejabberd_c2s.erl | 94 +++++++++++----- src/mod_muc/mod_muc_room.erl | 63 +---------- src/mod_muc/mod_muc_room.hrl | 80 ++++++++++++++ src/odbc/ejabberd_odbc.erl | 10 +- 8 files changed, 386 insertions(+), 232 deletions(-) create mode 100644 src/mod_muc/mod_muc_room.hrl diff --git a/ChangeLog b/ChangeLog index 0befd051c..e703e7aa9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ -2008-12-05 Jean-Sébastien Pédron +2008-12-08 Jean-Sébastien Pédron + + Merge from trunk (r1692 to r1709). + +2008-12-08 Jean-Sébastien Pédron * src/mod_pubsub/node_default.erl, src/mod_pubsub/node_pep.erl: Fix acl:match_rule/3 call. It takes a #jid record, not a short JID. @@ -10,6 +14,12 @@ src/mod_pubsub/nodetree_virtual.erl: Finish the conversion of mod_pubsub to Exmpp. +2008-12-08 Mickael Remond + + * src/ejabberd_c2s.erl: Enforce client stanza from attribute + (EJAB-812). + * src/jlib.erl: Likewise. + 2008-12-05 Jean-Sébastien Pédron * src/ejabberd_receiver.erl, src/mod_offline_odbc.erl, @@ -31,6 +41,12 @@ * src/mod_proxy65/mod_proxy65_stream.erl, src/mod_proxy65/mod_proxy65_service.erl: Convert mod_proxy65 to exmpp. +2008-12-02 Badlop + + * src/mod_muc/mod_muc_room.erl: Move definitions to header file + * src/mod_muc/mod_muc_room.hrl: New header file + * src/Makefile.in: Likewise + 2008-12-01 Jean-Sébastien Pédron Merge from trunk (r1649 to r1692). @@ -38,6 +54,11 @@ * src/ejabberd_frontend_socket.erl: Fix two warnings about unused variables. +2008-12-01 Badlop + + * doc/guide.tex: New subsection Database Connection + * doc/guide.html: Likewise + 2008-11-28 Alexey Shchepin * src/mod_muc/mod_muc_room.erl: Clean user activity after timeout diff --git a/doc/guide.html b/doc/guide.html index c15a76df7..e33aaf296 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -1246,7 +1246,18 @@ different storage systems for modules, and so forth.

      The following databas

    • OpenLDAP
    • Normally any LDAP compatible server should work; inform us about your success with a not-listed server so that we can list it here. -
    • +

      Important note about virtual hosting: +if you define several domains in ejabberd.cfg (see section 3.1.1), +you probably want that each virtual host uses a different configuration of database, authentication and storage, +so that usernames do not conflict and mix between different virtual hosts. +For that purpose, the options described in the next sections +must be set inside a host_cofig for each vhost (see section 3.1.2). +For example: +

      {host_config, "public.example.org", [
      +  {odbc_server, {pgsql, "localhost", "database", "ejabberd", "password"}},
      +  {auth_method, [odbc]}
      +]}.
      +

      3.2.1  MySQL

      Although this section will describe ejabberd’s configuration when you want to use the native MySQL driver, it does not describe MySQL’s installation and @@ -1254,18 +1265,7 @@ database creation. Check the MySQL documentation and the tutorial {odbc_pool_size, 10}. -

      You can configure an interval to make a dummy SQL request -to keep alive the connections to the database. -The default value is ’undefined’, so no keepalive requests are made. -Specify in seconds: for example 28800 means 8 hours. -

      {odbc_keepalive_interval, undefined}.
      -

      If the connection to the database fails, ejabberd waits 30 seconds before retrying. -You can modify this interval with this option: -

      {odbc_start_interval, 30}.
      -

      +you can find information to update your database schema.

      Driver Compilation

      You can skip this step if you installed ejabberd using a binary installer or if the binary packages of ejabberd you are using include support for MySQL.

      1. @@ -1276,14 +1276,9 @@ put them for example in the same directory as your ejabberd .beam files also needed for native MySQL support!). This can be done, by using next commands:
        ./configure --enable-odbc && make install
        -

      -

      Authentication

      -

      The option value name may be misleading, as the auth_method name is used -for access to a relational database through ODBC, as well as through the native -MySQL interface. Anyway, the first configuration step is to define the odbc -auth_method. For example: -

      {host_config, "public.example.org", [{auth_method, [odbc]}]}.
      -

      The actual database access is defined in the option odbc_server. Its +

      +

      Database Connection

      +

      The actual database access is defined in the option odbc_server. Its value is used to define if we want to use ODBC, or one of the two native interface available, PostgreSQL or MySQL.

      To use the native MySQL interface, you can pass a tuple of the following form as parameter: @@ -1297,6 +1292,24 @@ can thus take the following form:

      {mysql, "Server", Port, "Database", "Username", "Password"}
       

      The Port value should be an integer, without quotes. For example:

      {odbc_server, {mysql, "localhost", Port, "test", "root", "password"}}.
      +

      By default ejabberd opens 10 connections to the database for each virtual host. +Use this option to modify the value: +

      {odbc_pool_size, 10}.
      +

      You can configure an interval to make a dummy SQL request +to keep alive the connections to the database. +The default value is ’undefined’, so no keepalive requests are made. +Specify in seconds: for example 28800 means 8 hours. +

      {odbc_keepalive_interval, undefined}.
      +

      If the connection to the database fails, ejabberd waits 30 seconds before retrying. +You can modify this interval with this option: +

      {odbc_start_interval, 30}.
      +

      +

      Authentication

      +

      The option value name may be misleading, as the auth_method name is used +for access to a relational database through ODBC, as well as through the native +MySQL interface. Anyway, the first configuration step is to define the odbc +auth_method. For example: +

      {auth_method, [odbc]}.
       

      Storage

      MySQL also can be used to store information into from several ejabberd @@ -1314,7 +1327,16 @@ tutorial

      +

      Driver Compilation

      +

      You can skip this step if you installed ejabberd using a binary installer or +if the binary packages of ejabberd you are using include support for ODBC.

      If you want to use Microsoft SQL Server with ODBC, you need to configure, +compile and install ejabberd with support for ODBC and Microsoft SQL Server +enabled. This can be done, by using next commands: +

      ./configure --enable-odbc --enable-mssql && make install
      +

      +

      Database Connection

      +

      By default ejabberd opens 10 connections to the database for each virtual host. Use this option to modify the value:

      {odbc_pool_size, 10}.
       

      You can configure an interval to make a dummy SQL request @@ -1322,13 +1344,6 @@ to keep alive the connections to the database. The default value is ’undefined’, so no keepalive requests are made. Specify in seconds: for example 28800 means 8 hours.

      {odbc_keepalive_interval, undefined}.
      -

      -

      Driver Compilation

      -

      You can skip this step if you installed ejabberd using a binary installer or -if the binary packages of ejabberd you are using include support for ODBC.

      If you want to use Microsoft SQL Server with ODBC, you need to configure, -compile and install ejabberd with support for ODBC and Microsoft SQL Server -enabled. This can be done, by using next commands: -

      ./configure --enable-odbc --enable-mssql && make install
       

      Authentication

      The configuration of Microsoft SQL Server is the same as the configuration of @@ -1349,15 +1364,7 @@ and database creation. Check the PostgreSQL documentation and the tutorial ejabberd’s configuration which is duplicate to this section.

      Also the file pg.sql in the directory src/odbc might be interesting for you. This file contains the ejabberd schema for PostgreSQL. At the end of the file -you can find information to update your database schema.

      By default ejabberd opens 10 connections to the database for each virtual host. -Use this option to modify the value: -

      {odbc_pool_size, 10}.
      -

      You can configure an interval to make a dummy SQL request -to keep alive the connections to the database. -The default value is ’undefined’, so no keepalive requests are made. -Specify in seconds: for example 28800 means 8 hours. -

      {odbc_keepalive_interval, undefined}.
      -

      +you can find information to update your database schema.

      Driver Compilation

      You can skip this step if you installed ejabberd using a binary installer or if the binary packages of ejabberd you are using include support for @@ -1371,14 +1378,9 @@ directory as your ejabberd .beam files. (this is also needed for native PostgreSQL support!). This can be done, by using next commands:

      ./configure --enable-odbc && make install
      -

      -

      Authentication

      -

      The option value name may be misleading, as the auth_method name is used -for access to a relational database through ODBC, as well as through the native -PostgreSQL interface. Anyway, the first configuration step is to define the odbc -auth_method. For example: -

      {host_config, "public.example.org", [{auth_method, [odbc]}]}.
      -

      The actual database access is defined in the option odbc_server. Its +

      +

      Database Connection

      +

      The actual database access is defined in the option odbc_server. Its value is used to define if we want to use ODBC, or one of the two native interface available, PostgreSQL or MySQL.

      To use the native PostgreSQL interface, you can pass a tuple of the following form as parameter: @@ -1392,6 +1394,21 @@ can thus take the following form:

      {pgsql, "Server", Port, "Database", "Username", "Password"}
       

      The Port value should be an integer, without quotes. For example:

      {odbc_server, {pgsql, "localhost", 5432, "database", "ejabberd", "password"}}.
      +

      By default ejabberd opens 10 connections to the database for each virtual host. +Use this option to modify the value: +

      {odbc_pool_size, 10}.
      +

      You can configure an interval to make a dummy SQL request +to keep alive the connections to the database. +The default value is ’undefined’, so no keepalive requests are made. +Specify in seconds: for example 28800 means 8 hours. +

      {odbc_keepalive_interval, undefined}.
      +

      +

      Authentication

      +

      The option value name may be misleading, as the auth_method name is used +for access to a relational database through ODBC, as well as through the native +PostgreSQL interface. Anyway, the first configuration step is to define the odbc +auth_method. For example: +

      {auth_method, [odbc]}.
       

      Storage

      PostgreSQL also can be used to store information into from several ejabberd @@ -1406,15 +1423,7 @@ Keep in mind that you cannot have several variants of the same module loaded!

      Using ejabberd with MySQL native driver also can help you. Note that the tutorial contains information about ejabberd’s configuration which is duplicate to -this section.

      By default ejabberd opens 10 connections to the database for each virtual host. -Use this option to modify the value: -

      {odbc_pool_size, 10}.
      -

      You can configure an interval to make a dummy SQL request -to keep alive the connections to the database. -The default value is ’undefined’, so no keepalive requests are made. -Specify in seconds: for example 28800 means 8 hours. -

      {odbc_keepalive_interval, undefined}.
      -

      +this section.

      Driver Compilation

      You can skip this step if you installed ejabberd using a binary installer or if the binary packages of ejabberd you are using include support for ODBC.

      1. @@ -1424,16 +1433,26 @@ put them for example in the same directory as your ejabberd .beam files
      2. Then, configure, compile and install ejabberd with ODBC support enabled. This can be done, by using next commands:
        ./configure --enable-odbc && make install
        -

      -

      Authentication

      -

      The first configuration step is to define the odbc auth_method. For -example: -

      {host_config, "public.example.org", [{auth_method, [odbc]}]}.
      -

      The actual database access is defined in the option odbc_server. Its +

      +

      Database Connection

      +

      The actual database access is defined in the option odbc_server. Its value is used to defined if we want to use ODBC, or one of the two native interface available, PostgreSQL or MySQL.

      To use a relational database through ODBC, you can pass the ODBC connection string as odbc_server parameter. For example:

      {odbc_server, "DSN=database;UID=ejabberd;PWD=password"}.
      +

      By default ejabberd opens 10 connections to the database for each virtual host. +Use this option to modify the value: +

      {odbc_pool_size, 10}.
      +

      You can configure an interval to make a dummy SQL request +to keep alive the connections to the database. +The default value is ’undefined’, so no keepalive requests are made. +Specify in seconds: for example 28800 means 8 hours. +

      {odbc_keepalive_interval, undefined}.
      +

      +

      Authentication

      +

      The first configuration step is to define the odbc auth_method. For +example: +

      {auth_method, [odbc]}.
       

      Storage

      An ODBC compatible database also can be used to store information into from diff --git a/doc/guide.tex b/doc/guide.tex index 6702880f3..d40cd8ae5 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -1590,6 +1590,21 @@ The following LDAP servers are tested with \ejabberd{}: success with a not-listed server so that we can list it here. \end{itemize} +Important note about virtual hosting: +if you define several domains in ejabberd.cfg (see section \ref{hostnames}), +you probably want that each virtual host uses a different configuration of database, authentication and storage, +so that usernames do not conflict and mix between different virtual hosts. +For that purpose, the options described in the next sections +must be set inside a \term{host\_cofig} for each vhost (see section \ref{virtualhost}). +For example: +\begin{verbatim} +{host_config, "public.example.org", [ + {odbc_server, {pgsql, "localhost", "database-public-example-org", "ejabberd", "password"}}, + {auth_method, [odbc]} +]}. +\end{verbatim} + + \makesubsection{mysql}{MySQL} \ind{MySQL}\ind{MySQL!schema} @@ -1603,26 +1618,6 @@ Moreover, the file mysql.sql in the directory src/odbc might be interesting for you. This file contains the \ejabberd{} schema for MySQL. At the end of the file you can find information to update your database schema. -By default \ejabberd{} opens 10 connections to the database for each virtual host. -Use this option to modify the value: -\begin{verbatim} -{odbc_pool_size, 10}. -\end{verbatim} - -You can configure an interval to make a dummy SQL request -to keep alive the connections to the database. -The default value is 'undefined', so no keepalive requests are made. -Specify in seconds: for example 28800 means 8 hours. -\begin{verbatim} -{odbc_keepalive_interval, undefined}. -\end{verbatim} - -If the connection to the database fails, \ejabberd{} waits 30 seconds before retrying. -You can modify this interval with this option: -\begin{verbatim} -{odbc_start_interval, 30}. -\end{verbatim} - \makesubsubsection{compilemysql}{Driver Compilation} \ind{MySQL!Driver Compilation} @@ -1642,16 +1637,9 @@ if the binary packages of \ejabberd{} you are using include support for MySQL. \end{verbatim} \end{enumerate} -\makesubsubsection{mysqlauth}{Authentication} -\ind{MySQL!authentication} -The option value name may be misleading, as the \term{auth\_method} name is used -for access to a relational database through ODBC, as well as through the native -MySQL interface. Anyway, the first configuration step is to define the odbc -\term{auth\_method}. For example: -\begin{verbatim} -{host_config, "public.example.org", [{auth_method, [odbc]}]}. -\end{verbatim} +\makesubsubsection{configuremysql}{Database Connection} +\ind{MySQL!Database Connection} The actual database access is defined in the option \term{odbc\_server}. Its value is used to define if we want to use ODBC, or one of the two native @@ -1681,6 +1669,38 @@ The \term{Port} value should be an integer, without quotes. For example: {odbc_server, {mysql, "localhost", Port, "test", "root", "password"}}. \end{verbatim} +By default \ejabberd{} opens 10 connections to the database for each virtual host. +Use this option to modify the value: +\begin{verbatim} +{odbc_pool_size, 10}. +\end{verbatim} + +You can configure an interval to make a dummy SQL request +to keep alive the connections to the database. +The default value is 'undefined', so no keepalive requests are made. +Specify in seconds: for example 28800 means 8 hours. +\begin{verbatim} +{odbc_keepalive_interval, undefined}. +\end{verbatim} + +If the connection to the database fails, \ejabberd{} waits 30 seconds before retrying. +You can modify this interval with this option: +\begin{verbatim} +{odbc_start_interval, 30}. +\end{verbatim} + + +\makesubsubsection{mysqlauth}{Authentication} +\ind{MySQL!authentication} + +The option value name may be misleading, as the \term{auth\_method} name is used +for access to a relational database through ODBC, as well as through the native +MySQL interface. Anyway, the first configuration step is to define the odbc +\term{auth\_method}. For example: +\begin{verbatim} +{auth_method, [odbc]}. +\end{verbatim} + \makesubsubsection{mysqlstorage}{Storage} \ind{MySQL!storage} @@ -1707,6 +1727,24 @@ Moreover, the file mssql.sql in the directory src/odbc might be interesting for you. This file contains the \ejabberd{} schema for Microsoft SQL Server. At the end of the file you can find information to update your database schema. + +\makesubsubsection{compilemssql}{Driver Compilation} +\ind{Microsoft SQL Server!Driver Compilation} + +You can skip this step if you installed \ejabberd{} using a binary installer or +if the binary packages of \ejabberd{} you are using include support for ODBC. + +If you want to use Microsoft SQL Server with ODBC, you need to configure, +compile and install \ejabberd{} with support for ODBC and Microsoft SQL Server +enabled. This can be done, by using next commands: +\begin{verbatim} +./configure --enable-odbc --enable-mssql && make install +\end{verbatim} + + +\makesubsubsection{configuremssql}{Database Connection} +\ind{Microsoft SQL Server!Database Connection} + By default \ejabberd{} opens 10 connections to the database for each virtual host. Use this option to modify the value: \begin{verbatim} @@ -1721,18 +1759,6 @@ Specify in seconds: for example 28800 means 8 hours. {odbc_keepalive_interval, undefined}. \end{verbatim} -\makesubsubsection{compilemssql}{Driver Compilation} -\ind{Microsoft SQL Server!Driver Compilation} - -You can skip this step if you installed \ejabberd{} using a binary installer or -if the binary packages of \ejabberd{} you are using include support for ODBC. - -If you want to use Microsoft SQL Server with ODBC, you need to configure, -compile and install \ejabberd{} with support for ODBC and Microsoft SQL Server -enabled. This can be done, by using next commands: -\begin{verbatim} -./configure --enable-odbc --enable-mssql && make install -\end{verbatim} \makesubsubsection{mssqlauth}{Authentication} \ind{Microsoft SQL Server!authentication} @@ -1767,19 +1793,6 @@ Also the file pg.sql in the directory src/odbc might be interesting for you. This file contains the \ejabberd{} schema for PostgreSQL. At the end of the file you can find information to update your database schema. -By default \ejabberd{} opens 10 connections to the database for each virtual host. -Use this option to modify the value: -\begin{verbatim} -{odbc_pool_size, 10}. -\end{verbatim} - -You can configure an interval to make a dummy SQL request -to keep alive the connections to the database. -The default value is 'undefined', so no keepalive requests are made. -Specify in seconds: for example 28800 means 8 hours. -\begin{verbatim} -{odbc_keepalive_interval, undefined}. -\end{verbatim} \makesubsubsection{compilepgsql}{Driver Compilation} \ind{PostgreSQL!Driver Compilation} @@ -1802,16 +1815,9 @@ PostgreSQL. \end{verbatim} \end{enumerate} -\makesubsubsection{pgsqlauth}{Authentication} -\ind{PostgreSQL!authentication} -The option value name may be misleading, as the \term{auth\_method} name is used -for access to a relational database through ODBC, as well as through the native -PostgreSQL interface. Anyway, the first configuration step is to define the odbc -\term{auth\_method}. For example: -\begin{verbatim} -{host_config, "public.example.org", [{auth_method, [odbc]}]}. -\end{verbatim} +\makesubsubsection{configurepgsql}{Database Connection} +\ind{PostgreSQL!Database Connection} The actual database access is defined in the option \term{odbc\_server}. Its value is used to define if we want to use ODBC, or one of the two native @@ -1840,6 +1846,32 @@ The \term{Port} value should be an integer, without quotes. For example: \begin{verbatim} {odbc_server, {pgsql, "localhost", 5432, "database", "ejabberd", "password"}}. \end{verbatim} +By default \ejabberd{} opens 10 connections to the database for each virtual host. +Use this option to modify the value: +\begin{verbatim} +{odbc_pool_size, 10}. +\end{verbatim} + +You can configure an interval to make a dummy SQL request +to keep alive the connections to the database. +The default value is 'undefined', so no keepalive requests are made. +Specify in seconds: for example 28800 means 8 hours. +\begin{verbatim} +{odbc_keepalive_interval, undefined}. +\end{verbatim} + + +\makesubsubsection{pgsqlauth}{Authentication} +\ind{PostgreSQL!authentication} + +The option value name may be misleading, as the \term{auth\_method} name is used +for access to a relational database through ODBC, as well as through the native +PostgreSQL interface. Anyway, the first configuration step is to define the odbc +\term{auth\_method}. For example: +\begin{verbatim} +{auth_method, [odbc]}. +\end{verbatim} + \makesubsubsection{pgsqlstorage}{Storage} \ind{PostgreSQL!storage} @@ -1861,19 +1893,6 @@ of your database. Check the documentation of your database. The tutorial \footah contains information about \ejabberd{}'s configuration which is duplicate to this section. -By default \ejabberd{} opens 10 connections to the database for each virtual host. -Use this option to modify the value: -\begin{verbatim} -{odbc_pool_size, 10}. -\end{verbatim} - -You can configure an interval to make a dummy SQL request -to keep alive the connections to the database. -The default value is 'undefined', so no keepalive requests are made. -Specify in seconds: for example 28800 means 8 hours. -\begin{verbatim} -{odbc_keepalive_interval, undefined}. -\end{verbatim} \makesubsubsection{compileodbc}{Driver Compilation} @@ -1892,14 +1911,9 @@ ODBC. \end{verbatim} \end{enumerate} -\makesubsubsection{odbcauth}{Authentication} -\ind{ODBC!authentication} -The first configuration step is to define the odbc \term{auth\_method}. For -example: -\begin{verbatim} -{host_config, "public.example.org", [{auth_method, [odbc]}]}. -\end{verbatim} +\makesubsubsection{configureodbc}{Database Connection} +\ind{ODBC!Database Connection} The actual database access is defined in the option \term{odbc\_server}. Its value is used to defined if we want to use ODBC, or one of the two native @@ -1911,6 +1925,31 @@ string as \term{odbc\_server} parameter. For example: {odbc_server, "DSN=database;UID=ejabberd;PWD=password"}. \end{verbatim} +By default \ejabberd{} opens 10 connections to the database for each virtual host. +Use this option to modify the value: +\begin{verbatim} +{odbc_pool_size, 10}. +\end{verbatim} + +You can configure an interval to make a dummy SQL request +to keep alive the connections to the database. +The default value is 'undefined', so no keepalive requests are made. +Specify in seconds: for example 28800 means 8 hours. +\begin{verbatim} +{odbc_keepalive_interval, undefined}. +\end{verbatim} + + +\makesubsubsection{odbcauth}{Authentication} +\ind{ODBC!authentication} + +The first configuration step is to define the odbc \term{auth\_method}. For +example: +\begin{verbatim} +{auth_method, [odbc]}. +\end{verbatim} + + \makesubsubsection{odbcstorage}{Storage} \ind{ODBC!storage} diff --git a/src/Makefile.in b/src/Makefile.in index 096af8b5a..8917df636 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -194,6 +194,8 @@ install: all install -m 644 *.hrl $(INCLUDEDIR) install -d $(INCLUDEDIR)/eldap/ install -m 644 eldap/*.hrl $(INCLUDEDIR)/eldap/ + install -d $(INCLUDEDIR)/mod_muc/ + install -m 644 mod_muc/*.hrl $(INCLUDEDIR)/mod_muc/ install -d $(INCLUDEDIR)/mod_proxy65/ install -m 644 mod_proxy65/*.hrl $(INCLUDEDIR)/mod_proxy65/ install -d $(INCLUDEDIR)/mod_pubsub/ diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 7fa38ae98..39c6c6d3a 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -781,10 +781,43 @@ wait_for_session(closed, StateData) -> session_established({xmlstreamelement, El}, StateData) -> + FromJID = StateData#state.jid, + % Check 'from' attribute in stanza RFC 3920 Section 9.1.2 + case check_from(El, FromJID) of + 'invalid-from' -> + send_element(StateData, exmpp_stream:error('invalid-from')), + send_element(StateData, exmpp_stream:closing()), + {stop, normal, StateData}; + _NewEl -> + session_established2(El, StateData) + end; + +%% We hibernate the process to reduce memory consumption after a +%% configurable activity timeout +session_established(timeout, StateData) -> + %% TODO: Options must be stored in state: + Options = [], + proc_lib:hibernate(gen_fsm, enter_loop, + [?MODULE, Options, session_established, StateData]), + fsm_next_state(session_established, StateData); + +session_established({xmlstreamend, _Name}, StateData) -> + send_element(StateData, exmpp_stream:closing()), + {stop, normal, StateData}; + +session_established({xmlstreamerror, _}, StateData) -> + send_element(StateData, exmpp_stream:error('xml-not-well-formed')), + send_element(StateData, exmpp_stream:closing()), + {stop, normal, StateData}; + +session_established(closed, StateData) -> + {stop, normal, StateData}. + + +session_established2(El, StateData) -> try User = StateData#state.user, Server = StateData#state.server, - % TODO: check 'from' attribute in stanza FromJID = StateData#state.jid, To = exmpp_stanza:get_recipient(El), ToJID = case To of @@ -867,30 +900,7 @@ session_established({xmlstreamelement, El}, 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 -%% configurable activity timeout -session_established(timeout, StateData) -> - %% TODO: Options must be stored in state: - Options = [], - proc_lib:hibernate(gen_fsm, enter_loop, - [?MODULE, Options, session_established, StateData]), - fsm_next_state(session_established, StateData); - -session_established({xmlstreamend, _Name}, StateData) -> - send_element(StateData, exmpp_stream:closing()), - {stop, normal, StateData}; - -session_established({xmlstreamerror, _}, StateData) -> - send_element(StateData, exmpp_stream:error('xml-not-well-formed')), - send_element(StateData, exmpp_stream:closing()), - {stop, normal, StateData}; - -session_established(closed, StateData) -> - {stop, normal, StateData}. - - + end. %%---------------------------------------------------------------------- %% Func: StateName/3 @@ -1891,3 +1901,37 @@ fsm_reply(Reply, StateName, StateData) -> %% Used by c2s blacklist plugins is_ip_blacklisted({IP,_Port}) -> ejabberd_hooks:run_fold(check_bl_c2s, false, [IP]). + +%% Check from attributes +%% returns invalid-from|NewElement +check_from(El, FromJID) -> + case exmpp_stanza:get_sender(El) of + undefined -> + exmpp_stanza:set_sender(El, FromJID); + JIDElString -> + try + JIDEl = exmpp_jid:list_to_jid(JIDElString), + case JIDEl#jid.lresource of + undefined -> + %% Matching JID: The stanza is ok + if JIDEl#jid.lnode == FromJID#jid.lnode andalso + JIDEl#jid.ldomain == FromJID#jid.ldomain -> + El; + true -> + 'invalid-from' + end; + _ -> + %% Matching JID: The stanza is ok + if JIDEl#jid.lnode == FromJID#jid.lnode andalso + JIDEl#jid.ldomain == FromJID#jid.ldomain andalso + JIDEl#jid.lresource == FromJID#jid.lresource -> + El; + true -> + 'invalid-from' + end + end + catch + _:_ -> + 'invalid-from' + end + end. diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 6096375fd..b1884e7a2 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -49,70 +49,11 @@ -include_lib("exmpp/include/exmpp.hrl"). -include("ejabberd.hrl"). +-include("mod_muc_room.hrl"). --define(MAX_USERS_DEFAULT, 200). -define(MAX_USERS_DEFAULT_LIST, [5, 10, 20, 30, 50, 100, 200, 500, 1000, 2000, 5000]). --define(SETS, gb_sets). --define(DICT, dict). - --record(lqueue, {queue, len, max}). - --record(config, {title = "", - description = "", - allow_change_subj = true, - allow_query_users = true, - allow_private_messages = true, - allow_visitor_status = true, - allow_visitor_nickchange = true, - public = true, - public_list = true, - persistent = false, - moderated = true, - members_by_default = true, - members_only = false, - allow_user_invites = false, - password_protected = false, - password = "", - anonymous = true, - max_users = ?MAX_USERS_DEFAULT, - logging = false - }). - --record(user, {jid, - nick, - role, - last_presence}). - --record(activity, {message_time = 0, - presence_time = 0, - message_shaper, - presence_shaper, - message, - presence}). - --record(state, {room, - host, - server_host, - access, - jid, - config = #config{}, - users = ?DICT:new(), - affiliations = ?DICT:new(), - history = lqueue_new(20), - subject = "", - subject_author = "", - just_created = false, - activity = treap:empty(), - room_shaper, - room_queue = queue:new()}). - --record(muc_online_users, {us, - room, - host}). - - %-define(DBGFSM, true). -ifdef(DBGFSM). @@ -2761,7 +2702,7 @@ check_allowed_persistent_change(XEl, StateData, From) -> get_default_room_maxusers(RoomState) -> - DefRoomOpts = gen_mod:get_module_opt(RoomState#state.server_host, mod_muc, default_room_options, ?MAX_USERS_DEFAULT), + DefRoomOpts = gen_mod:get_module_opt(RoomState#state.server_host, mod_muc, default_room_options, []), RoomState2 = set_opts(DefRoomOpts, RoomState), (RoomState2#state.config)#config.max_users. diff --git a/src/mod_muc/mod_muc_room.hrl b/src/mod_muc/mod_muc_room.hrl new file mode 100644 index 000000000..1cc8cb1df --- /dev/null +++ b/src/mod_muc/mod_muc_room.hrl @@ -0,0 +1,80 @@ +%%%---------------------------------------------------------------------- +%%% +%%% ejabberd, Copyright (C) 2002-2008 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%%---------------------------------------------------------------------- + +-define(MAX_USERS_DEFAULT, 200). + +-define(SETS, gb_sets). +-define(DICT, dict). + +-record(lqueue, {queue, len, max}). + +-record(config, {title = "", + description = "", + allow_change_subj = true, + allow_query_users = true, + allow_private_messages = true, + allow_visitor_status = true, + allow_visitor_nickchange = true, + public = true, + public_list = true, + persistent = false, + moderated = true, + members_by_default = true, + members_only = false, + allow_user_invites = false, + password_protected = false, + password = "", + anonymous = true, + max_users = ?MAX_USERS_DEFAULT, + logging = false + }). + +-record(user, {jid, + nick, + role, + last_presence}). + +-record(activity, {message_time = 0, + presence_time = 0, + message_shaper, + presence_shaper, + message, + presence}). + +-record(state, {room, + host, + server_host, + access, + jid, + config = #config{}, + users = ?DICT:new(), + affiliations = ?DICT:new(), + history, + subject = "", + subject_author = "", + just_created = false, + activity = treap:empty(), + room_shaper, + room_queue = queue:new()}). + +-record(muc_online_users, {us, + room, + host}). diff --git a/src/odbc/ejabberd_odbc.erl b/src/odbc/ejabberd_odbc.erl index dfc1ee6c8..940d94d74 100644 --- a/src/odbc/ejabberd_odbc.erl +++ b/src/odbc/ejabberd_odbc.erl @@ -223,7 +223,15 @@ handle_info(_Info, State) -> %% Purpose: Shutdown the server %% Returns: any (ignored by gen_server) %%---------------------------------------------------------------------- -terminate(_Reason, _State) -> +terminate(_Reason, State) -> + case State#state.db_type of + mysql -> + % old versions of mysql driver don't have the stop function + % so the catch + catch mysql_conn:stop(State#state.db_ref); + _ -> + ok + end, ok. %%%---------------------------------------------------------------------- From 9f2fda60601cfa956c865f482d05f82fc6e863e3 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 9 Dec 2008 00:32:36 +0000 Subject: [PATCH 136/582] merge to lattest trunk r1716 SVN Revision: 1720 --- src/mod_pubsub/gen_pubsub_nodetree.erl | 2 + src/mod_pubsub/mod_pubsub.erl | 245 ++++++++++-------- src/mod_pubsub/node_default.erl | 4 + .../{node_zoo.erl => node_flat.erl} | 11 +- src/mod_pubsub/nodetree_default.erl | 8 + src/mod_pubsub/nodetree_virtual.erl | 8 + src/mod_pubsub/pubsub.hrl | 10 - 7 files changed, 161 insertions(+), 127 deletions(-) rename src/mod_pubsub/{node_zoo.erl => node_flat.erl} (97%) diff --git a/src/mod_pubsub/gen_pubsub_nodetree.erl b/src/mod_pubsub/gen_pubsub_nodetree.erl index ebdeca450..c249ff43d 100644 --- a/src/mod_pubsub/gen_pubsub_nodetree.erl +++ b/src/mod_pubsub/gen_pubsub_nodetree.erl @@ -42,7 +42,9 @@ behaviour_info(callbacks) -> {terminate, 2}, {options, 0}, {set_node, 1}, + {get_node, 3}, {get_node, 2}, + {get_nodes, 2}, {get_nodes, 1}, {get_subnodes, 3}, {get_subnodes_tree, 2}, diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index fed1c3aff..244268aa0 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -356,11 +356,11 @@ disco_sm_features(Acc, From, To, Node, _Lang) -> Acc end. -disco_sm_items(Acc, _From, To, [], _Lang) -> +disco_sm_items(Acc, From, To, [], _Lang) -> %% TODO, use iq_disco_items(Host, [], From) Host = To#jid.ldomain, LJID = jlib:short_prepd_bare_jid(To), - case tree_action(Host, get_nodes, [Host]) of + case tree_action(Host, get_nodes, [Host, From]) of [] -> Acc; Nodes -> @@ -460,7 +460,7 @@ handle_cast({presence, JID, Pid}, State) -> {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, JID]), lists:foreach( fun({Node, subscribed}) -> - case tree_action(Host, get_node, [Host, Node]) of + case tree_action(Host, get_node, [Host, Node, JID]) of #pubsub_node{options = Options} -> case get_option(Options, send_last_published_item) of on_sub_and_presence -> @@ -477,17 +477,14 @@ handle_cast({presence, JID, Pid}, State) -> end, State#state.plugins), %% and send to From last PEP events published by its contacts case catch ejabberd_c2s:get_subscribed(Pid) of - ContactsWithCaps when is_list(ContactsWithCaps) -> - Caps = proplists:get_value(LJID, ContactsWithCaps), - ContactsUsers = lists:usort(lists:map( - fun({{User, Server, _}, _}) -> {User, Server} end, ContactsWithCaps)), + Contacts when is_list(Contacts) -> lists:foreach( - fun({User, Server}) -> - PepKey = {User, Server, undefined}, + fun({User, Server, _}) -> + Owner = {User, Server, undefined}, lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) -> case get_option(Options, send_last_published_item) of on_sub_and_presence -> - case is_caps_notify(ServerHost, Node, Caps) of + case is_caps_notify(ServerHost, Node, LJID) of true -> Subscribed = case get_option(Options, access_model) of open -> true; @@ -499,8 +496,7 @@ handle_cast({presence, JID, Pid}, State) -> element(2, get_roster_info(User, Server, LJID, Grps)) end, if Subscribed -> - ?DEBUG("send ~s's ~s event to ~s",[exmpp_jid:jid_to_list(User, Server),Node,exmpp_jid:jid_to_list(JID)]), - send_last_item(PepKey, Node, LJID); + send_last_item(Owner, Node, LJID); true -> ok end; @@ -510,8 +506,8 @@ handle_cast({presence, JID, Pid}, State) -> _ -> ok end - end, tree_action(Host, get_nodes, [PepKey])) - end, ContactsUsers); + end, tree_action(Host, get_nodes, [Owner, JID])) + end, Contacts); _ -> ok end, @@ -786,7 +782,7 @@ iq_disco_items(Host, Item, From) -> Node = string_to_node(SNode), %% Note: Multiple Node Discovery not supported (mask on pubsub#type) %% TODO this code is also back-compatible with pubsub v1.8 (for client issue) - %% TODO make it pubsub v1.10 compliant (this breaks client compatibility) + %% TODO make it pubsub v1.12 compliant (breaks client compatibility ?) %% TODO That is, remove name attribute Action = fun(#pubsub_node{type = Type}) -> @@ -951,6 +947,10 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) -> get_subscriptions(Host, From, Plugins); {get, 'affiliations'} -> get_affiliations(Host, From, Plugins); + {get, "options"} -> + {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "subscription-options")}; + {set, "options"} -> + {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "subscription-options")}; _ -> {error, 'feature-not-implemented'} end; @@ -1024,7 +1024,7 @@ send_authorization_request(Host, Node, Subscriber) -> #xmlattr{name = 'type', value = "boolean"}, #xmlattr{name = 'label', value = translate:translate(Lang, "Allow this JID to subscribe to this pubsub node?")}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"false">>}]}]}]}]}, - case tree_action(Host, get_node, [Host, Node]) of + case tree_action(Host, get_node, [Host, Node, Subscriber]) of #pubsub_node{owners = Owners} -> lists:foreach( fun({U1, S1, R1}) -> @@ -1053,19 +1053,37 @@ find_authorization_response(Packet) -> [] -> none; [XFields] when is_list(XFields) -> case lists:keysearch("FORM_TYPE", 1, XFields) of - {value, {_, ?NS_PUBSUB_SUBSCRIBE_AUTH_s}} -> + {value, {_, [?NS_PUBSUB_SUBSCRIBE_AUTH_s]}} -> XFields; _ -> invalid end end. +%% @spec (Host, JID, Node, Subscription) -> void +%% Host = mod_pubsub:host() +%% JID = jlib:jid() +%% Node = string() +%% Subscription = atom() +%% Plugins = [Plugin::string()] +%% @doc Send a message to JID with the supplied Subscription +send_authorization_approval(Host, JID, Node, Subscription) -> + Stanza = {xmlelement, "message", + [], + [{xmlelement, "event", [{"xmlns", ?NS_PUBSUB_EVENT}], + [{xmlelement, "subscription", + [{"node", Node}, + {"jid", jlib:jid_to_string(JID)}, + {"subscription", subscription_to_string(Subscription)}], + []}]}]}, + ejabberd_router ! {route, service_jid(Host), JID, Stanza}. + handle_authorization_response(Host, From, To, Packet, XFields) -> case {lists:keysearch("pubsub#node", 1, XFields), lists:keysearch("pubsub#subscriber_jid", 1, XFields), lists:keysearch("pubsub#allow", 1, XFields)} of - {{value, {_, SNode}}, {value, {_, SSubscriber}}, - {value, {_, SAllow}}} -> + {{value, {_, [SNode]}}, {value, {_, [SSubscriber]}}, + {value, {_, [SAllow]}}} -> Node = case Host of {_, _, _} -> [SNode]; _ -> string:tokens(SNode, "/") @@ -1080,7 +1098,7 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> %%options = Options, owners = Owners}) -> IsApprover = lists:member(jlib:short_prepd_bare_jid(From), Owners), - Subscription = node_call(Type, get_subscription, [Host, Node, Subscriber]), + {result, Subscription} = node_call(Type, get_subscription, [Host, Node, Subscriber]), if not IsApprover -> {error, 'forbidden'}; @@ -1091,6 +1109,7 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> true -> subscribed; false -> none end, + send_authorization_approval(Host, Subscriber, SNode, NewSubscription), node_call(Type, set_subscription, [Host, Node, Subscriber, NewSubscription]) end end, @@ -1457,34 +1476,38 @@ publish_item(Host, ServerHost, Node, Publisher, "", Payload) -> publish_item(Host, ServerHost, Node, Publisher, uniqid(), Payload); publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> Action = fun(#pubsub_node{options = Options, type = Type}) -> - Features = features(Type), - PublishFeature = lists:member("publish", Features), - PublishModel = get_option(Options, publish_model), - MaxItems = max_items(Options), - PayloadSize = size(term_to_binary(Payload)), - PayloadMaxSize = get_option(Options, max_payload_size), - if - not PublishFeature -> - %% Node does not support item publication - {error, extended_error('feature-not-implemented', unsupported, "publish")}; - PayloadSize > PayloadMaxSize -> - %% Entity attempts to publish very large payload - {error, extended_error('not-acceptable', "payload-too-big")}; - %%?? -> iq_pubsub just does that matchs - %% % Entity attempts to publish item with multiple payload elements or namespace does not match - %% {error, extended_error('bad-request', "invalid-payload")}; - %% % Publisher attempts to publish to persistent node with no item - %% {error, extended_error('bad-request', "item-required")}; - Payload == "" -> - %% Publisher attempts to publish to payload node with no payload - {error, extended_error('bad-request', "payload-required")}; - %%?? -> - %% % Publisher attempts to publish to transient notification node with item - %% {error, extended_error('bad-request', "item-forbidden")}; - true -> - node_call(Type, publish_item, [Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload]) - end - end, + Features = features(Type), + PublishFeature = lists:member("publish", Features), + PublishModel = get_option(Options, publish_model), + MaxItems = max_items(Options), + PayloadCount = payload_elements(xmlelement, Payload), + PayloadSize = size(term_to_binary(Payload)), + PayloadMaxSize = get_option(Options, max_payload_size), + % pubsub#deliver_payloads true + % pubsub#persist_items true -> 1 item; false -> 0 item + if + not PublishFeature -> + %% Node does not support item publication + {error, extended_error('feature-not-implemented', unsupported, "publish")}; + PayloadSize > PayloadMaxSize -> + %% Entity attempts to publish very large payload + {error, extended_error('not-acceptable', "payload-too-big")}; + PayloadCount > 1 -> + %% Entity attempts to publish item with multiple payload elements + {error, extended_error('bad-request', "invalid-payload")}; + Payload == "" -> + %% Publisher attempts to publish to payload node with no payload + {error, extended_error('bad-request', "payload-required")}; + (MaxItems == 0) and (PayloadSize > 0) -> + % Publisher attempts to publish to transient notification node with item + {error, extended_error('bad-request', "item-forbidden")}; + (MaxItems > 0) and (PayloadSize == 0) -> + % Publisher attempts to publish to persistent node with no item + {error, extended_error('bad-request', "item-required")}; + true -> + node_call(Type, publish_item, [Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload]) + end + end, ejabberd_hooks:run(pubsub_publish_item, ServerHost, [ServerHost, Node, Publisher, service_jid(Host), ItemId, Payload]), Reply = [], case transaction(Host, Node, Action, sync_dirty) of @@ -1556,7 +1579,7 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> PersistentFeature = lists:member("persistent-items", Features), DeleteFeature = lists:member("delete-nodes", Features), if - %%?? -> iq_pubsub just does that matchs + %%-> iq_pubsub just does that matchs %% %% Request does not specify an item %% {error, extended_error('bad-request', "item-required")}; not PersistentFeature -> @@ -1735,7 +1758,7 @@ send_items(Host, Node, {LU, LS, LR} = LJID, Number) -> []; Items -> case Number of - last -> lists:sublist(lists:reverse(Items), 1); + last -> lists:last(Items); all -> Items; N when N > 0 -> lists:nthtail(length(Items)-N, Items); _ -> Items @@ -2098,6 +2121,15 @@ is_to_delivered({User, Server, _}, _, true) -> end, false, Ss) end. +%% @spec (Elem, Payload) -> int() +%% Elem = atom() +%% Payload = term() +%% @doc

      Count occurence of given element in payload.

      +payload_elements(Elem, Payload) -> payload_elements(Elem, Payload, 0). +payload_elements(_, [], Count) -> Count; +payload_elements(Elem, [Elem|Tail], Count) -> payload_elements(Elem, Tail, Count+1); +payload_elements(Elem, [_|Tail], Count) -> payload_elements(Elem, Tail, Count). + %%%%%% broadcast functions broadcast_publish_item(Host, Node, ItemId, _From, Payload) -> @@ -2324,58 +2356,52 @@ broadcast_config_notification(Host, Node, Lang) -> %% broadcast Stanza to all contacts of the user that are advertising %% interest in this kind of Node. broadcast_by_caps({LUser, LServer, LResource}, Node, _Type, Stanza) -> - ?DEBUG("looking for pid of ~p@~p/~p", [LUser, LServer, LResource]), - %% We need to know the resource, so we can ask for presence data. - SenderResource = case LResource of - undefined -> - %% If we don't know the resource, just pick one. - case ejabberd_sm:get_user_resources(LUser, LServer) of - [R|_] -> - R; - [] -> - undefined - end; - _ -> - LResource - end, - case SenderResource of - undefined -> - ?DEBUG("~p@~p is offline; can't deliver ~p to contacts", [LUser, LServer, Stanza]), - ok; - _ -> - case ejabberd_sm:get_session_pid(LUser, LServer, SenderResource) of - C2SPid when is_pid(C2SPid) -> - %% set the from address on the notification to the bare JID of the account owner - %% Also, add "replyto" if entity has presence subscription to the account owner - %% See XEP-0163 1.1 section 4.3.1 - Sender = exmpp_jid:make_jid(LUser, LServer), - %%ReplyTo = jlib:make_jid(LUser, LServer, SenderResource), % This has to be used - case catch ejabberd_c2s:get_subscribed_and_online(C2SPid) of - ContactsWithCaps when is_list(ContactsWithCaps) -> - ?DEBUG("found contacts with caps: ~p", [ContactsWithCaps]), - lists:foreach( - fun({{U1, S1, R1}, Caps}) -> - case is_caps_notify(LServer, Node, Caps) of - true -> - To = exmpp_jid:make_jid(U1, S1, R1), - ejabberd_router ! {route, Sender, To, Stanza}; - false -> - ok + SenderResource = user_resource(LUser, LServer, LResource), + case ejabberd_sm:get_session_pid(LUser, LServer, SenderResource) of + C2SPid when is_pid(C2SPid) -> + %% set the from address on the notification to the bare JID of the account owner + %% Also, add "replyto" if entity has presence subscription to the account owner + %% See XEP-0163 1.1 section 4.3.1 + Sender = exmpp_jid:make_jid(LUser, LServer), + %%ReplyTo = jlib:make_jid(LUser, LServer, SenderResource), % This has to be used + case catch ejabberd_c2s:get_subscribed(C2SPid) of + Contacts when is_list(Contacts) -> + Online = lists:foldl(fun({U, S, R}, Acc) -> + case user_resource(U, S, R) of + [] -> Acc; + OR -> [{U, S, OR}|Acc] end - end, ContactsWithCaps); - _ -> - ok - end, - ok; - _ -> - ?DEBUG("~p@~p has no session; can't deliver ~p to contacts", [LUser, LServer, Stanza]), - ok - end + end, [], Contacts), + lists:foreach(fun({U, S, R}) -> + case is_caps_notify(LServer, Node, {U, S, R}) of + true -> + ejabberd_router ! {route, Sender, exmpp_jlib:make_jid(U, S, R), Stanza}; + false -> + ok + end + end, Online); + _ -> + ok + end, + ok; + _ -> + ?DEBUG("~p@~p has no session; can't deliver ~p to contacts", [LUser, LServer, Stanza]), + ok end; broadcast_by_caps(_, _, _, _) -> ok. + +user_resource(LUser, LServer, []) -> + %% If we don't know the resource, just pick first if any + case ejabberd_sm:get_user_resources(LUser, LServer) of + [R|_] -> R; + [] -> [] + end; +user_resource(_, _, LResource) -> + LResource. -is_caps_notify(Host, Node, Caps) -> +is_caps_notify(Host, Node, LJID) -> + Caps = mod_caps:get_caps(LJID), case catch mod_caps:get_features(Host, Caps) of Features when is_list(Features) -> lists:member(Node ++ "+notify", Features); _ -> false @@ -2408,7 +2434,7 @@ get_configure(Host, Node, From, Lang) -> transaction(Host, Node, Action, sync_dirty). get_default(Host, Node, _From, Lang) -> - Type=select_type(Host, Host, Node), + Type = select_type(Host, Host, Node), Options = node_options(Type), {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'default', children = @@ -2647,7 +2673,8 @@ set_xoption([{"pubsub#type", Value} | Opts], NewOpts) -> set_xoption([{"pubsub#body_xslt", Value} | Opts], NewOpts) -> ?SET_STRING_XOPT(body_xslt, Value); set_xoption([_ | _Opts], _NewOpts) -> - {error, 'not-acceptable'}. + % skip unknown field + set_xoption(Opts, NewOpts). %%%% plugin handling @@ -2657,18 +2684,18 @@ plugins(Host) -> _ -> [?STDNODE] end. select_type(ServerHost, Host, Node, Type)-> - ?DEBUG("SELECT_TYPE : ~p~n", [Node]), - case Host of - {_User, _Server, _Resource} -> - case ets:lookup(gen_mod:get_module_proc(ServerHost, pubsub_state), pep_mapping) of - [{pep_mapping, PM}] -> ?DEBUG("SELECT_TYPE : ~p~n", [PM]), proplists:get_value(Node, PM,?PEPNODE); - R -> ?DEBUG("SELECT_TYPE why ?: ~p~n", [R]), ?PEPNODE - end; - _ -> - Type + ?DEBUG("SELECT_TYPE : ~p~n", [[ServerHost, Host, Node, Type]]), + case Host of + {_User, _Server, _Resource} -> + case ets:lookup(gen_mod:get_module_proc(ServerHost, pubsub_state), pep_mapping) of + [{pep_mapping, PM}] -> ?DEBUG("SELECT_TYPE : ~p~n", [PM]), proplists:get_value(Node, PM, ?PEPNODE); + R -> ?DEBUG("SELECT_TYPE why ?: ~p~n", [R]), ?PEPNODE + end; + _ -> + Type end. select_type(ServerHost, Host, Node) -> - select_type(ServerHost, Host, Node,hd(plugins(ServerHost))). + select_type(ServerHost, Host, Node, hd(plugins(ServerHost))). features() -> [ diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 15d871300..8757ac4a4 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -382,6 +382,10 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> %% Requesting entity is prohibited from unsubscribing entity not Authorized -> {error, 'forbidden'}; + %% Was just subscriber, remove the record + State#pubsub_state.affiliation == none -> + mnesia:delete({pubsub_state, State#pubsub_state.stateid}), + {result, default}; true -> set_state(State#pubsub_state{subscription = none}), {result, default} diff --git a/src/mod_pubsub/node_zoo.erl b/src/mod_pubsub/node_flat.erl similarity index 97% rename from src/mod_pubsub/node_zoo.erl rename to src/mod_pubsub/node_flat.erl index 0fc6fb797..6996912b0 100644 --- a/src/mod_pubsub/node_zoo.erl +++ b/src/mod_pubsub/node_flat.erl @@ -22,7 +22,7 @@ %%% @end %%% ==================================================================== --module(node_zoo). +-module(node_flat). -author('christophe.romain@process-one.net'). -include_lib("exmpp/include/exmpp.hrl"). @@ -70,7 +70,7 @@ terminate(Host, ServerHost) -> node_default:terminate(Host, ServerHost). options() -> - [{node_type, zoo}, + [{node_type, flat}, {deliver_payloads, true}, {notify_config, false}, {notify_delete, false}, @@ -99,12 +99,7 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> true; % pubsub service always allowed _ -> {LU, LS, LR} = LOwner, - case acl:match_rule(ServerHost, Access, exmpp_jid:make_jid(LU, LS, LR)) of - allow -> - true; - _ -> - false - end + acl:match_rule(ServerHost, Access, exmpp_jid:make_jid(LU, LS, LR)) =:= allow end, {result, Allowed}. diff --git a/src/mod_pubsub/nodetree_default.erl b/src/mod_pubsub/nodetree_default.erl index 0c3ce3082..126ea7f75 100644 --- a/src/mod_pubsub/nodetree_default.erl +++ b/src/mod_pubsub/nodetree_default.erl @@ -46,7 +46,9 @@ terminate/2, options/0, set_node/1, + get_node/3, get_node/2, + get_nodes/2, get_nodes/1, get_subnodes/3, get_subnodes_tree/2, @@ -98,6 +100,9 @@ set_node(_) -> %% @spec (Host, Node) -> pubsubNode() | {error, Reason} %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() +get_node(Host, Node, _From) -> + get_node(Host, Node). + get_node(Host, Node) -> case catch mnesia:read({pubsub_node, {Host, Node}}) of [Record] when is_record(Record, pubsub_node) -> Record; @@ -107,6 +112,9 @@ get_node(Host, Node) -> %% @spec (Key) -> [pubsubNode()] | {error, Reason} %% Key = mod_pubsub:host() | mod_pubsub:jid() +get_nodes(Key, _From) -> + get_nodes(Key). + get_nodes(Key) -> mnesia:match_object(#pubsub_node{nodeid = {Key, '_'}, _ = '_'}). diff --git a/src/mod_pubsub/nodetree_virtual.erl b/src/mod_pubsub/nodetree_virtual.erl index 80a6e745e..2df61e70a 100644 --- a/src/mod_pubsub/nodetree_virtual.erl +++ b/src/mod_pubsub/nodetree_virtual.erl @@ -44,7 +44,9 @@ terminate/2, options/0, set_node/1, + get_node/3, get_node/2, + get_nodes/2, get_nodes/1, get_subnodes/3, get_subnodes_tree/2, @@ -87,6 +89,9 @@ set_node(_NodeRecord) -> %% Node = mod_pubsub:pubsubNode() %% @doc

      Virtual node tree does not handle a node database. Any node is considered %% as existing. Node record contains default values.

      +get_node(Host, Node, _From) -> + get_node(Host, Node). + get_node(Host, Node) -> #pubsub_node{nodeid = {Host, Node}}. @@ -94,6 +99,9 @@ get_node(Host, Node) -> %% Host = mod_pubsub:host() | mod_pubsub:jid() %% @doc

      Virtual node tree does not handle a node database. Any node is considered %% as existing. Nodes list can not be determined.

      +get_nodes(Key, _From) -> + get_nodes(Key). + get_nodes(_Key) -> []. diff --git a/src/mod_pubsub/pubsub.hrl b/src/mod_pubsub/pubsub.hrl index f763909a7..b4ceed4fa 100644 --- a/src/mod_pubsub/pubsub.hrl +++ b/src/mod_pubsub/pubsub.hrl @@ -119,13 +119,3 @@ payload = [] }). - -%% @type pubsubPresence() = #pubsub_presence{ -%% key = {Host::host(), User::string(), Server::string()}, -%% presence = list()}. -%%%

      This is the format of the published presence table. The type of the -%%% table is: set,ram.

      --record(pubsub_presence, {key, - resource - }). - From 44b4c29d08fefd1b6bf158ded1e712c7a04b3d0d Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 9 Dec 2008 00:35:27 +0000 Subject: [PATCH 137/582] lattest pubsub merge added in Changelog SVN Revision: 1721 --- ChangeLog | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index e703e7aa9..c5773945b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,10 @@ +2008-12-09 Christophe Romain + + * src/mod_pubsub: Mergr from lattest trunk (r1716). + 2008-12-08 Jean-Sébastien Pédron - Merge from trunk (r1692 to r1709). + * src/mod_pubsub: Merge from trunk (r1692 to r1709). 2008-12-08 Jean-Sébastien Pédron From 3d28a7837d13373a9497b1ee26a85867e17166b4 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 9 Dec 2008 22:09:30 +0000 Subject: [PATCH 138/582] minor bugfix SVN Revision: 1723 --- src/mod_pubsub/mod_pubsub.erl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 244268aa0..8f009e1ca 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -1480,7 +1480,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> PublishFeature = lists:member("publish", Features), PublishModel = get_option(Options, publish_model), MaxItems = max_items(Options), - PayloadCount = payload_elements(xmlelement, Payload), + PayloadCount = payload_xmlelements(Payload), PayloadSize = size(term_to_binary(Payload)), PayloadMaxSize = get_option(Options, max_payload_size), % pubsub#deliver_payloads true @@ -2125,10 +2125,10 @@ is_to_delivered({User, Server, _}, _, true) -> %% Elem = atom() %% Payload = term() %% @doc

      Count occurence of given element in payload.

      -payload_elements(Elem, Payload) -> payload_elements(Elem, Payload, 0). -payload_elements(_, [], Count) -> Count; -payload_elements(Elem, [Elem|Tail], Count) -> payload_elements(Elem, Tail, Count+1); -payload_elements(Elem, [_|Tail], Count) -> payload_elements(Elem, Tail, Count). +payload_xmlelements(Payload) -> payload_xmlelements(Payload, 0). +payload_xmlelements([], Count) -> Count; +payload_xmlelements([{xmlelement, _, _, _}|Tail], Count) -> payload_xmlelements(Tail, Count+1); +payload_xmlelements([_|Tail], Count) -> payload_xmlelements(Tail, Count). %%%%%% broadcast functions From e1575e3177cd75fea8d6dc103ffa32958717cce2 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 9 Dec 2008 22:42:34 +0000 Subject: [PATCH 139/582] fix typo bug injected in r1712 SVN Revision: 1725 --- src/mod_pubsub/mod_pubsub.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 8f009e1ca..97233b1a8 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -1758,7 +1758,7 @@ send_items(Host, Node, {LU, LS, LR} = LJID, Number) -> []; Items -> case Number of - last -> lists:last(Items); + last -> [lists:last(Items)]; all -> Items; N when N > 0 -> lists:nthtail(length(Items)-N, Items); _ -> Items From f83fc5196051f2ffd4326290a409abf78d7f1523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 10 Dec 2008 14:44:08 +0000 Subject: [PATCH 140/582] Replace stringprep by exmpp_stringprep. PR: EJABP-1 SVN Revision: 1726 --- ChangeLog | 7 ++++++- src/eldap/eldap_utils.erl | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index c5773945b..b6895da2b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,11 @@ +2008-12-10 Jean-Sébastien Pédron + + * src/eldap/eldap_utils.erl (case_insensitive_match/2): Replace + stringprep by exmpp_stringprep. + 2008-12-09 Christophe Romain - * src/mod_pubsub: Mergr from lattest trunk (r1716). + * src/mod_pubsub: Merge from latest trunk (r1716). 2008-12-08 Jean-Sébastien Pédron diff --git a/src/eldap/eldap_utils.erl b/src/eldap/eldap_utils.erl index 1f6d156d3..759725c53 100644 --- a/src/eldap/eldap_utils.erl +++ b/src/eldap/eldap_utils.erl @@ -121,8 +121,8 @@ make_filter(Data, UIDs) -> end. case_insensitive_match(X, Y) -> - X1 = stringprep:tolower(X), - Y1 = stringprep:tolower(Y), + X1 = exmpp_stringprep:to_lower(X), + Y1 = exmpp_stringprep:to_lower(Y), if X1 == Y1 -> true; true -> false From 96aaba738bc02aab12125687b477ac0b0aa21da4 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Mon, 15 Dec 2008 19:58:53 +0000 Subject: [PATCH 141/582] fix get_item_name deadlock on transaction SVN Revision: 1729 --- ChangeLog | 5 +++++ src/mod_pubsub/mod_pubsub.erl | 11 ++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index b6895da2b..544b2a392 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-12-15 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: fix get_item_name deadlock on + transaction + 2008-12-10 Jean-Sébastien Pédron * src/eldap/eldap_utils.erl (case_insensitive_match/2): Replace diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 97233b1a8..0021bfdcf 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -393,9 +393,10 @@ disco_sm_items(Acc, From, To, Node, _Lang) -> fun(#pubsub_item{itemid = Id}) -> %% "jid" is required by XEP-0030, and %% "node" is forbidden by XEP-0060. + {result, Name} = node_action(Host, Node, get_item_name, [Host, Node, Id]), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(LJID)}, - #xmlattr{name = 'name', value = get_item_name(Host, Node, Id)}]} + #xmlattr{name = 'name', value = Name}]} end, AllItems), {result, NodeItems ++ Items} end. @@ -800,8 +801,9 @@ iq_disco_items(Host, Item, From) -> Items = lists:map( fun(#pubsub_item{itemid = {RN, _}}) -> SN = node_to_string(Node) ++ "!" ++ RN, + {result, Name} = node_call(Type, get_item_name, [Host, Node, RN]), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [#xmlattr{name = 'jid', value = Host}, #xmlattr{name = 'node', value = SN}, - #xmlattr{name = 'name', value = get_item_name(Host, Node, RN)}]} + #xmlattr{name = 'name', value = Name}]} end, NodeItems), {result, Nodes ++ Items} end, @@ -2840,8 +2842,3 @@ uniqid() -> {T1, T2, T3} = now(), lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])). -%% @doc Return the name of a given node if available. -get_item_name(Host, Node, Id) -> - {result, Name} = node_action(Host, Node, get_item_name, [Host, Node, Id]), - Name. - From 62f9f6e6c5d918cdf6b4013a7e8cde3a7f7041ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 16 Dec 2008 10:31:08 +0000 Subject: [PATCH 142/582] Convert to exmpp the parts in mod_pubsub recently merged from trunk. Warning: Ejabberd is unusable because the rest of trunk hasn't been merged yet! PR: EJABP-1 SVN Revision: 1730 --- ChangeLog | 8 +++++++- src/mod_pubsub/mod_pubsub.erl | 28 +++++++++++++--------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index 544b2a392..22274b464 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,12 @@ +2008-12-16 Jean-Sébastien Pédron + + * src/mod_pubsub/mod_pubsub.erl: Convert to exmpp the parts recently + merged from trunk. Warning: Ejabberd is unusable because the rest of + trunk hasn't been merged yet! + 2008-12-15 Christophe Romain - * src/mod_pubsub/mod_pubsub.erl: fix get_item_name deadlock on + * src/mod_pubsub/mod_pubsub.erl: Fix get_item_name deadlock on transaction 2008-12-10 Jean-Sébastien Pédron diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 0021bfdcf..41da14324 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -480,9 +480,9 @@ handle_cast({presence, JID, Pid}, State) -> case catch ejabberd_c2s:get_subscribed(Pid) of Contacts when is_list(Contacts) -> lists:foreach( - fun({User, Server, _}) -> + fun({{User, Server, _}, _}) -> Owner = {User, Server, undefined}, - lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) -> + lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options} = PN) -> case get_option(Options, send_last_published_item) of on_sub_and_presence -> case is_caps_notify(ServerHost, Node, LJID) of @@ -950,9 +950,9 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) -> {get, 'affiliations'} -> get_affiliations(Host, From, Plugins); {get, "options"} -> - {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "subscription-options")}; + {error, extended_error('feature-not-implemented', unsupported, "subscription-options")}; {set, "options"} -> - {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "subscription-options")}; + {error, extended_error('feature-not-implemented', unsupported, "subscription-options")}; _ -> {error, 'feature-not-implemented'} end; @@ -1070,14 +1070,12 @@ find_authorization_response(Packet) -> %% Plugins = [Plugin::string()] %% @doc Send a message to JID with the supplied Subscription send_authorization_approval(Host, JID, Node, Subscription) -> - Stanza = {xmlelement, "message", - [], - [{xmlelement, "event", [{"xmlns", ?NS_PUBSUB_EVENT}], - [{xmlelement, "subscription", - [{"node", Node}, - {"jid", jlib:jid_to_string(JID)}, - {"subscription", subscription_to_string(Subscription)}], - []}]}]}, + Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'subscription', attrs = + [#xmlattr{name = 'node', value = Node}, + #xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(JID)}, + #xmlattr{name = 'subscription', value = subscription_to_string(Subscription)}]}]}]}, ejabberd_router ! {route, service_jid(Host), JID, Stanza}. handle_authorization_response(Host, From, To, Packet, XFields) -> @@ -2129,7 +2127,7 @@ is_to_delivered({User, Server, _}, _, true) -> %% @doc

      Count occurence of given element in payload.

      payload_xmlelements(Payload) -> payload_xmlelements(Payload, 0). payload_xmlelements([], Count) -> Count; -payload_xmlelements([{xmlelement, _, _, _}|Tail], Count) -> payload_xmlelements(Tail, Count+1); +payload_xmlelements([#xmlel{}|Tail], Count) -> payload_xmlelements(Tail, Count+1); payload_xmlelements([_|Tail], Count) -> payload_xmlelements(Tail, Count). %%%%%% broadcast functions @@ -2377,7 +2375,7 @@ broadcast_by_caps({LUser, LServer, LResource}, Node, _Type, Stanza) -> lists:foreach(fun({U, S, R}) -> case is_caps_notify(LServer, Node, {U, S, R}) of true -> - ejabberd_router ! {route, Sender, exmpp_jlib:make_jid(U, S, R), Stanza}; + ejabberd_router ! {route, Sender, exmpp_jid:make_jid(U, S, R), Stanza}; false -> ok end @@ -2674,7 +2672,7 @@ set_xoption([{"pubsub#type", Value} | Opts], NewOpts) -> ?SET_STRING_XOPT(type, Value); set_xoption([{"pubsub#body_xslt", Value} | Opts], NewOpts) -> ?SET_STRING_XOPT(body_xslt, Value); -set_xoption([_ | _Opts], _NewOpts) -> +set_xoption([_ | Opts], NewOpts) -> % skip unknown field set_xoption(Opts, NewOpts). From 6a3436b1c48bd63cfd3e86ab72bbf70d897a9d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Tue, 16 Dec 2008 13:16:56 +0000 Subject: [PATCH 143/582] Merge from trunk (r1709 to r1730). Ejabberd should be usable again. PR: EJABP-1 SVN Revision: 1731 --- ChangeLog | 49 +++++++++++++++- src/ejabberd_c2s.erl | 103 ++++++++++------------------------ src/mod_caps.erl | 35 +++++++++--- src/mod_pubsub/mod_pubsub.erl | 4 +- 4 files changed, 106 insertions(+), 85 deletions(-) diff --git a/ChangeLog b/ChangeLog index 22274b464..ba97da968 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-12-16 Jean-Sébastien Pédron + + Merge from trunk (r1709 to r1730). + + Ejabberd should be usable again. + 2008-12-16 Jean-Sébastien Pédron * src/mod_pubsub/mod_pubsub.erl: Convert to exmpp the parts recently @@ -9,6 +15,10 @@ * src/mod_pubsub/mod_pubsub.erl: Fix get_item_name deadlock on transaction +2008-12-12 Alexey Shchepin + + * src/ejabberd_c2s.erl: Bugfix in "from" attribute checking + 2008-12-10 Jean-Sébastien Pédron * src/eldap/eldap_utils.erl (case_insensitive_match/2): Replace @@ -18,9 +28,46 @@ * src/mod_pubsub: Merge from latest trunk (r1716). +2008-12-09 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: prevent publish items with invalid + XML schema bugfix (EJAB-699) (previous commit was uncomplete) + and fix bug injected in previous commit + +2008-12-08 Christophe Romain + + * src/ejabberd_c2s.erl: Reduce memory consumption due to caps handling + * src/mod_pubsub/mod_pubsub.erl: Likewise + * src/mod_caps.erl: Likewise + + * src/mod_pubsub/mod_pubsub.erl: ignore unknown configuration fields + (EJAB-762) (thanks to Jack Moffitt) + + * src/mod_pubsub/mod_pubsub.erl: fix node authorization bug (EJAB-798) + send authorization update event (EJAB-799) (thanks to Brian Cully) + + * src/mod_pubsub/mod_pubsub.erl: add nodetree filtering and + authorization (EJAB-813) (thanks to Brian Cully) + * src/mod_pubsub/nodetree_default.erl: Likewise + * src/mod_pubsub/nodetree_virtual.erl: Likewise + * src/mod_pubsub/gen_pubsub_nodetree.erl: Likewise + + * src/mod_pubsub/mod_pubsub.erl: prevent publish items with invalid + XML schema (EJAB-699) + + * src/mod_pubsub/pubsub.hrl: remove unused pubsub_presence record + + * src/mod_pubsub/node_flat.erl: renamed from node_zoo + + * src/mod_pubsub/mod_pubsub.erl: reply to suscriptions options queries + with unsupported feature error (EJAB-713) + + * src/mod_pubsub/node_default.erl: remove pubsub_state record when + unsubscribing node without affiliation (EJAB-776) + 2008-12-08 Jean-Sébastien Pédron - * src/mod_pubsub: Merge from trunk (r1692 to r1709). + Merge from trunk (r1692 to r1709). 2008-12-08 Jean-Sébastien Pédron diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 39c6c6d3a..0b40b5be7 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -37,8 +37,7 @@ send_element/2, socket_type/0, get_presence/1, - get_subscribed/1, - get_subscribed_and_online/1]). + get_subscribed/1]). %% gen_fsm callbacks -export([init/1, @@ -85,7 +84,6 @@ pres_f = ?SETS:new(), pres_a = ?SETS:new(), pres_i = ?SETS:new(), - pres_available = ?DICT:new(), pres_last, pres_pri, pres_timestamp, pres_invis = false, @@ -205,14 +203,8 @@ init([{SockMod, Socket}, Opts]) -> end. %% Return list of all available resources of contacts, -%% in form [{JID, Caps}]. get_subscribed(FsmRef) -> - gen_fsm:sync_send_all_state_event( - FsmRef, get_subscribed, 1000). -get_subscribed_and_online(FsmRef) -> - gen_fsm:sync_send_all_state_event( - FsmRef, get_subscribed_and_online, 1000). - + gen_fsm:sync_send_all_state_event(FsmRef, get_subscribed, 1000). %%---------------------------------------------------------------------- %% Func: StateName/2 @@ -951,29 +943,8 @@ handle_sync_event({get_presence}, _From, StateName, StateData) -> fsm_reply(Reply, StateName, StateData); handle_sync_event(get_subscribed, _From, StateName, StateData) -> - Subscribed = StateData#state.pres_f, - Online = StateData#state.pres_available, - Pred = fun({U, S, _} = User, _Caps) -> - ?SETS:is_element({U, S, undefined}, - Subscribed) orelse - ?SETS:is_element(User, Subscribed) - end, - SubscribedAndOnline = ?DICT:filter(Pred, Online), - SubscribedWithCaps = ?SETS:fold(fun(User, Acc) -> - [{User, undefined}|Acc] - end, ?DICT:to_list(SubscribedAndOnline), Subscribed), - {reply, SubscribedWithCaps, StateName, StateData}; - -handle_sync_event(get_subscribed_and_online, _From, StateName, StateData) -> - Subscribed = StateData#state.pres_f, - Online = StateData#state.pres_available, - Pred = fun({U, S, _R} = User, _Caps) -> - ?SETS:is_element({U, S, undefined}, - Subscribed) orelse - ?SETS:is_element(User, Subscribed) - end, - SubscribedAndOnline = ?DICT:filter(Pred, Online), - {reply, ?DICT:to_list(SubscribedAndOnline), StateName, StateData}; + Subscribed = ?SETS:to_list(StateData#state.pres_f), + {reply, Subscribed, StateName, StateData}; handle_sync_event(_Event, _From, StateName, StateData) -> Reply = ok, @@ -1065,42 +1036,39 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> LFrom = jlib:short_prepd_jid(From), LBFrom = jlib:short_prepd_bare_jid(From), %% Note contact availability - Els = Packet#xmlel.children, - Caps = mod_caps:read_caps(Els), - mod_caps:note_caps(StateData#state.server, From, Caps), - NewAvailable = case exmpp_presence:get_type(Packet) of - 'unavailable' -> - ?DICT:erase(LFrom, StateData#state.pres_available); - _ -> - ?DICT:store(LFrom, Caps, StateData#state.pres_available) - end, - NewStateData = StateData#state{pres_available = NewAvailable}, + case exmpp_presence:get_type(Packet) of + 'unavailable' -> + mod_caps:clear_caps(From); + _ -> + Caps = mod_caps:read_caps(Packet#xmlel.children), + mod_caps:note_caps(StateData#state.server, From, Caps) + end, case ?SETS:is_element( - LFrom, NewStateData#state.pres_a) orelse + LFrom, StateData#state.pres_a) orelse ?SETS:is_element( - LBFrom, NewStateData#state.pres_a) of + LBFrom, StateData#state.pres_a) of true -> - {true, Attrs, NewStateData}; + {true, Attrs, StateData}; false -> case ?SETS:is_element( - LFrom, NewStateData#state.pres_f) of + LFrom, StateData#state.pres_f) of true -> A = ?SETS:add_element( LFrom, - NewStateData#state.pres_a), + StateData#state.pres_a), {true, Attrs, - NewStateData#state{pres_a = A}}; + StateData#state{pres_a = A}}; false -> case ?SETS:is_element( - LBFrom, NewStateData#state.pres_f) of + LBFrom, StateData#state.pres_f) of true -> A = ?SETS:add_element( LBFrom, - NewStateData#state.pres_a), + StateData#state.pres_a), {true, Attrs, - NewStateData#state{pres_a = A}}; + StateData#state{pres_a = A}}; false -> - {true, Attrs, NewStateData} + {true, Attrs, StateData} end end end; @@ -1907,28 +1875,15 @@ is_ip_blacklisted({IP,_Port}) -> check_from(El, FromJID) -> case exmpp_stanza:get_sender(El) of undefined -> - exmpp_stanza:set_sender(El, FromJID); - JIDElString -> + El; + SJID -> try - JIDEl = exmpp_jid:list_to_jid(JIDElString), - case JIDEl#jid.lresource of - undefined -> - %% Matching JID: The stanza is ok - if JIDEl#jid.lnode == FromJID#jid.lnode andalso - JIDEl#jid.ldomain == FromJID#jid.ldomain -> - El; - true -> - 'invalid-from' - end; - _ -> - %% Matching JID: The stanza is ok - if JIDEl#jid.lnode == FromJID#jid.lnode andalso - JIDEl#jid.ldomain == FromJID#jid.ldomain andalso - JIDEl#jid.lresource == FromJID#jid.lresource -> - El; - true -> - 'invalid-from' - end + JID = exmpp_jid:list_to_jid(SJID), + case exmpp_jid:compare_jids(JID, FromJID) of + true -> + El; + false -> + 'invalid-from' end catch _:_ -> diff --git a/src/mod_caps.erl b/src/mod_caps.erl index d58b23587..98ebe1ec3 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -31,7 +31,9 @@ -behaviour(gen_mod). -export([read_caps/1, + get_caps/1, note_caps/3, + clear_caps/1, get_features/2, handle_disco_response/3]). @@ -58,6 +60,7 @@ -record(caps, {node, version, exts}). -record(caps_features, {node_pair, features}). +-record(user_caps, {jid, caps}). -record(state, {host, disco_requests = ?DICT:new(), feature_queries = []}). @@ -80,12 +83,26 @@ read_caps([_ | Tail], Result) -> read_caps([], Result) -> Result. +%% get_caps reads user caps from database +get_caps(JID) -> + case catch mnesia:dirty_read({user_caps, list_to_binary(exmpp_jid:jid_to_list(JID))}) of + [#user_caps{caps=Caps}] -> + Caps; + _ -> + nothing + end. + +%% clear_caps removes user caps from database +clear_caps(JID) -> + catch mnesia:dirty_delete({user_caps, list_to_binary(exmpp_jid:jid_to_list(JID))}). + %% note_caps should be called to make the module request disco %% information. Host is the host that asks, From is the full JID that %% sent the caps packet, and Caps is what read_caps returned. note_caps(Host, From, Caps) -> case Caps of - nothing -> ok; + nothing -> + ok; _ -> Proc = gen_mod:get_module_proc(Host, ?PROCNAME), gen_server:cast(Proc, {note_caps, From, Caps}) @@ -129,7 +146,9 @@ init([Host, _Opts]) -> mnesia:create_table(caps_features, [{ram_copies, [node()]}, {attributes, record_info(fields, caps_features)}]), - mnesia:add_table_copy(caps_features, node(), ram_copies), + mnesia:create_table(user_caps, + [{disc_copies, [node()]}, + {attributes, record_info(fields, user_caps)}]), {ok, #state{host = Host}}. maybe_get_features(#caps{node = Node, version = Version, exts = Exts}) -> @@ -177,10 +196,12 @@ handle_call(stop, _From, State) -> {stop, normal, ok, State}. handle_cast({note_caps, From, - #caps{node = Node, version = Version, exts = Exts}}, + #caps{node = Node, version = Version, exts = Exts} = Caps}, #state{host = Host, disco_requests = Requests} = State) -> %% XXX: this leads to race conditions where ejabberd will send %% lots of caps disco requests. + mnesia:dirty_write(#user_caps{jid = list_to_binary(exmpp_jid:jid_to_list(From)), + caps = Caps}), SubNodes = [Version | Exts], %% Now, find which of these are not already in the database. Fun = fun() -> @@ -195,11 +216,9 @@ handle_cast({note_caps, From, end, case mnesia:transaction(Fun) of {atomic, Missing} -> - %% For each unknown caps "subnode", we send a disco - %% request. - NewRequests = - lists:foldl( - fun(SubNode, Dict) -> + %% For each unknown caps "subnode", we send a disco request. + NewRequests = lists:foldl( + fun(SubNode, Dict) -> ID = randoms:get_string(), Query = exmpp_xml:set_attribute( #xmlel{ns = ?NS_DISCO_INFO, name = 'query'}, diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 41da14324..754d947a6 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -480,9 +480,9 @@ handle_cast({presence, JID, Pid}, State) -> case catch ejabberd_c2s:get_subscribed(Pid) of Contacts when is_list(Contacts) -> lists:foreach( - fun({{User, Server, _}, _}) -> + fun({User, Server, _}) -> Owner = {User, Server, undefined}, - lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options} = PN) -> + lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) -> case get_option(Options, send_last_published_item) of on_sub_and_presence -> case is_caps_notify(ServerHost, Node, LJID) of From 69805f36fa8b517242c4729da03e208f6afe6dfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 17 Dec 2008 13:52:44 +0000 Subject: [PATCH 144/582] Merge from trunk (r1730 to r1734). PR: EJABP-1 SVN Revision: 1735 --- ChangeLog | 28 +++++++++ README | 2 +- doc/guide.html | 114 +++++++++++++++++++--------------- doc/guide.tex | 92 +++++++++++++++------------ src/ejabberd.cfg.example | 5 +- src/ejabberd_admin.erl | 17 +++++ src/ejabberd_logger_h.erl | 7 ++- src/mod_pubsub/mod_pubsub.erl | 112 +++++++++++++++++---------------- 8 files changed, 228 insertions(+), 149 deletions(-) diff --git a/ChangeLog b/ChangeLog index ba97da968..51a2c7540 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2008-12-17 Jean-Sébastien Pédron + + Merge from trunk (r1730 to r1734). + +2008-12-16 Badlop + + * src/mod_pubsub/mod_pubsub.erl: Fix update pubsub tables from + ejabberd 1.x to 2.x (EJAB-817) + + * doc/guide.tex: Fix capitalization of some section titles + + * doc/guide.tex: Mention as optional Requirements: mysql, pgsql + and pam + + * src/ejabberd_admin.erl: Command reopen-log must also rotate + sasl.log (thanks to Alexander Tsvyashchenko)(EJAB-711) + * src/ejabberd_logger_h.erl: Export the function rotate_log/1 + * doc/guide.tex: Improve explanation of log files rotation + + * doc/guide.tex: Improve explanation of watchdog admins + option: only useful for developers (EJAB-816) + * src/ejabberd.cfg.example: Likewise + + * doc/guide.tex: Say 'higher' instead of 'newer' in requirements + * README: Likewise + + * doc/guide.tex: Simplify example mod_muc configuration + 2008-12-16 Jean-Sébastien Pédron Merge from trunk (r1709 to r1730). diff --git a/README b/README index e798e9095..bbc9511ab 100644 --- a/README +++ b/README @@ -9,7 +9,7 @@ To compile ejabberd you need: - GNU Make - GCC - libexpat 1.95 or higher - - Erlang/OTP R10B-9 or newer + - Erlang/OTP R10B-9 or higher - OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended. - Zlib 1.2.3 or higher, for Stream Compression support diff --git a/doc/guide.html b/doc/guide.html index e33aaf296..2982f355d 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -96,7 +96,7 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}
    • Chapter 2  Installing ejabberd -
    • Chapter 4  Managing an ejabberd server +
    • Chapter 4  Managing an ejabberd Server
    • Chapter 6  Clustering
      • @@ -199,9 +199,9 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}
    • Chapter 7  Debugging
    • Appendix A  Internationalization and Localization
    • Appendix B  Release Notes @@ -304,8 +304,8 @@ or with the command bin/ejabberdctl live in other Operating Systems. This way you see the error message provided by Erlang and can identify what is exactly the problem.

      The ejabberdctl administration script is included in the bin directory. Please refer to the section 4.1 for details about ejabberdctl, -and configurable options to fine tune the Erlang runtime system.

      -

      2.2  Installing ejabberd with Operating System specific packages

      Some Operating Systems provide a specific ejabberd package adapted to +and configurable options to fine tune the Erlang runtime system.

      +

      2.2  Installing ejabberd with Operating System Specific Packages

      Some Operating Systems provide a specific ejabberd package adapted to the system architecture and libraries. It usually also checks dependencies and performs basic configuration tasks like creating the initial @@ -330,10 +330,13 @@ as long as your system have all the dependencies.

    • GCC
    • Libexpat 1.95 or higher -
    • Erlang/OTP R10B-9 or newer. +
    • Erlang/OTP R10B-9 or higher.
    • OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended.
    • Zlib 1.2.3 or higher, for Stream Compression support (XEP-0138). Optional. -
    • GNU Iconv 1.8 or higher, for the IRC Transport (mod_irc). Optional. Not needed on systems with GNU Libc. +
    • Erlang mysql library. Optional. For MySQL authentication or storage. See section 3.2.1. +
    • Erlang pgsql library. Optional. For PostgreSQL authentication or storage. See section 3.2.3. +
    • PAM library. Optional. For Pluggable Authentication Modules (PAM). See section 3.1.4. +
    • GNU Iconv 1.8 or higher, for the IRC Transport (mod_irc). Optional. Not needed on systems with GNU Libc. See section 3.3.6.
    • 2.4.2  Download Source Code

      Released versions of ejabberd are available in the ProcessOne ejabberd downloads page: @@ -400,7 +403,7 @@ to install ejabberd.

      The files and directories created are, by de .erlang.cookie

      Erlang cookie file (see section 5.3)
      acl.DCD, ...
      Mnesia database spool files (*.DCD, *.DCL, *.DAT)
      -
      /var/log/ejabberd/
      Log directory (see section 7.2): +
      /var/log/ejabberd/
      Log directory (see section 7.1):
      ejabberd.log
      ejabberd service log
      sasl.log
      Erlang/OTP system log @@ -1254,7 +1257,7 @@ For that purpose, the options described in the next sections must be set inside a host_cofig for each vhost (see section 3.1.2). For example:

      {host_config, "public.example.org", [
      -  {odbc_server, {pgsql, "localhost", "database", "ejabberd", "password"}},
      +  {odbc_server, {pgsql, "localhost", "database-public-example-org", "ejabberd", "password"}},
         {auth_method, [odbc]}
       ]}.
       

      @@ -2106,16 +2109,16 @@ to new hardware. This will involve service breakdowns around 23:00 UMT. We apologise for this inconvenience.’ to conference.example.org, it will be displayed in all active rooms. In this example the history feature is disabled. -
      {acl, admins, {user, "admin", "example.org"}}.
      +
      {acl, admin, {user, "admin", "example.org"}}.
       
      -{access, muc_admins, [{allow, admins}]}.
      +{access, muc_admin, [{allow, admin}]}.
       
       {modules,
        [
         ...
         {mod_muc, [{access, all},
                    {access_create, all},
      -             {access_admin, muc_admins},
      +             {access_admin, muc_admin},
                    {history_size, 0}]},
         ...
        ]}.
      @@ -2132,20 +2135,20 @@ and the default value of 20 history messages will be send to the users.
       
      {acl, paying_customers, {user, "customer1", "example.net"}}.
       {acl, paying_customers, {user, "customer2", "example.com"}}.
       {acl, paying_customers, {user, "customer3", "example.org"}}.
      -{acl, admins, {user, "admin", "example.org"}}.
      +{acl, admin, {user, "admin", "example.org"}}.
       
      -{access, muc_admins, [{allow, admins},
      +{access, muc_admin, [{allow, admin},
                             {deny, all}]}.
       {access, muc_access, [{allow, paying_customers},
      -                      {allow, admins},
      +                      {allow, admin},
                             {deny, all}]}.
       
       {modules,
        [
         ...
         {mod_muc, [{access, muc_access},
      -             {access_create, muc_admins},
      -             {access_admin, muc_admins}]},
      +             {access_create, muc_admin},
      +             {access_admin, muc_admin}]},
         ...
        ]}.
       
    • In the following example, MUC anti abuse options are used. An @@ -2164,7 +2167,7 @@ the newly created rooms have by default those options. [ ... {mod_muc, [{access, muc_access}, - {access_create, muc_admins}, + {access_create, muc_admin}, {default_room_options, [ {allow_change_subj, false}, @@ -2174,7 +2177,7 @@ the newly created rooms have by default those options. {title, "New chatroom"}, {anonymous, false} ]}, - {access_admin, muc_admins}]}, + {access_admin, muc_admin}]}, ... ]}.
    • @@ -2897,8 +2900,8 @@ answers ejabberd’s version when queried.

      Options: The default value is true.

      iqdisc
      This specifies the processing discipline for Software Version (jabber:iq:version) IQ queries (see section 3.3.2). -

      -

      Chapter 4  Managing an ejabberd server

      +

      +

      Chapter 4  Managing an ejabberd Server

      4.1  ejabberdctl

      4.1.1  Commands

      The ejabberdctl command line administration script allows to start, stop and perform many other administrative tasks in a local or remote ejabberd server.

      When ejabberdctl is executed without any parameter, @@ -2915,8 +2918,9 @@ The more interesting ones are: help

      Get help about ejabberdctl or any available command. Try ejabberdctl help help.
      status
      Check the status of the ejabberd server.
      stop
      Stop the ejabberd server which is running in the machine. -
      reopen-log
      If you use a tool to rotate logs, you have to configure it -so that this command is executed after each rotation. +
      reopen-log
      Reopen the log files after they were renamed. +If the old files were not renamed before calling this command, +they are automatically renamed to "*-old.log". See section 7.1.
      backup, restore, install-fallback, dump, load
      You can use these commands to create and restore backups.
      import-file, import-dir
      @@ -2933,8 +2937,8 @@ error is represented by 1, and other codes may be used for specifical results. This can be used by other scripts to determine automatically if a command succedded or failed, -for example using: echo $?

      -

      4.1.2  Erlang runtime system

      ejabberd is an Erlang/OTP application that runs inside an Erlang runtime system. +for example using: echo $?

      +

      4.1.2  Erlang Runtime System

      ejabberd is an Erlang/OTP application that runs inside an Erlang runtime system. This system is configured using environment variables and command line parameters. The ejabberdctl administration script uses many of those possibilities. You can configure some of them with the file ejabberdctl.cfg, @@ -3133,8 +3137,8 @@ However, the cookie system is not ultimately effective to prevent unauthorized access or intrusion to an Erlang node. The communication between Erlang nodes are not encrypted, so the cookie could be read sniffing the traffic on the network. -The recommended way to secure the Erlang node is to block the port 4369.

      -

      5.4  Erlang node name

      An Erlang node may have a node name. +The recommended way to secure the Erlang node is to block the port 4369.

      +

      5.4  Erlang Node Name

      An Erlang node may have a node name. The name can be short (if indicated with the command-line parameter -sname) or long (if indicated with the parameter -name). Starting an Erlang node with -sname limits the communication between Erlang nodes to the LAN.

      Using the option -sname instead of -name is a simple method @@ -3142,8 +3146,8 @@ to difficult unauthorized access to your Erlang node. However, it is not ultimately effective to prevent access to the Erlang node, because it may be possible to fake the fact that you are on another network using a modified version of Erlang epmd. -The recommended way to secure the Erlang node is to block the port 4369.

      -

      5.5  Securing sensible files

      ejabberd stores sensible data in the file system either in plain text or binary files. +The recommended way to secure the Erlang node is to block the port 4369.

      +

      5.5  Securing Sensible Files

      ejabberd stores sensible data in the file system either in plain text or binary files. The file system permissions should be set to only allow the proper user to read, write and execute those files and directories.

      ejabberd configuration file: /etc/ejabberd/ejabberd.cfg
      @@ -3256,20 +3260,8 @@ domain.

      Chapter 7  Debugging

      -

      -

      7.1  Watchdog Alerts

      -

      ejabberd includes a watchdog mechanism. -If a process in the ejabberd server consumes too much memory, -a message is sent to the Jabber accounts defined with the option -watchdog_admins - in the ejabberd configuration file. -Example configuration: -

      {watchdog_admins, ["admin2@localhost", "admin2@example.org"]}.
      -

      To remove watchdog admins, remove them in the option. -To remove all watchdog admins, set the option with an empty list: -

      {watchdog_admins, []}.
      -

      -

      7.2  Log Files

      An ejabberd node writes two log files: +

      +

      7.1  Log Files

      An ejabberd node writes two log files:

      ejabberd.log
      is the ejabberd service log, with the messages reported by ejabberd code
      sasl.log
      is the Erlang/OTP system log, with the messages reported by Erlang/OTP using SASL (System Architecture Support Libraries) @@ -3285,12 +3277,32 @@ The possible levels are:

      For example, the default configuration is:

      {loglevel, 4}.
      -

      -

      7.3  Debug Console

      The Debug Console is an Erlang shell attached to an already running ejabberd server. +

      The log files grow continually, so it is recommended to rotate them periodically. +To rotate the log files, rename the files and then reopen them. +The ejabberd command reopen-log +(please refer to section 4.1.1) +reopens the log files, +and also renames the old ones if you didn’t rename them.

      +

      7.2  Debug Console

      The Debug Console is an Erlang shell attached to an already running ejabberd server. With this Erlang shell, an experienced administrator can perform complex tasks.

      This shell gives complete control over the ejabberd server, so it is important to use it with extremely care. There are some simple and safe examples in the article -Interconnecting Erlang Nodes

      To exit the shell, close the window or press the keys: control+c control+c.

      +Interconnecting Erlang Nodes

      To exit the shell, close the window or press the keys: control+c control+c.

      +

      7.3  Watchdog Alerts

      +

      ejabberd includes a watchdog mechanism that may be useful to developers +when troubleshooting a problem related to memory usage. +If a process in the ejabberd server consumes a lot of memory, +a message is sent to the Jabber accounts defined with the option +watchdog_admins + in the ejabberd configuration file. +Note that the threshold to define what is too much memory usage +is only configurable editing the source code. +Example configuration: +

      {watchdog_admins, ["admin2@localhost", "admin2@example.org"]}.
      +

      To remove watchdog admins, remove them in the option. +To remove all watchdog admins, set the option with an empty list: +

      {watchdog_admins, []}.
      +

      Appendix A  Internationalization and Localization

      The source code of ejabberd supports localization. The translators can edit the diff --git a/doc/guide.tex b/doc/guide.tex index d40cd8ae5..0ca65220b 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -261,7 +261,7 @@ The \term{ejabberdctl} administration script is included in the \term{bin} direc Please refer to the section~\ref{ejabberdctl} for details about \term{ejabberdctl}, and configurable options to fine tune the Erlang runtime system. -\makesection{install.os}{Installing \ejabberd{} with Operating System specific packages} +\makesection{install.os}{Installing \ejabberd{} with Operating System Specific Packages} Some Operating Systems provide a specific \ejabberd{} package adapted to the system architecture and libraries. @@ -301,10 +301,13 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need: \item GNU Make \item GCC \item Libexpat 1.95 or higher -\item Erlang/OTP R10B-9 or newer. +\item Erlang/OTP R10B-9 or higher. \item OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended. \item Zlib 1.2.3 or higher, for Stream Compression support (\xepref{0138}). Optional. -\item GNU Iconv 1.8 or higher, for the IRC Transport (mod\_irc). Optional. Not needed on systems with GNU Libc. +\item Erlang mysql library. Optional. For MySQL authentication or storage. See section \ref{compilemysql}. +\item Erlang pgsql library. Optional. For PostgreSQL authentication or storage. See section \ref{compilepgsql}. +\item PAM library. Optional. For Pluggable Authentication Modules (PAM). See section \ref{pam}. +\item GNU Iconv 1.8 or higher, for the IRC Transport (mod\_irc). Optional. Not needed on systems with GNU Libc. See section \ref{modirc}. \end{itemize} \makesubsection{download}{Download Source Code} @@ -2756,16 +2759,16 @@ Examples: it will be displayed in all active rooms. In this example the history feature is disabled. \begin{verbatim} -{acl, admins, {user, "admin", "example.org"}}. +{acl, admin, {user, "admin", "example.org"}}. -{access, muc_admins, [{allow, admins}]}. +{access, muc_admin, [{allow, admin}]}. {modules, [ ... {mod_muc, [{access, all}, {access_create, all}, - {access_admin, muc_admins}, + {access_admin, muc_admin}, {history_size, 0}]}, ... ]}. @@ -2784,20 +2787,20 @@ Examples: {acl, paying_customers, {user, "customer1", "example.net"}}. {acl, paying_customers, {user, "customer2", "example.com"}}. {acl, paying_customers, {user, "customer3", "example.org"}}. -{acl, admins, {user, "admin", "example.org"}}. +{acl, admin, {user, "admin", "example.org"}}. -{access, muc_admins, [{allow, admins}, +{access, muc_admin, [{allow, admin}, {deny, all}]}. {access, muc_access, [{allow, paying_customers}, - {allow, admins}, + {allow, admin}, {deny, all}]}. {modules, [ ... {mod_muc, [{access, muc_access}, - {access_create, muc_admins}, - {access_admin, muc_admins}]}, + {access_create, muc_admin}, + {access_admin, muc_admin}]}, ... ]}. \end{verbatim} @@ -2824,7 +2827,7 @@ defined, but some user restriction could be added as well: [ ... {mod_muc, [{access, muc_access}, - {access_create, muc_admins}, + {access_create, muc_admin}, {default_room_options, [ {allow_change_subj, false}, @@ -2834,7 +2837,7 @@ defined, but some user restriction could be added as well: {title, "New chatroom"}, {anonymous, false} ]}, - {access_admin, muc_admins}]}, + {access_admin, muc_admin}]}, ... ]}. \end{verbatim} @@ -3727,7 +3730,7 @@ Options: \iqdiscitem{Software Version (\ns{jabber:iq:version})} \end{description} -\makechapter{manage}{Managing an \ejabberd{} server} +\makechapter{manage}{Managing an \ejabberd{} Server} \makesection{ejabberdctl}{\term{ejabberdctl}} @@ -3753,8 +3756,9 @@ The more interesting ones are: \titem{help} Get help about ejabberdctl or any available command. Try \term{ejabberdctl help help}. \titem{status} Check the status of the \ejabberd{} server. \titem{stop} Stop the \ejabberd{} server which is running in the machine. -\titem{reopen-log} If you use a tool to rotate logs, you have to configure it - so that this command is executed after each rotation. +\titem{reopen-log} Reopen the log files after they were renamed. + If the old files were not renamed before calling this command, + they are automatically renamed to \term{"*-old.log"}. See section \ref{logfiles}. \titem {backup, restore, install-fallback, dump, load} You can use these commands to create and restore backups. %%More information about backuping can @@ -3782,7 +3786,7 @@ if a command succedded or failed, for example using: \term{echo \$?} -\makesubsection{erlangconfiguration}{Erlang runtime system} +\makesubsection{erlangconfiguration}{Erlang Runtime System} \ejabberd{} is an Erlang/OTP application that runs inside an Erlang runtime system. This system is configured using environment variables and command line parameters. @@ -4041,7 +4045,7 @@ so the cookie could be read sniffing the traffic on the network. The recommended way to secure the Erlang node is to block the port 4369. -\makesection{nodename}{Erlang node name} +\makesection{nodename}{Erlang Node Name} An Erlang node may have a node name. The name can be short (if indicated with the command-line parameter \term{-sname}) @@ -4056,7 +4060,7 @@ using a modified version of Erlang \term{epmd}. The recommended way to secure the Erlang node is to block the port 4369. -\makesection{secure-files}{Securing sensible files} +\makesection{secure-files}{Securing Sensible Files} \ejabberd{} stores sensible data in the file system either in plain text or binary files. The file system permissions should be set to only allow the proper user to read, @@ -4276,26 +4280,6 @@ The syntax is the following: \makechapter{debugging}{Debugging} \ind{debugging} -\makesection{watchdog}{Watchdog Alerts} -\ind{debugging!watchdog} - -\ejabberd{} includes a watchdog mechanism. -If a process in the \ejabberd{} server consumes too much memory, -a message is sent to the Jabber accounts defined with the option -\term{watchdog\_admins} -\ind{options!watchdog\_admins} in the \ejabberd{} configuration file. -Example configuration: -\begin{verbatim} -{watchdog_admins, ["admin2@localhost", "admin2@example.org"]}. -\end{verbatim} - -To remove watchdog admins, remove them in the option. -To remove all watchdog admins, set the option with an empty list: -\begin{verbatim} -{watchdog_admins, []}. -\end{verbatim} - - \makesection{logfiles}{Log Files} An \ejabberd{} node writes two log files: @@ -4319,6 +4303,13 @@ For example, the default configuration is: {loglevel, 4}. \end{verbatim} +The log files grow continually, so it is recommended to rotate them periodically. +To rotate the log files, rename the files and then reopen them. +The ejabberd command \term{reopen-log} +(please refer to section \ref{commands}) +reopens the log files, +and also renames the old ones if you didn't rename them. + \makesection{debugconsole}{Debug Console} @@ -4333,6 +4324,29 @@ There are some simple and safe examples in the article To exit the shell, close the window or press the keys: control+c control+c. +\makesection{watchdog}{Watchdog Alerts} +\ind{debugging!watchdog} + +\ejabberd{} includes a watchdog mechanism that may be useful to developers +when troubleshooting a problem related to memory usage. +If a process in the \ejabberd{} server consumes a lot of memory, +a message is sent to the Jabber accounts defined with the option +\term{watchdog\_admins} +\ind{options!watchdog\_admins} in the \ejabberd{} configuration file. +Note that the threshold to define what is too much memory usage +is only configurable editing the source code. +Example configuration: +\begin{verbatim} +{watchdog_admins, ["admin2@localhost", "admin2@example.org"]}. +\end{verbatim} + +To remove watchdog admins, remove them in the option. +To remove all watchdog admins, set the option with an empty list: +\begin{verbatim} +{watchdog_admins, []}. +\end{verbatim} + + \appendix{} \makechapter{i18ni10n}{Internationalization and Localization} diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index 022a9ebc2..6a6b52494 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -72,8 +72,9 @@ {loglevel, 4}. %% -%% watchdog_admins: If an ejabberd process consumes too much memory, -%% send live notifications to those Jabber accounts. +%% watchdog_admins: Only useful for developers: if an ejabberd process +%% consumes a lot of memory, send live notifications to these Jabber +%% accounts. %% %%{watchdog_admins, ["bob@example.com"]}. diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl index e08765fff..993ac64ce 100644 --- a/src/ejabberd_admin.erl +++ b/src/ejabberd_admin.erl @@ -158,8 +158,25 @@ reopen_log() -> ejabberd_hooks:run(reopen_log_hook, []), %% TODO: Use the Reopen log API for logger_h ? ejabberd_logger_h:reopen_log(), + case application:get_env(sasl,sasl_error_logger) of + {ok, {file, SASLfile}} -> + error_logger:delete_report_handler(sasl_report_file_h), + ejabberd_logger_h:rotate_log(SASLfile), + error_logger:add_report_handler(sasl_report_file_h, + {SASLfile, get_sasl_error_logger_type()}); + _ -> false + end, ok. +%% Function copied from Erlang/OTP lib/sasl/src/sasl.erl which doesn't export it +get_sasl_error_logger_type () -> + case application:get_env (sasl, errlog_type) of + {ok, error} -> error; + {ok, progress} -> progress; + {ok, all} -> all; + {ok, Bad} -> exit ({bad_config, {sasl, {errlog_type, Bad}}}); + _ -> all + end. %%% %%% Account management diff --git a/src/ejabberd_logger_h.erl b/src/ejabberd_logger_h.erl index 2e750ca34..e8e6f3baa 100644 --- a/src/ejabberd_logger_h.erl +++ b/src/ejabberd_logger_h.erl @@ -31,7 +31,7 @@ %% gen_event callbacks -export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, - code_change/3, reopen_log/0]). + code_change/3, reopen_log/0, rotate_log/1]). -record(state, {fd, file}). @@ -206,10 +206,11 @@ write_time({{Y,Mo,D},{H,Mi,S}}, Type) -> io_lib:format("~n=~s==== ~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w ===~n", [Type, Y, Mo, D, H, Mi, S]). -%% Rename the log file if it the filename exists +%% @doc Rename the log file if exists, to "*-old.log". %% This is needed in systems when the file must be closed before rotation (Windows). %% On most Unix-like system, the file can be renamed from the command line and -%%the log can directly be reopened. +%% the log can directly be reopened. +%% @spec (Filename::string()) -> ok rotate_log(Filename) -> case file:read_file_info(Filename) of {ok, _FileInfo} -> diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 754d947a6..48d2ca061 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -242,60 +242,66 @@ update_database(Host) -> [host_node, host_parent, info] -> ?INFO_MSG("upgrade pubsub tables",[]), F = fun() -> - NewRecords = - lists:foldl( - fun({pubsub_node, NodeId, ParentId, {nodeinfo, Items, Options, Entities}}, RecList) -> - ItemsList = - lists:foldl( - fun({item, IID, Publisher, Payload}, Acc) -> - C = {Publisher, unknown}, - M = {Publisher, now()}, - mnesia:write( - #pubsub_item{itemid = {IID, NodeId}, - creation = C, - modification = M, - payload = Payload}), - [{Publisher, IID} | Acc] - end, [], Items), - Owners = - dict:fold( - fun(JID, {entity, Aff, Sub}, Acc) -> - UsrItems = - lists:foldl( - fun({P, I}, IAcc) -> - case P of - JID -> [I | IAcc]; - _ -> IAcc - end - end, [], ItemsList), - mnesia:write( - #pubsub_state{stateid = {JID, NodeId}, - items = UsrItems, - affiliation = Aff, - subscription = Sub}), - case Aff of - owner -> [JID | Acc]; - _ -> Acc - end - end, [], Entities), - mnesia:delete({pubsub_node, NodeId}), - [#pubsub_node{nodeid = NodeId, - parentid = ParentId, - owners = Owners, - options = Options} | - RecList] - end, [], - mnesia:match_object( - {pubsub_node, {Host, '_'}, '_', '_'})), - mnesia:delete_table(pubsub_node), - mnesia:create_table(pubsub_node, - [{disc_copies, [node()]}, - {attributes, record_info(fields, pubsub_node)}]), - lists:foreach(fun(Record) -> - mnesia:write(Record) - end, NewRecords) + lists:foldl( + fun({pubsub_node, NodeId, ParentId, {nodeinfo, Items, Options, Entities}}, RecList) -> + ItemsList = + lists:foldl( + fun({item, IID, Publisher, Payload}, Acc) -> + C = {Publisher, unknown}, + M = {Publisher, now()}, + mnesia:write( + #pubsub_item{itemid = {IID, NodeId}, + creation = C, + modification = M, + payload = Payload}), + [{Publisher, IID} | Acc] + end, [], Items), + Owners = + dict:fold( + fun(JID, {entity, Aff, Sub}, Acc) -> + UsrItems = + lists:foldl( + fun({P, I}, IAcc) -> + case P of + JID -> [I | IAcc]; + _ -> IAcc + end + end, [], ItemsList), + mnesia:write( + #pubsub_state{stateid = {JID, NodeId}, + items = UsrItems, + affiliation = Aff, + subscription = Sub}), + case Aff of + owner -> [JID | Acc]; + _ -> Acc + end + end, [], Entities), + mnesia:delete({pubsub_node, NodeId}), + [#pubsub_node{nodeid = NodeId, + parentid = ParentId, + owners = Owners, + options = Options} | + RecList] + end, [], + mnesia:match_object( + {pubsub_node, {Host, '_'}, '_', '_'})) end, - mnesia:transaction(F); + {atomic, NewRecords} = mnesia:transaction(F), + {atomic, ok} = mnesia:delete_table(pubsub_node), + {atomic, ok} = mnesia:create_table(pubsub_node, + [{disc_copies, [node()]}, + {attributes, record_info(fields, pubsub_node)}]), + FNew = fun() -> lists:foreach(fun(Record) -> + mnesia:write(Record) + end, NewRecords) + end, + case mnesia:transaction(FNew) of + {atomic, Result} -> + ?INFO_MSG("Pubsub tables updated correctly: ~p", [Result]); + {aborted, Reason} -> + ?ERROR_MSG("Problem updating Pubsub tables:~n~p", [Reason]) + end; _ -> ok end. From d3ddf10839b105024fad6d51646165ddb4bf9845 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Wed, 17 Dec 2008 16:24:15 +0000 Subject: [PATCH 145/582] mod_muc_room.erl: Fix bug in MUC invite. SVN Revision: 1736 --- ChangeLog | 4 ++++ src/mod_muc/mod_muc_room.erl | 38 +++++++++++++++++++----------------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 51a2c7540..a7667f87e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2008-12-17 Pablo Polvorin + + * src/mod_muc/mod_muc_room.erl: Fix bug in MUC invite. + 2008-12-17 Jean-Sébastien Pédron Merge from trunk (r1730 to r1734). diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index b1884e7a2..70babd033 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -261,7 +261,7 @@ normal_state({route, From, undefined, StateData#state.jid, From, exmpp_stanza:reply_with_error(Packet, Err)), {next_state, normal_state, StateData}; - normal -> + Type when (Type == 'normal') orelse (Type == 'undefined') -> case catch check_invitation(From, exmpp_xml:get_child_elements(Packet), Lang, @@ -884,7 +884,7 @@ process_presence(From, Nick, #xmlel{name = 'presence'} = Packet, _ -> StateData end; - available -> + 'available' -> case is_user_online(From, StateData) of true -> case is_nick_change(From, Nick, StateData) of @@ -3236,23 +3236,24 @@ check_invitation(From, Els, Lang, StateData) -> InviteEl, [{element, 'reason'}, cdata]), ContinueEl = - case xml:get_path( + case exmpp_xml:get_path( InviteEl, [{element, 'continue'}]) of - [] -> []; + 'undefined' -> []; Continue1 -> [Continue1] end, IEl = - [#xmlel{name = 'invite', - attrs = [#xmlattr{name = 'from', - value = exmpp_jid:jid_to_list(From)}], - children = [#xmlel{name = 'reason', - children = [#xmlcdata{cdata = Reason} ]}] - ++ ContinueEl}], + [#xmlel{ns = ?NS_MUC_USER, + name = 'invite', + attrs = [#xmlattr{name = 'from', + value = exmpp_jid:jid_to_list(From)}], + children = [#xmlel{ns =?NS_MUC_USER, name = 'reason', + children = [#xmlcdata{cdata = Reason} ]}] + ++ ContinueEl}], PasswdEl = case (StateData#state.config)#config.password_protected of true -> - [#xmlel{name = 'password', + [#xmlel{ns = ?NS_MUC_USER, name = 'password', children = [#xmlcdata{cdata = (StateData#state.config)#config.password}]}]; _ -> @@ -3261,7 +3262,7 @@ check_invitation(From, Els, Lang, StateData) -> Body = #xmlel{name = 'body', children = [#xmlcdata{cdata = - lists:flatten( + list_to_binary([ io_lib:format( translate:translate(Lang, "~s invites you to the room ~s"), @@ -3269,7 +3270,7 @@ check_invitation(From, Els, Lang, StateData) -> exmpp_jid:jid_to_list(StateData#state.room, StateData#state.host, "") - ])) ++ + ]), case (StateData#state.config)#config.password_protected of true -> ", " ++ @@ -3278,14 +3279,15 @@ check_invitation(From, Els, Lang, StateData) -> (StateData#state.config)#config.password ++ "'"; _ -> "" - end ++ + end, case Reason of - "" -> ""; - _ -> " (" ++ Reason ++ ") " + <<>> -> ""; + _ -> [" (", Reason, ") "] end - }]}, + ])}]}, + %%TODO: always NS_JABER_CLIENT? Msg = - #xmlel{name = 'message', + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', attrs = [#xmlattr{name = 'type', value = "normal"}], children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = IEl ++ PasswdEl}, From e6535dcc67d25ddbd7bab3824f9018243e1e05b5 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 18 Dec 2008 13:46:30 +0000 Subject: [PATCH 146/582] Check option of the nodetree instead of checking configuration SVN Revision: 1738 --- ChangeLog | 5 +++++ src/mod_pubsub/mod_pubsub.erl | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index a7667f87e..baa889ee2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-12-18 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: Check option of the nodetree instead + of checking configuration (thanks to Eric Cestari)(EJAB-737) + 2008-12-17 Pablo Polvorin * src/mod_muc/mod_muc_room.erl: Fix bug in MUC invite. diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 48d2ca061..0440f24b3 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -1244,8 +1244,8 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> ok -> node_call(Type, create_node, [Host, Node, Owner]); {error, 'conflict'} -> - case ets:lookup(gen_mod:get_module_proc(ServerHost, pubsub_state), nodetree) of - [{nodetree, nodetree_virtual}] -> node_call(Type, create_node, [Host, Node, Owner]); + case proplists:get_value(virtual_tree, tree_call(Host, options, [])) of + true -> node_call(Type, create_node, [Host, Node, Owner]); _ -> {error, 'conflict'} end; Error -> From 978adbbd943246a91f64e0ae3656882a9be920b9 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Sat, 20 Dec 2008 00:01:26 +0000 Subject: [PATCH 147/582] Fix send_last_published_item issue when running on clustered table (EJAB-793) SVN Revision: 1741 --- ChangeLog | 5 +++++ src/mod_pubsub/mod_pubsub.erl | 35 ++++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index baa889ee2..a89077a0d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2008-12-19 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: Fix send_last_published_item issue + when running on clustered table (thanks to Vincent Barat)(EJAB-793) + 2008-12-18 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: Check option of the nodetree instead diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 0440f24b3..c8eb5e500 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -1750,24 +1750,41 @@ get_items(Host, Node, From) -> %% Host = host() %% Node = pubsubNode() %% LJID = {U, S, []} -%% @doc

      Resend the items of a node to the user.

      -%send_all_items(Host, Node, LJID) -> -% send_items(Host, Node, LJID, all). - +%% @doc

      Resend the last item of a node to the user.

      send_last_item(Host, Node, LJID) -> send_items(Host, Node, LJID, last). -%% TODO use cache-last-item feature +%% @spec (Host, Node, LJID) -> any() +%% Host = host() +%% Node = pubsubNode() +%% LJID = {U, S, []} +%% @doc

      Resend the items of a node to the user.

      +%% @todo use cache-last-item feature send_items(Host, Node, {LU, LS, LR} = LJID, Number) -> ToSend = case get_items(Host, Node, LJID) of [] -> []; Items -> case Number of - last -> [lists:last(Items)]; - all -> Items; - N when N > 0 -> lists:nthtail(length(Items)-N, Items); - _ -> Items + last -> + %%% [lists:last(Items)] does not work on clustered table + [First|Tail] = Items, + [lists:foldl( + fun(CurItem, LastItem) -> + {_, {LMS, LS, LmS}} = LastItem#pubsub_item.creation, + {_, {CMS, CS, CmS}} = CurItem#pubsub_item.creation, + LTimestamp = LMS * 1000000 + LS * 1000 + LmS, + CTimestamp = CMS * 1000000 + CS * 1000 + CmS, + if + CTimestamp > LTimestamp -> CurItem; + true -> LastItem + end + end, First, Tail)]; + N when N > 0 -> + %%% This case is buggy on clustered table due to lake of order + lists:nthtail(length(Items)-N, Items); + _ -> + Items end end, ItemsEls = lists:map( From 214ef3105386d982238bba1e315e590d7413c1b2 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 23 Dec 2008 13:58:38 +0000 Subject: [PATCH 148/582] Improve handling of PEP sent to external contacts (EJAB-825) SVN Revision: 1751 --- ChangeLog | 6 +++++ src/mod_caps.erl | 48 ++++++++++++++++++++++++++++++----- src/mod_pubsub/mod_pubsub.erl | 34 +++++++++++++------------ 3 files changed, 65 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index a89077a0d..2ef1596c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-12-23 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: Improve handling of PEP sent to + external contacts (EJAB-825) + * src/mod_caps.erl: Likewise + 2008-12-19 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: Fix send_last_published_item issue diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 98ebe1ec3..f7aa858cb 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -35,6 +35,7 @@ note_caps/3, clear_caps/1, get_features/2, + get_user_resource/2, handle_disco_response/3]). %% gen_mod callbacks @@ -61,6 +62,7 @@ -record(caps, {node, version, exts}). -record(caps_features, {node_pair, features}). -record(user_caps, {jid, caps}). +-record(user_caps_default, {uid, resource}). -record(state, {host, disco_requests = ?DICT:new(), feature_queries = []}). @@ -84,8 +86,9 @@ read_caps([], Result) -> Result. %% get_caps reads user caps from database -get_caps(JID) -> - case catch mnesia:dirty_read({user_caps, list_to_binary(exmpp_jid:jid_to_list(JID))}) of +get_caps({U, S, R}) -> + BJID = exmpp_jlib:jid_to_binary(U, S, R), + case catch mnesia:dirty_read({user_caps, BJID}) of [#user_caps{caps=Caps}] -> Caps; _ -> @@ -93,8 +96,26 @@ get_caps(JID) -> end. %% clear_caps removes user caps from database -clear_caps(JID) -> - catch mnesia:dirty_delete({user_caps, list_to_binary(exmpp_jid:jid_to_list(JID))}). +clear_caps({U, S, R}) -> + BJID = exmpp_jlib:jid_to_binary(U, S, R), + BUID = exmpp_jlib:jid_to_binary(U, S), + catch mnesia:dirty_delete({user_caps, BJID}), + case catch mnesia:dirty_read({user_caps_default, BUID}) of + [#user_caps_default{resource=R}] -> + catch mnesia:dirty_delete({user_caps_default, BUID}); + _ -> + ok + end. + +%% give default user resource +get_user_resource(U, S) -> + BUID = exmpp_jlib:bare_jid_to_binary(U, S), + case catch mnesia:dirty_read({user_caps_default, BUID}) of + [#user_caps_default{resource=R}] -> + R; + _ -> + [] + end. %% note_caps should be called to make the module request disco %% information. Host is the host that asks, From is the full JID that @@ -113,7 +134,8 @@ note_caps(Host, From, Caps) -> %% timeout error. get_features(Host, Caps) -> case Caps of - nothing -> []; + nothing -> + []; #caps{} -> Proc = gen_mod:get_module_proc(Host, ?PROCNAME), gen_server:call(Proc, {get_features, Caps}) @@ -149,6 +171,9 @@ init([Host, _Opts]) -> mnesia:create_table(user_caps, [{disc_copies, [node()]}, {attributes, record_info(fields, user_caps)}]), + mnesia:create_table(user_caps_default, + [{disc_copies, [node()]}, + {attributes, record_info(fields, user_caps_default)}]), {ok, #state{host = Host}}. maybe_get_features(#caps{node = Node, version = Version, exts = Exts}) -> @@ -200,8 +225,17 @@ handle_cast({note_caps, From, #state{host = Host, disco_requests = Requests} = State) -> %% XXX: this leads to race conditions where ejabberd will send %% lots of caps disco requests. - mnesia:dirty_write(#user_caps{jid = list_to_binary(exmpp_jid:jid_to_list(From)), - caps = Caps}), + #jid{node = U, domain = S, resource = R} = From, + BJID = exmpp_jlib:jid_to_binary(From), + mnesia:dirty_write(#user_caps{jid = BJID, caps = Caps}), + case ejabberd_sm:get_user_resources(U, S) of + [] -> + ok; + _ -> + % only store default resource of external contacts + BUID = exmpp_jlib:bare_jid_to_binary(From), + mnesia:dirty_write(#user_caps_default{uid = BUID, resource = R}) + end, SubNodes = [Version | Exts], %% Now, find which of these are not already in the database. Fun = fun() -> diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index c8eb5e500..da1620e58 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -2389,20 +2389,15 @@ broadcast_by_caps({LUser, LServer, LResource}, Node, _Type, Stanza) -> %%ReplyTo = jlib:make_jid(LUser, LServer, SenderResource), % This has to be used case catch ejabberd_c2s:get_subscribed(C2SPid) of Contacts when is_list(Contacts) -> - Online = lists:foldl(fun({U, S, R}, Acc) -> - case user_resource(U, S, R) of - [] -> Acc; - OR -> [{U, S, OR}|Acc] - end - end, [], Contacts), lists:foreach(fun({U, S, R}) -> - case is_caps_notify(LServer, Node, {U, S, R}) of + OR = user_resource(U, S, R), + case is_caps_notify(LServer, Node, {U, S, OR}) of true -> - ejabberd_router ! {route, Sender, exmpp_jid:make_jid(U, S, R), Stanza}; + ejabberd_router ! {route, Sender, exmpp_jid:make_jid(U, S, OR), Stanza}; false -> ok end - end, Online); + end, Contacts); _ -> ok end, @@ -2414,20 +2409,27 @@ broadcast_by_caps({LUser, LServer, LResource}, Node, _Type, Stanza) -> broadcast_by_caps(_, _, _, _) -> ok. +%% If we don't know the resource, just pick first if any +%% If no resource available, check if caps anyway (remote online) user_resource(LUser, LServer, []) -> - %% If we don't know the resource, just pick first if any case ejabberd_sm:get_user_resources(LUser, LServer) of - [R|_] -> R; - [] -> [] + [R|_] -> + R; + [] -> + mod_caps:get_user_resource(LUser, LServer) end; user_resource(_, _, LResource) -> LResource. is_caps_notify(Host, Node, LJID) -> - Caps = mod_caps:get_caps(LJID), - case catch mod_caps:get_features(Host, Caps) of - Features when is_list(Features) -> lists:member(Node ++ "+notify", Features); - _ -> false + case mod_caps:get_caps(LJID) of + nothing -> + false; + Caps -> + case catch mod_caps:get_features(Host, Caps) of + Features when is_list(Features) -> lists:member(Node ++ "+notify", Features); + _ -> false + end end. %%%%%%% Configuration handling From e032a8c54f0b28af78c05bb3ae22106cec40bc83 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Sat, 3 Jan 2009 00:29:36 +0000 Subject: [PATCH 149/582] PubSub cleanup, EJAB-827 fix, EJAB-701 partial fix SVN Revision: 1767 --- ChangeLog | 18 ++ src/mod_pubsub/mod_pubsub.erl | 406 +++++++++++++------------------- src/mod_pubsub/node_default.erl | 208 +++++++--------- src/mod_pubsub/node_pep.erl | 12 +- src/mod_pubsub/pubsub.hrl | 10 +- 5 files changed, 278 insertions(+), 376 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2ef1596c7..cbba3fa0b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2009-01-03 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: deliver notification depending on + presence-based-delivery configuration (EJAB-827). notification code + rewrite. + + * src/mod_pubsub/mod_pubsub.erl: code cleanning, minor bugfixes + * src/mod_pubsub/node_default.erl: Likewise + * src/mod_pubsub/node_pep.erl: Likewise + * src/mod_pubsub/pubsub.hrl: Likewise + + * src/mod_pubsub/mod_pubsub.erl: prevent subscribing with full jid, + waiting for full jid support (EJAB-701) + + * src/mod_pubsub/mod_pubsub.erl: use of delete-any feature instead of + delete-nodes for delete item use case (fix from erroneous definition + in XEP-0060) + 2008-12-23 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: Improve handling of PEP sent to diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index da1620e58..19cca3886 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -30,7 +30,7 @@ %%% %%% @reference See XEP-0060: Pubsub for %%% the latest version of the PubSub specification. -%%% This module uses version 1.11 of the specification as a base. +%%% This module uses version 1.12 of the specification as a base. %%% Most of the specification is implemented. %%% Functions concerning configuration should be rewritten. %%% Code is derivated from the original pubsub v1.7, by Alexey Shchepin @@ -40,7 +40,7 @@ -module(mod_pubsub). -author('christophe.romain@process-one.net'). --version('1.11-01'). +-version('1.12-01'). -behaviour(gen_server). -behaviour(gen_mod). @@ -92,9 +92,7 @@ string_to_subscription/1, string_to_affiliation/1, extended_error/2, - extended_error/3, - make_stanza/3, - route_stanza/3 + extended_error/3 ]). %% API and gen_server callbacks @@ -1076,12 +1074,11 @@ find_authorization_response(Packet) -> %% Plugins = [Plugin::string()] %% @doc Send a message to JID with the supplied Subscription send_authorization_approval(Host, JID, Node, Subscription) -> - Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = + Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'subscription', attrs = [#xmlattr{name = 'node', value = Node}, #xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(JID)}, - #xmlattr{name = 'subscription', value = subscription_to_string(Subscription)}]}]}]}, + #xmlattr{name = 'subscription', value = subscription_to_string(Subscription)}]}]), ejabberd_router ! {route, service_jid(Host), JID, Stanza}. handle_authorization_response(Host, From, To, Packet, XFields) -> @@ -1271,7 +1268,6 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> %% [{xmlelement, "x", [{"xmlns", ?NS_DATA_FORMS}, {"type", "result"}], %% [?XFIELD("hidden", "", "FORM_TYPE", ?NS_PUBSUB_NMI), %% ?XFIELD("jid-single", "Node Creator", "creator", jlib:jid_to_string(OwnerKey))]}]), - %% todo publish_item(Host, ServerHost, ["pubsub", "nodes"], node_to_string(Node)), case Result of default -> {result, Reply}; _ -> {result, Result} @@ -1317,14 +1313,17 @@ delete_node(Host, Node, Owner) -> {error, Error} -> {error, Error}; {result, {Result, broadcast, Removed}} -> - broadcast_removed_node(Host, Removed), - %%broadcast_retract_item(Host, ["pubsub", "nodes"], node_to_string(Node)), + lists:foreach(fun(RNode) -> + broadcast_removed_node(Host, RNode) + end, Removed), case Result of default -> {result, Reply}; _ -> {result, Result} end; {result, {Result, Removed}} -> - broadcast_removed_node(Host, Removed), + lists:foreach(fun(RNode) -> + broadcast_removed_node(Host, RNode) + end, Removed), case Result of default -> {result, Reply}; _ -> {result, Result} @@ -1536,23 +1535,17 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> {error, Reason} -> {error, Reason}; {result, {Result, broadcast, Removed}} -> - lists:foreach(fun(OldItem) -> - broadcast_retract_item(Host, Node, OldItem) - end, Removed), + broadcast_retract_items(Host, Node, Removed), broadcast_publish_item(Host, Node, ItemId, jlib:short_prepd_jid(Publisher), Payload), case Result of default -> {result, Reply}; _ -> {result, Result} end; {result, default, Removed} -> - lists:foreach(fun(OldItem) -> - broadcast_retract_item(Host, Node, OldItem) - end, Removed), + broadcast_retract_items(Host, Node, Removed), {result, Reply}; {result, Result, Removed} -> - lists:foreach(fun(OldItem) -> - broadcast_retract_item(Host, Node, OldItem) - end, Removed), + broadcast_retract_items(Host, Node, Removed), {result, Result}; {result, default} -> {result, Reply}; @@ -1583,7 +1576,7 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> Action = fun(#pubsub_node{type = Type}) -> Features = features(Type), PersistentFeature = lists:member("persistent-items", Features), - DeleteFeature = lists:member("delete-nodes", Features), + DeleteFeature = lists:member("delete-any", Features), if %%-> iq_pubsub just does that matchs %% %% Request does not specify an item @@ -1593,7 +1586,7 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> {error, extended_error('feature-not-implemented', unsupported, "persistent-items")}; not DeleteFeature -> %% Service does not support item deletion - {error, extended_error('feature-not-implemented', unsupported, "delete-nodes")}; + {error, extended_error('feature-not-implemented', unsupported, "delete-any")}; true -> node_call(Type, delete_item, [Host, Node, Publisher, ItemId]) end @@ -1603,7 +1596,7 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> {error, Reason} -> {error, Reason}; {result, {Result, broadcast}} -> - broadcast_retract_item(Host, Node, ItemId, ForceNotify), + broadcast_retract_items(Host, Node, [ItemId], ForceNotify), case Result of default -> {result, Reply}; _ -> {result, Result} @@ -1771,12 +1764,10 @@ send_items(Host, Node, {LU, LS, LR} = LJID, Number) -> [First|Tail] = Items, [lists:foldl( fun(CurItem, LastItem) -> - {_, {LMS, LS, LmS}} = LastItem#pubsub_item.creation, - {_, {CMS, CS, CmS}} = CurItem#pubsub_item.creation, - LTimestamp = LMS * 1000000 + LS * 1000 + LmS, - CTimestamp = CMS * 1000000 + CS * 1000 + CmS, + {_, LTimeStamp} = LastItem#pubsub_item.creation, + {_, CTimeStamp} = CurItem#pubsub_item.creation, if - CTimestamp > LTimestamp -> CurItem; + CTimeStamp > LTimeStamp -> CurItem; true -> LastItem end end, First, Tail)]; @@ -1795,10 +1786,9 @@ send_items(Host, Node, {LU, LS, LR} = LJID, Number) -> end, #xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = ItemAttrs, children = Payload} end, ToSend), - Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = + Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = - ItemsEls}]}]}, + ItemsEls}]), ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(LU, LS, LR), Stanza}. %% @spec (Host, JID, Plugins) -> {error, Reason} | {result, Response} @@ -2132,10 +2122,10 @@ service_jid(Host) -> %% Subscription = atom() %% PresenceDelivery = boolean() %% @doc

      Check if a notification must be delivered or not.

      -is_to_delivered(_, none, _) -> false; -is_to_delivered(_, pending, _) -> false; -is_to_delivered(_, _, false) -> true; -is_to_delivered({User, Server, _}, _, true) -> +is_to_deliver(_, none, _) -> false; +is_to_deliver(_, pending, _) -> false; +is_to_deliver(_, _, false) -> true; +is_to_deliver({User, Server, _}, _, true) -> case mnesia:dirty_match_object({session, '_', '_', {User, Server}, '_', '_'}) of [] -> false; Ss -> @@ -2153,228 +2143,172 @@ payload_xmlelements([], Count) -> Count; payload_xmlelements([#xmlel{}|Tail], Count) -> payload_xmlelements(Tail, Count+1); payload_xmlelements([_|Tail], Count) -> payload_xmlelements(Tail, Count). +%% @spec (Els) -> stanza() +%% Els = [xmlelement()] +%% @doc

      Build pubsub event stanza +event_stanza(Els) -> + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = Els}]}. + %%%%%% broadcast functions broadcast_publish_item(Host, Node, ItemId, _From, Payload) -> Action = fun(#pubsub_node{options = Options, type = Type}) -> - case node_call(Type, get_states, [Host, Node]) of - {error, _} -> {result, false}; - {result, []} -> {result, false}; - {result, States} -> - PresenceDelivery = get_option(Options, presence_based_delivery), - BroadcastAll = get_option(Options, broadcast_all_resources), - Content = case get_option(Options, deliver_payloads) of - true -> Payload; - false -> [] - end, - ItemAttrs = case ItemId of - "" -> []; - _ -> [#xmlattr{name = 'id', value = ItemId}] - end, - Stanza = make_stanza(Node, ItemAttrs, Content), - lists:foreach( - fun(#pubsub_state{stateid = {LJID, _}, - subscription = Subscription}) -> - case is_to_delivered(LJID, Subscription, PresenceDelivery) of - true -> - DestJIDs = case BroadcastAll of - true -> ejabberd_sm:get_user_resources(element(1, LJID), element(2, LJID)); - false -> [LJID] - end, - route_stanza(Host, DestJIDs, Stanza); - false -> - ok - end - end, States), - broadcast_by_caps(Host, Node, Type, Stanza), - {result, true} - end + case node_call(Type, get_states, [Host, Node]) of + {result, []} -> + {result, false}; + {result, States} -> + Content = case get_option(Options, deliver_payloads) of + true -> Payload; + false -> [] + end, + ItemAttrs = case ItemId of + "" -> []; + _ -> [#xmlattr{name = 'id', value = ItemId}] + end, + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = ItemAttrs, children = Content}]}]), + broadcast_stanza(Host, Options, States, Stanza), + broadcast_by_caps(Host, Node, Type, Stanza), + {result, true}; + _ -> + {result, false} + end end, transaction(Host, Node, Action, sync_dirty). -%% ItemAttrs is a list of tuples: -%% For example: [{"id", ItemId}] -make_stanza(Node, ItemAttrs, Payload) -> - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = ItemAttrs, children = Payload}]}]}]}. - -%% DestJIDs = [{LUser, LServer, LResource}] -route_stanza(Host, DestJIDs, Stanza) -> - lists:foreach( - fun({DU, DS, DR}) -> - ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(DU, DS, DR), Stanza} - end, DestJIDs). - -broadcast_retract_item(Host, Node, ItemId) -> - broadcast_retract_item(Host, Node, ItemId, false). -broadcast_retract_item(Host, Node, ItemId, ForceNotify) -> +broadcast_retract_items(Host, Node, ItemIds) -> + broadcast_retract_items(Host, Node, ItemIds, false). +broadcast_retract_items(Host, Node, ItemIds, ForceNotify) -> Action = fun(#pubsub_node{options = Options, type = Type}) -> - case node_call(Type, get_states, [Host, Node]) of - {error, _} -> {result, false}; - {result, []} -> {result, false}; - {result, States} -> - Notify = case ForceNotify of - true -> true; - _ -> get_option(Options, notify_retract) - end, - ItemAttrs = case ItemId of - "" -> []; - _ -> [#xmlattr{name = 'id', value = ItemId}] - end, - Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = ItemAttrs}]}]}]}, - case Notify of - true -> - lists:foreach( - fun(#pubsub_state{stateid = {{U, S, R}, _}, - subscription = Subscription}) -> - if (Subscription /= none) and - (Subscription /= pending) -> - ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(U, S, R), Stanza}; - true -> - ok - end - end, States), - broadcast_by_caps(Host, Node, Type, Stanza), - {result, true}; - false -> - {result, false} - end - end + case (get_option(Options, notify_retract) or ForceNotify) of + true -> + case node_call(Type, get_states, [Host, Node]) of + {result, []} -> + {result, false}; + {result, States} -> + RetractEls = lists:map( + fun(ItemId) -> + ItemAttrs = case ItemId of + "" -> []; + _ -> [#xmlattr{name = 'id', value = ItemId}] + end, + #xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = ItemAttrs} + end, ItemIds), + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], + children = RetractEls}]), + broadcast_stanza(Host, Options, States, Stanza), + broadcast_by_caps(Host, Node, Type, Stanza), + {result, true}; + _ -> + {result, false} + end; + _ -> + {result, false} + end end, transaction(Host, Node, Action, sync_dirty). broadcast_purge_node(Host, Node) -> Action = fun(#pubsub_node{options = Options, type = Type}) -> - case node_call(Type, get_states, [Host, Node]) of - {error, _} -> {result, false}; - {result, []} -> {result, false}; - {result, States} -> - Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'purge', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}]}]}]}, - case get_option(Options, notify_retract) of - true -> - lists:foreach( - fun(#pubsub_state{stateid = {{U, S, R},_}, - subscription = Subscription}) -> - if (Subscription /= none) and - (Subscription /= pending) -> - ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(U, S, R), Stanza}; - true -> - ok - end - end, States), - broadcast_by_caps(Host, Node, Type, Stanza), - {result, true}; - false -> - {result, false} - end - end + case get_option(Options, notify_retract) of + true -> + case node_call(Type, get_states, [Host, Node]) of + {result, []} -> + {result, false}; + {result, States} -> + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'purge', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}]}]), + broadcast_stanza(Host, Options, States, Stanza), + broadcast_by_caps(Host, Node, Type, Stanza), + {result, true}; + _ -> + {result, false} + end; + _ -> + {result, false} + end end, transaction(Host, Node, Action, sync_dirty). -broadcast_removed_node(Host, Removed) -> - lists:foreach( - fun(Node) -> - Action = - fun(#pubsub_node{options = Options, type = Type}) -> - Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'delete', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}]}]}]}, - case get_option(Options, notify_delete) of - true -> - case node_call(Type, get_states, [Host, Node]) of - {result, States} -> - lists:foreach( - fun(#pubsub_state{stateid = {{U, S, R}, _}, - subscription = Subscription}) -> - if (Subscription /= none) and - (Subscription /= pending) -> - ejabberd_router ! {route, service_jid(Host), jlib:make_jid(U, S, R), Stanza}; - true -> - ok - end - end, States), - broadcast_by_caps(Host, Node, Type, Stanza), - {result, true}; - _ -> - {result, false} - end; - _ -> - {result, false} - end - end, - transaction(Host, Node, Action, sync_dirty) - end, Removed). +broadcast_removed_node(Host, Node) -> + Action = + fun(#pubsub_node{options = Options, type = Type}) -> + case get_option(Options, notify_delete) of + true -> + case node_call(Type, get_states, [Host, Node]) of + {result, []} -> + {result, false}; + {result, States} -> + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'delete', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}]}]), + broadcast_stanza(Host, Options, States, Stanza), + broadcast_by_caps(Host, Node, Type, Stanza), + {result, true}; + _ -> + {result, false} + end; + _ -> + {result, false} + end + end, + transaction(Host, Node, Action, sync_dirty). broadcast_config_notification(Host, Node, Lang) -> Action = fun(#pubsub_node{options = Options, owners = Owners, type = Type}) -> - case node_call(Type, get_states, [Host, Node]) of - {error, _} -> {result, false}; - {result, []} -> {result, false}; - {result, States} -> - case get_option(Options, notify_config) of - true -> - PresenceDelivery = get_option(Options, presence_based_delivery), - Content = case get_option(Options, deliver_payloads) of - true -> - [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', value = "form"}], children = - get_configure_xfields(Type, Options, Lang, Owners)}]; - false -> - [] - end, - Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = [#xmlattr{name = 'id', value = "configuration"}], children = - Content}]}]}]}, - lists:foreach( - fun(#pubsub_state{stateid = {{U, S, R} = LJID, _}, - subscription = Subscription}) -> - case is_to_delivered(LJID, Subscription, PresenceDelivery) of - true -> - ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(U, S, R), Stanza}; - false -> - ok - end - end, States), - broadcast_by_caps(Host, Node, Type, Stanza), - {result, true}; - _ -> - {result, false} - end - end + case get_option(Options, notify_config) of + true -> + case node_call(Type, get_states, [Host, Node]) of + {result, []} -> + {result, false}; + {result, States} -> + Content = case get_option(Options, deliver_payloads) of + true -> + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', value = "form"}], children = + get_configure_xfields(Type, Options, Lang, Owners)}]; + false -> + [] + end, + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = [#xmlattr{name = 'id', value = "configuration"}], children = + Content}]}]), + broadcast_stanza(Host, Options, States, Stanza), + broadcast_by_caps(Host, Node, Type, Stanza), + {result, true}; + _ -> + {result, false} + end; + _ -> + {result, false} + end end, transaction(Host, Node, Action, sync_dirty). -%TODO: simplify broadcast_* using a generic function like that: -%broadcast(Host, Node, Fun) -> -% transaction(fun() -> -% case tree_call(Host, get_node, [Host, Node]) of -% #pubsub_node{options = Options, owners = Owners, type = Type} -> -% case node_call(Type, get_states, [Host, Node]) of -% {error, _} -> {result, false}; -% {result, []} -> {result, false}; -% {result, States} -> -% lists:foreach(fun(#pubsub_state{stateid = {JID,_}, subscription = Subscription}) -> -% Fun(Host, Node, Options, Owners, JID, Subscription) -% end, States), -% {result, true} -% end; -% Other -> -% Other -% end -% end, sync_dirty). - +broadcast_stanza(Host, NodeOpts, States, Stanza) -> + PresenceDelivery = get_option(NodeOpts, presence_based_delivery), + BroadcastAll = get_option(NodeOpts, broadcast_all_resources), + From = service_jid(Host), + lists:foreach(fun(#pubsub_state{stateid = {LJID, _}, subscription = Subs}) -> + case is_to_deliver(LJID, Subs, PresenceDelivery) of + true -> + JIDs = case BroadcastAll of + true -> ejabberd_sm:get_user_resources(element(1, LJID), element(2, LJID)); + false -> [LJID] + end, + lists:foreach(fun({U, S, R}) -> + ejabberd_router ! {route, From, exmpp_jlib:make_jid(U, S, R), Stanza} + end, JIDs); + false -> + ok + end + end, States). %% broadcast Stanza to all contacts of the user that are advertising %% interest in this kind of Node. @@ -2724,18 +2658,18 @@ select_type(ServerHost, Host, Node) -> features() -> [ - %"access-authorize", % OPTIONAL + %TODO "access-authorize", % OPTIONAL "access-open", % OPTIONAL this relates to access_model option in node_default "access-presence", % OPTIONAL this relates to access_model option in node_pep - %"access-roster", % OPTIONAL - %"access-whitelist", % OPTIONAL + %TODO "access-roster", % OPTIONAL + %TODO "access-whitelist", % OPTIONAL % see plugin "auto-create", % OPTIONAL % see plugin "auto-subscribe", % RECOMMENDED "collections", % RECOMMENDED "config-node", % RECOMMENDED "create-and-configure", % RECOMMENDED % see plugin "create-nodes", % RECOMMENDED - %TODO "delete-any", % OPTIONAL + % see plugin "delete-any", % RECOMMENDED % see plugin "delete-nodes", % RECOMMENDED % see plugin "filtered-notifications", % RECOMMENDED %TODO "get-pending", % OPTIONAL diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 8757ac4a4..2deb66907 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -160,6 +160,7 @@ features() -> ["create-nodes", "auto-create", "delete-nodes", + "delete-any", "instant-nodes", "manage-subscriptions", "modify-affiliations", @@ -222,8 +223,7 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) -> %% @doc

      create_node(Host, Node, Owner) -> OwnerKey = jlib:short_prepd_bare_jid(Owner), - mnesia:write(#pubsub_state{stateid = {OwnerKey, {Host, Node}}, - affiliation = owner, subscription = none}), + set_state(#pubsub_state{stateid = {OwnerKey, {Host, Node}}, affiliation = owner}), {result, {default, broadcast}}. @@ -236,12 +236,8 @@ delete_node(Host, Removed) -> fun(Node) -> lists:foreach( fun(#pubsub_state{stateid = StateId, items = Items}) -> - lists:foreach( - fun(ItemId) -> - mnesia:delete( - {pubsub_item, {ItemId, {Host, Node}}}) - end, Items), - mnesia:delete({pubsub_state, StateId}) + del_items(Host, Node, Items), + del_state(StateId) end, mnesia:match_object( #pubsub_state{stateid = {'_', {Host, Node}}, _ = '_'})) @@ -283,13 +279,9 @@ delete_node(Host, Removed) -> %%

      In the default plugin module, the record is unchanged.

      subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - Authorized = (jlib:short_prepd_bare_jid(Sender) == jlib:short_bare_jid(Subscriber)), - % TODO add some acl check for Authorized ? - State = case get_state(Host, Node, Subscriber) of - {error, 'item-not-found'} -> - #pubsub_state{stateid = {Subscriber, {Host, Node}}}; % TODO: bug on Key ? - {result, S} -> S - end, + SubscriberKey = jlib:short_prepd_bare_jid(Subscriber), + Authorized = (jlib:short_prepd_bare_jid(Sender) == SubscriberKey), + State = get_state(Host, Node, SubscriberKey), #pubsub_state{affiliation = Affiliation, subscription = Subscription} = State, if @@ -325,7 +317,6 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel, if AccessModel == authorize -> pending; - %%TODO Affiliation == none -> ? %%NeedConfiguration -> %% unconfigured true -> @@ -353,43 +344,29 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel, %% Reason = mod_pubsub:stanzaError() %% @doc

      Unsubscribe the Subscriber from the Node.

      unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> - SenderKey = jlib:short_prepd_jid(Sender), - Match = jlib:short_prepd_bare_jid(Sender) == jlib:short_bare_jid(Subscriber), - Authorized = case Match of - true -> - true; - false -> - case get_state(Host, Node, SenderKey) of % TODO: bug on Key ? - {result, #pubsub_state{affiliation=owner}} -> true; - _ -> false - end - end, - case get_state(Host, Node, Subscriber) of - {error, 'item-not-found'} -> - %% Requesting entity is not a subscriber + SubscriberKey = jlib:short_prepd_bare_jid(Subscriber), + Authorized = (jlib:short_prepd_bare_jid(Sender) == SubscriberKey), + State = get_state(Host, Node, SubscriberKey), + if + %% Entity did not specify SubID + %%SubID == "", ?? -> + %% {error, ?ERR_EXTENDED('bad-request', "subid-required")}; + %% Invalid subscription identifier + %%InvalidSubID -> + %% {error, ?ERR_EXTENDED('not-acceptable', "invalid-subid")}; + %% Requesting entity is not a subscriber + State#pubsub_state.subscription == none -> {error, ?ERR_EXTENDED('unexpected-request', "not-subscribed")}; - {result, State} -> - if - %% Entity did not specify SubID - %%SubID == "", ?? -> - %% {error, ?ERR_EXTENDED('bad-request', "subid-required")}; - %% Invalid subscription identifier - %%InvalidSubID -> - %% {error, ?ERR_EXTENDED('not-acceptable', "invalid-subid")}; - %% Requesting entity is not a subscriber - State#pubsub_state.subscription == none -> - {error, ?ERR_EXTENDED('unexpected-request', "not-subscribed")}; - %% Requesting entity is prohibited from unsubscribing entity - not Authorized -> - {error, 'forbidden'}; - %% Was just subscriber, remove the record - State#pubsub_state.affiliation == none -> - mnesia:delete({pubsub_state, State#pubsub_state.stateid}), - {result, default}; - true -> - set_state(State#pubsub_state{subscription = none}), - {result, default} - end + %% Requesting entity is prohibited from unsubscribing entity + (not Authorized) and (State#pubsub_state.affiliation =/= owner) -> + {error, 'forbidden'}; + %% Was just subscriber, remove the record + State#pubsub_state.affiliation == none -> + mnesia:delete({pubsub_state, State#pubsub_state.stateid}), + {result, default}; + true -> + set_state(State#pubsub_state{subscription = none}), + {result, default} end. %% @spec (Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) -> @@ -433,10 +410,7 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> %%

      In the default plugin module, the record is unchanged.

      publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) -> PublisherKey = jlib:short_prepd_bare_jid(Publisher), - State = case get_state(Host, Node, PublisherKey) of - {error, 'item-not-found'} -> #pubsub_state{stateid={PublisherKey, {Host, Node}}}; - {result, S} -> S - end, + State = get_state(Host, Node, PublisherKey), #pubsub_state{affiliation = Affiliation, subscription = Subscription} = State, if @@ -448,17 +422,17 @@ publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) -> %% Entity does not have sufficient privileges to publish to node {error, 'forbidden'}; true -> - PubId = {PublisherKey, now()}, + PubId = {PublisherKey, now()}, %% TODO, uses {now(),PublisherKey} for sorting (EJAB-824) %% TODO: check creation, presence, roster (EJAB-663) Item = case get_item(Host, Node, ItemId) of - {error, 'item-not-found'} -> + {result, OldItem} -> + OldItem#pubsub_item{modification = PubId, + payload = Payload}; + _ -> #pubsub_item{itemid = {ItemId, {Host, Node}}, creation = PubId, modification = PubId, - payload = Payload}; - {result, OldItem} -> - OldItem#pubsub_item{modification = PubId, - payload = Payload} + payload = Payload} end, Items = [ItemId | State#pubsub_state.items--[ItemId]], {result, {NI, OI}} = remove_extra_items( @@ -492,9 +466,7 @@ remove_extra_items(Host, Node, MaxItems, ItemIds) -> NewItems = lists:sublist(ItemIds, MaxItems), OldItems = lists:nthtail(length(NewItems), ItemIds), %% Remove extra items: - lists:foreach(fun(ItemId) -> - mnesia:delete({pubsub_item, {ItemId, {Host, Node}}}) - end, OldItems), + del_items(Host, Node, OldItems), %% Return the new items list: {result, {NewItems, OldItems}}. @@ -510,12 +482,7 @@ remove_extra_items(Host, Node, MaxItems, ItemIds) -> %% or a publisher.

      delete_item(Host, Node, Publisher, ItemId) -> PublisherKey = jlib:short_prepd_bare_jid(Publisher), - State = case get_state(Host, Node, PublisherKey) of - {error, 'item-not-found'} -> - #pubsub_state{stateid = {PublisherKey, {Host, Node}}}; - {result, S} -> - S - end, + State = get_state(Host, Node, PublisherKey), #pubsub_state{affiliation = Affiliation, items = Items} = State, Allowed = (Affiliation == publisher) orelse (Affiliation == owner) orelse case get_item(Host, Node, ItemId) of @@ -529,7 +496,7 @@ delete_item(Host, Node, Publisher, ItemId) -> true -> case get_item(Host, Node, ItemId) of {result, _} -> - mnesia:delete({pubsub_item, {ItemId, {Host, Node}}}), + del_item(Host, Node, ItemId), NewItems = lists:delete(ItemId, Items), set_state(State#pubsub_state{items = NewItems}), {result, {default, broadcast}}; @@ -548,16 +515,14 @@ delete_item(Host, Node, Publisher, ItemId) -> purge_node(Host, Node, Owner) -> OwnerKey = jlib:short_prepd_bare_jid(Owner), case get_state(Host, Node, OwnerKey) of - {result, #pubsub_state{items = Items, affiliation = owner}} -> + #pubsub_state{items = Items, affiliation = owner} -> lists:foreach(fun(ItemId) -> mnesia:delete({pubsub_item, {ItemId, {Host, Node}}}) end, Items), {result, {default, broadcast}}; - {result, _} -> - %% Entity is not owner - {error, 'forbidden'}; _ -> - {error, 'item-not-found'} + %% Entity is not owner + {error, 'forbidden'} end. %% @spec (Host, JID) -> [{Node,Affiliation}] @@ -573,8 +538,7 @@ purge_node(Host, Node, Owner) -> get_entity_affiliations(Host, Owner) -> OwnerKey = jlib:short_prepd_bare_jid(Owner), States = mnesia:match_object( - #pubsub_state{stateid = {OwnerKey, {Host, '_'}}, - _ = '_'}), + #pubsub_state{stateid = {OwnerKey, {Host, '_'}}, _ = '_'}), Tr = fun(#pubsub_state{stateid = {_, {_, N}}, affiliation = A}) -> {N, A} end, @@ -582,8 +546,7 @@ get_entity_affiliations(Host, Owner) -> get_node_affiliations(Host, Node) -> States = mnesia:match_object( - #pubsub_state{stateid = {'_', {Host, Node}}, - _ = '_'}), + #pubsub_state{stateid = {'_', {Host, Node}}, _ = '_'}), Tr = fun(#pubsub_state{stateid = {J, {_, _}}, affiliation = A}) -> {J, A} end, @@ -591,22 +554,13 @@ get_node_affiliations(Host, Node) -> get_affiliation(Host, Node, Owner) -> OwnerKey = jlib:short_prepd_bare_jid(Owner), - Affiliation = case get_state(Host, Node, OwnerKey) of - {result, #pubsub_state{affiliation = A}} -> A; - _ -> none - end, - {result, Affiliation}. + State = get_state(Host, Node, OwnerKey), + {result, State#pubsub_state.affiliation}. set_affiliation(Host, Node, Owner, Affiliation) -> OwnerKey = jlib:short_prepd_bare_jid(Owner), - Record = case get_state(Host, Node, OwnerKey) of - {error, 'item-not-found'} -> - #pubsub_state{stateid = {OwnerKey, {Host, Node}}, - affiliation = Affiliation}; - {result, State} -> - State#pubsub_state{affiliation = Affiliation} - end, - set_state(Record), + State = get_state(Host, Node, OwnerKey), + set_state(State#pubsub_state{affiliation = Affiliation}), ok. %% @spec (Host, Owner) -> [{Node,Subscription}] @@ -623,8 +577,7 @@ set_affiliation(Host, Node, Owner, Affiliation) -> get_entity_subscriptions(Host, Owner) -> OwnerKey = jlib:short_prepd_bare_jid(Owner), States = mnesia:match_object( - #pubsub_state{stateid = {OwnerKey, {Host, '_'}}, - _ = '_'}), + #pubsub_state{stateid = {OwnerKey, {Host, '_'}}, _ = '_'}), Tr = fun(#pubsub_state{stateid = {_, {_, N}}, subscription = S}) -> {N, S} end, @@ -632,8 +585,7 @@ get_entity_subscriptions(Host, Owner) -> get_node_subscriptions(Host, Node) -> States = mnesia:match_object( - #pubsub_state{stateid = {'_', {Host, Node}}, - _ = '_'}), + #pubsub_state{stateid = {'_', {Host, Node}}, _ = '_'}), Tr = fun(#pubsub_state{stateid = {J, {_, _}}, subscription = S}) -> {J, S} end, @@ -641,22 +593,13 @@ get_node_subscriptions(Host, Node) -> get_subscription(Host, Node, Owner) -> OwnerKey = jlib:short_prepd_bare_jid(Owner), - Subscription = case get_state(Host, Node, OwnerKey) of - {result, #pubsub_state{subscription = S}} -> S; - _ -> none - end, - {result, Subscription}. + State = get_state(Host, Node, OwnerKey), + {result, State#pubsub_state.subscription}. set_subscription(Host, Node, Owner, Subscription) -> OwnerKey = jlib:short_prepd_bare_jid(Owner), - Record = case get_state(Host, Node, OwnerKey) of - {error, 'item-not-found'} -> - #pubsub_state{stateid = {OwnerKey, {Host, Node}}, - subscription = Subscription}; - {result, State} -> - State#pubsub_state{subscription = Subscription} - end, - set_state(Record), + State = get_state(Host, Node, OwnerKey), + set_state(State#pubsub_state{subscription = Subscription}), ok. %% @spec (Host, Node) -> [States] | [] @@ -685,11 +628,10 @@ get_states(Host, Node) -> %% State = mod_pubsub:pubsubItems() %% @doc

      Returns a state (one state list), given its reference.

      get_state(Host, Node, JID) -> - case mnesia:read({pubsub_state, {JID, {Host, Node}}}) of - [State] when is_record(State, pubsub_state) -> - {result, State}; - _ -> - {error, 'item-not-found'} + StateId = {JID, {Host, Node}}, + case mnesia:read({pubsub_state, StateId}) of + [State] when is_record(State, pubsub_state) -> State + _ -> #pubsub_state{stateid=StateId} end. %% @spec (State) -> ok | {error, Reason::stanzaError()} @@ -700,6 +642,12 @@ set_state(State) when is_record(State, pubsub_state) -> set_state(_) -> {error, 'internal-server-error'}. +%% @spec (StateId) -> ok | {error, Reason::stanzaError()} +%% StateId = mod_pubsub:pubsubStateId() +%% @doc

      Delete a state from database.

      +del_state(StateId) -> + mnesia:delete({pubsub_state, StateId}). + %% @spec (Host, Node) -> [Items] | [] %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() @@ -719,11 +667,9 @@ get_items(Host, Node, _From) -> #pubsub_item{itemid = {'_', {Host, Node}}, _ = '_'}), {result, Items}. get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> - {Affiliation, Subscription} = - case get_state(Host, Node, jlib:short_prepd_bare_jid(JID)) of - {result, #pubsub_state{affiliation = A, subscription = S}} -> {A, S}; - _ -> {none, none} - end, + State = get_state(Host, Node, jlib:short_prepd_bare_jid(JID)), + #pubsub_state{affiliation = Affiliation, + subscription = Subscription} = State, Subscribed = not ((Subscription == none) or (Subscription == pending)), if %%SubID == "", ?? -> @@ -771,11 +717,9 @@ get_item(Host, Node, ItemId) -> {error, 'item-not-found'} end. get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> - {Affiliation, Subscription} = - case get_state(Host, Node, jlib:short_prepd_bare_jid(JID)) of - {result, #pubsub_state{affiliation = A, subscription = S}} -> {A, S}; - _ -> {none, none} - end, + State = get_state(Host, Node, jlib:short_prepd_bare_jid(JID)), + #pubsub_state{affiliation = Affiliation, + subscription = Subscription} = State, Subscribed = not ((Subscription == none) or (Subscription == pending)), if %%SubID == "", ?? -> @@ -817,6 +761,18 @@ set_item(Item) when is_record(Item, pubsub_item) -> set_item(_) -> {error, 'internal-server-error'}. +%% @spec (ItemId) -> ok | {error, Reason::stanzaError()} +%% Host = mod_pubsub:host() +%% Node = mod_pubsub:pubsubNode() +%% ItemId = string() +%% @doc

      Delete an item from database.

      +del_item(Host, Node, ItemId) -> + mnesia:delete({pubsub_item, {ItemId, {Host, Node}}}). +del_items(Host, Node, ItemIds) -> + lists:foreach(fun(ItemId) -> + del_item(Host, Node, ItemId) + end, ItemIds). + %% @doc

      Return the name of the node if known: Default is to return %% node id.

      get_item_name(_Host, _Node, Id) -> diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index ec617abda..cbbc16ce6 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -182,15 +182,9 @@ get_affiliation(_Host, Node, Owner) -> set_affiliation(_Host, Node, Owner, Affiliation) -> OwnerKey = jlib:short_prepd_bare_jid(Owner), - Record = case get_state(OwnerKey, Node, OwnerKey) of - {error, 'item-not-found'} -> - #pubsub_state{stateid = {OwnerKey, {OwnerKey, Node}}, - affiliation = Affiliation}; - {result, State} -> - State#pubsub_state{affiliation = Affiliation} - end, - set_state(Record), - ok. + State = get_state(OwnerKey, Node, OwnerKey), + set_state(State#pubsub_state{affiliation = Affiliation}), + ok. get_entity_subscriptions(_Host, _Owner) -> {result, []}. diff --git a/src/mod_pubsub/pubsub.hrl b/src/mod_pubsub/pubsub.hrl index b4ceed4fa..61ed88dbe 100644 --- a/src/mod_pubsub/pubsub.hrl +++ b/src/mod_pubsub/pubsub.hrl @@ -72,7 +72,7 @@ %%% lserver = string(), %%% lresource = string()}. -%%% @type usr() = {User::string(), Server::string(), Resource::string()}. +%%% @type ljid() = {User::string(), Server::string(), Resource::string()}. %%% @type affiliation() = none | owner | publisher | outcast. %%% @type subscription() = none | pending | unconfigured | subscribed. @@ -81,7 +81,7 @@ %%% nodeid = {Host::host(), Node::pubsubNode()}, %%% parentid = {Host::host(), Node::pubsubNode()}, %%% type = nodeType(), -%%% owners = [usr()], +%%% owners = [ljid()], %%% options = [nodeOption()]}. %%%

      This is the format of the nodes table. The type of the table %%% is: set,ram/disc.

      @@ -94,7 +94,7 @@ }). %%% @type pubsubState() = #pubsub_state{ -%%% stateid = {jid(), {Host::host(), Node::pubsubNode()}}, +%%% stateid = {ljid(), {Host::host(), Node::pubsubNode()}}, %%% items = [ItemId::string()], %%% affiliation = affiliation(), %%% subscription = subscription()}. @@ -108,8 +108,8 @@ %% @type pubsubItem() = #pubsub_item{ %% itemid = {ItemId::string(), {Host::host(),Node::pubsubNode()}}, -%% creation = {JID::jid(), now()}, -%% modification = {JID::jid(), now()}, +%% creation = {ljid(), now()}, +%% modification = {ljid(), now()}, %% payload = XMLContent::string()}. %%%

      This is the format of the published items table. The type of the %%% table is: set,disc,fragmented.

      From 1a44fe29b421c838998443709d7c0008d05ecb0d Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Sat, 3 Jan 2009 00:58:18 +0000 Subject: [PATCH 150/582] PubSub: Added access-whitelist and member-affiliation features (EJAB-780) SVN Revision: 1769 --- ChangeLog | 3 +++ src/mod_pubsub/mod_pubsub.erl | 6 ++++-- src/mod_pubsub/node_default.erl | 15 +++++++++------ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index cbba3fa0b..6e42e4083 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,9 @@ delete-nodes for delete item use case (fix from erroneous definition in XEP-0060) + * src/mod_pubsub/mod_pubsub.erl: Added "access-whitelist" and + "member-affiliation" features (thanks to Andy Skelton)(EJAB-780) + 2008-12-23 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: Improve handling of PEP sent to diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 19cca3886..95aab8969 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -2063,6 +2063,7 @@ get_roster_info(OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, _}, A %% @doc

      Convert an affiliation type from string to atom.

      string_to_affiliation("owner") -> owner; string_to_affiliation("publisher") -> publisher; +string_to_affiliation("member") -> member; string_to_affiliation("outcast") -> outcast; string_to_affiliation("none") -> none; string_to_affiliation(_) -> false. @@ -2083,6 +2084,7 @@ string_to_subscription(_) -> false. %% @doc

      Convert an affiliation type from atom to string.

      affiliation_to_string(owner) -> "owner"; affiliation_to_string(publisher) -> "publisher"; +affiliation_to_string(member) -> "member"; affiliation_to_string(outcast) -> "outcast"; affiliation_to_string(_) -> "none". @@ -2662,7 +2664,7 @@ features() -> "access-open", % OPTIONAL this relates to access_model option in node_default "access-presence", % OPTIONAL this relates to access_model option in node_pep %TODO "access-roster", % OPTIONAL - %TODO "access-whitelist", % OPTIONAL + "access-whitelist", % OPTIONAL % see plugin "auto-create", % OPTIONAL % see plugin "auto-subscribe", % RECOMMENDED "collections", % RECOMMENDED @@ -2679,7 +2681,7 @@ features() -> %TODO "cache-last-item", %TODO "leased-subscription", % OPTIONAL % see plugin "manage-subscriptions", % OPTIONAL - %TODO "member-affiliation", % RECOMMENDED + "member-affiliation", % RECOMMENDED %TODO "meta-data", % RECOMMENDED % see plugin "modify-affiliations", % OPTIONAL %TODO "multi-collection", % OPTIONAL diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 2deb66907..6e0617813 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -284,6 +284,7 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel, State = get_state(Host, Node, SubscriberKey), #pubsub_state{affiliation = Affiliation, subscription = Subscription} = State, + Whitelisted = lists:member(Affiliation, [member, publisher, owner]), if not Authorized -> %% JIDs do not match @@ -300,8 +301,8 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel, (AccessModel == roster) and (not RosterGroup) -> %% Entity is not authorized to create a subscription (not in roster group) {error, ?ERR_EXTENDED('not-authorized', "not-in-roster-group")}; - (AccessModel == whitelist) -> % TODO: to be done - %% Node has whitelist access model + (AccessModel == whitelist) and (not Whitelisted) -> + %% Node has whitelist access model and entity lacks required affiliation {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; (AccessModel == authorize) -> % TODO: to be done %% Node has authorize access model @@ -671,6 +672,7 @@ get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubI #pubsub_state{affiliation = Affiliation, subscription = Subscription} = State, Subscribed = not ((Subscription == none) or (Subscription == pending)), + Whitelisted = lists:member(Affiliation, [member, publisher, owner]), if %%SubID == "", ?? -> %% Entity has multiple subscriptions to the node but does not specify a subscription ID @@ -690,8 +692,8 @@ get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubI (AccessModel == roster) and (not RosterGroup) -> %% Entity is not authorized to create a subscription (not in roster group) {error, ?ERR_EXTENDED('not-authorized', "not-in-roster-group")}; - (AccessModel == whitelist) -> % TODO: to be done - %% Node has whitelist access model + (AccessModel == whitelist) and (not Whitelisted) -> + %% Node has whitelist access model and entity lacks required affiliation {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; (AccessModel == authorize) -> % TODO: to be done %% Node has authorize access model @@ -721,6 +723,7 @@ get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup #pubsub_state{affiliation = Affiliation, subscription = Subscription} = State, Subscribed = not ((Subscription == none) or (Subscription == pending)), + Whitelisted = lists:member(Affiliation, [member, publisher, owner]), if %%SubID == "", ?? -> %% Entity has multiple subscriptions to the node but does not specify a subscription ID @@ -740,8 +743,8 @@ get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup (AccessModel == roster) and (not RosterGroup) -> %% Entity is not authorized to create a subscription (not in roster group) {error, ?ERR_EXTENDED('not-authorized', "not-in-roster-group")}; - (AccessModel == whitelist) -> % TODO: to be done - %% Node has whitelist access model + (AccessModel == whitelist) and (not Whitelisted) -> + %% Node has whitelist access model and entity lacks required affiliation {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; (AccessModel == authorize) -> % TODO: to be done %% Node has authorize access model From 4827db4f5650ab12366b4be5f8a88c40bc7137ac Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Sat, 3 Jan 2009 15:15:38 +0000 Subject: [PATCH 151/582] Big #jid to binary() conversion. Internal tables (ejabberd_router, ejabberd_sm, ejabberd_hooks, mod_last, mod_roster) use binary() as storage. Basic test using the ODBC backend. SVN Revision: 1770 --- ChangeLog | 26 ++++ src/ejabberd_auth_internal.erl | 8 +- src/ejabberd_auth_odbc.erl | 8 +- src/ejabberd_c2s.erl | 261 +++++++++++++++++++------------- src/ejabberd_hooks.erl | 10 +- src/ejabberd_local.erl | 13 +- src/ejabberd_receiver.erl | 59 +++++--- src/ejabberd_router.erl | 31 ++-- src/ejabberd_s2s.erl | 10 +- src/ejabberd_s2s_in.erl | 36 ++--- src/ejabberd_service.erl | 9 +- src/ejabberd_sm.erl | 214 ++++++++++++++------------ src/ejabberd_system_monitor.erl | 18 ++- src/jlib.erl | 52 ++----- src/mod_adhoc.erl | 55 ++++--- src/mod_announce.erl | 117 +++++++------- src/mod_caps.erl | 19 ++- src/mod_configure.erl | 148 ++++++++++-------- src/mod_configure2.erl | 2 +- src/mod_disco.erl | 98 ++++++------ src/mod_echo.erl | 5 +- src/mod_irc/mod_irc.erl | 17 ++- src/mod_last.erl | 40 ++--- src/mod_last_odbc.erl | 40 ++--- src/mod_muc/mod_muc.erl | 14 +- src/mod_muc/mod_muc_log.erl | 2 +- src/mod_muc/mod_muc_room.erl | 34 +++-- src/mod_offline.erl | 44 +++--- src/mod_offline_odbc.erl | 58 ++++--- src/mod_privacy.erl | 50 +++--- src/mod_privacy_odbc.erl | 50 +++--- src/mod_private.erl | 18 ++- src/mod_private_odbc.erl | 21 ++- src/mod_pubsub/node_default.erl | 2 +- src/mod_register.erl | 58 ++++--- src/mod_roster.erl | 101 ++++++------ src/mod_roster_odbc.erl | 120 ++++++++------- src/mod_service_log.erl | 18 ++- src/mod_shared_roster.erl | 60 ++++---- src/mod_stats.erl | 4 +- src/mod_vcard.erl | 21 ++- src/mod_vcard_ldap.erl | 13 +- src/mod_vcard_odbc.erl | 24 +-- src/mod_version.erl | 2 +- 44 files changed, 1129 insertions(+), 881 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6e42e4083..1a5d73e47 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2009-01-03 Pablo Polvorin + * src/mod_pubsub_node_default.erl: Fix typo + + * src/mod_vcard.erl, src/mod_vcard_ldap.erl,src/ ejabberd_hooks.erl, + mod_muc/mod_muc_room.erl, src/mod_muc/mod_muc.erl, + src/mod_muc/mod_muc_log.erl, src/mod_shared_roster.erl, + src/ejabberd_auth_odbc.erl, src/mod_offline_odbc.erl, + src/ejabberd_system_monitor.erl, src/ejabberd_s2s_in.erl, + src/mod_configure.erl, src/ejabberd_receiver.erl, src/mod_irc/mod_irc.erl, + src/ejabberd_sm.erl, src/mod_privacy_odbc.erl, src/ejabberd_c2s.erl, + src/mod_announce.erl, src/ejabberd_local.erl, src/mod_privacy.erl, + src/ejabberd_auth_internal.erl, src/mod_adhoc.erl, src/mod_echo.erl, + src/jlib.erl, src/mod_vcard_odbc.erl, src/ejabberd_s2s.erl, + src/mod_stats.erl, src/ejabberd_router.erl, src/mod_last.erl, + src/mod_private.erl, src/mod_roster.erl, src/ejabberd_service.erl, + src/mod_disco.erl, src/mod_private_odbc.erl, src/mod_service_log.erl, + src/mod_configure2.erl, src/mod_roster_odbc.erl, src/mod_offline.erl, + src/mod_register.erl, src/mod_version.erl, src/mod_caps.erl, + src/mod_last_odbc.erl: Use exmpp API to access JID fields. Keep + #jid fields in binary format when possible. Change all 'user' and + 'server' arguments in all hooks to binary. Change internal tables of + ejabberd_sm, ejabberd_router, ejabberd_hooks, mod_last, mod_roster + to use binary() storage. + + + 2009-01-03 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: deliver notification depending on diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index ab49f89f9..04efc52c8 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -261,7 +261,9 @@ remove_user(User, Server) -> mnesia:delete({passwd, US}) end, mnesia:transaction(F), - ejabberd_hooks:run(remove_user, LServer, [User, Server]) + ejabberd_hooks:run(remove_user, + list_to_binary(LServer), + [list_to_binary(User), list_to_binary(Server)]) catch _ -> ok @@ -285,7 +287,9 @@ remove_user(User, Server, Password) -> end, case mnesia:transaction(F) of {atomic, ok} -> - ejabberd_hooks:run(remove_user, LServer, [User, Server]), + ejabberd_hooks:run(remove_user, + list_to_binary(LServer), + [list_to_binary(User), list_to_binary(Server)]), ok; {atomic, Res} -> Res; diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index 1938427fb..79debf2ad 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -231,8 +231,8 @@ remove_user(User, Server) -> Username = ejabberd_odbc:escape(LUser), LServer = exmpp_stringprep:nameprep(Server), catch odbc_queries:del_user(LServer, Username), - ejabberd_hooks:run(remove_user, exmpp_stringprep:nameprep(Server), - [User, Server]) + ejabberd_hooks:run(remove_user, list_to_binary(LServer), + [list_to_binary(User), list_to_binary(Server)]) catch _ -> error @@ -249,8 +249,8 @@ remove_user(User, Server, Password) -> LServer, Username, Pass), case Result of {selected, ["password"], [{Password}]} -> - ejabberd_hooks:run(remove_user, exmpp_stringprep:nameprep(Server), - [User, Server]), + ejabberd_hooks:run(remove_user, list_to_binary(LServer), + [list_to_binary(User), list_to_binary(Server)]), ok; {selected, ["password"], []} -> not_exists; diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 0b40b5be7..2a806fbc1 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -37,7 +37,8 @@ send_element/2, socket_type/0, get_presence/1, - get_subscribed/1]). + get_subscribed/1, + get_subscribed_and_online/1]). %% gen_fsm callbacks -export([init/1, @@ -54,6 +55,9 @@ handle_info/3, terminate/3]). + +-export([get_state/1]). + -include_lib("exmpp/include/exmpp.hrl"). -include("ejabberd.hrl"). @@ -78,12 +82,13 @@ tls_options = [], authenticated = false, jid, - user = undefined, server = ?MYNAME, resource = undefined, + user = undefined, server = list_to_binary(?MYNAME), resource = undefined, sid, pres_t = ?SETS:new(), pres_f = ?SETS:new(), pres_a = ?SETS:new(), pres_i = ?SETS:new(), + pres_available = ?DICT:new(), pres_last, pres_pri, pres_timestamp, pres_invis = false, @@ -98,7 +103,7 @@ -ifdef(DBGFSM). -define(FSMOPTS, [{debug, [trace]}]). -else. --define(FSMOPTS, []). +-define(FSMOPTS, [{spawn_opt,[{fullsweep_after,10}]}]). -endif. %% Module start with or without supervisor: @@ -142,6 +147,11 @@ socket_type() -> get_presence(FsmRef) -> gen_fsm:sync_send_all_state_event(FsmRef, {get_presence}, 1000). + +%%TODO: for debug only +get_state(FsmRef) -> + gen_fsm:sync_send_all_state_event(FsmRef, get_state, 1000). + %%%---------------------------------------------------------------------- %%% Callback functions from gen_fsm %%%---------------------------------------------------------------------- @@ -170,7 +180,6 @@ init([{SockMod, Socket}, Opts]) -> TLSOpts = lists:filter(fun({certfile, _}) -> true; (_) -> false end, Opts), - Zlib = lists:member(zlib, Opts) andalso (not StartTLSRequired), IP = peerip(SockMod, Socket), %% Check if IP is blacklisted: case is_ip_blacklisted(IP) of @@ -203,8 +212,14 @@ init([{SockMod, Socket}, Opts]) -> end. %% Return list of all available resources of contacts, +%% in form [{JID, Caps}]. get_subscribed(FsmRef) -> - gen_fsm:sync_send_all_state_event(FsmRef, get_subscribed, 1000). + gen_fsm:sync_send_all_state_event( + FsmRef, get_subscribed, 1000). +get_subscribed_and_online(FsmRef) -> + gen_fsm:sync_send_all_state_event( + FsmRef, get_subscribed_and_online, 1000). + %%---------------------------------------------------------------------- %% Func: StateName/2 @@ -226,6 +241,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> ?NS_XMPP -> Server = exmpp_stringprep:nameprep( exmpp_stream:get_receiving_entity(Opening)), + ServerB = list_to_binary(Server), case lists:member(Server, ?MYHOSTS) of true -> Lang = exmpp_stream:get_lang(Opening), @@ -275,7 +291,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> end, Other_Feats = ejabberd_hooks:run_fold( c2s_stream_features, - Server, + ServerB, [], []), send_element(StateData, exmpp_stream:features( @@ -285,7 +301,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> Other_Feats)), fsm_next_state(wait_for_feature_request, StateData#state{ - server = Server, + server = ServerB, sasl_state = SASLState, lang = Lang}); _ -> @@ -299,7 +315,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> ])), fsm_next_state(wait_for_bind, StateData#state{ - server = Server, + server = ServerB, lang = Lang}); _ -> send_element( @@ -307,7 +323,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> exmpp_stream:features([])), fsm_next_state(wait_for_session, StateData#state{ - server = Server, + server = ServerB, lang = Lang}) end end; @@ -324,7 +340,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> send_element(StateData, Header), fsm_next_state(wait_for_auth, StateData#state{ - server = Server, + server = ServerB, lang = Lang}) end end; @@ -368,10 +384,11 @@ wait_for_stream(closed, StateData) -> wait_for_auth({xmlstreamelement, El}, StateData) -> + ServerString = binary_to_list(StateData#state.server), case is_auth_packet(El) of {auth, _ID, get, {_U, _, _, _}} -> Fields = case ejabberd_auth:plain_password_required( - StateData#state.server) of + ServerString) of false -> both; true -> plain end, @@ -386,11 +403,12 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> {auth, _ID, set, {U, P, D, R}} -> try JID = exmpp_jid:make_jid(U, StateData#state.server, R), - case acl:match_rule(StateData#state.server, + UBinary = exmpp_jid:lnode(JID), + case acl:match_rule(ServerString, StateData#state.access, JID) of allow -> case ejabberd_auth:check_password_with_authmodule( - U, StateData#state.server, P, + U, ServerString, P, StateData#state.streamid, D) of {true, AuthModule} -> ?INFO_MSG( @@ -402,7 +420,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> Info = [{ip, StateData#state.ip}, {conn, Conn}, {auth_module, AuthModule}], ejabberd_sm:open_session( - SID, U, StateData#state.server, R, Info), + SID, exmpp_jid:make_jid(U, StateData#state.server, R), Info), Res = exmpp_server_legacy_auth:success(El), send_element(StateData, Res), change_shaper(StateData, JID), @@ -410,18 +428,20 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> roster_get_subscription_lists, StateData#state.server, {[], []}, - [U, StateData#state.server]), + [UBinary, StateData#state.server]), LJID = jlib:short_prepd_bare_jid(JID), Fs1 = [LJID | Fs], Ts1 = [LJID | Ts], PrivList = ejabberd_hooks:run_fold( privacy_get_user_list, StateData#state.server, #userlist{}, - [U, StateData#state.server]), + [UBinary, StateData#state.server]), fsm_next_state(session_established, StateData#state{ - user = U, - resource = R, + sasl_state = 'undefined', + %not used anymore, let the GC work. + user = list_to_binary(U), + resource = list_to_binary(R), jid = JID, sid = SID, conn = Conn, @@ -504,7 +524,7 @@ wait_for_feature_request({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, StateData#state{ streamid = new_id(), authenticated = true, - user = U }); + user = list_to_binary(U) }); {continue, ServerOut, NewSASLState} -> send_element(StateData, exmpp_server_sasl:challenge(ServerOut)), @@ -528,8 +548,9 @@ wait_for_feature_request({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, {?NS_TLS, 'starttls'} when TLS == true, TLSEnabled == false, SockMod == gen_tcp -> + ServerString = binary_to_list(StateData#state.server), TLSOpts = case ejabberd_config:get_local_option( - {domain_certfile, StateData#state.server}) of + {domain_certfile, ServerString}) of undefined -> StateData#state.tls_options; CertFile -> @@ -619,7 +640,7 @@ wait_for_sasl_response({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, streamid = new_id(), authenticated = true, auth_module = AuthModule, - user = U}); + user = list_to_binary(U)}); {continue, ServerOut, NewSASLState} -> send_element(StateData, exmpp_server_sasl:challenge(ServerOut)), @@ -662,18 +683,17 @@ wait_for_sasl_response(closed, StateData) -> wait_for_bind({xmlstreamelement, El}, StateData) -> try - U = StateData#state.user, R = case exmpp_server_binding:wished_resource(El) of undefined -> lists:concat([randoms:get_string() | tuple_to_list(now())]); Resource -> Resource end, - JID = exmpp_jid:make_jid(U, StateData#state.server, R), + JID = exmpp_jid:make_jid(StateData#state.user, StateData#state.server, R), Res = exmpp_server_binding:bind(El, JID), send_element(StateData, Res), fsm_next_state(wait_for_session, - StateData#state{resource = R, jid = JID}) + StateData#state{resource = exmpp_jid:resource(JID), jid = JID}) catch throw:{stringprep, resourceprep, _, _} -> Err = exmpp_server_binding:error(El, 'bad-request'), @@ -702,11 +722,10 @@ wait_for_bind(closed, StateData) -> wait_for_session({xmlstreamelement, El}, StateData) -> try - U = StateData#state.user, - R = StateData#state.resource, + ServerString = binary_to_list(StateData#state.server), JID = StateData#state.jid, true = exmpp_server_session:want_establishment(El), - case acl:match_rule(StateData#state.server, + case acl:match_rule(ServerString, StateData#state.access, JID) of allow -> ?INFO_MSG("(~w) Opened session for ~s", @@ -717,7 +736,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> Info = [{ip, StateData#state.ip}, {conn, Conn}, {auth_module, StateData#state.auth_module}], ejabberd_sm:open_session( - SID, U, StateData#state.server, R, Info), + SID, JID, Info), Res = exmpp_server_session:establish(El), send_element(StateData, Res), change_shaper(StateData, JID), @@ -725,7 +744,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> roster_get_subscription_lists, StateData#state.server, {[], []}, - [U, StateData#state.server]), + [StateData#state.user, StateData#state.server]), LJID = jlib:short_prepd_bare_jid(JID), Fs1 = [LJID | Fs], Ts1 = [LJID | Ts], @@ -733,9 +752,11 @@ wait_for_session({xmlstreamelement, El}, StateData) -> ejabberd_hooks:run_fold( privacy_get_user_list, StateData#state.server, #userlist{}, - [U, StateData#state.server]), + [StateData#state.user, StateData#state.server]), fsm_next_state(session_established, StateData#state{ + sasl_state = 'undefined', + %not used anymore, let the GC work. sid = SID, conn = Conn, pres_f = ?SETS:from_list(Fs1), @@ -773,15 +794,13 @@ wait_for_session(closed, StateData) -> session_established({xmlstreamelement, El}, StateData) -> - FromJID = StateData#state.jid, - % Check 'from' attribute in stanza RFC 3920 Section 9.1.2 - case check_from(El, FromJID) of - 'invalid-from' -> - send_element(StateData, exmpp_stream:error('invalid-from')), - send_element(StateData, exmpp_stream:closing()), - {stop, normal, StateData}; - _NewEl -> - session_established2(El, StateData) + case check_from(El, StateData#state.jid) of + 'invalid-from' -> + send_element(StateData, exmpp_stream:error('invalid-from')), + send_element(StateData, exmpp_stream:closing()), + {stop, normal, StateData}; + _ -> + session_established2(El, StateData) end; %% We hibernate the process to reduce memory consumption after a @@ -810,11 +829,13 @@ session_established2(El, StateData) -> try User = StateData#state.user, Server = StateData#state.server, + + % TODO: check 'from' attribute in stanza FromJID = StateData#state.jid, To = exmpp_stanza:get_recipient(El), ToJID = case To of undefined -> - exmpp_jid:make_bare_jid(User, Server); + exmpp_jid:jid_to_bare_jid(StateData#state.jid); _ -> exmpp_jid:list_to_jid(To) end, @@ -839,10 +860,10 @@ session_established2(El, StateData) -> user_send_packet, Server, [FromJID, ToJID, PresenceEl]), - case ToJID of - #jid{node = User, - domain = Server, - resource = undefined} -> + case {exmpp_jid:node(ToJID), + exmpp_jid:domain(ToJID), + exmpp_jid:resource(ToJID)} of + {User, Server,undefined} -> ?DEBUG("presence_update(~p,~n\t~p,~n\t~p)", [FromJID, PresenceEl, StateData]), presence_update(FromJID, PresenceEl, @@ -894,6 +915,7 @@ session_established2(El, StateData) -> fsm_next_state(session_established, StateData) end. + %%---------------------------------------------------------------------- %% Func: StateName/3 %% Returns: {next_state, NextStateName, NextStateData} | @@ -925,8 +947,12 @@ handle_event(_Event, StateName, StateData) -> %% {stop, Reason, NewStateData} | %% {stop, Reason, Reply, NewStateData} %%---------------------------------------------------------------------- +%TODO: for debug only +handle_sync_event(get_state,_From,StateName,StateData) -> + {reply,{StateName, StateData}, StateName, StateData}; + handle_sync_event({get_presence}, _From, StateName, StateData) -> - User = StateData#state.user, + User = binary_to_list(StateData#state.user), PresLast = StateData#state.pres_last, Show = case PresLast of @@ -937,14 +963,35 @@ handle_sync_event({get_presence}, _From, StateName, StateData) -> undefined -> ""; _ -> exmpp_presence:get_status(PresLast) end, - Resource = StateData#state.resource, + Resource = binary_to_list(StateData#state.resource), Reply = {User, Resource, atom_to_list(Show), Status}, fsm_reply(Reply, StateName, StateData); handle_sync_event(get_subscribed, _From, StateName, StateData) -> - Subscribed = ?SETS:to_list(StateData#state.pres_f), - {reply, Subscribed, StateName, StateData}; + Subscribed = StateData#state.pres_f, + Online = StateData#state.pres_available, + Pred = fun({U, S, _} = User, _Caps) -> + ?SETS:is_element({U, S, undefined}, + Subscribed) orelse + ?SETS:is_element(User, Subscribed) + end, + SubscribedAndOnline = ?DICT:filter(Pred, Online), + SubscribedWithCaps = ?SETS:fold(fun(User, Acc) -> + [{User, undefined}|Acc] + end, ?DICT:to_list(SubscribedAndOnline), Subscribed), + {reply, SubscribedWithCaps, StateName, StateData}; + +handle_sync_event(get_subscribed_and_online, _From, StateName, StateData) -> + Subscribed = StateData#state.pres_f, + Online = StateData#state.pres_available, + Pred = fun({U, S, _R} = User, _Caps) -> + ?SETS:is_element({U, S, undefined}, + Subscribed) orelse + ?SETS:is_element(User, Subscribed) + end, + SubscribedAndOnline = ?DICT:filter(Pred, Online), + {reply, ?DICT:to_list(SubscribedAndOnline), StateName, StateData}; handle_sync_event(_Event, _From, StateName, StateData) -> Reply = ok, @@ -1036,39 +1083,44 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> LFrom = jlib:short_prepd_jid(From), LBFrom = jlib:short_prepd_bare_jid(From), %% Note contact availability - case exmpp_presence:get_type(Packet) of - 'unavailable' -> - mod_caps:clear_caps(From); - _ -> - Caps = mod_caps:read_caps(Packet#xmlel.children), - mod_caps:note_caps(StateData#state.server, From, Caps) - end, + Els = Packet#xmlel.children, + Caps = mod_caps:read_caps(Els), + ServerString = binary_to_list(StateData#state.server), + mod_caps:note_caps(ServerString, From, Caps), + NewAvailable = case exmpp_presence:get_type(Packet) of + 'unavailable' -> + ?DICT:erase(LFrom, StateData#state.pres_available); + _ -> + %?DICT:store(LFrom, Caps, StateData#state.pres_available) + StateData#state.pres_available + end, + NewStateData = StateData#state{pres_available = NewAvailable}, case ?SETS:is_element( - LFrom, StateData#state.pres_a) orelse + LFrom, NewStateData#state.pres_a) orelse ?SETS:is_element( - LBFrom, StateData#state.pres_a) of + LBFrom, NewStateData#state.pres_a) of true -> - {true, Attrs, StateData}; + {true, Attrs, NewStateData}; false -> case ?SETS:is_element( - LFrom, StateData#state.pres_f) of + LFrom, NewStateData#state.pres_f) of true -> A = ?SETS:add_element( LFrom, - StateData#state.pres_a), + NewStateData#state.pres_a), {true, Attrs, - StateData#state{pres_a = A}}; + NewStateData#state{pres_a = A}}; false -> case ?SETS:is_element( - LBFrom, StateData#state.pres_f) of + LBFrom, NewStateData#state.pres_f) of true -> A = ?SETS:add_element( LBFrom, - StateData#state.pres_a), + NewStateData#state.pres_a), {true, Attrs, - StateData#state{pres_a = A}}; + NewStateData#state{pres_a = A}}; false -> - {true, Attrs, StateData} + {true, Attrs, NewStateData} end end end; @@ -1080,7 +1132,9 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> ?DEBUG("broadcast~n~p~n", [Packet#xmlel.children]), case Packet#xmlel.children of [{item, {U, S, R} = _IJIDShort, ISubscription}] -> - IJID = exmpp_jid:make_jid(U, S, R), + IJID = exmpp_jid:make_jid(U, + S, + R), {false, Attrs, roster_change(IJID, ISubscription, StateData)}; @@ -1108,7 +1162,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> true -> case exmpp_iq:get_request(Packet) of #xmlel{ns = ?NS_VCARD} -> - Host = StateData#state.server, + Host = binary_to_list(StateData#state.server), case ets:lookup(sm_iqtable, {?NS_VCARD, Host}) of [{_, Module, Function, Opts}] -> gen_iq_handler:handle(Host, Module, Function, Opts, @@ -1186,6 +1240,7 @@ handle_info(Info, StateName, StateData) -> %% Returns: any %%---------------------------------------------------------------------- terminate(_Reason, StateName, StateData) -> + %%TODO: resource could be 'undefined' if terminate before bind? case StateName of session_established -> case StateData#state.authenticated of @@ -1199,9 +1254,7 @@ terminate(_Reason, StateName, StateData) -> "Replaced by new connection"), ejabberd_sm:close_session_unset_presence( StateData#state.sid, - StateData#state.user, - StateData#state.server, - StateData#state.resource, + StateData#state.jid, "Replaced by new connection"), presence_broadcast( StateData, From, StateData#state.pres_a, Packet1), @@ -1219,17 +1272,13 @@ terminate(_Reason, StateName, StateData) -> pres_i = EmptySet, pres_invis = false} -> ejabberd_sm:close_session(StateData#state.sid, - StateData#state.user, - StateData#state.server, - StateData#state.resource); + StateData#state.jid); _ -> From = StateData#state.jid, Packet = exmpp_presence:unavailable(), ejabberd_sm:close_session_unset_presence( StateData#state.sid, - StateData#state.user, - StateData#state.server, - StateData#state.resource, + StateData#state.jid, ""), presence_broadcast( StateData, From, StateData#state.pres_a, Packet), @@ -1248,7 +1297,7 @@ terminate(_Reason, StateName, StateData) -> %%%---------------------------------------------------------------------- change_shaper(StateData, JID) -> - Shaper = acl:match_rule(StateData#state.server, + Shaper = acl:match_rule(binary_to_list(StateData#state.server), StateData#state.shaper, JID), (StateData#state.sockmod):change_shaper(StateData#state.socket, Shaper). @@ -1257,9 +1306,9 @@ send_text(StateData, Text) -> (StateData#state.sockmod):send(StateData#state.socket, Text). send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> - send_text(StateData, exmpp_stream:to_list(El)); + send_text(StateData, exmpp_stream:to_iolist(El)); send_element(StateData, El) -> - send_text(StateData, exmpp_stanza:to_list(El)). + send_text(StateData, exmpp_stanza:to_iolist(El)). new_id() -> @@ -1372,9 +1421,7 @@ presence_update(From, Packet, StateData) -> Info = [{ip, StateData#state.ip}, {conn, StateData#state.conn}, {auth_module, StateData#state.auth_module}], ejabberd_sm:unset_presence(StateData#state.sid, - StateData#state.user, - StateData#state.server, - StateData#state.resource, + StateData#state.jid, Status, Info), presence_broadcast(StateData, From, StateData#state.pres_a, Packet), @@ -1476,8 +1523,6 @@ presence_update(From, Packet, StateData) -> presence_track(From, To, Packet, StateData) -> LTo = jlib:short_prepd_jid(To), - User = StateData#state.user, - Server = StateData#state.server, BFrom = exmpp_jid:jid_to_bare_jid(From), case exmpp_presence:get_type(Packet) of 'unavailable' -> @@ -1494,26 +1539,26 @@ presence_track(From, To, Packet, StateData) -> pres_a = A}; 'subscribe' -> ejabberd_hooks:run(roster_out_subscription, - Server, - [User, Server, To, subscribe]), + StateData#state.server, + [StateData#state.user, StateData#state.server, To, subscribe]), ejabberd_router:route(BFrom, To, Packet), StateData; 'subscribed' -> ejabberd_hooks:run(roster_out_subscription, - Server, - [User, Server, To, subscribed]), + StateData#state.server, + [StateData#state.user, StateData#state.server, To, subscribed]), ejabberd_router:route(BFrom, To, Packet), StateData; 'unsubscribe' -> ejabberd_hooks:run(roster_out_subscription, - Server, - [User, Server, To, unsubscribe]), + StateData#state.server, + [StateData#state.user, StateData#state.server, To, unsubscribe]), ejabberd_router:route(BFrom, To, Packet), StateData; 'unsubscribed' -> ejabberd_hooks:run(roster_out_subscription, - Server, - [User, Server, To, unsubscribed]), + StateData#state.server, + [StateData#state.user, StateData#state.server, To, unsubscribed]), ejabberd_router:route(BFrom, To, Packet), StateData; 'error' -> @@ -1718,9 +1763,7 @@ update_priority(Priority, Packet, StateData) -> Info = [{ip, StateData#state.ip}, {conn, StateData#state.conn}, {auth_module, StateData#state.auth_module}], ejabberd_sm:set_presence(StateData#state.sid, - StateData#state.user, - StateData#state.server, - StateData#state.resource, + StateData#state.jid, Priority, Packet, Info). @@ -1732,7 +1775,7 @@ process_privacy_iq(From, To, case Type of get -> R = ejabberd_hooks:run_fold( - privacy_iq_get, StateData#state.server, + privacy_iq_get, StateData#state.server , {error, ?ERR_FEATURE_NOT_IMPLEMENTED(IQ_NS)}, [From, To, IQ_Rec, StateData#state.privacy_list]), {R, StateData}; @@ -1761,22 +1804,23 @@ process_privacy_iq(From, To, NewStateData. -resend_offline_messages(#state{user = User, - server = Server, +resend_offline_messages(#state{user = UserB, + server = ServerB, privacy_list = PrivList} = StateData) -> + case ejabberd_hooks:run_fold(resend_offline_messages_hook, - Server, + StateData#state.server, [], - [User, Server]) of + [UserB, ServerB]) of Rs when list(Rs) -> lists:foreach( fun({route, From, To, Packet}) -> Pass = case ejabberd_hooks:run_fold( - privacy_check_packet, Server, + privacy_check_packet, StateData#state.server, allow, - [User, - Server, + [StateData#state.user, + StateData#state.server, PrivList, {From, To, Packet}, in]) of @@ -1799,13 +1843,13 @@ resend_offline_messages(#state{user = User, end, Rs) end. -resend_subscription_requests(#state{user = User, - server = Server} = StateData) -> +resend_subscription_requests(#state{user = UserB, + server = ServerB} = StateData) -> PendingSubscriptions = ejabberd_hooks:run_fold( resend_subscription_requests_hook, - Server, + StateData#state.server, [], - [User, Server]), + [UserB, ServerB]), lists:foreach(fun(XMLPacket) -> send_element(StateData, XMLPacket) @@ -1813,6 +1857,7 @@ resend_subscription_requests(#state{user = User, PendingSubscriptions). process_unauthenticated_stanza(StateData, El) when ?IS_IQ(El) -> + ServerString = binary_to_list(StateData#state.server), case exmpp_iq:get_kind(El) of request -> IQ_Rec = exmpp_iq:xmlel_to_iq(El), @@ -1828,7 +1873,7 @@ process_unauthenticated_stanza(StateData, El) when ?IS_IQ(El) -> ResIQ = exmpp_iq:error_without_original(El, 'service-unavailable'), Res1 = exmpp_stanza:set_sender(ResIQ, - exmpp_jid:make_bare_jid(StateData#state.server)), + exmpp_jid:make_bare_jid(ServerString)), Res2 = exmpp_stanza:remove_recipient(Res1), send_element(StateData, Res2); _ -> diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl index 0609e20d4..d317c6a87 100644 --- a/src/ejabberd_hooks.erl +++ b/src/ejabberd_hooks.erl @@ -61,19 +61,21 @@ start_link() -> add(Hook, Module, Function, Seq) -> add(Hook, global, Module, Function, Seq). -add(Hook, Host, Module, Function, Seq) -> +add(Hook, Host, Module, Function, Seq) + when is_binary(Host) orelse is_atom(Host) -> gen_server:call(ejabberd_hooks, {add, Hook, Host, Module, Function, Seq}). delete(Hook, Module, Function, Seq) -> delete(Hook, global, Module, Function, Seq). -delete(Hook, Host, Module, Function, Seq) -> +delete(Hook, Host, Module, Function, Seq) + when is_binary(Host) orelse is_atom(Host) -> gen_server:call(ejabberd_hooks, {delete, Hook, Host, Module, Function, Seq}). run(Hook, Args) -> run(Hook, global, Args). -run(Hook, Host, Args) -> +run(Hook, Host, Args) when is_binary(Host) orelse is_atom(Host) -> case ets:lookup(hooks, {Hook, Host}) of [{_, Ls}] -> run1(Ls, Hook, Args); @@ -84,7 +86,7 @@ run(Hook, Host, Args) -> run_fold(Hook, Val, Args) -> run_fold(Hook, global, Val, Args). -run_fold(Hook, Host, Val, Args) -> +run_fold(Hook, Host, Val, Args) when is_binary(Host) orelse is_atom(Host) -> case ets:lookup(hooks, {Hook, Host}) of [{_, Ls}] -> run_fold1(Ls, Hook, Val, Args); diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 96118c457..32d503ce2 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -76,7 +76,7 @@ start_link() -> process_iq(From, To, Packet) -> case exmpp_iq:xmlel_to_iq(Packet) of #iq{kind = request, ns = XMLNS} = IQ_Rec -> - Host = To#jid.ldomain, + Host = exmpp_jid:ldomain_as_list(To), case ets:lookup(?IQTABLE, {XMLNS, Host}) of [{_, Module, Function}] -> ResIQ = Module:Function(From, To, IQ_Rec), @@ -182,7 +182,7 @@ init([]) -> lists:foreach( fun(Host) -> ejabberd_router:register_route(Host, {apply, ?MODULE, route}), - ejabberd_hooks:add(local_send_to_resource_hook, Host, + ejabberd_hooks:add(local_send_to_resource_hook, list_to_binary(Host), ?MODULE, bounce_resource_packet, 100) end, ?MYHOSTS), catch ets:new(?IQTABLE, [named_table, public]), @@ -302,10 +302,13 @@ code_change(_OldVsn, State, _Extra) -> do_route(From, To, Packet) -> ?DEBUG("local route~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n", [From, To, Packet, 8]), + + LNode = exmpp_jid:lnode(To), + LResource = exmpp_jid:lresource(To), if - To#jid.lnode /= undefined -> + LNode /= undefined -> ejabberd_sm:route(From, To, Packet); - To#jid.lresource == undefined -> + LResource == undefined -> case Packet of _ when ?IS_IQ(Packet) -> process_iq(From, To, Packet); @@ -322,7 +325,7 @@ do_route(From, To, Packet) -> "result" -> ok; _ -> ejabberd_hooks:run(local_send_to_resource_hook, - To#jid.ldomain, + exmpp_jid:ldomain(To), [From, To, Packet]) end end. diff --git a/src/ejabberd_receiver.erl b/src/ejabberd_receiver.erl index e6d56734c..7386fed07 100644 --- a/src/ejabberd_receiver.erl +++ b/src/ejabberd_receiver.erl @@ -134,13 +134,14 @@ init([Socket, SockMod, Shaper, MaxStanzaSize]) -> %%-------------------------------------------------------------------- handle_call({starttls, TLSSocket}, _From, #state{xml_stream_state = XMLStreamState} = State) -> - NewXMLStreamState = exmpp_xmlstream:reset(XMLStreamState), + NewXMLStreamState = do_reset_stream(XMLStreamState), NewState = State#state{socket = TLSSocket, sock_mod = tls, xml_stream_state = NewXMLStreamState}, case tls:recv_data(TLSSocket, "") of {ok, TLSData} -> - {reply, ok, process_data(TLSData, NewState), ?HIBERNATE_TIMEOUT}; + {NextState, Hib} = process_data(TLSData, NewState), + {reply, ok, NextState, Hib}; {error, _Reason} -> {stop, normal, ok, NewState} end; @@ -152,7 +153,8 @@ handle_call({compress, ZlibSocket}, _From, xml_stream_state = NewXMLStreamState}, case ejabberd_zlib:recv_data(ZlibSocket, "") of {ok, ZlibData} -> - {reply, ok, process_data(ZlibData, NewState), ?HIBERNATE_TIMEOUT}; + {NextState, Hib} = process_data(ZlibData, NewState), + {reply, ok, NextState, Hib}; {error, _Reason} -> {stop, normal, ok, NewState} end; @@ -164,7 +166,10 @@ handle_call(reset_stream, _From, ?HIBERNATE_TIMEOUT}; handle_call({become_controller, C2SPid}, _From, State) -> Parser = exmpp_xml:start_parser([ - names_as_atom, + {names_as_atom, true}, + {check_nss, xmpp}, + {check_elems, xmpp}, + {check_attrs, xmpp}, {max_size, State#state.max_stanza_size} ]), XMLStreamState = exmpp_xmlstream:start( @@ -208,21 +213,22 @@ handle_info({Tag, _TCPSocket, Data}, tls -> case tls:recv_data(Socket, Data) of {ok, TLSData} -> - {noreply, process_data(TLSData, State), - ?HIBERNATE_TIMEOUT}; + {NextState, Hib} = process_data(TLSData, State), + {noreply, NextState, Hib}; {error, _Reason} -> {stop, normal, State} end; ejabberd_zlib -> case ejabberd_zlib:recv_data(Socket, Data) of {ok, ZlibData} -> - {noreply, process_data(ZlibData, State), - ?HIBERNATE_TIMEOUT}; + {NextState, Hib} = process_data(ZlibData, State), + {noreply, NextState, Hib}; {error, _Reason} -> {stop, normal, State} end; _ -> - {noreply, process_data(Data, State), ?HIBERNATE_TIMEOUT} + {NextState, Hib} = process_data(Data, State), + {noreply, NextState, Hib} end; handle_info({Tag, _TCPSocket}, State) when (Tag == tcp_closed) or (Tag == ssl_closed) -> @@ -239,8 +245,8 @@ handle_info({timeout, _Ref, activate}, State) -> activate_socket(State), {noreply, State, ?HIBERNATE_TIMEOUT}; handle_info(timeout, State) -> - proc_lib:hibernate(gen_server, enter_loop, [?MODULE, [], State]), - {noreply, State, ?HIBERNATE_TIMEOUT}; + {noreply, State, hibernate}; + handle_info(_Info, State) -> {noreply, State, ?HIBERNATE_TIMEOUT}. @@ -299,19 +305,30 @@ process_data(Data, ?DEBUG("Received XML on stream = ~p", [binary_to_list(Data)]), {ok, XMLStreamState1} = exmpp_xmlstream:parse(XMLStreamState, Data), {NewShaperState, Pause} = shaper:update(ShaperState, size(Data)), - if - C2SPid == undefined -> - ok; - Pause > 0 -> - erlang:start_timer(Pause, self(), activate); - true -> - activate_socket(State) - end, - State#state{xml_stream_state = XMLStreamState1, - shaper_state = NewShaperState}. + HibTimeout = + if + C2SPid == undefined -> + infinity; + Pause > 0 -> + erlang:start_timer(Pause, self(), activate), + hibernate; + + true -> + activate_socket(State), + ?HIBERNATE_TIMEOUT + end, + {State#state{xml_stream_state = XMLStreamState1, + shaper_state = NewShaperState}, HibTimeout}. close_stream(undefined) -> ok; close_stream(XMLStreamState) -> exmpp_xml:stop_parser(exmpp_xmlstream:get_parser(XMLStreamState)), exmpp_xmlstream:stop(XMLStreamState). + + +do_reset_stream(undefined) -> + undefined; + +do_reset_stream(XMLStreamState) -> + exmpp_xmlstream:reset(XMLStreamState). diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index b3f387e72..5d39e9924 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -89,27 +89,28 @@ register_route(Domain) -> register_route(Domain, LocalHint) -> try LDomain = exmpp_stringprep:nameprep(Domain), + LDomainB = list_to_binary(LDomain), Pid = self(), case get_component_number(LDomain) of undefined -> F = fun() -> - mnesia:write(#route{domain = LDomain, + mnesia:write(#route{domain = LDomainB, pid = Pid, local_hint = LocalHint}) end, mnesia:transaction(F); N -> F = fun() -> - case mnesia:read({route, LDomain}) of + case mnesia:read({route, LDomainB}) of [] -> mnesia:write( - #route{domain = LDomain, + #route{domain = LDomainB, pid = Pid, local_hint = 1}), lists:foreach( fun(I) -> mnesia:write( - #route{domain = LDomain, + #route{domain = LDomainB, pid = undefined, local_hint = I}) end, lists:seq(2, N)); @@ -118,7 +119,7 @@ register_route(Domain, LocalHint) -> fun(#route{pid = undefined, local_hint = I} = R) -> mnesia:write( - #route{domain = LDomain, + #route{domain = LDomainB, pid = Pid, local_hint = I}), mnesia:delete_object(R), @@ -143,12 +144,13 @@ register_routes(Domains) -> unregister_route(Domain) -> try LDomain = exmpp_stringprep:nameprep(Domain), + LDomainB = list_to_binary(LDomain), Pid = self(), case get_component_number(LDomain) of undefined -> F = fun() -> case mnesia:match_object( - #route{domain = LDomain, + #route{domain = LDomainB, pid = Pid, _ = '_'}) of [R] -> @@ -160,13 +162,13 @@ unregister_route(Domain) -> mnesia:transaction(F); _ -> F = fun() -> - case mnesia:match_object(#route{domain=LDomain, + case mnesia:match_object(#route{domain=LDomainB, pid = Pid, _ = '_'}) of [R] -> I = R#route.local_hint, mnesia:write( - #route{domain = LDomain, + #route{domain = LDomainB, pid = undefined, local_hint = I}), mnesia:delete_object(R); @@ -188,10 +190,14 @@ unregister_routes(Domains) -> dirty_get_all_routes() -> - lists:usort(mnesia:dirty_all_keys(route)) -- ?MYHOSTS. + lists:usort( + lists:map(fun erlang:binary_to_list/1, + mnesia:dirty_all_keys(route))) -- ?MYHOSTS. dirty_get_all_domains() -> - lists:usort(mnesia:dirty_all_keys(route)). + lists:usort( + lists:map(fun erlang:binary_to_list/1, + mnesia:dirty_all_keys(route))). %%==================================================================== @@ -326,8 +332,8 @@ do_route(OrigFrom, OrigTo, OrigPacket) -> case ejabberd_hooks:run_fold(filter_packet, {OrigFrom, OrigTo, OrigPacket}, []) of {From, To, Packet} -> - LDstDomain = To#jid.ldomain, - case mnesia:dirty_read(route, LDstDomain) of + LDomain = exmpp_jid:ldomain(To), + case mnesia:dirty_read(route, LDomain) of [] -> ejabberd_s2s:route(From, To, Packet); [R] -> @@ -346,6 +352,7 @@ do_route(OrigFrom, OrigTo, OrigPacket) -> drop end; Rs -> + LDstDomain = exmpp_jid:ldomain_as_list(To), Value = case ejabberd_config:get_local_option( {domain_balancing, LDstDomain}) of undefined -> now(); diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index 0806ffe5a..2cdbfa897 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -281,7 +281,7 @@ do_route(From, To, Packet) -> ?DEBUG("sending to process ~p~n", [Pid]), NewPacket1 = exmpp_stanza:set_sender(Packet, From), NewPacket = exmpp_stanza:set_recipient(NewPacket1, To), - #jid{ldomain = MyServer} = From, + MyServer = exmpp_jid:ldomain(From), ejabberd_hooks:run( s2s_send_packet, MyServer, @@ -301,8 +301,8 @@ do_route(From, To, Packet) -> end. find_connection(From, To) -> - #jid{ldomain = MyServer} = From, - #jid{ldomain = Server} = To, + MyServer = exmpp_jid:ldomain_as_list(From), + Server = exmpp_jid:ldomain_as_list(To), FromTo = {MyServer, Server}, MaxS2SConnectionsNumber = max_s2s_connections_number(FromTo), MaxS2SConnectionsNumberPerNode = @@ -430,12 +430,12 @@ needed_connections_number(Ls, MaxS2SConnectionsNumber, %% service. %% -------------------------------------------------------------------- is_service(From, To) -> - LFromDomain = From#jid.ldomain, + LFromDomain = exmpp_jid:ldomain_as_list(From), case ejabberd_config:get_local_option({route_subdomains, LFromDomain}) of s2s -> % bypass RFC 3920 10.3 false; _ -> - LDstDomain = To#jid.ldomain, + LDstDomain = exmpp_jid:ldomain_as_list(To), P = fun(Domain) -> is_subdomain(LDstDomain, Domain) end, lists:any(P, ?MYHOSTS) end. diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 29bd85bdf..2092415ba 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -390,8 +390,8 @@ stream_established({xmlstreamelement, El}, StateData) -> % This is handled by C2S and S2S send_element functions. if (To /= error) and (From /= error) -> - LFrom = From#jid.ldomain, - LTo = To#jid.ldomain, + LFrom = exmpp_jid:ldomain_as_list(From), + LTo = exmpp_jid:ldomain_as_list(To), if StateData#state.authenticated -> case (LFrom == StateData#state.auth_domain) @@ -406,7 +406,7 @@ stream_established({xmlstreamelement, El}, StateData) -> (Name == 'presence')) -> ejabberd_hooks:run( s2s_receive_packet, - LFrom, + exmpp_jid:ldomain(From), [From, To, El]), ejabberd_router:route( From, To, El); @@ -426,7 +426,7 @@ stream_established({xmlstreamelement, El}, StateData) -> (Name == 'presence')) -> ejabberd_hooks:run( s2s_receive_packet, - LFrom, + exmpp_jid:ldomain(From), [From, To, El]), ejabberd_router:route( From, To, El); @@ -612,10 +612,11 @@ get_cert_domains(Cert) -> end, if D /= error -> - case exmpp_jid:list_to_jid(D) of - #jid{lnode = undefined, - ldomain = LD, - lresource = undefined} -> + JID = exmpp_jid:list_to_jid(D), + case {exmpp_jid:lnode_as_list(JID), + exmpp_jid:ldomain_as_list(JID), + exmpp_jid:lresource_as_list(JID)} of + {undefined, LD, undefined} -> [LD]; _ -> [] @@ -647,11 +648,11 @@ get_cert_domains(Cert) -> case 'XmppAddr':decode( 'XmppAddr', XmppAddr) of {ok, D} when is_binary(D) -> - case exmpp_jid:list_to_jid( - binary_to_list(D)) of - #jid{lnode = undefined, - ldomain = LD, - lresource = undefined} -> + JID2 = exmpp_jid:list_to_jid(binary_to_list(D)), + case {exmpp_jid:lnode_as_list(JID2), + exmpp_jid:ldomain_as_list(JID2), + exmpp_jid:lresource_as_list(JID2)} of + { undefined, LD, undefined} -> case idna:domain_utf8_to_ascii(LD) of false -> []; @@ -665,10 +666,11 @@ get_cert_domains(Cert) -> [] end; ({dNSName, D}) when is_list(D) -> - case exmpp_jid:list_to_jid(D) of - #jid{lnode = undefined, - ldomain = LD, - lresource = undefined} -> + JID3 = exmpp_jid:list_to_jid(D), + case {exmpp_jid:lnode_as_list(JID3), + exmpp_jid:ldomain_as_list(JID3), + exmpp_jid:lresource_as_list(JID3)} of + {undefined, LD, undefined} -> [LD]; _ -> [] diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 8f16a6f6e..3a819c130 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -231,14 +231,11 @@ stream_established({xmlstreamelement, El}, StateData) -> %% The default is the standard behaviour in XEP-0114 _ -> FromJID1 = exmpp_jib:string_to_jid(From), - case FromJID1 of - #jid{ldomain = Server} -> - case lists:member(Server, StateData#state.hosts) of + Server = exmpp_jid:ldomain_as_list(FromJID1), + case lists:member(Server, StateData#state.hosts) of true -> FromJID1; false -> error - end; - _ -> error - end + end end, To = exmpp_stanza:get_recipient(El), ToJID = case To of diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index f4f1b0923..33ea18656 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -32,14 +32,14 @@ %% API -export([start_link/0, route/3, - open_session/5, close_session/4, + open_session/3, close_session/2, check_in_subscription/6, bounce_offline_message/3, disconnect_removed_user/2, get_user_resources/2, - set_presence/7, - unset_presence/6, - close_session_unset_presence/5, + set_presence/5, + unset_presence/4, + close_session_unset_presence/3, dirty_get_sessions_list/0, dirty_get_my_sessions_list/0, get_vh_session_list/1, @@ -49,9 +49,9 @@ connected_users/0, connected_users_number/0, user_resources/2, - get_session_pid/3, + get_session_pid/1, get_user_info/3, - get_user_ip/3 + get_user_ip/1 ]). %% gen_server callbacks @@ -76,6 +76,9 @@ {?NS_XMPP, ?NS_XMPP_pfx}, {?NS_DIALBACK, ?NS_DIALBACK_pfx} ]). + +-define(IS_BINARY_OR_UNDEF(X), + (is_binary(X) orelse X == 'undefined')). %%==================================================================== %% API %%==================================================================== @@ -105,14 +108,13 @@ route(From, To, Packet) -> ok end. -open_session(SID, User, Server, Resource, Info) -> - set_session(SID, User, Server, Resource, undefined, Info), - check_for_sessions_to_replace(User, Server, Resource), - JID = exmpp_jid:make_jid(User, Server, Resource), - ejabberd_hooks:run(sm_register_connection_hook, JID#jid.ldomain, +open_session(SID, JID, Info) when ?IS_JID(JID) -> + set_session(SID, JID, undefined, Info), + check_for_sessions_to_replace(JID), + ejabberd_hooks:run(sm_register_connection_hook, exmpp_jid:ldomain(JID), [SID, JID, Info]). -close_session(SID, User, Server, Resource) -> +close_session(SID, JID ) when ?IS_JID(JID)-> Info = case mnesia:dirty_read({session, SID}) of [] -> []; [#session{info=I}] -> I @@ -121,12 +123,12 @@ close_session(SID, User, Server, Resource) -> mnesia:delete({session, SID}) end, mnesia:sync_dirty(F), - JID = exmpp_jid:make_jid(User, Server, Resource), - ejabberd_hooks:run(sm_remove_connection_hook, JID#jid.ldomain, + ejabberd_hooks:run(sm_remove_connection_hook, exmpp_jid:ldomain(JID), [SID, JID, Info]). -check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) -> - case ejabberd_auth:is_user_exists(User, Server) of +check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) + when is_binary(User), is_binary(Server)-> + case ejabberd_auth:is_user_exists(binary_to_list(User), binary_to_list(Server)) of true -> Acc; false -> @@ -139,27 +141,26 @@ bounce_offline_message(From, To, Packet) -> stop. disconnect_removed_user(User, Server) -> - ejabberd_sm:route(#jid{}, - exmpp_jid:make_bare_jid(User, Server), + ejabberd_sm:route(exmpp_jid:make_jid(), + exmpp_jid:make_bare_jid(User, + Server), #xmlel{name = 'broadcast', children = [{exit, "User removed"}]}). -get_user_resources(User, Server) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - US = {LUser, LServer}, +get_user_resources(User, Server) + when is_binary(User), is_binary(Server) -> + US = {User, Server}, case catch mnesia:dirty_index_read(session, US, #session.us) of {'EXIT', _Reason} -> []; Ss -> - [element(3, S#session.usr) || S <- clean_session_list(Ss)] + [binary_to_list(element(3, S#session.usr)) || S <- clean_session_list(Ss)] end. -get_user_ip(User, Server, Resource) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - LResource = exmpp_stringprep:resourceprep(Resource), - USR = {LUser, LServer, LResource}, +get_user_ip(JID) when ?IS_JID(JID) -> + USR = {exmpp_jid:lnode(JID), + exmpp_jid:ldomain(JID), + exmpp_jid:lresource(JID)}, case mnesia:dirty_index_read(session, USR, #session.usr) of [] -> undefined; @@ -168,11 +169,16 @@ get_user_ip(User, Server, Resource) -> proplists:get_value(ip, Session#session.info) end. -get_user_info(User, Server, Resource) -> +get_user_info(User, Server, Resource) + when is_binary(User), + is_binary(Server), + is_binary(Resource) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), LResource = exmpp_stringprep:resourceprep(Resource), - USR = {LUser, LServer, LResource}, + USR = {list_to_binary(LUser), + list_to_binary(LServer), + list_to_binary(LResource)}, case mnesia:dirty_index_read(session, USR, #session.usr) of [] -> offline; @@ -184,26 +190,37 @@ get_user_info(User, Server, Resource) -> [{node, Node}, {conn, Conn}, {ip, IP}] end. -set_presence(SID, User, Server, Resource, Priority, Presence, Info) -> - set_session(SID, User, Server, Resource, Priority, Info), - ejabberd_hooks:run(set_presence_hook, exmpp_stringprep:nameprep(Server), - [User, Server, Resource, Presence]). +set_presence(SID, JID, Priority, Presence, Info) when ?IS_JID(JID) -> + set_session(SID, JID, Priority, Info), + ejabberd_hooks:run(set_presence_hook, + exmpp_jid:ldomain(JID), + [exmpp_jid:lnode(JID), + exmpp_jid:ldomain(JID), + exmpp_jid:lresource(JID), + Presence]). -unset_presence(SID, User, Server, Resource, Status, Info) -> - set_session(SID, User, Server, Resource, undefined, Info), - ejabberd_hooks:run(unset_presence_hook, exmpp_stringprep:nameprep(Server), - [User, Server, Resource, Status]). +unset_presence(SID, JID, Status, Info) when ?IS_JID(JID)-> + set_session(SID, JID, undefined, Info), + ejabberd_hooks:run(unset_presence_hook, + exmpp_jid:ldomain(JID), + [exmpp_jid:lnode(JID), + exmpp_jid:ldomain(JID), + exmpp_jid:lresource(JID), + Status]). -close_session_unset_presence(SID, User, Server, Resource, Status) -> - close_session(SID, User, Server, Resource), - ejabberd_hooks:run(unset_presence_hook, exmpp_stringprep:nameprep(Server), - [User, Server, Resource, Status]). +close_session_unset_presence(SID, JID, Status) when ?IS_JID(JID) -> + close_session(SID, JID), + ejabberd_hooks:run(unset_presence_hook, + exmpp_jid:ldomain(JID), + [exmpp_jid:lnode(JID), + exmpp_jid:ldomain(JID), + exmpp_jid:lresource(JID), + Status]). -get_session_pid(User, Server, Resource) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - LResource = exmpp_stringprep:resourceprep(Resource), - USR = {LUser, LServer, LResource}, +get_session_pid(JID) when ?IS_JID(JID) -> + USR = {exmpp_jid:lnode(JID), + exmpp_jid:ldomain(JID), + exmpp_jid:lresource(JID)}, case catch mnesia:dirty_index_read(session, USR, #session.usr) of [#session{sid = {_, Pid}}] -> Pid; _ -> none @@ -223,8 +240,9 @@ dirty_get_my_sessions_list() -> [{'==', {node, '$1'}, node()}], ['$_']}]). -get_vh_session_list(Server) -> - LServer = exmpp_stringprep:nameprep(Server), +get_vh_session_list(Server) when is_binary(Server) -> + LServer = list_to_binary( + exmpp_stringprep:nameprep(Server)), mnesia:dirty_select( session, [{#session{usr = '$1', _ = '_'}, @@ -264,11 +282,12 @@ init([]) -> ets:new(sm_iqtable, [named_table]), lists:foreach( fun(Host) -> - ejabberd_hooks:add(roster_in_subscription, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:add(roster_in_subscription, HostB, ejabberd_sm, check_in_subscription, 20), - ejabberd_hooks:add(offline_message_hook, Host, + ejabberd_hooks:add(offline_message_hook, HostB, ejabberd_sm, bounce_offline_message, 100), - ejabberd_hooks:add(remove_user, Host, + ejabberd_hooks:add(remove_user, HostB, ejabberd_sm, disconnect_removed_user, 100) end, ?MYHOSTS), ejabberd_commands:register_commands(commands()), @@ -365,12 +384,11 @@ code_change(_OldVsn, State, _Extra) -> %%% Internal functions %%-------------------------------------------------------------------- -set_session(SID, User, Server, Resource, Priority, Info) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - LResource = exmpp_stringprep:resourceprep(Resource), - US = {LUser, LServer}, - USR = {LUser, LServer, LResource}, +set_session(SID, JID, Priority, Info) -> + US = {exmpp_jid:node(JID), exmpp_jid:ldomain(JID)}, + USR = {exmpp_jid:node(JID), + exmpp_jid:ldomain(JID), + exmpp_jid:lresource(JID)}, F = fun() -> mnesia:write(#session{sid = SID, usr = USR, @@ -398,9 +416,7 @@ clean_table_from_bad_node(Node) -> do_route(From, To, Packet) -> ?DEBUG("session manager~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n", [From, To, Packet, 8]), - #jid{node = User, domain = Server, - lnode = LUser, ldomain = LServer, lresource = LResource} = To, - case LResource of + case exmpp_jid:lresource(To) of undefined -> case Packet of _ when ?IS_PRESENCE(Packet) -> @@ -410,37 +426,37 @@ do_route(From, To, Packet) -> Reason = exmpp_presence:get_status(Packet), {ejabberd_hooks:run_fold( roster_in_subscription, - LServer, + exmpp_jid:ldomain(To), false, - [User, Server, From, subscribe, Reason]), + [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, subscribe, Reason]), true}; 'subscribed' -> {ejabberd_hooks:run_fold( roster_in_subscription, - LServer, + exmpp_jid:ldomain(To), false, - [User, Server, From, subscribed, <<>>]), + [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, subscribed, <<>>]), true}; 'unsubscribe' -> {ejabberd_hooks:run_fold( roster_in_subscription, - LServer, + exmpp_jid:ldomain(To), false, - [User, Server, From, unsubscribe, <<>>]), + [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, unsubscribe, <<>>]), true}; 'unsubscribed' -> {ejabberd_hooks:run_fold( roster_in_subscription, - LServer, + exmpp_jid:ldomain(To), false, - [User, Server, From, unsubscribed, <<>>]), + [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, unsubscribed, <<>>]), true}; _ -> {true, false} end, if Pass -> PResources = get_user_present_resources( - LUser, LServer), + exmpp_jid:lnode(To), exmpp_jid:ldomain(To)), lists:foreach( fun({_, R}) -> do_route( @@ -461,12 +477,15 @@ do_route(From, To, Packet) -> do_route(From, exmpp_jid:bare_jid_to_jid(To, R), Packet) - end, get_user_resources(User, Server)); + end, get_user_resources(exmpp_jid:lnode(To), + exmpp_jid:ldomain(To))); _ -> ok end; _ -> - USR = {LUser, LServer, LResource}, + USR = {exmpp_jid:lnode(To), + exmpp_jid:ldomain(To), + exmpp_jid:lresource(To)}, case mnesia:dirty_index_read(session, USR, #session.usr) of [] -> case Packet of @@ -494,8 +513,8 @@ do_route(From, To, Packet) -> end. route_message(From, To, Packet) -> - LUser = To#jid.lnode, - LServer = To#jid.ldomain, + LUser = exmpp_jid:lnode(To), + LServer = exmpp_jid:ldomain(To), PrioRes = get_user_present_resources(LUser, LServer), case catch lists:max(PrioRes) of {Priority, _R} when is_integer(Priority), Priority >= 0 -> @@ -503,8 +522,7 @@ route_message(From, To, Packet) -> %% Route messages to all priority that equals the max, if %% positive fun({P, R}) when P == Priority -> - LResource = exmpp_stringprep:resourceprep(R), - USR = {LUser, LServer, LResource}, + USR = {LUser, LServer, R}, case mnesia:dirty_index_read(session, USR, #session.usr) of [] -> ok; % Race condition @@ -528,10 +546,11 @@ route_message(From, To, Packet) -> 'headline' -> bounce_offline_message(From, To, Packet); _ -> - case ejabberd_auth:is_user_exists(LUser, LServer) of + case ejabberd_auth:is_user_exists(exmpp_jid:lnode_as_list(To), + exmpp_jid:ldomain_as_list(To)) of true -> ejabberd_hooks:run(offline_message_hook, - LServer, + exmpp_jid:ldomain(To), [From, To, Packet]); _ -> Err = exmpp_stanza:reply_with_error( @@ -580,18 +599,16 @@ get_user_present_resources(LUser, LServer) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% On new session, check if some existing connections need to be replace -check_for_sessions_to_replace(User, Server, Resource) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - LResource = exmpp_stringprep:resourceprep(Resource), - +check_for_sessions_to_replace(JID) -> %% TODO: Depending on how this is executed, there could be an unneeded %% replacement for max_sessions. We need to check this at some point. - check_existing_resources(LUser, LServer, LResource), - check_max_sessions(LUser, LServer). + check_existing_resources(JID), + check_max_sessions(JID). -check_existing_resources(LUser, LServer, LResource) -> - USR = {LUser, LServer, LResource}, +check_existing_resources(JID) -> + USR = {exmpp_jid:lnode(JID), + exmpp_jid:ldomain(JID), + exmpp_jid:lresource(JID)}, %% A connection exist with the same resource. We replace it: SIDs = mnesia:dirty_select( session, @@ -607,14 +624,16 @@ check_existing_resources(LUser, LServer, LResource) -> end, SIDs) end. -check_max_sessions(LUser, LServer) -> +check_max_sessions(JID) -> %% If the max number of sessions for a given is reached, we replace the %% first one SIDs = mnesia:dirty_select( session, - [{#session{sid = '$1', us = {LUser, LServer}, _ = '_'}, [], + [{#session{sid = '$1', + us = {exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID)}, + _ = '_'}, [], ['$1']}]), - MaxSessions = get_max_user_sessions(LUser, LServer), + MaxSessions = get_max_user_sessions(JID), if length(SIDs) =< MaxSessions -> ok; @@ -628,9 +647,9 @@ check_max_sessions(LUser, LServer) -> %% This option defines the max number of time a given users are allowed to %% log in %% Defaults to infinity -get_max_user_sessions(LUser, Host) -> +get_max_user_sessions(JID) -> case acl:match_rule( - Host, max_user_sessions, exmpp_jid:make_bare_jid(LUser, Host)) of + exmpp_jid:ldomain_as_list(JID), max_user_sessions, exmpp_jid:jid_to_bare_jid(JID)) of Max when is_integer(Max) -> Max; infinity -> infinity; _ -> ?MAX_USER_SESSIONS @@ -642,8 +661,8 @@ get_max_user_sessions(LUser, Host) -> process_iq(From, To, Packet) -> case exmpp_iq:xmlel_to_iq(Packet) of #iq{kind = request, ns = XMLNS} = IQ_Rec -> - Host = To#jid.ldomain, - case ets:lookup(sm_iqtable, {XMLNS, Host}) of + LServer = exmpp_jid:ldomain_as_list(To), + case ets:lookup(sm_iqtable, {XMLNS, LServer}) of [{_, Module, Function}] -> ResIQ = Module:Function(From, To, IQ_Rec), if @@ -654,8 +673,8 @@ process_iq(From, To, Packet) -> ok end; [{_, Module, Function, Opts}] -> - gen_iq_handler:handle(Host, Module, Function, Opts, - From, To, IQ_Rec); + gen_iq_handler:handle(LServer, + Module, Function, Opts, From, To, IQ_Rec); [] -> Err = exmpp_iq:error(Packet, 'service-unavailable'), ejabberd_router:route(To, From, Err) @@ -703,7 +722,8 @@ connected_users_number() -> length(dirty_get_sessions_list()). user_resources(User, Server) -> - Resources = get_user_resources(User, Server), + Resources = get_user_resources(list_to_binary(User), + list_to_binary(Server)), lists:sort(Resources). diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl index a975d4473..3e0bc6840 100644 --- a/src/ejabberd_system_monitor.erl +++ b/src/ejabberd_system_monitor.erl @@ -55,12 +55,13 @@ start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). process_command(From, To, Packet) -> - case To of - #jid{lnode = undefined, lresource = "watchdog"} -> + case {exmpp_jid:lnode(To), exmpp_jid:lresource(To) } of + {undefined, <<"watchdog">>} -> case Packet#xmlel.name of 'message' -> - LFrom = jlib:short_prepd_bare_jid(From), - case lists:member(LFrom, get_admin_jids()) of + case lists:any(fun(J) -> + exmpp_jid:compare_jids(J,From) + end, get_admin_jids()) of true -> Body = exmpp_xml:get_path( Packet, [{element, 'body'}, cdata_as_list]), @@ -95,7 +96,8 @@ init([]) -> erlang:system_monitor(self(), [{large_heap, 1000000}]), lists:foreach( fun(Host) -> - ejabberd_hooks:add(local_send_to_resource_hook, Host, + ejabberd_hooks:add(local_send_to_resource_hook, + list_to_binary(Host), ?MODULE, process_command, 50) end, ?MYHOSTS), {ok, #state{}}. @@ -168,7 +170,7 @@ process_large_heap(Pid, Info) -> "(~w) The process ~w is consuming too much memory: ~w.~n" "~s", [node(), Pid, Info, DetailedInfo]), - From = exmpp_jid:make_jid(undefined, Host, "watchdog"), + From = exmpp_jid:make_jid(undefined, Host, <<"watchdog">>), lists:foreach( fun(S) -> try @@ -195,7 +197,9 @@ get_admin_jids() -> fun(S) -> try JID = exmpp_jid:list_to_jid(S), - [jlib:short_prepd_jid(JID)] + [{exmpp_jid:lnode(JID), + exmpp_jid:ldomain(JID), + exmpp_jid:lresource(JID)}] catch _ -> [] diff --git a/src/jlib.erl b/src/jlib.erl index 18c1c4e1a..e6cdceb0d 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -37,7 +37,6 @@ encode_base64/1, ip_to_list/1, from_old_jid/1, - to_old_jid/1, short_jid/1, short_bare_jid/1, short_prepd_jid/1, @@ -295,49 +294,26 @@ ip_to_list({A,B,C,D}) -> %% %% Empty fields are set to `undefined', not the empty string. -from_old_jid(#jid{node = Node, resource = Resource, - lnode = LNode, lresource = LResource} = JID) -> - {Node1, LNode1} = case Node of - "" -> {undefined, undefined}; - _ -> {Node, LNode} - end, - {Resource1, LResource1} = case Resource of - "" -> {undefined, undefined}; - _ -> {Resource, LResource} - end, - JID#jid{node = Node1, resource = Resource1, - lnode = LNode1, lresource = LResource1}. +%%TODO: this doesn't make sence!, it is still used?. +from_old_jid(JID) -> + Node = exmpp_jid:node(JID), + Resource = exmpp_jid:resource(JID), + Domain = exmpp_jid:domain(JID), + exmpp_jid:make_jid(Node,Domain,Resource). -%% @spec (JID) -> New_JID -%% JID = jid() -%% New_JID = jid() -%% @doc Convert a JID from its exmpp form to its ejabberd form. -%% -%% Empty fields are set to the empty string, not `undefined'. - -to_old_jid(#jid{node = Node, resource = Resource, - lnode = LNode, lresource = LResource} = JID) -> - {Node1, LNode1} = case Node of - undefined -> {"", ""}; - _ -> {Node, LNode} - end, - {Resource1, LResource1} = case Resource of - undefined -> {"", ""}; - _ -> {Resource, LResource} - end, - JID#jid{node = Node1, resource = Resource1, - lnode = LNode1, lresource = LResource1}. short_jid(JID) -> - {JID#jid.node, JID#jid.domain, JID#jid.resource}. + {exmpp_jid:node(JID), exmpp_jid:domain(JID), exmpp_jid:resource(JID)}. short_bare_jid(JID) -> - Bare_JID = exmpp_jid:jid_to_bare_jid(JID), - {Bare_JID#jid.node, Bare_JID#jid.domain, Bare_JID#jid.resource}. + short_jid(exmpp_jid:jid_to_bare_jid(JID)). short_prepd_jid(JID) -> - {JID#jid.lnode, JID#jid.ldomain, JID#jid.lresource}. + {exmpp_jid:lnode(JID), + exmpp_jid:ldomain(JID), + exmpp_jid:lresource(JID)}. short_prepd_bare_jid(JID) -> - Bare_JID = exmpp_jid:jid_to_bare_jid(JID), - {Bare_JID#jid.lnode, Bare_JID#jid.ldomain, Bare_JID#jid.lresource}. + short_prepd_jid(exmpp_jid:jid_to_bare_jid(JID)). + + diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl index db010ef27..70f2900f2 100644 --- a/src/mod_adhoc.erl +++ b/src/mod_adhoc.erl @@ -48,6 +48,7 @@ -include("adhoc.hrl"). start(Host, Opts) -> + HostB = list_to_binary(Host), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_ADHOC, @@ -55,31 +56,34 @@ start(Host, Opts) -> gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ADHOC, ?MODULE, process_sm_iq, IQDisc), - ejabberd_hooks:add(disco_local_identity, Host, ?MODULE, get_local_identity, 99), - ejabberd_hooks:add(disco_local_features, Host, ?MODULE, get_local_features, 99), - ejabberd_hooks:add(disco_local_items, Host, ?MODULE, get_local_commands, 99), - ejabberd_hooks:add(disco_sm_identity, Host, ?MODULE, get_sm_identity, 99), - ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 99), - ejabberd_hooks:add(disco_sm_items, Host, ?MODULE, get_sm_commands, 99), - ejabberd_hooks:add(adhoc_local_items, Host, ?MODULE, ping_item, 100), - ejabberd_hooks:add(adhoc_local_commands, Host, ?MODULE, ping_command, 100). + ejabberd_hooks:add(disco_local_identity, HostB, ?MODULE, get_local_identity, 99), + ejabberd_hooks:add(disco_local_features, HostB, ?MODULE, get_local_features, 99), + ejabberd_hooks:add(disco_local_items, HostB, ?MODULE, get_local_commands, 99), + ejabberd_hooks:add(disco_sm_identity, HostB, ?MODULE, get_sm_identity, 99), + ejabberd_hooks:add(disco_sm_features, HostB, ?MODULE, get_sm_features, 99), + ejabberd_hooks:add(disco_sm_items, HostB, ?MODULE, get_sm_commands, 99), + ejabberd_hooks:add(adhoc_local_items, HostB, ?MODULE, ping_item, 100), + ejabberd_hooks:add(adhoc_local_commands, HostB, ?MODULE, ping_command, 100). stop(Host) -> - ejabberd_hooks:delete(adhoc_local_commands, Host, ?MODULE, ping_command, 100), - ejabberd_hooks:delete(adhoc_local_items, Host, ?MODULE, ping_item, 100), - ejabberd_hooks:delete(disco_sm_items, Host, ?MODULE, get_sm_commands, 99), - ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 99), - ejabberd_hooks:delete(disco_sm_identity, Host, ?MODULE, get_sm_identity, 99), - ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, get_local_commands, 99), - ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, get_local_features, 99), - ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, get_local_identity, 99), + HostB = list_to_binary(Host), + ejabberd_hooks:delete(adhoc_local_commands, HostB, ?MODULE, ping_command, 100), + ejabberd_hooks:delete(adhoc_local_items, HostB, ?MODULE, ping_item, 100), + ejabberd_hooks:delete(disco_sm_items, HostB, ?MODULE, get_sm_commands, 99), + ejabberd_hooks:delete(disco_sm_features, HostB, ?MODULE, get_sm_features, 99), + ejabberd_hooks:delete(disco_sm_identity, HostB, ?MODULE, get_sm_identity, 99), + ejabberd_hooks:delete(disco_local_items, HostB, ?MODULE, get_local_commands, 99), + ejabberd_hooks:delete(disco_local_features, HostB, ?MODULE, get_local_features, 99), + ejabberd_hooks:delete(disco_local_identity, HostB, ?MODULE, get_local_identity, 99), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ADHOC), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ADHOC). %------------------------------------------------------------------------- -get_local_commands(Acc, _From, #jid{domain = Server, ldomain = LServer} = _To, "", Lang) -> +get_local_commands(Acc, _From, To, "", Lang) -> + Server = exmpp_jid:domain_as_list(To), + LServer = exmpp_jid:ldomain_as_list(To), Display = gen_mod:get_module_opt(LServer, ?MODULE, report_commands_node, false), case Display of false -> @@ -98,8 +102,8 @@ get_local_commands(Acc, _From, #jid{domain = Server, ldomain = LServer} = _To, " {result, Items ++ Nodes} end; -get_local_commands(_Acc, From, #jid{ldomain = LServer} = To, ?NS_ADHOC_s, Lang) -> - ejabberd_hooks:run_fold(adhoc_local_items, LServer, {result, []}, [From, To, Lang]); +get_local_commands(_Acc, From, To, ?NS_ADHOC_s, Lang) -> + ejabberd_hooks:run_fold(adhoc_local_items, exmpp_jid:ldomain(To), {result, []}, [From, To, Lang]); get_local_commands(_Acc, _From, _To, "ping", _Lang) -> {result, []}; @@ -109,7 +113,8 @@ get_local_commands(Acc, _From, _To, _Node, _Lang) -> %------------------------------------------------------------------------- -get_sm_commands(Acc, _From, #jid{ldomain = LServer} = To, "", Lang) -> +get_sm_commands(Acc, _From, To, "", Lang) -> + LServer = exmpp_jid:ldomain_as_list(To), Display = gen_mod:get_module_opt(LServer, ?MODULE, report_commands_node, false), case Display of false -> @@ -128,8 +133,8 @@ get_sm_commands(Acc, _From, #jid{ldomain = LServer} = To, "", Lang) -> {result, Items ++ Nodes} end; -get_sm_commands(_Acc, From, #jid{ldomain = LServer} = To, ?NS_ADHOC_s, Lang) -> - ejabberd_hooks:run_fold(adhoc_sm_items, LServer, {result, []}, [From, To, Lang]); +get_sm_commands(_Acc, From, To, ?NS_ADHOC_s, Lang) -> + ejabberd_hooks:run_fold(adhoc_sm_items, exmpp_jid:ldomain(To), {result, []}, [From, To, Lang]); get_sm_commands(Acc, _From, _To, _Node, _Lang) -> Acc. @@ -216,8 +221,7 @@ process_adhoc_request(From, To, IQ_Rec, Hook) -> {error, Error} -> exmpp_iq:error(IQ_Rec, Error); #adhoc_request{} = AdhocRequest -> - Host = To#jid.ldomain, - case ejabberd_hooks:run_fold(Hook, Host, empty, + case ejabberd_hooks:run_fold(Hook, exmpp_jid:ldomain(To), empty, [From, To, AdhocRequest]) of ignore -> ignore; @@ -231,7 +235,8 @@ process_adhoc_request(From, To, IQ_Rec, Hook) -> end. -ping_item(Acc, _From, #jid{domain = Server} = _To, Lang) -> +ping_item(Acc, _From, To, Lang) -> + Server = exmpp_jid:domain_as_list(To), Items = case Acc of {result, I} -> I; diff --git a/src/mod_announce.erl b/src/mod_announce.erl index f70c487cb..7ef24156e 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -59,19 +59,20 @@ tokenize(Node) -> string:tokens(Node, "/#"). start(Host, _Opts) -> + HostB = list_to_binary(Host), mnesia:create_table(motd, [{disc_copies, [node()]}, {attributes, record_info(fields, motd)}]), mnesia:create_table(motd_users, [{disc_copies, [node()]}, {attributes, record_info(fields, motd_users)}]), update_tables(), - ejabberd_hooks:add(local_send_to_resource_hook, Host, + ejabberd_hooks:add(local_send_to_resource_hook, HostB, ?MODULE, announce, 50), - ejabberd_hooks:add(disco_local_identity, Host, ?MODULE, disco_identity, 50), - ejabberd_hooks:add(disco_local_features, Host, ?MODULE, disco_features, 50), - ejabberd_hooks:add(disco_local_items, Host, ?MODULE, disco_items, 50), - ejabberd_hooks:add(adhoc_local_items, Host, ?MODULE, announce_items, 50), - ejabberd_hooks:add(adhoc_local_commands, Host, ?MODULE, announce_commands, 50), - ejabberd_hooks:add(user_available_hook, Host, + ejabberd_hooks:add(disco_local_identity, HostB, ?MODULE, disco_identity, 50), + ejabberd_hooks:add(disco_local_features, HostB, ?MODULE, disco_features, 50), + ejabberd_hooks:add(disco_local_items, HostB, ?MODULE, disco_items, 50), + ejabberd_hooks:add(adhoc_local_items, HostB, ?MODULE, announce_items, 50), + ejabberd_hooks:add(adhoc_local_commands, HostB, ?MODULE, announce_commands, 50), + ejabberd_hooks:add(user_available_hook, HostB, ?MODULE, send_motd, 50), register(gen_mod:get_module_proc(Host, ?PROCNAME), proc_lib:spawn(?MODULE, init, [])). @@ -116,14 +117,15 @@ loop() -> end. stop(Host) -> - ejabberd_hooks:delete(adhoc_local_commands, Host, ?MODULE, announce_commands, 50), - ejabberd_hooks:delete(adhoc_local_items, Host, ?MODULE, announce_items, 50), - ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, disco_identity, 50), - ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, disco_features, 50), - ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, disco_items, 50), - ejabberd_hooks:delete(local_send_to_resource_hook, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:delete(adhoc_local_commands, HostB, ?MODULE, announce_commands, 50), + ejabberd_hooks:delete(adhoc_local_items, HostB, ?MODULE, announce_items, 50), + ejabberd_hooks:delete(disco_local_identity, HostB, ?MODULE, disco_identity, 50), + ejabberd_hooks:delete(disco_local_features, HostB, ?MODULE, disco_features, 50), + ejabberd_hooks:delete(disco_local_items, HostB, ?MODULE, disco_items, 50), + ejabberd_hooks:delete(local_send_to_resource_hook, HostB, ?MODULE, announce, 50), - ejabberd_hooks:delete(user_available_hook, Host, + ejabberd_hooks:delete(user_available_hook, HostB, ?MODULE, send_motd, 50), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), exit(whereis(Proc), stop), @@ -131,39 +133,39 @@ stop(Host) -> %% Announcing via messages to a custom resource announce(From, To, Packet) -> - case To of - #jid{lnode = undefined, lresource = Res} -> + case {exmpp_jid:lnode(To), exmpp_jid:lresource(To)} of + {undefined, Res} -> Name = Packet#xmlel.name, - Proc = gen_mod:get_module_proc(To#jid.ldomain, ?PROCNAME), + Proc = gen_mod:get_module_proc(exmpp_jid:ldomain_as_list(To), ?PROCNAME), case {Res, Name} of - {"announce/all", 'message'} -> + {<<"announce/all">>, 'message'} -> Proc ! {announce_all, From, To, Packet}, stop; - {"announce/all-hosts/all", 'message'} -> + {<<"announce/all-hosts/all">>, 'message'} -> Proc ! {announce_all_hosts_all, From, To, Packet}, stop; - {"announce/online", 'message'} -> + {<<"announce/online">>, 'message'} -> Proc ! {announce_online, From, To, Packet}, stop; - {"announce/all-hosts/online", 'message'} -> + {<<"announce/all-hosts/online">>, 'message'} -> Proc ! {announce_all_hosts_online, From, To, Packet}, stop; - {"announce/motd", 'message'} -> + {<<"announce/motd">>, 'message'} -> Proc ! {announce_motd, From, To, Packet}, stop; - {"announce/all-hosts/motd", 'message'} -> + {<<"announce/all-hosts/motd">>, 'message'} -> Proc ! {announce_all_hosts_motd, From, To, Packet}, stop; - {"announce/motd/update", 'message'} -> + {<<"announce/motd/update">>, 'message'} -> Proc ! {announce_motd_update, From, To, Packet}, stop; - {"announce/all-hosts/motd/update", 'message'} -> + {<<"announce/all-hosts/motd/update">>, 'message'} -> Proc ! {announce_all_hosts_motd_update, From, To, Packet}, stop; - {"announce/motd/delete", 'message'} -> + {<<"announce/motd/delete">>, 'message'} -> Proc ! {announce_motd_delete, From, To, Packet}, stop; - {"announce/all-hosts/motd/delete", 'message'} -> + {<<"announce/all-hosts/motd/delete">>, 'message'} -> Proc ! {announce_all_hosts_motd_delete, From, To, Packet}, stop; _ -> @@ -218,8 +220,8 @@ disco_identity(Acc, _From, _To, Node, Lang) -> {result, Feats} end). -disco_features(Acc, From, #jid{ldomain = LServer} = _To, - "announce", _Lang) -> +disco_features(Acc, From, To, "announce", _Lang) -> + LServer = exmpp_jid:ldomain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -235,8 +237,8 @@ disco_features(Acc, From, #jid{ldomain = LServer} = _To, end end; -disco_features(Acc, From, #jid{ldomain = LServer} = _To, - Node, _Lang) -> +disco_features(Acc, From, To, Node, _Lang) -> + LServer = exmpp_jid:ldomain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -287,8 +289,10 @@ disco_features(Acc, From, #jid{ldomain = LServer} = _To, {result, Items} end). -disco_items(Acc, From, #jid{ldomain = LServer, domain = Server} = _To, - "", Lang) -> +disco_items(Acc, From, To, "", Lang) -> + LServer = exmpp_jid:ldomain_as_list(To), + Server = exmpp_jid:domain_as_list(To), + case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -309,7 +313,8 @@ disco_items(Acc, From, #jid{ldomain = LServer, domain = Server} = _To, end end; -disco_items(Acc, From, #jid{ldomain = LServer} = To, "announce", Lang) -> +disco_items(Acc, From, To, "announce", Lang) -> + LServer = exmpp_jid:ldomain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -317,7 +322,8 @@ disco_items(Acc, From, #jid{ldomain = LServer} = To, "announce", Lang) -> announce_items(Acc, From, To, Lang) end; -disco_items(Acc, From, #jid{ldomain = LServer} = _To, Node, _Lang) -> +disco_items(Acc, From, To, Node, _Lang) -> + LServer = exmpp_jid:ldomain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -354,7 +360,9 @@ disco_items(Acc, From, #jid{ldomain = LServer} = _To, Node, _Lang) -> %%------------------------------------------------------------------------- -announce_items(Acc, From, #jid{ldomain = LServer, domain = Server} = _To, Lang) -> +announce_items(Acc, From, To, Lang) -> + LServer = exmpp_jid:ldomain_as_list(To), + Server = exmpp_jid:domain_as_list(To), Access1 = gen_mod:get_module_opt(LServer, ?MODULE, access, none), Nodes1 = case acl:match_rule(LServer, Access1, From) of allow -> @@ -399,8 +407,8 @@ commands_result(Allow, From, To, Request) -> end. -announce_commands(Acc, From, #jid{ldomain = LServer} = To, - #adhoc_request{ node = Node} = Request) -> +announce_commands(Acc, From, To, #adhoc_request{ node = Node} = Request) -> + LServer = exmpp_jid:ldomain_as_list(To), LNode = tokenize(Node), F = fun() -> Access = gen_mod:get_module_opt(global, ?MODULE, access, none), @@ -455,7 +463,7 @@ announce_commands(From, To, #adhoc_response{status = canceled}); XData == false, ActionIsExecute -> %% User requests form - Elements = generate_adhoc_form(Lang, Node, To#jid.ldomain), + Elements = generate_adhoc_form(Lang, Node, exmpp_jid:ldomain_as_list(To)), adhoc:produce_response( Request, #adhoc_response{status = executing, @@ -529,11 +537,12 @@ join_lines([], Acc) -> %% Remove last newline lists:flatten(lists:reverse(tl(Acc))). -handle_adhoc_form(From, #jid{ldomain = LServer} = To, +handle_adhoc_form(From, To, #adhoc_request{lang = Lang, node = Node, sessionid = SessionID}, Fields) -> + LServer = exmpp_jid:ldomain_as_list(To), Confirm = case lists:keysearch("confirm", 1, Fields) of {value, {"confirm", ["true"]}} -> true; @@ -654,14 +663,14 @@ get_title(Lang, ?NS_ADMIN_s ++ "#delete-motd-allhosts") -> %%------------------------------------------------------------------------- announce_all(From, To, Packet) -> - Host = To#jid.ldomain, + Host = exmpp_jid:ldomain_as_list(To), Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), case acl:match_rule(Host, Access, From) of deny -> Err = exmpp_stanza:reply_with_error(Packet, 'forbidden'), ejabberd_router:route(To, From, Err); allow -> - Local = exmpp_jid:make_jid(To#jid.domain), + Local = exmpp_jid:make_jid(exmpp_jid:domain(To)), lists:foreach( fun({User, Server}) -> Dest = exmpp_jid:make_jid(User, Server), @@ -676,7 +685,7 @@ announce_all_hosts_all(From, To, Packet) -> Err = exmpp_stanza:reply_with_error(Packet, 'forbidden'), ejabberd_router:route(To, From, Err); allow -> - Local = exmpp_jid:make_jid(To#jid.domain), + Local = exmpp_jid:make_jid(exmpp_jid:domain(To)), lists:foreach( fun({User, Server}) -> Dest = exmpp_jid:make_jid(User, Server), @@ -685,15 +694,15 @@ announce_all_hosts_all(From, To, Packet) -> end. announce_online(From, To, Packet) -> - Host = To#jid.ldomain, + Host = exmpp_jid:ldomain_as_list(To), Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), case acl:match_rule(Host, Access, From) of deny -> Err = exmpp_stanza:reply_with_error(Packet, 'forbidden'), ejabberd_router:route(To, From, Err); allow -> - announce_online1(ejabberd_sm:get_vh_session_list(Host), - To#jid.domain, + announce_online1(ejabberd_sm:get_vh_session_list(exmpp_jid:ldomain(To)), + exmpp_jid:domain_as_list(To), Packet) end. @@ -705,7 +714,7 @@ announce_all_hosts_online(From, To, Packet) -> ejabberd_router:route(To, From, Err); allow -> announce_online1(ejabberd_sm:dirty_get_sessions_list(), - To#jid.domain, + exmpp_jid:domain_as_list(To), Packet) end. @@ -718,7 +727,7 @@ announce_online1(Sessions, Server, Packet) -> end, Sessions). announce_motd(From, To, Packet) -> - Host = To#jid.ldomain, + Host = exmpp_jid:ldomain_as_list(To), Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), case acl:match_rule(Host, Access, From) of deny -> @@ -741,7 +750,7 @@ announce_all_hosts_motd(From, To, Packet) -> announce_motd(Host, Packet) -> announce_motd_update(Host, Packet), - Sessions = ejabberd_sm:get_vh_session_list(Host), + Sessions = ejabberd_sm:get_vh_session_list(list_to_binary(Host)), announce_online1(Sessions, Host, Packet), F = fun() -> lists:foreach( @@ -752,7 +761,7 @@ announce_motd(Host, Packet) -> mnesia:transaction(F). announce_motd_update(From, To, Packet) -> - Host = To#jid.ldomain, + Host = exmpp_jid:ldomain_as_list(To), Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), case acl:match_rule(Host, Access, From) of deny -> @@ -781,7 +790,7 @@ announce_motd_update(LServer, Packet) -> mnesia:transaction(F). announce_motd_delete(From, To, Packet) -> - Host = To#jid.ldomain, + Host = exmpp_jid:ldomain_as_list(To), Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), case acl:match_rule(Host, Access, From) of deny -> @@ -817,7 +826,9 @@ announce_motd_delete(LServer) -> end, mnesia:transaction(F). -send_motd(#jid{lnode = LUser, ldomain = LServer} = JID) -> +send_motd(JID) -> + LServer = exmpp_jid:ldomain_as_list(JID), + LUser = exmpp_jid:lnode_as_list(JID), case catch mnesia:dirty_read({motd, LServer}) of [#motd{packet = Packet}] -> US = {LUser, LServer}, @@ -825,7 +836,7 @@ send_motd(#jid{lnode = LUser, ldomain = LServer} = JID) -> [#motd_users{}] -> ok; _ -> - Local = exmpp_jid:make_jid(LServer), + Local = exmpp_jid:make_jid(exmpp_jid:ldomain(JID)), ejabberd_router:route(Local, JID, Packet), F = fun() -> mnesia:write(#motd_users{us = US}) diff --git a/src/mod_caps.erl b/src/mod_caps.erl index f7aa858cb..19e24edd3 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -87,7 +87,7 @@ read_caps([], Result) -> %% get_caps reads user caps from database get_caps({U, S, R}) -> - BJID = exmpp_jlib:jid_to_binary(U, S, R), + BJID = exmpp_jid:jid_to_binary(U, S, R), case catch mnesia:dirty_read({user_caps, BJID}) of [#user_caps{caps=Caps}] -> Caps; @@ -97,8 +97,8 @@ get_caps({U, S, R}) -> %% clear_caps removes user caps from database clear_caps({U, S, R}) -> - BJID = exmpp_jlib:jid_to_binary(U, S, R), - BUID = exmpp_jlib:jid_to_binary(U, S), + BJID = exmpp_jid:jid_to_binary(U, S, R), + BUID = exmpp_jid:jid_to_binary(U, S), catch mnesia:dirty_delete({user_caps, BJID}), case catch mnesia:dirty_read({user_caps_default, BUID}) of [#user_caps_default{resource=R}] -> @@ -109,7 +109,7 @@ clear_caps({U, S, R}) -> %% give default user resource get_user_resource(U, S) -> - BUID = exmpp_jlib:bare_jid_to_binary(U, S), + BUID = exmpp_jid:bare_jid_to_binary(U, S), case catch mnesia:dirty_read({user_caps_default, BUID}) of [#user_caps_default{resource=R}] -> R; @@ -225,15 +225,18 @@ handle_cast({note_caps, From, #state{host = Host, disco_requests = Requests} = State) -> %% XXX: this leads to race conditions where ejabberd will send %% lots of caps disco requests. - #jid{node = U, domain = S, resource = R} = From, - BJID = exmpp_jlib:jid_to_binary(From), + %#jid{node = U, domain = S, resource = R} = From, + U = exmpp_jid:lnode(From), + S = exmpp_jid:ldomain(From), + R = exmpp_jid:resource(From), + BJID = exmpp_jid:jid_to_binary(From), mnesia:dirty_write(#user_caps{jid = BJID, caps = Caps}), case ejabberd_sm:get_user_resources(U, S) of [] -> ok; _ -> % only store default resource of external contacts - BUID = exmpp_jlib:bare_jid_to_binary(From), + BUID = exmpp_jid:bare_jid_to_binary(From), mnesia:dirty_write(#user_caps_default{uid = BUID, resource = R}) end, SubNodes = [Version | Exts], @@ -340,7 +343,7 @@ handle_cast(visit_feature_queries, #state{feature_queries = FeatureQueries} = St {noreply, State#state{feature_queries = NewFeatureQueries}}. handle_disco_response(From, To, IQ_Rec) -> - #jid{ldomain = Host} = To, + Host = exmpp_jid:ldomain_as_list(To), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), gen_server:cast(Proc, {disco_response, From, To, IQ_Rec}). diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 5a760972e..9fb3f72c5 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -59,29 +59,31 @@ -define(NS_ADMIN_s, "http://jabber.org/protocol/admin"). start(Host, _Opts) -> - ejabberd_hooks:add(disco_local_items, Host, ?MODULE, get_local_items, 50), - ejabberd_hooks:add(disco_local_features, Host, ?MODULE, get_local_features, 50), - ejabberd_hooks:add(disco_local_identity, Host, ?MODULE, get_local_identity, 50), - ejabberd_hooks:add(disco_sm_items, Host, ?MODULE, get_sm_items, 50), - ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50), - ejabberd_hooks:add(disco_sm_identity, Host, ?MODULE, get_sm_identity, 50), - ejabberd_hooks:add(adhoc_local_items, Host, ?MODULE, adhoc_local_items, 50), - ejabberd_hooks:add(adhoc_local_commands, Host, ?MODULE, adhoc_local_commands, 50), - ejabberd_hooks:add(adhoc_sm_items, Host, ?MODULE, adhoc_sm_items, 50), - ejabberd_hooks:add(adhoc_sm_commands, Host, ?MODULE, adhoc_sm_commands, 50), + HostB = list_to_binary(Host), + ejabberd_hooks:add(disco_local_items, HostB, ?MODULE, get_local_items, 50), + ejabberd_hooks:add(disco_local_features, HostB, ?MODULE, get_local_features, 50), + ejabberd_hooks:add(disco_local_identity, HostB, ?MODULE, get_local_identity, 50), + ejabberd_hooks:add(disco_sm_items, HostB, ?MODULE, get_sm_items, 50), + ejabberd_hooks:add(disco_sm_features, HostB, ?MODULE, get_sm_features, 50), + ejabberd_hooks:add(disco_sm_identity, HostB, ?MODULE, get_sm_identity, 50), + ejabberd_hooks:add(adhoc_local_items, HostB, ?MODULE, adhoc_local_items, 50), + ejabberd_hooks:add(adhoc_local_commands, HostB, ?MODULE, adhoc_local_commands, 50), + ejabberd_hooks:add(adhoc_sm_items, HostB, ?MODULE, adhoc_sm_items, 50), + ejabberd_hooks:add(adhoc_sm_commands, HostB, ?MODULE, adhoc_sm_commands, 50), ok. stop(Host) -> - ejabberd_hooks:delete(adhoc_sm_commands, Host, ?MODULE, adhoc_sm_commands, 50), - ejabberd_hooks:delete(adhoc_sm_items, Host, ?MODULE, adhoc_sm_items, 50), - ejabberd_hooks:delete(adhoc_local_commands, Host, ?MODULE, adhoc_local_commands, 50), - ejabberd_hooks:delete(adhoc_local_items, Host, ?MODULE, adhoc_local_items, 50), - ejabberd_hooks:delete(disco_sm_identity, Host, ?MODULE, get_sm_identity, 50), - ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50), - ejabberd_hooks:delete(disco_sm_items, Host, ?MODULE, get_sm_items, 50), - ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, get_local_identity, 50), - ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, get_local_features, 50), - ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, get_local_items, 50), + HostB = list_to_binary(Host), + ejabberd_hooks:delete(adhoc_sm_commands, HostB, ?MODULE, adhoc_sm_commands, 50), + ejabberd_hooks:delete(adhoc_sm_items, HostB, ?MODULE, adhoc_sm_items, 50), + ejabberd_hooks:delete(adhoc_local_commands, HostB, ?MODULE, adhoc_local_commands, 50), + ejabberd_hooks:delete(adhoc_local_items, HostB, ?MODULE, adhoc_local_items, 50), + ejabberd_hooks:delete(disco_sm_identity, HostB, ?MODULE, get_sm_identity, 50), + ejabberd_hooks:delete(disco_sm_features, HostB, ?MODULE, get_sm_features, 50), + ejabberd_hooks:delete(disco_sm_items, HostB, ?MODULE, get_sm_items, 50), + ejabberd_hooks:delete(disco_local_identity, HostB, ?MODULE, get_local_identity, 50), + ejabberd_hooks:delete(disco_local_features, HostB, ?MODULE, get_local_features, 50), + ejabberd_hooks:delete(disco_local_items, HostB, ?MODULE, get_local_items, 50), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ADHOC), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ADHOC). @@ -181,7 +183,8 @@ get_local_identity(Acc, _From, _To, Node, Lang) -> {result, Feats} end). -get_sm_features(Acc, From, #jid{ldomain = LServer} = _To, Node, _Lang) -> +get_sm_features(Acc, From, To, Node, _Lang) -> + LServer = exmpp_jid:ldomain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -195,7 +198,8 @@ get_sm_features(Acc, From, #jid{ldomain = LServer} = _To, Node, _Lang) -> end end. -get_local_features(Acc, From, #jid{ldomain = LServer} = _To, Node, _Lang) -> +get_local_features(Acc, From, To, Node, _Lang) -> + LServer = exmpp_jid:ldomain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -250,7 +254,8 @@ get_local_features(Acc, From, #jid{ldomain = LServer} = _To, Node, _Lang) -> %%%----------------------------------------------------------------------- -adhoc_sm_items(Acc, From, #jid{ldomain = LServer} = To, Lang) -> +adhoc_sm_items(Acc, From, To, Lang) -> + LServer = exmpp_jid:ldomain_as_list(To), case acl:match_rule(LServer, configure, From) of allow -> Items = case Acc of @@ -268,9 +273,8 @@ adhoc_sm_items(Acc, From, #jid{ldomain = LServer} = To, Lang) -> %%%----------------------------------------------------------------------- -get_sm_items(Acc, From, - #jid{node = User, domain = Server, ldomain = LServer} = To, - Node, Lang) -> +get_sm_items(Acc, From, To, Node, Lang) -> + LServer = exmpp_jid:ldomain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -283,7 +287,7 @@ get_sm_items(Acc, From, {allow, ""} -> Nodes = [?NODEJID(To, "Configuration", "config"), ?NODEJID(To, "User Management", "user")], - {result, Items ++ Nodes ++ get_user_resources(User, Server)}; + {result, Items ++ Nodes ++ get_user_resources(To)}; {allow, "config"} -> {result, []}; {_, "config"} -> @@ -293,18 +297,23 @@ get_sm_items(Acc, From, end end. -get_user_resources(User, Server) -> - Rs = ejabberd_sm:get_user_resources(User, Server), +get_user_resources(BareJID) -> + Rs = ejabberd_sm:get_user_resources(exmpp_jid:lnode(BareJID), + exmpp_jid:ldomain(BareJID)), lists:map(fun(R) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(User, Server, R)}, - #xmlattr{name = 'name', value = User}]} + [#xmlattr{name = 'jid', + value = exmpp_jid:jid_to_list( + exmpp_jid:bare_jid_to_jid(BareJID, R))}, + #xmlattr{name = 'name', + value = exmpp_jid:lnode_as_list(BareJID)}]} end, lists:sort(Rs)). %%%----------------------------------------------------------------------- -adhoc_local_items(Acc, From, #jid{ldomain = LServer, domain = Server} = To, - Lang) -> +adhoc_local_items(Acc, From, To, Lang) -> + LServer = exmpp_jid:ldomain_as_list(To), + Server = exmpp_jid:domain_as_list(To), case acl:match_rule(LServer, configure, From) of allow -> Items = case Acc of @@ -373,7 +382,8 @@ recursively_get_local_items(LServer, Node, Server, Lang) -> end end). -get_local_items(Acc, From, #jid{ldomain = LServer} = To, "", Lang) -> +get_local_items(Acc, From, To, "", Lang) -> + LServer = exmpp_jid:ldomain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -397,7 +407,8 @@ get_local_items(Acc, From, #jid{ldomain = LServer} = To, "", Lang) -> end end; -get_local_items(Acc, From, #jid{ldomain = LServer} = To, Node, Lang) -> +get_local_items(Acc, From, To, Node, Lang) -> + LServer = exmpp_jid:ldomain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -584,7 +595,7 @@ get_local_items(_Host, _, _Server, _Lang) -> get_online_vh_users(Host) -> - case catch ejabberd_sm:get_vh_session_list(Host) of + case catch ejabberd_sm:get_vh_session_list(list_to_binary(Host)) of {'EXIT', _Reason} -> []; USRs -> @@ -716,8 +727,8 @@ get_stopped_nodes(_Lang) -> adhoc_local_commands(From, To, Request) end). -adhoc_local_commands(Acc, From, #jid{ldomain = LServer} = To, - #adhoc_request{node = Node} = Request) -> +adhoc_local_commands(Acc, From, To, #adhoc_request{node = Node} = Request) -> + LServer = exmpp_jid:ldomain_as_list(To), LNode = tokenize(Node), Allow = acl:match_rule(LServer, configure, From), case LNode of @@ -741,12 +752,13 @@ adhoc_local_commands(Acc, From, #jid{ldomain = LServer} = To, Acc end. -adhoc_local_commands(From, #jid{ldomain = LServer} = _To, +adhoc_local_commands(From, To, #adhoc_request{lang = Lang, node = Node, sessionid = SessionID, action = Action, xdata = XData} = Request) -> + LServer = exmpp_jid:ldomain_as_list(To), LNode = tokenize(Node), %% If the "action" attribute is not present, it is %% understood as "execute". If there was no @@ -1247,7 +1259,7 @@ get_form(Host, ?NS_ADMINL("get-registered-users-num"), Lang) -> }]}]}; get_form(Host, ?NS_ADMINL("get-online-users-num"), Lang) -> - Num = io_lib:format("~p", [length(ejabberd_sm:get_vh_session_list(Host))]), + Num = io_lib:format("~p", [length(ejabberd_sm:get_vh_session_list(list_to_binary(Host)))]), {result, completed, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), @@ -1535,8 +1547,8 @@ set_form(_From, _Host, ?NS_ADMINL("add-user"), _Lang, XData) -> Password = get_value("password", XData), Password = get_value("password-verify", XData), AccountJID = exmpp_jid:list_to_jid(AccountString), - User = AccountJID#jid.lnode, - Server = AccountJID#jid.ldomain, + User = exmpp_jid:lnode_as_list(AccountJID), + Server = exmpp_jid:ldomain_as_list(AccountJID), true = lists:member(Server, ?MYHOSTS), ejabberd_auth:try_register(User, Server, Password), {result, []}; @@ -1547,9 +1559,8 @@ set_form(_From, _Host, ?NS_ADMINL("delete-user"), _Lang, XData) -> ASL2 = lists:map( fun(AccountString) -> JID = exmpp_jid:list_to_jid(AccountString), - [_|_] = JID#jid.lnode, - User = JID#jid.lnode, - Server = JID#jid.ldomain, + User = [_|_] = exmpp_jid:lnode_as_list(JID), + Server = exmpp_jid:ldomain_as_list(JID), true = ejabberd_auth:is_user_exists(User, Server), {User, Server} end, @@ -1560,11 +1571,10 @@ set_form(_From, _Host, ?NS_ADMINL("delete-user"), _Lang, XData) -> set_form(_From, _Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> AccountString = get_value("accountjid", XData), JID = exmpp_jid:list_to_jid(AccountString), - [_|_] = JID#jid.lnode, - LUser = JID#jid.lnode, - LServer = JID#jid.ldomain, + LUser = [_|_] = exmpp_jid:lnode_as_list(JID), + LServer = exmpp_jid:ldomain_as_list(JID), %% Code copied from ejabberd_sm.erl - case JID#jid.lresource of + case exmpp_jid:lresource_as_list(JID) of undefined -> SIDs = mnesia:dirty_select(session, [{#session{sid = '$1', usr = {LUser, LServer, '_'}, _ = '_'}, [], ['$1']}]), @@ -1579,9 +1589,8 @@ set_form(_From, _Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> set_form(_From, _Host, ?NS_ADMINL("get-user-password"), Lang, XData) -> AccountString = get_value("accountjid", XData), JID = exmpp_jid:list_to_jid(AccountString), - [_|_] = JID#jid.lnode, - User = JID#jid.lnode, - Server = JID#jid.ldomain, + User = [_|_] = exmpp_jid:lnode_as_list(JID), + Server = exmpp_jid:ldomain_as_list(JID), Password = ejabberd_auth:get_password(User, Server), true = is_list(Password), {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = @@ -1594,9 +1603,8 @@ set_form(_From, _Host, ?NS_ADMINL("change-user-password"), _Lang, XData) -> AccountString = get_value("accountjid", XData), Password = get_value("password", XData), JID = exmpp_jid:list_to_jid(AccountString), - [_|_] = JID#jid.lnode, - User = JID#jid.lnode, - Server = JID#jid.ldomain, + User = [_|_] = exmpp_jid:lnode_as_list(JID), + Server = exmpp_jid:ldomain_as_list(JID), true = ejabberd_auth:is_user_exists(User, Server), ejabberd_auth:set_password(User, Server, Password), {result, []}; @@ -1604,14 +1612,14 @@ set_form(_From, _Host, ?NS_ADMINL("change-user-password"), _Lang, XData) -> set_form(_From, _Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> AccountString = get_value("accountjid", XData), JID = exmpp_jid:list_to_jid(AccountString), - [_|_] = JID#jid.lnode, - User = JID#jid.lnode, - Server = JID#jid.ldomain, + User = [_|_] = exmpp_jid:lnode_as_list(JID), + Server = exmpp_jid:ldomain_as_list(JID), %% Code copied from web/ejabberd_web_admin.erl %% TODO: Update time format to XEP-0202: Entity Time FLast = - case ejabberd_sm:get_user_resources(User, Server) of + case ejabberd_sm:get_user_resources(exmpp_jid:lnode(User), + exmpp_jid:ldomain(Server)) of [] -> _US = {User, Server}, case get_last_info(User, Server) of @@ -1641,15 +1649,19 @@ set_form(_From, _Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> set_form(_From, _Host, ?NS_ADMINL("user-stats"), Lang, XData) -> AccountString = get_value("accountjid", XData), JID = exmpp_jid:list_to_jid(AccountString), - [_|_] = JID#jid.lnode, - User = JID#jid.lnode, - Server = JID#jid.ldomain, + User = [_|_] = exmpp_jid:lnode_as_list(JID), + Server = exmpp_jid:ldomain_as_list(JID), - Resources = ejabberd_sm:get_user_resources(User, Server), - IPs1 = [ejabberd_sm:get_user_ip(User, Server, Resource) || Resource <- Resources], + Resources = ejabberd_sm:get_user_resources(exmpp_jid:lnode(JID), + exmpp_jid:ldomain(JID)), + IPs1 = [ejabberd_sm:get_user_ip(exmpp_jid:bare_jid_to_jid(JID,Resource)) + || Resource <- Resources], IPs = [inet_parse:ntoa(IP)++":"++integer_to_list(Port) || {IP, Port} <- IPs1], - Items = ejabberd_hooks:run_fold(roster_get, Server, [], [{User, Server}]), + Items = ejabberd_hooks:run_fold(roster_get, + exmpp_jid:ldomain(JID), + [], + [{list_to_binary(User), list_to_binary(Server)}]), Rostersize = integer_to_list(erlang:length(Items)), {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = @@ -1729,12 +1741,14 @@ get_last_info(User, Server) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -adhoc_sm_commands(_Acc, From, - #jid{node = User, domain = Server, ldomain = LServer} = _To, +adhoc_sm_commands(_Acc, From, To, #adhoc_request{lang = Lang, node = "config", action = Action, xdata = XData} = Request) -> + User = exmpp_jid:node_as_list(To), + Server = exmpp_jid:domain_as_list(To), + LServer = exmpp_jid:ldomain_as_list(To), case acl:match_rule(LServer, configure, From) of deny -> {error, 'forbidden'}; diff --git a/src/mod_configure2.erl b/src/mod_configure2.erl index e6d64c4ce..9dd9b8c81 100644 --- a/src/mod_configure2.erl +++ b/src/mod_configure2.erl @@ -71,7 +71,7 @@ stop(Host) -> process_local_iq(From, To, #iq{type = Type, payload = Request} = IQ_Rec) -> - case acl:match_rule(To#jid.ldomain, configure, From) of + case acl:match_rule(exmpp_jid:ldomain_as_list(To), configure, From) of deny -> exmpp_iq:error(IQ_Rec, 'not-allowed'); allow -> diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 21097c79d..be36ce749 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -54,6 +54,7 @@ -record(disco_publish, {owner_node, jid, name, node}). start(Host, Opts) -> + HostB = list_to_binary(Host), mnesia:create_table(disco_publish, [{disc_only_copies, [node()]}, {attributes, record_info(fields, disco_publish)}, @@ -84,23 +85,24 @@ start(Host, Opts) -> ExtraDomains), catch ets:new(disco_sm_features, [named_table, ordered_set, public]), catch ets:new(disco_sm_nodes, [named_table, ordered_set, public]), - ejabberd_hooks:add(disco_local_items, Host, ?MODULE, get_local_services, 100), - ejabberd_hooks:add(disco_local_features, Host, ?MODULE, get_local_features, 100), - ejabberd_hooks:add(disco_local_identity, Host, ?MODULE, get_local_identity, 100), - ejabberd_hooks:add(disco_sm_items, Host, ?MODULE, get_sm_items, 100), - ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 100), - ejabberd_hooks:add(disco_sm_identity, Host, ?MODULE, get_sm_identity, 100), - ejabberd_hooks:add(disco_sm_items, Host, ?MODULE, get_publish_items, 75), + ejabberd_hooks:add(disco_local_items, HostB, ?MODULE, get_local_services, 100), + ejabberd_hooks:add(disco_local_features, HostB, ?MODULE, get_local_features, 100), + ejabberd_hooks:add(disco_local_identity, HostB, ?MODULE, get_local_identity, 100), + ejabberd_hooks:add(disco_sm_items, HostB, ?MODULE, get_sm_items, 100), + ejabberd_hooks:add(disco_sm_features, HostB, ?MODULE, get_sm_features, 100), + ejabberd_hooks:add(disco_sm_identity, HostB, ?MODULE, get_sm_identity, 100), + ejabberd_hooks:add(disco_sm_items, HostB, ?MODULE, get_publish_items, 75), ok. stop(Host) -> - ejabberd_hooks:delete(disco_sm_items, Host, ?MODULE, get_publish_items, 75), - ejabberd_hooks:delete(disco_sm_identity, Host, ?MODULE, get_sm_identity, 100), - ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 100), - ejabberd_hooks:delete(disco_sm_items, Host, ?MODULE, get_sm_items, 100), - ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, get_local_identity, 100), - ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, get_local_features, 100), - ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, get_local_services, 100), + HostB = list_to_binary(Host), + ejabberd_hooks:delete(disco_sm_items, HostB, ?MODULE, get_publish_items, 75), + ejabberd_hooks:delete(disco_sm_identity, HostB, ?MODULE, get_sm_identity, 100), + ejabberd_hooks:delete(disco_sm_features, HostB, ?MODULE, get_sm_features, 100), + ejabberd_hooks:delete(disco_sm_items, HostB, ?MODULE, get_sm_items, 100), + ejabberd_hooks:delete(disco_local_identity, HostB, ?MODULE, get_local_identity, 100), + ejabberd_hooks:delete(disco_local_features, HostB, ?MODULE, get_local_features, 100), + ejabberd_hooks:delete(disco_local_items, HostB, ?MODULE, get_local_services, 100), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_DISCO_ITEMS), @@ -128,11 +130,10 @@ unregister_extra_domain(Host, Domain) -> process_local_iq_items(From, To, #iq{type = get, payload = SubEl, lang = Lang} = IQ_Rec) -> - Host = To#jid.ldomain, Node = exmpp_xml:get_attribute(SubEl, 'node', ""), case ejabberd_hooks:run_fold(disco_local_items, - Host, + exmpp_jid:ldomain(To), empty, [From, To, Node, Lang]) of {result, Items} -> @@ -152,14 +153,13 @@ process_local_iq_items(_From, _To, #iq{type = set} = IQ_Rec) -> process_local_iq_info(From, To, #iq{type = get, payload = SubEl, lang = Lang} = IQ_Rec) -> - Host = To#jid.ldomain, Node = exmpp_xml:get_attribute(SubEl, 'node', ""), Identity = ejabberd_hooks:run_fold(disco_local_identity, - Host, + exmpp_jid:ldomain(To), [], [From, To, Node, Lang]), case ejabberd_hooks:run_fold(disco_local_features, - Host, + exmpp_jid:ldomain(To), empty, [From, To, Node, Lang]) of {result, Features} -> @@ -196,7 +196,7 @@ get_local_features(Acc, _From, To, [], _Lang) -> {result, Features} -> Features; empty -> [] end, - Host = To#jid.ldomain, + Host = exmpp_jid:ldomain_as_list(To), {result, ets:select(disco_features, [{{{'_', Host}}, [], ['$_']}]) ++ Feats}; @@ -237,7 +237,7 @@ get_local_services(Acc, _From, To, [], _Lang) -> {result, Its} -> Its; empty -> [] end, - Host = To#jid.ldomain, + Host = exmpp_jid:ldomain_as_list(To), {result, lists:usort( lists:map(fun domain_to_xml/1, @@ -270,10 +270,9 @@ get_vh_services(Host) -> process_sm_iq_items(From, To, #iq{type = get, payload = SubEl, lang = Lang} = IQ_Rec) -> - Host = To#jid.ldomain, Node = exmpp_xml:get_attribute(SubEl, 'node', ""), case ejabberd_hooks:run_fold(disco_sm_items, - Host, + exmpp_jid:ldomain(To), empty, [From, To, Node, Lang]) of {result, Items} -> @@ -288,8 +287,10 @@ process_sm_iq_items(From, To, #iq{type = get, payload = SubEl, exmpp_iq:error(IQ_Rec, Error) end; process_sm_iq_items(From, To, #iq{type = set, payload = SubEl} = IQ_Rec) -> - #jid{lnode = LTo, ldomain = ToServer} = To, - #jid{lnode = LFrom, ldomain = LServer} = From, + LTo = exmpp_jid:lnode_as_list(To), + ToServer = exmpp_jid:ldomain_as_list(To), + LFrom = exmpp_jid:lnode_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), Self = (LTo == LFrom) andalso (ToServer == LServer), Node = exmpp_xml:get_attribute(SubEl, 'node', ""), if @@ -310,16 +311,18 @@ process_sm_iq_items(From, To, #iq{type = set, payload = SubEl} = IQ_Rec) -> get_sm_items({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; -get_sm_items(Acc, - #jid{lnode = LFrom, ldomain = LSFrom}, - #jid{node = User, domain = Server, lnode = LTo, ldomain = LSTo} = _To, - [], _Lang) -> +get_sm_items(Acc, From, To, [], _Lang) -> + LFrom = exmpp_jid:lnode_as_list(From), + LSFrom = exmpp_jid:ldomain_as_list(From), + LTo = exmpp_jid:lnode_as_list(To), + LSTo = exmpp_jid:ldomain_as_list(To), + Items = case Acc of {result, Its} -> Its; empty -> [] end, Items1 = case {LFrom, LSFrom} of - {LTo, LSTo} -> get_user_resources(User, Server); + {LTo, LSTo} -> get_user_resources(To); _ -> [] end, {result, Items ++ Items1}; @@ -328,8 +331,10 @@ get_sm_items({result, _} = Acc, _From, _To, _Node, _Lang) -> Acc; get_sm_items(empty, From, To, _Node, _Lang) -> - #jid{lnode = LFrom, ldomain = LSFrom} = From, - #jid{lnode = LTo, ldomain = LSTo} = To, + LFrom = exmpp_jid:lnode_as_list(From), + LSFrom = exmpp_jid:ldomain_as_list(From), + LTo = exmpp_jid:lnode_as_list(To), + LSTo = exmpp_jid:ldomain_as_list(To), case {LFrom, LSFrom} of {LTo, LSTo} -> {error, 'item-not-found'}; @@ -339,14 +344,13 @@ get_sm_items(empty, From, To, _Node, _Lang) -> process_sm_iq_info(From, To, #iq{type = get, payload = SubEl, lang = Lang} = IQ_Rec) -> - Host = To#jid.ldomain, Node = exmpp_xml:get_attribute(SubEl, 'node', ""), Identity = ejabberd_hooks:run_fold(disco_sm_identity, - Host, + exmpp_jid:ldomain(To), [], [From, To, Node, Lang]), case ejabberd_hooks:run_fold(disco_sm_features, - Host, + exmpp_jid:ldomain(To), empty, [From, To, Node, Lang]) of {result, Features} -> @@ -369,8 +373,10 @@ get_sm_identity(Acc, _From, _To, _Node, _Lang) -> Acc. get_sm_features(empty, From, To, _Node, _Lang) -> - #jid{lnode = LFrom, ldomain = LSFrom} = From, - #jid{lnode = LTo, ldomain = LSTo} = To, + LFrom = exmpp_jid:lnode_as_list(From), + LSFrom = exmpp_jid:ldomain_as_list(From), + LTo = exmpp_jid:lnode_as_list(To), + LSTo = exmpp_jid:ldomain_as_list(To), case {LFrom, LSFrom} of {LTo, LSTo} -> {error, 'item-not-found'}; @@ -383,21 +389,23 @@ get_sm_features(Acc, _From, _To, _Node, _Lang) -> -get_user_resources(User, Server) -> - Rs = ejabberd_sm:get_user_resources(User, Server), +get_user_resources(JID) -> + Rs = ejabberd_sm:get_user_resources(exmpp_jid:lnode(JID), + exmpp_jid:ldomain(JID)), lists:map(fun(R) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [ #xmlattr{name = 'jid', value = - exmpp_jid:jid_to_list(User, Server, R)}, - #xmlattr{name = 'name', value = User} + exmpp_jid:jid_to_list(exmpp_jid:bare_jid_to_jid(JID, R))}, + #xmlattr{name = 'name', value = exmpp_jid:lnode_as_list(JID)} ]} end, lists:sort(Rs)). -get_publish_items(empty, - #jid{lnode = LFrom, ldomain = LSFrom}, - #jid{lnode = LTo, ldomain = LSTo} = _To, - Node, _Lang) -> +get_publish_items(empty, From, To, Node, _Lang) -> + LFrom = exmpp_jid:lnode_as_list(From), + LSFrom = exmpp_jid:ldomain_as_list(From), + LTo = exmpp_jid:lnode_as_list(To), + LSTo = exmpp_jid:ldomain_as_list(To), if (LFrom == LTo) and (LSFrom == LSTo) -> retrieve_disco_publish({LTo, LSTo}, Node); diff --git a/src/mod_echo.erl b/src/mod_echo.erl index 991788a3f..4eef833e4 100644 --- a/src/mod_echo.erl +++ b/src/mod_echo.erl @@ -118,7 +118,7 @@ handle_cast(_Msg, State) -> %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- handle_info({route, From, To, Packet}, State) -> - Packet2 = case From#jid.node of + Packet2 = case exmpp_jid:node(From) of undefined -> exmpp_stanza:reply_with_error(Packet, 'bad-request'); _ -> Packet end, @@ -174,8 +174,7 @@ do_client_version(disabled, _From, _To) -> do_client_version(enabled, From, To) -> %% It is important to identify this process and packet Random_resource = integer_to_list(random:uniform(100000)), - From2 = From#jid{resource = Random_resource, - lresource = Random_resource}, + From2 = exmpp_jid:bare_jid_to_jid(From,Random_resource), %% Build an iq:query request Request = #xmlel{ns = ?NS_SOFT_VERSION, name = 'query'}, diff --git a/src/mod_irc/mod_irc.erl b/src/mod_irc/mod_irc.erl index 2f2e37780..cadef5e2f 100644 --- a/src/mod_irc/mod_irc.erl +++ b/src/mod_irc/mod_irc.erl @@ -204,7 +204,8 @@ do_route(Host, ServerHost, Access, From, To, Packet, DefEnc) -> end. do_route1(Host, ServerHost, From, To, Packet, DefEnc) -> - #jid{node = ChanServ, resource = Resource} = To, + ChanServ = exmpp_jid:node_as_list(To), + Resource = exmpp_jid:resource_as_list(To), case ChanServ of undefined -> case Resource of @@ -400,8 +401,10 @@ process_irc_register(Host, From, _To, _DefEnc, get_form(Host, From, [], Lang, DefEnc) -> - #jid{node = User, domain = Server, - lnode = LUser, ldomain = LServer} = From, + User = exmpp_jid:node_as_list(From), + Server = exmpp_jid:domain_as_list(From), + LUser = exmpp_jid:lnode_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), US = {LUser, LServer}, Customs = case catch mnesia:dirty_read({irc_custom, {US, Host}}) of @@ -485,7 +488,8 @@ get_form(_Host, _, _, _Lang, _) -> set_form(Host, From, [], _Lang, XData) -> - {LUser, LServer, _} = jlib:short_prepd_jid(From), + LUser = exmpp_jid:lnode_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), US = {LUser, LServer}, case {lists:keysearch("username", 1, XData), lists:keysearch("encodings", 1, XData)} of @@ -529,8 +533,9 @@ set_form(_Host, _, _, _Lang, _XData) -> get_user_and_encoding(Host, From, IRCServer, DefEnc) -> - #jid{node = User, domain = _Server, - lnode = LUser, ldomain = LServer} = From, + User = exmpp_jid:node_as_list(From), + LUser = exmpp_jid:lnode_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), US = {LUser, LServer}, case catch mnesia:dirty_read({irc_custom, {US, Host}}) of {'EXIT', _Reason} -> diff --git a/src/mod_last.erl b/src/mod_last.erl index a08b5404b..85644b775 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -47,6 +47,7 @@ start(Host, Opts) -> + HostB = list_to_binary(Host), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), mnesia:create_table(last_activity, [{disc_copies, [node()]}, @@ -56,15 +57,16 @@ start(Host, Opts) -> ?MODULE, process_local_iq, IQDisc), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY, ?MODULE, process_sm_iq, IQDisc), - ejabberd_hooks:add(remove_user, Host, + ejabberd_hooks:add(remove_user, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:add(unset_presence_hook, Host, + ejabberd_hooks:add(unset_presence_hook, HostB, ?MODULE, on_presence_update, 50). stop(Host) -> - ejabberd_hooks:delete(remove_user, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:delete(remove_user, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:delete(unset_presence_hook, Host, + ejabberd_hooks:delete(unset_presence_hook, HostB, ?MODULE, on_presence_update, 50), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY). @@ -79,27 +81,25 @@ process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> process_sm_iq(From, To, #iq{type = get} = IQ_Rec) -> - User = To#jid.lnode, - Server = To#jid.ldomain, {Subscription, _Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, Server, - {none, []}, [User, Server, From]), + roster_get_jid_info, exmpp_jid:ldomain(To), + {none, []}, [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From]), if (Subscription == both) or (Subscription == from) -> UserListRecord = ejabberd_hooks:run_fold( - privacy_get_user_list, Server, + privacy_get_user_list, exmpp_jid:ldomain(To), #userlist{}, - [User, Server]), + [exmpp_jid:lnode(To), exmpp_jid:ldomain(To)]), case ejabberd_hooks:run_fold( - privacy_check_packet, Server, + privacy_check_packet, exmpp_jid:ldomain(To), allow, - [User, Server, UserListRecord, + [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), UserListRecord, {From, To, exmpp_presence:available()}, out]) of allow -> - get_last(IQ_Rec, User, Server); + get_last(IQ_Rec, exmpp_jid:lnode(To), exmpp_jid:ldomain(To)); deny -> exmpp_iq:error(IQ_Rec, 'not-allowed') end; @@ -133,11 +133,10 @@ on_presence_update(User, Server, _Resource, Status) -> TimeStamp = MegaSecs * 1000000 + Secs, store_last_info(User, Server, TimeStamp, Status). -store_last_info(User, Server, TimeStamp, Status) -> +store_last_info(User, Server, TimeStamp, Status) + when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - US = {LUser, LServer}, + US = {User, Server}, F = fun() -> mnesia:write(#last_activity{us = US, timestamp = TimeStamp, @@ -150,7 +149,7 @@ store_last_info(User, Server, TimeStamp, Status) -> end. %% Returns: {ok, Timestamp, Status} | not_found -get_last_info(LUser, LServer) -> +get_last_info(LUser, LServer) when is_binary(LUser), is_binary(LServer) -> case catch mnesia:dirty_read(last_activity, {LUser, LServer}) of {'EXIT', _Reason} -> not_found; @@ -160,7 +159,7 @@ get_last_info(LUser, LServer) -> {ok, TimeStamp, Status} end. -remove_user(User, Server) -> +remove_user(User, Server) when is_binary(User), is_binary(Server) -> try LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), @@ -250,7 +249,8 @@ convert_to_exmpp2(#last_activity{us = {U, S} = Key, status = Status} = LA, % Convert status. Status1 = list_to_binary(Status), % Prepare the new record. - New_LA = LA#last_activity{us = {U1, S}, status = Status1}, + New_LA = LA#last_activity{us = {list_to_binary(U1), list_to_binary(S)}, + status = Status1}, % Write the new record. mnesia:write(New_LA), Acc. diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 64569fd69..1dca155e8 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -44,20 +44,22 @@ -include("mod_privacy.hrl"). start(Host, Opts) -> + HostB = list_to_binary(Host), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY, ?MODULE, process_local_iq, IQDisc), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY, ?MODULE, process_sm_iq, IQDisc), - ejabberd_hooks:add(remove_user, Host, + ejabberd_hooks:add(remove_user, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:add(unset_presence_hook, Host, + ejabberd_hooks:add(unset_presence_hook, HostB, ?MODULE, on_presence_update, 50). stop(Host) -> - ejabberd_hooks:delete(remove_user, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:delete(remove_user, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:delete(unset_presence_hook, Host, + ejabberd_hooks:delete(unset_presence_hook, HostB, ?MODULE, on_presence_update, 50), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY). @@ -71,22 +73,22 @@ process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> exmpp_iq:error(IQ_Rec, 'not-allowed'). process_sm_iq(From, To, #iq{type = get} = IQ_Rec) -> - User = To#jid.lnode, - Server = To#jid.ldomain, + User = exmpp_jid:lnode_as_list(To), + Server = exmpp_jid:ldomain_as_list(To), {Subscription, _Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, Server, - {none, []}, [User, Server, From]), + roster_get_jid_info, exmpp_jid:ldomain(To), + {none, []}, [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From]), if (Subscription == both) or (Subscription == from) -> UserListRecord = ejabberd_hooks:run_fold( - privacy_get_user_list, Server, + privacy_get_user_list, exmpp_jid:ldomain(To), #userlist{}, - [User, Server]), + [exmpp_jid:lnode(To), exmpp_jid:ldomain(To)]), case ejabberd_hooks:run_fold( - privacy_check_packet, Server, + privacy_check_packet, exmpp_jid:ldomain(To), allow, - [User, Server, UserListRecord, + [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), UserListRecord, {From, To, exmpp_presence:available()}, out]) of @@ -129,13 +131,17 @@ on_presence_update(User, Server, _Resource, Status) -> TimeStamp = MegaSecs * 1000000 + Secs, store_last_info(User, Server, TimeStamp, Status). -store_last_info(User, Server, TimeStamp, Status) -> +store_last_info(User, Server, TimeStamp, Status) + when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), + %LUser = exmpp_stringprep:nodeprep(User), + %LServer = exmpp_stringprep:nameprep(Server), + LUser = binary_to_list(User), + LServer = binary_to_list(Server), + Username = ejabberd_odbc:escape(LUser), Seconds = ejabberd_odbc:escape(integer_to_list(TimeStamp)), - State = ejabberd_odbc:escape(binary_to_list(Status)), + State = ejabberd_odbc:escape(Status), odbc_queries:set_last_t(LServer, Username, Seconds, State) catch _ -> @@ -151,7 +157,7 @@ get_last_info(LUser, LServer) -> {selected, ["seconds","state"], [{STimeStamp, Status}]} -> case catch list_to_integer(STimeStamp) of TimeStamp when is_integer(TimeStamp) -> - {ok, TimeStamp, list_to_binary(Status)}; + {ok, TimeStamp, Status}; _ -> not_found end; diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index 57232f994..e55b19afb 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -136,7 +136,7 @@ process_iq_disco_items(Host, From, To, #iq{} = IQ) -> can_use_nick(_Host, _JID, "") -> false; can_use_nick(Host, JID, Nick) -> - LUS = {JID#jid.lnode, JID#jid.ldomain}, + LUS = {exmpp_jid:lnode_as_list(JID), exmpp_jid:ldomain_as_list(JID)}, case catch mnesia:dirty_select( muc_registered, [{#muc_registered{us_host = '$1', @@ -312,8 +312,8 @@ do_route(Host, ServerHost, Access, HistorySize, RoomShaper, do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, From, To, Packet, DefRoomOpts) -> {_AccessRoute, AccessCreate, AccessAdmin, _AccessPersistent} = Access, - Room = To#jid.lnode, - Nick = To#jid.lresource, + Room = exmpp_jid:lnode_as_list(To), + Nick = exmpp_jid:lresource_as_list(To), #xmlel{name = Name} = Packet, case Room of 'undefined' -> @@ -554,8 +554,8 @@ flush() -> children = [#xmlcdata{cdata = Val}]}]}). iq_get_register_info(Host, From, Lang) -> - LUser = From#jid.lnode, - LServer = From#jid.ldomain, + LUser = exmpp_jid:lnode_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), LUS = {LUser, LServer}, {Nick, Registered} = case catch mnesia:dirty_read(muc_registered, {LUS, Host}) of @@ -584,8 +584,8 @@ iq_get_register_info(Host, From, Lang) -> iq_set_register_info(Host, From, Nick, Lang) -> - LUser = From#jid.lnode, - LServer = From#jid.ldomain, + LUser = exmpp_jid:lnode_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), LUS = {LUser, LServer}, F = fun() -> case Nick of diff --git a/src/mod_muc/mod_muc_log.erl b/src/mod_muc/mod_muc_log.erl index 2c4dc8c70..328f8b736 100644 --- a/src/mod_muc/mod_muc_log.erl +++ b/src/mod_muc/mod_muc_log.erl @@ -272,7 +272,7 @@ build_filename_string(TimeStamp, OutDir, RoomJID, DirType, DirName, FileFormat) get_room_name(RoomJID) -> JID = exmpp_jid:list_to_jid(RoomJID), - JID#jid.node. + exmpp_jid:node_as_list(JID). %% calculate day before get_timestamp_daydiff(TimeStamp, Daydiff) -> diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 70babd033..8368c4c05 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -261,6 +261,7 @@ normal_state({route, From, undefined, StateData#state.jid, From, exmpp_stanza:reply_with_error(Packet, Err)), {next_state, normal_state, StateData}; + %%TODO: currently exmpp_message:get_type/1 never returns 'undefined' Type when (Type == 'normal') orelse (Type == 'undefined') -> case catch check_invitation(From, exmpp_xml:get_child_elements(Packet), @@ -2139,11 +2140,16 @@ process_admin_items_set(UJID, Items, Lang, StateData) -> fun(E, SD) -> case catch ( case E of - {JID, affiliation, owner, _} - when (JID#jid.lnode == "") -> + {JID, affiliation, owner, _} -> + case exmpp_jid:lnode(JID) of + <<>> -> + SD; + %% TODO: <<>> or 'undefined' ? + %% TODO: double case on the E var, because + %% exmpp_jid:lnode/1 can't be used in guards %% If the provided JID does not have username, %% forget the affiliation completely - SD; + _ -> case E of {JID, role, none, Reason} -> catch send_kickban_presence( JID, Reason, "307", SD), @@ -2187,6 +2193,8 @@ process_admin_items_set(UJID, Items, Lang, StateData) -> send_update_presence(JID, SD1), SD1 end + end + end ) of {'EXIT', ErrReason} -> ?ERROR_MSG("MUC ITEMS SET ERR: ~p~n", @@ -3285,7 +3293,7 @@ check_invitation(From, Els, Lang, StateData) -> _ -> [" (", Reason, ") "] end ])}]}, - %%TODO: always NS_JABER_CLIENT? + %%TODO: always NS_JABBER_CLIENT? Msg = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', attrs = [#xmlattr{name = 'type', value = "normal"}], @@ -3370,8 +3378,8 @@ add_to_log(Type, Data, StateData) -> %% Users number checking tab_add_online_user(JID, StateData) -> - LUser = JID#jid.lnode, - LServer = JID#jid.ldomain, + LUser = exmpp_jid:lnode(JID), + LServer = exmpp_jid:ldomain(JID), US = {LUser, LServer}, Room = StateData#state.room, Host = StateData#state.host, @@ -3381,7 +3389,9 @@ tab_add_online_user(JID, StateData) -> -tab_remove_online_user(#jid{lnode = LUser, ldomain = LServer}, StateData) -> +tab_remove_online_user(JID, StateData) when ?IS_JID(JID) -> + LUser = exmpp_jid:lnode(JID), + LServer = exmpp_jid:ldomain(JID), tab_remove_online_user({LUser, LServer, none},StateData); tab_remove_online_user({LUser, LServer,_}, StateData) -> @@ -3393,8 +3403,8 @@ tab_remove_online_user({LUser, LServer,_}, StateData) -> #muc_online_users{us = US, room = Room, host = Host}). tab_count_user(JID) -> - LUser = JID#jid.lnode, - LServer = JID#jid.ldomain, + LUser = exmpp_jid:lnode(JID), + LServer = exmpp_jid:ldomain(JID), US = {LUser, LServer}, case catch ets:select( muc_online_users, @@ -3407,11 +3417,7 @@ tab_count_user(JID) -> jid_replace_resource(JID, Resource) -> - case exmpp_stringprep:resourceprep(Resource) of - error -> error; - LResource -> - JID#jid{resource = Resource, lresource = LResource} - end. + exmpp_jid:bare_jid_to_jid(JID, Resource). diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 129c41b52..e0dc642da 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -59,24 +59,25 @@ -define(PREFIXED_NS, [{?NS_XMPP, ?NS_XMPP_pfx}]). start(Host, Opts) -> + HostB = list_to_binary(Host), mnesia:create_table(offline_msg, [{disc_only_copies, [node()]}, {type, bag}, {attributes, record_info(fields, offline_msg)}]), update_table(), - ejabberd_hooks:add(offline_message_hook, Host, + ejabberd_hooks:add(offline_message_hook, HostB, ?MODULE, store_packet, 50), - ejabberd_hooks:add(resend_offline_messages_hook, Host, + ejabberd_hooks:add(resend_offline_messages_hook, HostB, ?MODULE, pop_offline_messages, 50), - ejabberd_hooks:add(remove_user, Host, + ejabberd_hooks:add(remove_user, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:add(anonymous_purge_hook, Host, + ejabberd_hooks:add(anonymous_purge_hook, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:add(webadmin_page_host, Host, + ejabberd_hooks:add(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), - ejabberd_hooks:add(webadmin_user, Host, + ejabberd_hooks:add(webadmin_user, HostB, ?MODULE, webadmin_user, 50), - ejabberd_hooks:add(webadmin_user_parse_query, Host, + ejabberd_hooks:add(webadmin_user_parse_query, HostB, ?MODULE, webadmin_user_parse_query, 50), MaxOfflineMsgs = gen_mod:get_opt(user_max_messages, Opts, infinity), register(gen_mod:get_module_proc(Host, ?PROCNAME), @@ -134,19 +135,20 @@ receive_all(US, Msgs) -> stop(Host) -> - ejabberd_hooks:delete(offline_message_hook, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:delete(offline_message_hook, HostB, ?MODULE, store_packet, 50), - ejabberd_hooks:delete(resend_offline_messages_hook, Host, + ejabberd_hooks:delete(resend_offline_messages_hook, HostB, ?MODULE, pop_offline_messages, 50), - ejabberd_hooks:delete(remove_user, Host, + ejabberd_hooks:delete(remove_user, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:delete(anonymous_purge_hook, Host, + ejabberd_hooks:delete(anonymous_purge_hook, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:delete(webadmin_page_host, Host, + ejabberd_hooks:delete(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), - ejabberd_hooks:delete(webadmin_user, Host, + ejabberd_hooks:delete(webadmin_user, HostB, ?MODULE, webadmin_user, 50), - ejabberd_hooks:delete(webadmin_user_parse_query, Host, + ejabberd_hooks:delete(webadmin_user_parse_query, HostB, ?MODULE, webadmin_user_parse_query, 50), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), exit(whereis(Proc), stop), @@ -159,10 +161,11 @@ store_packet(From, To, Packet) -> (Type /= "headline") -> case check_event(From, To, Packet) of true -> - #jid{lnode = LUser, ldomain = LServer} = To, + LUser = exmpp_jid:lnode_as_list(To), + LServer = exmpp_jid:ldomain_as_list(To), TimeStamp = now(), Expire = find_x_expire(TimeStamp, Packet#xmlel.children), - gen_mod:get_module_proc(To#jid.ldomain, ?PROCNAME) ! + gen_mod:get_module_proc(LServer, ?PROCNAME) ! #offline_msg{us = {LUser, LServer}, timestamp = TimeStamp, expire = Expire, @@ -267,10 +270,11 @@ resend_offline_messages(User, Server) -> ok end. -pop_offline_messages(Ls, User, Server) -> +pop_offline_messages(Ls, User, Server) + when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), + LUser = binary_to_list(User), + LServer = binary_to_list(Server), US = {LUser, LServer}, F = fun() -> Rs = mnesia:wread({offline_msg, US}), @@ -347,7 +351,7 @@ remove_old_messages(Days) -> end, mnesia:transaction(F). -remove_user(User, Server) -> +remove_user(User, Server) when is_binary(User), is_binary(Server) -> try LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index bb54951d2..4f121e0af 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -58,19 +58,20 @@ -define(PREFIXED_NS, [{?NS_XMPP, ?NS_XMPP_pfx}]). start(Host, Opts) -> - ejabberd_hooks:add(offline_message_hook, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:add(offline_message_hook, HostB, ?MODULE, store_packet, 50), - ejabberd_hooks:add(resend_offline_messages_hook, Host, + ejabberd_hooks:add(resend_offline_messages_hook, HostB, ?MODULE, pop_offline_messages, 50), - ejabberd_hooks:add(remove_user, Host, + ejabberd_hooks:add(remove_user, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:add(anonymous_purge_hook, Host, + ejabberd_hooks:add(anonymous_purge_hook, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:add(webadmin_page_host, Host, + ejabberd_hooks:add(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), - ejabberd_hooks:add(webadmin_user, Host, + ejabberd_hooks:add(webadmin_user, HostB, ?MODULE, webadmin_user, 50), - ejabberd_hooks:add(webadmin_user_parse_query, Host, + ejabberd_hooks:add(webadmin_user_parse_query, HostB, ?MODULE, webadmin_user_parse_query, 50), MaxOfflineMsgs = gen_mod:get_opt(user_max_messages, Opts, infinity), register(gen_mod:get_module_proc(Host, ?PROCNAME), @@ -102,7 +103,7 @@ loop(Host, MaxOfflineMsgs) -> fun(M) -> Username = ejabberd_odbc:escape( - (M#offline_msg.to)#jid.lnode), + exmpp_jid:lnode_as_list(M#offline_msg.to)), From = M#offline_msg.from, To = M#offline_msg.to, Packet0 = exmpp_stanza:set_jids( @@ -142,19 +143,20 @@ receive_all(Username, Msgs) -> stop(Host) -> - ejabberd_hooks:delete(offline_message_hook, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:delete(offline_message_hook, HostB, ?MODULE, store_packet, 50), - ejabberd_hooks:delete(resend_offline_messages_hook, Host, + ejabberd_hooks:delete(resend_offline_messages_hook, HostB, ?MODULE, pop_offline_messages, 50), - ejabberd_hooks:delete(remove_user, Host, + ejabberd_hooks:delete(remove_user, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:delete(anonymous_purge_hook, Host, + ejabberd_hooks:delete(anonymous_purge_hook, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:delete(webadmin_page_host, Host, + ejabberd_hooks:delete(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), - ejabberd_hooks:delete(webadmin_user, Host, + ejabberd_hooks:delete(webadmin_user, HostB, ?MODULE, webadmin_user, 50), - ejabberd_hooks:delete(webadmin_user_parse_query, Host, + ejabberd_hooks:delete(webadmin_user_parse_query, HostB, ?MODULE, webadmin_user_parse_query, 50), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), exit(whereis(Proc), stop), @@ -167,10 +169,10 @@ store_packet(From, To, Packet) -> (Type /= "headline") -> case check_event(From, To, Packet) of true -> - #jid{lnode = LUser} = To, + LUser = exmpp_jid:lnode_as_list(To), TimeStamp = now(), Expire = find_x_expire(TimeStamp, Packet#xmlel.children), - gen_mod:get_module_proc(To#jid.ldomain, ?PROCNAME) ! + gen_mod:get_module_proc(exmpp_jid:ldomain_as_list(To), ?PROCNAME) ! #offline_msg{user = LUser, timestamp = TimeStamp, expire = Expire, @@ -241,17 +243,20 @@ find_x_expire(TimeStamp, [_ | Els]) -> find_x_expire(TimeStamp, Els). -pop_offline_messages(Ls, User, Server) -> +pop_offline_messages(Ls, User, Server) + when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), + LUser = binary_to_list(User), + LServer = binary_to_list(Server), EUser = ejabberd_odbc:escape(LUser), case odbc_queries:get_and_del_spool_msg_t(LServer, EUser) of {atomic, {selected, ["username","xml"], Rs}} -> Ls ++ lists:flatmap( fun({_, XML}) -> try - [El] = exmpp_xml:parse_document(XML, [names_as_atom]), + [El] = exmpp_xml:parse_document(XML, + [names_as_atom, {check_elems, xmpp}, + {check_nss,xmpp}, {check_attrs,xmpp}]), To = exmpp_jid:list_to_jid( exmpp_stanza:get_recipient(El)), From = exmpp_jid:list_to_jid( @@ -271,7 +276,8 @@ pop_offline_messages(Ls, User, Server) -> end. -remove_user(User, Server) -> +remove_user(User, Server) + when is_binary(User), is_binary(Server) -> try LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), @@ -327,7 +333,9 @@ user_queue(User, Server, Query, Lang) -> {selected, ["username", "xml"], Rs} -> lists:flatmap( fun({_, XML}) -> - try exmpp_xml:parse_document(XML, [names_as_atom]) of + try exmpp_xml:parse_document(XML, + [names_as_atom, {check_elems, xmpp}, + {check_nss,xmpp}, {check_attrs,xmpp}]) of [El] -> [El] catch @@ -394,7 +402,9 @@ user_queue_parse_query(Username, LServer, Query) -> {selected, ["xml", "seq"], Rs} -> lists:flatmap( fun({XML, Seq}) -> - try exmpp_xml:parse_document(XML, [names_as_atom]) of + try exmpp_xml:parse_document(XML, + [names_as_atom, {check_elems, xmpp}, + {check_nss,xmpp}, {check_attrs,xmpp}]) of [El] -> [{El, Seq}] catch diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index ecd1006f4..674bdd0c6 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -44,33 +44,35 @@ start(Host, Opts) -> + HostB = list_to_binary(Host), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), mnesia:create_table(privacy, [{disc_copies, [node()]}, {attributes, record_info(fields, privacy)}]), update_table(), - ejabberd_hooks:add(privacy_iq_get, Host, + ejabberd_hooks:add(privacy_iq_get, HostB, ?MODULE, process_iq_get, 50), - ejabberd_hooks:add(privacy_iq_set, Host, + ejabberd_hooks:add(privacy_iq_set, HostB, ?MODULE, process_iq_set, 50), - ejabberd_hooks:add(privacy_get_user_list, Host, + ejabberd_hooks:add(privacy_get_user_list, HostB, ?MODULE, get_user_list, 50), - ejabberd_hooks:add(privacy_check_packet, Host, + ejabberd_hooks:add(privacy_check_packet, HostB, ?MODULE, check_packet, 50), - ejabberd_hooks:add(privacy_updated_list, Host, + ejabberd_hooks:add(privacy_updated_list, HostB, ?MODULE, updated_list, 50), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PRIVACY, ?MODULE, process_iq, IQDisc). stop(Host) -> - ejabberd_hooks:delete(privacy_iq_get, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:delete(privacy_iq_get, HostB, ?MODULE, process_iq_get, 50), - ejabberd_hooks:delete(privacy_iq_set, Host, + ejabberd_hooks:delete(privacy_iq_set, HostB, ?MODULE, process_iq_set, 50), - ejabberd_hooks:delete(privacy_get_user_list, Host, + ejabberd_hooks:delete(privacy_get_user_list, HostB, ?MODULE, get_user_list, 50), - ejabberd_hooks:delete(privacy_check_packet, Host, + ejabberd_hooks:delete(privacy_check_packet, HostB, ?MODULE, check_packet, 50), - ejabberd_hooks:delete(privacy_updated_list, Host, + ejabberd_hooks:delete(privacy_updated_list, HostB, ?MODULE, updated_list, 50), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVACY). @@ -80,7 +82,8 @@ process_iq(_From, _To, IQ_Rec) -> process_iq_get(_, From, _To, #iq{payload = SubEl}, #userlist{name = Active}) -> - #jid{lnode = LUser, ldomain = LServer} = From, + LUser = exmpp_jid:lnode_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), case exmpp_xml:get_child_elements(SubEl) of [] -> process_lists_get(LUser, LServer, Active); @@ -238,7 +241,8 @@ list_to_action(S) -> process_iq_set(_, From, _To, #iq{payload = SubEl}) -> - #jid{lnode = LUser, ldomain = LServer} = From, + LUser = exmpp_jid:lnode_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), case exmpp_xml:get_child_elements(SubEl) of [#xmlel{name = Name} = Child] -> ListName = exmpp_xml:get_attribute(Child, 'name', false), @@ -510,10 +514,11 @@ parse_matches1(_Item, [#xmlel{} | _Els]) -> -get_user_list(_, User, Server) -> +get_user_list(_, User, Server) + when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), + LUser = binary_to_list(User), + LServer = binary_to_list(Server), case catch mnesia:dirty_read(privacy, {LUser, LServer}) of [] -> #userlist{}; @@ -542,7 +547,8 @@ get_user_list(_, User, Server) -> check_packet(_, User, Server, #userlist{list = List}, {From, To, #xmlel{name = PName}}, - Dir) when PName =:= message ; + Dir) when + PName =:= message ; PName =:= iq ; PName =:= presence -> case List of @@ -554,7 +560,8 @@ check_packet(_, User, Server, LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, exmpp_stringprep:nameprep(Server), + roster_get_jid_info, + Server, {none, []}, [User, Server, From]), check_packet_aux(List, message, LJID, Subscription, Groups); @@ -562,7 +569,8 @@ check_packet(_, User, Server, LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, exmpp_stringprep:nameprep(Server), + roster_get_jid_info, + Server, {none, []}, [User, Server, From]), check_packet_aux(List, iq, LJID, Subscription, Groups); @@ -570,7 +578,8 @@ check_packet(_, User, Server, LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, exmpp_stringprep:nameprep(Server), + roster_get_jid_info, + Server, {none, []}, [User, Server, From]), check_packet_aux(List, presence_in, LJID, Subscription, Groups); @@ -578,7 +587,8 @@ check_packet(_, User, Server, LJID = jlib:short_prepd_jid(To), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, exmpp_stringprep:nameprep(Server), + roster_get_jid_info, + Server, {none, []}, [User, Server, To]), check_packet_aux(List, presence_out, LJID, Subscription, Groups); diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 57af4fc30..67a8e6a33 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -43,30 +43,32 @@ -include("mod_privacy.hrl"). start(Host, Opts) -> + HostB = list_to_binary(Host), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - ejabberd_hooks:add(privacy_iq_get, Host, + ejabberd_hooks:add(privacy_iq_get, HostB, ?MODULE, process_iq_get, 50), - ejabberd_hooks:add(privacy_iq_set, Host, + ejabberd_hooks:add(privacy_iq_set, HostB, ?MODULE, process_iq_set, 50), - ejabberd_hooks:add(privacy_get_user_list, Host, + ejabberd_hooks:add(privacy_get_user_list, HostB, ?MODULE, get_user_list, 50), - ejabberd_hooks:add(privacy_check_packet, Host, + ejabberd_hooks:add(privacy_check_packet, HostB, ?MODULE, check_packet, 50), - ejabberd_hooks:add(privacy_updated_list, Host, + ejabberd_hooks:add(privacy_updated_list, HostB, ?MODULE, updated_list, 50), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PRIVACY, ?MODULE, process_iq, IQDisc). stop(Host) -> - ejabberd_hooks:delete(privacy_iq_get, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:delete(privacy_iq_get, HostB, ?MODULE, process_iq_get, 50), - ejabberd_hooks:delete(privacy_iq_set, Host, + ejabberd_hooks:delete(privacy_iq_set, HostB, ?MODULE, process_iq_set, 50), - ejabberd_hooks:delete(privacy_get_user_list, Host, + ejabberd_hooks:delete(privacy_get_user_list, HostB, ?MODULE, get_user_list, 50), - ejabberd_hooks:delete(privacy_check_packet, Host, + ejabberd_hooks:delete(privacy_check_packet, HostB, ?MODULE, check_packet, 50), - ejabberd_hooks:delete(privacy_updated_list, Host, + ejabberd_hooks:delete(privacy_updated_list, HostB, ?MODULE, updated_list, 50), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVACY). @@ -76,7 +78,8 @@ process_iq(_From, _To, IQ_Rec) -> process_iq_get(_, From, _To, #iq{payload = SubEl}, #userlist{name = Active}) -> - #jid{lnode = LUser, ldomain = LServer} = From, + LUser = exmpp_jid:lnode_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), case exmpp_xml:get_child_elements(SubEl) of [] -> process_lists_get(LUser, LServer, Active); @@ -244,7 +247,8 @@ list_to_action(S) -> process_iq_set(_, From, _To, #iq{payload = SubEl}) -> - #jid{lnode = LUser, ldomain = LServer} = From, + LUser = exmpp_jid:lnode_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), case exmpp_xml:get_child_elements(SubEl) of [#xmlel{name = Name} = Child] -> ListName = exmpp_xml:get_attribute(Child, 'name', false), @@ -511,10 +515,11 @@ parse_matches1(_Item, [#xmlel{} | _Els]) -> -get_user_list(_, User, Server) -> +get_user_list(_, User, Server) + when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), + LUser = binary_to_list(User), + LServer = binary_to_list(Server), case catch sql_get_default_privacy_list(LUser, LServer) of {selected, ["name"], []} -> #userlist{}; @@ -541,7 +546,8 @@ get_user_list(_, User, Server) -> check_packet(_, User, Server, #userlist{list = List}, {From, To, #xmlel{name = PName}}, - Dir) when PName =:= message ; + Dir) when + PName =:= message ; PName =:= iq ; PName =:= presence -> case List of @@ -553,7 +559,8 @@ check_packet(_, User, Server, LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, exmpp_stringprep:nameprep(Server), + roster_get_jid_info, + Server, {none, []}, [User, Server, From]), check_packet_aux(List, message, LJID, Subscription, Groups); @@ -561,7 +568,8 @@ check_packet(_, User, Server, LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, exmpp_stringprep:nameprep(Server), + roster_get_jid_info, + Server, {none, []}, [User, Server, From]), check_packet_aux(List, iq, LJID, Subscription, Groups); @@ -569,7 +577,8 @@ check_packet(_, User, Server, LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, exmpp_stringprep:nameprep(Server), + roster_get_jid_info, + Server, {none, []}, [User, Server, From]), check_packet_aux(List, presence_in, LJID, Subscription, Groups); @@ -577,7 +586,8 @@ check_packet(_, User, Server, LJID = jlib:short_prepd_jid(To), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, exmpp_stringprep:nameprep(Server), + roster_get_jid_info, + Server, {none, []}, [User, Server, To]), check_packet_aux(List, presence_out, LJID, Subscription, Groups); diff --git a/src/mod_private.erl b/src/mod_private.erl index f88bc3b4d..a2c37a7bc 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -41,18 +41,20 @@ -record(private_storage, {usns, xml}). start(Host, Opts) -> + HostB = list_to_binary(Host), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), mnesia:create_table(private_storage, [{disc_only_copies, [node()]}, {attributes, record_info(fields, private_storage)}]), update_table(), - ejabberd_hooks:add(remove_user, Host, + ejabberd_hooks:add(remove_user, HostB, ?MODULE, remove_user, 50), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE, ?MODULE, process_sm_iq, IQDisc). stop(Host) -> - ejabberd_hooks:delete(remove_user, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:delete(remove_user, HostB, ?MODULE, remove_user, 50), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE). @@ -71,7 +73,8 @@ process_sm_iq(From, To, #iq{type = Type} = IQ_Rec) -> end. process_iq_get(From, _To, #iq{payload = SubEl} = IQ_Rec) -> - #jid{lnode = LUser, ldomain = LServer} = From, + LUser = exmpp_jid:lnode_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), case catch get_data(LUser, LServer, exmpp_xml:get_child_elements(SubEl)) of @@ -85,7 +88,8 @@ process_iq_get(From, _To, #iq{payload = SubEl} = IQ_Rec) -> process_iq_set(From, _To, #iq{payload = SubEl} = IQ_Rec) -> - #jid{lnode = LUser, ldomain = LServer} = From, + LUser = exmpp_jid:lnode_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), F = fun() -> lists:foreach( fun(El) -> @@ -108,7 +112,8 @@ check_packet(From, To, IQ_Rec, [F | R]) -> ok -> check_packet(From, To, IQ_Rec, R) end. -check_domain(#jid{ldomain = LServer}, _To, _IQ_Rec) -> +check_domain(From, _To, _IQ_Rec) -> + LServer = exmpp_jid:ldomain_as_list(From), case lists:member(LServer, ?MYHOSTS) of true -> ok; false -> {error, 'not-allowed'} @@ -158,7 +163,8 @@ get_data(LUser, LServer, [El | Els], Res) -> [El | Res]) end. -remove_user(User, Server) -> +remove_user(User, Server) + when is_binary(User), is_binary(Server) -> try LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), diff --git a/src/mod_private_odbc.erl b/src/mod_private_odbc.erl index 94e4b6eeb..622b0df0b 100644 --- a/src/mod_private_odbc.erl +++ b/src/mod_private_odbc.erl @@ -39,14 +39,16 @@ -include("ejabberd.hrl"). start(Host, Opts) -> + HostB = list_to_binary(Host), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - ejabberd_hooks:add(remove_user, Host, + ejabberd_hooks:add(remove_user, HostB, ?MODULE, remove_user, 50), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE, ?MODULE, process_sm_iq, IQDisc). stop(Host) -> - ejabberd_hooks:delete(remove_user, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:delete(remove_user, HostB, ?MODULE, remove_user, 50), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE). @@ -65,7 +67,8 @@ process_sm_iq(From, To, #iq{type = Type} = IQ_Rec) -> end. process_iq_get(From, _To, #iq{payload = SubEl} = IQ_Rec) -> - #jid{lnode = LUser, ldomain = LServer} = From, + LUser = exmpp_jid:lnode_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), case catch get_data(LUser, LServer, exmpp_xml:get_child_elements(SubEl)) of @@ -79,7 +82,8 @@ process_iq_get(From, _To, #iq{payload = SubEl} = IQ_Rec) -> process_iq_set(From, _To, #iq{payload = SubEl} = IQ_Rec) -> - #jid{lnode = LUser, ldomain = LServer} = From, + LUser = exmpp_jid:lnode_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), F = fun() -> lists:foreach( fun(El) -> @@ -102,7 +106,8 @@ check_packet(From, To, IQ_Rec, [F | R]) -> ok -> check_packet(From, To, IQ_Rec, R) end. -check_domain(#jid{ldomain = LServer}, _To, _IQ_Rec) -> +check_domain(From, _To, _IQ_Rec) -> + LServer = exmpp_jid:ldomain_as_list(From), case lists:member(LServer, ?MYHOSTS) of true -> ok; false -> {error, 'not-allowed'} @@ -151,7 +156,9 @@ get_data(LUser, LServer, [El | Els], Res) -> LXMLNS = ejabberd_odbc:escape(XMLNS), case catch odbc_queries:get_private_data(LServer, Username, LXMLNS) of {selected, ["data"], [{SData}]} -> - [Data] = exmpp_xml:parse_document(SData,[names_as_atom]), + [Data] = exmpp_xml:parse_document(SData, + [names_as_atom, {check_elems, xmpp}, + {check_nss,xmpp}, {check_attrs,xmpp}]), get_data(LUser, LServer, Els, [Data | Res]); %% MREMOND: I wonder when the query could return a vcard ? {selected, ["vcard"], []} -> @@ -162,7 +169,7 @@ get_data(LUser, LServer, [El | Els], Res) -> end. -remove_user(User, Server) -> +remove_user(User, Server) when is_binary(User), is_binary(Server) -> try LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 6e0617813..2e3e0ad02 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -631,7 +631,7 @@ get_states(Host, Node) -> get_state(Host, Node, JID) -> StateId = {JID, {Host, Node}}, case mnesia:read({pubsub_state, StateId}) of - [State] when is_record(State, pubsub_state) -> State + [State] when is_record(State, pubsub_state) -> State; _ -> #pubsub_state{stateid=StateId} end. diff --git a/src/mod_register.erl b/src/mod_register.erl index 49c3b209b..2f1d37b38 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -40,14 +40,15 @@ -include("ejabberd.hrl"). start(Host, Opts) -> + HostB = list_to_binary(Host), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_INBAND_REGISTER, ?MODULE, process_iq, IQDisc), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_INBAND_REGISTER, ?MODULE, process_iq, IQDisc), - ejabberd_hooks:add(c2s_stream_features, Host, + ejabberd_hooks:add(c2s_stream_features, HostB, ?MODULE, stream_feature_register, 50), - ejabberd_hooks:add(c2s_unauthenticated_iq, Host, + ejabberd_hooks:add(c2s_unauthenticated_iq, HostB, ?MODULE, unauthenticated_iq_register, 50), mnesia:create_table(mod_register_ip, [{ram_copies, [node()]}, @@ -57,9 +58,10 @@ start(Host, Opts) -> ok. stop(Host) -> - ejabberd_hooks:delete(c2s_stream_features, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:delete(c2s_stream_features, HostB, ?MODULE, stream_feature_register, 50), - ejabberd_hooks:delete(c2s_unauthenticated_iq, Host, + ejabberd_hooks:delete(c2s_unauthenticated_iq, HostB, ?MODULE, unauthenticated_iq_register, 50), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_INBAND_REGISTER), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_INBAND_REGISTER). @@ -74,17 +76,20 @@ unauthenticated_iq_register(_Acc, {A, _Port} -> A; _ -> undefined end, - ResIQ = process_iq(#jid{}, - exmpp_jid:make_bare_jid(Server), + BareJID = exmpp_jid:make_bare_jid(Server), + ResIQ = process_iq(exmpp_jid:make_jid(), + BareJID, IQ_Rec, Address), - exmpp_iq:iq_to_xmlel(ResIQ, exmpp_jid:make_bare_jid(Server), undefined); + exmpp_iq:iq_to_xmlel(ResIQ, BareJID, undefined); unauthenticated_iq_register(Acc, _Server, _IQ, _IP) -> Acc. process_iq(From, To, IQ) -> - process_iq(From, To, IQ, jlib:short_prepd_bare_jid(From)). + process_iq(From, To, IQ, {exmpp_jid:lnode_as_list(From), + exmpp_jid:ldomain_as_list(From), + exmpp_jid:lresource_as_list(From)}). process_iq(From, To, #iq{type = Type, lang = Lang, payload = SubEl} = IQ_Rec, @@ -94,12 +99,12 @@ process_iq(From, To, UTag = exmpp_xml:get_element(SubEl, 'username'), PTag = exmpp_xml:get_element(SubEl, 'password'), RTag = exmpp_xml:get_element(SubEl, 'remove'), - Server = To#jid.ldomain, + Server = exmpp_jid:ldomain_as_list(To), if (UTag /= undefined) and (RTag /= undefined) -> User = exmpp_xml:get_cdata_as_list(UTag), - case From of - #jid{node = User, ldomain = Server} -> + case {exmpp_jid:node_as_list(From), exmpp_jid:ldomain_as_list(From)} of + {User, Server} -> ejabberd_auth:remove_user(User, Server), exmpp_iq:result(IQ_Rec, SubEl); _ -> @@ -132,14 +137,18 @@ process_iq(From, To, end end; (UTag == undefined) and (RTag /= undefined) -> - case From of - #jid{node = User, - ldomain = Server, - resource = Resource} -> + case {exmpp_jid:node_as_list(From), + exmpp_jid:ldomain_as_list(From), + exmpp_jid:resource_as_list(From)}of + {User, Server, Resource} -> ResIQ = exmpp_iq:result(IQ_Rec, SubEl), ejabberd_router:route( - exmpp_jid:make_jid(User, Server, Resource), - exmpp_jid:make_jid(User, Server, Resource), + exmpp_jid:make_jid(User, + Server, + Resource), + exmpp_jid:make_jid(User, + Server, + Resource), exmpp_iq:iq_to_xmlel(ResIQ)), ejabberd_auth:remove_user(User, Server), ignore; @@ -149,8 +158,8 @@ process_iq(From, To, (UTag /= undefined) and (PTag /= undefined) -> User = exmpp_xml:get_cdata_as_list(UTag), Password = exmpp_xml:get_cdata_as_list(PTag), - case From of - #jid{node = User, ldomain = Server} -> + case {exmpp_jid:node_as_list(From), exmpp_jid:ldomain_as_list(From)} of + {User, Server} -> try_set_password(User, Server, Password, IQ_Rec, SubEl); _ -> case try_register(User, Server, Password, @@ -195,7 +204,8 @@ try_register(User, Server, Password, Source, Lang) -> false -> {error, 'bad-request'}; _ -> - JID = exmpp_jid:make_bare_jid(User, Server), + JID = exmpp_jid:make_bare_jid(User, + Server), Access = gen_mod:get_module_opt(Server, ?MODULE, access, all), case acl:match_rule(Server, Access, JID) of deny -> @@ -205,8 +215,8 @@ try_register(User, Server, Password, Source, Lang) -> true -> case ejabberd_auth:try_register(User, Server, Password) of {atomic, ok} -> - ejabberd_hooks:run(user_registered, Server, - [User, Server]), + ejabberd_hooks:run(user_registered, exmpp_jid:domain(JID), + [exmpp_jid:node(JID), exmpp_jid:domain(JID)]), send_welcome_message(JID), send_registration_notifications(JID), ok; @@ -233,7 +243,7 @@ try_register(User, Server, Password, Source, Lang) -> send_welcome_message(JID) -> - Host = JID#jid.ldomain, + Host = exmpp_jid:ldomain_as_list(JID), case gen_mod:get_module_opt(Host, ?MODULE, welcome_message, {"", ""}) of {"", ""} -> ok; @@ -247,7 +257,7 @@ send_welcome_message(JID) -> end. send_registration_notifications(UJID) -> - Host = UJID#jid.ldomain, + Host = exmpp_jid:ldomain_as_list(UJID), case gen_mod:get_module_opt(Host, ?MODULE, registration_watchers, []) of [] -> ok; JIDs when is_list(JIDs) -> diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 91a038223..dd8b72908 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -53,61 +53,63 @@ start(Host, Opts) -> + HostB = list_to_binary(Host), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), mnesia:create_table(roster,[{disc_copies, [node()]}, {attributes, record_info(fields, roster)}]), update_table(), mnesia:add_table_index(roster, us), - ejabberd_hooks:add(roster_get, Host, + ejabberd_hooks:add(roster_get, HostB, ?MODULE, get_user_roster, 50), - ejabberd_hooks:add(roster_in_subscription, Host, + ejabberd_hooks:add(roster_in_subscription, HostB, ?MODULE, in_subscription, 50), - ejabberd_hooks:add(roster_out_subscription, Host, + ejabberd_hooks:add(roster_out_subscription, HostB, ?MODULE, out_subscription, 50), - ejabberd_hooks:add(roster_get_subscription_lists, Host, + ejabberd_hooks:add(roster_get_subscription_lists, HostB, ?MODULE, get_subscription_lists, 50), - ejabberd_hooks:add(roster_get_jid_info, Host, + ejabberd_hooks:add(roster_get_jid_info, HostB, ?MODULE, get_jid_info, 50), - ejabberd_hooks:add(remove_user, Host, + ejabberd_hooks:add(remove_user, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:add(anonymous_purge_hook, Host, + ejabberd_hooks:add(anonymous_purge_hook, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:add(resend_subscription_requests_hook, Host, + ejabberd_hooks:add(resend_subscription_requests_hook, HostB, ?MODULE, get_in_pending_subscriptions, 50), - ejabberd_hooks:add(webadmin_page_host, Host, + ejabberd_hooks:add(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), - ejabberd_hooks:add(webadmin_user, Host, + ejabberd_hooks:add(webadmin_user, HostB, ?MODULE, webadmin_user, 50), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ROSTER, ?MODULE, process_iq, IQDisc). stop(Host) -> - ejabberd_hooks:delete(roster_get, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:delete(roster_get, HostB, ?MODULE, get_user_roster, 50), - ejabberd_hooks:delete(roster_in_subscription, Host, + ejabberd_hooks:delete(roster_in_subscription, HostB, ?MODULE, in_subscription, 50), - ejabberd_hooks:delete(roster_out_subscription, Host, + ejabberd_hooks:delete(roster_out_subscription, HostB, ?MODULE, out_subscription, 50), - ejabberd_hooks:delete(roster_get_subscription_lists, Host, + ejabberd_hooks:delete(roster_get_subscription_lists, HostB, ?MODULE, get_subscription_lists, 50), - ejabberd_hooks:delete(roster_get_jid_info, Host, + ejabberd_hooks:delete(roster_get_jid_info, HostB, ?MODULE, get_jid_info, 50), - ejabberd_hooks:delete(remove_user, Host, + ejabberd_hooks:delete(remove_user, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:delete(anonymous_purge_hook, Host, + ejabberd_hooks:delete(anonymous_purge_hook, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:delete(resend_subscription_requests_hook, Host, + ejabberd_hooks:delete(resend_subscription_requests_hook, HostB, ?MODULE, get_in_pending_subscriptions, 50), - ejabberd_hooks:delete(webadmin_page_host, Host, + ejabberd_hooks:delete(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), - ejabberd_hooks:delete(webadmin_user, Host, + ejabberd_hooks:delete(webadmin_user, HostB, ?MODULE, webadmin_user, 50), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ROSTER). process_iq(From, To, IQ_Rec) -> - #jid{ldomain = LServer} = From, + LServer = exmpp_jid:ldomain_as_list(From), case lists:member(LServer, ?MYHOSTS) of true -> process_local_iq(From, To, IQ_Rec); @@ -123,8 +125,8 @@ process_local_iq(From, To, #iq{type = set} = IQ_Rec) -> process_iq_get(From, To, IQ_Rec) -> - US = {From#jid.lnode, From#jid.ldomain}, - case catch ejabberd_hooks:run_fold(roster_get, To#jid.ldomain, [], [US]) of + US = {exmpp_jid:lnode(From), exmpp_jid:ldomain_(From)}, + case catch ejabberd_hooks:run_fold(roster_get, exmpp_jid:ldomain(To), [], [US]) of Items when is_list(Items) -> XItems = lists:map(fun item_to_xml/1, Items), Result = #xmlel{ns = ?NS_ROSTER, name = 'query', @@ -189,7 +191,9 @@ process_iq_set(From, To, #iq{payload = Request} = IQ_Rec) -> process_item_set(From, To, #xmlel{} = El) -> try JID1 = exmpp_jid:list_to_jid(exmpp_xml:get_attribute(El, 'jid', "")), - #jid{node = User, lnode = LUser, ldomain = LServer} = From, + User = exmpp_jid:node(From), + LUser = exmpp_jid:lnode(From), + LServer = exmpp_jid:ldomain(From), JID = jlib:short_jid(JID1), LJID = jlib:short_prepd_jid(JID1), F = fun() -> @@ -216,7 +220,7 @@ process_item_set(From, To, #xmlel{} = El) -> %% If the item exist in shared roster, take the %% subscription information from there: Item3 = ejabberd_hooks:run_fold(roster_process_item, - LServer, Item2, [LServer]), + exmpp_jid:ldomain(From), Item2, [exmpp_jid:ldomain(From)]), {Item, Item3} end, case mnesia:transaction(F) of @@ -305,8 +309,8 @@ process_item_els(Item, []) -> Item. -push_item(User, Server, From, Item) -> - ejabberd_sm:route(#jid{}, +push_item(User, Server, From, Item) when is_binary(User), is_binary(Server) -> + ejabberd_sm:route(exmpp_jid:make_jid(), exmpp_jid:make_bare_jid(User, Server), #xmlel{name = 'broadcast', children = [{item, @@ -317,7 +321,8 @@ push_item(User, Server, From, Item) -> end, ejabberd_sm:get_user_resources(User, Server)). % TODO: don't push to those who didn't load roster -push_item(User, Server, Resource, From, Item) -> +push_item(User, Server, Resource, From, Item) when is_binary(User), + is_binary(Server) -> Request = #xmlel{ns = ?NS_ROSTER, name = 'query', children = [item_to_xml(Item)]}, ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request, @@ -327,11 +332,10 @@ push_item(User, Server, Resource, From, Item) -> exmpp_jid:make_jid(User, Server, Resource), ResIQ). -get_subscription_lists(_, User, Server) -> +get_subscription_lists(_, User, Server) + when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - US = {LUser, LServer}, + US = {User,Server}, case mnesia:dirty_index_read(roster, US, #roster.us) of Items when is_list(Items) -> fill_subscription_lists(Items, [], []); @@ -370,17 +374,16 @@ in_subscription(_, User, Server, JID, Type, Reason) -> out_subscription(User, Server, JID, Type) -> process_subscription(out, User, Server, JID, Type, <<>>). -process_subscription(Direction, User, Server, JID1, Type, Reason) -> +process_subscription(Direction, User, Server, JID1, Type, Reason) + when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), - US = {LUser, LServer}, + US = {User, Server}, LJID = jlib:short_prepd_jid(JID1), F = fun() -> - Item = case mnesia:read({roster, {LUser, LServer, LJID}}) of + Item = case mnesia:read({roster, {User, Server, LJID}}) of [] -> JID = jlib:short_jid(JID1), - #roster{usj = {LUser, LServer, LJID}, + #roster{usj = {User, Server, LJID}, us = US, jid = JID}; [I] -> @@ -414,7 +417,7 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) -> {none, AutoReply}; {none, none} when Item#roster.subscription == none, Item#roster.ask == in -> - mnesia:delete({roster, {LUser, LServer, LJID}}), + mnesia:delete({roster, {User, Server, LJID}}), {none, AutoReply}; {Subscription, Pending} -> AskBinary = case AskMessage of @@ -556,10 +559,11 @@ in_auto_reply(both, none, unsubscribe) -> unsubscribed; in_auto_reply(_, _, _) -> none. -remove_user(User, Server) -> +remove_user(User, Server) + when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), + LUser = list_to_binary(exmpp_stringprep:nodeprep(User)), + LServer = list_to_binary(exmpp_stringprep:nameprep(Server)), US = {LUser, LServer}, F = fun() -> lists:foreach(fun(R) -> @@ -645,9 +649,10 @@ process_item_attrs_ws(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> process_item_attrs_ws(Item, []) -> Item. -get_in_pending_subscriptions(Ls, User, Server) -> +get_in_pending_subscriptions(Ls, User, Server) + when is_binary(User), is_binary(Server) -> JID = exmpp_jid:make_bare_jid(User, Server), - US = {JID#jid.lnode, JID#jid.ldomain}, + US = {exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID)}, case mnesia:dirty_index_read(roster, US, #roster.us) of Result when list(Result) -> Ls ++ lists:map( @@ -676,12 +681,10 @@ get_in_pending_subscriptions(Ls, User, Server) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -get_jid_info(_, User, Server, JID) -> +get_jid_info(_, User, Server, JID) when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), LJID = jlib:short_prepd_jid(JID), - case catch mnesia:dirty_read(roster, {LUser, LServer, LJID}) of + case catch mnesia:dirty_read(roster, {User, Server, LJID}) of [#roster{subscription = Subscription, groups = Groups}] -> {Subscription, Groups}; _ -> @@ -691,7 +694,7 @@ get_jid_info(_, User, Server, JID) -> {none, []}; true -> case catch mnesia:dirty_read( - roster, {LUser, LServer, LRJID}) of + roster, {User, Server, LRJID}) of [#roster{subscription = Subscription, groups = Groups}] -> {Subscription, Groups}; diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 639803c60..ad85f0890 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -52,56 +52,58 @@ start(Host, Opts) -> + HostB = list_to_binary(Host), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - ejabberd_hooks:add(roster_get, Host, + ejabberd_hooks:add(roster_get, HostB, ?MODULE, get_user_roster, 50), - ejabberd_hooks:add(roster_in_subscription, Host, + ejabberd_hooks:add(roster_in_subscription, HostB, ?MODULE, in_subscription, 50), - ejabberd_hooks:add(roster_out_subscription, Host, + ejabberd_hooks:add(roster_out_subscription, HostB, ?MODULE, out_subscription, 50), - ejabberd_hooks:add(roster_get_subscription_lists, Host, + ejabberd_hooks:add(roster_get_subscription_lists, HostB, ?MODULE, get_subscription_lists, 50), - ejabberd_hooks:add(roster_get_jid_info, Host, + ejabberd_hooks:add(roster_get_jid_info, HostB, ?MODULE, get_jid_info, 50), - ejabberd_hooks:add(remove_user, Host, + ejabberd_hooks:add(remove_user, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:add(anonymous_purge_hook, Host, + ejabberd_hooks:add(anonymous_purge_hook, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:add(resend_subscription_requests_hook, Host, + ejabberd_hooks:add(resend_subscription_requests_hook, HostB, ?MODULE, get_in_pending_subscriptions, 50), - ejabberd_hooks:add(webadmin_page_host, Host, + ejabberd_hooks:add(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), - ejabberd_hooks:add(webadmin_user, Host, + ejabberd_hooks:add(webadmin_user, HostB, ?MODULE, webadmin_user, 50), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ROSTER, ?MODULE, process_iq, IQDisc). stop(Host) -> - ejabberd_hooks:delete(roster_get, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:delete(roster_get, HostB, ?MODULE, get_user_roster, 50), - ejabberd_hooks:delete(roster_in_subscription, Host, + ejabberd_hooks:delete(roster_in_subscription, HostB, ?MODULE, in_subscription, 50), - ejabberd_hooks:delete(roster_out_subscription, Host, + ejabberd_hooks:delete(roster_out_subscription, HostB, ?MODULE, out_subscription, 50), - ejabberd_hooks:delete(roster_get_subscription_lists, Host, + ejabberd_hooks:delete(roster_get_subscription_lists, HostB, ?MODULE, get_subscription_lists, 50), - ejabberd_hooks:delete(roster_get_jid_info, Host, + ejabberd_hooks:delete(roster_get_jid_info, HostB, ?MODULE, get_jid_info, 50), - ejabberd_hooks:delete(remove_user, Host, + ejabberd_hooks:delete(remove_user, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:delete(anonymous_purge_hook, Host, + ejabberd_hooks:delete(anonymous_purge_hook, HostB, ?MODULE, remove_user, 50), - ejabberd_hooks:delete(resend_subscription_requests_hook, Host, + ejabberd_hooks:delete(resend_subscription_requests_hook, HostB, ?MODULE, get_in_pending_subscriptions, 50), - ejabberd_hooks:delete(webadmin_page_host, Host, + ejabberd_hooks:delete(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), - ejabberd_hooks:delete(webadmin_user, Host, + ejabberd_hooks:delete(webadmin_user, HostB, ?MODULE, webadmin_user, 50), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ROSTER). process_iq(From, To, IQ_Rec) -> - #jid{ldomain = LServer} = From, + LServer = exmpp_jid:ldomain_as_list(From), case lists:member(LServer, ?MYHOSTS) of true -> process_local_iq(From, To, IQ_Rec); @@ -117,8 +119,8 @@ process_local_iq(From, To, #iq{type = set} = IQ_Rec) -> process_iq_get(From, To, IQ_Rec) -> - US = {From#jid.lnode, From#jid.ldomain}, - case catch ejabberd_hooks:run_fold(roster_get, To#jid.ldomain, [], [US]) of + US = {exmpp_jid:lnode(From), exmpp_jid:ldomain(From)}, + case catch ejabberd_hooks:run_fold(roster_get, exmpp_jid:ldomain(To), [], [US]) of Items when is_list(Items) -> XItems = lists:map(fun item_to_xml/1, Items), Result = #xmlel{ns = ?NS_ROSTER, name = 'query', @@ -136,13 +138,14 @@ get_user_roster(Acc, {LUser, LServer}) -> true end, Items) ++ Acc. -get_roster(LUser, LServer) -> - Username = ejabberd_odbc:escape(LUser), - case catch odbc_queries:get_roster(LServer, Username) of +get_roster(LUser, LServer) when is_binary(LUser), is_binary(LServer)-> + Username = ejabberd_odbc:escape(binary_to_list(LUser)), + DomainString = binary_to_list(LServer), + case catch odbc_queries:get_roster(DomainString, Username) of {selected, ["username", "jid", "nick", "subscription", "ask", "askmessage", "server", "subscribe", "type"], Items} when is_list(Items) -> - JIDGroups = case catch odbc_queries:get_roster_jid_groups(LServer, Username) of + JIDGroups = case catch odbc_queries:get_roster_jid_groups(DomainString, Username) of {selected, ["jid","grp"], JGrps} when is_list(JGrps) -> JGrps; @@ -214,7 +217,8 @@ process_iq_set(From, To, #iq{payload = Request} = IQ_Rec) -> process_item_set(From, To, #xmlel{} = El) -> try JID1 = exmpp_jid:list_to_jid(exmpp_xml:get_attribute(El, 'jid', "")), - #jid{node = User, lnode = LUser, ldomain = LServer} = From, + LUser = exmpp_jid:lnode_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), {U0, S0, R0} = LJID = jlib:short_prepd_jid(JID1), Username = ejabberd_odbc:escape(LUser), SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(U0, S0, R0)), @@ -229,7 +233,7 @@ process_item_set(From, To, #xmlel{} = El) -> us = {LUser, LServer}, jid = LJID}; [I] -> - R = raw_to_record(LServer, I), + R = raw_to_record(exmpp_jid:ldomain(From), I), case R of %% Bad JID in database: error -> @@ -257,12 +261,12 @@ process_item_set(From, To, #xmlel{} = El) -> %% If the item exist in shared roster, take the %% subscription information from there: Item3 = ejabberd_hooks:run_fold(roster_process_item, - LServer, Item2, [LServer]), + exmpp_jid:ldomain(From), Item2, [exmpp_jid:ldomain(From)]), {Item, Item3} end, case odbc_queries:sql_transaction(LServer, F) of {atomic, {OldItem, Item}} -> - push_item(User, LServer, To, Item), + push_item(exmpp_jid:node(From), exmpp_jid:ldomain(From), To, Item), case Item#roster.subscription of remove -> IsTo = case OldItem#roster.subscription of @@ -340,8 +344,8 @@ process_item_els(Item, []) -> Item. -push_item(User, Server, From, Item) -> - ejabberd_sm:route(#jid{}, +push_item(User, Server, From, Item) when is_binary(User), is_binary(Server) -> + ejabberd_sm:route(exmpp_jid:make_jid(), exmpp_jid:make_bare_jid(User, Server), #xmlel{name = 'broadcast', children = [{item, @@ -362,16 +366,17 @@ push_item(User, Server, Resource, From, Item) -> exmpp_jid:make_jid(User, Server, Resource), ResIQ). -get_subscription_lists(_, User, Server) -> +get_subscription_lists(_, User, Server) + when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), + LUser = binary_to_list(User), + LServer = binary_to_list(Server), Username = ejabberd_odbc:escape(LUser), case catch odbc_queries:get_roster(LServer, Username) of {selected, ["username", "jid", "nick", "subscription", "ask", "askmessage", "server", "subscribe", "type"], Items} when is_list(Items) -> - fill_subscription_lists(LServer, Items, [], []); + fill_subscription_lists(Server, Items, [], []); _ -> {[], []} end @@ -414,10 +419,11 @@ in_subscription(_, User, Server, JID, Type, Reason) -> out_subscription(User, Server, JID, Type) -> process_subscription(out, User, Server, JID, Type, <<>>). -process_subscription(Direction, User, Server, JID1, Type, Reason) -> +process_subscription(Direction, User, Server, JID1, Type, Reason) + when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), + LUser = binary_to_list(User), + LServer = binary_to_list(Server), {N0,D0,R0} = LJID = jlib:short_prepd_jid(JID1), Username = ejabberd_odbc:escape(LUser), SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(N0,D0,R0)), @@ -430,7 +436,7 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) -> [I]} -> %% raw_to_record can return error, but %% jlib_to_string would fail before this point - R = raw_to_record(LServer, I), + R = raw_to_record(list_to_binary(LServer), I), Groups = case odbc_queries:get_roster_groups(LServer, Username, SJID) of {selected, ["grp"], JGrps} when is_list(JGrps) -> @@ -443,8 +449,8 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) -> ["username", "jid", "nick", "subscription", "ask", "askmessage", "server", "subscribe", "type"], []} -> - #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, + #roster{usj = {list_to_binary(LUser), list_to_binary(LServer), LJID}, + us = {list_to_binary(LUser), list_to_binary(LServer)}, jid = LJID} end, NewState = case Direction of @@ -619,7 +625,7 @@ in_auto_reply(both, none, unsubscribe) -> unsubscribed; in_auto_reply(_, _, _) -> none. -remove_user(User, Server) -> +remove_user(User, Server) when is_binary(User), is_binary(Server) -> try LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), @@ -705,10 +711,11 @@ process_item_attrs_ws(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> process_item_attrs_ws(Item, []) -> Item. -get_in_pending_subscriptions(Ls, User, Server) -> +get_in_pending_subscriptions(Ls, User, Server) + when is_binary(User), is_binary(Server) -> JID = exmpp_jid:make_bare_jid(User, Server), - LUser = JID#jid.lnode, - LServer = JID#jid.ldomain, + LUser = exmpp_jid:lnode_as_list(JID), + LServer = exmpp_jid:ldomain_as_list(JID), Username = ejabberd_odbc:escape(LUser), case catch odbc_queries:get_roster(LServer, Username) of {selected, ["username", "jid", "nick", "subscription", "ask", @@ -726,7 +733,7 @@ get_in_pending_subscriptions(Ls, User, Server) -> end, lists:flatmap( fun(I) -> - case raw_to_record(LServer, I) of + case raw_to_record(exmpp_jid:ldomain(JID), I) of %% Bad JID in database: error -> []; @@ -745,12 +752,12 @@ get_in_pending_subscriptions(Ls, User, Server) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% JID is #jid record, because it's used latter on for both short_prepd_jid +%% JID is jid() record, because it's used latter on for both short_prepd_jid %% and short_prepd_bare_jid -get_jid_info(_, User, Server, JID) -> +get_jid_info(_, User, Server, JID) when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), + LUser = binary_to_list(User), + LServer = binary_to_list(Server), LJID = {N, D, R} = jlib:short_prepd_jid(JID), Username = ejabberd_odbc:escape(LUser), SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(N, D, R)), @@ -805,7 +812,7 @@ get_jid_info(_, User, Server, JID) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% raw_to_record(LServer, {User, SJID, Nick, SSubscription, SAsk, SAskMessage, - _SServer, _SSubscribe, _SType}) -> + _SServer, _SSubscribe, _SType}) when is_binary(LServer) -> try JID = exmpp_jid:list_to_jid(SJID), LJID = jlib:short_prepd_jid(JID), @@ -823,8 +830,9 @@ raw_to_record(LServer, {User, SJID, Nick, SSubscription, SAsk, SAskMessage, "I" -> in; _ -> none end, - #roster{usj = {User, LServer, LJID}, - us = {User, LServer}, + UserB = list_to_binary(User), + #roster{usj = {UserB, LServer, LJID}, + us = {UserB, LServer}, jid = LJID, name = Nick, subscription = Subscription, @@ -841,7 +849,7 @@ record_to_string(#roster{us = {User, _Server}, subscription = Subscription, ask = Ask, askmessage = AskMessage}) -> - Username = ejabberd_odbc:escape(User), + Username = ejabberd_odbc:escape(binary_to_list(User)), {U, S, R} = JID, SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(U, S, R)), Nick = ejabberd_odbc:escape(Name), diff --git a/src/mod_service_log.erl b/src/mod_service_log.erl index 2b360fea4..7ecf11a84 100644 --- a/src/mod_service_log.erl +++ b/src/mod_service_log.erl @@ -39,35 +39,37 @@ -include("ejabberd.hrl"). start(Host, _Opts) -> - ejabberd_hooks:add(user_send_packet, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:add(user_send_packet, HostB, ?MODULE, log_user_send, 50), - ejabberd_hooks:add(user_receive_packet, Host, + ejabberd_hooks:add(user_receive_packet, HostB, ?MODULE, log_user_receive, 50), ok. stop(Host) -> - ejabberd_hooks:delete(user_send_packet, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:delete(user_send_packet, HostB, ?MODULE, log_user_send, 50), - ejabberd_hooks:delete(user_receive_packet, Host, + ejabberd_hooks:delete(user_receive_packet, HostB, ?MODULE, log_user_receive, 50), ok. log_user_send(From, To, Packet) -> - log_packet(From, To, Packet, From#jid.ldomain). + log_packet(From, To, Packet, exmpp_jid:ldomain_as_list(From)). log_user_receive(_JID, From, To, Packet) -> - log_packet(From, To, Packet, To#jid.ldomain). + log_packet(From, To, Packet, exmpp_jid:ldomain_as_list(To)). log_packet(From, To, Packet, Host) -> Loggers = gen_mod:get_module_opt(Host, ?MODULE, loggers, []), - ServerJID = #jid{domain = Host, ldomain = Host}, + ServerJID = exmpp_jid:make_bare_jid(Host), FixedPacket = exmpp_stanza:set_jids(Packet, From, To), lists:foreach( fun(Logger) -> ejabberd_router:route( ServerJID, - #jid{domain = Logger, ldomain = Logger}, + exmpp_jid:make_bare_jid(Logger), #xmlel{name = 'route', children = [FixedPacket]}) end, Loggers). diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index e6b35fdd7..e0522510f 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -60,6 +60,7 @@ -record(sr_user, {us, group_host}). start(Host, _Opts) -> + HostB = list_to_binary(Host), mnesia:create_table(sr_group, [{disc_copies, [node()]}, {attributes, record_info(fields, sr_group)}]), @@ -68,47 +69,48 @@ start(Host, _Opts) -> {type, bag}, {attributes, record_info(fields, sr_user)}]), mnesia:add_table_index(sr_user, group_host), - ejabberd_hooks:add(webadmin_menu_host, Host, + ejabberd_hooks:add(webadmin_menu_host, HostB, ?MODULE, webadmin_menu, 70), - ejabberd_hooks:add(webadmin_page_host, Host, + ejabberd_hooks:add(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), - ejabberd_hooks:add(roster_get, Host, + ejabberd_hooks:add(roster_get, HostB, ?MODULE, get_user_roster, 70), - ejabberd_hooks:add(roster_in_subscription, Host, + ejabberd_hooks:add(roster_in_subscription, HostB, ?MODULE, in_subscription, 30), - ejabberd_hooks:add(roster_out_subscription, Host, + ejabberd_hooks:add(roster_out_subscription, HostB, ?MODULE, out_subscription, 30), - ejabberd_hooks:add(roster_get_subscription_lists, Host, + ejabberd_hooks:add(roster_get_subscription_lists, HostB, ?MODULE, get_subscription_lists, 70), - ejabberd_hooks:add(roster_get_jid_info, Host, + ejabberd_hooks:add(roster_get_jid_info, HostB, ?MODULE, get_jid_info, 70), - ejabberd_hooks:add(roster_process_item, Host, + ejabberd_hooks:add(roster_process_item, HostB, ?MODULE, process_item, 50), - ejabberd_hooks:add(user_registered, Host, + ejabberd_hooks:add(user_registered, HostB, ?MODULE, user_registered, 50). -%%ejabberd_hooks:add(remove_user, Host, +%%ejabberd_hooks:add(remove_user, HostB, %% ?MODULE, remove_user, 50), stop(Host) -> - ejabberd_hooks:delete(webadmin_menu_host, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:delete(webadmin_menu_host, HostB, ?MODULE, webadmin_menu, 70), - ejabberd_hooks:delete(webadmin_page_host, Host, + ejabberd_hooks:delete(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), - ejabberd_hooks:delete(roster_get, Host, + ejabberd_hooks:delete(roster_get, HostB, ?MODULE, get_user_roster, 70), - ejabberd_hooks:delete(roster_in_subscription, Host, + ejabberd_hooks:delete(roster_in_subscription, HostB, ?MODULE, in_subscription, 30), - ejabberd_hooks:delete(roster_out_subscription, Host, + ejabberd_hooks:delete(roster_out_subscription, HostB, ?MODULE, out_subscription, 30), - ejabberd_hooks:delete(roster_get_subscription_lists, Host, + ejabberd_hooks:delete(roster_get_subscription_lists, HostB, ?MODULE, get_subscription_lists, 70), - ejabberd_hooks:delete(roster_get_jid_info, Host, + ejabberd_hooks:delete(roster_get_jid_info, HostB, ?MODULE, get_jid_info, 70), - ejabberd_hooks:delete(roster_process_item, Host, + ejabberd_hooks:delete(roster_process_item, HostB, ?MODULE, process_item, 50), - ejabberd_hooks:delete(user_registered, Host, + ejabberd_hooks:delete(user_registered, HostB, ?MODULE, user_registered, 50). -%%ejabberd_hooks:delete(remove_user, Host, +%%ejabberd_hooks:delete(remove_user, HostB, %% ?MODULE, remove_user, 50), @@ -252,10 +254,11 @@ set_item(User, Server, Resource, Item) -> ResIQ). -get_subscription_lists({F, T}, User, Server) -> +get_subscription_lists({F, T}, User, Server) + when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), + LUser = binary_to_list(User), + LServer = binary_to_list(Server), US = {LUser, LServer}, DisplayedGroups = get_user_displayed_groups(US), SRUsers = @@ -271,10 +274,11 @@ get_subscription_lists({F, T}, User, Server) -> {[], []} end. -get_jid_info({Subscription, Groups}, User, Server, JID) -> +get_jid_info({Subscription, Groups}, User, Server, JID) + when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), + LUser = binary_to_list(User), + LServer = binary_to_list(Server), US = {LUser, LServer}, {U1, S1, _} = jlib:short_prepd_jid(JID), US1 = {U1, S1}, @@ -574,7 +578,7 @@ push_item(User, Server, From, Item) -> fun(Resource) -> JID = exmpp_jid:make_jid(User, Server, Resource), ejabberd_router:route(JID, JID, Stanza) - end, ejabberd_sm:get_user_resources(User, Server)). + end, ejabberd_sm:get_user_resources(list_to_binary(User), list_to_binary(Server))). item_to_xml(Item) -> {U, S, R} = Item#roster.jid, @@ -807,7 +811,7 @@ shared_roster_group_parse_query(Host, Group, Query) -> _ -> try JID = exmpp_jid:list_to_jid(SJID), - [{JID#jid.lnode, JID#jid.ldomain} | USs] + [{exmpp_jid:lnode_as_list(JID), exmpp_jid:ldomain_as_list(JID)} | USs] catch _ -> error diff --git a/src/mod_stats.erl b/src/mod_stats.erl index f5910ea8a..0884ba252 100644 --- a/src/mod_stats.erl +++ b/src/mod_stats.erl @@ -49,7 +49,7 @@ process_local_iq(_From, To, #iq{type = get, Node = string:tokens(exmpp_xml:get_attribute(SubEl, 'node', ""), "/"), Names = get_names(exmpp_xml:get_child_elements(SubEl), []), - case get_local_stats(To#jid.domain, Node, Names) of + case get_local_stats(exmpp_jid:domain_as_list(To), Node, Names) of {result, Res} -> Result = #xmlel{ns = XMLNS, name = 'query', children = Res}, exmpp_iq:result(IQ_Rec, Result); @@ -130,7 +130,7 @@ get_local_stats(_Server, _, _) -> get_local_stat(Server, [], Name) when Name == "users/online" -> - case catch ejabberd_sm:get_vh_session_list(Server) of + case catch ejabberd_sm:get_vh_session_list(list_to_binary(Server)) of {'EXIT', _Reason} -> ?STATERR("500", "Internal Server Error"); Users -> diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index c015b1500..465203b1d 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -62,6 +62,7 @@ -define(PROCNAME, ejabberd_mod_vcard). start(Host, Opts) -> + HostB = list_to_binary(Host), mnesia:create_table(vcard, [{disc_only_copies, [node()]}, {attributes, record_info(fields, vcard)}]), mnesia:create_table(vcard_search, @@ -81,14 +82,14 @@ start(Host, Opts) -> mnesia:add_table_index(vcard_search, lorgname), mnesia:add_table_index(vcard_search, lorgunit), - ejabberd_hooks:add(remove_user, Host, + ejabberd_hooks:add(remove_user, HostB, ?MODULE, remove_user, 50), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD, ?MODULE, process_local_iq, IQDisc), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD, ?MODULE, process_sm_iq, IQDisc), - ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50), + ejabberd_hooks:add(disco_sm_features, HostB, ?MODULE, get_sm_features, 50), MyHost = gen_mod:get_opt_host(Host, Opts, "vjud.@HOST@"), Search = gen_mod:get_opt(search, Opts, true), register(gen_mod:get_module_proc(Host, ?PROCNAME), @@ -122,13 +123,14 @@ loop(Host, ServerHost) -> end. stop(Host) -> - ejabberd_hooks:delete(remove_user, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:delete(remove_user, HostB, ?MODULE, remove_user, 50), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD), - ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50), + ejabberd_hooks:delete(disco_sm_features, HostB, ?MODULE, get_sm_features, 50), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), Proc ! stop, {wait, Proc}. @@ -167,7 +169,8 @@ process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> - #jid{lnode = LUser, ldomain = LServer} = To, + LUser = exmpp_jid:lnode_as_list(To), + LServer = exmpp_jid:ldomain_as_list(To), US = {LUser, LServer}, F = fun() -> mnesia:read({vcard, US}) @@ -187,7 +190,8 @@ process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> exmpp_iq:result(IQ_Rec) end; process_sm_iq(From, _To, #iq{type = set, payload = Request} = IQ_Rec) -> - #jid{node = User, ldomain = LServer} = From, + User = exmpp_jid:node_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), case lists:member(LServer, ?MYHOSTS) of true -> set_vcard(User, LServer, Request), @@ -307,7 +311,8 @@ set_vcard(User, LServer, VCARD) -> do_route(ServerHost, From, To, Packet) -> - #jid{node = User, resource = Resource} = To, + User = exmpp_jid:node(To), + Resource = exmpp_jid:resource(To), if (User /= undefined) or (Resource /= undefined) -> Err = exmpp_stanza:reply_with_error(Packet, 'service-unavailable'), @@ -651,7 +656,7 @@ reindex_vcards() -> mnesia:transaction(F). -remove_user(User, Server) -> +remove_user(User, Server) when is_binary(User), is_binary(Server) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index caae4b667..a7200a38a 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -155,7 +155,7 @@ terminate(_Reason, State) -> Host = State#state.serverhost, gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD), - ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50), + ejabberd_hooks:delete(disco_sm_features, list_to_binary(Host), ?MODULE, get_sm_features, 50), case State#state.search of true -> ejabberd_router:unregister_route(State#state.myhost); @@ -174,7 +174,8 @@ init([Host, Opts]) -> ?MODULE, process_local_iq, IQDisc), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD, ?MODULE, process_sm_iq, IQDisc), - ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50), + ejabberd_hooks:add(disco_sm_features, + list_to_binary(Host), ?MODULE, get_sm_features, 50), eldap_pool:start_link(State#state.eldap_id, State#state.servers, State#state.backups, @@ -234,7 +235,8 @@ process_local_iq(_From, _To, #iq{type = get, lang = Lang} = IQ_Rec) -> process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> exmpp_iq:error(IQ_Rec, 'not-allowed'). -process_sm_iq(_From, #jid{ldomain=LServer} = To, #iq{} = IQ_Rec) -> +process_sm_iq(_From, To, #iq{} = IQ_Rec) -> + LServer = exmpp_jid:ldomain_as_list(To), case catch process_vcard_ldap(To, IQ_Rec, LServer) of {'EXIT', _} -> exmpp_iq:error(IQ_Rec, 'internal-server-error'); @@ -248,7 +250,7 @@ process_vcard_ldap(To, IQ_Rec, Server) -> set -> exmpp_iq:error(IQ_Rec, 'not-allowed'); get -> - #jid{lnode = LUser} = To, + LUser = exmpp_jid:lnode_as_list(To), LServer = State#state.serverhost, case ejabberd_auth:is_user_exists(LUser, LServer) of true -> @@ -402,7 +404,8 @@ do_route(State, From, To, Packet) -> spawn(?MODULE, route, [State, From, To, Packet]). route(State, From, To, Packet) -> - #jid{node = User, resource = Resource} = To, + User = exmpp_jid:node(To), + Resource = exmpp_jid:resource(To), if (User /= undefined) or (Resource /= undefined) -> Err = exmpp_stanza:reply_with_error(Packet, 'service-unavailable'), diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl index dd1a59adb..21f9d0595 100644 --- a/src/mod_vcard_odbc.erl +++ b/src/mod_vcard_odbc.erl @@ -45,14 +45,15 @@ -define(PROCNAME, ejabberd_mod_vcard). start(Host, Opts) -> - ejabberd_hooks:add(remove_user, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:add(remove_user, HostB, ?MODULE, remove_user, 50), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD, ?MODULE, process_local_iq, IQDisc), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD, ?MODULE, process_sm_iq, IQDisc), - ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50), + ejabberd_hooks:add(disco_sm_features, HostB, ?MODULE, get_sm_features, 50), MyHost = gen_mod:get_opt_host(Host, Opts, "vjud.@HOST@"), Search = gen_mod:get_opt(search, Opts, true), register(gen_mod:get_module_proc(Host, ?PROCNAME), @@ -86,11 +87,12 @@ loop(Host, ServerHost) -> end. stop(Host) -> - ejabberd_hooks:delete(remove_user, Host, + HostB = list_to_binary(Host), + ejabberd_hooks:delete(remove_user, HostB, ?MODULE, remove_user, 50), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD), - ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50), + ejabberd_hooks:delete(disco_sm_features, HostB, ?MODULE, get_sm_features, 50), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), Proc ! stop, {wait, Proc}. @@ -129,12 +131,14 @@ process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> - #jid{lnode = LUser, ldomain = LServer} = To, + LUser = exmpp_jid:lnode_as_list(To), + LServer = exmpp_jid:ldomain_as_list(To), Username = ejabberd_odbc:escape(LUser), case catch odbc_queries:get_vcard(LServer, Username) of {selected, ["vcard"], [{SVCARD}]} -> try exmpp_xml:parse_document(SVCARD, - [names_as_atom]) of + [names_as_atom, {check_elems, xmpp}, + {check_nss,xmpp}, {check_attrs,xmpp}]) of [VCARD] -> exmpp_iq:result(IQ_Rec, VCARD) catch @@ -148,7 +152,8 @@ process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> exmpp_iq:error(IQ_Rec, 'internal-server-error') end; process_sm_iq(From, _To, #iq{type = set, payload = Request} = IQ_Rec) -> - #jid{node = User, ldomain = LServer} = From, + User = exmpp_jid:node_as_list(From), + LServer = exmpp_jid:ldomain_as_list(From), case lists:member(LServer, ?MYHOSTS) of true -> set_vcard(User, LServer, Request), @@ -277,7 +282,8 @@ set_vcard(User, LServer, VCARD) -> ]}]). do_route(ServerHost, From, To, Packet) -> - #jid{node = User, resource = Resource} = To, + User = exmpp_jid:node(To), + Resource = exmpp_jid:resource(To), if (User /= undefined) or (Resource /= undefined) -> Err = exmpp_stanza:reply_with_error(Packet, 'service-unavailable'), @@ -615,7 +621,7 @@ make_val(Match, Field, Val) -> % mnesia:transaction(F). -remove_user(User, Server) -> +remove_user(User, Server) when is_binary(User), is_binary(server) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), Username = ejabberd_odbc:escape(LUser), diff --git a/src/mod_version.erl b/src/mod_version.erl index ec7115a37..19d154048 100644 --- a/src/mod_version.erl +++ b/src/mod_version.erl @@ -53,7 +53,7 @@ process_local_iq(_From, To, #iq{type = Type} = IQ_Rec) -> set -> exmpp_iq:error(IQ_Rec, 'not-allowed'); get -> - Host = To#jid.domain, + Host = exmpp_jid:domain_as_list(To), OS = case gen_mod:get_module_opt(Host, ?MODULE, show_os, true) of true -> [get_os()]; false -> [] From 2cbd61f26866211e69722efce53333d2208a6e5f Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Mon, 5 Jan 2009 15:41:53 +0000 Subject: [PATCH 152/582] Fix typo in mod_roster SVN Revision: 1773 --- ChangeLog | 3 +++ src/mod_roster.erl | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 1a5d73e47..0dfeb25eb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2009-01-05 Pablo Polvorin + * src/mod_roster.erl: Fix typo. + 2009-01-03 Pablo Polvorin * src/mod_pubsub_node_default.erl: Fix typo diff --git a/src/mod_roster.erl b/src/mod_roster.erl index dd8b72908..6817e07a2 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -125,7 +125,7 @@ process_local_iq(From, To, #iq{type = set} = IQ_Rec) -> process_iq_get(From, To, IQ_Rec) -> - US = {exmpp_jid:lnode(From), exmpp_jid:ldomain_(From)}, + US = {exmpp_jid:lnode(From), exmpp_jid:ldomain(From)}, case catch ejabberd_hooks:run_fold(roster_get, exmpp_jid:ldomain(To), [], [US]) of Items when is_list(Items) -> XItems = lists:map(fun item_to_xml/1, Items), From e0e58711bb3c76350bdc9b1bf9fb03d53e254a6d Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Thu, 8 Jan 2009 14:54:00 +0000 Subject: [PATCH 153/582] XML attributes as binary(). Change Node argument to binary in the following hooks: disco_local_items, disco_local_features, disco_local_identity, disco_sm_items and disco_sm_identity. SVN Revision: 1780 --- ChangeLog | 15 ++ src/adhoc.erl | 10 +- src/ejabberd_c2s.erl | 4 +- src/ejabberd_s2s_in.erl | 4 +- src/ejabberd_s2s_out.erl | 4 +- src/ejabberd_service.erl | 8 +- src/mod_adhoc.erl | 57 +++--- src/mod_announce.erl | 114 +++++------ src/mod_configure.erl | 311 +++++++++++++++-------------- src/mod_configure2.erl | 12 +- src/mod_disco.erl | 60 +++--- src/mod_irc/mod_irc.erl | 32 +-- src/mod_irc/mod_irc_connection.erl | 68 +++---- src/mod_last.erl | 4 +- src/mod_last_odbc.erl | 4 +- src/mod_muc/mod_muc.erl | 9 +- src/mod_offline_odbc.erl | 4 +- src/mod_privacy.erl | 38 ++-- src/mod_privacy_odbc.erl | 38 ++-- src/mod_pubsub/mod_pubsub.erl | 13 +- src/mod_roster.erl | 18 +- src/mod_roster.hrl | 2 +- src/mod_roster_odbc.erl | 22 +- src/mod_stats.erl | 102 +++++----- src/mod_vcard.erl | 92 ++++----- src/mod_vcard_ldap.erl | 28 +-- src/mod_vcard_odbc.erl | 92 ++++----- src/web/ejabberd_http_poll.erl | 4 +- 28 files changed, 596 insertions(+), 573 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0dfeb25eb..b03b74aee 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2009-01-08 Pablo Polvorin + * src/mod_vcard_ldap.erl, src/mod_muc/mod_muc.erl, src/mod_roster.hrl, + src/mod_offline_odbc.erl, src/ejabberd_s2s_in.erl, src/adhoc.erl, + src/mod_configure.erl, src/mod_irc/mod_irc_connection.erl, + src/mod_irc/mod_irc.erl, src/web/ejabberd_http_poll.erl, + src/mod_privacy_odbc.erl, src/ejabberd_c2s.erl, src/mod_announce.erl, + src/mod_privacy.erl, src/mod_adhoc.erl, src/mod_pubsub/mod_pubsub.erl, + src/mod_vcard_odbc.erl, src/mod_stats.erl, src/mod_last.erl, + src/mod_roster.erl, src/ejabberd_service.erl, src/mod_disco.erl, + src/mod_configure2.erl, src/mod_roster_odbc.erl, src/ejabberd_s2s_out.erl, + src/mod_last_odbc.erl: XML attributes as binary(). Change Node argument + to binary in the following hooks: disco_local_items, disco_local_features, + disco_local_identity, disco_sm_items and disco_sm_identity. + + 2009-01-05 Pablo Polvorin * src/mod_roster.erl: Fix typo. diff --git a/src/adhoc.erl b/src/adhoc.erl index 26ea5a7c2..32f4d4038 100644 --- a/src/adhoc.erl +++ b/src/adhoc.erl @@ -113,7 +113,7 @@ produce_response(#adhoc_response{lang = _Lang, "" -> ActionsElAttrs = []; _ -> - ActionsElAttrs = [#xmlattr{name = 'execute', value = DefaultAction}] + ActionsElAttrs = [#xmlattr{name = 'execute', value = list_to_binary(DefaultAction)}] end, ActionsEls = [#xmlel{ns = ?NS_ADHOC, name = 'actions', attrs = ActionsElAttrs, children = @@ -121,11 +121,11 @@ produce_response(#adhoc_response{lang = _Lang, end, NotesEls = lists:map(fun({Type, Text}) -> #xmlel{ns = ?NS_ADHOC, name = 'note', attrs = - [#xmlattr{name = 'type', value = Type}], + [#xmlattr{name = 'type', value = list_to_binary(Type)}], children = [#xmlcdata{cdata = list_to_binary(Text)}]} end, Notes), #xmlel{ns = ?NS_ADHOC, name = 'command', attrs = - [#xmlattr{name = 'sessionid', value = SessionID}, - #xmlattr{name = 'node', value = Node}, - #xmlattr{name = 'status', value = atom_to_list(Status)}], children = + [#xmlattr{name = 'sessionid', value = list_to_binary(SessionID)}, + #xmlattr{name = 'node', value = list_to_binary(Node)}, + #xmlattr{name = 'status', value = list_to_binary(atom_to_list(Status))}], children = ActionsEls ++ NotesEls ++ Elements}. diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 2a806fbc1..34b124587 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -837,7 +837,7 @@ session_established2(El, StateData) -> undefined -> exmpp_jid:jid_to_bare_jid(StateData#state.jid); _ -> - exmpp_jid:list_to_jid(To) + exmpp_jid:binary_to_jid(To) end, NewEl = case exmpp_stanza:get_lang(El) of undefined -> @@ -1923,7 +1923,7 @@ check_from(El, FromJID) -> El; SJID -> try - JID = exmpp_jid:list_to_jid(SJID), + JID = exmpp_jid:binary_to_jid(SJID), case exmpp_jid:compare_jids(JID, FromJID) of true -> El; diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 2092415ba..703e20cd9 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -371,7 +371,7 @@ stream_established({xmlstreamelement, El}, StateData) -> error; F -> try - exmpp_jid:list_to_jid(F) + exmpp_jid:binary_to_jid(F) catch _Exception1 -> error end @@ -381,7 +381,7 @@ stream_established({xmlstreamelement, El}, StateData) -> error; T -> try - exmpp_jid:list_to_jid(T) + exmpp_jid:binary_to_jid(T) catch _Exception2 -> error end diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 88f2e8aad..ea4078db0 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -807,8 +807,8 @@ bounce_element(El, Condition) -> "result" -> ok; _ -> Err = exmpp_stanza:reply_with_error(El, Condition), - From = exmpp_jid:list_to_jid(exmpp_stanza:get_sender(El)), - To = exmpp_jid:list_to_jid(exmpp_stanza:get_recipient(El)), + From = exmpp_jid:binary_to_jid(exmpp_stanza:get_sender(El)), + To = exmpp_jid:binary_to_jid(exmpp_stanza:get_recipient(El)), % No namespace conversion (:server <-> :client) is done. % This is handled by C2S and S2S send_element functions. ejabberd_router:route(To, From, Err) diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 3a819c130..bc8266b19 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -154,7 +154,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS, attrs = Attrs}}, StateData) -> %% component served by this Jabber server. %% However several transports don't respect that, %% so ejabberd doesn't check 'to' attribute (EJAB-717) - To = exmpp_stanza:get_recipient_from_attrs(Attrs), + To = binary_to_list(exmpp_stanza:get_recipient_from_attrs(Attrs)), Opening_Reply = exmpp_stream:opening_reply(xml:crypt(To), ?NS_COMPONENT_ACCEPT, {0, 0}, StateData#state.streamid), @@ -227,10 +227,10 @@ stream_established({xmlstreamelement, El}, StateData) -> %% when accept packets from any address. %% In this case, the component can send packet of %% behalf of the server users. - false -> exmpp_jid:list_to_jid(From); + false -> exmpp_jid:binary_to_jid(From); %% The default is the standard behaviour in XEP-0114 _ -> - FromJID1 = exmpp_jib:string_to_jid(From), + FromJID1 = exmpp_jid:binary_to_jid(From), Server = exmpp_jid:ldomain_as_list(FromJID1), case lists:member(Server, StateData#state.hosts) of true -> FromJID1; @@ -240,7 +240,7 @@ stream_established({xmlstreamelement, El}, StateData) -> To = exmpp_stanza:get_recipient(El), ToJID = case To of undefined -> error; - _ -> exmpp_jib:string_to_jid(To) + _ -> exmpp_jib:binary_to_jid(To) end, if ((El#xmlel.name == 'iq') or (El#xmlel.name == 'message') or diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl index 70f2900f2..9a92347ed 100644 --- a/src/mod_adhoc.erl +++ b/src/mod_adhoc.erl @@ -81,8 +81,8 @@ stop(Host) -> %------------------------------------------------------------------------- -get_local_commands(Acc, _From, To, "", Lang) -> - Server = exmpp_jid:domain_as_list(To), +get_local_commands(Acc, _From, To, <<>>, Lang) -> + Server = exmpp_jid:domain(To), LServer = exmpp_jid:ldomain_as_list(To), Display = gen_mod:get_module_opt(LServer, ?MODULE, report_commands_node, false), case Display of @@ -96,16 +96,17 @@ get_local_commands(Acc, _From, To, "", Lang) -> Nodes = [#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [#xmlattr{name = 'jid', value = Server}, - #xmlattr{name = 'node', value = ?NS_ADHOC_s}, - #xmlattr{name = 'name', value = translate:translate(Lang, "Commands")}] + #xmlattr{name = 'node', value = list_to_binary(?NS_ADHOC_s)}, + #xmlattr{name = 'name', + value = list_to_binary(translate:translate(Lang, "Commands"))}] }], {result, Items ++ Nodes} end; -get_local_commands(_Acc, From, To, ?NS_ADHOC_s, Lang) -> +get_local_commands(_Acc, From, To, ?NS_ADHOC_b, Lang) -> ejabberd_hooks:run_fold(adhoc_local_items, exmpp_jid:ldomain(To), {result, []}, [From, To, Lang]); -get_local_commands(_Acc, _From, _To, "ping", _Lang) -> +get_local_commands(_Acc, _From, _To, <<"ping">>, _Lang) -> {result, []}; get_local_commands(Acc, _From, _To, _Node, _Lang) -> @@ -113,7 +114,7 @@ get_local_commands(Acc, _From, _To, _Node, _Lang) -> %------------------------------------------------------------------------- -get_sm_commands(Acc, _From, To, "", Lang) -> +get_sm_commands(Acc, _From, To, <<>>, Lang) -> LServer = exmpp_jid:ldomain_as_list(To), Display = gen_mod:get_module_opt(LServer, ?MODULE, report_commands_node, false), case Display of @@ -126,14 +127,14 @@ get_sm_commands(Acc, _From, To, "", Lang) -> end, Nodes = [#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(To)}, - #xmlattr{name = 'node', value = ?NS_ADHOC_s}, - #xmlattr{name = 'name', value = translate:translate(Lang, "Commands")}] + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(To)}, + #xmlattr{name = 'node', value = list_to_binary(?NS_ADHOC_s)}, + #xmlattr{name = 'name', value = list_to_binary(translate:translate(Lang, "Commands"))}] }], {result, Items ++ Nodes} end; -get_sm_commands(_Acc, From, To, ?NS_ADHOC_s, Lang) -> +get_sm_commands(_Acc, From, To, ?NS_ADHOC_b, Lang) -> ejabberd_hooks:run_fold(adhoc_sm_items, exmpp_jid:ldomain(To), {result, []}, [From, To, Lang]); get_sm_commands(Acc, _From, _To, _Node, _Lang) -> @@ -142,17 +143,17 @@ get_sm_commands(Acc, _From, _To, _Node, _Lang) -> %------------------------------------------------------------------------- %% On disco info request to the ad-hoc node, return automation/command-list. -get_local_identity(Acc, _From, _To, ?NS_ADHOC_s, Lang) -> +get_local_identity(Acc, _From, _To, ?NS_ADHOC_b, Lang) -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = - [#xmlattr{name = 'category', value = "automation"}, - #xmlattr{name = 'type', value = "command-list"}, - #xmlattr{name = 'name', value = translate:translate(Lang, "Commands")}]} | Acc]; + [#xmlattr{name = 'category', value = <<"automation">>}, + #xmlattr{name = 'type', value = <<"command-list">>}, + #xmlattr{name = 'name', value = list_to_binary(translate:translate(Lang, "Commands"))}]} | Acc]; -get_local_identity(Acc, _From, _To, "ping", Lang) -> +get_local_identity(Acc, _From, _To, <<"ping">>, Lang) -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = - [#xmlattr{name = 'category', value = "automation"}, - #xmlattr{name = 'type', value = "command-node"}, - #xmlattr{name = 'name', value = translate:translate(Lang, "Ping")}]} | Acc]; + [#xmlattr{name = 'category', value = <<"automation">>}, + #xmlattr{name = 'type', value = <<"command-node">>}, + #xmlattr{name = 'name', value = list_to_binary(translate:translate(Lang, "Ping"))}]} | Acc]; get_local_identity(Acc, _From, _To, _Node, _Lang) -> Acc. @@ -162,27 +163,27 @@ get_local_identity(Acc, _From, _To, _Node, _Lang) -> %% On disco info request to the ad-hoc node, return automation/command-list. get_sm_identity(Acc, _From, _To, ?NS_ADHOC_s, Lang) -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = - [#xmlattr{name = 'category', value = "automation"}, - #xmlattr{name = 'type', value = "command-list"}, - #xmlattr{name = 'name', value = translate:translate(Lang, "Commands")}]} | Acc]; + [#xmlattr{name = 'category', value = <<"automation">>}, + #xmlattr{name = 'type', value = <<"command-list">>}, + #xmlattr{name = 'name', value = list_to_binary(translate:translate(Lang, "Commands"))}]} | Acc]; get_sm_identity(Acc, _From, _To, _Node, _Lang) -> Acc. %------------------------------------------------------------------------- -get_local_features(Acc, _From, _To, "", _Lang) -> +get_local_features(Acc, _From, _To, <<>>, _Lang) -> Feats = case Acc of {result, I} -> I; _ -> [] end, {result, Feats ++ [?NS_ADHOC_s]}; -get_local_features(_Acc, _From, _To, ?NS_ADHOC_s, _Lang) -> +get_local_features(_Acc, _From, _To, ?NS_ADHOC_b, _Lang) -> %% override all lesser features... {result, []}; -get_local_features(_Acc, _From, _To, "ping", _Lang) -> +get_local_features(_Acc, _From, _To, <<"ping">>, _Lang) -> %% override all lesser features... {result, [?NS_ADHOC_s]}; @@ -236,7 +237,7 @@ process_adhoc_request(From, To, IQ_Rec, Hook) -> ping_item(Acc, _From, To, Lang) -> - Server = exmpp_jid:domain_as_list(To), + Server = exmpp_jid:domain(To), Items = case Acc of {result, I} -> I; @@ -245,8 +246,8 @@ ping_item(Acc, _From, To, Lang) -> end, Nodes = [#xmlel{ns = ?NS_DISCO_INFO, name = 'item', attrs = [#xmlattr{name = 'jid', value = Server}, - #xmlattr{name = 'node', value = "ping"}, - #xmlattr{name = 'name', value = translate:translate(Lang, "Ping")}]}], + #xmlattr{name = 'node', value = <<"ping">>}, + #xmlattr{name = 'name', value = list_to_binary(translate:translate(Lang, "Ping"))}]}], {result, Items ++ Nodes}. diff --git a/src/mod_announce.erl b/src/mod_announce.erl index 7ef24156e..f3a7cbb37 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -179,12 +179,12 @@ announce(From, To, Packet) -> %% Announcing via ad-hoc commands -define(INFO_COMMAND(Lang, Node), [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = - [#xmlattr{name = 'category', value = "automation"}, - #xmlattr{name = 'type', value = "command-node"}, - #xmlattr{name = 'name', value = get_title(Lang, Node)}]}]). + [#xmlattr{name = 'category', value = <<"automation">>}, + #xmlattr{name = 'type', value = <<"command-node">>}, + #xmlattr{name = 'name', value = list_to_binary(get_title(Lang, Node))}]}]). disco_identity(Acc, _From, _To, Node, Lang) -> - LNode = tokenize(Node), + LNode = tokenize(binary_to_list(Node)), case LNode of ?NS_ADMINL("announce") -> ?INFO_COMMAND(Lang, Node); @@ -220,7 +220,7 @@ disco_identity(Acc, _From, _To, Node, Lang) -> {result, Feats} end). -disco_features(Acc, From, To, "announce", _Lang) -> +disco_features(Acc, From, To, <<"announce">>, _Lang) -> LServer = exmpp_jid:ldomain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> @@ -248,25 +248,25 @@ disco_features(Acc, From, To, Node, _Lang) -> AccessGlobal = gen_mod:get_module_opt(global, ?MODULE, access, none), AllowGlobal = acl:match_rule(global, AccessGlobal, From), case Node of - ?NS_ADMIN_s ++ "#announce" -> + <> -> ?INFO_RESULT(Allow, [?NS_ADHOC_s]); - ?NS_ADMIN_s ++ "#announce-all" -> + <> -> ?INFO_RESULT(Allow, [?NS_ADHOC_s]); - ?NS_ADMIN_s ++ "#set-motd" -> + <> -> ?INFO_RESULT(Allow, [?NS_ADHOC_s]); - ?NS_ADMIN_s ++ "#edit-motd" -> + <> -> ?INFO_RESULT(Allow, [?NS_ADHOC_s]); - ?NS_ADMIN_s ++ "#delete-motd" -> + <> -> ?INFO_RESULT(Allow, [?NS_ADHOC_s]); - ?NS_ADMIN_s ++ "#announce-allhosts" -> + <> -> ?INFO_RESULT(AllowGlobal, [?NS_ADHOC_s]); - ?NS_ADMIN_s ++ "#announce-all-allhosts" -> + <> -> ?INFO_RESULT(AllowGlobal, [?NS_ADHOC_s]); - ?NS_ADMIN_s ++ "#set-motd-allhosts" -> + <> -> ?INFO_RESULT(AllowGlobal, [?NS_ADHOC_s]); - ?NS_ADMIN_s ++ "#edit-motd-allhosts" -> + <> -> ?INFO_RESULT(AllowGlobal, [?NS_ADHOC_s]); - ?NS_ADMIN_s ++ "#delete-motd-allhosts" -> + <> -> ?INFO_RESULT(AllowGlobal, [?NS_ADHOC_s]); _ -> Acc @@ -279,7 +279,7 @@ disco_features(Acc, From, To, Node, _Lang) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [#xmlattr{name = 'jid', value = Server}, #xmlattr{name = 'node', value = Node}, - #xmlattr{name = 'name', value = get_title(Lang, Node)}]}). + #xmlattr{name = 'name', value = list_to_binary(get_title(Lang, Node))}]}). -define(ITEMS_RESULT(Allow, Items), case Allow of @@ -289,9 +289,9 @@ disco_features(Acc, From, To, Node, _Lang) -> {result, Items} end). -disco_items(Acc, From, To, "", Lang) -> +disco_items(Acc, From, To, <<>>, Lang) -> LServer = exmpp_jid:ldomain_as_list(To), - Server = exmpp_jid:domain_as_list(To), + Server = exmpp_jid:domain(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> @@ -308,12 +308,12 @@ disco_items(Acc, From, To, "", Lang) -> {result, I} -> I; _ -> [] end, - Nodes = [?NODE_TO_ITEM(Lang, Server, "announce")], + Nodes = [?NODE_TO_ITEM(Lang, Server, <<"announce">>)], {result, Items ++ Nodes} end end; -disco_items(Acc, From, To, "announce", Lang) -> +disco_items(Acc, From, To, <<"announce">>, Lang) -> LServer = exmpp_jid:ldomain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> @@ -333,25 +333,25 @@ disco_items(Acc, From, To, Node, _Lang) -> AccessGlobal = gen_mod:get_module_opt(global, ?MODULE, access, none), AllowGlobal = acl:match_rule(global, AccessGlobal, From), case Node of - ?NS_ADMIN_s ++ "#announce" -> + <> -> ?ITEMS_RESULT(Allow, []); - ?NS_ADMIN_s ++ "#announce-all" -> + <> -> ?ITEMS_RESULT(Allow, []); - ?NS_ADMIN_s ++ "#set-motd" -> + <> -> ?ITEMS_RESULT(Allow, []); - ?NS_ADMIN_s ++ "#edit-motd" -> + <> -> ?ITEMS_RESULT(Allow, []); - ?NS_ADMIN_s ++ "#delete-motd" -> + <> -> ?ITEMS_RESULT(Allow, []); - ?NS_ADMIN_s ++ "#announce-allhosts" -> + <> -> ?ITEMS_RESULT(AllowGlobal, []); - ?NS_ADMIN_s ++ "#announce-all-allhosts" -> + <> -> ?ITEMS_RESULT(AllowGlobal, []); - ?NS_ADMIN_s ++ "#set-motd-allhosts" -> + <> -> ?ITEMS_RESULT(AllowGlobal, []); - ?NS_ADMIN_s ++ "#edit-motd-allhosts" -> + <> -> ?ITEMS_RESULT(AllowGlobal, []); - ?NS_ADMIN_s ++ "#delete-motd-allhosts" -> + <> -> ?ITEMS_RESULT(AllowGlobal, []); _ -> Acc @@ -362,26 +362,26 @@ disco_items(Acc, From, To, Node, _Lang) -> announce_items(Acc, From, To, Lang) -> LServer = exmpp_jid:ldomain_as_list(To), - Server = exmpp_jid:domain_as_list(To), + Server = exmpp_jid:domain(To), Access1 = gen_mod:get_module_opt(LServer, ?MODULE, access, none), Nodes1 = case acl:match_rule(LServer, Access1, From) of allow -> - [?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#announce"), - ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#announce-all"), - ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#set-motd"), - ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#edit-motd"), - ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#delete-motd")]; + [?NODE_TO_ITEM(Lang, Server, <>), + ?NODE_TO_ITEM(Lang, Server, <>), + ?NODE_TO_ITEM(Lang, Server, <>), + ?NODE_TO_ITEM(Lang, Server, <>), + ?NODE_TO_ITEM(Lang, Server, <>)]; deny -> [] end, Access2 = gen_mod:get_module_opt(global, ?MODULE, access, none), Nodes2 = case acl:match_rule(global, Access2, From) of allow -> - [?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#announce-allhosts"), - ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#announce-all-allhosts"), - ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#set-motd-allhosts"), - ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#edit-motd-allhosts"), - ?NODE_TO_ITEM(Lang, Server, ?NS_ADMIN_s ++ "#delete-motd-allhosts")]; + [?NODE_TO_ITEM(Lang, Server, <>), + ?NODE_TO_ITEM(Lang, Server, <>), + ?NODE_TO_ITEM(Lang, Server, <>), + ?NODE_TO_ITEM(Lang, Server, <>), + ?NODE_TO_ITEM(Lang, Server, <>)]; deny -> [] end, @@ -481,17 +481,17 @@ announce_commands(From, To, end. -define(VVALUE(Val), - #xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Val)}]}). + #xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = Val}]}). -define(VVALUEL(Val), case Val of - "" -> []; + <<>> -> []; _ -> [?VVALUE(Val)] end). -define(TVFIELD(Type, Var, Val), #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, #xmlattr{name = 'var', value = Var}], children = ?VVALUEL(Val)}). --define(HFIELD(), ?TVFIELD("hidden", "FORM_TYPE", ?NS_ADMIN_s)). +-define(HFIELD(), ?TVFIELD(<<"hidden">>, <<"FORM_TYPE">>, list_to_binary(?NS_ADMIN_s))). generate_adhoc_form(Lang, Node, ServerHost) -> LNode = tokenize(Node), @@ -502,29 +502,29 @@ generate_adhoc_form(Lang, Node, ServerHost) -> {[], []} end, #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = - [#xmlattr{name = 'type', value = "form"}], children = + [#xmlattr{name = 'type', value = <<"form">>}], children = [?HFIELD(), #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(get_title(Lang, Node))}]}] ++ if (LNode == ?NS_ADMINL("delete-motd")) or (LNode == ?NS_ADMINL("delete-motd-allhosts")) -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = "confirm"}, - #xmlattr{name = 'type', value = "boolean"}, - #xmlattr{name = 'label', value = translate:translate(Lang, "Really delete message of the day?")}], children = + [#xmlattr{name = 'var', value = <<"confirm">>}, + #xmlattr{name = 'type', value = <<"boolean">>}, + #xmlattr{name = 'label', value = list_to_binary(translate:translate(Lang, "Really delete message of the day?"))}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"true">>}]}]}]; true -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = "subject"}, - #xmlattr{name = 'type', value = "text-single"}, - #xmlattr{name = 'label', value = translate:translate(Lang, "Subject")}], children = - ?VVALUEL(OldSubject)}, + [#xmlattr{name = 'var', value = <<"subject">>}, + #xmlattr{name = 'type', value = <<"text-single">>}, + #xmlattr{name = 'label', value = list_to_binary(translate:translate(Lang, "Subject"))}], children = + ?VVALUEL(list_to_binary(OldSubject))}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = "body"}, - #xmlattr{name = 'type', value = "text-multi"}, - #xmlattr{name = 'label', value = translate:translate(Lang, "Message body")}], children = - ?VVALUEL(OldBody)}] + [#xmlattr{name = 'var', value = <<"body">>}, + #xmlattr{name = 'type', value = <<"text-multi">>}, + #xmlattr{name = 'label', value = list_to_binary(translate:translate(Lang, "Message body"))}], children = + ?VVALUEL(list_to_binary(OldBody))}] end}. join_lines([]) -> @@ -569,7 +569,7 @@ handle_adhoc_form(From, To, node = Node, sessionid = SessionID, status = completed}, - Packet = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', attrs = [#xmlattr{name = 'type', value = "normal"}], children = + Packet = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', attrs = [#xmlattr{name = 'type', value = <<"normal">>}], children = if Subject /= [] -> [#xmlel{ns = ?NS_JABBER_CLIENT, name = 'subject', children = [#xmlcdata{cdata = list_to_binary(Subject)}]}]; diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 9fb3f72c5..1271e976a 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -51,7 +51,7 @@ -include("ejabberd.hrl"). -include("adhoc.hrl"). --define(T(Lang, Text), translate:translate(Lang, Text)). +-define(T(Lang, Text), list_to_binary(translate:translate(Lang, Text))). %% Copied from ejabberd_sm.erl -record(session, {sid, usr, us, priority, info}). @@ -96,11 +96,11 @@ stop(Host) -> #xmlattr{name = 'name', value = ?T(Lang, Name)}]}]). -define(INFO_COMMAND(Name, Lang), - ?INFO_IDENTITY("automation", "command-node", Name, Lang)). + ?INFO_IDENTITY(<<"automation">>, <<"command-node">>, Name, Lang)). -define(NODEJID(To, Name, Node), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(To)}, + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(To)}, #xmlattr{name = 'name', value = ?T(Lang, Name)}, #xmlattr{name = 'node', value = Node}]}). @@ -110,7 +110,7 @@ stop(Host) -> #xmlattr{name = 'name', value = ?T(Lang, Name)}, #xmlattr{name = 'node', value = Node}]}). --define(NS_ADMINX(Sub), ?NS_ADMIN_s++"#"++Sub). +-define(NS_ADMINX(Sub), <>). -define(NS_ADMINL(Sub), ["http:","jabber.org","protocol","admin", Sub]). tokenize(Node) -> string:tokens(Node, "/#"). @@ -123,10 +123,10 @@ get_sm_identity(Acc, _From, _To, Node, Lang) -> end. get_local_identity(Acc, _From, _To, Node, Lang) -> - LNode = tokenize(Node), + LNode = tokenize(binary_to_list(Node)), case LNode of ["running nodes", ENode] -> - ?INFO_IDENTITY("ejabberd", "node", ENode, Lang); + ?INFO_IDENTITY(<<"ejabberd">>, <<"node">>, ENode, Lang); ["running nodes", _ENode, "DB"] -> ?INFO_COMMAND("Database", Lang); ["running nodes", _ENode, "modules", "start"] -> @@ -204,7 +204,7 @@ get_local_features(Acc, From, To, Node, _Lang) -> false -> Acc; _ -> - LNode = tokenize(Node), + LNode = tokenize(binary_to_list(Node)), Allow = acl:match_rule(LServer, configure, From), case LNode of ["config"] -> @@ -263,9 +263,9 @@ adhoc_sm_items(Acc, From, To, Lang) -> empty -> [] end, Nodes = [#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(To)}, + [#xmlattr{name = 'jid', value = exmpp_jid:jid_binary(To)}, #xmlattr{name = 'name', value = ?T(Lang, "Configuration")}, - #xmlattr{name = 'node', value = "config"}]}], + #xmlattr{name = 'node', value = <<"config">>}]}], {result, Items ++ Nodes}; _ -> Acc @@ -283,10 +283,10 @@ get_sm_items(Acc, From, To, Node, Lang) -> {result, Its} -> Its; empty -> [] end, - case {acl:match_rule(LServer, configure, From), Node} of + case {acl:match_rule(LServer, configure, From), binary_to_list(Node)} of {allow, ""} -> - Nodes = [?NODEJID(To, "Configuration", "config"), - ?NODEJID(To, "User Management", "user")], + Nodes = [?NODEJID(To, "Configuration", <<"config">>), + ?NODEJID(To, "User Management", <<"user">>)], {result, Items ++ Nodes ++ get_user_resources(To)}; {allow, "config"} -> {result, []}; @@ -303,17 +303,16 @@ get_user_resources(BareJID) -> lists:map(fun(R) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [#xmlattr{name = 'jid', - value = exmpp_jid:jid_to_list( + value = exmpp_jid:jid_to_binary( exmpp_jid:bare_jid_to_jid(BareJID, R))}, #xmlattr{name = 'name', - value = exmpp_jid:lnode_as_list(BareJID)}]} + value = exmpp_jid:lnode(BareJID)}]} end, lists:sort(Rs)). %%%----------------------------------------------------------------------- adhoc_local_items(Acc, From, To, Lang) -> LServer = exmpp_jid:ldomain_as_list(To), - Server = exmpp_jid:domain_as_list(To), case acl:match_rule(LServer, configure, From) of allow -> Items = case Acc of @@ -321,7 +320,7 @@ adhoc_local_items(Acc, From, To, Lang) -> empty -> [] end, %% Recursively get all configure commands - Nodes = recursively_get_local_items(LServer, "", Server, Lang), + Nodes = recursively_get_local_items(LServer, "", exmpp_jid:domain(To), Lang), Nodes1 = lists:filter( fun(N) -> Nd = exmpp_xml:get_attribute(N, 'node', ""), @@ -374,7 +373,7 @@ recursively_get_local_items(LServer, Node, Server, Lang) -> Fallback; allow -> case get_local_items(LServer, LNode, - exmpp_jid:jid_to_list(To), Lang) of + exmpp_jid:jid_to_binary(To), Lang) of {result, Res} -> {result, Res}; {error, Error} -> @@ -382,7 +381,7 @@ recursively_get_local_items(LServer, Node, Server, Lang) -> end end). -get_local_items(Acc, From, To, "", Lang) -> +get_local_items(Acc, From, To, <<>>, Lang) -> LServer = exmpp_jid:ldomain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> @@ -398,7 +397,7 @@ get_local_items(Acc, From, To, "", Lang) -> {result, Items}; allow -> case get_local_items(LServer, [], - exmpp_jid:jid_to_list(To), Lang) of + exmpp_jid:jid_to_binary(To), Lang) of {result, Res} -> {result, Items ++ Res}; {error, _Error} -> @@ -413,7 +412,7 @@ get_local_items(Acc, From, To, Node, Lang) -> false -> Acc; _ -> - LNode = tokenize(Node), + LNode = tokenize(binary_to_list(Node)), Allow = acl:match_rule(LServer, configure, From), case LNode of ["config"] -> @@ -465,19 +464,19 @@ get_local_items(Acc, From, To, Node, Lang) -> get_local_items(_Host, [], Server, Lang) -> {result, - [?NODE("Configuration", "config"), - ?NODE("User Management", "user"), - ?NODE("Online Users", "online users"), - ?NODE("All Users", "all users"), - ?NODE("Outgoing s2s Connections", "outgoing s2s"), - ?NODE("Running Nodes", "running nodes"), - ?NODE("Stopped Nodes", "stopped nodes") + [?NODE("Configuration", <<"config">>), + ?NODE("User Management", <<"user">>), + ?NODE("Online Users", <<"online users">>), + ?NODE("All Users", <<"all users">>), + ?NODE("Outgoing s2s Connections", <<"outgoing s2s">>), + ?NODE("Running Nodes", <<"running nodes">>), + ?NODE("Stopped Nodes", <<"stopped nodes">>) ]}; get_local_items(_Host, ["config"], Server, Lang) -> {result, - [?NODE("Access Control Lists", "config/acls"), - ?NODE("Access Rules", "config/access") + [?NODE("Access Control Lists", <<"config/acls">>), + ?NODE("Access Rules", <<"config/access">>) ]}; get_local_items(_Host, ["config", _], _Server, _Lang) -> @@ -485,15 +484,15 @@ get_local_items(_Host, ["config", _], _Server, _Lang) -> get_local_items(_Host, ["user"], Server, Lang) -> {result, - [?NODE("Add User", ?NS_ADMINX("add-user")), - ?NODE("Delete User", ?NS_ADMINX("delete-user")), - ?NODE("End User Session", ?NS_ADMINX("end-user-session")), - ?NODE("Get User Password", ?NS_ADMINX("get-user-password")), - ?NODE("Change User Password",?NS_ADMINX("change-user-password")), - ?NODE("Get User Last Login Time", ?NS_ADMINX("get-user-lastlogin")), - ?NODE("Get User Statistics", ?NS_ADMINX("user-stats")), - ?NODE("Get Number of Registered Users",?NS_ADMINX("get-registered-users-num")), - ?NODE("Get Number of Online Users",?NS_ADMINX("get-online-users-num")) + [?NODE("Add User", ?NS_ADMINX(<<"add-user">>)), + ?NODE("Delete User", ?NS_ADMINX(<<"delete-user">>)), + ?NODE("End User Session", ?NS_ADMINX(<<"end-user-session">>)), + ?NODE("Get User Password", ?NS_ADMINX(<<"get-user-password">>)), + ?NODE("Change User Password",?NS_ADMINX(<<"change-user-password">>)), + ?NODE("Get User Last Login Time", ?NS_ADMINX(<<"get-user-lastlogin">>)), + ?NODE("Get User Statistics", ?NS_ADMINX(<<"user-stats">>)), + ?NODE("Get Number of Registered Users",?NS_ADMINX(<<"get-registered-users-num">>)), + ?NODE("Get Number of Online Users",?NS_ADMINX(<<"get-online-users-num">>)) ]}; get_local_items(_Host, ["http:" | _], _Server, _Lang) -> @@ -518,8 +517,8 @@ get_local_items(Host, ["all users", [$@ | Diap]], _Server, _Lang) -> Sub = lists:sublist(SUsers, N1, N2 - N1 + 1), lists:map(fun({S, U}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(U, S)}, - #xmlattr{name = 'name', value = exmpp_jid:jid_to_list(U, S)}]} + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(U, S)}, + #xmlattr{name = 'name', value = exmpp_jid:jid_to_binary(U, S)}]} end, Sub) end of {'EXIT', _Reason} -> @@ -542,43 +541,47 @@ get_local_items(_Host, ["stopped nodes"], _Server, Lang) -> {result, get_stopped_nodes(Lang)}; get_local_items(_Host, ["running nodes", ENode], Server, Lang) -> + ENodeB = list_to_binary(ENode), {result, - [?NODE("Database", "running nodes/" ++ ENode ++ "/DB"), - ?NODE("Modules", "running nodes/" ++ ENode ++ "/modules"), - ?NODE("Backup Management", "running nodes/" ++ ENode ++ "/backup"), + [?NODE("Database", <<"running nodes/", ENodeB/binary, "/DB">>), + ?NODE("Modules", <<"running nodes/", ENodeB/binary, "/modules">>), + ?NODE("Backup Management", <<"running nodes/", ENodeB/binary, "/backup">>), ?NODE("Import Users From jabberd 1.4 Spool Files", - "running nodes/" ++ ENode ++ "/import"), - ?NODE("Restart Service", "running nodes/" ++ ENode ++ "/restart"), - ?NODE("Shut Down Service", "running nodes/" ++ ENode ++ "/shutdown") + <<"running nodes/", ENodeB/binary, "/import">>), + ?NODE("Restart Service", <<"running nodes/", ENodeB/binary, "/restart">>), + ?NODE("Shut Down Service", <<"running nodes/", ENodeB/binary, "/shutdown">>) ]}; get_local_items(_Host, ["running nodes", _ENode, "DB"], _Server, _Lang) -> {result, []}; get_local_items(_Host, ["running nodes", ENode, "modules"], Server, Lang) -> + ENodeB = list_to_binary(ENode), {result, - [?NODE("Start Modules", "running nodes/" ++ ENode ++ "/modules/start"), - ?NODE("Stop Modules", "running nodes/" ++ ENode ++ "/modules/stop") + [?NODE("Start Modules", <<"running nodes/", ENodeB/binary, "/modules/start">>), + ?NODE("Stop Modules", <<"running nodes/", ENodeB/binary, "/modules/stop">>) ]}; get_local_items(_Host, ["running nodes", _ENode, "modules", _], _Server, _Lang) -> {result, []}; get_local_items(_Host, ["running nodes", ENode, "backup"], Server, Lang) -> + ENodeB = list_to_binary(ENode), {result, - [?NODE("Backup", "running nodes/" ++ ENode ++ "/backup/backup"), - ?NODE("Restore", "running nodes/" ++ ENode ++ "/backup/restore"), + [?NODE("Backup", <<"running nodes/", ENodeB/binary, "/backup/backup">>), + ?NODE("Restore", <<"running nodes/", ENodeB/binary, "/backup/restore">>), ?NODE("Dump to Text File", - "running nodes/" ++ ENode ++ "/backup/textfile") + <<"running nodes/", ENodeB/binary, "/backup/textfile">>) ]}; get_local_items(_Host, ["running nodes", _ENode, "backup", _], _Server, _Lang) -> {result, []}; get_local_items(_Host, ["running nodes", ENode, "import"], Server, Lang) -> + ENodeB = list_to_binary(ENode), {result, - [?NODE("Import File", "running nodes/" ++ ENode ++ "/import/file"), - ?NODE("Import Directory", "running nodes/" ++ ENode ++ "/import/dir") + [?NODE("Import File", <<"running nodes/", ENodeB/binary, "/import/file">>), + ?NODE("Import Directory", <<"running nodes/", ENodeB/binary, "/import/dir">>) ]}; get_local_items(_Host, ["running nodes", _ENode, "import", _], _Server, _Lang) -> @@ -602,8 +605,8 @@ get_online_vh_users(Host) -> SURs = lists:sort([{S, U, R} || {U, S, R} <- USRs]), lists:map(fun({S, U, R}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(U, S, R)}, - #xmlattr{name = 'name', value = exmpp_jid:jid_to_list(U, S)}]} + [#xmlattr{name = 'jid', value = exmpp_jid:jid_binary(U, S, R)}, + #xmlattr{name = 'name', value = exmpp_jid:jid_to_binary(U, S)}]} end, SURs) end. @@ -617,8 +620,8 @@ get_all_vh_users(Host) -> N when N =< 100 -> lists:map(fun({S, U}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(U, S)}, - #xmlattr{name = 'name', value = exmpp_jid:jid_to_list(U, S)}]} + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(U, S)}, + #xmlattr{name = 'name', value = exmpp_jid:jid_to_binary(U, S)}]} end, SUsers); N -> NParts = trunc(math:sqrt(N * 0.618)) + 1, @@ -626,20 +629,19 @@ get_all_vh_users(Host) -> lists:map(fun(K) -> L = K + M - 1, Node = - "@" ++ integer_to_list(K) ++ - "-" ++ integer_to_list(L), + <<"@", (list_to_binary(integer_to_list(K)))/binary, + "-", (list_to_binary(integer_to_list(L)))/binary>>, {FS, FU} = lists:nth(K, SUsers), {LS, LU} = if L < N -> lists:nth(L, SUsers); true -> lists:last(SUsers) end, Name = - FU ++ "@" ++ FS ++ - " -- " ++ - LU ++ "@" ++ LS, + <<(list_to_binary(FU))/binary, "@", (list_to_binary(FS))/binary, + " -- ", (list_to_binary(LU))/binary, "@", (list_to_binary(LS))/binary>>, #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = Host}, - #xmlattr{name = 'node', value = "all users/" ++ Node}, + [#xmlattr{name = 'jid', value = list_to_binary(Host)}, + #xmlattr{name = 'node', value = <<"all users/", Node/binary>>}, #xmlattr{name = 'name', value = Name}]} end, lists:seq(1, N, M)) end @@ -656,10 +658,10 @@ get_outgoing_s2s(Host, Lang) -> lists:map( fun(T) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = Host}, - #xmlattr{name = 'node', value = "outgoing s2s/" ++ T}, + [#xmlattr{name = 'jid', value = list_to_binary(Host)}, + #xmlattr{name = 'node', value = <<"outgoing s2s/", (list_to_binary(T))/binary>>}, #xmlattr{name = 'name', value = - lists:flatten( + list_to_binary( io_lib:format( ?T(Lang, "To ~s"), [T]))}]} end, lists:usort(TConns)) @@ -673,10 +675,10 @@ get_outgoing_s2s(Host, Lang, To) -> lists:map( fun({F, _T}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = Host}, - #xmlattr{name = 'node', value = "outgoing s2s/" ++ To ++ "/" ++ F}, + [#xmlattr{name = 'jid', value = list_to_binary(Host)}, + #xmlattr{name = 'node', value = <<"outgoing s2s/", (list_to_binary(To))/binary, "/", (list_to_binary(F))/binary>>}, #xmlattr{name = 'name', value = - lists:flatten( + list_to_binary( io_lib:format( ?T(Lang, "From ~s"), [F]))}]} end, lists:keysort(1, lists:filter(fun(E) -> @@ -692,10 +694,10 @@ get_running_nodes(Server, _Lang) -> DBNodes -> lists:map( fun(N) -> - S = atom_to_list(N), + S = list_to_binary(atom_to_list(N)), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = Server}, - #xmlattr{name = 'node', value = "running nodes/" ++ S}, + [#xmlattr{name = 'jid', value = list_to_binary(Server)}, + #xmlattr{name = 'node', value = <<"running nodes/", (list_to_binary(S))/binary>>}, #xmlattr{name = 'name', value = S}]} end, lists:sort(DBNodes)) end. @@ -709,10 +711,10 @@ get_stopped_nodes(_Lang) -> DBNodes -> lists:map( fun(N) -> - S = atom_to_list(N), + S = list_to_binary(atom_to_list(N)), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = ?MYNAME}, - #xmlattr{name = 'node', value = "stopped nodes/" ++ S}, + [#xmlattr{name = 'jid', value = list_to_binary(?MYNAME)}, + #xmlattr{name = 'node', value = <<"stopped nodes/", S/binary>>}, #xmlattr{name = 'name', value = S}]} end, lists:sort(DBNodes)) end. @@ -815,8 +817,8 @@ adhoc_local_commands(From, To, -define(TVFIELD(Type, Var, Val), #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, #xmlattr{name = 'var', value = Var}], - children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Val)}]}]}). --define(HFIELD(), ?TVFIELD("hidden", "FORM_TYPE", ?NS_ADMIN_s)). + children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = Val}]}]}). +-define(HFIELD(), ?TVFIELD(<<"hidden">>, <<"FORM_TYPE">>, list_to_binary(?NS_ADMIN_s))). -define(TLFIELD(Type, Label, Var), #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, @@ -827,7 +829,7 @@ adhoc_local_commands(From, To, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, #xmlattr{name = 'label', value = ?T(Lang, Label)}, #xmlattr{name = 'var', value = Var}], - children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Val)}]}]}). + children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = Val}]}]}). -define(XMFIELD(Type, Label, Var, Vals), #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, @@ -836,9 +838,9 @@ adhoc_local_commands(From, To, children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Val)}]} || Val <- Vals]}). -define(TABLEFIELD(Table, Val), - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = "list-single"}, - #xmlattr{name = 'label', value = atom_to_list(Table)}, - #xmlattr{name = 'var', value = atom_to_list(Table)}], + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = <<"list-single">>}, + #xmlattr{name = 'label', value = list_to_binary(atom_to_list(Table))}, + #xmlattr{name = 'var', value = list_to_binary(atom_to_list(Table))}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(atom_to_list(Val))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = [#xmlattr{name = 'label', value = ?T(Lang, "RAM copy")}], @@ -917,7 +919,7 @@ get_form(Host, ["running nodes", ENode, "modules", "stop"], Lang) -> Lang, "Choose modules to stop"))}]} | lists:map(fun(M) -> S = atom_to_list(M), - ?XFIELD("boolean", S, S, "0") + ?XFIELD(<<"boolean">>, S, list_to_binary(S), <<"0">>) end, SModules) ]}]} end @@ -934,21 +936,22 @@ get_form(_Host, ["running nodes", ENode, "modules", "start"], Lang) -> [#xmlcdata{cdata = list_to_binary(?T( Lang, "Enter list of {Module, [Options]}"))}]}, - ?XFIELD("text-multi", "List of modules to start", "modules", "[].") + ?XFIELD(<<"text-multi">>, "List of modules to start", <<"modules">>, <<"[].">>) ]}]}; get_form(_Host, ["running nodes", ENode, "backup", "backup"], Lang) -> {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = - [?HFIELD(), + [ + ?HFIELD(), #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T( Lang, "Backup to File at ") ++ ENode)}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = + #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = [#xmlcdata{cdata = list_to_binary(?T( - Lang, "Enter path to backup file"))}]}, - ?XFIELD("text-single", "Path to File", "path", "") + Lang, "Enter path to backup file"))}]}, + ?XFIELD(<<"text-single">>, "Path to File", <<"path">>, <<"">>) ]}]}; get_form(_Host, ["running nodes", ENode, "backup", "restore"], Lang) -> @@ -962,7 +965,7 @@ get_form(_Host, ["running nodes", ENode, "backup", "restore"], Lang) -> [#xmlcdata{cdata = list_to_binary(?T( Lang, "Enter path to backup file"))}]}, - ?XFIELD("text-single", "Path to File", "path", "") + ?XFIELD(<<"text-single">>, "Path to File", <<"path">>, <<"">>) ]}]}; get_form(_Host, ["running nodes", ENode, "backup", "textfile"], Lang) -> @@ -976,7 +979,7 @@ get_form(_Host, ["running nodes", ENode, "backup", "textfile"], Lang) -> [#xmlcdata{cdata = list_to_binary(?T( Lang, "Enter path to text file"))}]}, - ?XFIELD("text-single", "Path to File", "path", "") + ?XFIELD(<<"text-single">>, "Path to File", <<"path">>, <<"">>) ]}]}; get_form(_Host, ["running nodes", ENode, "import", "file"], Lang) -> @@ -990,7 +993,7 @@ get_form(_Host, ["running nodes", ENode, "import", "file"], Lang) -> [#xmlcdata{cdata = list_to_binary(?T( Lang, "Enter path to jabberd1.4 spool file"))}]}, - ?XFIELD("text-single", "Path to File", "path", "") + ?XFIELD(<<"text-single">>, "Path to File", <<"path">>, <<"">>) ]}]}; get_form(_Host, ["running nodes", ENode, "import", "dir"], Lang) -> @@ -1004,14 +1007,14 @@ get_form(_Host, ["running nodes", ENode, "import", "dir"], Lang) -> [#xmlcdata{cdata = list_to_binary(?T( Lang, "Enter path to jabberd1.4 spool dir"))}]}, - ?XFIELD("text-single", "Path to Dir", "path", "") + ?XFIELD(<<"text-single">>, "Path to Dir", <<"path">>, <<"">>) ]}]}; get_form(_Host, ["running nodes", _ENode, "restart"], Lang) -> Make_option = fun(LabelNum, LabelUnit, Value)-> #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = - [#xmlattr{name = 'label', value = LabelNum ++ ?T(Lang, LabelUnit)}], children = + [#xmlattr{name = 'label', value = <<(list_to_binary(LabelNum))/binary, (?T(Lang, LabelUnit))/binary>>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Value)}]}]} end, {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = @@ -1019,9 +1022,9 @@ get_form(_Host, ["running nodes", _ENode, "restart"], Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "Restart Service"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "list-single"}, + [#xmlattr{name = 'type', value = <<"list-single">>}, #xmlattr{name = 'label', value = ?T(Lang, "Time delay")}, - #xmlattr{name = 'var', value = "delay"}], children = + #xmlattr{name = 'var', value = <<"delay">>}], children = [Make_option("", "immediately", "1"), Make_option("15 ", "seconds", "15"), Make_option("30 ", "seconds", "30"), @@ -1037,15 +1040,15 @@ get_form(_Host, ["running nodes", _ENode, "restart"], Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'required'} ]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "fixed"}, + [#xmlattr{name = 'type', value = <<"fixed">>}, #xmlattr{name = 'label', value = ?T(Lang, "Send announcement to all online users on all hosts")}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = "subject"}, - #xmlattr{name = 'type', value = "text-single"}, + [#xmlattr{name = 'var', value = <<"subject">>}, + #xmlattr{name = 'type', value = <<"text-single">>}, #xmlattr{name = 'label', value = ?T(Lang, "Subject")}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = "announcement"}, - #xmlattr{name = 'type', value = "text-multi"}, + [#xmlattr{name = 'var', value = <<"announcement">>}, + #xmlattr{name = 'type', value = <<"text-multi">>}, #xmlattr{name = 'label', value = ?T(Lang, "Message body")}]} ]}]}; @@ -1053,7 +1056,7 @@ get_form(_Host, ["running nodes", _ENode, "shutdown"], Lang) -> Make_option = fun(LabelNum, LabelUnit, Value)-> #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = - [#xmlattr{name = 'label', value = LabelNum ++ ?T(Lang, LabelUnit)}], children = + [#xmlattr{name = 'label', value = <<(list_to_binary(LabelNum))/binary, (?T(Lang, LabelUnit))/binary>>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Value)}]}]} end, {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = @@ -1061,9 +1064,9 @@ get_form(_Host, ["running nodes", _ENode, "shutdown"], Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "Shut Down Service"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "list-single"}, + [#xmlattr{name = 'type', value = <<"list-single">>}, #xmlattr{name = 'label', value = ?T(Lang, "Time delay")}, - #xmlattr{name = 'var', value = "delay"}], children = + #xmlattr{name = 'var', value = <<"delay">>}], children = [Make_option("", "immediately", "1"), Make_option("15 ", "seconds", "15"), Make_option("30 ", "seconds", "30"), @@ -1079,15 +1082,15 @@ get_form(_Host, ["running nodes", _ENode, "shutdown"], Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'required'} ]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "fixed"}, + [#xmlattr{name = 'type', value = <<"fixed">>}, #xmlattr{name = 'label', value = ?T(Lang, "Send announcement to all online users on all hosts")}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = "subject"}, - #xmlattr{name = 'type', value = "text-single"}, + [#xmlattr{name = 'var', value = <<"subject">>}, + #xmlattr{name = 'type', value = <<"text-single">>}, #xmlattr{name = 'label', value = ?T(Lang, "Subject")}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = "announcement"}, - #xmlattr{name = 'type', value = "text-multi"}, + [#xmlattr{name = 'var', value = <<"announcement">>}, + #xmlattr{name = 'type', value = <<"text-multi">>}, #xmlattr{name = 'label', value = ?T(Lang, "Message body")}]} ]}]}; @@ -1098,11 +1101,11 @@ get_form(Host, ["config", "acls"], Lang) -> [#xmlcdata{cdata = list_to_binary(?T( Lang, "Access Control List Configuration"))}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = "text-multi"}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = <<"text-multi">>}, #xmlattr{name = 'label', value = ?T( Lang, "Access control lists")}, - #xmlattr{name = 'var', value = "acls"}], + #xmlattr{name = 'var', value = <<"acls">>}], children = lists:map(fun(S) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(S)}]} end, @@ -1126,11 +1129,11 @@ get_form(Host, ["config", "access"], Lang) -> [#xmlcdata{cdata = list_to_binary(?T( Lang, "Access Configuration"))}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs =[#xmlattr{name = 'type', value = "text-multi"}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs =[#xmlattr{name = 'type', value = <<"text-multi">>}, #xmlattr{name = 'label', value = ?T( Lang, "Access rules")}, - #xmlattr{name = 'var', value = "access"}], + #xmlattr{name = 'var', value = <<"access">>}], children = lists:map(fun(S) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'value', children =[#xmlcdata{cdata = list_to_binary(S)}]} end, @@ -1153,19 +1156,19 @@ get_form(_Host, ?NS_ADMINL("add-user"), Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "Add User"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "jid-single"}, + [#xmlattr{name = 'type', value = <<"jid-single">>}, #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, - #xmlattr{name = 'var', value = "accountjid"}], children = + #xmlattr{name = 'var', value = <<"accountjid">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "text-private"}, + [#xmlattr{name = 'type', value = <<"text-private">>}, #xmlattr{name = 'label', value = ?T(Lang, "Password")}, - #xmlattr{name = 'var', value = "password"}], children = + #xmlattr{name = 'var', value = <<"password">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "text-private"}, + [#xmlattr{name = 'type', value = <<"text-private">>}, #xmlattr{name = 'label', value = ?T(Lang, "Password Verification")}, - #xmlattr{name = 'var', value = "password-verify"}], children = + #xmlattr{name = 'var', value = <<"password-verify">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; @@ -1175,9 +1178,9 @@ get_form(_Host, ?NS_ADMINL("delete-user"), Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "Delete User"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "jid-multi"}, + [#xmlattr{name = 'type', value = <<"jid-multi">>}, #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, - #xmlattr{name = 'var', value = "accountjids"}], children = + #xmlattr{name = 'var', value = <<"accountjids">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; @@ -1187,9 +1190,9 @@ get_form(_Host, ?NS_ADMINL("end-user-session"), Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "End User Session"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "jid-single"}, + [#xmlattr{name = 'type', value = <<"jid-single">>}, #xmlattr{name = 'label', value = list_to_binary(?T(Lang, "Jabber ID"))}, - #xmlattr{name = 'var', value = "accountjid"}], children = + #xmlattr{name = 'var', value = <<"accountjid">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; @@ -1199,9 +1202,9 @@ get_form(_Host, ?NS_ADMINL("get-user-password"), Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "Get User Password"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "jid-single"}, + [#xmlattr{name = 'type', value = <<"jid-single">>}, #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, - #xmlattr{name = 'var', value = "accountjid"}], children = + #xmlattr{name = 'var', value = <<"accountjid">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; @@ -1211,14 +1214,14 @@ get_form(_Host, ?NS_ADMINL("change-user-password"), Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "Get User Password"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "jid-single"}, + [#xmlattr{name = 'type', value = <<"jid-single">>}, #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, - #xmlattr{name = 'var', value = "accountjid"}], children = + #xmlattr{name = 'var', value = <<"accountjid">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "text-private"}, + [#xmlattr{name = 'type', value = <<"text-private">>}, #xmlattr{name = 'label', value = ?T(Lang, "Password")}, - #xmlattr{name = 'var', value = "password"}], children = + #xmlattr{name = 'var', value = <<"password">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; @@ -1228,9 +1231,9 @@ get_form(_Host, ?NS_ADMINL("get-user-lastlogin"), Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "Get User Last Login Time"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "jid-single"}, + [#xmlattr{name = 'type', value = <<"jid-single">>}, #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, - #xmlattr{name = 'var', value = "accountjid"}], children = + #xmlattr{name = 'var', value = <<"accountjid">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; @@ -1240,9 +1243,9 @@ get_form(_Host, ?NS_ADMINL("user-stats"), Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "Get User Statistics"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "jid-single"}, + [#xmlattr{name = 'type', value = <<"jid-single">>}, #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, - #xmlattr{name = 'var', value = "accountjid"}], children = + #xmlattr{name = 'var', value = <<"accountjid">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; @@ -1252,9 +1255,9 @@ get_form(Host, ?NS_ADMINL("get-registered-users-num"), Lang) -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "text-single"}, + [#xmlattr{name = 'type', value = <<"text-single">>}, #xmlattr{name = 'label', value = ?T(Lang, "Number of registered users")}, - #xmlattr{name = 'var', value = "registeredusersnum"}], children = + #xmlattr{name = 'var', value = <<"registeredusersnum">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Num)}]}] }]}]}; @@ -1264,9 +1267,9 @@ get_form(Host, ?NS_ADMINL("get-online-users-num"), Lang) -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "text-single"}, + [#xmlattr{name = 'type', value = <<"text-single">>}, #xmlattr{name = 'label', value = ?T(Lang, "Number of online users")}, - #xmlattr{name = 'var', value = "onlineusersnum"}], children = + #xmlattr{name = 'var', value = <<"onlineusersnum">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Num)}]}] }]}]}; @@ -1595,8 +1598,8 @@ set_form(_From, _Host, ?NS_ADMINL("get-user-password"), Lang, XData) -> true = is_list(Password), {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - ?XFIELD("jid-single", "Jabber ID", "accountjid", AccountString), - ?XFIELD("text-single", "Password", "password", Password) + ?XFIELD(<<"jid-single">>, "Jabber ID", <<"accountjid">>, list_to_binary(AccountString)), + ?XFIELD(<<"text-single">>, "Password", <<"password">>, list_to_binary(Password)) ]}]}; set_form(_From, _Host, ?NS_ADMINL("change-user-password"), _Lang, XData) -> @@ -1640,10 +1643,10 @@ set_form(_From, _Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> _ -> ?T(Lang, "Online") end, - {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', value = "result"}], children = + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', value = <<"result">>}], children = [?HFIELD(), - ?XFIELD("jid-single", "Jabber ID", "accountjid", AccountString), - ?XFIELD("text-single", "Last login", "lastlogin", FLast) + ?XFIELD(<<"jid-single">>, "Jabber ID", <<"accountjid">>, list_to_binary(AccountString)), + ?XFIELD(<<"text-single">>, "Last login", <<"lastlogin">>, list_to_binary(FLast)) ]}]}; set_form(_From, _Host, ?NS_ADMINL("user-stats"), Lang, XData) -> @@ -1666,10 +1669,10 @@ set_form(_From, _Host, ?NS_ADMINL("user-stats"), Lang, XData) -> {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), - ?XFIELD("jid-single", "Jabber ID", "accountjid", AccountString), - ?XFIELD("text-single", "Roster size", "rostersize", Rostersize), - ?XMFIELD("text-multi", "IP addresses", "ipaddresses", IPs), - ?XMFIELD("text-multi", "Resources", "onlineresources", Resources) + ?XFIELD(<<"jid-single">>, "Jabber ID", <<"accountjid">>, AccountString), + ?XFIELD(<<"text-single">>, "Roster size", <<"rostersize">>, Rostersize), + ?XMFIELD(<<"text-multi">>, "IP addresses", <<"ipaddresses">>, IPs), + ?XMFIELD(<<"text-multi">>, "Resources", <<"onlineresources">>, Resources) ]}]}; set_form(_From, _Host, _, _Lang, _XData) -> @@ -1699,25 +1702,25 @@ stop_node(From, Host, ENode, Action, XData) -> Delay = list_to_integer(get_value("delay", XData)), Subject = case get_value("subject", XData) of [] -> []; - S -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'var', value = "subject"}], children = + S -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'var', value = <<"subject">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(S)}]}]}] end, Announcement = case get_values("announcement", XData) of [] -> []; - As -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'var', value = "body"}], children = + As -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'var', value = <<"body">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Line)}]} || Line <- As] }] end, case Subject ++ Announcement of [] -> ok; SubEls -> Request = #adhoc_request{ - node = ?NS_ADMINX("announce-allhosts"), + node = binary_to_list(?NS_ADMINX(<<"announce-allhosts">>)), action = "complete", xdata = #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = - [#xmlattr{name = 'type', value = "submit"}], children = + [#xmlattr{name = 'type', value = <<"submit">>}], children = SubEls}, others= [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = - [#xmlattr{name = 'type', value = "submit"}], children = + [#xmlattr{name = 'type', value = <<"submit">>}], children = SubEls}] }, To = exmpp_jid:make_jid(Host), @@ -1799,9 +1802,9 @@ get_sm_form(User, Server, "config", Lang) -> list_to_binary(?T( Lang, "Administration of ") ++ User)}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = "list-single"}, + [#xmlattr{name = 'type', value = <<"list-single">>}, #xmlattr{name = 'label', value = ?T(Lang, "Action on user")}, - #xmlattr{name = 'var', value = "action"}], children = + #xmlattr{name = 'var', value = <<"action">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"edit">>}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = [#xmlattr{name = 'label', value = ?T(Lang, "Edit Properties")}], children = @@ -1810,8 +1813,8 @@ get_sm_form(User, Server, "config", Lang) -> [#xmlattr{name = 'label', value = ?T(Lang, "Remove User")}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"remove">>}]}]} ]}, - ?XFIELD("text-private", "Password", "password", - ejabberd_auth:get_password_s(User, Server)) + ?XFIELD(<<"text-private">>, "Password", <<"password">>, + list_to_binary(ejabberd_auth:get_password_s(User, Server))) ]}]}; get_sm_form(_User, _Server, _Node, _Lang) -> diff --git a/src/mod_configure2.erl b/src/mod_configure2.erl index 9dd9b8c81..252a127bd 100644 --- a/src/mod_configure2.erl +++ b/src/mod_configure2.erl @@ -125,18 +125,18 @@ process_get(#xmlel{ns = ?NS_ECONFIGURE, name = 'info'}) -> S2SConns = ejabberd_s2s:dirty_get_connections(), TConns = lists:usort([element(2, C) || C <- S2SConns]), Attrs = [#xmlattr{name = 'registered-users', value = - integer_to_list(mnesia:table_info(passwd, size))}, + list_to_binary(integer_to_list(mnesia:table_info(passwd, size)))}, #xmlattr{name = 'online-users', value = - integer_to_list(mnesia:table_info(presence, size))}, + list_to_binary(integer_to_list(mnesia:table_info(presence, size)))}, #xmlattr{name = 'running-nodes', value = - integer_to_list(length(mnesia:system_info(running_db_nodes)))}, + list_to_binary(integer_to_list(length(mnesia:system_info(running_db_nodes))))}, #xmlattr{name = 'stopped-nodes', value = - integer_to_list( + list_to_binary(integer_to_list( length(lists:usort(mnesia:system_info(db_nodes) ++ mnesia:system_info(extra_db_nodes)) -- - mnesia:system_info(running_db_nodes)))}, + mnesia:system_info(running_db_nodes))))}, #xmlattr{name = 'outgoing-s2s-servers', value = - integer_to_list(length(TConns))}], + list_to_binary(integer_to_list(length(TConns)))}], {result, #xmlel{ns = ?NS_ECONFIGURE, name = 'info', attrs = Attrs}}; process_get(#xmlel{ns = ?NS_ECONFIGURE, name = 'welcome-message', attrs = Attrs}) -> {Subj, Body} = case ejabberd_config:get_local_option(welcome_message) of diff --git a/src/mod_disco.erl b/src/mod_disco.erl index be36ce749..ab57c109e 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -130,7 +130,7 @@ unregister_extra_domain(Host, Domain) -> process_local_iq_items(From, To, #iq{type = get, payload = SubEl, lang = Lang} = IQ_Rec) -> - Node = exmpp_xml:get_attribute(SubEl, 'node', ""), + Node = exmpp_xml:get_attribute_as_binary(SubEl, 'node', <<>>), case ejabberd_hooks:run_fold(disco_local_items, exmpp_jid:ldomain(To), @@ -138,7 +138,7 @@ process_local_iq_items(From, To, #iq{type = get, payload = SubEl, [From, To, Node, Lang]) of {result, Items} -> ANode = case Node of - "" -> []; + <<>> -> []; _ -> [#xmlattr{name = 'node', value = Node}] end, Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', @@ -153,7 +153,7 @@ process_local_iq_items(_From, _To, #iq{type = set} = IQ_Rec) -> process_local_iq_info(From, To, #iq{type = get, payload = SubEl, lang = Lang} = IQ_Rec) -> - Node = exmpp_xml:get_attribute(SubEl, 'node', ""), + Node = exmpp_xml:get_attribute_as_binary(SubEl, 'node', <<>>), Identity = ejabberd_hooks:run_fold(disco_local_identity, exmpp_jid:ldomain(To), [], @@ -164,7 +164,7 @@ process_local_iq_info(From, To, #iq{type = get, payload = SubEl, [From, To, Node, Lang]) of {result, Features} -> ANode = case Node of - "" -> []; + <<>> -> []; _ -> [#xmlattr{name = 'node', value = Node}] end, Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', @@ -178,11 +178,11 @@ process_local_iq_info(From, To, #iq{type = get, payload = SubEl, process_local_iq_info(_From, _To, #iq{type = set} = IQ_Rec) -> exmpp_iq:error(IQ_Rec, 'not-allowed'). -get_local_identity(Acc, _From, _To, [], _Lang) -> +get_local_identity(Acc, _From, _To, <<>>, _Lang) -> Acc ++ [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [ - #xmlattr{name = 'category', value = "server"}, - #xmlattr{name = 'type', value = "im"}, - #xmlattr{name = 'name', value = "ejabberd"} + #xmlattr{name = 'category', value = <<"server">>}, + #xmlattr{name = 'type', value = <<"im">>}, + #xmlattr{name = 'name', value = <<"ejabberd">>} ]}]; get_local_identity(Acc, _From, _To, _Node, _Lang) -> @@ -191,7 +191,7 @@ get_local_identity(Acc, _From, _To, _Node, _Lang) -> get_local_features({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; -get_local_features(Acc, _From, To, [], _Lang) -> +get_local_features(Acc, _From, To, <<>>, _Lang) -> Feats = case Acc of {result, Features} -> Features; empty -> [] @@ -211,28 +211,30 @@ get_local_features(Acc, _From, _To, _Node, _Lang) -> feature_to_xml({{Feature, _Host}}) -> feature_to_xml(Feature); -feature_to_xml(Feature) when is_list(Feature) -> + +feature_to_xml(Feature) when is_binary(Feature) -> #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ #xmlattr{name = 'var', value = Feature} ]}; + +feature_to_xml(Feature) when is_list(Feature) -> + feature_to_xml(list_to_binary(Feature)); feature_to_xml(Feature) when is_atom(Feature) -> - #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ - #xmlattr{name = 'var', value = atom_to_list(Feature)} - ]}. + feature_to_xml(atom_to_list(Feature)). domain_to_xml({Domain}) -> + domain_to_xml(Domain); +domain_to_xml(Domain) when is_binary(Domain)-> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [ #xmlattr{name = 'jid', value = Domain} ]}; -domain_to_xml(Domain) -> - #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [ - #xmlattr{name = 'jid', value = Domain} - ]}. +domain_to_xml(Domain) when is_list(Domain) -> + domain_to_xml(list_to_binary(Domain)). get_local_services({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; -get_local_services(Acc, _From, To, [], _Lang) -> +get_local_services(Acc, _From, To, <<>>, _Lang) -> Items = case Acc of {result, Its} -> Its; empty -> [] @@ -270,14 +272,14 @@ get_vh_services(Host) -> process_sm_iq_items(From, To, #iq{type = get, payload = SubEl, lang = Lang} = IQ_Rec) -> - Node = exmpp_xml:get_attribute(SubEl, 'node', ""), + Node = exmpp_xml:get_attribute_as_binary(SubEl, 'node', <<>>), case ejabberd_hooks:run_fold(disco_sm_items, exmpp_jid:ldomain(To), empty, [From, To, Node, Lang]) of {result, Items} -> ANode = case Node of - "" -> []; + <<>> -> []; _ -> [#xmlattr{name = 'node', value = Node}] end, Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', @@ -311,7 +313,7 @@ process_sm_iq_items(From, To, #iq{type = set, payload = SubEl} = IQ_Rec) -> get_sm_items({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; -get_sm_items(Acc, From, To, [], _Lang) -> +get_sm_items(Acc, From, To, <<>>, _Lang) -> LFrom = exmpp_jid:lnode_as_list(From), LSFrom = exmpp_jid:ldomain_as_list(From), LTo = exmpp_jid:lnode_as_list(To), @@ -344,7 +346,7 @@ get_sm_items(empty, From, To, _Node, _Lang) -> process_sm_iq_info(From, To, #iq{type = get, payload = SubEl, lang = Lang} = IQ_Rec) -> - Node = exmpp_xml:get_attribute(SubEl, 'node', ""), + Node = exmpp_xml:get_attribute_as_binary(SubEl, 'node', <<>>), Identity = ejabberd_hooks:run_fold(disco_sm_identity, exmpp_jid:ldomain(To), [], @@ -355,7 +357,7 @@ process_sm_iq_info(From, To, #iq{type = get, payload = SubEl, [From, To, Node, Lang]) of {result, Features} -> ANode = case Node of - "" -> []; + <<>> -> []; _ -> [#xmlattr{name = 'node', value = Node}] end, Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', @@ -395,8 +397,8 @@ get_user_resources(JID) -> lists:map(fun(R) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [ #xmlattr{name = 'jid', value = - exmpp_jid:jid_to_list(exmpp_jid:bare_jid_to_jid(JID, R))}, - #xmlattr{name = 'name', value = exmpp_jid:lnode_as_list(JID)} + exmpp_jid:jid_to_binary(exmpp_jid:bare_jid_to_jid(JID, R))}, + #xmlattr{name = 'name', value = exmpp_jid:lnode(JID)} ]} end, lists:sort(Rs)). @@ -408,7 +410,7 @@ get_publish_items(empty, From, To, Node, _Lang) -> LSTo = exmpp_jid:ldomain_as_list(To), if (LFrom == LTo) and (LSFrom == LSTo) -> - retrieve_disco_publish({LTo, LSTo}, Node); + retrieve_disco_publish({LTo, LSTo}, binary_to_list(Node)); true -> empty end; @@ -486,18 +488,18 @@ retrieve_disco_publish(User, Node) -> name = Name, node = PNode}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - lists:append([[#xmlattr{name = 'jid', value = Jid}], + lists:append([[#xmlattr{name = 'jid', value = list_to_binary(Jid)}], case Name of "" -> []; _ -> - [#xmlattr{name = 'name', value = Name}] + [#xmlattr{name = 'name', value = list_to_binary(Name)}] end, case PNode of "" -> []; _ -> - [#xmlattr{name = 'node', value = PNode}] + [#xmlattr{name = 'node', value = list_to_binary(PNode)}] end])} end, Items)} end. diff --git a/src/mod_irc/mod_irc.erl b/src/mod_irc/mod_irc.erl index cadef5e2f..28ab85e63 100644 --- a/src/mod_irc/mod_irc.erl +++ b/src/mod_irc/mod_irc.erl @@ -303,17 +303,17 @@ closed_connection(Host, From, Server) -> iq_disco(Lang) -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = - [#xmlattr{name = 'category', value = "conference"}, - #xmlattr{name = 'type', value = "irc"}, - #xmlattr{name = 'name', value = translate:translate(Lang, "IRC Transport")}]}, + [#xmlattr{name = 'category', value = <<"conference">>}, + #xmlattr{name = 'type', value = <<"irc">>}, + #xmlattr{name = 'name', value = list_to_binary(translate:translate(Lang, "IRC Transport"))}]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [#xmlattr{name = 'var', value = ?NS_DISCO_INFO_s}]}, + [#xmlattr{name = 'var', value = list_to_binary(?NS_DISCO_INFO_s)}]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [#xmlattr{name = 'var', value = ?NS_MUC_s}]}, + [#xmlattr{name = 'var', value = list_to_binary(?NS_MUC_s)}]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [#xmlattr{name = 'var', value = ?NS_INBAND_REGISTER_s}]}, + [#xmlattr{name = 'var', value = list_to_binary(?NS_INBAND_REGISTER_s)}]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [#xmlattr{name = 'var', value = ?NS_VCARD_s}]}]. + [#xmlattr{name = 'var', value = list_to_binary(?NS_VCARD_s)}]}]. iq_get_vcard(Lang) -> [#xmlel{ns = ?NS_VCARD, name = 'FN', children = @@ -439,13 +439,13 @@ get_form(Host, From, [], Lang, DefEnc) -> Lang, "Enter username and encodings you wish to use for " "connecting to IRC servers"))}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = "text-single"}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = <<"text-single">>}, #xmlattr{name = 'label', value = - translate:translate( - Lang, "IRC Username")}, - #xmlattr{name = 'var', value = "username"}], children = + list_to_binary(translate:translate( + Lang, "IRC Username"))}, + #xmlattr{name = 'var', value = <<"username">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Username)}]}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = "fixed"}], children = + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = <<"fixed">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary( lists:flatten( @@ -457,7 +457,7 @@ get_form(Host, From, [], Lang, DefEnc) -> "in format '{\"irc server\", \"encoding\"}'. " "By default this service use \"~s\" encoding."), [DefEnc])))}]}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = "fixed"}], children = + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = <<"fixed">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary( translate:translate( @@ -465,10 +465,10 @@ get_form(Host, From, [], Lang, DefEnc) -> "Example: [{\"irc.lucky.net\", \"koi8-r\"}, " "{\"vendetta.fef.net\", \"iso8859-1\"}]." ))}]}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = "text-multi"}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = <<"text-multi">>}, #xmlattr{name = 'label', value = - translate:translate(Lang, "Encodings")}, - #xmlattr{name = 'var', value = "encodings"}], children = + list_to_binary(translate:translate(Lang, "Encodings"))}, + #xmlattr{name = 'var', value = <<"encodings">>}], children = lists:map( fun(S) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(S)}]} diff --git a/src/mod_irc/mod_irc_connection.erl b/src/mod_irc/mod_irc_connection.erl index 3548effa2..9852db8c5 100644 --- a/src/mod_irc/mod_irc_connection.erl +++ b/src/mod_irc/mod_irc_connection.erl @@ -590,8 +590,8 @@ terminate(_Reason, _StateName, StateData) -> lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, StateData#state.nick), StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = "error"}], children = - [#xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', attrs = [#xmlattr{name = 'code', value = "502"}], children = + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = <<"error">>}], children = + [#xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', attrs = [#xmlattr{name = 'code', value = <<"502">>}], children = [#xmlcdata{cdata = <<"Server Connect Failed">>}]}]}) end, dict:fetch_keys(StateData#state.channels)), case StateData#state.socket of @@ -629,11 +629,11 @@ bounce_messages(Reason) -> ok; _ -> Error = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', - attrs = [#xmlattr{name = 'code', value = "502"}], + attrs = [#xmlattr{name = 'code', value = <<"502">>}], children = [#xmlcdata{cdata = Reason}]}, Err = exmpp_stanza:reply_with_error(El, Error), - From = exmpp_jid:list_to_jid(exmpp_stanza:get_sender(El)), - To = exmpp_jid:list_to_jid(exmpp_stanza:get_recipient(El)), + From = exmpp_jid:binary_to_jid(exmpp_stanza:get_sender(El)), + To = exmpp_jid:binary_to_jid(exmpp_stanza:get_recipient(El)), ejabberd_router:route(To, From, Err) end, bounce_messages(Reason) @@ -678,12 +678,12 @@ process_channel_list_user(StateData, Chan, User) -> end, {User2, Affiliation, Role} = case User1 of - [$@ | U2] -> {U2, "admin", "moderator"}; - [$+ | U2] -> {U2, "member", "participant"}; - [$\% | U2] -> {U2, "admin", "moderator"}; - [$& | U2] -> {U2, "admin", "moderator"}; - [$~ | U2] -> {U2, "admin", "moderator"}; - _ -> {User1, "member", "participant"} + [$@ | U2] -> {U2, <<"admin">>, <<"moderator">>}; + [$+ | U2] -> {U2, <<"member">>, <<"participant">>}; + [$\% | U2] -> {U2, <<"admin">>, <<"moderator">>}; + [$& | U2] -> {U2, <<"admin">>, <<"moderator">>}; + [$~ | U2] -> {U2, <<"admin">>, <<"moderator">>}; + _ -> {User1, <<"member">>, <<"participant">>} end, ejabberd_router:route( exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), @@ -893,11 +893,11 @@ process_part(StateData, Chan, From, String) -> exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = "unavailable"}], children = + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = <<"unavailable">>}], children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [#xmlattr{name = 'affiliation', value = "member"}, - #xmlattr{name = 'role', value = "none"}]}]}, + [#xmlattr{name = 'affiliation', value = <<"member">>}, + #xmlattr{name = 'role', value = <<"none">>}]}]}, #xmlel{ns = ?NS_MUC_USER, name = 'status', children = [#xmlcdata{cdata = list_to_binary(Msg1 ++ " (" ++ FromIdent ++ ")")}]}] }), @@ -927,11 +927,11 @@ process_quit(StateData, From, String) -> lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = "unavailable"}], children = + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = <<"unavailable">>}], children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [#xmlattr{name = 'affiliation', value = "member"}, - #xmlattr{name = 'role', value = "none"}]}]}, + [#xmlattr{name = 'affiliation', value = <<"member">>}, + #xmlattr{name = 'role', value = <<"none">>}]}]}, #xmlel{ns = ?NS_MUC_USER, name = 'status', children = [#xmlcdata{cdata = list_to_binary(Msg1 ++ " (" ++ FromIdent ++ ")")}]} ]}), @@ -953,8 +953,8 @@ process_join(StateData, Channel, From, _String) -> #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [#xmlattr{name = 'affiliation', value = "member"}, - #xmlattr{name = 'role', value = "participant"}]}]}, + [#xmlattr{name = 'affiliation', value = <<"member">>}, + #xmlattr{name = 'role', value = <<"participant">>}]}]}, #xmlel{ns = ?NS_MUC_USER, name = 'status', children = [#xmlcdata{cdata = list_to_binary(FromIdent)}]}]}), @@ -979,8 +979,8 @@ process_mode_o(StateData, Chan, _From, Nick, Affiliation, Role) -> #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [#xmlattr{name = 'affiliation', value = Affiliation}, - #xmlattr{name = 'role', value = Role}]}]}]}). + [#xmlattr{name = 'affiliation', value = list_to_binary(Affiliation)}, + #xmlattr{name = 'role', value = list_to_binary(Role)}]}]}]}). process_kick(StateData, Chan, From, Nick, String) -> Msg = lists:last(string:tokens(String, ":")), @@ -994,12 +994,12 @@ process_kick(StateData, Chan, From, Nick, String) -> exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, Nick), StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = "unavailable"}], children = + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = <<"unavailable">>}], children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [#xmlattr{name = 'affiliation', value = "none"}, - #xmlattr{name = 'role', value = "none"}]}, - #xmlel{ns = ?NS_MUC_USER, name = 'status', attrs = [#xmlattr{name = 'code', value = "307"}]} + [#xmlattr{name = 'affiliation', value = <<"none">>}, + #xmlattr{name = 'role', value = <<"none">>}]}, + #xmlel{ns = ?NS_MUC_USER, name = 'status', attrs = [#xmlattr{name = 'code', value = <<"307">>}]} ]}]}). process_nick(StateData, From, NewNick) -> @@ -1015,13 +1015,13 @@ process_nick(StateData, From, NewNick) -> lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = "unavailable"}], children = + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = <<"unavailable">>}], children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [#xmlattr{name = 'affiliation', value = "member"}, - #xmlattr{name = 'role', value = "participant"}, - #xmlattr{name = 'nick', value = Nick}]}, - #xmlel{ns = ?NS_MUC_USER, name = 'status', attrs = [#xmlattr{name = 'code', value = "303"}]} + [#xmlattr{name = 'affiliation', value = <<"member">>}, + #xmlattr{name = 'role', value = <<"participant">>}, + #xmlattr{name = 'nick', value = list_to_binary(Nick)}]}, + #xmlel{ns = ?NS_MUC_USER, name = 'status', attrs = [#xmlattr{name = 'code', value = <<"303">>}]} ]}]}), ejabberd_router:route( exmpp_jid:make_jid( @@ -1031,8 +1031,8 @@ process_nick(StateData, From, NewNick) -> #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [#xmlattr{name = 'affiliation', value = "member"}, - #xmlattr{name = 'role', value = "participant"}]} + [#xmlattr{name = 'affiliation', value = <<"member">>}, + #xmlattr{name = 'role', value = <<"participant">>}]} ]}]}), ?SETS:add_element(Nick, remove_element(FromUser, Ps)); @@ -1051,8 +1051,8 @@ process_error(StateData, String) -> lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, StateData#state.nick), StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = "error"}], children = - [#xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', attrs = [#xmlattr{name = 'code', value = "502"}], children = + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = <<"error">>}], children = + [#xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', attrs = [#xmlattr{name = 'code', value = <<"502">>}], children = [#xmlcdata{cdata = list_to_binary(String)}]}]}) end, dict:fetch_keys(StateData#state.channels)). diff --git a/src/mod_last.erl b/src/mod_last.erl index 85644b775..b363db588 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -74,7 +74,7 @@ stop(Host) -> process_local_iq(_From, _To, #iq{type = get} = IQ_Rec) -> Sec = trunc(element(1, erlang:statistics(wall_clock))/1000), Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = - [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}]}, + [#xmlattr{name = 'seconds', value = list_to_binary(integer_to_list(Sec))}]}, exmpp_iq:result(IQ_Rec, Response); process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> exmpp_iq:error(IQ_Rec, 'not-allowed'). @@ -121,7 +121,7 @@ get_last(IQ_Rec, LUser, LServer) -> TimeStamp2 = MegaSecs * 1000000 + Secs, Sec = TimeStamp2 - TimeStamp, Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', - attrs = [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}], + attrs = [#xmlattr{name = 'seconds', value = list_to_binary(integer_to_list(Sec))}], children = [#xmlcdata{cdata = Status}]}, exmpp_iq:result(IQ_Rec, Response) end. diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 1dca155e8..286f19867 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -67,7 +67,7 @@ stop(Host) -> process_local_iq(_From, _To, #iq{type = get} = IQ_Rec) -> Sec = trunc(element(1, erlang:statistics(wall_clock))/1000), Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = - [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}]}, + [#xmlattr{name = 'seconds', value = list_to_binary(integer_to_list(Sec))}]}, exmpp_iq:result(IQ_Rec, Response); process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> exmpp_iq:error(IQ_Rec, 'not-allowed'). @@ -116,7 +116,7 @@ get_last(IQ_Rec, LUser, LServer) -> TimeStamp2 = MegaSecs * 1000000 + Secs, Sec = TimeStamp2 - TimeStamp, Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', - attrs = [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}], + attrs = [#xmlattr{name = 'seconds', value = list_to_binary(integer_to_list(Sec))}], children = [#xmlcdata{cdata = list_to_binary(Status)}]}, exmpp_iq:result(IQ_Rec, Response); _ -> diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index e55b19afb..9dd7de980 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -98,19 +98,20 @@ stop(Host) -> %% C) mod_muc:stop was called, and each room is being terminated %% In this case, the mod_muc process died before the room processes %% So the message sending must be catched -room_destroyed(Host, Room, Pid, ServerHost) -> +room_destroyed(Host, Room, Pid, ServerHost) when is_binary(Host), + is_binary(Room) -> catch gen_mod:get_module_proc(ServerHost, ?PROCNAME) ! {room_destroyed, {Room, Host}, Pid}, ok. -store_room(Host, Name, Opts) -> +store_room(Host, Name, Opts) when is_binary(Host), is_binary(Name) -> F = fun() -> mnesia:write(#muc_room{name_host = {Name, Host}, opts = Opts}) end, mnesia:transaction(F). -restore_room(Host, Name) -> +restore_room(Host, Name) when is_binary(Host), is_binary(Name) -> case catch mnesia:dirty_read(muc_room, {Name, Host}) of [#muc_room{opts = Opts}] -> Opts; @@ -118,7 +119,7 @@ restore_room(Host, Name) -> error end. -forget_room(Host, Name) -> +forget_room(Host, Name) when is_binary(Host), is_binary(Name) -> F = fun() -> mnesia:delete({muc_room, {Name, Host}}) end, diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index 4f121e0af..4a169c10f 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -257,9 +257,9 @@ pop_offline_messages(Ls, User, Server) [El] = exmpp_xml:parse_document(XML, [names_as_atom, {check_elems, xmpp}, {check_nss,xmpp}, {check_attrs,xmpp}]), - To = exmpp_jid:list_to_jid( + To = exmpp_jid:binary_to_jid( exmpp_stanza:get_recipient(El)), - From = exmpp_jid:list_to_jid( + From = exmpp_jid:binary_to_jid( exmpp_stanza:get_sender(El)), [{route, From, To, El}] catch diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 674bdd0c6..0b1352d5d 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -156,14 +156,14 @@ process_list_get(LUser, LServer, Name) -> item_to_xml(Item) -> - Attrs1 = [#xmlattr{name = 'action', value = action_to_list(Item#listitem.action)}, - #xmlattr{name = 'order', value = order_to_list(Item#listitem.order)}], + Attrs1 = [#xmlattr{name = 'action', value = action_to_binary(Item#listitem.action)}, + #xmlattr{name = 'order', value = order_to_binary(Item#listitem.order)}], Attrs2 = case Item#listitem.type of none -> Attrs1; Type -> - [#xmlattr{name = 'type', value = type_to_list(Item#listitem.type)}, - #xmlattr{name = 'value', value = value_to_list(Type, Item#listitem.value)} | + [#xmlattr{name = 'type', value = type_to_binary(Item#listitem.type)}, + #xmlattr{name = 'value', value = value_to_binary(Type, Item#listitem.value)} | Attrs1] end, SubEls = case Item#listitem.match_all of @@ -199,34 +199,34 @@ item_to_xml(Item) -> exmpp_xml:set_attributes(#xmlel{ns = ?NS_PRIVACY, name = item, children = SubEls}, Attrs2). -action_to_list(Action) -> +action_to_binary(Action) -> case Action of - allow -> "allow"; - deny -> "deny" + allow -> <<"allow">>; + deny -> <<"deny">> end. -order_to_list(Order) -> - integer_to_list(Order). +order_to_binary(Order) -> + list_to_binary(integer_to_list(Order)). -type_to_list(Type) -> +type_to_binary(Type) -> case Type of - jid -> "jid"; - group -> "group"; - subscription -> "subscription" + jid -> <<"jid">>; + group -> <<"group">>; + subscription -> <<"subscription">> end. -value_to_list(Type, Val) -> +value_to_binary(Type, Val) -> case Type of jid -> {N, D, R} = Val, - exmpp_jid:jid_to_list(N, D, R); + exmpp_jid:jid_to_binary(N, D, R); group -> Val; subscription -> case Val of - both -> "both"; - to -> "to"; - from -> "from"; - none -> "none" + both -> <<"both">>; + to -> <<"to">>; + from -> <<"from">>; + none -> <<"none">> end end. diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 67a8e6a33..943354191 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -162,14 +162,14 @@ process_list_get(LUser, LServer, Name) -> item_to_xml(Item) -> - Attrs1 = [#xmlattr{name = 'action', value = action_to_list(Item#listitem.action)}, - #xmlattr{name = 'order', value = order_to_list(Item#listitem.order)}], + Attrs1 = [#xmlattr{name = 'action', value = action_to_binary(Item#listitem.action)}, + #xmlattr{name = 'order', value = order_to_binary(Item#listitem.order)}], Attrs2 = case Item#listitem.type of none -> Attrs1; Type -> - [#xmlattr{name = 'type', value = type_to_list(Item#listitem.type)}, - #xmlattr{name = 'value', value = value_to_list(Type, Item#listitem.value)} | + [#xmlattr{name = 'type', value = type_to_binary(Item#listitem.type)}, + #xmlattr{name = 'value', value = value_to_binary(Type, Item#listitem.value)} | Attrs1] end, SubEls = case Item#listitem.match_all of @@ -205,34 +205,34 @@ item_to_xml(Item) -> exmpp_xml:set_attributes(#xmlel{ns = ?NS_PRIVACY, name = item, children = SubEls}, Attrs2). -action_to_list(Action) -> +action_to_binary(Action) -> case Action of - allow -> "allow"; - deny -> "deny" + allow -> <<"allow">>; + deny -> <<"deny">> end. -order_to_list(Order) -> - integer_to_list(Order). +order_to_binary(Order) -> + list_to_binary(integer_to_list(Order)). -type_to_list(Type) -> +type_to_binary(Type) -> case Type of - jid -> "jid"; - group -> "group"; - subscription -> "subscription" + jid -> <<"jid">>; + group -> <<"group">>; + subscription -> <<"subscription">> end. -value_to_list(Type, Val) -> +value_to_binary(Type, Val) -> case Type of jid -> {N, D, R} = Val, - exmpp_jid:jid_to_list(N, D, R); + exmpp_jid:jid_to_binary(N, D, R); group -> Val; subscription -> case Val of - both -> "both"; - to -> "to"; - from -> "from"; - none -> "none" + both -> <<"both">>; + to -> <<"to">>; + from -> <<"from">>; + none -> <<"none">> end end. diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 95aab8969..4b388d72c 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -315,12 +315,12 @@ identity(Host) -> end, #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = Identity}. -disco_local_identity(Acc, _From, To, [], _Lang) -> +disco_local_identity(Acc, _From, To, <<>>, _Lang) -> Acc ++ [identity(To#jid.ldomain)]; disco_local_identity(Acc, _From, _To, _Node, _Lang) -> Acc. -disco_local_features(Acc, _From, To, [], _Lang) -> +disco_local_features(Acc, _From, To, <<>>, _Lang) -> Host = To#jid.ldomain, Feats = case Acc of {result, I} -> I; @@ -332,12 +332,12 @@ disco_local_features(Acc, _From, To, [], _Lang) -> disco_local_features(Acc, _From, _To, _Node, _Lang) -> Acc. -disco_local_items(Acc, _From, _To, [], _Lang) -> +disco_local_items(Acc, _From, _To, <<>>, _Lang) -> Acc; disco_local_items(Acc, _From, _To, _Node, _Lang) -> Acc. -disco_sm_identity(Acc, _From, To, [], _Lang) -> +disco_sm_identity(Acc, _From, To, <<>>, _Lang) -> Acc ++ [identity(To#jid.ldomain)]; disco_sm_identity(Acc, From, To, Node, _Lang) -> LOwner = jlib:short_prepd_bare_jid(To), @@ -360,7 +360,7 @@ disco_sm_features(Acc, From, To, Node, _Lang) -> Acc end. -disco_sm_items(Acc, From, To, [], _Lang) -> +disco_sm_items(Acc, From, To, <<>>, _Lang) -> %% TODO, use iq_disco_items(Host, [], From) Host = To#jid.ldomain, LJID = jlib:short_prepd_bare_jid(To), @@ -381,7 +381,8 @@ disco_sm_items(Acc, From, To, [], _Lang) -> {result, NodeItems ++ Items} end; -disco_sm_items(Acc, From, To, Node, _Lang) -> +disco_sm_items(Acc, From, To, NodeB, _Lang) -> + Node = binary_to_list(NodeB), %% TODO, use iq_disco_items(Host, Node, From) Host = To#jid.ldomain, LJID = jlib:short_prepd_bare_jid(To), diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 6817e07a2..f412e1906 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -154,7 +154,7 @@ item_to_xml(Item) -> Attrs1 = exmpp_xml:set_attribute_in_list([], 'jid', exmpp_jid:jid_to_list(U, S, R)), Attrs2 = case Item#roster.name of - "" -> + <<>> -> Attrs1; Name -> exmpp_xml:set_attribute_in_list(Attrs1, 'name', Name) @@ -205,7 +205,7 @@ process_item_set(From, To, #xmlel{} = El) -> jid = JID}; [I] -> I#roster{jid = JID, - name = "", + name = <<>>, groups = [], xs = []} end, @@ -274,7 +274,7 @@ process_item_attrs(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> process_item_attrs(Item#roster{name = Val}, Attrs); 'subscription' -> case Val of - "remove" -> + <<"remove">> -> process_item_attrs(Item#roster{subscription = remove}, Attrs); _ -> @@ -623,19 +623,19 @@ process_item_attrs_ws(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> process_item_attrs_ws(Item#roster{name = Val}, Attrs); 'subscription' -> case Val of - "remove" -> + <<"remove">> -> process_item_attrs_ws(Item#roster{subscription = remove}, Attrs); - "none" -> + <<"none">> -> process_item_attrs_ws(Item#roster{subscription = none}, Attrs); - "both" -> + <<"both">> -> process_item_attrs_ws(Item#roster{subscription = both}, Attrs); - "from" -> + <<"from">> -> process_item_attrs_ws(Item#roster{subscription = from}, Attrs); - "to" -> + <<"to">> -> process_item_attrs_ws(Item#roster{subscription = to}, Attrs); _ -> @@ -888,7 +888,7 @@ user_roster(User, Server, Query, Lang) -> [?XAC("td", [{"class", "valign"}], catch exmpp_jid:jid_to_list(U, S, R)), ?XAC("td", [{"class", "valign"}], - R#roster.name), + binary_to_list(R#roster.name)), ?XAC("td", [{"class", "valign"}], atom_to_list(R#roster.subscription)), ?XAC("td", [{"class", "valign"}], diff --git a/src/mod_roster.hrl b/src/mod_roster.hrl index 617e17df4..8fd0be57f 100644 --- a/src/mod_roster.hrl +++ b/src/mod_roster.hrl @@ -22,7 +22,7 @@ -record(roster, {usj, us, jid, - name = "", + name = <<>>, subscription = none, ask = none, groups = [], diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index ad85f0890..6434f3897 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -181,7 +181,7 @@ item_to_xml(Item) -> Attrs1 = exmpp_xml:set_attribute_in_list([], 'jid', exmpp_jid:jid_to_list(U, S, R)), Attrs2 = case Item#roster.name of - "" -> + <<>> -> Attrs1; Name -> exmpp_xml:set_attribute_in_list(Attrs1, 'name', Name) @@ -245,7 +245,7 @@ process_item_set(From, To, #xmlel{} = El) -> usj = {LUser, LServer, LJID}, us = {LUser, LServer}, jid = LJID, - name = ""} + name = <<>>} end end, Item1 = process_item_attrs(Item, El#xmlel.attrs), @@ -315,7 +315,7 @@ process_item_attrs(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> process_item_attrs(Item#roster{name = Val}, Attrs); 'subscription' -> case Val of - "remove" -> + <<"remove">> -> process_item_attrs(Item#roster{subscription = remove}, Attrs); _ -> @@ -685,19 +685,19 @@ process_item_attrs_ws(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> process_item_attrs_ws(Item#roster{name = Val}, Attrs); 'subscription' -> case Val of - "remove" -> + <<"remove">> -> process_item_attrs_ws(Item#roster{subscription = remove}, Attrs); - "none" -> + <<"none">> -> process_item_attrs_ws(Item#roster{subscription = none}, Attrs); - "both" -> + <<"both">> -> process_item_attrs_ws(Item#roster{subscription = both}, Attrs); - "from" -> + <<"from">> -> process_item_attrs_ws(Item#roster{subscription = from}, Attrs); - "to" -> + <<"to">> -> process_item_attrs_ws(Item#roster{subscription = to}, Attrs); _ -> @@ -834,7 +834,7 @@ raw_to_record(LServer, {User, SJID, Nick, SSubscription, SAsk, SAskMessage, #roster{usj = {UserB, LServer, LJID}, us = {UserB, LServer}, jid = LJID, - name = Nick, + name = list_to_binary(Nick), subscription = Subscription, ask = Ask, askmessage = list_to_binary(SAskMessage)} @@ -852,7 +852,7 @@ record_to_string(#roster{us = {User, _Server}, Username = ejabberd_odbc:escape(binary_to_list(User)), {U, S, R} = JID, SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(U, S, R)), - Nick = ejabberd_odbc:escape(Name), + Nick = ejabberd_odbc:escape(binary_to_list(Name)), SSubscription = case Subscription of both -> "B"; to -> "T"; @@ -939,7 +939,7 @@ user_roster(User, Server, Query, Lang) -> [?XAC("td", [{"class", "valign"}], catch exmpp_jid:jid_to_list(U, S, R)), ?XAC("td", [{"class", "valign"}], - R#roster.name), + binary_to_list(R#roster.name)), ?XAC("td", [{"class", "valign"}], atom_to_list(R#roster.subscription)), ?XAC("td", [{"class", "valign"}], diff --git a/src/mod_stats.erl b/src/mod_stats.erl index 0884ba252..b1f80a98e 100644 --- a/src/mod_stats.erl +++ b/src/mod_stats.erl @@ -63,9 +63,9 @@ process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> get_names([], Res) -> Res; get_names([#xmlel{name = 'stat', attrs = Attrs} | Els], Res) -> - Name = exmpp_xml:get_attribute_from_list(Attrs, 'name', ""), + Name = exmpp_xml:get_attribute_from_list_as_binary(Attrs, 'name', <<>>), case Name of - "" -> + <<>> -> get_names(Els, Res); _ -> get_names(Els, [Name | Res]) @@ -78,10 +78,10 @@ get_names([_ | Els], Res) -> get_local_stats(_Server, [], []) -> {result, - [?STAT("users/online"), - ?STAT("users/total"), - ?STAT("users/all-hosts/online"), - ?STAT("users/all-hosts/total") + [?STAT(<<"users/online">>), + ?STAT(<<"users/total">>), + ?STAT(<<"users/all-hosts/online">>), + ?STAT(<<"users/all-hosts/total">>) ]}; get_local_stats(Server, [], Names) -> @@ -91,13 +91,13 @@ get_local_stats(Server, [], Names) -> get_local_stats(_Server, ["running nodes", _], []) -> {result, - [?STAT("time/uptime"), - ?STAT("time/cputime"), - ?STAT("users/online"), - ?STAT("transactions/commited"), - ?STAT("transactions/aborted"), - ?STAT("transactions/restarted"), - ?STAT("transactions/logged") + [?STAT(<<"time/uptime">>), + ?STAT(<<"time/cputime">>), + ?STAT(<<"users/online">>), + ?STAT(<<"transactions/commited">>), + ?STAT(<<"transactions/aborted">>), + ?STAT(<<"transactions/restarted">>), + ?STAT(<<"transactions/logged">>) ]}; get_local_stats(_Server, ["running nodes", ENode], Names) -> @@ -126,107 +126,107 @@ get_local_stats(_Server, _, _) -> [#xmlattr{name = 'name', value = Name}], children = [#xmlel{ns = ?NS_STATS, name = 'error', attrs = [#xmlattr{name = 'code', value = Code}], children = - [#xmlcdata{cdata = list_to_binary(Desc)}]}]}). + [#xmlcdata{cdata = Desc}]}]}). -get_local_stat(Server, [], Name) when Name == "users/online" -> +get_local_stat(Server, [], Name) when Name == <<"users/online">> -> case catch ejabberd_sm:get_vh_session_list(list_to_binary(Server)) of {'EXIT', _Reason} -> - ?STATERR("500", "Internal Server Error"); + ?STATERR(<<"500">>, <<"Internal Server Error">>); Users -> - ?STATVAL(integer_to_list(length(Users)), "users") + ?STATVAL(list_to_binary(integer_to_list(length(Users))), <<"users">>) end; -get_local_stat(Server, [], Name) when Name == "users/total" -> +get_local_stat(Server, [], Name) when Name == <<"users/total">> -> %%LServer = jlib:nameprep(Server), case catch ejabberd_auth:get_vh_registered_users_number(Server) of {'EXIT', _Reason} -> - ?STATERR("500", "Internal Server Error"); + ?STATERR(<<"500">>, <<"Internal Server Error">>); NUsers -> - ?STATVAL(integer_to_list(NUsers), "users") + ?STATVAL(list_to_binary(integer_to_list(NUsers)), <<"users">>) end; -get_local_stat(_Server, [], Name) when Name == "users/all-hosts/online" -> +get_local_stat(_Server, [], Name) when Name == <<"users/all-hosts/online">> -> case catch mnesia:table_info(session, size) of {'EXIT', _Reason} -> - ?STATERR("500", "Internal Server Error"); + ?STATERR(<<"500">>, <<"Internal Server Error">>); Users -> - ?STATVAL(integer_to_list(Users), "users") + ?STATVAL(list_to_binary(integer_to_list(Users)), <<"users">>) end; -get_local_stat(_Server, [], Name) when Name == "users/all-hosts/total" -> +get_local_stat(_Server, [], Name) when Name == <<"users/all-hosts/total">> -> case catch mnesia:table_info(passwd, size) of {'EXIT', _Reason} -> - ?STATERR("500", "Internal Server Error"); + ?STATERR(<<"500">>, <<"Internal Server Error">>); Users -> - ?STATVAL(integer_to_list(Users), "users") + ?STATVAL(list_to_binary(integer_to_list(Users)), <<"users">>) end; get_local_stat(_Server, _, Name) -> - ?STATERR("404", "Not Found"). + ?STATERR(<<"404">>, <<"Not Found">>). -get_node_stat(Node, Name) when Name == "time/uptime" -> +get_node_stat(Node, Name) when Name == <<"time/uptime">> -> case catch rpc:call(Node, erlang, statistics, [wall_clock]) of {badrpc, _Reason} -> - ?STATERR("500", "Internal Server Error"); + ?STATERR(<<"500">>, <<"Internal Server Error">>); CPUTime -> - ?STATVAL( - io_lib:format("~.3f", [element(1, CPUTime)/1000]), "seconds") + ?STATVAL(list_to_binary( + io_lib:format("~.3f", [element(1, CPUTime)/1000])), "seconds") end; -get_node_stat(Node, Name) when Name == "time/cputime" -> +get_node_stat(Node, Name) when Name == <<"time/cputime">> -> case catch rpc:call(Node, erlang, statistics, [runtime]) of {badrpc, _Reason} -> - ?STATERR("500", "Internal Server Error"); + ?STATERR(<<"500">>, <<"Internal Server Error">>); RunTime -> - ?STATVAL( - io_lib:format("~.3f", [element(1, RunTime)/1000]), "seconds") + ?STATVAL(list_to_binary( + io_lib:format("~.3f", [element(1, RunTime)/1000])), "seconds") end; -get_node_stat(Node, Name) when Name == "users/online" -> +get_node_stat(Node, Name) when Name == <<"users/online">> -> case catch rpc:call(Node, ejabberd_sm, dirty_get_my_sessions_list, []) of {badrpc, _Reason} -> - ?STATERR("500", "Internal Server Error"); + ?STATERR(<<"500">>, <<"Internal Server Error">>); Users -> - ?STATVAL(integer_to_list(length(Users)), "users") + ?STATVAL(list_to_binary(integer_to_list(length(Users))), <<"users">>) end; -get_node_stat(Node, Name) when Name == "transactions/commited" -> +get_node_stat(Node, Name) when Name == <<"transactions/commited">> -> case catch rpc:call(Node, mnesia, system_info, [transaction_commits]) of {badrpc, _Reason} -> - ?STATERR("500", "Internal Server Error"); + ?STATERR(<<"500">>, <<"Internal Server Error">>); Transactions -> - ?STATVAL(integer_to_list(Transactions), "transactions") + ?STATVAL(list_to_binary(integer_to_list(Transactions)), <<"transactions">>) end; -get_node_stat(Node, Name) when Name == "transactions/aborted" -> +get_node_stat(Node, Name) when Name == <<"transactions/aborted">> -> case catch rpc:call(Node, mnesia, system_info, [transaction_failures]) of {badrpc, _Reason} -> - ?STATERR("500", "Internal Server Error"); + ?STATERR(<<"500">>, <<"Internal Server Error">>); Transactions -> - ?STATVAL(integer_to_list(Transactions), "transactions") + ?STATVAL(list_to_binary(integer_to_list(Transactions)), <<"transactions">>) end; -get_node_stat(Node, Name) when Name == "transactions/restarted" -> +get_node_stat(Node, Name) when Name == <<"transactions/restarted">> -> case catch rpc:call(Node, mnesia, system_info, [transaction_restarts]) of {badrpc, _Reason} -> - ?STATERR("500", "Internal Server Error"); + ?STATERR(<<"500">>, <<"Internal Server Error">>); Transactions -> - ?STATVAL(integer_to_list(Transactions), "transactions") + ?STATVAL(list_to_binary(integer_to_list(Transactions)), <<"transactions">>) end; -get_node_stat(Node, Name) when Name == "transactions/logged" -> +get_node_stat(Node, Name) when Name == <<"transactions/logged">> -> case catch rpc:call(Node, mnesia, system_info, [transaction_log_writes]) of {badrpc, _Reason} -> - ?STATERR("500", "Internal Server Error"); + ?STATERR(<<"500">>, <<"Internal Server Error">>); Transactions -> - ?STATVAL(integer_to_list(Transactions), "transactions") + ?STATVAL(list_to_binary(integer_to_list(Transactions)), <<"transactions">>) end; get_node_stat(_, Name) -> - ?STATERR("404", "Not Found"). + ?STATERR(<<"404">>, <<"Not Found">>). search_running_node(SNode) -> diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index 465203b1d..b465a14ed 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -284,7 +284,7 @@ set_vcard(User, LServer, VCARD) -> [#xmlel{ns = ?NS_SEARCH, name = 'instructions', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "You need an x:data capable client to search"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = - [#xmlattr{name = 'type', value = "form"}], children = + [#xmlattr{name = 'type', value = <<"form">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ exmpp_jid:jid_to_list(JID))}]}, #xmlel{ns = ?NS_SEARCH, name = 'instructions', children = @@ -293,18 +293,18 @@ set_vcard(User, LServer, VCARD) -> "for any matching Jabber User " "(Add * to the end of field to " "match substring)"))}]}, - ?TLFIELD("text-single", "User", "user"), - ?TLFIELD("text-single", "Full Name", "fn"), - ?TLFIELD("text-single", "Name", "first"), - ?TLFIELD("text-single", "Middle Name", "middle"), - ?TLFIELD("text-single", "Family Name", "last"), - ?TLFIELD("text-single", "Nickname", "nick"), - ?TLFIELD("text-single", "Birthday", "bday"), - ?TLFIELD("text-single", "Country", "ctry"), - ?TLFIELD("text-single", "City", "locality"), - ?TLFIELD("text-single", "Email", "email"), - ?TLFIELD("text-single", "Organization Name", "orgname"), - ?TLFIELD("text-single", "Organization Unit", "orgunit") + ?TLFIELD(<<"text-single">>, "User", <<"user">>), + ?TLFIELD(<<"text-single">>, "Full Name", <<"fn">>), + ?TLFIELD(<<"text-single">>, "Name", <<"first">>), + ?TLFIELD(<<"text-single">>, "Middle Name", <<"middle">>), + ?TLFIELD(<<"text-single">>, "Family Name", <<"last">>), + ?TLFIELD(<<"text-single">>, "Nickname", <<"nick">>), + ?TLFIELD(<<"text-single">>, "Birthday", <<"bday">>), + ?TLFIELD(<<"text-single">>, "Country", <<"ctry">>), + ?TLFIELD(<<"text-single">>, "City", <<"locality">>), + ?TLFIELD(<<"text-single">>, "Email", <<"email">>), + ?TLFIELD(<<"text-single">>, "Organization Name", <<"orgname">>), + ?TLFIELD(<<"text-single">>, "Organization Unit", <<"orgunit">>) ]}]). @@ -346,7 +346,7 @@ do_route(ServerHost, From, To, Packet) -> ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', - value = "result"}], + value = <<"result">>}], children = search_result(Lang, To, ServerHost, XData)}]}, ResIQ = exmpp_iq:result(Packet, @@ -371,24 +371,24 @@ do_route(ServerHost, From, To, Packet) -> #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [ #xmlattr{name = 'category', - value = "directory"}, + value = <<"directory">>}, #xmlattr{name = 'type', - value = "user"}, + value = <<"user">>}, #xmlattr{name = 'name', - value = translate:translate(Lang, - "vCard User Search")}]}, + value = list_to_binary(translate:translate(Lang, + "vCard User Search"))}]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ #xmlattr{name = 'var', - value = ?NS_DISCO_INFO_s}]}, + value = list_to_binary(?NS_DISCO_INFO_s)}]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ #xmlattr{name = 'var', - value = ?NS_SEARCH_s}]}, + value = list_to_binary(?NS_SEARCH_s)}]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ #xmlattr{name = 'var', - value = ?NS_VCARD_s}]} + value = list_to_binary(?NS_VCARD_s)}]} ]}, ResIQ = exmpp_iq:result(Packet, Result), ejabberd_router:route(To, @@ -449,42 +449,42 @@ search_result(Lang, JID, ServerHost, Data) -> translate:translate(Lang, "Search Results for ") ++ exmpp_jid:jid_to_list(JID))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'reported', children = - [?TLFIELD("text-single", "Jabber ID", "jid"), - ?TLFIELD("text-single", "Full Name", "fn"), - ?TLFIELD("text-single", "Name", "first"), - ?TLFIELD("text-single", "Middle Name", "middle"), - ?TLFIELD("text-single", "Family Name", "last"), - ?TLFIELD("text-single", "Nickname", "nick"), - ?TLFIELD("text-single", "Birthday", "bday"), - ?TLFIELD("text-single", "Country", "ctry"), - ?TLFIELD("text-single", "City", "locality"), - ?TLFIELD("text-single", "Email", "email"), - ?TLFIELD("text-single", "Organization Name", "orgname"), - ?TLFIELD("text-single", "Organization Unit", "orgunit") + [?TLFIELD(<<"text-single">>, "Jabber ID", <<"jid">>), + ?TLFIELD(<<"text-single">>, "Full Name", <<"fn">>), + ?TLFIELD(<<"text-single">>, "Name", <<"first">>), + ?TLFIELD(<<"text-single">>, "Middle Name", <<"middle">>), + ?TLFIELD(<<"text-single">>, "Family Name", <<"last">>), + ?TLFIELD(<<"text-single">>, "Nickname", <<"nick">>), + ?TLFIELD(<<"text-single">>, "Birthday", <<"bday">>), + ?TLFIELD(<<"text-single">>, "Country", <<"ctry">>), + ?TLFIELD(<<"text-single">>, "City", <<"locality">>), + ?TLFIELD(<<"text-single">>, "Email", <<"email">>), + ?TLFIELD(<<"text-single">>, "Organization Name", <<"orgname">>), + ?TLFIELD(<<"text-single">>, "Organization Unit", <<"orgunit">>) ]}] ++ lists:map(fun record_to_item/1, search(ServerHost, Data)). -define(FIELD(Var, Val), #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'var', value = Var}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = - [#xmlcdata{cdata = list_to_binary(Val)}]}]}). + [#xmlcdata{cdata = Val}]}]}). record_to_item(R) -> {User, Server} = R#vcard_search.user, #xmlel{ns = ?NS_DATA_FORMS, name = 'item', children = [ - ?FIELD("jid", User ++ "@" ++ Server), - ?FIELD("fn", R#vcard_search.fn), - ?FIELD("last", R#vcard_search.family), - ?FIELD("first", R#vcard_search.given), - ?FIELD("middle", R#vcard_search.middle), - ?FIELD("nick", R#vcard_search.nickname), - ?FIELD("bday", R#vcard_search.bday), - ?FIELD("ctry", R#vcard_search.ctry), - ?FIELD("locality", R#vcard_search.locality), - ?FIELD("email", R#vcard_search.email), - ?FIELD("orgname", R#vcard_search.orgname), - ?FIELD("orgunit", R#vcard_search.orgunit) + ?FIELD(<<"jid">>, list_to_binary(User ++ "@" ++ Server)), + ?FIELD(<<"fn">>, list_to_binary(R#vcard_search.fn)), + ?FIELD(<<"last">>, list_to_binary(R#vcard_search.family)), + ?FIELD(<<"first">>, list_to_binary(R#vcard_search.given)), + ?FIELD(<<"middle">>, list_to_binary(R#vcard_search.middle)), + ?FIELD(<<"nick">>, list_to_binary(R#vcard_search.nickname)), + ?FIELD(<<"bday">>, list_to_binary(R#vcard_search.bday)), + ?FIELD(<<"ctry">>, list_to_binary(R#vcard_search.ctry)), + ?FIELD(<<"locality">>, list_to_binary(R#vcard_search.locality)), + ?FIELD(<<"email">>, list_to_binary(R#vcard_search.email)), + ?FIELD(<<"orgname">>, list_to_binary(R#vcard_search.orgname)), + ?FIELD(<<"orgunit">>, list_to_binary(R#vcard_search.orgunit)) ] }. diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index a7200a38a..b6f5a35d3 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -391,14 +391,14 @@ ldap_attribute_to_vcard(_, _) -> [#xmlel{ns = ?NS_SEARCH, name = 'instructions', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "You need an x:data capable client to search"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = - [#xmlattr{name = 'type', value = "form"}], children = + [#xmlattr{name = 'type', value = <<"form">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ exmpp_jid:jid_to_list(JID))}]}, #xmlel{ns = ?NS_SEARCH, name = 'instructions', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Fill in fields to search " "for any matching Jabber User"))}]} - ] ++ lists:map(fun({X,Y}) -> ?TLFIELD("text-single", X, Y) end, SearchFields)}]). + ] ++ lists:map(fun({X,Y}) -> ?TLFIELD(<<"text-single">>, X, list_to_binary(Y)) end, SearchFields)}]). do_route(State, From, To, Packet) -> spawn(?MODULE, route, [State, From, To, Packet]). @@ -439,7 +439,7 @@ route(State, From, To, Packet) -> ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', - value = "result"}], + value = <<"result">>}], children = search_result(Lang, To, State, XData)}]}, ResIQ = exmpp_iq:result(Packet, Result), @@ -464,20 +464,20 @@ route(State, From, To, Packet) -> #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [ #xmlattr{name = 'category', - value = "directory"}, + value = <<"directory">>}, #xmlattr{name = 'type', - value = "user"}, + value = <<"user">>}, #xmlattr{name = 'name', - value = translate:translate(Lang, - "vCard User Search")}]}, + value = list_to_binary(translate:translate(Lang, + "vCard User Search"))}]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ #xmlattr{name = 'var', - value = ?NS_SEARCH_s}]}, + value = list_to_binary(?NS_SEARCH_s)}]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ #xmlattr{name = 'var', - value = ?NS_VCARD_s}]} + value = list_to_binary(?NS_VCARD_s)}]} ]}, ResIQ = exmpp_iq:result(Packet, Result), ejabberd_router:route(To, @@ -528,9 +528,9 @@ search_result(Lang, JID, State, Data) -> [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search Results for ") ++ exmpp_jid:jid_to_list(JID))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'reported', children = - [?TLFIELD("text-single", "Jabber ID", "jid")] ++ + [?TLFIELD(<<"text-single">>, "Jabber ID", <<"jid">>)] ++ lists:map( - fun({Name, Value}) -> ?TLFIELD("text-single", Name, Value) end, + fun({Name, Value}) -> ?TLFIELD(<<"text-single">>, Name, list_to_binary(Value)) end, SearchReported) }], case search(State, Data) of @@ -544,7 +544,7 @@ search_result(Lang, JID, State, Data) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'var', value = Var}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = - [#xmlcdata{cdata = list_to_binary(Val)}]}]}). + [#xmlcdata{cdata = Val}]}]}). search(State, Data) -> Base = State#state.base, @@ -591,8 +591,8 @@ search_items(Entries, State) -> VCardMap, {Username, ?MYNAME})} end, SearchReported), - Result = [?FIELD("jid", Username ++ "@" ++ LServer)] ++ - [?FIELD(Name, Value) || {Name, Value} <- RFields], + Result = [?FIELD(<<"jid">>, list_to_binary(Username ++ "@" ++ LServer))] ++ + [?FIELD(list_to_binary(Name), list_to_binary(Value)) || {Name, Value} <- RFields], [#xmlel{ns = ?NS_DATA_FORMS, name = 'item', children = Result}]; _ -> [] diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl index 21f9d0595..a67412dff 100644 --- a/src/mod_vcard_odbc.erl +++ b/src/mod_vcard_odbc.erl @@ -250,7 +250,7 @@ set_vcard(User, LServer, VCARD) -> -define(TLFIELD(Type, Label, Var), #xmlel{ns = ?NS_VCARD, name = 'field', attrs = [ #xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'label', value = translate:translate(Lang, Label)}, + #xmlattr{name = 'label', value = list_to_binary(translate:translate(Lang, Label))}, #xmlattr{name = 'var', value = Var}]}). @@ -258,7 +258,7 @@ set_vcard(User, LServer, VCARD) -> [#xmlel{ns = ?NS_SEARCH, name = 'instructions', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "You need an x:data capable client to search"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = - [#xmlattr{name = 'type', value = "form"}], children = + [#xmlattr{name = 'type', value = <<"form">>}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ exmpp_jid:jid_to_list(JID))}]}, #xmlel{ns = ?NS_SEARCH, name = 'instructions', children = @@ -267,18 +267,18 @@ set_vcard(User, LServer, VCARD) -> "for any matching Jabber User " "(Add * to the end of field to " "match substring)"))}]}, - ?TLFIELD("text-single", "User", "user"), - ?TLFIELD("text-single", "Full Name", "fn"), - ?TLFIELD("text-single", "Name", "first"), - ?TLFIELD("text-single", "Middle Name", "middle"), - ?TLFIELD("text-single", "Family Name", "last"), - ?TLFIELD("text-single", "Nickname", "nick"), - ?TLFIELD("text-single", "Birthday", "bday"), - ?TLFIELD("text-single", "Country", "ctry"), - ?TLFIELD("text-single", "City", "locality"), - ?TLFIELD("text-single", "Email", "email"), - ?TLFIELD("text-single", "Organization Name", "orgname"), - ?TLFIELD("text-single", "Organization Unit", "orgunit") + ?TLFIELD(<<"text-single">>, "User", <<"user">>), + ?TLFIELD(<<"text-single">>, "Full Name", <<"fn">>), + ?TLFIELD(<<"text-single">>, "Name", <<"first">>), + ?TLFIELD(<<"text-single">>, "Middle Name", <<"middle">>), + ?TLFIELD(<<"text-single">>, "Family Name", <<"last">>), + ?TLFIELD(<<"text-single">>, "Nickname", <<"nick">>), + ?TLFIELD(<<"text-single">>, "Birthday", <<"bday">>), + ?TLFIELD(<<"text-single">>, "Country", <<"ctry">>), + ?TLFIELD(<<"text-single">>, "City", <<"locality">>), + ?TLFIELD(<<"text-single">>, "Email", <<"email">>), + ?TLFIELD(<<"text-single">>, "Organization Name", <<"orgname">>), + ?TLFIELD(<<"text-single">>, "Organization Unit", <<"orgunit">>) ]}]). do_route(ServerHost, From, To, Packet) -> @@ -317,7 +317,7 @@ do_route(ServerHost, From, To, Packet) -> ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', - value = "result"}], + value = <<"result">>}], children = search_result(Lang, To, ServerHost, XData)}]}, ResIQ = exmpp_iq:result(Packet, @@ -342,20 +342,20 @@ do_route(ServerHost, From, To, Packet) -> #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [ #xmlattr{name = 'category', - value = "directory"}, + value = <<"directory">>}, #xmlattr{name = 'type', - value = "user"}, + value = <<"user">>}, #xmlattr{name = 'name', - value = translate:translate(Lang, - "vCard User Search")}]}, + value = list_to_binary(translate:translate(Lang, + "vCard User Search"))}]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ #xmlattr{name = 'var', - value = ?NS_SEARCH_s}]}, + value = list_to_binary(?NS_SEARCH_s)}]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ #xmlattr{name = 'var', - value = ?NS_VCARD_s}]} + value = list_to_binary(?NS_VCARD_s)}]} ]}, ResIQ = exmpp_iq:result(Packet, Result), ejabberd_router:route(To, @@ -416,18 +416,18 @@ search_result(Lang, JID, ServerHost, Data) -> translate:translate(Lang, "Search Results for ") ++ exmpp_jid:jid_to_list(JID))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'reported', children = - [?TLFIELD("text-single", "Jabber ID", "jid"), - ?TLFIELD("text-single", "Full Name", "fn"), - ?TLFIELD("text-single", "Name", "first"), - ?TLFIELD("text-single", "Middle Name", "middle"), - ?TLFIELD("text-single", "Family Name", "last"), - ?TLFIELD("text-single", "Nickname", "nick"), - ?TLFIELD("text-single", "Birthday", "bday"), - ?TLFIELD("text-single", "Country", "ctry"), - ?TLFIELD("text-single", "City", "locality"), - ?TLFIELD("text-single", "Email", "email"), - ?TLFIELD("text-single", "Organization Name", "orgname"), - ?TLFIELD("text-single", "Organization Unit", "orgunit") + [?TLFIELD(<<"text-single">>, "Jabber ID", <<"jid">>), + ?TLFIELD(<<"text-single">>, "Full Name", <<"fn">>), + ?TLFIELD(<<"text-single">>, "Name", <<"first">>), + ?TLFIELD(<<"text-single">>, "Middle Name", <<"middle">>), + ?TLFIELD(<<"text-single">>, "Family Name", <<"last">>), + ?TLFIELD(<<"text-single">>, "Nickname", <<"nick">>), + ?TLFIELD(<<"text-single">>, "Birthday", <<"bday">>), + ?TLFIELD(<<"text-single">>, "Country", <<"ctry">>), + ?TLFIELD(<<"text-single">>, "City", <<"locality">>), + ?TLFIELD(<<"text-single">>, "Email", <<"email">>), + ?TLFIELD(<<"text-single">>, "Organization Name", <<"orgname">>), + ?TLFIELD(<<"text-single">>, "Organization Unit", <<"orgunit">>) ]}] ++ lists:map(fun(R) -> record_to_item(ServerHost, R) end, search(ServerHost, Data)). @@ -435,7 +435,7 @@ search_result(Lang, JID, ServerHost, Data) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'var', value = Var}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = - [#xmlcdata{cdata = list_to_binary(Val)}]}]}). + [#xmlcdata{cdata = Val}]}]}). record_to_item(LServer, {Username, FN, Family, Given, Middle, @@ -443,18 +443,18 @@ record_to_item(LServer, {Username, FN, Family, Given, Middle, EMail, OrgName, OrgUnit}) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'item', children = [ - ?FIELD("jid", Username ++ "@" ++ LServer), - ?FIELD("fn", FN), - ?FIELD("last", Family), - ?FIELD("first", Given), - ?FIELD("middle", Middle), - ?FIELD("nick", Nickname), - ?FIELD("bday", BDay), - ?FIELD("ctry", CTRY), - ?FIELD("locality", Locality), - ?FIELD("email", EMail), - ?FIELD("orgname", OrgName), - ?FIELD("orgunit", OrgUnit) + ?FIELD(<<"jid">>, list_to_binary(Username ++ "@" ++ LServer)), + ?FIELD(<<"fn">>, list_to_binary(FN)), + ?FIELD(<<"last">>, list_to_binary(Family)), + ?FIELD(<<"first">>, list_to_binary(Given)), + ?FIELD(<<"middle">>, list_to_binary(Middle)), + ?FIELD(<<"nick">>, list_to_binary(Nickname)), + ?FIELD(<<"bday">>, list_to_binary(BDay)), + ?FIELD(<<"ctry">>, list_to_binary(CTRY)), + ?FIELD(<<"locality">>, list_to_binary(Locality)), + ?FIELD(<<"email">>, list_to_binary(EMail)), + ?FIELD(<<"orgname">>, list_to_binary(OrgName)), + ?FIELD(<<"orgunit">>, list_to_binary(OrgUnit)) ] }. diff --git a/src/web/ejabberd_http_poll.erl b/src/web/ejabberd_http_poll.erl index 370217998..7f8c70807 100644 --- a/src/web/ejabberd_http_poll.erl +++ b/src/web/ejabberd_http_poll.erl @@ -416,12 +416,12 @@ get_jid("from", ParsedPacket) -> undefined -> #jid{}; From -> - exmpp_jid:list_to_jid(From) + exmpp_jid:binary_to_jid(From) end; get_jid("to", ParsedPacket) -> case exmpp_stanza:get_recipient(ParsedPacket) of undefined -> #jid{}; From -> - exmpp_jid:list_to_jid(From) + exmpp_jid:binary_to_jid(From) end. From 068c93e5629cbaa142340f3761fa4ea70393d2b0 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 8 Jan 2009 17:27:47 +0000 Subject: [PATCH 154/582] fix EJAB-701 and EJAB-836 SVN Revision: 1781 --- ChangeLog | 9 +++ src/mod_pubsub/mod_pubsub.erl | 22 ++--- src/mod_pubsub/node_default.erl | 139 ++++++++++++++++++-------------- 3 files changed, 97 insertions(+), 73 deletions(-) diff --git a/ChangeLog b/ChangeLog index b03b74aee..429f7151a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2009-01-08 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: completely support subscription using + full JID (EJAB-701) + * src/mod_pubsub/node_default.erl: Likewise + + * src/mod_pubsub/node_default.erl: any entity can retrieve item when + node access model is "open" (thanks to Myers Carpenter)(EJAB-836) + 2009-01-08 Pablo Polvorin * src/mod_vcard_ldap.erl, src/mod_muc/mod_muc.erl, src/mod_roster.hrl, src/mod_offline_odbc.erl, src/ejabberd_s2s_in.erl, src/adhoc.erl, diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 4b388d72c..65e483d34 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -465,12 +465,12 @@ handle_cast({presence, JID, Pid}, State) -> lists:foreach(fun(Type) -> {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, JID]), lists:foreach( - fun({Node, subscribed}) -> + fun({Node, subscribed, SubJID}) -> case tree_action(Host, get_node, [Host, Node, JID]) of #pubsub_node{options = Options} -> case get_option(Options, send_last_published_item) of on_sub_and_presence -> - send_last_item(Host, Node, LJID); + send_last_item(Host, Node, SubJID); _ -> ok end; @@ -522,13 +522,11 @@ handle_cast({presence, JID, Pid}, State) -> handle_cast({remove_user, LUser, LServer}, State) -> Host = State#state.host, Owner = exmpp_jid:make_bare_jid(LUser, LServer), - OwnerKey = jlib:short_prepd_bare_jid(Owner), %% remove user's subscriptions lists:foreach(fun(Type) -> {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, Owner]), lists:foreach(fun - ({Node, subscribed}) -> - JID = exmpp_jid:jid_to_list(LUser, LServer), + ({Node, subscribed, JID}) -> unsubscribe_node(Host, Node, Owner, JID, all); (_) -> ok @@ -537,7 +535,7 @@ handle_cast({remove_user, LUser, LServer}, State) -> %% remove user's PEP nodes lists:foreach(fun(#pubsub_node{nodeid={NodeKey, NodeName}}) -> delete_node(NodeKey, NodeName, Owner) - end, tree_action(Host, get_nodes, [OwnerKey])), + end, tree_action(Host, get_nodes, [jlib:short_prepd_bare_jid(Owner)])), %% remove user's nodes delete_node(Host, ["home", LServer, LUser], Owner), {noreply, State}; @@ -1446,13 +1444,14 @@ subscribe_node(Host, Node, From, JID) -> %%
    • The node does not exist.
    • %%
    • The request specifies a subscription ID that is not valid or current.
    • %% -unsubscribe_node(Host, Node, From, JID, SubId) -> - Subscriber = try - jlib:short_prepd_jid(exmpp_jid:list_to_jid(JID)) +unsubscribe_node(Host, Node, From, JID, SubId) when is_list(JID) -> + Subscriber = try jlib:short_prepd_jid(exmpp_jid:list_to_jid(JID)) catch _:_ -> {undefined, undefined, undefined} end, + unsubscribe_node(Host, Node, From, Subscriber, SubId); +unsubscribe_node(Host, Node, From, Subscriber, SubId) -> case node_action(Host, Node, unsubscribe_node, [Host, Node, From, Subscriber, SubId]) of {error, Error} -> @@ -1930,7 +1929,8 @@ get_subscriptions(Host, JID, Plugins) when is_list(Plugins) -> %% Service does not support retreive subscriptions {{error, extended_error('feature-not-implemented', unsupported, "retrieve-subscriptions")}, Acc}; true -> - {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, JID]), + Subscriber = jlib:jid_remove_resource(JID), + {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, Subscriber]), {Status, [Subscriptions|Acc]} end end, {ok, []}, Plugins), @@ -2296,7 +2296,7 @@ broadcast_config_notification(Host, Node, Lang) -> broadcast_stanza(Host, NodeOpts, States, Stanza) -> PresenceDelivery = get_option(NodeOpts, presence_based_delivery), - BroadcastAll = get_option(NodeOpts, broadcast_all_resources), + BroadcastAll = get_option(NodeOpts, broadcast_all_resources), %% XXX this is not standard From = service_jid(Host), lists:foreach(fun(#pubsub_state{stateid = {LJID, _}, subscription = Subs}) -> case is_to_deliver(LJID, Subs, PresenceDelivery) of diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 2e3e0ad02..27a9fdd55 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -279,11 +279,16 @@ delete_node(Host, Removed) -> %%

      In the default plugin module, the record is unchanged.

      subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - SubscriberKey = jlib:short_prepd_bare_jid(Subscriber), - Authorized = (jlib:short_prepd_bare_jid(Sender) == SubscriberKey), - State = get_state(Host, Node, SubscriberKey), - #pubsub_state{affiliation = Affiliation, - subscription = Subscription} = State, + SubKey = jlib:short_prepd_jid(Owner), + GenKey = jlib:short_prepd_bare_jid(SubKey), + Authorized = (jlib:short_prepd_bare_jid(Sender) == GenKey), + GenState = get_state(Host, Node, GenKey), + SubState = case SubKey of + GenKey -> GenState; + _ -> get_state(Host, Node, SubKey) + end, + Affiliation = GenState#pubsub_state.affiliation, + Subscription = SubState#pubsub_state.subscription, Whitelisted = lists:member(Affiliation, [member, publisher, owner]), if not Authorized -> @@ -323,7 +328,7 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel, true -> subscribed end, - set_state(State#pubsub_state{subscription = NewSubscription}), + set_state(SubState#pubsub_state{subscription = NewSubscription}), case NewSubscription of subscribed -> case SendLast of @@ -345,9 +350,16 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel, %% Reason = mod_pubsub:stanzaError() %% @doc

      Unsubscribe the Subscriber from the Node.

      unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> - SubscriberKey = jlib:short_prepd_bare_jid(Subscriber), - Authorized = (jlib:short_prepd_bare_jid(Sender) == SubscriberKey), - State = get_state(Host, Node, SubscriberKey), + SubKey = jlib:short_prepd_jid(Subscriber), + GenKey = jlib:short_prepd_bare_jid(SubKey), + Authorized = (jlib:short_prepd_bare_jid(Sender) == GenKey), + GenState = get_state(Host, Node, GenKey), + SubState = case SubKey of + GenKey -> GenState; + _ -> get_state(Host, Node, SubKey) + end, + Affiliation = GenState#pubsub_state.affiliation, + Subscription = SubState#pubsub_state.subscription, if %% Entity did not specify SubID %%SubID == "", ?? -> @@ -356,17 +368,17 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> %%InvalidSubID -> %% {error, ?ERR_EXTENDED('not-acceptable', "invalid-subid")}; %% Requesting entity is not a subscriber - State#pubsub_state.subscription == none -> + Subscription == none -> {error, ?ERR_EXTENDED('unexpected-request', "not-subscribed")}; %% Requesting entity is prohibited from unsubscribing entity - (not Authorized) and (State#pubsub_state.affiliation =/= owner) -> + (not Authorized) and (Affiliation =/= owner) -> {error, 'forbidden'}; %% Was just subscriber, remove the record - State#pubsub_state.affiliation == none -> - mnesia:delete({pubsub_state, State#pubsub_state.stateid}), + Affiliation == none -> + del_state(SubState#pubsub_state.stateid), {result, default}; true -> - set_state(State#pubsub_state{subscription = none}), + set_state(SubState#pubsub_state{subscription = none}), {result, default} end. @@ -410,10 +422,15 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> %%

      %%

      In the default plugin module, the record is unchanged.

      publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) -> - PublisherKey = jlib:short_prepd_bare_jid(Publisher), - State = get_state(Host, Node, PublisherKey), - #pubsub_state{affiliation = Affiliation, - subscription = Subscription} = State, + SubKey = jlib:short_prepd_jid(Publisher), + GenKey = jlib:short_prepd_bare_jid(SubKey), + GenState = get_state(Host, Node, GenKey), + SubState = case SubKey of + GenKey -> GenState; + _ -> get_state(Host, Node, SubKey) + end, + Affiliation = GenState#pubsub_state.affiliation, + Subscription = SubState#pubsub_state.subscription, if not ((PublishModel == open) or ((PublishModel == publishers) @@ -423,7 +440,7 @@ publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) -> %% Entity does not have sufficient privileges to publish to node {error, 'forbidden'}; true -> - PubId = {PublisherKey, now()}, %% TODO, uses {now(),PublisherKey} for sorting (EJAB-824) + PubId = {SubKey, now()}, %% TODO, uses {now(),PublisherKey} for sorting (EJAB-824) %% TODO: check creation, presence, roster (EJAB-663) Item = case get_item(Host, Node, ItemId) of {result, OldItem} -> @@ -431,17 +448,17 @@ publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) -> payload = Payload}; _ -> #pubsub_item{itemid = {ItemId, {Host, Node}}, - creation = PubId, + creation = {GenKey, now()}, modification = PubId, payload = Payload} end, - Items = [ItemId | State#pubsub_state.items--[ItemId]], + Items = [ItemId | GenState#pubsub_state.items--[ItemId]], {result, {NI, OI}} = remove_extra_items( Host, Node, MaxItems, Items), if MaxItems > 0 -> set_item(Item); true -> ok end, - set_state(State#pubsub_state{items = NI}), + set_state(GenState#pubsub_state{items = NI}), {result, {default, broadcast, OI}} end. @@ -482,12 +499,12 @@ remove_extra_items(Host, Node, MaxItems, ItemIds) -> %%

      Default plugin: The user performing the deletion must be the node owner %% or a publisher.

      delete_item(Host, Node, Publisher, ItemId) -> - PublisherKey = jlib:short_prepd_bare_jid(Publisher), - State = get_state(Host, Node, PublisherKey), - #pubsub_state{affiliation = Affiliation, items = Items} = State, + GenKey = jlib:short_prepd_bare_jid(Publisher), + GenState = get_state(Host, Node, GenKey), + #pubsub_state{affiliation = Affiliation, items = Items} = GenState, Allowed = (Affiliation == publisher) orelse (Affiliation == owner) orelse case get_item(Host, Node, ItemId) of - {result, #pubsub_item{creation = {PublisherKey, _}}} -> true; + {result, #pubsub_item{creation = {GenKey, _}}} -> true; _ -> false end, if @@ -499,7 +516,7 @@ delete_item(Host, Node, Publisher, ItemId) -> {result, _} -> del_item(Host, Node, ItemId), NewItems = lists:delete(ItemId, Items), - set_state(State#pubsub_state{items = NewItems}), + set_state(GenState#pubsub_state{items = NewItems}), {result, {default, broadcast}}; _ -> %% Non-existent node or item @@ -514,8 +531,9 @@ delete_item(Host, Node, Publisher, ItemId) -> %% Node = mod_pubsub:pubsubNode() %% Owner = mod_pubsub:jid() purge_node(Host, Node, Owner) -> - OwnerKey = jlib:short_prepd_bare_jid(Owner), - case get_state(Host, Node, OwnerKey) of + GenKey = jlib:short_prepd_bare_jid(Owner), + GenState = get_state(Host, Node, GenKey), + case GenState of #pubsub_state{items = Items, affiliation = owner} -> lists:foreach(fun(ItemId) -> mnesia:delete({pubsub_item, {ItemId, {Host, Node}}}) @@ -537,9 +555,9 @@ purge_node(Host, Node, Owner) -> %% that will be added to the affiliation stored in the main %% pubsub_state table.

      get_entity_affiliations(Host, Owner) -> - OwnerKey = jlib:short_prepd_bare_jid(Owner), + GenKey = jlib:short_prepd_bare_jid(Owner), States = mnesia:match_object( - #pubsub_state{stateid = {OwnerKey, {Host, '_'}}, _ = '_'}), + #pubsub_state{stateid = {GenKey, {Host, '_'}}, _ = '_'}), Tr = fun(#pubsub_state{stateid = {_, {_, N}}, affiliation = A}) -> {N, A} end, @@ -554,14 +572,14 @@ get_node_affiliations(Host, Node) -> {result, lists:map(Tr, States)}. get_affiliation(Host, Node, Owner) -> - OwnerKey = jlib:short_prepd_bare_jid(Owner), - State = get_state(Host, Node, OwnerKey), - {result, State#pubsub_state.affiliation}. + GenKey = jlib:short_prepd_bare_jid(Owner), + GenState = get_state(Host, Node, GenKey), + {result, GenState#pubsub_state.affiliation}. set_affiliation(Host, Node, Owner, Affiliation) -> - OwnerKey = jlib:short_prepd_bare_jid(Owner), - State = get_state(Host, Node, OwnerKey), - set_state(State#pubsub_state{affiliation = Affiliation}), + GenKey = jlib:short_prepd_bare_jid(Owner), + GenState = get_state(Host, Node, GenKey), + set_state(GenState#pubsub_state{affiliation = Affiliation}), ok. %% @spec (Host, Owner) -> [{Node,Subscription}] @@ -576,11 +594,16 @@ set_affiliation(Host, Node, Owner, Affiliation) -> %% that will be added to the affiliation stored in the main %% pubsub_state table.

      get_entity_subscriptions(Host, Owner) -> - OwnerKey = jlib:short_prepd_bare_jid(Owner), - States = mnesia:match_object( - #pubsub_state{stateid = {OwnerKey, {Host, '_'}}, _ = '_'}), - Tr = fun(#pubsub_state{stateid = {_, {_, N}}, subscription = S}) -> - {N, S} + States = case jlib:short_prepd_bare_jid(Owner) of + {U, D, ""} -> mnesia:match_object( + #pubsub_state{stateid = {{U, D, '_'}, {Host, '_'}}, _ = '_'}); + {U, D, R} -> mnesia:match_object( + #pubsub_state{stateid = {{U, D, ""}, {Host, '_'}}, _ = '_'}) + ++ mnesia:match_object( + #pubsub_state{stateid = {{U, D, R}, {Host, '_'}}, _ = '_'}) + end, + Tr = fun(#pubsub_state{stateid = {J, {_, N}}, subscription = S}) -> + {N, S, J} end, {result, lists:map(Tr, States)}. @@ -593,14 +616,14 @@ get_node_subscriptions(Host, Node) -> {result, lists:map(Tr, States)}. get_subscription(Host, Node, Owner) -> - OwnerKey = jlib:short_prepd_bare_jid(Owner), - State = get_state(Host, Node, OwnerKey), - {result, State#pubsub_state.subscription}. + GenKey = jlib:short_prepd_bare_jid(Owner), + GenState = get_state(Host, Node, GenKey), + {result, GenState#pubsub_state.subscription}. set_subscription(Host, Node, Owner, Subscription) -> - OwnerKey = jlib:short_prepd_bare_jid(Owner), - State = get_state(Host, Node, OwnerKey), - set_state(State#pubsub_state{subscription = Subscription}), + GenKey = jlib:short_prepd_bare_jid(Owner), + GenState = get_state(Host, Node, GenKey), + set_state(GenState#pubsub_state{subscription = Subscription}), ok. %% @spec (Host, Node) -> [States] | [] @@ -668,10 +691,9 @@ get_items(Host, Node, _From) -> #pubsub_item{itemid = {'_', {Host, Node}}, _ = '_'}), {result, Items}. get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> - State = get_state(Host, Node, jlib:short_prepd_bare_jid(JID)), - #pubsub_state{affiliation = Affiliation, - subscription = Subscription} = State, - Subscribed = not ((Subscription == none) or (Subscription == pending)), + GenKey = jlib:short_prepd_bare_jid(JID), + GenState = get_state(Host, Node, GenKey), + Affiliation = GenState#pubsub_state.affiliation, Whitelisted = lists:member(Affiliation, [member, publisher, owner]), if %%SubID == "", ?? -> @@ -683,9 +705,6 @@ get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubI Affiliation == outcast -> %% Requesting entity is blocked {error, 'forbidden'}; - (AccessModel == open) and (not Subscribed) -> - %% Entity is not subscribed - {error, ?ERR_EXTENDED('not-authorized', "not-subscribed")}; (AccessModel == presence) and (not PresenceSubscription) -> %% Entity is not authorized to create a subscription (presence subscription required) {error, ?ERR_EXTENDED('not-authorized', "presence-subscription-required")}; @@ -719,10 +738,9 @@ get_item(Host, Node, ItemId) -> {error, 'item-not-found'} end. get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> - State = get_state(Host, Node, jlib:short_prepd_bare_jid(JID)), - #pubsub_state{affiliation = Affiliation, - subscription = Subscription} = State, - Subscribed = not ((Subscription == none) or (Subscription == pending)), + GenKey = jlib:short_prepd_bare_jid(JID), + GenState = get_state(Host, Node, GenKey), + Affiliation = GenState#pubsub_state.affiliation, Whitelisted = lists:member(Affiliation, [member, publisher, owner]), if %%SubID == "", ?? -> @@ -734,9 +752,6 @@ get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup Affiliation == outcast -> %% Requesting entity is blocked {error, 'forbidden'}; - (AccessModel == open) and (not Subscribed) -> - %% Entity is not subscribed - {error, ?ERR_EXTENDED('not-authorized', "not-subscribed")}; (AccessModel == presence) and (not PresenceSubscription) -> %% Entity is not authorized to create a subscription (presence subscription required) {error, ?ERR_EXTENDED('not-authorized', "presence-subscription-required")}; From d2524b20d50974d114c8a8c8b130225078c58eb7 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 8 Jan 2009 18:44:11 +0000 Subject: [PATCH 155/582] minor pubsub fixes SVN Revision: 1782 --- ChangeLog | 11 +++++++++++ src/mod_pubsub/node.template | 1 + src/mod_pubsub/node_buddy.erl | 1 + src/mod_pubsub/node_club.erl | 1 + src/mod_pubsub/node_default.erl | 4 +--- src/mod_pubsub/node_mb.erl | 1 + src/mod_pubsub/node_pep.erl | 1 + src/mod_pubsub/node_private.erl | 1 + src/mod_pubsub/node_public.erl | 1 + 9 files changed, 19 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 429f7151a..58a8e0464 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,17 @@ * src/mod_pubsub/node_default.erl: any entity can retrieve item when node access model is "open" (thanks to Myers Carpenter)(EJAB-836) + * src/mod_pubsub/node_default.erl: use of del_items + + * src/mod_pubsub/node.template: apply delete-any feature + * src/mod_pubsub/node_mb.erl: Likewise + * src/mod_pubsub/node_buddy.erl: Likewise + * src/mod_pubsub/node_private.erl: Likewise + * src/mod_pubsub/node_public.erl: Likewise + * src/mod_pubsub/node_pep.erl: Likewise + * src/mod_pubsub/node_default.erl: Likewise + * src/mod_pubsub/node_club.erl: Likewise + 2009-01-08 Pablo Polvorin * src/mod_vcard_ldap.erl, src/mod_muc/mod_muc.erl, src/mod_roster.hrl, src/mod_offline_odbc.erl, src/ejabberd_s2s_in.erl, src/adhoc.erl, diff --git a/src/mod_pubsub/node.template b/src/mod_pubsub/node.template index b98322d0d..447c919ad 100644 --- a/src/mod_pubsub/node.template +++ b/src/mod_pubsub/node.template @@ -95,6 +95,7 @@ options() -> features() -> ["create-nodes", "delete-nodes", + "delete-any", "instant-nodes", "outcast-affiliation", "persistent-items", diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl index 95fefe9a5..832e0dd31 100644 --- a/src/mod_pubsub/node_buddy.erl +++ b/src/mod_pubsub/node_buddy.erl @@ -98,6 +98,7 @@ options() -> features() -> ["create-nodes", "delete-nodes", + "delete-any", "instant-nodes", "item-ids", "outcast-affiliation", diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl index 6ff3fd33a..8fd13cf47 100644 --- a/src/mod_pubsub/node_club.erl +++ b/src/mod_pubsub/node_club.erl @@ -98,6 +98,7 @@ options() -> features() -> ["create-nodes", "delete-nodes", + "delete-any", "instant-nodes", "outcast-affiliation", "persistent-items", diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 27a9fdd55..f83f5008a 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -535,9 +535,7 @@ purge_node(Host, Node, Owner) -> GenState = get_state(Host, Node, GenKey), case GenState of #pubsub_state{items = Items, affiliation = owner} -> - lists:foreach(fun(ItemId) -> - mnesia:delete({pubsub_item, {ItemId, {Host, Node}}}) - end, Items), + del_items(Host, Node, Items), {result, {default, broadcast}}; _ -> %% Entity is not owner diff --git a/src/mod_pubsub/node_mb.erl b/src/mod_pubsub/node_mb.erl index 15cc1d312..d90f2391f 100644 --- a/src/mod_pubsub/node_mb.erl +++ b/src/mod_pubsub/node_mb.erl @@ -102,6 +102,7 @@ features() -> "auto-create", %* "auto-subscribe", %* "delete-nodes", %* + "delete-any", %* "filtered-notifications", %* "modify-affiliations", "outcast-affiliation", diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index cbbc16ce6..abc3e2ed3 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -98,6 +98,7 @@ features() -> "auto-create", %* "auto-subscribe", %* "delete-nodes", %* + "delete-any", %* "filtered-notifications", %* "modify-affiliations", "outcast-affiliation", diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl index 20a8e5e01..ae9768344 100644 --- a/src/mod_pubsub/node_private.erl +++ b/src/mod_pubsub/node_private.erl @@ -98,6 +98,7 @@ options() -> features() -> ["create-nodes", "delete-nodes", + "delete-any", "instant-nodes", "outcast-affiliation", "persistent-items", diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl index c12e37187..5276c4d26 100644 --- a/src/mod_pubsub/node_public.erl +++ b/src/mod_pubsub/node_public.erl @@ -98,6 +98,7 @@ options() -> features() -> ["create-nodes", "delete-nodes", + "delete-any", "instant-nodes", "outcast-affiliation", "persistent-items", From 98f51dc91f086a545c873e86e60f1d55b65f4645 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Fri, 9 Jan 2009 19:18:46 +0000 Subject: [PATCH 156/582] Adapt to new exmpp API where get_id/1, get_lang/1, get_initiating_entity/1, get_receiving_entity/1 and get_type/1 returns binary(). SVN Revision: 1791 --- ChangeLog | 17 +++++ src/ejabberd_c2s.erl | 13 ++-- src/ejabberd_local.erl | 4 +- src/ejabberd_s2s.erl | 4 +- src/ejabberd_s2s_out.erl | 8 +-- src/mod_irc/mod_irc.erl | 4 +- src/mod_irc/mod_irc_connection.erl | 2 +- src/mod_muc/mod_muc.erl | 8 +-- src/mod_muc/mod_muc_room.erl | 112 ++++++++++++++--------------- src/mod_offline.erl | 6 +- src/mod_offline_odbc.erl | 4 +- src/mod_pubsub/mod_pubsub.erl | 4 +- src/mod_pubsub/node_default.erl | 2 +- src/mod_roster.erl | 4 +- src/mod_roster_odbc.erl | 4 +- src/translate.erl | 43 +++++++---- 16 files changed, 136 insertions(+), 103 deletions(-) diff --git a/ChangeLog b/ChangeLog index 58a8e0464..95598c786 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2009-01-09 Pablo Polvorin + + * src/mod_muc/mod_muc_room.erl, src/mod_muc/mod_muc.erl + src/mod_offline_odbc.erl, src/mod_irc/mod_irc_connection.erl, + src/mod_irc/mod_irc.erl, src/ejabberd_c2s.erl, src/ejabberd_local.erl, + src/mod_pubsub/mod_pubsub.erl, src/ejabberd_s2s.erl, src/mod_roster.erl, + src/mod_roster_odbc.erl, src/ejabberd_s2s_out.erl, src/mod_offline.erl, + src/translate.erl: Adapt to new exmpp API where get_id/1, get_lang/1, + get_initiating_entity/1, get_receiving_entity/1 and get_type/1 + returns binary(). + + * src/mod_pubsub/node_default.erl: Fix typo in variable name. + + * src/ejabberd_c2s.erl: Fix bug in handle_info/3 when dealing with + VCARD requests: convert to IQ struct before invoking gen_iq_handler. + + 2009-01-08 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: completely support subscription using diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 34b124587..1ea7de1df 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -239,9 +239,9 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> StateData#state.streamid, DefaultLang), case NS of ?NS_XMPP -> - Server = exmpp_stringprep:nameprep( + ServerB = exmpp_stringprep:nameprep( exmpp_stream:get_receiving_entity(Opening)), - ServerB = list_to_binary(Server), + Server = binary_to_list(ServerB), case lists:member(Server, ?MYHOSTS) of true -> Lang = exmpp_stream:get_lang(Opening), @@ -900,9 +900,9 @@ session_established2(El, StateData) -> catch throw:{stringprep, _, _, _} -> case exmpp_stanza:get_type(El) of - "error" -> + <<"error">> -> ok; - "result" -> + <<"result">> -> ok; _ -> Err = exmpp_stanza:reply_with_error(El, 'jid-malformed'), @@ -1166,7 +1166,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> case ets:lookup(sm_iqtable, {?NS_VCARD, Host}) of [{_, Module, Function, Opts}] -> gen_iq_handler:handle(Host, Module, Function, Opts, - From, To, Packet); + From, To, exmpp_iq:xmlel_to_iq(Packet)); [] -> Res = exmpp_iq:error(Packet, 'feature-not-implemented'), ejabberd_router:route(To, From, Res) @@ -1857,7 +1857,6 @@ resend_subscription_requests(#state{user = UserB, PendingSubscriptions). process_unauthenticated_stanza(StateData, El) when ?IS_IQ(El) -> - ServerString = binary_to_list(StateData#state.server), case exmpp_iq:get_kind(El) of request -> IQ_Rec = exmpp_iq:xmlel_to_iq(El), @@ -1873,7 +1872,7 @@ process_unauthenticated_stanza(StateData, El) when ?IS_IQ(El) -> ResIQ = exmpp_iq:error_without_original(El, 'service-unavailable'), Res1 = exmpp_stanza:set_sender(ResIQ, - exmpp_jid:make_bare_jid(ServerString)), + exmpp_jid:make_bare_jid(StateData#state.server)), Res2 = exmpp_stanza:remove_recipient(Res1), send_element(StateData, Res2); _ -> diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 32d503ce2..fe3ea584c 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -321,8 +321,8 @@ do_route(From, To, Packet) -> end; true -> case exmpp_stanza:get_type(Packet) of - "error" -> ok; - "result" -> ok; + <<"error">> -> ok; + <<"result">> -> ok; _ -> ejabberd_hooks:run(local_send_to_resource_hook, exmpp_jid:ldomain(To), diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index 2cdbfa897..8073518bf 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -290,8 +290,8 @@ do_route(From, To, Packet) -> ok; {aborted, _Reason} -> case exmpp_stanza:get_type(Packet) of - "error" -> ok; - "result" -> ok; + <<"error">> -> ok; + <<"result">> -> ok; _ -> Err = exmpp_stanza:reply_with_error(Packet, 'service-unavailable'), diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index ea4078db0..67d4bc615 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -803,8 +803,8 @@ send_queue(StateData, Q) -> %% Bounce a single message (xmlel) bounce_element(El, Condition) -> case exmpp_stanza:get_type(El) of - "error" -> ok; - "result" -> ok; + <<"error">> -> ok; + <<"result">> -> ok; _ -> Err = exmpp_stanza:reply_with_error(El, Condition), From = exmpp_jid:binary_to_jid(exmpp_stanza:get_sender(El)), @@ -882,14 +882,14 @@ is_verify_res(#xmlel{ns = ?NS_DIALBACK, name = 'result', exmpp_stanza:get_recipient_from_attrs(Attrs), exmpp_stanza:get_sender_from_attrs(Attrs), exmpp_stanza:get_id_from_attrs(Attrs), - exmpp_stanza:get_type_from_attrs(Attrs)}; + binary_to_list(exmpp_stanza:get_type_from_attrs(Attrs))}; is_verify_res(#xmlel{ns = ?NS_DIALBACK, name = 'verify', attrs = Attrs}) -> {verify, exmpp_stanza:get_recipient_from_attrs(Attrs), exmpp_stanza:get_sender_from_attrs(Attrs), exmpp_stanza:get_id_from_attrs(Attrs), - exmpp_stanza:get_type_from_attrs(Attrs)}; + binary_to_list(exmpp_stanza:get_type_from_attrs(Attrs))}; is_verify_res(_) -> false. diff --git a/src/mod_irc/mod_irc.erl b/src/mod_irc/mod_irc.erl index 28ab85e63..341a97df2 100644 --- a/src/mod_irc/mod_irc.erl +++ b/src/mod_irc/mod_irc.erl @@ -371,10 +371,10 @@ process_irc_register(Host, From, _To, _DefEnc, exmpp_iq:error(IQ_Rec, 'not-acceptable'); _ -> case exmpp_stanza:get_type(XDataEl) of - "cancel" -> + <<"cancel">> -> Result = #xmlel{ns = XMLNS, name = 'query'}, exmpp_iq:result(IQ_Rec, Result); - "submit" -> + <<"submit">> -> XData = jlib:parse_xdata_submit(XDataEl), case XData of invalid -> diff --git a/src/mod_irc/mod_irc_connection.erl b/src/mod_irc/mod_irc_connection.erl index 9852db8c5..0679a411b 100644 --- a/src/mod_irc/mod_irc_connection.erl +++ b/src/mod_irc/mod_irc_connection.erl @@ -625,7 +625,7 @@ bounce_messages(Reason) -> receive {send_element, El} -> case exmpp_stanza:get_type(El) of - "error" -> + <<"error">> -> ok; _ -> Error = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index 9dd7de980..2f9f594ac 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -401,9 +401,9 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, end; _ -> case exmpp_stanza:get_type(Packet) of - "error" -> + <<"error">> -> ok; - "result" -> + <<"result">> -> ok; _ -> Err = exmpp_iq:error(Packet,'item-not-found'), @@ -638,9 +638,9 @@ process_iq_register_set(Host, From, SubEl, Lang) -> case exmpp_xml:get_child_elements(SubEl) of [#xmlel{ns= NS, name = 'x'} = XEl] -> case {NS, exmpp_stanza:get_type(XEl)} of - {?NS_DATA_FORMS, "cancel"} -> + {?NS_DATA_FORMS, <<"cancel">>} -> ok; - {?NS_DATA_FORMS, "submit"} -> + {?NS_DATA_FORMS, <<"submit">>} -> XData = jlib:parse_xdata_submit(XEl), case XData of invalid -> diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 8368c4c05..d6db806af 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -966,38 +966,38 @@ is_user_online(JID, StateData) -> LJID = jlib:short_prepd_jid(JID), ?DICT:is_key(LJID, StateData#state.users). -role_to_list(Role) -> +role_to_binary(Role) -> case Role of - moderator -> "moderator"; - participant -> "participant"; - visitor -> "visitor"; - none -> "none" + moderator -> <<"moderator">>; + participant -> <<"participant">>; + visitor -> <<"visitor">>; + none -> <<"none">> end. -affiliation_to_list(Affiliation) -> +affiliation_to_binary(Affiliation) -> case Affiliation of - owner -> "owner"; - admin -> "admin"; - member -> "member"; - outcast -> "outcast"; - none -> "none" + owner -> <<"owner">>; + admin -> <<"admin">>; + member -> <<"member">>; + outcast -> <<"outcast">>; + none -> <<"none">> end. -list_to_role(Role) -> +binary_to_role(Role) -> case Role of - "moderator" -> moderator; - "participant" -> participant; - "visitor" -> visitor; - "none" -> none + <<"moderator">> -> moderator; + <<"participant">> -> participant; + <<"visitor">> -> visitor; + <<"none">> -> none end. -list_to_affiliation(Affiliation) -> +binary_to_affiliation(Affiliation) -> case Affiliation of - "owner" -> owner; - "admin" -> admin; - "member" -> member; - "outcast" -> outcast; - "none" -> none + <<"owner">> -> owner; + <<"admin">> -> admin; + <<"member">> -> member; + <<"outcast">> -> outcast; + <<"none">> -> none end. %% Decide the fate of the message and its sender @@ -1758,8 +1758,8 @@ send_new_presence(NJID, Reason, StateData) -> last_presence = Presence}} = ?DICT:find(jlib:short_prepd_jid(NJID), StateData#state.users), Affiliation = get_affiliation(NJID, StateData), - SAffiliation = affiliation_to_list(Affiliation), - SRole = role_to_list(Role), + SAffiliation = affiliation_to_binary(Affiliation), + SRole = role_to_binary(Role), lists:foreach( fun({_LJID, Info}) -> ItemAttrs = @@ -1824,12 +1824,12 @@ send_existing_presences(ToJID, StateData) -> true -> [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(FromJID)}, #xmlattr{name = 'affiliation', - value = affiliation_to_list(FromAffiliation)}, - #xmlattr{name = 'role', value = role_to_list(FromRole)}]; + value = affiliation_to_binary(FromAffiliation)}, + #xmlattr{name = 'role', value = role_to_binary(FromRole)}]; _ -> [#xmlattr{name = 'affiliation', - value = affiliation_to_list(FromAffiliation)}, - #xmlattr{name = 'role', value = role_to_list(FromRole)}] + value = affiliation_to_binary(FromAffiliation)}, + #xmlattr{name = 'role', value = role_to_binary(FromRole)}] end, Packet = exmpp_xml:append_child(Presence, #xmlel{ns = ?NS_MUC_USER, name = 'x', @@ -1871,8 +1871,8 @@ send_nick_changing(JID, OldNick, StateData) -> last_presence = Presence}} = ?DICT:find(jlib:short_prepd_jid(JID), StateData#state.users), Affiliation = get_affiliation(JID, StateData), - SAffiliation = affiliation_to_list(Affiliation), - SRole = role_to_list(Role), + SAffiliation = affiliation_to_binary(Affiliation), + SRole = role_to_binary(Role), lists:foreach( fun({_LJID, Info}) -> ItemAttrs1 = @@ -2030,13 +2030,13 @@ process_iq_admin(From, get, Lang, SubEl, StateData) -> Item -> FAffiliation = get_affiliation(From, StateData), FRole = get_role(From, StateData), - case exmpp_xml:get_attribute(Item, 'role', false) of + case exmpp_xml:get_attribute_as_binary(Item, 'role', false) of false -> - case exmpp_xml:get_attribute(Item, 'affiliation', false) of + case exmpp_xml:get_attribute_as_binary(Item, 'affiliation', false) of false -> {error, 'bad-request'}; StrAffiliation -> - case catch list_to_affiliation(StrAffiliation) of + case catch binary_to_affiliation(StrAffiliation) of {'EXIT', _} -> {error, 'bad-request'}; SAffiliation -> @@ -2053,7 +2053,7 @@ process_iq_admin(From, get, Lang, SubEl, StateData) -> end end; StrRole -> - case catch list_to_role(StrRole) of + case catch binary_to_role(StrRole) of {'EXIT', _} -> {error, 'bad-request'}; SRole -> @@ -2082,9 +2082,9 @@ items_with_affiliation(SAffiliation, StateData) -> {N, D, R} = JID, #xmlel{name = 'item', attrs = [#xmlattr{name = 'affiliation', - value = affiliation_to_list(Affiliation)}, + value = affiliation_to_binary(Affiliation)}, #xmlattr{name = 'jid', - value = exmpp_jid:jid_to_list(N, D, R)}], + value = exmpp_jid:jid_to_binary(N, D, R)}], children = [ #xmlel{name = 'reason', children = [#xmlcdata{cdata = Reason}]}]}; @@ -2092,9 +2092,9 @@ items_with_affiliation(SAffiliation, StateData) -> {N, D, R} = JID, #xmlel{name = 'item', attrs = [#xmlattr{name = 'affiliation', - value = affiliation_to_list(Affiliation)}, + value = affiliation_to_binary(Affiliation)}, #xmlattr{name = 'jid', - value = exmpp_jid:jid_to_list(N, D, R)}]} + value = exmpp_jid:jid_to_binary(N, D, R)}]} end, search_affiliation(SAffiliation, StateData)). user_to_item(#user{role = Role, @@ -2104,10 +2104,10 @@ user_to_item(#user{role = Role, Affiliation = get_affiliation(JID, StateData), #xmlel{name = 'item', attrs = [ - #xmlattr{name = 'role', value = role_to_list(Role)}, - #xmlattr{name = 'affiliation', value = affiliation_to_list(Affiliation)}, + #xmlattr{name = 'role', value = role_to_binary(Role)}, + #xmlattr{name = 'affiliation', value = affiliation_to_binary(Affiliation)}, #xmlattr{name = 'nick', value = Nick}, - #xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(JID)}] + #xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(JID)}] }. search_role(Role, StateData) -> @@ -2225,9 +2225,9 @@ find_changed_items(UJID, UAffiliation, URole, [#xmlcdata{} | Items], find_changed_items(UJID, UAffiliation, URole, [#xmlel{name = 'item'} = Item | Items], Lang, StateData, Res) -> - TJID = case exmpp_xml:get_attribute(Item, 'jid',false) of + TJID = case exmpp_xml:get_attribute_as_binary(Item, 'jid',false) of S when S =/= false -> - try exmpp_jid:list_to_jid(S) of + try exmpp_jid:binary_to_jid(S) of J -> {value, J} catch @@ -2261,13 +2261,13 @@ find_changed_items(UJID, UAffiliation, URole, {value, JID} -> TAffiliation = get_affiliation(JID, StateData), TRole = get_role(JID, StateData), - case exmpp_xml:get_attribute(Item, 'role',false) of + case exmpp_xml:get_attribute_as_binary(Item, 'role',false) of false -> - case exmpp_xml:get_attribute(Item, 'affiliation', false) of + case exmpp_xml:get_attribute_as_binary(Item, 'affiliation', false) of false -> {error, 'bad-request'}; StrAffiliation -> - case catch list_to_affiliation(StrAffiliation) of + case catch binary_to_affiliation(StrAffiliation) of {'EXIT', _} -> ErrText1 = io_lib:format( @@ -2324,7 +2324,7 @@ find_changed_items(UJID, UAffiliation, URole, end end; StrRole -> - case catch list_to_role(StrRole) of + case catch binary_to_role(StrRole) of {'EXIT', _} -> ErrText1 = io_lib:format( @@ -2566,7 +2566,7 @@ send_kickban_presence1(UJID, Reason, Code, StateData) -> nick = Nick}} = ?DICT:find(UJID, StateData#state.users), {N,D,R} = UJID, Affiliation = get_affiliation(exmpp_jid:make_jid(N,D,R), StateData), - SAffiliation = affiliation_to_list(Affiliation), + SAffiliation = affiliation_to_binary(Affiliation), lists:foreach( fun({_LJID, Info}) -> ItemAttrs = [#xmlattr{name = 'affiliation', value = SAffiliation}, @@ -2607,10 +2607,10 @@ process_iq_owner(From, set, Lang, SubEl, StateData) -> owner -> case exmpp_xml:get_child_elements(SubEl) of [#xmlel{ns = XMLNS, name = 'x'} = XEl] -> - case {XMLNS, exmpp_xml:get_attribute(XEl, 'type',false)} of - {?NS_DATA_FORMS, "cancel"} -> + case {XMLNS, exmpp_xml:get_attribute_as_binary(XEl, 'type',false)} of + {?NS_DATA_FORMS, <<"cancel">>} -> {result, [], StateData}; - {?NS_DATA_FORMS, "submit"} -> + {?NS_DATA_FORMS, <<"submit">>} -> case {check_allowed_log_change(XEl, StateData, From), check_allowed_persistent_change(XEl, StateData, From)} of {allow, allow} -> set_config(XEl, StateData); @@ -2639,11 +2639,11 @@ process_iq_owner(From, get, Lang, SubEl, StateData) -> [] -> get_config(Lang, StateData, From); [Item] -> - case exmpp_xml:get_attribute(Item, 'affiliation',false) of + case exmpp_xml:get_attribute_as_binary(Item, 'affiliation',false) of false -> {error, 'bad-request'}; StrAffiliation -> - case catch list_to_affiliation(StrAffiliation) of + case catch binary_to_affiliation(StrAffiliation) of {'EXIT', _} -> ErrText = io_lib:format( @@ -3227,7 +3227,7 @@ check_invitation(From, Els, Lang, StateData) -> _ -> throw({error, 'bad-request'}) end, - JID = try exmpp_jid:list_to_jid(exmpp_xml:get_attribute(InviteEl, + JID = try exmpp_jid:binary_to_jid(exmpp_xml:get_attribute_as_binary(InviteEl, 'to', false)) of JID1 -> JID1 @@ -3330,8 +3330,8 @@ check_decline_invitation(Packet) -> #xmlel{name = 'message'} = Packet, #xmlel{ns = ?NS_MUC_USER} = XEl = exmpp_xml:get_element(Packet, 'x'), DEl = exmpp_xml:get_element(XEl, 'decline'), - ToString = exmpp_xml:get_attribute(DEl, 'to', false), - ToJID = exmpp_jid:list_to_jid(ToString), + ToString = exmpp_xml:get_attribute_as_binary(DEl, 'to', false), + ToJID = exmpp_jid:binary_to_jid(ToString), {true, {Packet, XEl, DEl, ToJID}}. %% Send the decline to the inviter user. diff --git a/src/mod_offline.erl b/src/mod_offline.erl index e0dc642da..bbf50fb80 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -157,8 +157,8 @@ stop(Host) -> store_packet(From, To, Packet) -> Type = exmpp_stanza:get_type(Packet), if - (Type /= "error") and (Type /= "groupchat") and - (Type /= "headline") -> + (Type /= <<"error">>) and (Type /= <<"groupchat">>) and + (Type /= <<"headline">>) -> case check_event(From, To, Packet) of true -> LUser = exmpp_jid:lnode_as_list(To), @@ -197,7 +197,7 @@ check_event(From, To, Packet) -> S -> #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'id', children = [#xmlcdata{cdata = - list_to_binary(S)}]} + S}]} end, X = #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'x', children = [ID, #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'offline'}]}, diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index 4a169c10f..e9b24e1fe 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -165,8 +165,8 @@ stop(Host) -> store_packet(From, To, Packet) -> Type = exmpp_stanza:get_type(Packet), if - (Type /= "error") and (Type /= "groupchat") and - (Type /= "headline") -> + (Type /= <<"error">>) and (Type /= <<"groupchat">>) and + (Type /= <<"headline">>) -> case check_event(From, To, Packet) of true -> LUser = exmpp_jid:lnode_as_list(To), diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 65e483d34..96da35ef6 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -694,9 +694,9 @@ do_route(ServerHost, Access, Plugins, Host, From, To, Packet) -> end; _ -> case exmpp_stanza:get_type(Packet) of - "error" -> + <<"error">> -> ok; - "result" -> + <<"result">> -> ok; _ -> Err = exmpp_stanza:reply_with_error(Packet, diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index f83f5008a..9fe26920c 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -279,7 +279,7 @@ delete_node(Host, Removed) -> %%

      In the default plugin module, the record is unchanged.

      subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - SubKey = jlib:short_prepd_jid(Owner), + SubKey = jlib:short_prepd_jid(Subscriber), GenKey = jlib:short_prepd_bare_jid(SubKey), Authorized = (jlib:short_prepd_bare_jid(Sender) == GenKey), GenState = get_state(Host, Node, GenKey), diff --git a/src/mod_roster.erl b/src/mod_roster.erl index f412e1906..61de76362 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -190,7 +190,7 @@ process_iq_set(From, To, #iq{payload = Request} = IQ_Rec) -> process_item_set(From, To, #xmlel{} = El) -> try - JID1 = exmpp_jid:list_to_jid(exmpp_xml:get_attribute(El, 'jid', "")), + JID1 = exmpp_jid:binary_to_jid(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), User = exmpp_jid:node(From), LUser = exmpp_jid:lnode(From), LServer = exmpp_jid:ldomain(From), @@ -596,7 +596,7 @@ set_items(User, Server, #xmlel{children = Els}) -> process_item_set_t(LUser, LServer, #xmlel{} = El) -> try - JID1 = exmpp_jid:list_to_jid(exmpp_xml:get_attribute(El, 'jid', "")), + JID1 = exmpp_jid:binary_to_jid(exmpp_xml:get_attribute(El, 'jid', <<>>)), JID = jlib:short_jid(JID1), LJID = jlib:short_prepd_jid(JID1), Item = #roster{usj = {LUser, LServer, LJID}, diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 6434f3897..2e63508ed 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -216,7 +216,7 @@ process_iq_set(From, To, #iq{payload = Request} = IQ_Rec) -> process_item_set(From, To, #xmlel{} = El) -> try - JID1 = exmpp_jid:list_to_jid(exmpp_xml:get_attribute(El, 'jid', "")), + JID1 = exmpp_jid:binary_to_jid(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), LUser = exmpp_jid:lnode_as_list(From), LServer = exmpp_jid:ldomain_as_list(From), {U0, S0, R0} = LJID = jlib:short_prepd_jid(JID1), @@ -655,7 +655,7 @@ set_items(User, Server, #xmlel{children = Els}) -> process_item_set_t(LUser, LServer, #xmlel{} = El) -> try - JID1 = exmpp_jid:list_to_jid(exmpp_xml:get_attribute(El, 'jid', "")), + JID1 = exmpp_jid:binary_to_jid(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), {U0, S0, R0} = LJID = jlib:short_prepd_jid(JID1), Username = ejabberd_odbc:escape(LUser), SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(U0, S0, R0)), diff --git a/src/translate.erl b/src/translate.erl index a5513ce64..df76d145e 100644 --- a/src/translate.erl +++ b/src/translate.erl @@ -32,6 +32,8 @@ load_file/2, translate/2]). +-export([tokens/2, ascii_tolower/1]). + -include("ejabberd.hrl"). start() -> @@ -68,7 +70,8 @@ load_dir(Dir) -> lists:foreach( fun(FN) -> L = ascii_tolower( - string:substr(FN, 1, string:len(FN) - 4)), + list_to_binary( + string:substr(FN, 1, string:len(FN) - 4))), load_file(L, Dir ++ "/" ++ FN) end, MsgFiles), ok; @@ -107,14 +110,14 @@ translate(Lang, Msg) -> [{_, Trans}] -> Trans; _ -> - ShortLang = case string:tokens(LLang, "-") of + ShortLang = case tokens(LLang, $-) of [] -> LLang; [SL | _] -> SL end, case ShortLang of - "en" -> + <<"en">> -> Msg; LLang -> translate(Msg); @@ -132,7 +135,7 @@ translate(Msg) -> case ?MYLANG of undefined -> Msg; - "en" -> + <<"en">> -> Msg; Lang -> LLang = ascii_tolower(Lang), @@ -140,14 +143,14 @@ translate(Msg) -> [{_, Trans}] -> Trans; _ -> - ShortLang = case string:tokens(LLang, "-") of + ShortLang = case tokens(LLang, $-) of [] -> LLang; [SL | _] -> SL end, case ShortLang of - "en" -> + <<"en">> -> Msg; Lang -> Msg; @@ -162,11 +165,25 @@ translate(Msg) -> end end. -ascii_tolower([C | Cs]) when C >= $A, C =< $Z -> - [C + ($a - $A) | ascii_tolower(Cs)]; -ascii_tolower([C | Cs]) -> - [C | ascii_tolower(Cs)]; -ascii_tolower([]) -> - []; + ascii_tolower(undefined) -> - []. + <<>>; +ascii_tolower(Bin) -> + << <<(char_tolower(X))>> || <> <= Bin >>. + +char_tolower(C) when C >= $A, C =< $Z -> + C + ($a -$A); +char_tolower(C) -> + C. + +tokens(<<>>,_Sep) -> + []; +tokens(Bin, Sep) -> + tokens(Bin, Sep, <<>>, []). + +tokens(<<>>, _Sep, T, Tokens) -> + lists:reverse([T|Tokens]); +tokens(<>, Sep, T, Tokens) -> + tokens(R, Sep, <<>>, [T | Tokens]); +tokens(<>, Sep, T, Tokens) -> + tokens(R, Sep, <>, Tokens). From 36080fb68222c24df49bc31df57a1c55df7e8de4 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Sat, 10 Jan 2009 13:40:38 +0000 Subject: [PATCH 157/582] fix unsubscription of full jid subscribed node (EJAB-839) SVN Revision: 1795 --- ChangeLog | 5 +++++ src/mod_pubsub/node_default.erl | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 95598c786..f31707cff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-01-10 Christophe Romain + + * src/mod_pubsub/node_default.erl: fix unsubscription of full jid + subscribed node (thanks to Andy Skelton)(EJAB-839) + 2009-01-09 Pablo Polvorin * src/mod_muc/mod_muc_room.erl, src/mod_muc/mod_muc.erl diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 9fe26920c..ebb92e112 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -374,7 +374,7 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> (not Authorized) and (Affiliation =/= owner) -> {error, 'forbidden'}; %% Was just subscriber, remove the record - Affiliation == none -> + SubState#pubsub_state.affiliation == none -> del_state(SubState#pubsub_state.stateid), {result, default}; true -> From c77f7e727b6b5f829aeb78d19625f07bec2977dd Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Sat, 10 Jan 2009 16:10:12 +0000 Subject: [PATCH 158/582] Update gen_iq_handler API, require the 'Host' argument to be in binary() format. Fix bug in vcard user search, odbc backend. SVN Revision: 1796 --- ChangeLog | 14 ++++++++ src/ejabberd_c2s.erl | 2 +- src/ejabberd_local.erl | 2 +- src/ejabberd_sm.erl | 2 +- src/mod_adhoc.erl | 8 ++--- src/mod_caps.erl | 4 +-- src/mod_configure.erl | 4 +-- src/mod_configure2.erl | 4 +-- src/mod_disco.erl | 16 ++++----- src/mod_last.erl | 8 ++--- src/mod_last_odbc.erl | 8 ++--- src/mod_privacy.erl | 4 +-- src/mod_privacy_odbc.erl | 4 +-- src/mod_private.erl | 4 +-- src/mod_private_odbc.erl | 4 +-- src/mod_pubsub/mod_pubsub.erl | 6 ++-- src/mod_register.erl | 8 ++--- src/mod_roster.erl | 4 +-- src/mod_roster_odbc.erl | 4 +-- src/mod_stats.erl | 4 +-- src/mod_time.erl | 4 +-- src/mod_vcard.erl | 8 ++--- src/mod_vcard_ldap.erl | 12 ++++--- src/mod_vcard_odbc.erl | 62 ++++++++++++++++------------------- src/mod_version.erl | 4 +-- 25 files changed, 109 insertions(+), 95 deletions(-) diff --git a/ChangeLog b/ChangeLog index f31707cff..666270236 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2009-01-10 Pablo Polvorin + + * src/mod_vcard_odbc.erl: Fix bug in user search. + + * src/mod_vcard_ldap.erl, src/mod_vcard.erl, src/mod_configure.erl, + src/ejabberd_sm.erl, src/mod_privacy_odbc.erl, src/ejabberd_c2s.erl, + src/ejabberd_local.erl, src/mod_privacy.erl, src/mod_adhoc.erl, + src/mod_pubsub/mod_pubsub.erl, src/mod_vcard_odbc.erl, src/mod_stats.erl, + src/mod_last.erl, src/mod_private.erl, src/mod_roster.erl, + src/mod_disco.erl, src/mod_private_odbc.erl, src/mod_configure2.erl, + src/mod_roster_odbc.erl, src/mod_register.erl, src/mod_version.erl, + src/mod_caps.erl, src/mod_last_odbc.erl, src/mod_time.erl: Update + gen_iq_handler API, require the 'Host' argument to be in binary() format. + 2009-01-10 Christophe Romain * src/mod_pubsub/node_default.erl: fix unsubscription of full jid diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 1ea7de1df..266130320 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1162,7 +1162,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> true -> case exmpp_iq:get_request(Packet) of #xmlel{ns = ?NS_VCARD} -> - Host = binary_to_list(StateData#state.server), + Host = StateData#state.server, case ets:lookup(sm_iqtable, {?NS_VCARD, Host}) of [{_, Module, Function, Opts}] -> gen_iq_handler:handle(Host, Module, Function, Opts, diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index fe3ea584c..190e958b1 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -76,7 +76,7 @@ start_link() -> process_iq(From, To, Packet) -> case exmpp_iq:xmlel_to_iq(Packet) of #iq{kind = request, ns = XMLNS} = IQ_Rec -> - Host = exmpp_jid:ldomain_as_list(To), + Host = exmpp_jid:ldomain(To), case ets:lookup(?IQTABLE, {XMLNS, Host}) of [{_, Module, Function}] -> ResIQ = Module:Function(From, To, IQ_Rec), diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 33ea18656..18d664680 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -661,7 +661,7 @@ get_max_user_sessions(JID) -> process_iq(From, To, Packet) -> case exmpp_iq:xmlel_to_iq(Packet) of #iq{kind = request, ns = XMLNS} = IQ_Rec -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:ldomain(To), case ets:lookup(sm_iqtable, {XMLNS, LServer}) of [{_, Module, Function}] -> ResIQ = Module:Function(From, To, IQ_Rec), diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl index 9a92347ed..3769eb330 100644 --- a/src/mod_adhoc.erl +++ b/src/mod_adhoc.erl @@ -51,9 +51,9 @@ start(Host, Opts) -> HostB = list_to_binary(Host), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_ADHOC, + gen_iq_handler:add_iq_handler(ejabberd_local, HostB, ?NS_ADHOC, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ADHOC, + gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_ADHOC, ?MODULE, process_sm_iq, IQDisc), ejabberd_hooks:add(disco_local_identity, HostB, ?MODULE, get_local_identity, 99), @@ -76,8 +76,8 @@ stop(Host) -> ejabberd_hooks:delete(disco_local_features, HostB, ?MODULE, get_local_features, 99), ejabberd_hooks:delete(disco_local_identity, HostB, ?MODULE, get_local_identity, 99), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ADHOC), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ADHOC). + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_ADHOC), + gen_iq_handler:remove_iq_handler(ejabberd_local, HostB, ?NS_ADHOC). %------------------------------------------------------------------------- diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 19e24edd3..4363722d7 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -262,7 +262,7 @@ handle_cast({note_caps, From, 'node', lists:concat([Node, "#", SubNode])), Stanza = exmpp_iq:get(?NS_JABBER_CLIENT, Query, ID), ejabberd_local:register_iq_response_handler - (Host, ID, ?MODULE, handle_disco_response), + (list_to_binary(Host), ID, ?MODULE, handle_disco_response), ejabberd_router:route(exmpp_jid:make_bare_jid(Host), From, Stanza), timer:send_after(?CAPS_QUERY_TIMEOUT, self(), {disco_timeout, ID}), @@ -322,7 +322,7 @@ handle_cast({disco_timeout, ID}, #state{host = Host, disco_requests = Requests} %% do not wait a response anymore for this IQ, client certainly will never answer NewRequests = case ?DICT:is_key(ID, Requests) of true -> - ejabberd_local:unregister_iq_response_handler(Host, ID), + ejabberd_local:unregister_iq_response_handler(list_to_binary(Host), ID), ?DICT:erase(ID, Requests); false -> Requests diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 1271e976a..00fcee006 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -84,8 +84,8 @@ stop(Host) -> ejabberd_hooks:delete(disco_local_identity, HostB, ?MODULE, get_local_identity, 50), ejabberd_hooks:delete(disco_local_features, HostB, ?MODULE, get_local_features, 50), ejabberd_hooks:delete(disco_local_items, HostB, ?MODULE, get_local_items, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ADHOC), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ADHOC). + gen_iq_handler:remove_iq_handler(ejabberd_local, HostB, ?NS_ADHOC), + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_ADHOC). %%%----------------------------------------------------------------------- diff --git a/src/mod_configure2.erl b/src/mod_configure2.erl index 252a127bd..d5effc743 100644 --- a/src/mod_configure2.erl +++ b/src/mod_configure2.erl @@ -42,7 +42,7 @@ start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE, + gen_iq_handler:add_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_ECONFIGURE, ?MODULE, process_local_iq, IQDisc), % Add nss/names/attrs used by this module to the known lists of Exmpp. exmpp_xml:add_autoload_known_nss([?NS_ECONFIGURE]), @@ -67,7 +67,7 @@ start(Host, Opts) -> ok. stop(Host) -> - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE). + gen_iq_handler:remove_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_ECONFIGURE). process_local_iq(From, To, #iq{type = Type, payload = Request} = IQ_Rec) -> diff --git a/src/mod_disco.erl b/src/mod_disco.erl index ab57c109e..6febc2453 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -64,13 +64,13 @@ start(Host, Opts) -> ejabberd_local:refresh_iq_handlers(), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS, + gen_iq_handler:add_iq_handler(ejabberd_local, HostB, ?NS_DISCO_ITEMS, ?MODULE, process_local_iq_items, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO, + gen_iq_handler:add_iq_handler(ejabberd_local, HostB, ?NS_DISCO_INFO, ?MODULE, process_local_iq_info, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_DISCO_ITEMS, + gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_DISCO_ITEMS, ?MODULE, process_sm_iq_items, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_DISCO_INFO, + gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_DISCO_INFO, ?MODULE, process_sm_iq_info, IQDisc), catch ets:new(disco_features, [named_table, ordered_set, public]), @@ -103,10 +103,10 @@ stop(Host) -> ejabberd_hooks:delete(disco_local_identity, HostB, ?MODULE, get_local_identity, 100), ejabberd_hooks:delete(disco_local_features, HostB, ?MODULE, get_local_features, 100), ejabberd_hooks:delete(disco_local_items, HostB, ?MODULE, get_local_services, 100), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_DISCO_ITEMS), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_DISCO_INFO), + gen_iq_handler:remove_iq_handler(ejabberd_local, HostB, ?NS_DISCO_ITEMS), + gen_iq_handler:remove_iq_handler(ejabberd_local, HostB, ?NS_DISCO_INFO), + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_DISCO_ITEMS), + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_DISCO_INFO), catch ets:match_delete(disco_features, {{'_', Host}}), catch ets:match_delete(disco_extra_domains, {{'_', Host}}), ok. diff --git a/src/mod_last.erl b/src/mod_last.erl index b363db588..f1f8e7bda 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -53,9 +53,9 @@ start(Host, Opts) -> [{disc_copies, [node()]}, {attributes, record_info(fields, last_activity)}]), update_table(), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY, + gen_iq_handler:add_iq_handler(ejabberd_local, HostB, ?NS_LAST_ACTIVITY, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY, + gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_LAST_ACTIVITY, ?MODULE, process_sm_iq, IQDisc), ejabberd_hooks:add(remove_user, HostB, ?MODULE, remove_user, 50), @@ -68,8 +68,8 @@ stop(Host) -> ?MODULE, remove_user, 50), ejabberd_hooks:delete(unset_presence_hook, HostB, ?MODULE, on_presence_update, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY). + gen_iq_handler:remove_iq_handler(ejabberd_local, HostB, ?NS_LAST_ACTIVITY), + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_LAST_ACTIVITY). process_local_iq(_From, _To, #iq{type = get} = IQ_Rec) -> Sec = trunc(element(1, erlang:statistics(wall_clock))/1000), diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 286f19867..4eab4ffea 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -46,9 +46,9 @@ start(Host, Opts) -> HostB = list_to_binary(Host), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY, + gen_iq_handler:add_iq_handler(ejabberd_local, HostB, ?NS_LAST_ACTIVITY, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY, + gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_LAST_ACTIVITY, ?MODULE, process_sm_iq, IQDisc), ejabberd_hooks:add(remove_user, HostB, ?MODULE, remove_user, 50), @@ -61,8 +61,8 @@ stop(Host) -> ?MODULE, remove_user, 50), ejabberd_hooks:delete(unset_presence_hook, HostB, ?MODULE, on_presence_update, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY). + gen_iq_handler:remove_iq_handler(ejabberd_local, HostB, ?NS_LAST_ACTIVITY), + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_LAST_ACTIVITY). process_local_iq(_From, _To, #iq{type = get} = IQ_Rec) -> Sec = trunc(element(1, erlang:statistics(wall_clock))/1000), diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 0b1352d5d..7d035994f 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -59,7 +59,7 @@ start(Host, Opts) -> ?MODULE, check_packet, 50), ejabberd_hooks:add(privacy_updated_list, HostB, ?MODULE, updated_list, 50), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PRIVACY, + gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_PRIVACY, ?MODULE, process_iq, IQDisc). stop(Host) -> @@ -74,7 +74,7 @@ stop(Host) -> ?MODULE, check_packet, 50), ejabberd_hooks:delete(privacy_updated_list, HostB, ?MODULE, updated_list, 50), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVACY). + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_PRIVACY). process_iq(_From, _To, IQ_Rec) -> exmpp_iq:error(IQ_Rec, 'not-allowed'). diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 943354191..953a2dc2c 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -55,7 +55,7 @@ start(Host, Opts) -> ?MODULE, check_packet, 50), ejabberd_hooks:add(privacy_updated_list, HostB, ?MODULE, updated_list, 50), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PRIVACY, + gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_PRIVACY, ?MODULE, process_iq, IQDisc). stop(Host) -> @@ -70,7 +70,7 @@ stop(Host) -> ?MODULE, check_packet, 50), ejabberd_hooks:delete(privacy_updated_list, HostB, ?MODULE, updated_list, 50), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVACY). + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_PRIVACY). process_iq(_From, _To, IQ_Rec) -> exmpp_iq:error(IQ_Rec, 'not-allowed'). diff --git a/src/mod_private.erl b/src/mod_private.erl index a2c37a7bc..f4a30132e 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -49,14 +49,14 @@ start(Host, Opts) -> update_table(), ejabberd_hooks:add(remove_user, HostB, ?MODULE, remove_user, 50), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE, + gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_PRIVATE, ?MODULE, process_sm_iq, IQDisc). stop(Host) -> HostB = list_to_binary(Host), ejabberd_hooks:delete(remove_user, HostB, ?MODULE, remove_user, 50), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE). + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_PRIVATE). process_sm_iq(From, To, #iq{type = Type} = IQ_Rec) -> diff --git a/src/mod_private_odbc.erl b/src/mod_private_odbc.erl index 622b0df0b..59f9947d7 100644 --- a/src/mod_private_odbc.erl +++ b/src/mod_private_odbc.erl @@ -43,14 +43,14 @@ start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), ejabberd_hooks:add(remove_user, HostB, ?MODULE, remove_user, 50), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE, + gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_PRIVATE, ?MODULE, process_sm_iq, IQDisc). stop(Host) -> HostB = list_to_binary(Host), ejabberd_hooks:delete(remove_user, HostB, ?MODULE, remove_user, 50), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE). + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_PRIVATE). process_sm_iq(From, To, #iq{type = Type} = IQ_Rec) -> diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 96da35ef6..af4a57257 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -166,10 +166,11 @@ init([ServerHost, Opts]) -> ejabberd_hooks:add(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 50), ejabberd_hooks:add(remove_user, ServerHost, ?MODULE, remove_user, 50), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), + ServerB = list_to_binary(ServerHost), lists:foreach( fun({NS,Mod,Fun}) -> gen_iq_handler:add_iq_handler( - Mod, ServerHost, NS, ?MODULE, Fun, IQDisc) + Mod, ServerB, NS, ?MODULE, Fun, IQDisc) end, [{?NS_PUBSUB, ejabberd_local, iq_local}, {?NS_PUBSUB_OWNER, ejabberd_local, iq_local}, @@ -584,8 +585,9 @@ terminate(_Reason, #state{host = Host, ejabberd_hooks:delete(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75), ejabberd_hooks:delete(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 50), ejabberd_hooks:delete(remove_user, ServerHost, ?MODULE, remove_user, 50), + ServerB = list_to_binary(ServerHost), lists:foreach(fun({NS,Mod}) -> - gen_iq_handler:remove_iq_handler(Mod, ServerHost, NS) + gen_iq_handler:remove_iq_handler(Mod, ServerB, NS) end, [{?NS_PUBSUB, ejabberd_local}, {?NS_PUBSUB_OWNER, ejabberd_local}, {?NS_PUBSUB, ejabberd_sm}, diff --git a/src/mod_register.erl b/src/mod_register.erl index 2f1d37b38..3b66aeea8 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -42,9 +42,9 @@ start(Host, Opts) -> HostB = list_to_binary(Host), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_INBAND_REGISTER, + gen_iq_handler:add_iq_handler(ejabberd_local, HostB, ?NS_INBAND_REGISTER, ?MODULE, process_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_INBAND_REGISTER, + gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_INBAND_REGISTER, ?MODULE, process_iq, IQDisc), ejabberd_hooks:add(c2s_stream_features, HostB, ?MODULE, stream_feature_register, 50), @@ -63,8 +63,8 @@ stop(Host) -> ?MODULE, stream_feature_register, 50), ejabberd_hooks:delete(c2s_unauthenticated_iq, HostB, ?MODULE, unauthenticated_iq_register, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_INBAND_REGISTER), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_INBAND_REGISTER). + gen_iq_handler:remove_iq_handler(ejabberd_local, HostB, ?NS_INBAND_REGISTER), + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_INBAND_REGISTER). stream_feature_register(Acc) -> diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 61de76362..05f0381ac 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -79,7 +79,7 @@ start(Host, Opts) -> ?MODULE, webadmin_page, 50), ejabberd_hooks:add(webadmin_user, HostB, ?MODULE, webadmin_user, 50), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ROSTER, + gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_ROSTER, ?MODULE, process_iq, IQDisc). stop(Host) -> @@ -104,7 +104,7 @@ stop(Host) -> ?MODULE, webadmin_page, 50), ejabberd_hooks:delete(webadmin_user, HostB, ?MODULE, webadmin_user, 50), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_ROSTER). diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 2e63508ed..39c301a4d 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -74,7 +74,7 @@ start(Host, Opts) -> ?MODULE, webadmin_page, 50), ejabberd_hooks:add(webadmin_user, HostB, ?MODULE, webadmin_user, 50), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ROSTER, + gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_ROSTER, ?MODULE, process_iq, IQDisc). stop(Host) -> @@ -99,7 +99,7 @@ stop(Host) -> ?MODULE, webadmin_page, 50), ejabberd_hooks:delete(webadmin_user, HostB, ?MODULE, webadmin_user, 50), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ROSTER). + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_ROSTER). process_iq(From, To, IQ_Rec) -> diff --git a/src/mod_stats.erl b/src/mod_stats.erl index b1f80a98e..f0b549660 100644 --- a/src/mod_stats.erl +++ b/src/mod_stats.erl @@ -37,11 +37,11 @@ start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_STATS, + gen_iq_handler:add_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_STATS, ?MODULE, process_local_iq, IQDisc). stop(Host) -> - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_STATS). + gen_iq_handler:remove_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_STATS). process_local_iq(_From, To, #iq{type = get, diff --git a/src/mod_time.erl b/src/mod_time.erl index c8cdaff63..24ee78489 100644 --- a/src/mod_time.erl +++ b/src/mod_time.erl @@ -40,11 +40,11 @@ start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_TIME, + gen_iq_handler:add_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_TIME, ?MODULE, process_local_iq, IQDisc). stop(Host) -> - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_TIME). + gen_iq_handler:remove_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_TIME). process_local_iq(_From, _To, #iq{type = get} = IQ_Rec) -> UTC = jlib:timestamp_to_iso(calendar:universal_time()), diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index b465a14ed..d66912c65 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -85,9 +85,9 @@ start(Host, Opts) -> ejabberd_hooks:add(remove_user, HostB, ?MODULE, remove_user, 50), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD, + gen_iq_handler:add_iq_handler(ejabberd_local, HostB, ?NS_VCARD, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD, + gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_VCARD, ?MODULE, process_sm_iq, IQDisc), ejabberd_hooks:add(disco_sm_features, HostB, ?MODULE, get_sm_features, 50), MyHost = gen_mod:get_opt_host(Host, Opts, "vjud.@HOST@"), @@ -126,9 +126,9 @@ stop(Host) -> HostB = list_to_binary(Host), ejabberd_hooks:delete(remove_user, HostB, ?MODULE, remove_user, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, + gen_iq_handler:remove_iq_handler(ejabberd_local, HostB, ?NS_VCARD), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_VCARD), ejabberd_hooks:delete(disco_sm_features, HostB, ?MODULE, get_sm_features, 50), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index b6f5a35d3..1279bcd7a 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -153,9 +153,10 @@ stop(Host) -> terminate(_Reason, State) -> Host = State#state.serverhost, - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD), - ejabberd_hooks:delete(disco_sm_features, list_to_binary(Host), ?MODULE, get_sm_features, 50), + HostB = list_to_binary(Host), + gen_iq_handler:remove_iq_handler(ejabberd_local, HostB, ?NS_VCARD), + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_VCARD), + ejabberd_hooks:delete(disco_sm_features, HostB, ?MODULE, get_sm_features, 50), case State#state.search of true -> ejabberd_router:unregister_route(State#state.myhost); @@ -168,11 +169,12 @@ start_link(Host, Opts) -> gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []). init([Host, Opts]) -> + HostB = list_to_binary(Host), State = parse_options(Host, Opts), IQDisc = gen_mod:get_opt(iqdisc, Opts, parallel), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD, + gen_iq_handler:add_iq_handler(ejabberd_local, HostB, ?NS_VCARD, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD, + gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_VCARD, ?MODULE, process_sm_iq, IQDisc), ejabberd_hooks:add(disco_sm_features, list_to_binary(Host), ?MODULE, get_sm_features, 50), diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl index a67412dff..c1f46b685 100644 --- a/src/mod_vcard_odbc.erl +++ b/src/mod_vcard_odbc.erl @@ -49,9 +49,9 @@ start(Host, Opts) -> ejabberd_hooks:add(remove_user, HostB, ?MODULE, remove_user, 50), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD, + gen_iq_handler:add_iq_handler(ejabberd_local, HostB, ?NS_VCARD, ?MODULE, process_local_iq, IQDisc), - gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD, + gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_VCARD, ?MODULE, process_sm_iq, IQDisc), ejabberd_hooks:add(disco_sm_features, HostB, ?MODULE, get_sm_features, 50), MyHost = gen_mod:get_opt_host(Host, Opts, "vjud.@HOST@"), @@ -90,8 +90,8 @@ stop(Host) -> HostB = list_to_binary(Host), ejabberd_hooks:delete(remove_user, HostB, ?MODULE, remove_user, 50), - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD), - gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD), + gen_iq_handler:remove_iq_handler(ejabberd_local, HostB, ?NS_VCARD), + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_VCARD), ejabberd_hooks:delete(disco_sm_features, HostB, ?MODULE, get_sm_features, 50), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), Proc ! stop, @@ -295,35 +295,31 @@ do_route(ServerHost, From, To, Packet) -> Lang = exmpp_stanza:get_lang(Packet), case {Type, Request#xmlel.ns} of {set, ?NS_SEARCH} -> - XDataEl = find_xdata_el(Request), - case XDataEl of - false -> - Err = exmpp_iq:error(Packet, 'bad-request'), - ejabberd_router:route(To, From, Err); - _ -> - XData = jlib:parse_xdata_submit(XDataEl), - case XData of - invalid -> - Err = exmpp_iq:error(Packet, - 'bad-request'), - ejabberd_router:route(To, From, - Err); - _ -> - Result = #xmlel{ - ns = ?NS_SEARCH, - name = 'query', - children = [ - #xmlel{ - ns = ?NS_DATA_FORMS, - name = 'x', - attrs = [#xmlattr{name = 'type', - value = <<"result">>}], - children = search_result(Lang, - To, ServerHost, XData)}]}, - ResIQ = exmpp_iq:result(Packet, - Result), - ejabberd_router:route( - To, From, exmpp_iq:iq_to_xmlel(ResIQ)) + XDataEl = find_xdata_el(Request), + case XDataEl of + false -> + Err = exmpp_iq:error(Packet, 'bad-request'), + ejabberd_router:route(To, From, Err); + _ -> + XData = jlib:parse_xdata_submit(XDataEl), + case XData of + invalid -> + Err = exmpp_iq:error(Packet, 'bad-request'), + ejabberd_router:route(To, From, Err); + _ -> + Result = #xmlel{ns = ?NS_SEARCH, + name = 'query', + children = [ + #xmlel{ns = ?NS_DATA_FORMS, + name = 'x', + attrs = [ + #xmlattr{name = 'type', + value = <<"result">>}], + children = search_result(Lang, + To, ServerHost, XData)}]}, + ResIQ = exmpp_iq:result(Packet, Result), + ejabberd_router:route( + To, From, ResIQ) end end; {get, ?NS_SEARCH} -> diff --git a/src/mod_version.erl b/src/mod_version.erl index 19d154048..07d6dfec4 100644 --- a/src/mod_version.erl +++ b/src/mod_version.erl @@ -41,11 +41,11 @@ start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_SOFT_VERSION, + gen_iq_handler:add_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_SOFT_VERSION, ?MODULE, process_local_iq, IQDisc). stop(Host) -> - gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_SOFT_VERSION). + gen_iq_handler:remove_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_SOFT_VERSION). process_local_iq(_From, To, #iq{type = Type} = IQ_Rec) -> From 89be1c2edee7205f70131f0eff6c9cbb0398ded0 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Sun, 11 Jan 2009 02:05:41 +0000 Subject: [PATCH 159/582] fix owners cache and fix unsubscribe permissions (EJAB-840) SVN Revision: 1800 --- ChangeLog | 6 ++++++ src/mod_pubsub/mod_pubsub.erl | 36 ++++++++++++++++++++++++--------- src/mod_pubsub/node_default.erl | 33 ++++++++++++++++++------------ 3 files changed, 53 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index 666270236..e5a9f1ea0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-01-11 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: fix owners cache and fix unsubscribe + permissions (thanks to Andy Skelton)(EJAB-840) + * src/mod_pubsub/node_default.erl: Likewise + 2009-01-10 Pablo Polvorin * src/mod_vcard_odbc.erl: Fix bug in user search. diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index af4a57257..0ab6b7053 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -2031,15 +2031,33 @@ set_subscriptions(Host, Node, From, EntitiesEls) -> {error, 'bad-request'}; _ -> Action = fun(#pubsub_node{type = Type, owners = Owners}) -> - case lists:member(Owner, Owners) of - true -> - lists:foreach(fun({JID, Subscription}) -> - node_call(Type, set_subscription, [Host, Node, JID, Subscription]) - end, Entities), - {result, []}; - _ -> - {error, 'forbidden'} - end + case lists:member(Owner, Owners) of + true -> + lists:foreach( + fun({JID, Affiliation}) -> + node_call(Type, set_affiliation, [Host, Node, JID, Affiliation]), + case Affiliation of + owner -> + NewOwner = jlib:short_prepd_bare_jid(JID), + NewOwners = [NewOwner|Owners], + tree_call(Host, set_node, [N#pubsub_node{owners = NewOwners}]); + none -> + NewOwner = jlib:short_prepd_bare_jid(JID), + case lists:member(OldOwner, Owners) of + true -> + NewOwners = Owners--[OldOwner], + tree_call(Host, set_node, [N#pubsub_node{owners = NewOwners}]); + _ -> + ok + end; + _ -> + ok + end + end, Entities), + {result, []}; + _ -> + {error, 'forbidden'} + end end, transaction(Host, Node, Action, sync_dirty) end. diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index ebb92e112..afc305f86 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -288,7 +288,6 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel, _ -> get_state(Host, Node, SubKey) end, Affiliation = GenState#pubsub_state.affiliation, - Subscription = SubState#pubsub_state.subscription, Whitelisted = lists:member(Affiliation, [member, publisher, owner]), if not Authorized -> @@ -297,7 +296,7 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel, Affiliation == outcast -> %% Requesting entity is blocked {error, 'forbidden'}; - Subscription == pending -> + SubState#pubsub_state.subscription == pending -> %% Requesting entity has pending subscription {error, ?ERR_EXTENDED('not-authorized', "pending-subscription")}; (AccessModel == presence) and (not PresenceSubscription) -> @@ -358,8 +357,6 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> GenKey -> GenState; _ -> get_state(Host, Node, SubKey) end, - Affiliation = GenState#pubsub_state.affiliation, - Subscription = SubState#pubsub_state.subscription, if %% Entity did not specify SubID %%SubID == "", ?? -> @@ -368,10 +365,10 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> %%InvalidSubID -> %% {error, ?ERR_EXTENDED('not-acceptable', "invalid-subid")}; %% Requesting entity is not a subscriber - Subscription == none -> + SubState#pubsub_state.subscription == none -> {error, ?ERR_EXTENDED('unexpected-request', "not-subscribed")}; %% Requesting entity is prohibited from unsubscribing entity - (not Authorized) and (Affiliation =/= owner) -> + not Authorized -> {error, 'forbidden'}; %% Was just subscriber, remove the record SubState#pubsub_state.affiliation == none -> @@ -577,7 +574,12 @@ get_affiliation(Host, Node, Owner) -> set_affiliation(Host, Node, Owner, Affiliation) -> GenKey = jlib:short_prepd_bare_jid(Owner), GenState = get_state(Host, Node, GenKey), - set_state(GenState#pubsub_state{affiliation = Affiliation}), + case {Affiliation, GenState#pubsub_state.subscription} of + {none, none} -> + del_state(GenState#pubsub_state.stateid); + _ -> + set_state(GenState#pubsub_state{affiliation = Affiliation}) + end, ok. %% @spec (Host, Owner) -> [{Node,Subscription}] @@ -614,14 +616,19 @@ get_node_subscriptions(Host, Node) -> {result, lists:map(Tr, States)}. get_subscription(Host, Node, Owner) -> - GenKey = jlib:short_prepd_bare_jid(Owner), - GenState = get_state(Host, Node, GenKey), - {result, GenState#pubsub_state.subscription}. + SubKey = jlib:short_prepd_jid(Owner), + SubState = get_state(Host, Node, SubKey), + {result, SubState#pubsub_state.subscription}. set_subscription(Host, Node, Owner, Subscription) -> - GenKey = jlib:short_prepd_bare_jid(Owner), - GenState = get_state(Host, Node, GenKey), - set_state(GenState#pubsub_state{subscription = Subscription}), + SubKey = jlib:short_prepd_jid(Owner), + SubState = get_state(Host, Node, SubKey), + case {Subscription, SubState#pubsub_state.affiliation} of + {none, none} -> + del_state(SubState#pubsub_state.stateid); + _ -> + set_state(SubState#pubsub_state{subscription = Subscription}) + end, ok. %% @spec (Host, Node) -> [States] | [] From 56bccce713575c6670a8429eb14128e76a3a3045 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Sun, 11 Jan 2009 06:24:42 +0000 Subject: [PATCH 160/582] fix previous fix misplacing (EJAB-840) SVN Revision: 1803 --- src/mod_pubsub/mod_pubsub.erl | 78 ++++++++++++++++----------------- src/mod_pubsub/node_default.erl | 6 +-- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 0ab6b7053..a5063678e 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -1897,18 +1897,33 @@ set_affiliations(Host, Node, From, EntitiesEls) -> {error, 'bad-request'}; _ -> Action = fun(#pubsub_node{type = Type, owners = Owners}) -> - case lists:member(Owner, Owners) of - true -> - lists:foreach( - fun({JID, Affiliation}) -> - node_call( - Type, set_affiliation, - [Host, Node, JID, Affiliation]) - end, Entities), - {result, []}; - _ -> - {error, 'forbidden'} - end + case lists:member(Owner, Owners) of + true -> + lists:foreach( + fun({JID, Affiliation}) -> + node_call(Type, set_affiliation, [Host, Node, JID, Affiliation]), + case Affiliation of + owner -> + NewOwner = jlib:short_prepd_bare_jid(JID), + NewOwners = [NewOwner|Owners], + tree_call(Host, set_node, [N#pubsub_node{owners = NewOwners}]); + none -> + NewOwner = jlib:short_prepd_bare_jid(JID), + case lists:member(OldOwner, Owners) of + true -> + NewOwners = Owners--[OldOwner], + tree_call(Host, set_node, [N#pubsub_node{owners = NewOwners}]); + _ -> + ok + end; + _ -> + ok + end + end, Entities), + {result, []}; + _ -> + {error, 'forbidden'} + end end, transaction(Host, Node, Action, sync_dirty) end. @@ -2031,33 +2046,18 @@ set_subscriptions(Host, Node, From, EntitiesEls) -> {error, 'bad-request'}; _ -> Action = fun(#pubsub_node{type = Type, owners = Owners}) -> - case lists:member(Owner, Owners) of - true -> - lists:foreach( - fun({JID, Affiliation}) -> - node_call(Type, set_affiliation, [Host, Node, JID, Affiliation]), - case Affiliation of - owner -> - NewOwner = jlib:short_prepd_bare_jid(JID), - NewOwners = [NewOwner|Owners], - tree_call(Host, set_node, [N#pubsub_node{owners = NewOwners}]); - none -> - NewOwner = jlib:short_prepd_bare_jid(JID), - case lists:member(OldOwner, Owners) of - true -> - NewOwners = Owners--[OldOwner], - tree_call(Host, set_node, [N#pubsub_node{owners = NewOwners}]); - _ -> - ok - end; - _ -> - ok - end - end, Entities), - {result, []}; - _ -> - {error, 'forbidden'} - end + case lists:member(Owner, Owners) of + true -> + lists:foreach( + fun({JID, Subscription}) -> + node_call( + Type, set_subscription, + [Host, Node, JID, Subscription]) + end, Entities), + {result, []}; + _ -> + {error, 'forbidden'} + end end, transaction(Host, Node, Action, sync_dirty) end. diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index afc305f86..8acf2449d 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -358,6 +358,9 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> _ -> get_state(Host, Node, SubKey) end, if + %% Requesting entity is prohibited from unsubscribing entity + not Authorized -> + {error, 'forbidden'}; %% Entity did not specify SubID %%SubID == "", ?? -> %% {error, ?ERR_EXTENDED('bad-request', "subid-required")}; @@ -367,9 +370,6 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> %% Requesting entity is not a subscriber SubState#pubsub_state.subscription == none -> {error, ?ERR_EXTENDED('unexpected-request', "not-subscribed")}; - %% Requesting entity is prohibited from unsubscribing entity - not Authorized -> - {error, 'forbidden'}; %% Was just subscriber, remove the record SubState#pubsub_state.affiliation == none -> del_state(SubState#pubsub_state.stateid), From 96c0ff44f957b5cc839ea907f1673c12a0a7c60a Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Mon, 12 Jan 2009 15:51:22 +0000 Subject: [PATCH 161/582] Fix typo SVN Revision: 1806 --- ChangeLog | 4 ++++ src/mod_pubsub/mod_pubsub.erl | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index e5a9f1ea0..eac4416f9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-01-11 Pablo Polvorin + + * src/mod_pubsub/mod_pubsub.erl: Fix typo. + 2009-01-11 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: fix owners cache and fix unsubscribe diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index a5063678e..1481e5269 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -1896,7 +1896,7 @@ set_affiliations(Host, Node, From, EntitiesEls) -> error -> {error, 'bad-request'}; _ -> - Action = fun(#pubsub_node{type = Type, owners = Owners}) -> + Action = fun(#pubsub_node{type = Type, owners = Owners}=N) -> case lists:member(Owner, Owners) of true -> lists:foreach( @@ -1908,7 +1908,7 @@ set_affiliations(Host, Node, From, EntitiesEls) -> NewOwners = [NewOwner|Owners], tree_call(Host, set_node, [N#pubsub_node{owners = NewOwners}]); none -> - NewOwner = jlib:short_prepd_bare_jid(JID), + OldOwner = jlib:short_prepd_bare_jid(JID), case lists:member(OldOwner, Owners) of true -> NewOwners = Owners--[OldOwner], From 49210e3099ce0d2cc95b77d065eee09fee2bec2f Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Mon, 12 Jan 2009 18:15:44 +0000 Subject: [PATCH 162/582] Apply commit 1212 (caps handling fix), was incorrectly overwritten on 1770. SVN Revision: 1807 --- ChangeLog | 4 +++ src/ejabberd_c2s.erl | 74 +++++++++++++------------------------------- src/mod_caps.erl | 6 ++-- 3 files changed, 29 insertions(+), 55 deletions(-) diff --git a/ChangeLog b/ChangeLog index eac4416f9..ba619b6ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,10 @@ * src/mod_pubsub/mod_pubsub.erl: Fix typo. + * src/mod_caps.erl, src/ejabberd_c2s.erl: Apply commit + 1212 (caps handling fix), was incorrectly overwritten on + 1770. + 2009-01-11 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: fix owners cache and fix unsubscribe diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 266130320..7e3be2d8e 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -37,8 +37,7 @@ send_element/2, socket_type/0, get_presence/1, - get_subscribed/1, - get_subscribed_and_online/1]). + get_subscribed/1]). %% gen_fsm callbacks -export([init/1, @@ -88,7 +87,6 @@ pres_f = ?SETS:new(), pres_a = ?SETS:new(), pres_i = ?SETS:new(), - pres_available = ?DICT:new(), pres_last, pres_pri, pres_timestamp, pres_invis = false, @@ -212,13 +210,8 @@ init([{SockMod, Socket}, Opts]) -> end. %% Return list of all available resources of contacts, -%% in form [{JID, Caps}]. get_subscribed(FsmRef) -> - gen_fsm:sync_send_all_state_event( - FsmRef, get_subscribed, 1000). -get_subscribed_and_online(FsmRef) -> - gen_fsm:sync_send_all_state_event( - FsmRef, get_subscribed_and_online, 1000). + gen_fsm:sync_send_all_state_event(FsmRef, get_subscribed, 1000). %%---------------------------------------------------------------------- @@ -969,29 +962,9 @@ handle_sync_event({get_presence}, _From, StateName, StateData) -> fsm_reply(Reply, StateName, StateData); handle_sync_event(get_subscribed, _From, StateName, StateData) -> - Subscribed = StateData#state.pres_f, - Online = StateData#state.pres_available, - Pred = fun({U, S, _} = User, _Caps) -> - ?SETS:is_element({U, S, undefined}, - Subscribed) orelse - ?SETS:is_element(User, Subscribed) - end, - SubscribedAndOnline = ?DICT:filter(Pred, Online), - SubscribedWithCaps = ?SETS:fold(fun(User, Acc) -> - [{User, undefined}|Acc] - end, ?DICT:to_list(SubscribedAndOnline), Subscribed), - {reply, SubscribedWithCaps, StateName, StateData}; + Subscribed = ?SETS:to_list(StateData#state.pres_f), + {reply, Subscribed, StateName, StateData}; -handle_sync_event(get_subscribed_and_online, _From, StateName, StateData) -> - Subscribed = StateData#state.pres_f, - Online = StateData#state.pres_available, - Pred = fun({U, S, _R} = User, _Caps) -> - ?SETS:is_element({U, S, undefined}, - Subscribed) orelse - ?SETS:is_element(User, Subscribed) - end, - SubscribedAndOnline = ?DICT:filter(Pred, Online), - {reply, ?DICT:to_list(SubscribedAndOnline), StateName, StateData}; handle_sync_event(_Event, _From, StateName, StateData) -> Reply = ok, @@ -1084,43 +1057,40 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> LBFrom = jlib:short_prepd_bare_jid(From), %% Note contact availability Els = Packet#xmlel.children, - Caps = mod_caps:read_caps(Els), - ServerString = binary_to_list(StateData#state.server), - mod_caps:note_caps(ServerString, From, Caps), - NewAvailable = case exmpp_presence:get_type(Packet) of - 'unavailable' -> - ?DICT:erase(LFrom, StateData#state.pres_available); - _ -> - %?DICT:store(LFrom, Caps, StateData#state.pres_available) - StateData#state.pres_available - end, - NewStateData = StateData#state{pres_available = NewAvailable}, + case exmpp_presence:get_type(Packet) of + 'unavailable' -> + mod_caps:clear_caps(From); + _ -> + ServerString = binary_to_list(StateData#state.server), + Caps = mod_caps:read_caps(Els), + mod_caps:note_caps(ServerString, From, Caps) + end, case ?SETS:is_element( - LFrom, NewStateData#state.pres_a) orelse + LFrom, StateData#state.pres_a) orelse ?SETS:is_element( - LBFrom, NewStateData#state.pres_a) of + LBFrom, StateData#state.pres_a) of true -> - {true, Attrs, NewStateData}; + {true, Attrs, StateData}; false -> case ?SETS:is_element( - LFrom, NewStateData#state.pres_f) of + LFrom, StateData#state.pres_f) of true -> A = ?SETS:add_element( LFrom, - NewStateData#state.pres_a), + StateData#state.pres_a), {true, Attrs, - NewStateData#state{pres_a = A}}; + StateData#state{pres_a = A}}; false -> case ?SETS:is_element( - LBFrom, NewStateData#state.pres_f) of + LBFrom, StateData#state.pres_f) of true -> A = ?SETS:add_element( LBFrom, - NewStateData#state.pres_a), + StateData#state.pres_a), {true, Attrs, - NewStateData#state{pres_a = A}}; + StateData#state{pres_a = A}}; false -> - {true, Attrs, NewStateData} + {true, Attrs, StateData} end end end; diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 4363722d7..9d694c5db 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -96,9 +96,9 @@ get_caps({U, S, R}) -> end. %% clear_caps removes user caps from database -clear_caps({U, S, R}) -> - BJID = exmpp_jid:jid_to_binary(U, S, R), - BUID = exmpp_jid:jid_to_binary(U, S), +clear_caps(JID) -> + BJID = exmpp_jid:jid_to_binary(JID), + BUID = exmpp_jid:bare_jid_to_binary(JID), catch mnesia:dirty_delete({user_caps, BJID}), case catch mnesia:dirty_read({user_caps_default, BUID}) of [#user_caps_default{resource=R}] -> From e8f630b93a8e3b428bda1a000879c43611c26db4 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Mon, 12 Jan 2009 18:17:05 +0000 Subject: [PATCH 163/582] mod_pubsub: initial update to new hooks API (using binaries). mod_pubsub is still unusable with exmpp. SVN Revision: 1809 --- ChangeLog | 4 ++- src/mod_pubsub/mod_pubsub.erl | 49 ++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index ba619b6ce..8ca7fcca7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,8 @@ 2009-01-11 Pablo Polvorin - * src/mod_pubsub/mod_pubsub.erl: Fix typo. + * src/mod_pubsub/mod_pubsub.erl: Fix typo, initial update + to new hooks API (using binaries). mod_pubsub is still + unusable with exmpp. * src/mod_caps.erl, src/ejabberd_c2s.erl: Apply commit 1212 (caps handling fix), was incorrectly overwritten on diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 1481e5269..045cedf8c 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -156,21 +156,21 @@ init([ServerHost, Opts]) -> ?DEBUG("pubsub init ~p ~p",[ServerHost,Opts]), Host = gen_mod:get_opt_host(ServerHost, Opts, "pubsub.@HOST@"), Access = gen_mod:get_opt(access_createnode, Opts, all), + ServerHostB = list_to_binary(ServerHost), mod_disco:register_feature(ServerHost, ?NS_PUBSUB_s), - ejabberd_hooks:add(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75), - ejabberd_hooks:add(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75), - ejabberd_hooks:add(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75), - ejabberd_hooks:add(disco_sm_identity, ServerHost, ?MODULE, disco_sm_identity, 75), - ejabberd_hooks:add(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75), - ejabberd_hooks:add(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75), - ejabberd_hooks:add(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 50), - ejabberd_hooks:add(remove_user, ServerHost, ?MODULE, remove_user, 50), + ejabberd_hooks:add(disco_local_identity, ServerHostB, ?MODULE, disco_local_identity, 75), + ejabberd_hooks:add(disco_local_features, ServerHostB, ?MODULE, disco_local_features, 75), + ejabberd_hooks:add(disco_local_items, ServerHostB, ?MODULE, disco_local_items, 75), + ejabberd_hooks:add(disco_sm_identity, ServerHostB, ?MODULE, disco_sm_identity, 75), + ejabberd_hooks:add(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), + ejabberd_hooks:add(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75), + ejabberd_hooks:add(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50), + ejabberd_hooks:add(remove_user, ServerHostB, ?MODULE, remove_user, 50), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - ServerB = list_to_binary(ServerHost), lists:foreach( fun({NS,Mod,Fun}) -> gen_iq_handler:add_iq_handler( - Mod, ServerB, NS, ?MODULE, Fun, IQDisc) + Mod, ServerHostB, NS, ?MODULE, Fun, IQDisc) end, [{?NS_PUBSUB, ejabberd_local, iq_local}, {?NS_PUBSUB_OWNER, ejabberd_local, iq_local}, @@ -411,8 +411,8 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) -> %% presence hooks handling functions %% -presence_probe(#jid{ldomain = Host} = JID, JID, Pid) -> - Proc = gen_mod:get_module_proc(Host, ?PROCNAME), +presence_probe(JID, JID, Pid) -> + Proc = gen_mod:get_module_proc(exmpp_jid:ldomain_as_list(JID), ?PROCNAME), gen_server:cast(Proc, {presence, JID, Pid}); presence_probe(_, _, _) -> ok. @@ -577,17 +577,17 @@ terminate(_Reason, #state{host = Host, plugins = Plugins}) -> terminate_plugins(Host, ServerHost, Plugins, TreePlugin), ejabberd_router:unregister_route(Host), - ejabberd_hooks:delete(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75), - ejabberd_hooks:delete(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75), - ejabberd_hooks:delete(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75), - ejabberd_hooks:delete(disco_sm_identity, ServerHost, ?MODULE, disco_sm_identity, 75), - ejabberd_hooks:delete(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75), - ejabberd_hooks:delete(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75), - ejabberd_hooks:delete(presence_probe_hook, ServerHost, ?MODULE, presence_probe, 50), - ejabberd_hooks:delete(remove_user, ServerHost, ?MODULE, remove_user, 50), - ServerB = list_to_binary(ServerHost), + ServerHostB = list_to_binary(ServerHost), + ejabberd_hooks:delete(disco_local_identity, ServerHostB, ?MODULE, disco_local_identity, 75), + ejabberd_hooks:delete(disco_local_features, ServerHostB, ?MODULE, disco_local_features, 75), + ejabberd_hooks:delete(disco_local_items, ServerHostB, ?MODULE, disco_local_items, 75), + ejabberd_hooks:delete(disco_sm_identity, ServerHostB, ?MODULE, disco_sm_identity, 75), + ejabberd_hooks:delete(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), + ejabberd_hooks:delete(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75), + ejabberd_hooks:delete(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50), + ejabberd_hooks:delete(remove_user, ServerHostB, ?MODULE, remove_user, 50), lists:foreach(fun({NS,Mod}) -> - gen_iq_handler:remove_iq_handler(Mod, ServerB, NS) + gen_iq_handler:remove_iq_handler(Mod, ServerHostB, NS) end, [{?NS_PUBSUB, ejabberd_local}, {?NS_PUBSUB_OWNER, ejabberd_local}, {?NS_PUBSUB, ejabberd_sm}, @@ -2660,8 +2660,9 @@ set_xoption([_ | Opts], NewOpts) -> %%%% plugin handling -plugins(Host) -> - case ets:lookup(gen_mod:get_module_proc(Host, pubsub_state), plugins) of +plugins(Host) when is_binary(Host) -> + HostL = binary_to_list(Host), + case ets:lookup(gen_mod:get_module_proc(HostL, pubsub_state), plugins) of [{plugins, PL}] -> PL; _ -> [?STDNODE] end. From 2538001b087d38fd82cbff90239a56ff46661ec1 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Thu, 15 Jan 2009 15:21:54 +0000 Subject: [PATCH 164/582] Store registered nicknames, rooms and domains as binary(). Use document_to_iolist/1 and iolist_size/1 instead of document_to_list/1. SVN Revision: 1820 --- ChangeLog | 7 ++++++ src/mod_muc/mod_muc.erl | 49 ++++++++++++++++++------------------ src/mod_muc/mod_muc_room.erl | 48 +++++++++++++++++++---------------- 3 files changed, 58 insertions(+), 46 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8ca7fcca7..e1dea738f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-01-15 Pablo Polvorin + + * src/mod_muc/mod_muc.erl, src/mod_muc/mod_muc_room.erl: + Store registered nicknames, rooms and domains as binary(). + Use document_to_iolist/1 and iolist_size/1 instead of + document_to_list/1. + 2009-01-11 Pablo Polvorin * src/mod_pubsub/mod_pubsub.erl: Fix typo, initial update diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index 2f9f594ac..e1768fc38 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -125,7 +125,7 @@ forget_room(Host, Name) when is_binary(Host), is_binary(Name) -> end, mnesia:transaction(F). -process_iq_disco_items(Host, From, To, #iq{} = IQ) -> +process_iq_disco_items(Host, From, To, #iq{} = IQ) when is_binary(Host) -> Lang = exmpp_stanza:get_lang(IQ), Res = exmpp_iq:result(IQ, #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', @@ -134,10 +134,10 @@ process_iq_disco_items(Host, From, To, #iq{} = IQ) -> From, exmpp_iq:iq_to_xmlel(Res)). -can_use_nick(_Host, _JID, "") -> +can_use_nick(_Host, _JID, <<>>) -> false; -can_use_nick(Host, JID, Nick) -> - LUS = {exmpp_jid:lnode_as_list(JID), exmpp_jid:ldomain_as_list(JID)}, +can_use_nick(Host, JID, Nick) when is_binary(Host), is_binary(Nick) -> + LUS = {exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID)}, case catch mnesia:dirty_select( muc_registered, [{#muc_registered{us_host = '$1', @@ -176,7 +176,8 @@ init([Host, Opts]) -> {attributes, record_info(fields, muc_online_room)}]), mnesia:add_table_copy(muc_online_room, node(), ram_copies), catch ets:new(muc_online_users, [bag, named_table, public, {keypos, 2}]), - MyHost = gen_mod:get_opt_host(Host, Opts, "conference.@HOST@"), + MyHost_L = gen_mod:get_opt_host(Host, Opts, "conference.@HOST@"), + MyHost = list_to_binary(MyHost_L), update_tables(MyHost), clean_table_from_bad_node(node(), MyHost), mnesia:add_table_index(muc_registered, nick), @@ -188,7 +189,7 @@ init([Host, Opts]) -> HistorySize = gen_mod:get_opt(history_size, Opts, 20), DefRoomOpts = gen_mod:get_opt(default_room_options, Opts, []), RoomShaper = gen_mod:get_opt(room_shaper, Opts, none), - ejabberd_router:register_route(MyHost), + ejabberd_router:register_route(MyHost_L), load_permanent_rooms(MyHost, Host, {Access, AccessCreate, AccessAdmin, AccessPersistent}, HistorySize, @@ -313,8 +314,8 @@ do_route(Host, ServerHost, Access, HistorySize, RoomShaper, do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, From, To, Packet, DefRoomOpts) -> {_AccessRoute, AccessCreate, AccessAdmin, _AccessPersistent} = Access, - Room = exmpp_jid:lnode_as_list(To), - Nick = exmpp_jid:lresource_as_list(To), + Room = exmpp_jid:lnode(To), + Nick = exmpp_jid:lresource(To), #xmlel{name = Name} = Packet, case Room of 'undefined' -> @@ -484,7 +485,7 @@ load_permanent_rooms(Host, ServerHost, Access, HistorySize, RoomShaper) -> end, Rs) end. -register_room(Host, Room, Pid) -> +register_room(Host, Room, Pid) when is_binary(Host), is_binary(Room) -> F = fun() -> mnesia:write(#muc_online_room{name_host = {Room, Host}, pid = Pid}) @@ -518,7 +519,7 @@ iq_disco_info(Lang) -> -iq_disco_items(Host, From, Lang) -> +iq_disco_items(Host, From, Lang) when is_binary(Host) -> lists:zf(fun(#muc_online_room{name_host = {Name, _Host}, pid = Pid}) -> case catch gen_fsm:sync_send_all_state_event( Pid, {get_disco_item, From, Lang}, 100) of @@ -527,9 +528,9 @@ iq_disco_items(Host, From, Lang) -> {true, #xmlel{name = 'item', attrs = [#xmlattr{name = 'jid', - value = exmpp_jid:jid_to_list(Name, + value = exmpp_jid:jid_to_binary(Name, Host, - "")}, + <<>>)}, #xmlattr{name = 'name', value = Desc}]}}; _ -> @@ -554,9 +555,9 @@ flush() -> children = [#xmlel{name = 'value', children = [#xmlcdata{cdata = Val}]}]}). -iq_get_register_info(Host, From, Lang) -> - LUser = exmpp_jid:lnode_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), +iq_get_register_info(Host, From, Lang) -> + LUser = exmpp_jid:lnode(From), + LServer = exmpp_jid:ldomain(From), LUS = {LUser, LServer}, {Nick, Registered} = case catch mnesia:dirty_read(muc_registered, {LUS, Host}) of @@ -576,21 +577,21 @@ iq_get_register_info(Host, From, Lang) -> children = [ #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = - translate:translate(Lang, "Nickname Registration at ") ++ Host}]}, + [translate:translate(Lang, "Nickname Registration at "), Host]}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = [#xmlcdata{cdata = translate:translate(Lang, "Enter nickname you want to register")}]}, - ?XFIELD("text-single", "Nickname", "nick", Nick)]}]. + ?XFIELD(<<"text-single">>, "Nickname", <<"nick">>, Nick)]}]. -iq_set_register_info(Host, From, Nick, Lang) -> - LUser = exmpp_jid:lnode_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), +iq_set_register_info(Host, From, Nick, Lang) when is_binary(Host), is_binary(Nick) -> + LUser = exmpp_jid:lnode(From), + LServer = exmpp_jid:ldomain(From), LUS = {LUser, LServer}, F = fun() -> case Nick of - "" -> + <<>> -> mnesia:delete({muc_registered, {LUS, Host}}), ok; _ -> @@ -654,7 +655,7 @@ process_iq_register_set(Host, From, SubEl, Lang) -> {Lang, translate:translate(Lang,ErrText)}), {error, Err}; {value, {_, [Nick]}} -> - iq_set_register_info(Host, From, Nick, Lang) + iq_set_register_info(Host, From, list_to_binary(Nick), Lang) end end; _ -> @@ -664,7 +665,7 @@ process_iq_register_set(Host, From, SubEl, Lang) -> {error, 'bad-request'} end; _ -> - iq_set_register_info(Host, From, "", Lang) + iq_set_register_info(Host, From, <<>>, Lang) end. iq_get_vcard(Lang) -> @@ -687,7 +688,7 @@ broadcast_service_message(Host, Msg) -> Pid, {service_message, Msg}) end, get_vh_rooms(Host)). -get_vh_rooms(Host) -> +get_vh_rooms(Host) when is_binary(Host) -> mnesia:dirty_select(muc_online_room, [{#muc_online_room{name_host = '$1', _ = '_'}, [{'==', {element, 2, '$1'}, Host}], diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index d6db806af..e14a871ba 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -117,7 +117,9 @@ start_link(Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts) -> %% ignore | %% {stop, StopReason} %%---------------------------------------------------------------------- -init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Creator, _Nick, DefRoomOpts]) -> +init([HostB, ServerHost, Access, RoomB, HistorySize, RoomShaper, Creator, _Nick, DefRoomOpts]) -> + Host = binary_to_list(HostB), + Room = binary_to_list(RoomB), process_flag(trap_exit, true), Shaper = shaper:new(RoomShaper), State = set_affiliation(Creator, owner, @@ -133,7 +135,9 @@ init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Creator, _Nick, D ?INFO_MSG("Created MUC room ~s@~s by ~s", [Room, Host, exmpp_jid:jid_to_list(Creator)]), {ok, normal_state, State1}; -init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts]) -> +init([HostB, ServerHost, Access, RoomB, HistorySize, RoomShaper, Opts]) -> + Host = binary_to_list(HostB), + Room = binary_to_list(RoomB), process_flag(trap_exit, true), Shaper = shaper:new(RoomShaper), State = set_opts(Opts, #state{host = Host, @@ -166,7 +170,7 @@ normal_state({route, From, undefined, trunc(gen_mod:get_module_opt( StateData#state.server_host, mod_muc, min_message_interval, 0) * 1000000), - Size = lists:flatlength(exmpp_xml:document_to_list(Packet)), + Size = erlang:iolist_size(exmpp_xml:document_to_binary(Packet)), {MessageShaper, MessageShaperInterval} = shaper:update(Activity#activity.message_shaper, Size), if @@ -720,7 +724,7 @@ terminate(_Reason, _StateName, StateData) -> fun(J, _, _) -> tab_remove_online_user(J, StateData) end, [], StateData#state.users), - mod_muc:room_destroyed(StateData#state.host, StateData#state.room, self(), + mod_muc:room_destroyed(list_to_binary(StateData#state.host), list_to_binary(StateData#state.room), self(), StateData#state.server_host), ok. @@ -892,7 +896,7 @@ process_presence(From, Nick, #xmlel{name = 'presence'} = Packet, true -> case {is_nick_exists(Nick, StateData), mod_muc:can_use_nick( - StateData#state.host, From, Nick), + list_to_binary(StateData#state.host), From, Nick), {(StateData#state.config)#config.allow_visitor_nickchange, is_visitor(From, StateData)}} of {_, _, {false, true}} -> @@ -1323,7 +1327,7 @@ prepare_room_queue(StateData) -> {{value, {message, From}}, _RoomQueue} -> Activity = get_user_activity(From, StateData), Packet = Activity#activity.message, - Size = lists:flatlength(exmpp_xml:documenent_to_list(Packet)), + Size = erlang:iolist_size(exmpp_xml:documenent_to_iolist(Packet)), {RoomShaper, RoomShaperInterval} = shaper:update(StateData#state.room_shaper, Size), erlang:send_after( @@ -1334,7 +1338,7 @@ prepare_room_queue(StateData) -> {{value, {presence, From}}, _RoomQueue} -> Activity = get_user_activity(From, StateData), {_Nick, Packet} = Activity#activity.presence, - Size = lists:flatlength(exmpp_xml:document_to_list(Packet)), + Size = erlang:iolist_size(exmpp_xml:document_to_iolist(Packet)), {RoomShaper, RoomShaperInterval} = shaper:update(StateData#state.room_shaper, Size), erlang:send_after( @@ -1461,7 +1465,7 @@ add_new_user(From, Nick, Packet, StateData) -> NUsers < MaxUsers) andalso NConferences < MaxConferences, is_nick_exists(Nick, StateData), - mod_muc:can_use_nick(StateData#state.host, From, Nick), + mod_muc:can_use_nick(list_to_binary(StateData#state.host), From, Nick), get_default_role(Affiliation, StateData)} of {false, _, _, _} -> % max user reached and user is not admin or owner @@ -1766,7 +1770,7 @@ send_new_presence(NJID, Reason, StateData) -> case (Info#user.role == moderator) orelse ((StateData#state.config)#config.anonymous == false) of true -> - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(RealJID)}, + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(RealJID)}, #xmlattr{name = 'affiliation', value = SAffiliation}, #xmlattr{name = 'role', value = SRole}]; _ -> @@ -1822,7 +1826,7 @@ send_existing_presences(ToJID, StateData) -> ((StateData#state.config)#config.anonymous == false) of true -> - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(FromJID)}, + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(FromJID)}, #xmlattr{name = 'affiliation', value = affiliation_to_binary(FromAffiliation)}, #xmlattr{name = 'role', value = role_to_binary(FromRole)}]; @@ -1879,7 +1883,7 @@ send_nick_changing(JID, OldNick, StateData) -> case (Info#user.role == moderator) orelse ((StateData#state.config)#config.anonymous == false) of true -> - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(RealJID)}, + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(RealJID)}, #xmlattr{name = 'affiliation', value = SAffiliation}, #xmlattr{name = 'role', value = SRole}, #xmlattr{name = 'nick', value = Nick}]; @@ -1892,7 +1896,7 @@ send_nick_changing(JID, OldNick, StateData) -> case (Info#user.role == moderator) orelse ((StateData#state.config)#config.anonymous == false) of true -> - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(RealJID)}, + [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(RealJID)}, #xmlattr{name = 'affiliation', value = SAffiliation}, #xmlattr{name = 'role', value = SRole}]; _ -> @@ -1902,7 +1906,7 @@ send_nick_changing(JID, OldNick, StateData) -> Packet1 = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', - attrs = [#xmlattr{name = 'type', value = "unavailable"}], + attrs = [#xmlattr{name = 'type', value = <<"unavailable">>}], children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [ #xmlel{ns = ?NS_MUC_USER, name = 'item', @@ -1968,7 +1972,7 @@ add_message_to_history(FromNick, Packet, StateData) -> jid_replace_resource(StateData#state.jid, FromNick)), StateData#state.jid), - Size = lists:flatlength(exmpp_xml:document_to_list(SPacket)), + Size = erlang:iolist_size(exmpp_xml:document_to_iolist(SPacket)), Q1 = lqueue_in({FromNick, TSPacket, HaveSubject, TimeStamp, Size}, StateData#state.history), add_to_log(text, {FromNick, Packet}, StateData), @@ -3183,9 +3187,9 @@ process_iq_disco_items(From, get, _Lang, StateData) -> fun({_LJID, Info}) -> Nick = Info#user.nick, #xmlel{name = 'item', attrs = [#xmlattr{name = 'jid', - value = exmpp_jid:jid_to_list( - StateData#state.room, - StateData#state.host, + value = exmpp_jid:jid_to_binary( + list_to_binary(StateData#state.room), + list_to_binary(StateData#state.host), Nick)}, #xmlattr{name = 'name', value = Nick}]} @@ -3254,7 +3258,7 @@ check_invitation(From, Els, Lang, StateData) -> [#xmlel{ns = ?NS_MUC_USER, name = 'invite', attrs = [#xmlattr{name = 'from', - value = exmpp_jid:jid_to_list(From)}], + value = exmpp_jid:jid_to_binary(From)}], children = [#xmlel{ns =?NS_MUC_USER, name = 'reason', children = [#xmlcdata{cdata = Reason} ]}] ++ ContinueEl}], @@ -3274,8 +3278,8 @@ check_invitation(From, Els, Lang, StateData) -> io_lib:format( translate:translate(Lang, "~s invites you to the room ~s"), - [exmpp_jid:jid_to_list(From), - exmpp_jid:jid_to_list(StateData#state.room, + [exmpp_jid:jid_to_binary(From), + exmpp_jid:jid_to_binary(StateData#state.room, StateData#state.host, "") ]), @@ -3301,7 +3305,7 @@ check_invitation(From, Els, Lang, StateData) -> children = IEl ++ PasswdEl}, #xmlel{ns = 'jabber:x:conference', name = 'x', attrs = [#xmlattr{name = 'jid', - value = exmpp_jid:jid_to_list( + value = exmpp_jid:jid_to_binary( StateData#state.room, StateData#state.host, "")}], @@ -3338,7 +3342,7 @@ check_decline_invitation(Packet) -> %% The original stanza must be slightly modified. send_decline_invitation({Packet, XEl, DEl = #xmlel{name='decline'}, ToJID}, RoomJID, FromJID) -> - FromString = exmpp_jid:jid_to_list(FromJID), + FromString = exmpp_jid:jid_to_binary(FromJID), DEl1 = exmpp_xml:remove_attribute(DEl, 'to'), DEl2 = exmpp_xml:set_attribute(DEl1, 'from',FromString), From 04f6a2be37cb2882047bff356dba535029689c30 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Thu, 15 Jan 2009 19:41:06 +0000 Subject: [PATCH 165/582] Store host and room name as binary(). Use jid_to_binary() instead of jid_to_list(). SVN Revision: 1821 --- src/mod_muc/mod_muc.erl | 3 +- src/mod_muc/mod_muc_room.erl | 57 ++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 33 deletions(-) diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index e1768fc38..55cf0008c 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -529,8 +529,7 @@ iq_disco_items(Host, From, Lang) when is_binary(Host) -> #xmlel{name = 'item', attrs = [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(Name, - Host, - <<>>)}, + Host)}, #xmlattr{name = 'name', value = Desc}]}}; _ -> diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index e14a871ba..ccd3c9db0 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -117,9 +117,7 @@ start_link(Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts) -> %% ignore | %% {stop, StopReason} %%---------------------------------------------------------------------- -init([HostB, ServerHost, Access, RoomB, HistorySize, RoomShaper, Creator, _Nick, DefRoomOpts]) -> - Host = binary_to_list(HostB), - Room = binary_to_list(RoomB), +init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Creator, _Nick, DefRoomOpts]) -> process_flag(trap_exit, true), Shaper = shaper:new(RoomShaper), State = set_affiliation(Creator, owner, @@ -133,11 +131,9 @@ init([HostB, ServerHost, Access, RoomB, HistorySize, RoomShaper, Creator, _Nick, room_shaper = Shaper}), State1 = set_opts(DefRoomOpts, State), ?INFO_MSG("Created MUC room ~s@~s by ~s", - [Room, Host, exmpp_jid:jid_to_list(Creator)]), + [Room, Host, exmpp_jid:jid_to_binary(Creator)]), {ok, normal_state, State1}; -init([HostB, ServerHost, Access, RoomB, HistorySize, RoomShaper, Opts]) -> - Host = binary_to_list(HostB), - Room = binary_to_list(RoomB), +init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts]) -> process_flag(trap_exit, true), Shaper = shaper:new(RoomShaper), State = set_opts(Opts, #state{host = Host, @@ -170,7 +166,7 @@ normal_state({route, From, undefined, trunc(gen_mod:get_module_opt( StateData#state.server_host, mod_muc, min_message_interval, 0) * 1000000), - Size = erlang:iolist_size(exmpp_xml:document_to_binary(Packet)), + Size = erlang:iolist_size(exmpp_xml:document_to_iolist(Packet)), {MessageShaper, MessageShaperInterval} = shaper:update(Activity#activity.message_shaper, Size), if @@ -585,11 +581,11 @@ handle_event({destroy, Reason}, _StateName, StateData) -> end}, StateData), ?INFO_MSG("Destroyed MUC room ~s with reason: ~p", - [exmpp_jid:jid_to_list(StateData#state.jid), Reason]), + [exmpp_jid:jid_to_binary(StateData#state.jid), Reason]), {stop, normal, StateData}; handle_event(destroy, StateName, StateData) -> ?INFO_MSG("Destroyed MUC room ~s", - [exmpp_jid:jid_to_list(StateData#state.jid)]), + [exmpp_jid:jid_to_binary(StateData#state.jid)]), handle_event({destroy, none}, StateName, StateData); handle_event({set_affiliations, Affiliations}, StateName, StateData) -> @@ -633,7 +629,7 @@ handle_sync_event({get_disco_item, JID, Lang}, _From, StateName, StateData) -> (FAffiliation == admin) orelse (FAffiliation == owner) of true -> - {item, get_title(StateData) ++ Tail}; + {item, list_to_binary([get_title(StateData), Tail])}; _ -> false end, @@ -724,7 +720,7 @@ terminate(_Reason, _StateName, StateData) -> fun(J, _, _) -> tab_remove_online_user(J, StateData) end, [], StateData#state.users), - mod_muc:room_destroyed(list_to_binary(StateData#state.host), list_to_binary(StateData#state.room), self(), + mod_muc:room_destroyed(StateData#state.host, StateData#state.room, self(), StateData#state.server_host), ok. @@ -855,7 +851,7 @@ get_participant_data(From, StateData) -> {ok, #user{nick = FromNick, role = Role}} -> {FromNick, Role}; error -> - {"", moderator} + {<<>>, moderator} end. @@ -896,7 +892,7 @@ process_presence(From, Nick, #xmlel{name = 'presence'} = Packet, true -> case {is_nick_exists(Nick, StateData), mod_muc:can_use_nick( - list_to_binary(StateData#state.host), From, Nick), + StateData#state.host, From, Nick), {(StateData#state.config)#config.allow_visitor_nickchange, is_visitor(From, StateData)}} of {_, _, {false, true}} -> @@ -960,7 +956,7 @@ process_presence(From, Nick, #xmlel{name = 'presence'} = Packet, (?DICT:to_list(StateData1#state.users) == []) of true -> ?INFO_MSG("Destroyed MUC room ~s because it's temporary and empty", - [exmpp_jid:jid_to_list(StateData#state.jid)]), + [exmpp_jid:jid_to_binary(StateData#state.jid)]), {stop, normal, StateData1}; _ -> {next_state, normal_state, StateData1} @@ -1012,7 +1008,7 @@ decide_fate_message(error, Packet, From, StateData) -> %% If this is an error stanza and its condition matches a criteria true -> Reason = io_lib:format("This participant is considered a ghost and is expulsed: ~s", - [exmpp_jid:jid_to_list(From)]), + [exmpp_jid:jid_to_binary(From)]), {expulse_sender, Reason}; false -> continue_delivery @@ -1438,7 +1434,7 @@ find_jid_by_nick(Nick, StateData) -> is_nick_change(JID, Nick, StateData) -> LJID = jlib:short_prepd_jid(JID), case Nick of - "" -> + <<>> -> false; _ -> {ok, #user{nick = OldNick}} = @@ -1465,7 +1461,7 @@ add_new_user(From, Nick, Packet, StateData) -> NUsers < MaxUsers) andalso NConferences < MaxConferences, is_nick_exists(Nick, StateData), - mod_muc:can_use_nick(list_to_binary(StateData#state.host), From, Nick), + mod_muc:can_use_nick(StateData#state.host, From, Nick), get_default_role(Affiliation, StateData)} of {false, _, _, _} -> % max user reached and user is not admin or owner @@ -1725,7 +1721,7 @@ extract_history([_ | Els], Type) -> send_update_presence(JID, StateData) -> - send_update_presence(JID, "", StateData). + send_update_presence(JID, <<>>, StateData). send_update_presence(JID, Reason, StateData) -> LJID = jlib:short_prepd_jid(JID), @@ -1753,7 +1749,7 @@ send_update_presence(JID, Reason, StateData) -> end, LJIDs). send_new_presence(NJID, StateData) -> - send_new_presence(NJID, "", StateData). + send_new_presence(NJID, <<>>, StateData). send_new_presence(NJID, Reason, StateData) -> {ok, #user{jid = RealJID, @@ -1778,7 +1774,7 @@ send_new_presence(NJID, Reason, StateData) -> #xmlattr{name = 'role', value = SRole}] end, ItemEls = case Reason of - "" -> + <<>> -> []; _ -> [#xmlel{name = 'reason', @@ -1991,7 +1987,7 @@ send_history(JID, Shift, StateData) -> send_subject(JID, Lang, StateData) -> case StateData#state.subject_author of - "" -> + <<>> -> ok; Nick -> Subject = StateData#state.subject, @@ -2138,7 +2134,7 @@ process_admin_items_set(UJID, Items, Lang, StateData) -> case find_changed_items(UJID, UAffiliation, URole, Items, Lang, StateData, []) of {result, Res} -> ?INFO_MSG("Processing MUC admin query from ~s in room ~s:~n ~p", - [exmpp_jid:jid_to_list(UJID), exmpp_jid:jid_to_list(StateData#state.jid), Res]), + [exmpp_jid:jid_to_binary(UJID), exmpp_jid:jid_to_binary(StateData#state.jid), Res]), NSD = lists:foldl( fun(E, SD) -> @@ -2625,7 +2621,7 @@ process_iq_owner(From, set, Lang, SubEl, StateData) -> end; [#xmlel{name = 'destroy'} = SubEl1] -> ?INFO_MSG("Destroyed MUC room ~s by the owner ~s", - [exmpp_jid:jid_to_list(StateData#state.jid), exmpp_jid:jid_to_list(From)]), + [exmpp_jid:jid_to_binary(StateData#state.jid), exmpp_jid:jid_to_binary(From)]), destroy_room(SubEl1, StateData); Items -> process_admin_items_set(From, Items, Lang, StateData) @@ -3188,8 +3184,8 @@ process_iq_disco_items(From, get, _Lang, StateData) -> Nick = Info#user.nick, #xmlel{name = 'item', attrs = [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary( - list_to_binary(StateData#state.room), - list_to_binary(StateData#state.host), + StateData#state.room, + StateData#state.host, Nick)}, #xmlattr{name = 'name', value = Nick}]} @@ -3203,7 +3199,7 @@ process_iq_disco_items(From, get, _Lang, StateData) -> get_title(StateData) -> case (StateData#state.config)#config.title of "" -> - StateData#state.room; + binary_to_list(StateData#state.room); Name -> Name end. @@ -3280,8 +3276,7 @@ check_invitation(From, Els, Lang, StateData) -> "~s invites you to the room ~s"), [exmpp_jid:jid_to_binary(From), exmpp_jid:jid_to_binary(StateData#state.room, - StateData#state.host, - "") + StateData#state.host) ]), case (StateData#state.config)#config.password_protected of true -> @@ -3307,8 +3302,8 @@ check_invitation(From, Els, Lang, StateData) -> attrs = [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary( StateData#state.room, - StateData#state.host, - "")}], + StateData#state.host) + }], children = [#xmlcdata{cdata = Reason}]}, Body]}, ejabberd_router:route(StateData#state.jid, JID, Msg), From 2cc2039ad823912112124b438101796d83eef39c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 19 Jan 2009 10:14:04 +0000 Subject: [PATCH 166/582] Merge from trunk (r1734 to r1752). Note: this merge doesn't include the following revisions because it was made by previous commits: r1737, r1740, r1745, r1747, r1748. Additionnaly, any deprecated content was removed from jlib.hrl. This leaves only the new RSM records. Warning: Ejabberd may be broken until the merge is completly finished. PR: EJABP-1 SVN Revision: 1824 --- ChangeLog | 140 +++++++++++----- doc/guide.tex | 8 + src/acl.erl | 4 + src/cyrsasl_digest.erl | 70 +++++--- src/ejabberd_auth.erl | 42 ++++- src/ejabberd_auth_internal.erl | 13 +- src/ejabberd_auth_ldap.erl | 1 + src/ejabberd_auth_odbc.erl | 11 +- src/ejabberd_auth_pam.erl | 2 +- src/ejabberd_config.erl | 7 +- src/jlib.erl | 69 ++++++++ src/jlib.hrl | 289 +-------------------------------- src/mod_last.erl | 35 +++- src/mod_last_odbc.erl | 33 +++- src/mod_muc/mod_muc.erl | 80 ++++++++- src/mod_privacy.erl | 16 +- src/mod_privacy_odbc.erl | 24 +++ src/mod_pubsub/node.template | 1 - src/mod_register.erl | 2 - src/mod_shared_roster.erl | 109 +++++++++++-- src/odbc/odbc_queries.erl | 2 +- 21 files changed, 551 insertions(+), 407 deletions(-) diff --git a/ChangeLog b/ChangeLog index e1dea738f..bb509b737 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,11 +1,22 @@ -2009-01-15 Pablo Polvorin +2009-01-16 Jean-Sébastien Pédron + + Merge from trunk (r1734 to r1752). + + Note: this merge doesn't include the following revisions because it + was made by previous commits: + r1737, r1740, r1745, r1747, r1748. + + * src/jlib.hrl: Any deprecated content was removed from jlib.hrl. This + leaves only the new RSM records. + +2009-01-15 Pablo Polvorin * src/mod_muc/mod_muc.erl, src/mod_muc/mod_muc_room.erl: Store registered nicknames, rooms and domains as binary(). Use document_to_iolist/1 and iolist_size/1 instead of document_to_list/1. -2009-01-11 Pablo Polvorin +2009-01-11 Pablo Polvorin * src/mod_pubsub/mod_pubsub.erl: Fix typo, initial update to new hooks API (using binaries). mod_pubsub is still @@ -21,42 +32,42 @@ permissions (thanks to Andy Skelton)(EJAB-840) * src/mod_pubsub/node_default.erl: Likewise -2009-01-10 Pablo Polvorin +2009-01-10 Pablo Polvorin * src/mod_vcard_odbc.erl: Fix bug in user search. * src/mod_vcard_ldap.erl, src/mod_vcard.erl, src/mod_configure.erl, src/ejabberd_sm.erl, src/mod_privacy_odbc.erl, src/ejabberd_c2s.erl, src/ejabberd_local.erl, src/mod_privacy.erl, src/mod_adhoc.erl, - src/mod_pubsub/mod_pubsub.erl, src/mod_vcard_odbc.erl, src/mod_stats.erl, - src/mod_last.erl, src/mod_private.erl, src/mod_roster.erl, - src/mod_disco.erl, src/mod_private_odbc.erl, src/mod_configure2.erl, - src/mod_roster_odbc.erl, src/mod_register.erl, src/mod_version.erl, - src/mod_caps.erl, src/mod_last_odbc.erl, src/mod_time.erl: Update - gen_iq_handler API, require the 'Host' argument to be in binary() format. + src/mod_pubsub/mod_pubsub.erl, src/mod_vcard_odbc.erl, + src/mod_stats.erl, src/mod_last.erl, src/mod_private.erl, + src/mod_roster.erl, src/mod_disco.erl, src/mod_private_odbc.erl, + src/mod_configure2.erl, src/mod_roster_odbc.erl, src/mod_register.erl, + src/mod_version.erl, src/mod_caps.erl, src/mod_last_odbc.erl, + src/mod_time.erl: Update gen_iq_handler API, require the 'Host' + argument to be in binary() format. 2009-01-10 Christophe Romain * src/mod_pubsub/node_default.erl: fix unsubscription of full jid subscribed node (thanks to Andy Skelton)(EJAB-839) -2009-01-09 Pablo Polvorin +2009-01-09 Pablo Polvorin * src/mod_muc/mod_muc_room.erl, src/mod_muc/mod_muc.erl src/mod_offline_odbc.erl, src/mod_irc/mod_irc_connection.erl, src/mod_irc/mod_irc.erl, src/ejabberd_c2s.erl, src/ejabberd_local.erl, - src/mod_pubsub/mod_pubsub.erl, src/ejabberd_s2s.erl, src/mod_roster.erl, - src/mod_roster_odbc.erl, src/ejabberd_s2s_out.erl, src/mod_offline.erl, - src/translate.erl: Adapt to new exmpp API where get_id/1, get_lang/1, - get_initiating_entity/1, get_receiving_entity/1 and get_type/1 - returns binary(). + src/mod_pubsub/mod_pubsub.erl, src/ejabberd_s2s.erl, + src/mod_roster.erl, src/mod_roster_odbc.erl, src/ejabberd_s2s_out.erl, + src/mod_offline.erl, src/translate.erl: Adapt to new exmpp API where + get_id/1, get_lang/1, get_initiating_entity/1, get_receiving_entity/1 + and get_type/1 return binary(). * src/mod_pubsub/node_default.erl: Fix typo in variable name. * src/ejabberd_c2s.erl: Fix bug in handle_info/3 when dealing with VCARD requests: convert to IQ struct before invoking gen_iq_handler. - 2009-01-08 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: completely support subscription using @@ -77,35 +88,39 @@ * src/mod_pubsub/node_default.erl: Likewise * src/mod_pubsub/node_club.erl: Likewise -2009-01-08 Pablo Polvorin +2009-01-08 Pablo Polvorin + * src/mod_vcard_ldap.erl, src/mod_muc/mod_muc.erl, src/mod_roster.hrl, src/mod_offline_odbc.erl, src/ejabberd_s2s_in.erl, src/adhoc.erl, src/mod_configure.erl, src/mod_irc/mod_irc_connection.erl, - src/mod_irc/mod_irc.erl, src/web/ejabberd_http_poll.erl, + src/mod_irc/mod_irc.erl, src/web/ejabberd_http_poll.erl, src/mod_privacy_odbc.erl, src/ejabberd_c2s.erl, src/mod_announce.erl, src/mod_privacy.erl, src/mod_adhoc.erl, src/mod_pubsub/mod_pubsub.erl, src/mod_vcard_odbc.erl, src/mod_stats.erl, src/mod_last.erl, src/mod_roster.erl, src/ejabberd_service.erl, src/mod_disco.erl, - src/mod_configure2.erl, src/mod_roster_odbc.erl, src/ejabberd_s2s_out.erl, - src/mod_last_odbc.erl: XML attributes as binary(). Change Node argument - to binary in the following hooks: disco_local_items, disco_local_features, - disco_local_identity, disco_sm_items and disco_sm_identity. - + src/mod_configure2.erl, src/mod_roster_odbc.erl, + src/ejabberd_s2s_out.erl, src/mod_last_odbc.erl: XML attributes as + binary(). Change Node argument to binary in the following hooks: + disco_local_items, disco_local_features, disco_local_identity, + disco_sm_items and disco_sm_identity. 2009-01-05 Pablo Polvorin + * src/mod_roster.erl: Fix typo. -2009-01-03 Pablo Polvorin - * src/mod_pubsub_node_default.erl: Fix typo +2009-01-03 Pablo Polvorin - * src/mod_vcard.erl, src/mod_vcard_ldap.erl,src/ ejabberd_hooks.erl, - mod_muc/mod_muc_room.erl, src/mod_muc/mod_muc.erl, + * src/mod_pubsub_node_default.erl: Fix typo. + + * src/mod_vcard.erl, src/mod_vcard_ldap.erl, src/ejabberd_hooks.erl, + src/mod_muc/mod_muc_room.erl, src/mod_muc/mod_muc.erl, src/mod_muc/mod_muc_log.erl, src/mod_shared_roster.erl, src/ejabberd_auth_odbc.erl, src/mod_offline_odbc.erl, - src/ejabberd_system_monitor.erl, src/ejabberd_s2s_in.erl, - src/mod_configure.erl, src/ejabberd_receiver.erl, src/mod_irc/mod_irc.erl, - src/ejabberd_sm.erl, src/mod_privacy_odbc.erl, src/ejabberd_c2s.erl, - src/mod_announce.erl, src/ejabberd_local.erl, src/mod_privacy.erl, + src/ejabberd_system_monitor.erl, src/ejabberd_s2s_in.erl, + src/mod_configure.erl, src/ejabberd_receiver.erl, + src/mod_irc/mod_irc.erl, src/ejabberd_sm.erl, + src/mod_privacy_odbc.erl, src/ejabberd_c2s.erl, src/mod_announce.erl, + src/ejabberd_local.erl, src/mod_privacy.erl, src/ejabberd_auth_internal.erl, src/mod_adhoc.erl, src/mod_echo.erl, src/jlib.erl, src/mod_vcard_odbc.erl, src/ejabberd_s2s.erl, src/mod_stats.erl, src/ejabberd_router.erl, src/mod_last.erl, @@ -113,13 +128,11 @@ src/mod_disco.erl, src/mod_private_odbc.erl, src/mod_service_log.erl, src/mod_configure2.erl, src/mod_roster_odbc.erl, src/mod_offline.erl, src/mod_register.erl, src/mod_version.erl, src/mod_caps.erl, - src/mod_last_odbc.erl: Use exmpp API to access JID fields. Keep - #jid fields in binary format when possible. Change all 'user' and - 'server' arguments in all hooks to binary. Change internal tables of - ejabberd_sm, ejabberd_router, ejabberd_hooks, mod_last, mod_roster - to use binary() storage. - - + src/mod_last_odbc.erl: Use exmpp API to access JID fields. Keep #jid + fields in binary format when possible. Change all 'user' and 'server' + arguments in all hooks to binary. Change internal tables of + ejabberd_sm, ejabberd_router, ejabberd_hooks, mod_last, mod_roster to + use binary() storage. 2009-01-03 Christophe Romain @@ -142,12 +155,61 @@ * src/mod_pubsub/mod_pubsub.erl: Added "access-whitelist" and "member-affiliation" features (thanks to Andy Skelton)(EJAB-780) +2008-12-23 Badlop + + * src/acl.erl: New ACL: shared_group (thanks to Maxim Ryazanov) + * doc/guide.tex: Likewise + + * src/mod_shared_roster.erl: Push new group members when + registered or manually added to group: EJAB-730 EJAB-731 EJAB-732 + EJAB-767 EJAB-794. When user is added to group, push it to other + members, and other members to it. When user is removed from group, + push deletion to other members, and other members to it. When user + is registered, push him to members of group @all@. When user is + deleted, push deletion to members of group @all@. Document several + functions in mod_shared_roster. + + * src/ejabberd_auth.erl: Rename hook user_registered to + register_user, for name consistency with the widely used hook + remove_user. Run hook register_user in ejabberd_auth, so it's run + when account is created with any method. Run hook remove_user in + ejabberd_auth, so it's run when account is deleted with any + method. + * src/ejabberd_auth_internal.erl: Likewise + * src/ejabberd_auth_ldap.erl: Likewise + * src/ejabberd_auth_odbc.erl: Likewise + * src/ejabberd_auth_pam.erl: Likewise + * src/mod_register.erl: Likewise + + * src/jlib.erl: Implementation of XEP-0059 Result Set + Management (thanks to Eric Cestari)(EJAB-807) + * src/jlib.hrl: Likewise + * src/mod_muc/mod_muc.erl: Likewise + 2008-12-23 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: Improve handling of PEP sent to external contacts (EJAB-825) * src/mod_caps.erl: Likewise +2008-12-23 Badlop + + * src/mod_last.erl: Implement workaround for uptime statistic in + 32 bit machines, so it can show uptime greater than 50 + days (EJAB-610) + * src/mod_last_odbc.erl: Likewise + * src/ejabberd_config.erl: Store start time in local_config table + + * src/cyrsasl_digest.erl: Check digest-uri in SASL digest + authentication (thanks to Paul Guyot)(EJAB-569) + + * src/odbc/odbc_queries.erl: Fix removal of private_storage of an + account when the account is removed + + * src/mod_privacy.erl: Remove privacy lists of an account when the + account is removed (EJAB-720) + * src/mod_privacy_odbc.erl: Likewise + 2008-12-19 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: Fix send_last_published_item issue @@ -158,7 +220,7 @@ * src/mod_pubsub/mod_pubsub.erl: Check option of the nodetree instead of checking configuration (thanks to Eric Cestari)(EJAB-737) -2008-12-17 Pablo Polvorin +2008-12-17 Pablo Polvorin * src/mod_muc/mod_muc_room.erl: Fix bug in MUC invite. diff --git a/doc/guide.tex b/doc/guide.tex index 0ca65220b..9501c0cc5 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -1239,6 +1239,14 @@ declarations of ACLs in the configuration file have the following syntax: \begin{verbatim} {acl, mucklres, {resource, "muckl"}}. \end{verbatim} +\titem{\{shared\_group, \}} Matches any member of a Shared Roster Group with name \term{} in the virtual host. Example: +\begin{verbatim} +{acl, techgroupmembers, {shared_group, "techteam"}}. +\end{verbatim} +\titem{\{shared\_group, , \}} Matches any member of a Shared Roster Group with name \term{} in the virtual host \term{}. Example: +\begin{verbatim} +{acl, techgroupmembers, {shared_group, "techteam", "example.org"}}. +\end{verbatim} \titem{\{user\_regexp, \}} Matches any local user with a name that matches \term{} on local virtual hosts. Example: \begin{verbatim} diff --git a/src/acl.erl b/src/acl.erl index c21e62488..e3fd76020 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -180,6 +180,10 @@ match_acl(ACL, JID, Host) -> ((Host == global) andalso lists:member(Server, ?MYHOSTS))) andalso is_regexp_match(User, UR); + {shared_group, G} -> + mod_shared_roster:is_user_in_group({User, Server}, G, Host); + {shared_group, G, H} -> + mod_shared_roster:is_user_in_group({User, Server}, G, H); {user_regexp, UR, S} -> (S == Server) andalso is_regexp_match(User, UR); diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl index c269a74bf..533fc4265 100644 --- a/src/cyrsasl_digest.erl +++ b/src/cyrsasl_digest.erl @@ -18,7 +18,8 @@ -behaviour(cyrsasl). --record(state, {step, nonce, username, authzid, get_password, auth_module}). +-record(state, {step, nonce, username, authzid, get_password, auth_module, + host}). start(_Opts) -> cyrsasl:register_mechanism("DIGEST-MD5", ?MODULE, true). @@ -26,9 +27,10 @@ start(_Opts) -> stop() -> ok. -mech_new(_Host, GetPassword, _CheckPassword) -> +mech_new(Host, GetPassword, _CheckPassword) -> {ok, #state{step = 1, nonce = randoms:get_string(), + host = Host, get_password = GetPassword}}. mech_step(#state{step = 1, nonce = Nonce} = State, _) -> @@ -41,27 +43,35 @@ mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) -> bad -> {error, 'bad-protocol'}; KeyVals -> + DigestURI = xml:get_attr_s("digest-uri", KeyVals), UserName = xml:get_attr_s("username", KeyVals), - AuthzId = xml:get_attr_s("authzid", KeyVals), - case (State#state.get_password)(UserName) of - {false, _} -> + case is_digesturi_valid(DigestURI, State#state.host) of + false -> + ?DEBUG("User login not authorized because digest-uri " + "seems invalid: ~p", [DigestURI]), {error, 'not-authorized', UserName}; - {Passwd, AuthModule} -> - Response = response(KeyVals, UserName, Passwd, - Nonce, AuthzId, "AUTHENTICATE"), - case xml:get_attr_s("response", KeyVals) of - Response -> - RspAuth = response(KeyVals, - UserName, Passwd, - Nonce, AuthzId, ""), - {continue, - "rspauth=" ++ RspAuth, - State#state{step = 5, - auth_module = AuthModule, - username = UserName, - authzid = AuthzId}}; - _ -> - {error, 'not-authorized', UserName} + true -> + AuthzId = xml:get_attr_s("authzid", KeyVals), + case (State#state.get_password)(UserName) of + {false, _} -> + {error, 'not-authorized', UserName}; + {Passwd, AuthModule} -> + Response = response(KeyVals, UserName, Passwd, + Nonce, AuthzId, "AUTHENTICATE"), + case xml:get_attr_s("response", KeyVals) of + Response -> + RspAuth = response(KeyVals, + UserName, Passwd, + Nonce, AuthzId, ""), + {continue, + "rspauth=" ++ RspAuth, + State#state{step = 5, + auth_module = AuthModule, + username = UserName, + authzid = AuthzId}}; + _ -> + {error, 'not-authorized', UserName} + end end end end; @@ -75,7 +85,6 @@ mech_step(A, B) -> ?DEBUG("SASL DIGEST: A ~p B ~p", [A,B]), {error, 'bad-protocol'}. - parse(S) -> parse1(S, "", []). @@ -118,6 +127,23 @@ parse4([], Key, Val, Ts) -> parse1([], "", [{Key, lists:reverse(Val)} | Ts]). +%% @doc Check if the digest-uri is valid. +%% RFC-2831 allows to provide the IP address in Host, +%% however ejabberd doesn't allow that. +%% If the service (for example jabber.example.org) +%% is provided by several hosts (being one of them server3.example.org), +%% then digest-uri can be like xmpp/server3.example.org/jabber.example.org +%% In that case, ejabberd only checks the service name, not the host. +is_digesturi_valid(DigestURICase, JabberHost) -> + DigestURI = stringprep:tolower(DigestURICase), + case catch string:tokens(DigestURI, "/") of + ["xmpp", Host] when Host == JabberHost -> + true; + ["xmpp", _Host, ServName] when ServName == JabberHost -> + true; + _ -> + false + end. diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 2cefb6eab..6462b6edd 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -139,6 +139,7 @@ set_password(User, Server, Password) -> Res end, {error, not_allowed}, auth_modules(Server)). +%% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, not_allowed} try_register(_User, _Server, "") -> %% We do not allow empty password {error, not_allowed}; @@ -149,12 +150,19 @@ try_register(User, Server, Password) -> false -> case lists:member(exmpp_stringprep:nameprep(Server), ?MYHOSTS) of true -> - lists:foldl( + Res = lists:foldl( fun(_M, {atomic, ok} = Res) -> Res; (M, _) -> M:try_register(User, Server, Password) - end, {error, not_allowed}, auth_modules(Server)); + end, {error, not_allowed}, auth_modules(Server)), + case Res of + {atomic, ok} -> + ejabberd_hooks:run(register_user, Server, + [User, Server]), + {atomic, ok}; + _ -> Res + end; false -> {error, not_allowed} end @@ -251,17 +259,37 @@ is_user_exists_in_other_modules(Module, User, Server) -> M:is_user_exists(User, Server) end, auth_modules(Server)--[Module]). +%% @spec (User, Server) -> ok | error | {error, not_allowed} +%% Remove user. +%% Note: it may return ok even if there was some problem removing the user. remove_user(User, Server) -> - lists:foreach( + R = lists:foreach( fun(M) -> M:remove_user(User, Server) - end, auth_modules(Server)). + end, auth_modules(Server)), + case R of + ok -> ejabberd_hooks:run(remove_user, jlib:nameprep(Server), [User, Server]); + _ -> none + end, + R. +%% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request | error +%% Try to remove user if the provided password is correct. +%% The removal is attempted in each auth method provided: +%% when one returns 'ok' the loop stops; +%% if no method returns 'ok' then it returns the error message indicated by the last method attempted. remove_user(User, Server, Password) -> - lists:foreach( - fun(M) -> + R = lists:foldl( + fun(_M, ok = Res) -> + Res; + (M, _) -> M:remove_user(User, Server, Password) - end, auth_modules(Server)). + end, error, auth_modules(Server)), + case R of + ok -> ejabberd_hooks:run(remove_user, jlib:nameprep(Server), [User, Server]); + _ -> none + end, + R. %%%---------------------------------------------------------------------- diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index 04efc52c8..ae4ef4989 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -112,6 +112,7 @@ set_password(User, Server, Password) -> ok end. +%% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, invalid_jid} | {aborted, Reason} try_register(User, Server, Password) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), @@ -252,6 +253,9 @@ is_user_exists(User, Server) -> false end. +%% @spec (User, Server) -> ok +%% Remove user. +%% Note: it returns ok even if there was some problem removing the user. remove_user(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -261,14 +265,14 @@ remove_user(User, Server) -> mnesia:delete({passwd, US}) end, mnesia:transaction(F), - ejabberd_hooks:run(remove_user, - list_to_binary(LServer), - [list_to_binary(User), list_to_binary(Server)]) + ok catch _ -> ok end. +%% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request +%% Remove user if the provided password is correct. remove_user(User, Server, Password) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -287,9 +291,6 @@ remove_user(User, Server, Password) -> end, case mnesia:transaction(F) of {atomic, ok} -> - ejabberd_hooks:run(remove_user, - list_to_binary(LServer), - [list_to_binary(User), list_to_binary(Server)]), ok; {atomic, Res} -> Res; diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl index b4128a9d1..7fd8487ad 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -153,6 +153,7 @@ check_password(User, Server, Password, _StreamID, _Digest) -> set_password(_User, _Server, _Password) -> {error, not_allowed}. +%% @spec (User, Server, Password) -> {error, not_allowed} try_register(_User, _Server, _Password) -> {error, not_allowed}. diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index 79debf2ad..1f0a97b0c 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -117,6 +117,7 @@ set_password(User, Server, Password) -> end. +%% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, invalid_jid} try_register(User, Server, Password) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -225,19 +226,23 @@ is_user_exists(User, Server) -> false end. +%% @spec (User, Server) -> ok | error +%% Remove user. +%% Note: it may return ok even if there was some problem removing the user. remove_user(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), Username = ejabberd_odbc:escape(LUser), LServer = exmpp_stringprep:nameprep(Server), catch odbc_queries:del_user(LServer, Username), - ejabberd_hooks:run(remove_user, list_to_binary(LServer), - [list_to_binary(User), list_to_binary(Server)]) + ok catch _ -> error end. +%% @spec (User, Server, Password) -> ok | error | not_exists | not_allowed +%% Remove user if the provided password is correct. remove_user(User, Server, Password) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -249,8 +254,6 @@ remove_user(User, Server, Password) -> LServer, Username, Pass), case Result of {selected, ["password"], [{Password}]} -> - ejabberd_hooks:run(remove_user, list_to_binary(LServer), - [list_to_binary(User), list_to_binary(Server)]), ok; {selected, ["password"], []} -> not_exists; diff --git a/src/ejabberd_auth_pam.erl b/src/ejabberd_auth_pam.erl index f26296d33..5f67bedba 100644 --- a/src/ejabberd_auth_pam.erl +++ b/src/ejabberd_auth_pam.erl @@ -91,7 +91,7 @@ remove_user(_User, _Server) -> {error, not_allowed}. remove_user(_User, _Server, _Password) -> - {error, not_allowed}. + not_allowed. plain_password_required() -> true. diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 51b228c4f..63c67cb6d 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -55,7 +55,10 @@ start() -> {attributes, record_info(fields, local_config)}]), mnesia:add_table_copy(local_config, node(), ram_copies), Config = get_ejabberd_config_path(), - load_file(Config). + load_file(Config), + %% This start time is used by mod_last: + add_local_option(node_start, now()), + ok. %% @doc Get the filename of the ejabberd configuration file. %% The filename can be specified with: erl -config "/path/to/ejabberd.cfg". @@ -76,7 +79,7 @@ get_ejabberd_config_path() -> %% @doc Load the ejabberd configuration file. %% It also includes additional configuration files and replaces macros. -%% @spec (File::string()) -> [term()] +%% @spec (File::string()) -> ok load_file(File) -> Terms = get_plain_terms_file(File), State = lists:foldl(fun search_hosts/2, #state{}, Terms), diff --git a/src/jlib.erl b/src/jlib.erl index e6cdceb0d..d76946fb0 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -36,6 +36,9 @@ decode_base64/1, encode_base64/1, ip_to_list/1, + rsm_encode/1, + rsm_encode/2, + rsm_decode/1, from_old_jid/1, short_jid/1, short_bare_jid/1, @@ -44,6 +47,8 @@ -include_lib("exmpp/include/exmpp.hrl"). +-include("jlib.hrl"). + parse_xdata_submit(#xmlel{attrs = Attrs, children = Els}) -> case exmpp_xml:get_attribute_from_list(Attrs, 'type', "") of @@ -75,6 +80,70 @@ parse_xdata_values([#xmlel{name = 'value', children = SubEls} | Els], Res) -> parse_xdata_values([_ | Els], Res) -> parse_xdata_values(Els, Res). +rsm_decode(#iq{payload=SubEl})-> + rsm_decode(SubEl); +rsm_decode(#xmlel{}=SubEl)-> + case exmpp_xml:get_element(SubEl, 'set') of + undefined -> + none; + #xmlelement{name = 'set', children = SubEls}-> + lists:foldl(fun rsm_parse_element/2, #rsm_in{}, SubEls) + end. + +rsm_parse_element(#xmlel{name = 'max'}=Elem, RsmIn)-> + CountStr = exmpp_xml:get_cdata_as_list(Elem), + {Count, _} = string:to_integer(CountStr), + RsmIn#rsm_in{max=Count}; + +rsm_parse_element(#xmlel{name = 'before'}=Elem, RsmIn)-> + UID = exmpp_xml:get_cdata_as_list(Elem), + RsmIn#rsm_in{direction=before, id=UID}; + +rsm_parse_element(#xmlel{name = 'after'}=Elem, RsmIn)-> + UID = exmpp_xml:get_cdata_as_list(Elem), + RsmIn#rsm_in{direction=aft, id=UID}; + +rsm_parse_element(#xmlel{name = 'index'}=Elem, RsmIn)-> + IndexStr = exmpp_xml:get_cdata_as_list(Elem), + {Index, _} = string:to_integer(IndexStr), + RsmIn#rsm_in{index=Index}; + + +rsm_parse_element(_, RsmIn)-> + RsmIn. + +rsm_encode(#iq{payload=SubEl}=IQ_Rec,RsmOut)-> + Set = #xmlel{ns = ?NS_RSM, name = 'set', children = + lists:reverse(rsm_encode_out(RsmOut))}, + New = exmpp_xml:prepend_child(SubEl, Set), + IQ_Rec#iq{payload=New}. + +rsm_encode(none)-> + []; +rsm_encode(RsmOut)-> + [#xmlel{ns = ?NS_RSM, name = 'set', children = lists:reverse(rsm_encode_out(RsmOut))}]. +rsm_encode_out(#rsm_out{count=Count, index=Index, first=First, last=Last})-> + El = rsm_encode_first(First, Index, []), + El2 = rsm_encode_last(Last,El), + rsm_encode_count(Count, El2). + +rsm_encode_first(undefined, undefined, Arr) -> + Arr; +rsm_encode_first(First, undefined, Arr) -> + [#xmlel{ns = ?NS_RSM, name = 'first', children = [#xmlcdata{cdata = list_to_binary(First)}]}|Arr]; +rsm_encode_first(First, Index, Arr) -> + [#xmlel{ns = ?NS_RSM, name = 'first', attrs = [#xmlattr{name = 'index', value = i2b(Index)}], children = [#xmlcdata{cdata = list_to_binary(First)}]}|Arr]. + +rsm_encode_last(undefined, Arr) -> Arr; +rsm_encode_last(Last, Arr) -> + [#xmlel{ns = ?NS_RSM, name = 'last', children = [#xmlcdata{cdata = list_to_binary(Last)}]}|Arr]. + +rsm_encode_count(undefined, Arr)-> Arr; +rsm_encode_count(Count, Arr)-> + [#xmlel{ns = ?NS_RSM, name = 'count', children = [#xmlcdata{cdata = i2b(Count)}]} | Arr]. + +i2b(I) when is_integer(I) -> list_to_binary(integer_to_list(I)); +i2b(L) when is_list(L) -> list_to_binary(L). timestamp_to_iso({{Year, Month, Day}, {Hour, Minute, Second}}) -> lists:flatten( diff --git a/src/jlib.hrl b/src/jlib.hrl index 39731b14a..93d2a5dce 100644 --- a/src/jlib.hrl +++ b/src/jlib.hrl @@ -19,290 +19,5 @@ %%% %%%---------------------------------------------------------------------- --define(NS_DISCO_ITEMS, "http://jabber.org/protocol/disco#items"). --define(NS_DISCO_INFO, "http://jabber.org/protocol/disco#info"). --define(NS_VCARD, "vcard-temp"). --define(NS_AUTH, "jabber:iq:auth"). --define(NS_AUTH_ERROR, "jabber:iq:auth:error"). --define(NS_REGISTER, "jabber:iq:register"). --define(NS_SEARCH, "jabber:iq:search"). --define(NS_ROSTER, "jabber:iq:roster"). --define(NS_PRIVACY, "jabber:iq:privacy"). --define(NS_PRIVATE, "jabber:iq:private"). --define(NS_VERSION, "jabber:iq:version"). --define(NS_TIME, "jabber:iq:time"). --define(NS_LAST, "jabber:iq:last"). --define(NS_XDATA, "jabber:x:data"). --define(NS_IQDATA, "jabber:iq:data"). --define(NS_DELAY, "jabber:x:delay"). --define(NS_EXPIRE, "jabber:x:expire"). --define(NS_EVENT, "jabber:x:event"). --define(NS_XCONFERENCE, "jabber:x:conference"). --define(NS_STATS, "http://jabber.org/protocol/stats"). --define(NS_MUC, "http://jabber.org/protocol/muc"). --define(NS_MUC_USER, "http://jabber.org/protocol/muc#user"). --define(NS_MUC_ADMIN, "http://jabber.org/protocol/muc#admin"). --define(NS_MUC_OWNER, "http://jabber.org/protocol/muc#owner"). --define(NS_PUBSUB, "http://jabber.org/protocol/pubsub"). --define(NS_PUBSUB_EVENT, "http://jabber.org/protocol/pubsub#event"). --define(NS_PUBSUB_OWNER, "http://jabber.org/protocol/pubsub#owner"). --define(NS_PUBSUB_NMI, "http://jabber.org/protocol/pubsub#node-meta-info"). --define(NS_PUBSUB_ERRORS,"http://jabber.org/protocol/pubsub#errors"). --define(NS_PUBSUB_NODE_CONFIG, "http://jabber.org/protocol/pubsub#node_config"). --define(NS_PUBSUB_SUB_AUTH, "http://jabber.org/protocol/pubsub#subscribe_authorization"). --define(NS_COMMANDS, "http://jabber.org/protocol/commands"). --define(NS_BYTESTREAMS, "http://jabber.org/protocol/bytestreams"). --define(NS_ADMIN, "http://jabber.org/protocol/admin"). - --define(NS_EJABBERD_CONFIG, "ejabberd:config"). - --define(NS_STREAM, "http://etherx.jabber.org/streams"). - --define(NS_STANZAS, "urn:ietf:params:xml:ns:xmpp-stanzas"). --define(NS_STREAMS, "urn:ietf:params:xml:ns:xmpp-streams"). - --define(NS_TLS, "urn:ietf:params:xml:ns:xmpp-tls"). --define(NS_SASL, "urn:ietf:params:xml:ns:xmpp-sasl"). --define(NS_SESSION, "urn:ietf:params:xml:ns:xmpp-session"). --define(NS_BIND, "urn:ietf:params:xml:ns:xmpp-bind"). - --define(NS_FEATURE_IQAUTH, "http://jabber.org/features/iq-auth"). --define(NS_FEATURE_IQREGISTER, "http://jabber.org/features/iq-register"). --define(NS_FEATURE_COMPRESS, "http://jabber.org/features/compress"). - --define(NS_COMPRESS, "http://jabber.org/protocol/compress"). - --define(NS_CAPS, "http://jabber.org/protocol/caps"). - -% TODO: remove "code" attribute (currently it used for backward-compatibility) --define(STANZA_ERROR(Code, Type, Condition), - {xmlelement, "error", - [{"code", Code}, {"type", Type}], - [{xmlelement, Condition, [{"xmlns", ?NS_STANZAS}], []}]}). - --define(ERR_BAD_REQUEST, - ?STANZA_ERROR("400", "modify", "bad-request")). --define(ERR_CONFLICT, - ?STANZA_ERROR("409", "cancel", "conflict")). --define(ERR_FEATURE_NOT_IMPLEMENTED, - ?STANZA_ERROR("501", "cancel", "feature-not-implemented")). --define(ERR_FORBIDDEN, - ?STANZA_ERROR("403", "auth", "forbidden")). --define(ERR_GONE, - ?STANZA_ERROR("302", "modify", "gone")). --define(ERR_INTERNAL_SERVER_ERROR, - ?STANZA_ERROR("500", "wait", "internal-server-error")). --define(ERR_ITEM_NOT_FOUND, - ?STANZA_ERROR("404", "cancel", "item-not-found")). --define(ERR_JID_MALFORMED, - ?STANZA_ERROR("400", "modify", "jid-malformed")). --define(ERR_NOT_ACCEPTABLE, - ?STANZA_ERROR("406", "modify", "not-acceptable")). --define(ERR_NOT_ALLOWED, - ?STANZA_ERROR("405", "cancel", "not-allowed")). --define(ERR_NOT_AUTHORIZED, - ?STANZA_ERROR("401", "auth", "not-authorized")). --define(ERR_PAYMENT_REQUIRED, - ?STANZA_ERROR("402", "auth", "payment-required")). --define(ERR_RECIPIENT_UNAVAILABLE, - ?STANZA_ERROR("404", "wait", "recipient-unavailable")). --define(ERR_REDIRECT, - ?STANZA_ERROR("302", "modify", "redirect")). --define(ERR_REGISTRATION_REQUIRED, - ?STANZA_ERROR("407", "auth", "registration-required")). --define(ERR_REMOTE_SERVER_NOT_FOUND, - ?STANZA_ERROR("404", "cancel", "remote-server-not-found")). --define(ERR_REMOTE_SERVER_TIMEOUT, - ?STANZA_ERROR("504", "wait", "remote-server-timeout")). --define(ERR_RESOURCE_CONSTRAINT, - ?STANZA_ERROR("500", "wait", "resource-constraint")). --define(ERR_SERVICE_UNAVAILABLE, - ?STANZA_ERROR("503", "cancel", "service-unavailable")). --define(ERR_SUBSCRIPTION_REQUIRED, - ?STANZA_ERROR("407", "auth", "subscription-required")). --define(ERR_UNEXPECTED_REQUEST, - ?STANZA_ERROR("400", "wait", "unexpected-request")). -%-define(ERR_, -% ?STANZA_ERROR("", "", "")). - --define(STANZA_ERRORT(Code, Type, Condition, Lang, Text), - {xmlelement, "error", - [{"code", Code}, {"type", Type}], - [{xmlelement, Condition, [{"xmlns", ?NS_STANZAS}], []}, - {xmlelement, "text", [{"xmlns", ?NS_STANZAS}], - [{xmlcdata, translate:translate(Lang, Text)}]}]}). - --define(ERRT_BAD_REQUEST(Lang, Text), - ?STANZA_ERRORT("400", "modify", "bad-request", Lang, Text)). --define(ERRT_CONFLICT(Lang, Text), - ?STANZA_ERRORT("409", "cancel", "conflict", Lang, Text)). --define(ERRT_FEATURE_NOT_IMPLEMENTED(Lang, Text), - ?STANZA_ERRORT("501", "cancel", "feature-not-implemented", Lang, Text)). --define(ERRT_FORBIDDEN(Lang, Text), - ?STANZA_ERRORT("403", "auth", "forbidden", Lang, Text)). --define(ERRT_GONE(Lang, Text), - ?STANZA_ERRORT("302", "modify", "gone", Lang, Text)). --define(ERRT_INTERNAL_SERVER_ERROR(Lang, Text), - ?STANZA_ERRORT("500", "wait", "internal-server-error", Lang, Text)). --define(ERRT_ITEM_NOT_FOUND(Lang, Text), - ?STANZA_ERRORT("404", "cancel", "item-not-found", Lang, Text)). --define(ERRT_JID_MALFORMED(Lang, Text), - ?STANZA_ERRORT("400", "modify", "jid-malformed", Lang, Text)). --define(ERRT_NOT_ACCEPTABLE(Lang, Text), - ?STANZA_ERRORT("406", "modify", "not-acceptable", Lang, Text)). --define(ERRT_NOT_ALLOWED(Lang, Text), - ?STANZA_ERRORT("405", "cancel", "not-allowed", Lang, Text)). --define(ERRT_NOT_AUTHORIZED(Lang, Text), - ?STANZA_ERRORT("401", "auth", "not-authorized", Lang, Text)). --define(ERRT_PAYMENT_REQUIRED(Lang, Text), - ?STANZA_ERRORT("402", "auth", "payment-required", Lang, Text)). --define(ERRT_RECIPIENT_UNAVAILABLE(Lang, Text), - ?STANZA_ERRORT("404", "wait", "recipient-unavailable", Lang, Text)). --define(ERRT_REDIRECT(Lang, Text), - ?STANZA_ERRORT("302", "modify", "redirect", Lang, Text)). --define(ERRT_REGISTRATION_REQUIRED(Lang, Text), - ?STANZA_ERRORT("407", "auth", "registration-required", Lang, Text)). --define(ERRT_REMOTE_SERVER_NOT_FOUND(Lang, Text), - ?STANZA_ERRORT("404", "cancel", "remote-server-not-found", Lang, Text)). --define(ERRT_REMOTE_SERVER_TIMEOUT(Lang, Text), - ?STANZA_ERRORT("504", "wait", "remote-server-timeout", Lang, Text)). --define(ERRT_RESOURCE_CONSTRAINT(Lang, Text), - ?STANZA_ERRORT("500", "wait", "resource-constraint", Lang, Text)). --define(ERRT_SERVICE_UNAVAILABLE(Lang, Text), - ?STANZA_ERRORT("503", "cancel", "service-unavailable", Lang, Text)). --define(ERRT_SUBSCRIPTION_REQUIRED(Lang, Text), - ?STANZA_ERRORT("407", "auth", "subscription-required", Lang, Text)). --define(ERRT_UNEXPECTED_REQUEST(Lang, Text), - ?STANZA_ERRORT("400", "wait", "unexpected-request", Lang, Text)). - -% Auth stanza errors --define(ERR_AUTH_NO_RESOURCE_PROVIDED(Lang), - ?ERRT_NOT_ACCEPTABLE(Lang, "No resource provided")). --define(ERR_AUTH_BAD_RESOURCE_FORMAT(Lang), - ?ERRT_NOT_ACCEPTABLE(Lang, "Illegal resource format")). --define(ERR_AUTH_RESOURCE_CONFLICT(Lang), - ?ERRT_CONFLICT(Lang, "Resource conflict")). - - --define(STREAM_ERROR(Condition), - {xmlelement, "stream:error", - [], - [{xmlelement, Condition, [{"xmlns", ?NS_STREAMS}], []}]}). - --define(SERR_BAD_FORMAT, - ?STREAM_ERROR("bad-format")). --define(SERR_BAD_NAMESPACE_PREFIX, - ?STREAM_ERROR("bad-namespace-prefix")). --define(SERR_CONFLICT, - ?STREAM_ERROR("conflict")). --define(SERR_CONNECTION_TIMEOUT, - ?STREAM_ERROR("connection-timeout")). --define(SERR_HOST_GONE, - ?STREAM_ERROR("host-gone")). --define(SERR_HOST_UNKNOWN, - ?STREAM_ERROR("host-unknown")). --define(SERR_IMPROPER_ADDRESSING, - ?STREAM_ERROR("improper-addressing")). --define(SERR_INTERNAL_SERVER_ERROR, - ?STREAM_ERROR("internal-server-error")). --define(SERR_INVALID_FROM, - ?STREAM_ERROR("invalid-from")). --define(SERR_INVALID_ID, - ?STREAM_ERROR("invalid-id")). --define(SERR_INVALID_NAMESPACE, - ?STREAM_ERROR("invalid-namespace")). --define(SERR_INVALID_XML, - ?STREAM_ERROR("invalid-xml")). --define(SERR_NOT_AUTHORIZED, - ?STREAM_ERROR("not-authorized")). --define(SERR_POLICY_VIOLATION, - ?STREAM_ERROR("policy-violation")). --define(SERR_REMOTE_CONNECTION_FAILED, - ?STREAM_ERROR("remote-connection-failed")). --define(SERR_RESOURSE_CONSTRAINT, - ?STREAM_ERROR("resource-constraint")). --define(SERR_RESTRICTED_XML, - ?STREAM_ERROR("restricted-xml")). -% TODO: include hostname or IP --define(SERR_SEE_OTHER_HOST, - ?STREAM_ERROR("see-other-host")). --define(SERR_SYSTEM_SHUTDOWN, - ?STREAM_ERROR("system-shutdown")). --define(SERR_UNSUPPORTED_ENCODING, - ?STREAM_ERROR("unsupported-encoding")). --define(SERR_UNSUPPORTED_STANZA_TYPE, - ?STREAM_ERROR("unsupported-stanza-type")). --define(SERR_UNSUPPORTED_VERSION, - ?STREAM_ERROR("unsupported-version")). --define(SERR_XML_NOT_WELL_FORMED, - ?STREAM_ERROR("xml-not-well-formed")). -%-define(SERR_, -% ?STREAM_ERROR("")). - --define(STREAM_ERRORT(Condition, Lang, Text), - {xmlelement, "stream:error", - [], - [{xmlelement, Condition, [{"xmlns", ?NS_STREAMS}], []}, - {xmlelement, "text", [{"xml:lang", Lang}, {"xmlns", ?NS_STREAMS}], - [{xmlcdata, translate:translate(Lang, Text)}]}]}). - --define(SERRT_BAD_FORMAT(Lang, Text), - ?STREAM_ERRORT("bad-format", Lang, Text)). --define(SERRT_BAD_NAMESPACE_PREFIX(Lang, Text), - ?STREAM_ERRORT("bad-namespace-prefix", Lang, Text)). --define(SERRT_CONFLICT(Lang, Text), - ?STREAM_ERRORT("conflict", Lang, Text)). --define(SERRT_CONNECTION_TIMEOUT(Lang, Text), - ?STREAM_ERRORT("connection-timeout", Lang, Text)). --define(SERRT_HOST_GONE(Lang, Text), - ?STREAM_ERRORT("host-gone", Lang, Text)). --define(SERRT_HOST_UNKNOWN(Lang, Text), - ?STREAM_ERRORT("host-unknown", Lang, Text)). --define(SERRT_IMPROPER_ADDRESSING(Lang, Text), - ?STREAM_ERRORT("improper-addressing", Lang, Text)). --define(SERRT_INTERNAL_SERVER_ERROR(Lang, Text), - ?STREAM_ERRORT("internal-server-error", Lang, Text)). --define(SERRT_INVALID_FROM(Lang, Text), - ?STREAM_ERRORT("invalid-from", Lang, Text)). --define(SERRT_INVALID_ID(Lang, Text), - ?STREAM_ERRORT("invalid-id", Lang, Text)). --define(SERRT_INVALID_NAMESPACE(Lang, Text), - ?STREAM_ERRORT("invalid-namespace", Lang, Text)). --define(SERRT_INVALID_XML(Lang, Text), - ?STREAM_ERRORT("invalid-xml", Lang, Text)). --define(SERRT_NOT_AUTHORIZED(Lang, Text), - ?STREAM_ERRORT("not-authorized", Lang, Text)). --define(SERRT_POLICY_VIOLATION(Lang, Text), - ?STREAM_ERRORT("policy-violation", Lang, Text)). --define(SERRT_REMOTE_CONNECTION_FAILED(Lang, Text), - ?STREAM_ERRORT("remote-connection-failed", Lang, Text)). --define(SERRT_RESOURSE_CONSTRAINT(Lang, Text), - ?STREAM_ERRORT("resource-constraint", Lang, Text)). --define(SERRT_RESTRICTED_XML(Lang, Text), - ?STREAM_ERRORT("restricted-xml", Lang, Text)). -% TODO: include hostname or IP --define(SERRT_SEE_OTHER_HOST(Lang, Text), - ?STREAM_ERRORT("see-other-host", Lang, Text)). --define(SERRT_SYSTEM_SHUTDOWN(Lang, Text), - ?STREAM_ERRORT("system-shutdown", Lang, Text)). --define(SERRT_UNSUPPORTED_ENCODING(Lang, Text), - ?STREAM_ERRORT("unsupported-encoding", Lang, Text)). --define(SERRT_UNSUPPORTED_STANZA_TYPE(Lang, Text), - ?STREAM_ERRORT("unsupported-stanza-type", Lang, Text)). --define(SERRT_UNSUPPORTED_VERSION(Lang, Text), - ?STREAM_ERRORT("unsupported-version", Lang, Text)). --define(SERRT_XML_NOT_WELL_FORMED(Lang, Text), - ?STREAM_ERRORT("xml-not-well-formed", Lang, Text)). -%-define(SERRT_(Lang, Text), -% ?STREAM_ERRORT("", Lang, Text)). - - --record(jid, {user, server, resource, - luser, lserver, lresource}). - --record(iq, {id = "", - type, - xmlns = "", - lang = "", - sub_el}). - +-record(rsm_in, {max, direction, id, index}). +-record(rsm_out, {count, index, first, last}). diff --git a/src/mod_last.erl b/src/mod_last.erl index f1f8e7bda..4ddb716f3 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -71,14 +71,36 @@ stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_local, HostB, ?NS_LAST_ACTIVITY), gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_LAST_ACTIVITY). +%%% +%%% Uptime of ejabberd node +%%% + process_local_iq(_From, _To, #iq{type = get} = IQ_Rec) -> - Sec = trunc(element(1, erlang:statistics(wall_clock))/1000), + Sec = get_node_uptime(), Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = [#xmlattr{name = 'seconds', value = list_to_binary(integer_to_list(Sec))}]}, exmpp_iq:result(IQ_Rec, Response); process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> exmpp_iq:error(IQ_Rec, 'not-allowed'). +%% @spec () -> integer() +%% @doc Get the uptime of the ejabberd node, expressed in seconds. +%% When ejabberd is starting, ejabberd_config:start/0 stores the datetime. +get_node_uptime() -> + case ejabberd_config:get_local_option(node_start) of + {_, _, _} = StartNow -> + now_to_seconds(now()) - now_to_seconds(StartNow); + _undefined -> + trunc(element(1, erlang:statistics(wall_clock))/1000) + end. + +now_to_seconds({MegaSecs, Secs, _MicroSecs}) -> + MegaSecs * 1000000 + Secs. + + +%%% +%%% Serve queries about user last online +%%% process_sm_iq(From, To, #iq{type = get} = IQ_Rec) -> {Subscription, _Groups} = @@ -117,8 +139,7 @@ get_last(IQ_Rec, LUser, LServer) -> [] -> exmpp_iq:error(IQ_Rec, 'service-unavailable'); [#last_activity{timestamp = TimeStamp, status = Status}] -> - {MegaSecs, Secs, _MicroSecs} = now(), - TimeStamp2 = MegaSecs * 1000000 + Secs, + TimeStamp2 = now_to_seconds(now()), Sec = TimeStamp2 - TimeStamp, Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = [#xmlattr{name = 'seconds', value = list_to_binary(integer_to_list(Sec))}], @@ -129,8 +150,7 @@ get_last(IQ_Rec, LUser, LServer) -> on_presence_update(User, Server, _Resource, Status) -> - {MegaSecs, Secs, _MicroSecs} = now(), - TimeStamp = MegaSecs * 1000000 + Secs, + TimeStamp = now_to_seconds(now()), store_last_info(User, Server, TimeStamp, Status). store_last_info(User, Server, TimeStamp, Status) @@ -147,8 +167,9 @@ store_last_info(User, Server, TimeStamp, Status) _ -> ok end. - -%% Returns: {ok, Timestamp, Status} | not_found + +%% @spec (LUser::string(), LServer::string() -> +%% {ok, Timestamp::integer(), Status::string()} | not_found get_last_info(LUser, LServer) when is_binary(LUser), is_binary(LServer) -> case catch mnesia:dirty_read(last_activity, {LUser, LServer}) of {'EXIT', _Reason} -> diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 4eab4ffea..4d8ea152d 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -64,14 +64,36 @@ stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_local, HostB, ?NS_LAST_ACTIVITY), gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_LAST_ACTIVITY). +%%% +%%% Uptime of ejabberd node +%%% + process_local_iq(_From, _To, #iq{type = get} = IQ_Rec) -> - Sec = trunc(element(1, erlang:statistics(wall_clock))/1000), + Sec = get_node_uptime(), Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = [#xmlattr{name = 'seconds', value = list_to_binary(integer_to_list(Sec))}]}, exmpp_iq:result(IQ_Rec, Response); process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> exmpp_iq:error(IQ_Rec, 'not-allowed'). +%% @spec () -> integer() +%% @doc Get the uptime of the ejabberd node, expressed in seconds. +%% When ejabberd is starting, ejabberd_config:start/0 stores the datetime. +get_node_uptime() -> + case ejabberd_config:get_local_option(node_start) of + {_, _, _} = StartNow -> + now_to_seconds(now()) - now_to_seconds(StartNow); + _undefined -> + trunc(element(1, erlang:statistics(wall_clock))/1000) + end. + +now_to_seconds({MegaSecs, Secs, _MicroSecs}) -> + MegaSecs * 1000000 + Secs. + + +%%% +%%% Serve queries about user last online +%%% process_sm_iq(From, To, #iq{type = get} = IQ_Rec) -> User = exmpp_jid:lnode_as_list(To), Server = exmpp_jid:ldomain_as_list(To), @@ -112,8 +134,7 @@ get_last(IQ_Rec, LUser, LServer) -> {selected, ["seconds","state"], [{STimeStamp, Status}]} -> case catch list_to_integer(STimeStamp) of TimeStamp when is_integer(TimeStamp) -> - {MegaSecs, Secs, _MicroSecs} = now(), - TimeStamp2 = MegaSecs * 1000000 + Secs, + TimeStamp2 = now_to_seconds(now()), Sec = TimeStamp2 - TimeStamp, Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = [#xmlattr{name = 'seconds', value = list_to_binary(integer_to_list(Sec))}], @@ -127,8 +148,7 @@ get_last(IQ_Rec, LUser, LServer) -> end. on_presence_update(User, Server, _Resource, Status) -> - {MegaSecs, Secs, _MicroSecs} = now(), - TimeStamp = MegaSecs * 1000000 + Secs, + TimeStamp = now_to_seconds(now()), store_last_info(User, Server, TimeStamp, Status). store_last_info(User, Server, TimeStamp, Status) @@ -148,7 +168,8 @@ store_last_info(User, Server, TimeStamp, Status) ok end. -%% Returns: {ok, Timestamp, Status} | not_found +%% @spec (LUser::string(), LServer::string() -> +%% {ok, Timestamp::integer(), Status::string()} | not_found get_last_info(LUser, LServer) -> Username = ejabberd_odbc:escape(LUser), case catch odbc_queries:get_last(LServer, Username) of diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index 55cf0008c..daa953371 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -48,6 +48,7 @@ -include_lib("exmpp/include/exmpp.hrl"). -include("ejabberd.hrl"). +-include("jlib.hrl"). -record(muc_room, {name_host, opts}). @@ -125,11 +126,11 @@ forget_room(Host, Name) when is_binary(Host), is_binary(Name) -> end, mnesia:transaction(F). -process_iq_disco_items(Host, From, To, #iq{} = IQ) when is_binary(Host) -> - Lang = exmpp_stanza:get_lang(IQ), +process_iq_disco_items(Host, From, To, #iq{lang = Lang} = IQ) when is_binary(Host) -> + Rsm = jlib:rsm_decode(IQ), Res = exmpp_iq:result(IQ, #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', - children = iq_disco_items(Host, From, Lang)}), + children = iq_disco_items(Host, From, Lang, Rsm)}), ejabberd_router:route(To, From, exmpp_iq:iq_to_xmlel(Res)). @@ -513,13 +514,15 @@ iq_disco_info(Lang) -> #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [#xmlattr{name = 'var', value = ?NS_INBAND_REGISTER_s}]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = + [#xmlattr{name = 'var', + value = ?NS_RSM_s}]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [#xmlattr{name = 'var', value = ?NS_VCARD_s}]}]. - -iq_disco_items(Host, From, Lang) when is_binary(Host) -> +iq_disco_items(Host, From, Lang, none) when is_binary(Host) -> lists:zf(fun(#muc_online_room{name_host = {Name, _Host}, pid = Pid}) -> case catch gen_fsm:sync_send_all_state_event( Pid, {get_disco_item, From, Lang}, 100) of @@ -535,7 +538,72 @@ iq_disco_items(Host, From, Lang) when is_binary(Host) -> _ -> false end - end, get_vh_rooms(Host)). + end, get_vh_rooms(Host)); + +iq_disco_items(Host, From, Lang, Rsm) -> + {Rooms, RsmO} = get_vh_rooms(Host, Rsm), + RsmOut = jlib:rsm_encode(RsmO), + lists:zf(fun(#muc_online_room{name_host = {Name, _Host}, pid = Pid}) -> + case catch gen_fsm:sync_send_all_state_event( + Pid, {get_disco_item, From, Lang}, 100) of + {item, Desc} -> + flush(), + {true, + {xmlelement, "item", + [{"jid", jlib:jid_to_string({Name, Host, ""})}, + {"name", Desc}], []}}; + _ -> + false + end + end, Rooms) ++ RsmOut. + +get_vh_rooms(Host, #rsm_in{max=M, direction=Direction, id=I, index=Index})-> + AllRooms = lists:sort(get_vh_rooms(Host)), + Count = erlang:length(AllRooms), + Guard = case Direction of + _ when Index =/= undefined -> [{'==', {element, 2, '$1'}, Host}]; + aft -> [{'==', {element, 2, '$1'}, Host}, {'>=',{element, 1, '$1'} ,I}]; + before when I =/= []-> [{'==', {element, 2, '$1'}, Host}, {'=<',{element, 1, '$1'} ,I}]; + _ -> [{'==', {element, 2, '$1'}, Host}] + end, + L = lists:sort( + mnesia:dirty_select(muc_online_room, + [{#muc_online_room{name_host = '$1', _ = '_'}, + Guard, + ['$_']}])), + L2 = if + Index == undefined andalso Direction == before -> + lists:reverse(lists:sublist(lists:reverse(L), 1, M)); + Index == undefined -> + lists:sublist(L, 1, M); + Index > Count orelse Index < 0 -> + []; + true -> + lists:sublist(L, Index+1, M) + end, + if + L2 == [] -> + {L2, #rsm_out{count=Count}}; + true -> + H = hd(L2), + NewIndex = get_room_pos(H, AllRooms), + T=lists:last(L2), + {F, _}=H#muc_online_room.name_host, + {Last, _}=T#muc_online_room.name_host, + {L2, #rsm_out{first=F, last=Last, count=Count, index=NewIndex}} + end. + +%% @doc Return the position of desired room in the list of rooms. +%% The room must exist in the list. The count starts in 0. +%% @spec (Desired::muc_online_room(), Rooms::[muc_online_room()]) -> integer() +get_room_pos(Desired, Rooms) -> + get_room_pos(Desired, Rooms, 0). +get_room_pos(Desired, [HeadRoom | _], HeadPosition) + when (Desired#muc_online_room.name_host == + HeadRoom#muc_online_room.name_host) -> + HeadPosition; +get_room_pos(Desired, [_ | Rooms], HeadPosition) -> + get_room_pos(Desired, Rooms, HeadPosition + 1). flush() -> receive diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 7d035994f..b159c3983 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -35,6 +35,7 @@ process_iq_get/5, get_user_list/3, check_packet/6, + remove_user/2, updated_list/3]). -include_lib("exmpp/include/exmpp.hrl"). @@ -59,6 +60,8 @@ start(Host, Opts) -> ?MODULE, check_packet, 50), ejabberd_hooks:add(privacy_updated_list, HostB, ?MODULE, updated_list, 50), + ejabberd_hooks:add(remove_user, HostB, + ?MODULE, remove_user, 50), gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_PRIVACY, ?MODULE, process_iq, IQDisc). @@ -74,6 +77,8 @@ stop(Host) -> ?MODULE, check_packet, 50), ejabberd_hooks:delete(privacy_updated_list, HostB, ?MODULE, updated_list, 50), + ejabberd_hooks:delete(remove_user, HostB, + ?MODULE, remove_user, 50), gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_PRIVACY). process_iq(_From, _To, IQ_Rec) -> @@ -667,6 +672,16 @@ is_type_match(Type, Value, JID, Subscription, Groups) -> end. +remove_user(User, Server) -> + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + F = fun() -> + mnesia:delete({privacy, + {LUser, LServer}}) + end, + mnesia:transaction(F). + + updated_list(_, #userlist{name = OldName} = Old, #userlist{name = NewName} = New) -> @@ -678,7 +693,6 @@ updated_list(_, end. - update_table() -> Fields = record_info(fields, privacy), case mnesia:table_info(privacy, attributes) of diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 953a2dc2c..1147c51db 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -35,6 +35,7 @@ process_iq_get/5, get_user_list/3, check_packet/6, + remove_user/2, updated_list/3]). -include_lib("exmpp/include/exmpp.hrl"). @@ -55,6 +56,8 @@ start(Host, Opts) -> ?MODULE, check_packet, 50), ejabberd_hooks:add(privacy_updated_list, HostB, ?MODULE, updated_list, 50), + ejabberd_hooks:add(remove_user, HostB, + ?MODULE, remove_user, 50), gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_PRIVACY, ?MODULE, process_iq, IQDisc). @@ -70,6 +73,8 @@ stop(Host) -> ?MODULE, check_packet, 50), ejabberd_hooks:delete(privacy_updated_list, HostB, ?MODULE, updated_list, 50), + ejabberd_hooks:delete(remove_user, HostB, + ?MODULE, remove_user, 50), gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_PRIVACY). process_iq(_From, _To, IQ_Rec) -> @@ -666,6 +671,12 @@ is_type_match(Type, Value, JID, Subscription, Groups) -> end. +remove_user(User, Server) -> + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + sql_del_privacy_lists(LUser, LServer). + + updated_list(_, #userlist{name = OldName} = Old, #userlist{name = NewName} = New) -> @@ -880,3 +891,16 @@ sql_set_privacy_list(ID, RItems) -> ") " "values ('", ID, "', ", Items, ");"]) end, RItems). + +sql_del_privacy_lists(LUser, LServer) -> + Username = ejabberd_odbc:escape(LUser), + Server = ejabberd_odbc:escape(LServer), + ejabberd_odbc:sql_query( + LServer, + ["delete from privacy_list where username='", Username, "';"]), + ejabberd_odbc:sql_query( + LServer, + ["delete from privacy_list_data where value='", Username++"@"++Server, "';"]), + ejabberd_odbc:sql_query( + LServer, + ["delete from privacy_default_list where username='", Username, "';"]). diff --git a/src/mod_pubsub/node.template b/src/mod_pubsub/node.template index 447c919ad..7b7fb175c 100644 --- a/src/mod_pubsub/node.template +++ b/src/mod_pubsub/node.template @@ -26,7 +26,6 @@ -author(__TO_BE_DEFINED__). -include("pubsub.hrl"). --include("jlib.hrl"). -behaviour(gen_pubsub_node). diff --git a/src/mod_register.erl b/src/mod_register.erl index 3b66aeea8..a51408920 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -215,8 +215,6 @@ try_register(User, Server, Password, Source, Lang) -> true -> case ejabberd_auth:try_register(User, Server, Password) of {atomic, ok} -> - ejabberd_hooks:run(user_registered, exmpp_jid:domain(JID), - [exmpp_jid:node(JID), exmpp_jid:domain(JID)]), send_welcome_message(JID), send_registration_notifications(JID), ok; diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index e0522510f..6ed4fbb0c 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -37,7 +37,8 @@ process_item/2, in_subscription/6, out_subscription/4, - user_registered/2, + register_user/2, + remove_user/2, list_groups/1, create_group/2, create_group/3, @@ -46,6 +47,7 @@ set_group_opts/3, get_group_users/2, get_group_explicit_users/2, + is_user_in_group/3, add_user_to_group/3, remove_user_from_group/3]). @@ -85,8 +87,10 @@ start(Host, _Opts) -> ?MODULE, get_jid_info, 70), ejabberd_hooks:add(roster_process_item, HostB, ?MODULE, process_item, 50), - ejabberd_hooks:add(user_registered, HostB, - ?MODULE, user_registered, 50). + ejabberd_hooks:add(register_user, HostB, + ?MODULE, register_user, 50), + ejabberd_hooks:add(remove_user, HostB, + ?MODULE, remove_user, 50). %%ejabberd_hooks:add(remove_user, HostB, %% ?MODULE, remove_user, 50), @@ -108,8 +112,10 @@ stop(Host) -> ?MODULE, get_jid_info, 70), ejabberd_hooks:delete(roster_process_item, HostB, ?MODULE, process_item, 50), - ejabberd_hooks:delete(user_registered, HostB, - ?MODULE, user_registered, 50). + ejabberd_hooks:delete(register_user, HostB, + ?MODULE, register_user, 50), + ejabberd_hooks:delete(remove_user, HostB, + ?MODULE, remove_user, 50). %%ejabberd_hooks:delete(remove_user, HostB, %% ?MODULE, remove_user, 50), @@ -443,6 +449,7 @@ get_group_users(_User, Host, Group, GroupOpts) -> [] end ++ get_group_explicit_users(Host, Group). +%% @spec (Host::string(), Group::string()) -> [{User::string(), Server::string()}] get_group_explicit_users(Host, Group) -> Read = (catch mnesia:dirty_index_read( sr_user, @@ -458,6 +465,7 @@ get_group_explicit_users(Host, Group) -> get_group_name(Host, Group) -> get_group_opt(Host, Group, name, Group). +%% Get list of names of groups that have @all@ in the memberlist get_special_users_groups(Host) -> lists:filter( fun(Group) -> @@ -465,6 +473,8 @@ get_special_users_groups(Host) -> end, 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) -> DisplayedGroups = lists:usort( @@ -476,6 +486,9 @@ displayed_groups(GroupsOpts, SelectedGroupsOpts) -> [G || G <- DisplayedGroups, not lists:member(disabled, 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) -> Groups = lists:filter( fun({_Group, Opts}) -> @@ -483,6 +496,9 @@ get_special_displayed_groups(GroupsOpts) -> end, GroupsOpts), displayed_groups(GroupsOpts, Groups). +%% Given a username and server, and a list of group names with options, +%% for the list of groups of that server that user is member +%% get the list of groups displayed get_user_displayed_groups(LUser, LServer, GroupsOpts) -> Groups = case catch mnesia:dirty_read(sr_user, {LUser, LServer}) of Rs when is_list(Rs) -> @@ -493,6 +509,7 @@ get_user_displayed_groups(LUser, LServer, GroupsOpts) -> end, displayed_groups(GroupsOpts, Groups). +%% @doc Get the list of groups that are displayed to this user get_user_displayed_groups(US) -> Host = element(2, US), DisplayedGroups1 = @@ -515,22 +532,60 @@ is_user_in_group({_U, S} = US, Group, Host) -> _ -> true end. + +%% @spec (Host::string(), {User::string(), Server::string()}, Group::string()) -> {atomic, ok} add_user_to_group(Host, US, Group) -> + {LUser, LServer} = US, + %% Push this new user to members of groups where this group is displayed + push_user_to_displayed(LUser, LServer, Group, both), + %% Push members of groups that are displayed to this group + push_displayed_to_user(LUser, LServer, Group, Host, both), R = #sr_user{us = US, group_host = {Group, Host}}, F = fun() -> mnesia:write(R) end, mnesia:transaction(F). +push_displayed_to_user(LUser, LServer, Group, Host, Subscription) -> + GroupsOpts = groups_with_opts(LServer), + GroupOpts = proplists:get_value(Group, GroupsOpts, []), + DisplayedGroups = proplists:get_value(displayed_groups, GroupOpts, []), + [push_members_to_user(LUser, LServer, DGroup, Host, Subscription) || DGroup <- DisplayedGroups]. + remove_user_from_group(Host, US, Group) -> GroupHost = {Group, Host}, R = #sr_user{us = US, group_host = GroupHost}, F = fun() -> mnesia:delete_object(R) end, - mnesia:transaction(F). + Result = mnesia:transaction(F), + {LUser, LServer} = US, + %% Push removal of the old user to members of groups where the group that this user was members was displayed + push_user_to_displayed(LUser, LServer, Group, remove), + %% Push removal of members of groups that where displayed to the group which this user has left + push_displayed_to_user(LUser, LServer, Group, Host, remove), + Result. -user_registered(User, Server) -> +push_members_to_user(LUser, LServer, Group, Host, Subscription) -> + GroupsOpts = groups_with_opts(LServer), + GroupOpts = proplists:get_value(Group, GroupsOpts, []), + GroupName = proplists:get_value(name, GroupOpts, Group), + Members = get_group_users(Host, Group), + lists:foreach( + fun({U, S}) -> + push_roster_item(LUser, LServer, U, S, GroupName, Subscription) + end, Members). + +register_user(User, Server) -> + %% Get list of groups where this user is member + Groups = get_user_groups({User, Server}), + %% Push this user to members of groups where is displayed a group which this user is member + [push_user_to_displayed(User, Server, Group, both) || Group <- Groups]. + +remove_user(User, Server) -> + push_user_to_members(User, Server, remove). + +push_user_to_members(User, Server, Subscription) -> try LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), @@ -543,14 +598,7 @@ user_registered(User, Server) -> GroupName = proplists:get_value(name, GroupOpts, Group), lists:foreach( fun({U, S}) -> - Item = #roster{usj = {U, S, {LUser, LServer, undefined}}, - us = {U, S}, - jid = {LUser, LServer, undefined}, - name = "", - subscription = both, - ask = none, - groups = [GroupName]}, - push_item(U, S, exmpp_jid:make_bare_jid(S), Item) + push_roster_item(U, S, LUser, LServer, GroupName, Subscription) end, get_group_users(LUser, LServer, Group, GroupOpts)) end, lists:usort(SpecialGroups++UserGroups)) catch @@ -558,6 +606,27 @@ user_registered(User, Server) -> ok end. +push_user_to_displayed(LUser, LServer, Group, Subscription) -> + GroupsOpts = groups_with_opts(LServer), + GroupOpts = proplists:get_value(Group, GroupsOpts, []), + GroupName = proplists:get_value(name, GroupOpts, Group), + DisplayedToGroupsOpts = displayed_to_groups(Group, LServer), + [push_user_to_group(LUser, LServer, GroupD, GroupName, Subscription) || {GroupD, _Opts} <- DisplayedToGroupsOpts]. + +push_user_to_group(LUser, LServer, Group, GroupName, Subscription) -> + lists:foreach( + fun({U, S}) -> + push_roster_item(U, S, LUser, LServer, GroupName, Subscription) + end, get_group_users(LServer, Group)). + +%% Get list of groups to which this group is displayed +displayed_to_groups(GroupName, LServer) -> + GroupsOpts = groups_with_opts(LServer), + lists:filter( + fun({_Group, Opts}) -> + lists:member(GroupName, proplists:get_value(displayed_groups, Opts, [])) + end, GroupsOpts). + push_item(_User, _Server, _From, none) -> ok; push_item(User, Server, From, Item) -> @@ -580,6 +649,16 @@ push_item(User, Server, From, Item) -> ejabberd_router:route(JID, JID, Stanza) end, ejabberd_sm:get_user_resources(list_to_binary(User), list_to_binary(Server))). +push_roster_item(User, Server, ContactU, ContactS, GroupName, Subscription) -> + Item = #roster{usj = {User, Server, {ContactU, ContactS, ""}}, + us = {User, Server}, + jid = {ContactU, ContactS, ""}, + name = "", + subscription = Subscription, + ask = none, + groups = [GroupName]}, + push_item(User, Server, jlib:make_jid("", Server, ""), Item). + item_to_xml(Item) -> {U, S, R} = Item#roster.jid, Attrs1 = exmpp_xml:set_attribute_in_list([], diff --git a/src/odbc/odbc_queries.erl b/src/odbc/odbc_queries.erl index c9f6819be..a2fb0ae41 100644 --- a/src/odbc/odbc_queries.erl +++ b/src/odbc/odbc_queries.erl @@ -376,7 +376,7 @@ get_private_data(LServer, Username, LXMLNS) -> "namespace='", LXMLNS, "';"]). del_user_private_storage(LServer, Username) -> - ejabberd_odbc:sql_transaction( + ejabberd_odbc:sql_query( LServer, ["delete from private_storage where username='", Username, "';"]). From 8a27b5446d8a039a27160aecf1d0488b371b792d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 19 Jan 2009 10:14:55 +0000 Subject: [PATCH 167/582] Fix accesses to the new #jid opaque type. PR: EJABP-1 SVN Revision: 1825 --- ChangeLog | 5 +++++ src/ejabberd_auth_anonymous.erl | 9 ++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index bb509b737..d80608647 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-01-19 Jean-Sébastien Pédron + + * src/ejabberd_auth_anonymous.erl: Fix accesses to the new #jid opaque + type. + 2009-01-16 Jean-Sébastien Pédron Merge from trunk (r1734 to r1752). diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index 955a0dc06..622c6c500 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -54,7 +54,6 @@ plain_password_required/0]). -include("ejabberd.hrl"). --include("jlib.hrl"). -record(anonymous, {us, sid}). %% Create the anonymous table if at least one virtual host has anonymous features enabled @@ -141,7 +140,9 @@ remove_connection(SID, LUser, LServer) -> mnesia:transaction(F). %% Register connection -register_connection(SID, #jid{luser = LUser, lserver = LServer}, Info) -> +register_connection(SID, JID, Info) -> + LUser = exmpp_jid:lnode(JID), + LServer = exmpp_jid:ldomain(JID), case proplists:get_value(auth_module, Info) of undefined -> ok; @@ -155,7 +156,9 @@ register_connection(SID, #jid{luser = LUser, lserver = LServer}, Info) -> end. %% Remove an anonymous user from the anonymous users table -unregister_connection(SID, #jid{luser = LUser, lserver = LServer}, _) -> +unregister_connection(SID, JID, _) -> + LUser = exmpp_jid:lnode(JID), + LServer = exmpp_jid:ldomain(JID), purge_hook(anonymous_user_exist(LUser, LServer), LUser, LServer), remove_connection(SID, LUser, LServer). From bc51bd0dbd9762bddcccf1b8f43922eafb8e55ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 19 Jan 2009 11:16:44 +0000 Subject: [PATCH 168/582] Merge from trunk (r1752 to r1764). Warning: Ejabberd may be broken until the merge is completly finished. PR: EJABP-1 SVN Revision: 1826 --- ChangeLog | 56 ++ doc/guide.html | 8 + doc/guide.tex | 4 + src/aclocal.m4 | 17 +- src/configure | 1243 ++++++++++++++++---------------- src/configure.ac | 18 +- src/ejabberd.cfg.example | 7 + src/ejabberd_c2s.erl | 26 +- src/ejabberd_config.erl | 2 + src/ejabberd_s2s_out.erl | 111 ++- src/ejabberd_socket.erl | 6 +- src/mod_privacy_odbc.erl | 98 +-- src/mod_roster_odbc.erl | 38 +- src/odbc/ejabberd_odbc.erl | 41 +- src/odbc/odbc_queries.erl | 239 ++++-- src/web/ejabberd_web_admin.erl | 15 +- 16 files changed, 1074 insertions(+), 855 deletions(-) diff --git a/ChangeLog b/ChangeLog index d80608647..64f489264 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-01-19 Jean-Sébastien Pédron + + Merge from trunk (r1752 to r1764). + 2009-01-19 Jean-Sébastien Pédron * src/ejabberd_auth_anonymous.erl: Fix accesses to the new #jid opaque @@ -160,6 +164,58 @@ * src/mod_pubsub/mod_pubsub.erl: Added "access-whitelist" and "member-affiliation" features (thanks to Andy Skelton)(EJAB-780) +2008-12-29 Alexey Shchepin + + * src/ejabberd_c2s.erl: Bugfix in "from" attribute checking + +2008-12-29 Evgeniy Khramtsov + + * src/odbc/ejabberd_odbc.erl: Print meaningful error message when + an SQL transaction exceeds number of restarts. Also rollbacks + this transaction to prevent deadlocks. + + * src/odbc/odbc_queries.erl: replaced string:join/2 function. + Removed ugly "catch" statement from update_t/4. + WARNING: this change requires last version of mysql driver. + You can update it from ejabberd-modules repository. + +2008-12-28 Mickael Remond + + * src/ejabberd_c2s.erl: We should allow use of bare resource in from by + the client (partially revert r1727) (EJAB-812). + +2008-12-26 Badlop + + * src/web/ejabberd_web_admin.erl: Show in ejabberd Web Admin the + connection method and connected node of Jabber clients (thanks to + Oleg Palij)(EJAB-319) + + * src/ejabberd_config.erl: Option outgoing_s2s_options to define + s2s outgoing behaviour: IPv4, IPv6 and timeout (thanks to Stephan + Maka)(EJAB-665) + * src/ejabberd_s2s_out.erl: Likewise + * src/ejabberd_socket.erl: Likewise + * src/ejabberd.cfg.example: Likewise + * doc/guide.tex: Likewise + * doc/guide.html: Likewise + +2008-12-26 Evgeniy Khramtsov + + * src/odbc/ejabberd_odbc.erl: get rid of SERIALIZABLE isolation + level on MySQL connections. + * src/odbc/odbc_queries.erl: replaces all delete->insert chains + with update->insert. + * src/mod_privacy_odbc.erl: moved sql queries to odbc_queries.erl. + * src/mod_roster_odbc.erl: changed interface for odbc_queries.erl. + +2008-12-24 Badlop + + * src/aclocal.m4: Fixes in configure script: fix + disable-ejabberd_zlib and disable-pam; in case of problems, PAM + verification aborts with error instead of warning. (EJAB-787) + * src/configure.ac: Likewise + * src/configure: Likewise + 2008-12-23 Badlop * src/acl.erl: New ACL: shared_group (thanks to Maxim Ryazanov) diff --git a/doc/guide.html b/doc/guide.html index 2982f355d..6d143c335 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -745,6 +745,10 @@ use STARTTLS for s2s connections. file containing a SSL certificate.
      {domain_certfile, Domain, Path}
      Full path to the file containing the SSL certificate for a specific domain. +
      {outgoing_s2s_options, Methods, Timeout}
      +Specify which address families to try, in what order, and connect timeout in milliseconds. +By default it first tries connecting with IPv4, if that fails it tries using IPv6, +with a timeout of 10000 milliseconds.
      {s2s_default_policy, allow|deny}
      The default policy for incoming and outgoing s2s connections to other Jabber servers. The default value is allow. @@ -1032,6 +1036,10 @@ declarations of ACLs in the configuration file have the following syntax:
      {resource, <resource>}
      Matches any JID with a resource <resource>. Example:
      {acl, mucklres, {resource, "muckl"}}.
      +
      {shared_group, <groupname>}
      Matches any member of a Shared Roster Group with name <groupname> in the virtual host. Example: +
      {acl, techgroupmembers, {shared_group, "techteam"}}.
      +
      {shared_group, <groupname>, <server>}
      Matches any member of a Shared Roster Group with name <groupname> in the virtual host <server>. Example: +
      {acl, techgroupmembers, {shared_group, "techteam", "example.org"}}.
       
      {user_regexp, <regexp>}
      Matches any local user with a name that matches <regexp> on local virtual hosts. Example:
      {acl, tests, {user_regexp, "^test[0-9]*$"}}.
      diff --git a/doc/guide.tex b/doc/guide.tex
      index 9501c0cc5..afc63a3ff 100644
      --- a/doc/guide.tex
      +++ b/doc/guide.tex
      @@ -870,6 +870,10 @@ There are some additional global options:
         file containing a SSL certificate.
         \titem{\{domain\_certfile, Domain, Path\}} \ind{options!domain\_certfile}
         Full path to the file containing the SSL certificate for a specific domain.
      +  \titem{\{outgoing\_s2s\_options, Methods, Timeout\}} \ind{options!outgoing\_s2s\_options}
      +  Specify which address families to try, in what order, and connect timeout in milliseconds.
      +  By default it first tries connecting with IPv4, if that fails it tries using IPv6,
      +  with a timeout of 10000 milliseconds.
         \titem{\{s2s\_default\_policy, allow|deny\}}
         The default policy for incoming and outgoing s2s connections to other Jabber servers.
         The default value is \term{allow}.
      diff --git a/src/aclocal.m4 b/src/aclocal.m4
      index 10a9e4bd1..5365443f0 100644
      --- a/src/aclocal.m4
      +++ b/src/aclocal.m4
      @@ -15,7 +15,7 @@ AC_DEFUN(AM_WITH_EXPAT,
       		     [ expat_found=no ],
       		     "$EXPAT_LIBS")
       	if test $expat_found = no; then
      -		AC_MSG_ERROR([Could not find the Expat library])
      +		AC_MSG_ERROR([Could not find development files of Expat library])
       	fi
       	expat_save_CFLAGS="$CFLAGS"
       	CFLAGS="$CFLAGS $EXPAT_CFLAGS"
      @@ -36,6 +36,7 @@ AC_DEFUN(AM_WITH_ZLIB,
       [ AC_ARG_WITH(zlib,
       	      [AC_HELP_STRING([--with-zlib=PREFIX], [prefix where zlib is installed])])
       
      +if test x"$ejabberd_zlib" != x; then
         ZLIB_CFLAGS=
         ZLIB_LIBS=
       	if test x"$with_zlib" != x; then
      @@ -49,7 +50,7 @@ AC_DEFUN(AM_WITH_ZLIB,
       		     [ zlib_found=no ],
       		     "$ZLIB_LIBS")
       	if test $zlib_found = no; then
      -		AC_MSG_ERROR([Could not find the zlib library])
      +		AC_MSG_ERROR([Could not find development files of zlib library. Install them or disable `ejabberd_zlib' with: --disable-ejabberd_zlib])
       	fi
       	zlib_save_CFLAGS="$CFLAGS"
       	CFLAGS="$CFLAGS $ZLIB_CFLAGS"
      @@ -57,19 +58,20 @@ AC_DEFUN(AM_WITH_ZLIB,
              CPPFLAGS="$CPPFLAGS $ZLIB_CFLAGS"
       	AC_CHECK_HEADERS(zlib.h, , zlib_found=no)
       	if test $zlib_found = no; then
      -		AC_MSG_ERROR([Could not find zlib.h])
      +		AC_MSG_ERROR([Could not find zlib.h. Install it or disable `ejabberd_zlib' with: --disable-ejabberd_zlib])
       	fi
       	CFLAGS="$zlib_save_CFLAGS"
              CPPFLAGS="$zlib_save_CPPFLAGS"
       
         AC_SUBST(ZLIB_CFLAGS)
         AC_SUBST(ZLIB_LIBS)
      +fi
       ])
       
       AC_DEFUN(AM_WITH_PAM,
       [ AC_ARG_WITH(pam,
       	      [AC_HELP_STRING([--with-pam=PREFIX], [prefix where PAM is installed])])
      -
      +if test x"$pam" != x; then
         PAM_CFLAGS=
         PAM_LIBS=
       	if test x"$with_pam" != x; then
      @@ -83,7 +85,7 @@ AC_DEFUN(AM_WITH_PAM,
       		     [ pam_found=no ],
       		     "$PAM_LIBS")
       	if test $pam_found = no; then
      -		AC_MSG_WARN([Could not find the PAM library])
      +		AC_MSG_ERROR([Could not find development files of PAM library. Install them or disable `pam' with: --disable-pam])
       	fi
       	pam_save_CFLAGS="$CFLAGS"
       	CFLAGS="$CFLAGS $PAM_CFLAGS"
      @@ -91,13 +93,14 @@ AC_DEFUN(AM_WITH_PAM,
              CPPFLAGS="$CPPFLAGS $PAM_CFLAGS"
       	AC_CHECK_HEADERS(security/pam_appl.h, , pam_found=no)
       	if test $pam_found = no; then
      -		AC_MSG_WARN([Could not find security/pam_appl.h])
      +		AC_MSG_ERROR([Could not find security/pam_appl.h. Install it or disable `pam' with: --disable-pam])
       	fi
       	CFLAGS="$pam_save_CFLAGS"
              CPPFLAGS="$pam_save_CPPFLAGS"
       
         AC_SUBST(PAM_CFLAGS)
         AC_SUBST(PAM_LIBS)
      +fi
       ])
       
       AC_DEFUN(AM_WITH_ERLANG,
      @@ -346,7 +349,7 @@ if test x"$tls" != x; then
               fi
           done
       if test x${have_openssl} != xyes; then
      -    AC_MSG_ERROR([openssl library cannot be found. Install openssl or disable `tls' module (--disable-tls).])
      +    AC_MSG_ERROR([Could not find development files of OpenSSL library. Install them or disable `tls' with: --disable-tls])
       fi
       AC_SUBST(SSL_LIBS)
       AC_SUBST(SSL_CFLAGS)
      diff --git a/src/configure b/src/configure
      index a6cc19b6c..ec6bd6d91 100755
      --- a/src/configure
      +++ b/src/configure
      @@ -672,31 +672,31 @@ GREP
       EGREP
       EXPAT_CFLAGS
       EXPAT_LIBS
      -ZLIB_CFLAGS
      -ZLIB_LIBS
      -PAM_CFLAGS
      -PAM_LIBS
       LIBOBJS
      -mod_pubsub
      -make_mod_pubsub
       mod_irc
       make_mod_irc
       mod_muc
       make_mod_muc
       mod_proxy65
       make_mod_proxy65
      +mod_pubsub
      +make_mod_pubsub
       eldap
       make_eldap
      -pam
      -make_pam
      -web
      -make_web
      -tls
      -make_tls
       odbc
       make_odbc
      +tls
      +make_tls
      +web
      +make_web
       ejabberd_zlib
       make_ejabberd_zlib
      +ZLIB_CFLAGS
      +ZLIB_LIBS
      +pam
      +make_pam
      +PAM_CFLAGS
      +PAM_LIBS
       hipe
       roster_gateway_workaround
       db_type
      @@ -1286,16 +1286,16 @@ if test -n "$ac_init_help"; then
       Optional Features:
         --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
         --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
      -  --enable-mod_pubsub     enable mod_pubsub (default: yes)
         --enable-mod_irc        enable mod_irc (default: yes)
         --enable-mod_muc        enable mod_muc (default: yes)
         --enable-mod_proxy65    enable mod_proxy65 (default: yes)
      +  --enable-mod_pubsub     enable mod_pubsub (default: yes)
         --enable-eldap          enable eldap (default: yes)
      -  --enable-pam            enable pam (default: no)
      -  --enable-web            enable web (default: yes)
      -  --enable-tls            enable tls (default: yes)
         --enable-odbc           enable odbc (default: no)
      +  --enable-tls            enable tls (default: yes)
      +  --enable-web            enable web (default: yes)
         --enable-ejabberd_zlib  enable ejabberd_zlib (default: yes)
      +  --enable-pam            enable pam (default: no)
         --enable-hipe           compile natively with HiPE, not recommended
                                 (default: no)
         --enable-roster-gateway-workaround
      @@ -4030,8 +4030,8 @@ else
       fi
       
       	if test $expat_found = no; then
      -		{ { echo "$as_me:$LINENO: error: Could not find the Expat library" >&5
      -echo "$as_me: error: Could not find the Expat library" >&2;}
      +		{ { echo "$as_me:$LINENO: error: Could not find development files of Expat library" >&5
      +echo "$as_me: error: Could not find development files of Expat library" >&2;}
          { (exit 1); exit 1; }; }
       	fi
       	expat_save_CFLAGS="$CFLAGS"
      @@ -4196,504 +4196,6 @@ echo "$as_me: error: Could not find expat.h" >&2;}
       
       
       
      -#locating zlib
      -
      -# Check whether --with-zlib was given.
      -if test "${with_zlib+set}" = set; then
      -  withval=$with_zlib;
      -fi
      -
      -
      -  ZLIB_CFLAGS=
      -  ZLIB_LIBS=
      -	if test x"$with_zlib" != x; then
      -		ZLIB_CFLAGS="-I$with_zlib/include"
      -		ZLIB_LIBS="-L$with_zlib/lib"
      -	fi
      -
      -	{ echo "$as_me:$LINENO: checking for gzgets in -lz" >&5
      -echo $ECHO_N "checking for gzgets in -lz... $ECHO_C" >&6; }
      -if test "${ac_cv_lib_z_gzgets+set}" = set; then
      -  echo $ECHO_N "(cached) $ECHO_C" >&6
      -else
      -  ac_check_lib_save_LIBS=$LIBS
      -LIBS="-lz "$ZLIB_LIBS" $LIBS"
      -cat >conftest.$ac_ext <<_ACEOF
      -/* confdefs.h.  */
      -_ACEOF
      -cat confdefs.h >>conftest.$ac_ext
      -cat >>conftest.$ac_ext <<_ACEOF
      -/* end confdefs.h.  */
      -
      -/* Override any GCC internal prototype to avoid an error.
      -   Use char because int might match the return type of a GCC
      -   builtin and then its argument prototype would still apply.  */
      -#ifdef __cplusplus
      -extern "C"
      -#endif
      -char gzgets ();
      -int
      -main ()
      -{
      -return gzgets ();
      -  ;
      -  return 0;
      -}
      -_ACEOF
      -rm -f conftest.$ac_objext conftest$ac_exeext
      -if { (ac_try="$ac_link"
      -case "(($ac_try" in
      -  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
      -  *) ac_try_echo=$ac_try;;
      -esac
      -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
      -  (eval "$ac_link") 2>conftest.er1
      -  ac_status=$?
      -  grep -v '^ *+' conftest.er1 >conftest.err
      -  rm -f conftest.er1
      -  cat conftest.err >&5
      -  echo "$as_me:$LINENO: \$? = $ac_status" >&5
      -  (exit $ac_status); } && {
      -	 test -z "$ac_c_werror_flag" ||
      -	 test ! -s conftest.err
      -       } && test -s conftest$ac_exeext &&
      -       $as_test_x conftest$ac_exeext; then
      -  ac_cv_lib_z_gzgets=yes
      -else
      -  echo "$as_me: failed program was:" >&5
      -sed 's/^/| /' conftest.$ac_ext >&5
      -
      -	ac_cv_lib_z_gzgets=no
      -fi
      -
      -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
      -      conftest$ac_exeext conftest.$ac_ext
      -LIBS=$ac_check_lib_save_LIBS
      -fi
      -{ echo "$as_me:$LINENO: result: $ac_cv_lib_z_gzgets" >&5
      -echo "${ECHO_T}$ac_cv_lib_z_gzgets" >&6; }
      -if test $ac_cv_lib_z_gzgets = yes; then
      -   ZLIB_LIBS="$ZLIB_LIBS -lz"
      -		       zlib_found=yes
      -else
      -   zlib_found=no
      -fi
      -
      -	if test $zlib_found = no; then
      -		{ { echo "$as_me:$LINENO: error: Could not find the zlib library" >&5
      -echo "$as_me: error: Could not find the zlib library" >&2;}
      -   { (exit 1); exit 1; }; }
      -	fi
      -	zlib_save_CFLAGS="$CFLAGS"
      -	CFLAGS="$CFLAGS $ZLIB_CFLAGS"
      -       zlib_save_CPPFLAGS="$CFLAGS"
      -       CPPFLAGS="$CPPFLAGS $ZLIB_CFLAGS"
      -
      -for ac_header in zlib.h
      -do
      -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
      -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
      -  { echo "$as_me:$LINENO: checking for $ac_header" >&5
      -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
      -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
      -  echo $ECHO_N "(cached) $ECHO_C" >&6
      -fi
      -ac_res=`eval echo '${'$as_ac_Header'}'`
      -	       { echo "$as_me:$LINENO: result: $ac_res" >&5
      -echo "${ECHO_T}$ac_res" >&6; }
      -else
      -  # Is the header compilable?
      -{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
      -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
      -cat >conftest.$ac_ext <<_ACEOF
      -/* confdefs.h.  */
      -_ACEOF
      -cat confdefs.h >>conftest.$ac_ext
      -cat >>conftest.$ac_ext <<_ACEOF
      -/* end confdefs.h.  */
      -$ac_includes_default
      -#include <$ac_header>
      -_ACEOF
      -rm -f conftest.$ac_objext
      -if { (ac_try="$ac_compile"
      -case "(($ac_try" in
      -  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
      -  *) ac_try_echo=$ac_try;;
      -esac
      -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
      -  (eval "$ac_compile") 2>conftest.er1
      -  ac_status=$?
      -  grep -v '^ *+' conftest.er1 >conftest.err
      -  rm -f conftest.er1
      -  cat conftest.err >&5
      -  echo "$as_me:$LINENO: \$? = $ac_status" >&5
      -  (exit $ac_status); } && {
      -	 test -z "$ac_c_werror_flag" ||
      -	 test ! -s conftest.err
      -       } && test -s conftest.$ac_objext; then
      -  ac_header_compiler=yes
      -else
      -  echo "$as_me: failed program was:" >&5
      -sed 's/^/| /' conftest.$ac_ext >&5
      -
      -	ac_header_compiler=no
      -fi
      -
      -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
      -{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
      -echo "${ECHO_T}$ac_header_compiler" >&6; }
      -
      -# Is the header present?
      -{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
      -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
      -cat >conftest.$ac_ext <<_ACEOF
      -/* confdefs.h.  */
      -_ACEOF
      -cat confdefs.h >>conftest.$ac_ext
      -cat >>conftest.$ac_ext <<_ACEOF
      -/* end confdefs.h.  */
      -#include <$ac_header>
      -_ACEOF
      -if { (ac_try="$ac_cpp conftest.$ac_ext"
      -case "(($ac_try" in
      -  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
      -  *) ac_try_echo=$ac_try;;
      -esac
      -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
      -  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
      -  ac_status=$?
      -  grep -v '^ *+' conftest.er1 >conftest.err
      -  rm -f conftest.er1
      -  cat conftest.err >&5
      -  echo "$as_me:$LINENO: \$? = $ac_status" >&5
      -  (exit $ac_status); } >/dev/null && {
      -	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
      -	 test ! -s conftest.err
      -       }; then
      -  ac_header_preproc=yes
      -else
      -  echo "$as_me: failed program was:" >&5
      -sed 's/^/| /' conftest.$ac_ext >&5
      -
      -  ac_header_preproc=no
      -fi
      -
      -rm -f conftest.err conftest.$ac_ext
      -{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
      -echo "${ECHO_T}$ac_header_preproc" >&6; }
      -
      -# So?  What about this header?
      -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
      -  yes:no: )
      -    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
      -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
      -    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
      -echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
      -    ac_header_preproc=yes
      -    ;;
      -  no:yes:* )
      -    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
      -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
      -    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
      -echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
      -    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
      -echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
      -    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
      -echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
      -    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
      -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
      -    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
      -echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
      -    ( cat <<\_ASBOX
      -## --------------------------------------- ##
      -## Report this to ejabberd@process-one.net ##
      -## --------------------------------------- ##
      -_ASBOX
      -     ) | sed "s/^/$as_me: WARNING:     /" >&2
      -    ;;
      -esac
      -{ echo "$as_me:$LINENO: checking for $ac_header" >&5
      -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
      -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
      -  echo $ECHO_N "(cached) $ECHO_C" >&6
      -else
      -  eval "$as_ac_Header=\$ac_header_preproc"
      -fi
      -ac_res=`eval echo '${'$as_ac_Header'}'`
      -	       { echo "$as_me:$LINENO: result: $ac_res" >&5
      -echo "${ECHO_T}$ac_res" >&6; }
      -
      -fi
      -if test `eval echo '${'$as_ac_Header'}'` = yes; then
      -  cat >>confdefs.h <<_ACEOF
      -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
      -_ACEOF
      -
      -else
      -  zlib_found=no
      -fi
      -
      -done
      -
      -	if test $zlib_found = no; then
      -		{ { echo "$as_me:$LINENO: error: Could not find zlib.h" >&5
      -echo "$as_me: error: Could not find zlib.h" >&2;}
      -   { (exit 1); exit 1; }; }
      -	fi
      -	CFLAGS="$zlib_save_CFLAGS"
      -       CPPFLAGS="$zlib_save_CPPFLAGS"
      -
      -
      -
      -
      -#locating PAM
      -
      -# Check whether --with-pam was given.
      -if test "${with_pam+set}" = set; then
      -  withval=$with_pam;
      -fi
      -
      -
      -  PAM_CFLAGS=
      -  PAM_LIBS=
      -	if test x"$with_pam" != x; then
      -		PAM_CFLAGS="-I$with_pam/include"
      -		PAM_LIBS="-L$with_pam/lib"
      -	fi
      -
      -	{ echo "$as_me:$LINENO: checking for pam_start in -lpam" >&5
      -echo $ECHO_N "checking for pam_start in -lpam... $ECHO_C" >&6; }
      -if test "${ac_cv_lib_pam_pam_start+set}" = set; then
      -  echo $ECHO_N "(cached) $ECHO_C" >&6
      -else
      -  ac_check_lib_save_LIBS=$LIBS
      -LIBS="-lpam "$PAM_LIBS" $LIBS"
      -cat >conftest.$ac_ext <<_ACEOF
      -/* confdefs.h.  */
      -_ACEOF
      -cat confdefs.h >>conftest.$ac_ext
      -cat >>conftest.$ac_ext <<_ACEOF
      -/* end confdefs.h.  */
      -
      -/* Override any GCC internal prototype to avoid an error.
      -   Use char because int might match the return type of a GCC
      -   builtin and then its argument prototype would still apply.  */
      -#ifdef __cplusplus
      -extern "C"
      -#endif
      -char pam_start ();
      -int
      -main ()
      -{
      -return pam_start ();
      -  ;
      -  return 0;
      -}
      -_ACEOF
      -rm -f conftest.$ac_objext conftest$ac_exeext
      -if { (ac_try="$ac_link"
      -case "(($ac_try" in
      -  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
      -  *) ac_try_echo=$ac_try;;
      -esac
      -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
      -  (eval "$ac_link") 2>conftest.er1
      -  ac_status=$?
      -  grep -v '^ *+' conftest.er1 >conftest.err
      -  rm -f conftest.er1
      -  cat conftest.err >&5
      -  echo "$as_me:$LINENO: \$? = $ac_status" >&5
      -  (exit $ac_status); } && {
      -	 test -z "$ac_c_werror_flag" ||
      -	 test ! -s conftest.err
      -       } && test -s conftest$ac_exeext &&
      -       $as_test_x conftest$ac_exeext; then
      -  ac_cv_lib_pam_pam_start=yes
      -else
      -  echo "$as_me: failed program was:" >&5
      -sed 's/^/| /' conftest.$ac_ext >&5
      -
      -	ac_cv_lib_pam_pam_start=no
      -fi
      -
      -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
      -      conftest$ac_exeext conftest.$ac_ext
      -LIBS=$ac_check_lib_save_LIBS
      -fi
      -{ echo "$as_me:$LINENO: result: $ac_cv_lib_pam_pam_start" >&5
      -echo "${ECHO_T}$ac_cv_lib_pam_pam_start" >&6; }
      -if test $ac_cv_lib_pam_pam_start = yes; then
      -   PAM_LIBS="$PAM_LIBS -lpam"
      -		       pam_found=yes
      -else
      -   pam_found=no
      -fi
      -
      -	if test $pam_found = no; then
      -		{ echo "$as_me:$LINENO: WARNING: Could not find the PAM library" >&5
      -echo "$as_me: WARNING: Could not find the PAM library" >&2;}
      -	fi
      -	pam_save_CFLAGS="$CFLAGS"
      -	CFLAGS="$CFLAGS $PAM_CFLAGS"
      -       pam_save_CPPFLAGS="$CPPFLAGS"
      -       CPPFLAGS="$CPPFLAGS $PAM_CFLAGS"
      -
      -for ac_header in security/pam_appl.h
      -do
      -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
      -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
      -  { echo "$as_me:$LINENO: checking for $ac_header" >&5
      -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
      -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
      -  echo $ECHO_N "(cached) $ECHO_C" >&6
      -fi
      -ac_res=`eval echo '${'$as_ac_Header'}'`
      -	       { echo "$as_me:$LINENO: result: $ac_res" >&5
      -echo "${ECHO_T}$ac_res" >&6; }
      -else
      -  # Is the header compilable?
      -{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
      -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
      -cat >conftest.$ac_ext <<_ACEOF
      -/* confdefs.h.  */
      -_ACEOF
      -cat confdefs.h >>conftest.$ac_ext
      -cat >>conftest.$ac_ext <<_ACEOF
      -/* end confdefs.h.  */
      -$ac_includes_default
      -#include <$ac_header>
      -_ACEOF
      -rm -f conftest.$ac_objext
      -if { (ac_try="$ac_compile"
      -case "(($ac_try" in
      -  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
      -  *) ac_try_echo=$ac_try;;
      -esac
      -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
      -  (eval "$ac_compile") 2>conftest.er1
      -  ac_status=$?
      -  grep -v '^ *+' conftest.er1 >conftest.err
      -  rm -f conftest.er1
      -  cat conftest.err >&5
      -  echo "$as_me:$LINENO: \$? = $ac_status" >&5
      -  (exit $ac_status); } && {
      -	 test -z "$ac_c_werror_flag" ||
      -	 test ! -s conftest.err
      -       } && test -s conftest.$ac_objext; then
      -  ac_header_compiler=yes
      -else
      -  echo "$as_me: failed program was:" >&5
      -sed 's/^/| /' conftest.$ac_ext >&5
      -
      -	ac_header_compiler=no
      -fi
      -
      -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
      -{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
      -echo "${ECHO_T}$ac_header_compiler" >&6; }
      -
      -# Is the header present?
      -{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
      -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
      -cat >conftest.$ac_ext <<_ACEOF
      -/* confdefs.h.  */
      -_ACEOF
      -cat confdefs.h >>conftest.$ac_ext
      -cat >>conftest.$ac_ext <<_ACEOF
      -/* end confdefs.h.  */
      -#include <$ac_header>
      -_ACEOF
      -if { (ac_try="$ac_cpp conftest.$ac_ext"
      -case "(($ac_try" in
      -  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
      -  *) ac_try_echo=$ac_try;;
      -esac
      -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
      -  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
      -  ac_status=$?
      -  grep -v '^ *+' conftest.er1 >conftest.err
      -  rm -f conftest.er1
      -  cat conftest.err >&5
      -  echo "$as_me:$LINENO: \$? = $ac_status" >&5
      -  (exit $ac_status); } >/dev/null && {
      -	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
      -	 test ! -s conftest.err
      -       }; then
      -  ac_header_preproc=yes
      -else
      -  echo "$as_me: failed program was:" >&5
      -sed 's/^/| /' conftest.$ac_ext >&5
      -
      -  ac_header_preproc=no
      -fi
      -
      -rm -f conftest.err conftest.$ac_ext
      -{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
      -echo "${ECHO_T}$ac_header_preproc" >&6; }
      -
      -# So?  What about this header?
      -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
      -  yes:no: )
      -    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
      -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
      -    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
      -echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
      -    ac_header_preproc=yes
      -    ;;
      -  no:yes:* )
      -    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
      -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
      -    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
      -echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
      -    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
      -echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
      -    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
      -echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
      -    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
      -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
      -    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
      -echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
      -    ( cat <<\_ASBOX
      -## --------------------------------------- ##
      -## Report this to ejabberd@process-one.net ##
      -## --------------------------------------- ##
      -_ASBOX
      -     ) | sed "s/^/$as_me: WARNING:     /" >&2
      -    ;;
      -esac
      -{ echo "$as_me:$LINENO: checking for $ac_header" >&5
      -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
      -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
      -  echo $ECHO_N "(cached) $ECHO_C" >&6
      -else
      -  eval "$as_ac_Header=\$ac_header_preproc"
      -fi
      -ac_res=`eval echo '${'$as_ac_Header'}'`
      -	       { echo "$as_me:$LINENO: result: $ac_res" >&5
      -echo "${ECHO_T}$ac_res" >&6; }
      -
      -fi
      -if test `eval echo '${'$as_ac_Header'}'` = yes; then
      -  cat >>confdefs.h <<_ACEOF
      -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
      -_ACEOF
      -
      -else
      -  pam_found=no
      -fi
      -
      -done
      -
      -	if test $pam_found = no; then
      -		{ echo "$as_me:$LINENO: WARNING: Could not find security/pam_appl.h" >&5
      -echo "$as_me: WARNING: Could not find security/pam_appl.h" >&2;}
      -	fi
      -	CFLAGS="$pam_save_CFLAGS"
      -       CPPFLAGS="$pam_save_CPPFLAGS"
      -
      -
      -
      -
       
       # Checks for typedefs, structures, and compiler characteristics.
       { echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
      @@ -5221,28 +4723,6 @@ fi
       
       
       
      -mod_pubsub=
      -make_mod_pubsub=
      -{ echo "$as_me:$LINENO: checking whether build mod_pubsub" >&5
      -echo $ECHO_N "checking whether build mod_pubsub... $ECHO_C" >&6; }
      -# Check whether --enable-mod_pubsub was given.
      -if test "${enable_mod_pubsub+set}" = set; then
      -  enableval=$enable_mod_pubsub; mr_enable_mod_pubsub="$enableval"
      -else
      -  mr_enable_mod_pubsub=yes
      -fi
      -
      -if test "$mr_enable_mod_pubsub" = "yes"; then
      -mod_pubsub=mod_pubsub
      -make_mod_pubsub=mod_pubsub/Makefile
      -fi
      -{ echo "$as_me:$LINENO: result: $mr_enable_mod_pubsub" >&5
      -echo "${ECHO_T}$mr_enable_mod_pubsub" >&6; }
      -
      -
      -
      -
      -
       mod_irc=
       make_mod_irc=
       { echo "$as_me:$LINENO: checking whether build mod_irc" >&5
      @@ -5309,6 +4789,28 @@ echo "${ECHO_T}$mr_enable_mod_proxy65" >&6; }
       
       
       
      +mod_pubsub=
      +make_mod_pubsub=
      +{ echo "$as_me:$LINENO: checking whether build mod_pubsub" >&5
      +echo $ECHO_N "checking whether build mod_pubsub... $ECHO_C" >&6; }
      +# Check whether --enable-mod_pubsub was given.
      +if test "${enable_mod_pubsub+set}" = set; then
      +  enableval=$enable_mod_pubsub; mr_enable_mod_pubsub="$enableval"
      +else
      +  mr_enable_mod_pubsub=yes
      +fi
      +
      +if test "$mr_enable_mod_pubsub" = "yes"; then
      +mod_pubsub=mod_pubsub
      +make_mod_pubsub=mod_pubsub/Makefile
      +fi
      +{ echo "$as_me:$LINENO: result: $mr_enable_mod_pubsub" >&5
      +echo "${ECHO_T}$mr_enable_mod_pubsub" >&6; }
      +
      +
      +
      +
      +
       eldap=
       make_eldap=
       { echo "$as_me:$LINENO: checking whether build eldap" >&5
      @@ -5331,72 +4833,6 @@ echo "${ECHO_T}$mr_enable_eldap" >&6; }
       
       
       
      -pam=
      -make_pam=
      -{ echo "$as_me:$LINENO: checking whether build pam" >&5
      -echo $ECHO_N "checking whether build pam... $ECHO_C" >&6; }
      -# Check whether --enable-pam was given.
      -if test "${enable_pam+set}" = set; then
      -  enableval=$enable_pam; mr_enable_pam="$enableval"
      -else
      -  mr_enable_pam=no
      -fi
      -
      -if test "$mr_enable_pam" = "yes"; then
      -pam=pam
      -make_pam=pam/Makefile
      -fi
      -{ echo "$as_me:$LINENO: result: $mr_enable_pam" >&5
      -echo "${ECHO_T}$mr_enable_pam" >&6; }
      -
      -
      -
      -
      -
      -web=
      -make_web=
      -{ echo "$as_me:$LINENO: checking whether build web" >&5
      -echo $ECHO_N "checking whether build web... $ECHO_C" >&6; }
      -# Check whether --enable-web was given.
      -if test "${enable_web+set}" = set; then
      -  enableval=$enable_web; mr_enable_web="$enableval"
      -else
      -  mr_enable_web=yes
      -fi
      -
      -if test "$mr_enable_web" = "yes"; then
      -web=web
      -make_web=web/Makefile
      -fi
      -{ echo "$as_me:$LINENO: result: $mr_enable_web" >&5
      -echo "${ECHO_T}$mr_enable_web" >&6; }
      -
      -
      -
      -
      -
      -tls=
      -make_tls=
      -{ echo "$as_me:$LINENO: checking whether build tls" >&5
      -echo $ECHO_N "checking whether build tls... $ECHO_C" >&6; }
      -# Check whether --enable-tls was given.
      -if test "${enable_tls+set}" = set; then
      -  enableval=$enable_tls; mr_enable_tls="$enableval"
      -else
      -  mr_enable_tls=yes
      -fi
      -
      -if test "$mr_enable_tls" = "yes"; then
      -tls=tls
      -make_tls=tls/Makefile
      -fi
      -{ echo "$as_me:$LINENO: result: $mr_enable_tls" >&5
      -echo "${ECHO_T}$mr_enable_tls" >&6; }
      -
      -
      -
      -
      -
       odbc=
       make_odbc=
       { echo "$as_me:$LINENO: checking whether build odbc" >&5
      @@ -5419,6 +4855,51 @@ echo "${ECHO_T}$mr_enable_odbc" >&6; }
       
       
       
      +tls=
      +make_tls=
      +{ echo "$as_me:$LINENO: checking whether build tls" >&5
      +echo $ECHO_N "checking whether build tls... $ECHO_C" >&6; }
      +# Check whether --enable-tls was given.
      +if test "${enable_tls+set}" = set; then
      +  enableval=$enable_tls; mr_enable_tls="$enableval"
      +else
      +  mr_enable_tls=yes
      +fi
      +
      +if test "$mr_enable_tls" = "yes"; then
      +tls=tls
      +make_tls=tls/Makefile
      +fi
      +{ echo "$as_me:$LINENO: result: $mr_enable_tls" >&5
      +echo "${ECHO_T}$mr_enable_tls" >&6; }
      +
      +
      +
      +
      +
      +web=
      +make_web=
      +{ echo "$as_me:$LINENO: checking whether build web" >&5
      +echo $ECHO_N "checking whether build web... $ECHO_C" >&6; }
      +# Check whether --enable-web was given.
      +if test "${enable_web+set}" = set; then
      +  enableval=$enable_web; mr_enable_web="$enableval"
      +else
      +  mr_enable_web=yes
      +fi
      +
      +if test "$mr_enable_web" = "yes"; then
      +web=web
      +make_web=web/Makefile
      +fi
      +{ echo "$as_me:$LINENO: result: $mr_enable_web" >&5
      +echo "${ECHO_T}$mr_enable_web" >&6; }
      +
      +
      +
      +
      +
      +
       ejabberd_zlib=
       make_ejabberd_zlib=
       { echo "$as_me:$LINENO: checking whether build ejabberd_zlib" >&5
      @@ -5440,6 +4921,532 @@ echo "${ECHO_T}$mr_enable_ejabberd_zlib" >&6; }
       
       
       
      +#locating zlib
      +
      +# Check whether --with-zlib was given.
      +if test "${with_zlib+set}" = set; then
      +  withval=$with_zlib;
      +fi
      +
      +
      +if test x"$ejabberd_zlib" != x; then
      +  ZLIB_CFLAGS=
      +  ZLIB_LIBS=
      +	if test x"$with_zlib" != x; then
      +		ZLIB_CFLAGS="-I$with_zlib/include"
      +		ZLIB_LIBS="-L$with_zlib/lib"
      +	fi
      +
      +	{ echo "$as_me:$LINENO: checking for gzgets in -lz" >&5
      +echo $ECHO_N "checking for gzgets in -lz... $ECHO_C" >&6; }
      +if test "${ac_cv_lib_z_gzgets+set}" = set; then
      +  echo $ECHO_N "(cached) $ECHO_C" >&6
      +else
      +  ac_check_lib_save_LIBS=$LIBS
      +LIBS="-lz "$ZLIB_LIBS" $LIBS"
      +cat >conftest.$ac_ext <<_ACEOF
      +/* confdefs.h.  */
      +_ACEOF
      +cat confdefs.h >>conftest.$ac_ext
      +cat >>conftest.$ac_ext <<_ACEOF
      +/* end confdefs.h.  */
      +
      +/* Override any GCC internal prototype to avoid an error.
      +   Use char because int might match the return type of a GCC
      +   builtin and then its argument prototype would still apply.  */
      +#ifdef __cplusplus
      +extern "C"
      +#endif
      +char gzgets ();
      +int
      +main ()
      +{
      +return gzgets ();
      +  ;
      +  return 0;
      +}
      +_ACEOF
      +rm -f conftest.$ac_objext conftest$ac_exeext
      +if { (ac_try="$ac_link"
      +case "(($ac_try" in
      +  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
      +  *) ac_try_echo=$ac_try;;
      +esac
      +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
      +  (eval "$ac_link") 2>conftest.er1
      +  ac_status=$?
      +  grep -v '^ *+' conftest.er1 >conftest.err
      +  rm -f conftest.er1
      +  cat conftest.err >&5
      +  echo "$as_me:$LINENO: \$? = $ac_status" >&5
      +  (exit $ac_status); } && {
      +	 test -z "$ac_c_werror_flag" ||
      +	 test ! -s conftest.err
      +       } && test -s conftest$ac_exeext &&
      +       $as_test_x conftest$ac_exeext; then
      +  ac_cv_lib_z_gzgets=yes
      +else
      +  echo "$as_me: failed program was:" >&5
      +sed 's/^/| /' conftest.$ac_ext >&5
      +
      +	ac_cv_lib_z_gzgets=no
      +fi
      +
      +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
      +      conftest$ac_exeext conftest.$ac_ext
      +LIBS=$ac_check_lib_save_LIBS
      +fi
      +{ echo "$as_me:$LINENO: result: $ac_cv_lib_z_gzgets" >&5
      +echo "${ECHO_T}$ac_cv_lib_z_gzgets" >&6; }
      +if test $ac_cv_lib_z_gzgets = yes; then
      +   ZLIB_LIBS="$ZLIB_LIBS -lz"
      +		       zlib_found=yes
      +else
      +   zlib_found=no
      +fi
      +
      +	if test $zlib_found = no; then
      +		{ { echo "$as_me:$LINENO: error: Could not find development files of zlib library. Install them or disable \`ejabberd_zlib' with: --disable-ejabberd_zlib" >&5
      +echo "$as_me: error: Could not find development files of zlib library. Install them or disable \`ejabberd_zlib' with: --disable-ejabberd_zlib" >&2;}
      +   { (exit 1); exit 1; }; }
      +	fi
      +	zlib_save_CFLAGS="$CFLAGS"
      +	CFLAGS="$CFLAGS $ZLIB_CFLAGS"
      +       zlib_save_CPPFLAGS="$CFLAGS"
      +       CPPFLAGS="$CPPFLAGS $ZLIB_CFLAGS"
      +
      +for ac_header in zlib.h
      +do
      +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
      +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
      +  { echo "$as_me:$LINENO: checking for $ac_header" >&5
      +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
      +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
      +  echo $ECHO_N "(cached) $ECHO_C" >&6
      +fi
      +ac_res=`eval echo '${'$as_ac_Header'}'`
      +	       { echo "$as_me:$LINENO: result: $ac_res" >&5
      +echo "${ECHO_T}$ac_res" >&6; }
      +else
      +  # Is the header compilable?
      +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
      +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
      +cat >conftest.$ac_ext <<_ACEOF
      +/* confdefs.h.  */
      +_ACEOF
      +cat confdefs.h >>conftest.$ac_ext
      +cat >>conftest.$ac_ext <<_ACEOF
      +/* end confdefs.h.  */
      +$ac_includes_default
      +#include <$ac_header>
      +_ACEOF
      +rm -f conftest.$ac_objext
      +if { (ac_try="$ac_compile"
      +case "(($ac_try" in
      +  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
      +  *) ac_try_echo=$ac_try;;
      +esac
      +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
      +  (eval "$ac_compile") 2>conftest.er1
      +  ac_status=$?
      +  grep -v '^ *+' conftest.er1 >conftest.err
      +  rm -f conftest.er1
      +  cat conftest.err >&5
      +  echo "$as_me:$LINENO: \$? = $ac_status" >&5
      +  (exit $ac_status); } && {
      +	 test -z "$ac_c_werror_flag" ||
      +	 test ! -s conftest.err
      +       } && test -s conftest.$ac_objext; then
      +  ac_header_compiler=yes
      +else
      +  echo "$as_me: failed program was:" >&5
      +sed 's/^/| /' conftest.$ac_ext >&5
      +
      +	ac_header_compiler=no
      +fi
      +
      +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
      +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
      +echo "${ECHO_T}$ac_header_compiler" >&6; }
      +
      +# Is the header present?
      +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
      +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
      +cat >conftest.$ac_ext <<_ACEOF
      +/* confdefs.h.  */
      +_ACEOF
      +cat confdefs.h >>conftest.$ac_ext
      +cat >>conftest.$ac_ext <<_ACEOF
      +/* end confdefs.h.  */
      +#include <$ac_header>
      +_ACEOF
      +if { (ac_try="$ac_cpp conftest.$ac_ext"
      +case "(($ac_try" in
      +  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
      +  *) ac_try_echo=$ac_try;;
      +esac
      +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
      +  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
      +  ac_status=$?
      +  grep -v '^ *+' conftest.er1 >conftest.err
      +  rm -f conftest.er1
      +  cat conftest.err >&5
      +  echo "$as_me:$LINENO: \$? = $ac_status" >&5
      +  (exit $ac_status); } >/dev/null && {
      +	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
      +	 test ! -s conftest.err
      +       }; then
      +  ac_header_preproc=yes
      +else
      +  echo "$as_me: failed program was:" >&5
      +sed 's/^/| /' conftest.$ac_ext >&5
      +
      +  ac_header_preproc=no
      +fi
      +
      +rm -f conftest.err conftest.$ac_ext
      +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
      +echo "${ECHO_T}$ac_header_preproc" >&6; }
      +
      +# So?  What about this header?
      +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
      +  yes:no: )
      +    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
      +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
      +    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
      +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
      +    ac_header_preproc=yes
      +    ;;
      +  no:yes:* )
      +    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
      +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
      +    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
      +echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
      +    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
      +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
      +    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
      +echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
      +    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
      +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
      +    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
      +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
      +    ( cat <<\_ASBOX
      +## --------------------------------------- ##
      +## Report this to ejabberd@process-one.net ##
      +## --------------------------------------- ##
      +_ASBOX
      +     ) | sed "s/^/$as_me: WARNING:     /" >&2
      +    ;;
      +esac
      +{ echo "$as_me:$LINENO: checking for $ac_header" >&5
      +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
      +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
      +  echo $ECHO_N "(cached) $ECHO_C" >&6
      +else
      +  eval "$as_ac_Header=\$ac_header_preproc"
      +fi
      +ac_res=`eval echo '${'$as_ac_Header'}'`
      +	       { echo "$as_me:$LINENO: result: $ac_res" >&5
      +echo "${ECHO_T}$ac_res" >&6; }
      +
      +fi
      +if test `eval echo '${'$as_ac_Header'}'` = yes; then
      +  cat >>confdefs.h <<_ACEOF
      +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
      +_ACEOF
      +
      +else
      +  zlib_found=no
      +fi
      +
      +done
      +
      +	if test $zlib_found = no; then
      +		{ { echo "$as_me:$LINENO: error: Could not find zlib.h. Install it or disable \`ejabberd_zlib' with: --disable-ejabberd_zlib" >&5
      +echo "$as_me: error: Could not find zlib.h. Install it or disable \`ejabberd_zlib' with: --disable-ejabberd_zlib" >&2;}
      +   { (exit 1); exit 1; }; }
      +	fi
      +	CFLAGS="$zlib_save_CFLAGS"
      +       CPPFLAGS="$zlib_save_CPPFLAGS"
      +
      +
      +
      +fi
      +
      +
      +
      +pam=
      +make_pam=
      +{ echo "$as_me:$LINENO: checking whether build pam" >&5
      +echo $ECHO_N "checking whether build pam... $ECHO_C" >&6; }
      +# Check whether --enable-pam was given.
      +if test "${enable_pam+set}" = set; then
      +  enableval=$enable_pam; mr_enable_pam="$enableval"
      +else
      +  mr_enable_pam=no
      +fi
      +
      +if test "$mr_enable_pam" = "yes"; then
      +pam=pam
      +make_pam=pam/Makefile
      +fi
      +{ echo "$as_me:$LINENO: result: $mr_enable_pam" >&5
      +echo "${ECHO_T}$mr_enable_pam" >&6; }
      +
      +
      +
      +
      +#locating PAM
      +
      +# Check whether --with-pam was given.
      +if test "${with_pam+set}" = set; then
      +  withval=$with_pam;
      +fi
      +
      +if test x"$pam" != x; then
      +  PAM_CFLAGS=
      +  PAM_LIBS=
      +	if test x"$with_pam" != x; then
      +		PAM_CFLAGS="-I$with_pam/include"
      +		PAM_LIBS="-L$with_pam/lib"
      +	fi
      +
      +	{ echo "$as_me:$LINENO: checking for pam_start in -lpam" >&5
      +echo $ECHO_N "checking for pam_start in -lpam... $ECHO_C" >&6; }
      +if test "${ac_cv_lib_pam_pam_start+set}" = set; then
      +  echo $ECHO_N "(cached) $ECHO_C" >&6
      +else
      +  ac_check_lib_save_LIBS=$LIBS
      +LIBS="-lpam "$PAM_LIBS" $LIBS"
      +cat >conftest.$ac_ext <<_ACEOF
      +/* confdefs.h.  */
      +_ACEOF
      +cat confdefs.h >>conftest.$ac_ext
      +cat >>conftest.$ac_ext <<_ACEOF
      +/* end confdefs.h.  */
      +
      +/* Override any GCC internal prototype to avoid an error.
      +   Use char because int might match the return type of a GCC
      +   builtin and then its argument prototype would still apply.  */
      +#ifdef __cplusplus
      +extern "C"
      +#endif
      +char pam_start ();
      +int
      +main ()
      +{
      +return pam_start ();
      +  ;
      +  return 0;
      +}
      +_ACEOF
      +rm -f conftest.$ac_objext conftest$ac_exeext
      +if { (ac_try="$ac_link"
      +case "(($ac_try" in
      +  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
      +  *) ac_try_echo=$ac_try;;
      +esac
      +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
      +  (eval "$ac_link") 2>conftest.er1
      +  ac_status=$?
      +  grep -v '^ *+' conftest.er1 >conftest.err
      +  rm -f conftest.er1
      +  cat conftest.err >&5
      +  echo "$as_me:$LINENO: \$? = $ac_status" >&5
      +  (exit $ac_status); } && {
      +	 test -z "$ac_c_werror_flag" ||
      +	 test ! -s conftest.err
      +       } && test -s conftest$ac_exeext &&
      +       $as_test_x conftest$ac_exeext; then
      +  ac_cv_lib_pam_pam_start=yes
      +else
      +  echo "$as_me: failed program was:" >&5
      +sed 's/^/| /' conftest.$ac_ext >&5
      +
      +	ac_cv_lib_pam_pam_start=no
      +fi
      +
      +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
      +      conftest$ac_exeext conftest.$ac_ext
      +LIBS=$ac_check_lib_save_LIBS
      +fi
      +{ echo "$as_me:$LINENO: result: $ac_cv_lib_pam_pam_start" >&5
      +echo "${ECHO_T}$ac_cv_lib_pam_pam_start" >&6; }
      +if test $ac_cv_lib_pam_pam_start = yes; then
      +   PAM_LIBS="$PAM_LIBS -lpam"
      +		       pam_found=yes
      +else
      +   pam_found=no
      +fi
      +
      +	if test $pam_found = no; then
      +		{ { echo "$as_me:$LINENO: error: Could not find development files of PAM library. Install them or disable \`pam' with: --disable-pam" >&5
      +echo "$as_me: error: Could not find development files of PAM library. Install them or disable \`pam' with: --disable-pam" >&2;}
      +   { (exit 1); exit 1; }; }
      +	fi
      +	pam_save_CFLAGS="$CFLAGS"
      +	CFLAGS="$CFLAGS $PAM_CFLAGS"
      +       pam_save_CPPFLAGS="$CPPFLAGS"
      +       CPPFLAGS="$CPPFLAGS $PAM_CFLAGS"
      +
      +for ac_header in security/pam_appl.h
      +do
      +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
      +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
      +  { echo "$as_me:$LINENO: checking for $ac_header" >&5
      +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
      +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
      +  echo $ECHO_N "(cached) $ECHO_C" >&6
      +fi
      +ac_res=`eval echo '${'$as_ac_Header'}'`
      +	       { echo "$as_me:$LINENO: result: $ac_res" >&5
      +echo "${ECHO_T}$ac_res" >&6; }
      +else
      +  # Is the header compilable?
      +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
      +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
      +cat >conftest.$ac_ext <<_ACEOF
      +/* confdefs.h.  */
      +_ACEOF
      +cat confdefs.h >>conftest.$ac_ext
      +cat >>conftest.$ac_ext <<_ACEOF
      +/* end confdefs.h.  */
      +$ac_includes_default
      +#include <$ac_header>
      +_ACEOF
      +rm -f conftest.$ac_objext
      +if { (ac_try="$ac_compile"
      +case "(($ac_try" in
      +  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
      +  *) ac_try_echo=$ac_try;;
      +esac
      +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
      +  (eval "$ac_compile") 2>conftest.er1
      +  ac_status=$?
      +  grep -v '^ *+' conftest.er1 >conftest.err
      +  rm -f conftest.er1
      +  cat conftest.err >&5
      +  echo "$as_me:$LINENO: \$? = $ac_status" >&5
      +  (exit $ac_status); } && {
      +	 test -z "$ac_c_werror_flag" ||
      +	 test ! -s conftest.err
      +       } && test -s conftest.$ac_objext; then
      +  ac_header_compiler=yes
      +else
      +  echo "$as_me: failed program was:" >&5
      +sed 's/^/| /' conftest.$ac_ext >&5
      +
      +	ac_header_compiler=no
      +fi
      +
      +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
      +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
      +echo "${ECHO_T}$ac_header_compiler" >&6; }
      +
      +# Is the header present?
      +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
      +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
      +cat >conftest.$ac_ext <<_ACEOF
      +/* confdefs.h.  */
      +_ACEOF
      +cat confdefs.h >>conftest.$ac_ext
      +cat >>conftest.$ac_ext <<_ACEOF
      +/* end confdefs.h.  */
      +#include <$ac_header>
      +_ACEOF
      +if { (ac_try="$ac_cpp conftest.$ac_ext"
      +case "(($ac_try" in
      +  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
      +  *) ac_try_echo=$ac_try;;
      +esac
      +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
      +  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
      +  ac_status=$?
      +  grep -v '^ *+' conftest.er1 >conftest.err
      +  rm -f conftest.er1
      +  cat conftest.err >&5
      +  echo "$as_me:$LINENO: \$? = $ac_status" >&5
      +  (exit $ac_status); } >/dev/null && {
      +	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
      +	 test ! -s conftest.err
      +       }; then
      +  ac_header_preproc=yes
      +else
      +  echo "$as_me: failed program was:" >&5
      +sed 's/^/| /' conftest.$ac_ext >&5
      +
      +  ac_header_preproc=no
      +fi
      +
      +rm -f conftest.err conftest.$ac_ext
      +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
      +echo "${ECHO_T}$ac_header_preproc" >&6; }
      +
      +# So?  What about this header?
      +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
      +  yes:no: )
      +    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
      +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
      +    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
      +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
      +    ac_header_preproc=yes
      +    ;;
      +  no:yes:* )
      +    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
      +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
      +    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
      +echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
      +    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
      +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
      +    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
      +echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
      +    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
      +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
      +    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
      +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
      +    ( cat <<\_ASBOX
      +## --------------------------------------- ##
      +## Report this to ejabberd@process-one.net ##
      +## --------------------------------------- ##
      +_ASBOX
      +     ) | sed "s/^/$as_me: WARNING:     /" >&2
      +    ;;
      +esac
      +{ echo "$as_me:$LINENO: checking for $ac_header" >&5
      +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
      +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
      +  echo $ECHO_N "(cached) $ECHO_C" >&6
      +else
      +  eval "$as_ac_Header=\$ac_header_preproc"
      +fi
      +ac_res=`eval echo '${'$as_ac_Header'}'`
      +	       { echo "$as_me:$LINENO: result: $ac_res" >&5
      +echo "${ECHO_T}$ac_res" >&6; }
      +
      +fi
      +if test `eval echo '${'$as_ac_Header'}'` = yes; then
      +  cat >>confdefs.h <<_ACEOF
      +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
      +_ACEOF
      +
      +else
      +  pam_found=no
      +fi
      +
      +done
      +
      +	if test $pam_found = no; then
      +		{ { echo "$as_me:$LINENO: error: Could not find security/pam_appl.h. Install it or disable \`pam' with: --disable-pam" >&5
      +echo "$as_me: error: Could not find security/pam_appl.h. Install it or disable \`pam' with: --disable-pam" >&2;}
      +   { (exit 1); exit 1; }; }
      +	fi
      +	CFLAGS="$pam_save_CFLAGS"
      +       CPPFLAGS="$pam_save_CPPFLAGS"
      +
      +
      +
      +fi
      +
       
       # Check whether --enable-hipe was given.
       if test "${enable_hipe+set}" = set; then
      @@ -5764,8 +5771,8 @@ done
               fi
           done
       if test x${have_openssl} != xyes; then
      -    { { echo "$as_me:$LINENO: error: openssl library cannot be found. Install openssl or disable \`tls' module (--disable-tls)." >&5
      -echo "$as_me: error: openssl library cannot be found. Install openssl or disable \`tls' module (--disable-tls)." >&2;}
      +    { { echo "$as_me:$LINENO: error: Could not find development files of OpenSSL library. Install them or disable \`tls' with: --disable-tls" >&5
      +echo "$as_me: error: Could not find development files of OpenSSL library. Install them or disable \`tls' with: --disable-tls" >&2;}
          { (exit 1); exit 1; }; }
       fi
       
      @@ -6631,31 +6638,31 @@ GREP!$GREP$ac_delim
       EGREP!$EGREP$ac_delim
       EXPAT_CFLAGS!$EXPAT_CFLAGS$ac_delim
       EXPAT_LIBS!$EXPAT_LIBS$ac_delim
      -ZLIB_CFLAGS!$ZLIB_CFLAGS$ac_delim
      -ZLIB_LIBS!$ZLIB_LIBS$ac_delim
      -PAM_CFLAGS!$PAM_CFLAGS$ac_delim
      -PAM_LIBS!$PAM_LIBS$ac_delim
       LIBOBJS!$LIBOBJS$ac_delim
      -mod_pubsub!$mod_pubsub$ac_delim
      -make_mod_pubsub!$make_mod_pubsub$ac_delim
       mod_irc!$mod_irc$ac_delim
       make_mod_irc!$make_mod_irc$ac_delim
       mod_muc!$mod_muc$ac_delim
       make_mod_muc!$make_mod_muc$ac_delim
       mod_proxy65!$mod_proxy65$ac_delim
       make_mod_proxy65!$make_mod_proxy65$ac_delim
      +mod_pubsub!$mod_pubsub$ac_delim
      +make_mod_pubsub!$make_mod_pubsub$ac_delim
       eldap!$eldap$ac_delim
       make_eldap!$make_eldap$ac_delim
      -pam!$pam$ac_delim
      -make_pam!$make_pam$ac_delim
      -web!$web$ac_delim
      -make_web!$make_web$ac_delim
      -tls!$tls$ac_delim
      -make_tls!$make_tls$ac_delim
       odbc!$odbc$ac_delim
       make_odbc!$make_odbc$ac_delim
      +tls!$tls$ac_delim
      +make_tls!$make_tls$ac_delim
      +web!$web$ac_delim
      +make_web!$make_web$ac_delim
       ejabberd_zlib!$ejabberd_zlib$ac_delim
       make_ejabberd_zlib!$make_ejabberd_zlib$ac_delim
      +ZLIB_CFLAGS!$ZLIB_CFLAGS$ac_delim
      +ZLIB_LIBS!$ZLIB_LIBS$ac_delim
      +pam!$pam$ac_delim
      +make_pam!$make_pam$ac_delim
      +PAM_CFLAGS!$PAM_CFLAGS$ac_delim
      +PAM_LIBS!$PAM_LIBS$ac_delim
       hipe!$hipe$ac_delim
       roster_gateway_workaround!$roster_gateway_workaround$ac_delim
       db_type!$db_type$ac_delim
      diff --git a/src/configure.ac b/src/configure.ac
      index ba6384633..c325c3f54 100644
      --- a/src/configure.ac
      +++ b/src/configure.ac
      @@ -18,10 +18,6 @@ AM_WITH_ERLANG
       AM_ICONV
       #locating libexpat
       AM_WITH_EXPAT
      -#locating zlib
      -AM_WITH_ZLIB
      -#locating PAM
      -AM_WITH_PAM
       
       # Checks for typedefs, structures, and compiler characteristics.
       AC_C_CONST
      @@ -36,16 +32,22 @@ AC_PREFIX_DEFAULT(/)
       AC_FUNC_MALLOC
       AC_HEADER_STDC
       
      -AC_MOD_ENABLE(mod_pubsub, yes)
       AC_MOD_ENABLE(mod_irc, yes)
       AC_MOD_ENABLE(mod_muc, yes)
       AC_MOD_ENABLE(mod_proxy65, yes)
      +AC_MOD_ENABLE(mod_pubsub, yes)
       AC_MOD_ENABLE(eldap, yes)
      -AC_MOD_ENABLE(pam, no)
      -AC_MOD_ENABLE(web, yes)
      -AC_MOD_ENABLE(tls, yes)
       AC_MOD_ENABLE(odbc, no)
      +AC_MOD_ENABLE(tls, yes)
      +AC_MOD_ENABLE(web, yes)
      +
       AC_MOD_ENABLE(ejabberd_zlib, yes)
      +#locating zlib
      +AM_WITH_ZLIB
      +
      +AC_MOD_ENABLE(pam, no)
      +#locating PAM
      +AM_WITH_PAM
       
       AC_ARG_ENABLE(hipe,
       [AC_HELP_STRING([--enable-hipe], [compile natively with HiPE, not recommended (default: no)])],
      diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example
      index 6a6b52494..046db942b 100644
      --- a/src/ejabberd.cfg.example
      +++ b/src/ejabberd.cfg.example
      @@ -186,6 +186,13 @@
       %%{{s2s_host, "goodhost.org"}, allow}.
       %%{{s2s_host, "badhost.org"}, deny}.
       
      +%%
      +%% Outgoing S2S options
      +%%
      +%% Preferred address families (which to try first) and connect timeout
      +%% in milliseconds.
      +%%
      +%%{outgoing_s2s_options, [ipv4, ipv6], 10000}.
       
       %%%   ==============
       %%%   AUTHENTICATION
      diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
      index 7e3be2d8e..649eadf6d 100644
      --- a/src/ejabberd_c2s.erl
      +++ b/src/ejabberd_c2s.erl
      @@ -1890,14 +1890,26 @@ check_from(El, FromJID) ->
           case exmpp_stanza:get_sender(El) of
       	undefined ->
       	    El;
      -	SJID ->
      +	{value, SJID} ->
       	    try
      -		JID = exmpp_jid:binary_to_jid(SJID),
      -		case exmpp_jid:compare_jids(JID, FromJID) of
      -		    true ->
      -			El;
      -		    false ->
      -			'invalid-from'
      +		JIDEl = exmpp_jid:parse_jid(SJID),
      +		case exmpp_jid:lresource(JIDEl) of 
      +		    undefined ->
      +			%% Matching JID: The stanza is ok
      +			case exmpp_jid:compare_bare_jids(JIDEl, FromJID) of
      +			    true ->
      +				El;
      +			   false ->
      +				'invalid-from'
      +			end;
      +		    _ ->
      +			%% Matching JID: The stanza is ok
      +			case exmpp_jid:compare_jids(JIDEl, FromJID) of
      +			    true ->
      +				El;
      +			    false ->
      +			       'invalid-from'
      +			end
       		end
       	    catch
       		_:_ ->
      diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl
      index 63c67cb6d..1708c7aa2 100644
      --- a/src/ejabberd_config.erl
      +++ b/src/ejabberd_config.erl
      @@ -331,6 +331,8 @@ process_term(Term, State) ->
       	    add_option(language, Val, State);
       	{outgoing_s2s_port, Port} ->
       	    add_option(outgoing_s2s_port, Port, State);
      +	{outgoing_s2s_options, Methods, Timeout} ->
      +	    add_option(outgoing_s2s_options, {Methods, Timeout}, State);
       	{s2s_use_starttls, Port} ->
       	    add_option(s2s_use_starttls, Port, State);
       	{s2s_certfile, CertFile} ->
      diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl
      index 67d4bc615..553609a97 100644
      --- a/src/ejabberd_s2s_out.erl
      +++ b/src/ejabberd_s2s_out.erl
      @@ -108,6 +108,8 @@
       ]).
       
       
      +-define(SOCKET_DEFAULT_RESULT, {error, badarg}).
      +
       %%%----------------------------------------------------------------------
       %%% API
       %%%----------------------------------------------------------------------
      @@ -195,7 +197,7 @@ open_socket(init, StateData) ->
       				 _ ->
       				     open_socket1(Addr, Port)
       			     end
      -		     end, {error, badarg}, AddrList) of
      +		     end, ?SOCKET_DEFAULT_RESULT, AddrList) of
       	{ok, Socket} ->
       	    Version = if
       			  StateData#state.use_v10 ->
      @@ -231,34 +233,40 @@ open_socket(_, StateData) ->
           {next_state, open_socket, StateData}.
       
       %%----------------------------------------------------------------------
      -open_socket1(Addr, Port) ->
      -    ?DEBUG("s2s_out: connecting to ~s:~p~n", [Addr, Port]),
      -    Res = case catch ejabberd_socket:connect(
      -		       Addr, Port,
      -		       [binary, {packet, 0},
      -			{active, false}]) of
      -	      {ok, _Socket} = R -> R;
      -	      {error, Reason1} ->
      -		  ?DEBUG("s2s_out: connect return ~p~n", [Reason1]),
      -		  catch ejabberd_socket:connect(
      -			  Addr, Port,
      -			  [binary, {packet, 0},
      -			   {active, false}, inet6]);
      -	      {'EXIT', Reason1} ->
      -		  ?DEBUG("s2s_out: connect crashed ~p~n", [Reason1]),
      -		  catch ejabberd_socket:connect(
      -			  Addr, Port,
      -			  [binary, {packet, 0},
      -			   {active, false}, inet6])
      -	  end,
      -    case Res of
      -	{ok, Socket} ->
      -	    {ok, Socket};
      -	{error, Reason} ->
      -	    ?DEBUG("s2s_out: inet6 connect return ~p~n", [Reason]),
      -	    {error, Reason};
      +%% IPv4
      +open_socket1({_,_,_,_} = Addr, Port) ->
      +    open_socket2(inet, Addr, Port);
      +
      +%% IPv6
      +open_socket1({_,_,_,_,_,_,_,_} = Addr, Port) ->
      +    open_socket2(inet6, Addr, Port);
      +
      +%% Hostname
      +open_socket1(Host, Port) ->
      +    lists:foldl(fun(_Family, {ok, _Socket} = R) ->
      +			R;
      +		   (Family, _) ->
      +			Addrs = get_addrs(Host, Family),
      +			lists:foldl(fun(_Addr, {ok, _Socket} = R) ->
      +					    R;
      +				       (Addr, _) ->
      +					    open_socket1(Addr, Port)
      +				    end, ?SOCKET_DEFAULT_RESULT, Addrs)
      +		end, ?SOCKET_DEFAULT_RESULT, outgoing_s2s_families()).
      +
      +open_socket2(Type, Addr, Port) ->
      +    ?DEBUG("s2s_out: connecting to ~p:~p~n", [Addr, Port]),
      +    Timeout = outgoing_s2s_timeout(),
      +    case (catch ejabberd_socket:connect(Addr, Port,
      +					[binary, {packet, 0},
      +					 {active, false}, Type],
      +					Timeout)) of
      +	{ok, _Socket} = R -> R;
      +	{error, Reason} = R ->
      +	    ?DEBUG("s2s_out: connect return ~p~n", [Reason]),
      +	    R;
       	{'EXIT', Reason} ->
      -	    ?DEBUG("s2s_out: inet6 connect crashed ~p~n", [Reason]),
      +	    ?DEBUG("s2s_out: connect crashed ~p~n", [Reason]),
       	    {error, Reason}
           end.
       
      @@ -953,6 +961,23 @@ test_get_addr_port(Server) ->
       	      end
             end, [], lists:seq(1, 100000)).
       
      +get_addrs(Host, Family) ->
      +    Type = case Family of
      +	       inet4 -> inet;
      +	       ipv4 -> inet;
      +	       inet6 -> inet6;
      +	       ipv6 -> inet6
      +	   end,
      +    case inet:gethostbyname(Host, Type) of
      +	{ok, #hostent{h_addr_list = Addrs}} ->
      +	    ?DEBUG("~s of ~s resolved to: ~p~n", [Type, Host, Addrs]),
      +	    Addrs;
      +	{error, Reason} ->
      +	    ?DEBUG("~s lookup of '~s' failed: ~p~n", [Type, Host, Reason]),
      +	    []
      +    end.
      +
      +
       outgoing_s2s_port() ->
           case ejabberd_config:get_local_option(outgoing_s2s_port) of
       	Port when is_integer(Port) ->
      @@ -961,6 +986,36 @@ outgoing_s2s_port() ->
       	    5269
           end.
       
      +outgoing_s2s_families() ->
      +    case ejabberd_config:get_local_option(outgoing_s2s_options) of
      +	{Families, _} when is_list(Families) ->
      +	    Families;
      +	undefined ->
      +	    %% DISCUSSION: Why prefer IPv4 first?
      +	    %%
      +	    %% IPv4 connectivity will be available for everyone for
      +	    %% many years to come. So, there's absolutely no benefit
      +	    %% in preferring IPv6 connections which are flaky at best
      +	    %% nowadays.
      +	    %%
      +	    %% On the other hand content providers hesitate putting up
      +	    %% AAAA records for their sites due to the mentioned
      +	    %% quality of current IPv6 connectivity. Making IPv6 the a
      +	    %% `fallback' may avoid these problems elegantly.
      +	    [ipv4, ipv6]
      +    end.
      +
      +outgoing_s2s_timeout() ->
      +    case ejabberd_config:get_local_option(outgoing_s2s_options) of
      +	{_, Timeout} when is_integer(Timeout) ->
      +	    Timeout;
      +	{_, infinity} ->
      +	    infinity;
      +	undefined ->
      +	    %% 10 seconds
      +	    10000
      +    end.
      +
       %% Human readable S2S logging: Log only new outgoing connections as INFO
       %% Do not log dialback
       log_s2s_out(false, _, _) -> ok;
      diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl
      index ba706e4e8..01e1eddcb 100644
      --- a/src/ejabberd_socket.erl
      +++ b/src/ejabberd_socket.erl
      @@ -30,6 +30,7 @@
       %% API
       -export([start/4,
       	 connect/3,
      +	 connect/4,
       	 starttls/2,
       	 starttls/3,
       	 compress/1,
      @@ -94,7 +95,10 @@ start(Module, SockMod, Socket, Opts) ->
           end.
       
       connect(Addr, Port, Opts) ->
      -    case gen_tcp:connect(Addr, Port, Opts) of
      +    connect(Addr, Port, Opts, infinity).
      +
      +connect(Addr, Port, Opts, Timeout) ->
      +    case gen_tcp:connect(Addr, Port, Opts, Timeout) of
       	{ok, Socket} ->
       	    Receiver = ejabberd_receiver:start(Socket, gen_tcp, none),
       	    SocketData = #socket_state{sockmod = gen_tcp,
      diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl
      index 1147c51db..88fa29daf 100644
      --- a/src/mod_privacy_odbc.erl
      +++ b/src/mod_privacy_odbc.erl
      @@ -775,132 +775,66 @@ item_to_raw(#listitem{type = Type,
           SMatchMessage = if MatchMessage -> "1"; true -> "0" end,
           SMatchPresenceIn = if MatchPresenceIn -> "1"; true -> "0" end,
           SMatchPresenceOut = if MatchPresenceOut -> "1"; true -> "0" end,
      -    ["'", SType, "', "
      -     "'", SValue, "', "
      -     "'", SAction, "', "
      -     "'", SOrder, "', "
      -     "'", SMatchAll, "', "
      -     "'", SMatchIQ, "', "
      -     "'", SMatchMessage, "', "
      -     "'", SMatchPresenceIn, "', "
      -     "'", SMatchPresenceOut, "'"].
      -
      +    [SType, SValue, SAction, SOrder, SMatchAll, SMatchIQ,
      +     SMatchMessage, SMatchPresenceIn, SMatchPresenceOut].
       
       sql_get_default_privacy_list(LUser, LServer) ->
           Username = ejabberd_odbc:escape(LUser),
      -    ejabberd_odbc:sql_query(
      -      LServer,
      -      ["select name from privacy_default_list "
      -       "where username='", Username, "';"]).
      +    odbc_queries:get_default_privacy_list(LServer, Username).
       
       sql_get_default_privacy_list_t(LUser) ->
           Username = ejabberd_odbc:escape(LUser),
      -    ejabberd_odbc:sql_query_t(
      -      ["select name from privacy_default_list "
      -       "where username='", Username, "';"]).
      +    odbc_queries:get_default_privacy_list_t(Username).
       
       sql_get_privacy_list_names(LUser, LServer) ->
           Username = ejabberd_odbc:escape(LUser),
      -    ejabberd_odbc:sql_query(
      -      LServer,
      -      ["select name from privacy_list "
      -       "where username='", Username, "';"]).
      +    odbc_queries:get_privacy_list_names(LServer, Username).
       
       sql_get_privacy_list_names_t(LUser) ->
           Username = ejabberd_odbc:escape(LUser),
      -    ejabberd_odbc:sql_query_t(
      -      ["select name from privacy_list "
      -       "where username='", Username, "';"]).
      +    odbc_queries:get_privacy_list_names_t(Username).
       
       sql_get_privacy_list_id(LUser, LServer, Name) ->
           Username = ejabberd_odbc:escape(LUser),
           SName = ejabberd_odbc:escape(Name),
      -    ejabberd_odbc:sql_query(
      -      LServer,
      -      ["select id from privacy_list "
      -       "where username='", Username, "' and name='", SName, "';"]).
      +    odbc_queries:get_privacy_list_id(LServer, Username, SName).
       
       sql_get_privacy_list_id_t(LUser, Name) ->
           Username = ejabberd_odbc:escape(LUser),
           SName = ejabberd_odbc:escape(Name),
      -    ejabberd_odbc:sql_query_t(
      -      ["select id from privacy_list "
      -       "where username='", Username, "' and name='", SName, "';"]).
      +    odbc_queries:get_privacy_list_id_t(Username, SName).
       
       sql_get_privacy_list_data(LUser, LServer, Name) ->
           Username = ejabberd_odbc:escape(LUser),
           SName = ejabberd_odbc:escape(Name),
      -    ejabberd_odbc:sql_query(
      -      LServer,
      -      ["select t, value, action, ord, match_all, match_iq, "
      -       "match_message, match_presence_in, match_presence_out "
      -       "from privacy_list_data "
      -       "where id = (select id from privacy_list where "
      -       "            username='", Username, "' and name='", SName, "') "
      -       "order by ord;"]).
      +    odbc_queries:get_privacy_list_data(LServer, Username, SName).
       
       sql_get_privacy_list_data_by_id(ID, LServer) ->
      -    ejabberd_odbc:sql_query(
      -      LServer,
      -      ["select t, value, action, ord, match_all, match_iq, "
      -       "match_message, match_presence_in, match_presence_out "
      -       "from privacy_list_data "
      -       "where id='", ID, "' order by ord;"]).
      +    odbc_queries:get_privacy_list_data_by_id(LServer, ID).
       
       sql_set_default_privacy_list(LUser, Name) ->
           Username = ejabberd_odbc:escape(LUser),
           SName = ejabberd_odbc:escape(Name),
      -    ejabberd_odbc:sql_query_t(
      -      ["delete from privacy_default_list "
      -       "      where username='", Username, "';"]),
      -    ejabberd_odbc:sql_query_t(
      -      ["insert into privacy_default_list(username, name) "
      -       "values ('", Username, "', '", SName, "');"]).
      +    odbc_queries:set_default_privacy_list(Username, SName).
       
       sql_unset_default_privacy_list(LUser, LServer) ->
           Username = ejabberd_odbc:escape(LUser),
      -    ejabberd_odbc:sql_query(
      -      LServer,
      -      ["delete from privacy_default_list "
      -       "      where username='", Username, "';"]).
      +    odbc_queries:unset_default_privacy_list(LServer, Username).
       
       sql_remove_privacy_list(LUser, Name) ->
           Username = ejabberd_odbc:escape(LUser),
           SName = ejabberd_odbc:escape(Name),
      -    ejabberd_odbc:sql_query_t(
      -      ["delete from privacy_list "
      -       "where username='", Username, "' and name='", SName, "';"]).
      +    odbc_queries:remove_privacy_list(Username, SName).
       
       sql_add_privacy_list(LUser, Name) ->
           Username = ejabberd_odbc:escape(LUser),
           SName = ejabberd_odbc:escape(Name),
      -    ejabberd_odbc:sql_query_t(
      -      ["insert into privacy_list(username, name) "
      -       "values ('", Username, "', '", SName, "');"]).
      +    odbc_queries:add_privacy_list(Username, SName).
       
       sql_set_privacy_list(ID, RItems) ->
      -    ejabberd_odbc:sql_query_t(
      -      ["delete from privacy_list_data "
      -       "where id='", ID, "';"]),
      -    lists:foreach(fun(Items) ->
      -			  ejabberd_odbc:sql_query_t(
      -			    ["insert into privacy_list_data("
      -			     "id, t, value, action, ord, match_all, match_iq, "
      -			     "match_message, match_presence_in, "
      -			     "match_presence_out "
      -			     ") "
      -		 	     "values ('", ID, "', ", Items, ");"])
      -		  end, RItems).
      +    odbc_queries:set_privacy_list(ID, RItems).
       
       sql_del_privacy_lists(LUser, LServer) ->
           Username = ejabberd_odbc:escape(LUser),
           Server = ejabberd_odbc:escape(LServer),
      -    ejabberd_odbc:sql_query(
      -      LServer,
      -      ["delete from privacy_list where username='", Username, "';"]),
      -    ejabberd_odbc:sql_query(
      -      LServer,
      -      ["delete from privacy_list_data where value='", Username++"@"++Server, "';"]),
      -    ejabberd_odbc:sql_query(
      -      LServer,
      -      ["delete from privacy_default_list where username='", Username, "';"]).
      +    odbc_queries:del_privacy_lists(LServer, Server, Username).
      diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl
      index 39c301a4d..3860a09c7 100644
      --- a/src/mod_roster_odbc.erl
      +++ b/src/mod_roster_odbc.erl
      @@ -640,18 +640,13 @@ remove_user(User, Server) when is_binary(User), is_binary(Server) ->
       %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
       
       set_items(User, Server, #xmlel{children = Els}) ->
      -    try
      -	LUser = exmpp_stringprep:nodeprep(User),
      -	LServer = exmpp_stringprep:nameprep(Server),
      -	catch odbc_queries:sql_transaction(
      -		LServer,
      -		 lists:flatmap(fun(El) ->
      -				   process_item_set_t(LUser, LServer, El)
      -			   end, Els))
      -    catch
      -	_ ->
      -	    ok
      -    end.
      +    LUser = exmpp_stringprep:nodeprep(User),
      +    LServer = exmpp_stringprep:nameprep(Server),
      +    catch odbc_queries:sql_transaction(
      +	    LServer,
      +	    lists:flatmap(fun(El) ->
      +				  process_item_set_t(LUser, LServer, El)
      +			  end, Els)).
       
       process_item_set_t(LUser, LServer, #xmlel{} = El) ->
           try
      @@ -868,13 +863,7 @@ record_to_string(#roster{us = {User, _Server},
       	       none	   -> "N"
       	   end,
           SAskMessage = ejabberd_odbc:escape(binary_to_list(AskMessage)),
      -    ["'", Username, "',"
      -     "'", SJID, "',"
      -     "'", Nick, "',"
      -     "'", SSubscription, "',"
      -     "'", SAsk, "',"
      -     "'", SAskMessage, "',"
      -     "'N', '', 'item'"].
      +    [Username, SJID, Nick, SSubscription, SAsk, SAskMessage, "N", "", "item"].
       
       groups_to_string(#roster{us = {User, _Server},
       			 jid = JID,
      @@ -885,12 +874,11 @@ groups_to_string(#roster{us = {User, _Server},
       
           %% Empty groups do not need to be converted to string to be inserted in
           %% the database
      -    lists:foldl(fun([], Acc) -> Acc;
      -		   (Group, Acc) ->
      -			String = ["'", Username, "',"
      -				  "'", SJID, "',"
      -				  "'", ejabberd_odbc:escape(binary_to_list(Group)), "'"],
      -			[String|Acc] end, [], Groups).
      +    lists:foldl(
      +      fun([], Acc) -> Acc;
      +	 (Group, Acc) ->
      + 	      G = ejabberd_odbc:escape(binary_to_list(Group)),
      +	      [[Username, SJID, G]|Acc] end, [], Groups).
       
       webadmin_page(_, Host,
       	      #request{us = _US,
      diff --git a/src/odbc/ejabberd_odbc.erl b/src/odbc/ejabberd_odbc.erl
      index 940d94d74..3a75b8a6e 100644
      --- a/src/odbc/ejabberd_odbc.erl
      +++ b/src/odbc/ejabberd_odbc.erl
      @@ -55,6 +55,8 @@
       -define(PGSQL_PORT, 5432).
       -define(MYSQL_PORT, 3306).
       
      +-define(TRANSACTION_TIMEOUT, 60000).
      +-define(KEEPALIVE_TIMEOUT, 60000).
       -define(KEEPALIVE_QUERY, "SELECT 1;").
       
       %%%----------------------------------------------------------------------
      @@ -68,7 +70,7 @@ start_link(Host, StartInterval) ->
       
       sql_query(Host, Query) ->
           gen_server:call(ejabberd_odbc_sup:get_random_pid(Host),
      -		    {sql_query, Query}, 60000).
      +		    {sql_query, Query}, ?TRANSACTION_TIMEOUT).
       
       %% SQL transaction based on a list of queries
       %% This function automatically
      @@ -83,7 +85,7 @@ sql_transaction(Host, Queries) when is_list(Queries) ->
       %% SQL transaction, based on a erlang anonymous function (F = fun)
       sql_transaction(Host, F) ->
           gen_server:call(ejabberd_odbc_sup:get_random_pid(Host),
      -		    {sql_transaction, F}, 60000).
      +		    {sql_transaction, F}, ?TRANSACTION_TIMEOUT).
       
       %% This function is intended to be used from inside an sql_transaction:
       sql_query_t(Query) ->
      @@ -93,12 +95,12 @@ sql_query_t(Query) ->
       	{error, "No SQL-driver information available."} ->
       	    % workaround for odbc bug
       	    {updated, 0};
      -	{error, _} ->
      -	    throw(aborted);
      +	{error, Reason} ->
      +	    throw({aborted, Reason});
       	Rs when is_list(Rs) ->
      -	    case lists:keymember(error, 1, Rs) of
      -		true ->
      -		    throw(aborted);
      +	    case lists:keysearch(error, 1, Rs) of
      +		{value, {error, Reason}} ->
      +		    throw({aborted, Reason});
       		_ ->
       		    QRes
       	    end;
      @@ -177,7 +179,7 @@ handle_call({sql_query, Query}, _From, State) ->
       	    {reply, Reply, State}
           end;
       handle_call({sql_transaction, F}, _From, State) ->
      -    case execute_transaction(State, F, ?MAX_TRANSACTION_RESTARTS) of
      +    case execute_transaction(State, F, ?MAX_TRANSACTION_RESTARTS, "") of
       	% error returned by MySQL driver
       	{error, "query timed out"} ->
       	    {stop, timeout, State};
      @@ -247,14 +249,22 @@ sql_query_internal(State, Query) ->
       	    mysql_to_odbc(mysql_conn:fetch(State#state.db_ref, Query, self()))
           end.
       
      -execute_transaction(_State, _F, 0) ->
      +execute_transaction(State, _F, 0, Reason) ->
      +    ?ERROR_MSG("SQL transaction restarts exceeded~n"
      +	       "** Restarts: ~p~n"
      +	       "** Last abort reason: ~p~n"
      +	       "** Stacktrace: ~p~n"
      +	       "** When State == ~p",
      +	       [?MAX_TRANSACTION_RESTARTS, Reason,
      +		erlang:get_stacktrace(), State]),
      +    sql_query_internal(State, "rollback;"),
           {aborted, restarts_exceeded};
      -execute_transaction(State, F, NRestarts) ->
      +execute_transaction(State, F, NRestarts, _Reason) ->
           put(?STATE_KEY, State),
           sql_query_internal(State, "begin;"),
           case catch F() of
      -	aborted ->
      -	    execute_transaction(State, F, NRestarts - 1);
      +	{aborted, Reason} ->
      +	    execute_transaction(State, F, NRestarts - 1, Reason);
       	{'EXIT', Reason} ->
       	    sql_query_internal(State, "rollback;"),
       	    {aborted, Reason};
      @@ -330,11 +340,6 @@ mysql_connect(Server, Port, DB, Username, Password, StartInterval) ->
       	{ok, Ref} ->
       	    erlang:monitor(process, Ref),
                   mysql_conn:fetch(Ref, ["set names 'utf8';"], self()),
      -	    % needed to ensure the order of queries, specifically at
      -	    % roster subscription time (this can also be set-up in the
      -	    % MySQL configuration, but not at the database level):
      -            mysql_conn:fetch(Ref, ["SET SESSION TRANSACTION ISOLATION LEVEL "
      -				   "SERIALIZABLE;"], self()),
       	    {ok, #state{db_ref = Ref, db_type = mysql}};
       	{error, Reason} ->
       	    ?ERROR_MSG("MySQL connection failed: ~p~nWaiting ~p seconds before retrying...~n",
      @@ -365,7 +370,7 @@ mysql_item_to_odbc(Columns, Recs) ->
       
       % perform a harmless query on all opened connexions to avoid connexion close.
       keep_alive(PID) ->
      -    gen_server:call(PID, {sql_query, ?KEEPALIVE_QUERY}, 60000).
      +    gen_server:call(PID, {sql_query, ?KEEPALIVE_QUERY}, ?KEEPALIVE_TIMEOUT).
       
       % log function used by MySQL driver
       log(Level, Format, Args) ->
      diff --git a/src/odbc/odbc_queries.erl b/src/odbc/odbc_queries.erl
      index a2fb0ae41..080a353c8 100644
      --- a/src/odbc/odbc_queries.erl
      +++ b/src/odbc/odbc_queries.erl
      @@ -61,6 +61,20 @@
       	 set_private_data_sql/3,
       	 get_private_data/3,
       	 del_user_private_storage/2,
      +	 get_default_privacy_list/2,
      +	 get_default_privacy_list_t/1,
      +	 get_privacy_list_names/2,
      +	 get_privacy_list_names_t/1,
      +	 get_privacy_list_id/3,
      +	 get_privacy_list_id_t/2,
      +	 get_privacy_list_data/3,
      +	 get_privacy_list_data_by_id/2,
      +	 set_default_privacy_list/2,
      +	 unset_default_privacy_list/2,
      +	 remove_privacy_list/2,
      +	 add_privacy_list/2,
      +	 set_privacy_list/2,
      +	 del_privacy_lists/3,
       	 set_vcard/26,
       	 get_vcard/2,
       	 escape/1,
      @@ -74,6 +88,14 @@
       -define(generic, true).
       -endif.
       
      +%% Almost a copy of string:join/2.
      +%% We use this version because string:join/2 is relatively
      +%% new function (introduced in R12B-0).
      +join([], _Sep) ->
      +    [];
      +join([H|T], Sep) ->
      +    [H, [[Sep, X] || X <- T]].
      +
       %% -----------------
       %% Generic queries
       -ifdef(generic).
      @@ -81,9 +103,25 @@
       get_db_type() ->
           generic.
       
      +%% Safe atomic update.
      +update_t(Table, Fields, Vals, Where) ->
      +    UPairs = lists:zipwith(fun(A, B) -> A ++ "='" ++ B ++ "'" end,
      +			   Fields, Vals),
      +    case ejabberd_odbc:sql_query_t(
      +	   ["update ", Table, " set ",
      +	    join(UPairs, ", "),
      +	    " where ", Where, ";"]) of
      +	{updated, 1} ->
      +	    ok;
      +	_ ->
      +	    ejabberd_odbc:sql_query_t(
      +	      ["insert into ", Table, "(", join(Fields, ", "),
      +	       ") values ('", join(Vals, "', '"), "');"])
      +    end.
      +
       %% F can be either a fun or a list of queries
      -%% TODO: We should probably move the list of queries transaction wrapper from the ejabberd_odbc module
      -%%       to this one (odbc_queries)
      +%% TODO: We should probably move the list of queries transaction
      +%% wrapper from the ejabberd_odbc module to this one (odbc_queries)
       sql_transaction(LServer, F) ->
           ejabberd_odbc:sql_transaction(LServer, F).
       
      @@ -97,9 +135,11 @@ set_last_t(LServer, Username, Seconds, State) ->
           %% MREMOND: I think this should be turn into a non transactional behaviour
           ejabberd_odbc:sql_transaction(
             LServer,
      -      [["delete from last where username='", Username, "';"],
      -       ["insert into last(username, seconds, state) "
      -	"values ('", Username, "', '", Seconds, "', '", State, "');"]]).
      +      fun() ->
      +	      update_t("last", ["username", "seconds", "state"],
      +		       [Username, Seconds, State],
      +		       ["username='", Username, "'"])
      +      end).
       
       del_last(LServer, Username) ->
           ejabberd_odbc:sql_query(
      @@ -115,9 +155,11 @@ get_password(LServer, Username) ->
       set_password_t(LServer, Username, Pass) ->
           ejabberd_odbc:sql_transaction(
             LServer,
      -      [["delete from users where username='", Username ,"';"],
      -       ["insert into users(username, password) "
      -	"values ('", Username, "', '", Pass, "');"]]).
      +      fun() ->
      +	      update_t("users", ["username", "password"],
      +		       [Username, Pass],
      +		       ["username='", Username ,"'"])
      +      end).
       
       add_user(LServer, Username, Pass) ->
           ejabberd_odbc:sql_query(
      @@ -296,16 +338,11 @@ del_roster_sql(Username, SJID) ->
             "        and jid='", SJID, "';"]].
       
       update_roster(_LServer, Username, SJID, ItemVals, ItemGroups) ->
      -    ejabberd_odbc:sql_query_t(
      -      ["delete from rosterusers "
      -       "      where username='", Username, "' "
      -       "        and jid='", SJID, "';"]),
      -    ejabberd_odbc:sql_query_t(
      -      ["insert into rosterusers("
      -       "              username, jid, nick, "
      -       "              subscription, ask, askmessage, "
      -       "              server, subscribe, type) "
      -       " values (", ItemVals, ");"]),
      +    update_t("rosterusers",
      +	     ["username", "jid", "nick", "subscription", "ask",
      +	      "askmessage", "server", "subscribe", "type"],
      +	     ItemVals,
      +	     ["username='", Username, "' and jid='", SJID, "'"]),
           ejabberd_odbc:sql_query_t(
             ["delete from rostergroups "
              "      where username='", Username, "' "
      @@ -314,7 +351,7 @@ update_roster(_LServer, Username, SJID, ItemVals, ItemGroups) ->
       			  ejabberd_odbc:sql_query_t(
       			    ["insert into rostergroups("
       			     "              username, jid, grp) "
      -			     " values (", ItemGroup, ");"])
      +			     " values ('", join(ItemGroup, "', '"), "');"])
       		  end,
       		  ItemGroups).
       
      @@ -326,26 +363,21 @@ update_roster_sql(Username, SJID, ItemVals, ItemGroups) ->
             "              username, jid, nick, "
             "              subscription, ask, askmessage, "
             "              server, subscribe, type) "
      -      " values (", ItemVals, ");"],
      +      " values ('", join(ItemVals, "', '"), "');"],
            ["delete from rostergroups "
             "      where username='", Username, "' "
             "        and jid='", SJID, "';"]] ++
            [["insert into rostergroups("
              "              username, jid, grp) "
      -       " values (", ItemGroup, ");"] ||
      +       " values ('", join(ItemGroup, "', '"), "');"] ||
       	 ItemGroup <- ItemGroups].
       
       roster_subscribe(_LServer, Username, SJID, ItemVals) ->
      -    ejabberd_odbc:sql_query_t(
      -      ["delete from rosterusers "
      -       "      where username='", Username, "' "
      -       "        and jid='", SJID, "';"]),
      -    ejabberd_odbc:sql_query_t(
      -      ["insert into rosterusers("
      -       "              username, jid, nick, "
      -       "              subscription, ask, askmessage, "
      -       "              server, subscribe, type) "
      -       " values (", ItemVals, ");"]).
      +    update_t("rosterusers",
      +	     ["username", "jid", "nick", "subscription", "ask",
      +	      "askmessage", "server", "subscribe", "type"],
      +	     ItemVals,
      +	     ["username='", Username, "' and jid='", SJID, "'"]).
       
       get_subscription(LServer, Username, SJID) ->
           ejabberd_odbc:sql_query(
      @@ -355,10 +387,10 @@ get_subscription(LServer, Username, SJID) ->
              "and jid='", SJID, "'"]).
       
       set_private_data(_LServer, Username, LXMLNS, SData) ->
      -    lists:foreach(fun(Query) ->
      -            ejabberd_odbc:sql_query_t(Query)
      -        end,
      -        set_private_data_sql(Username, LXMLNS, SData)).
      +    update_t("private_storage",
      +	     ["username", "namespace", "data"],
      +	     [Username, LXMLNS, SData], 
      +	     ["username='", Username, "' and namespace='", LXMLNS, "'"]).
       
       set_private_data_sql(Username, LXMLNS, SData) ->
           [["delete from private_storage "
      @@ -380,35 +412,29 @@ del_user_private_storage(LServer, Username) ->
             LServer,
             ["delete from private_storage where username='", Username, "';"]).
       
      -
       set_vcard(LServer, LUsername, SBDay, SCTRY, SEMail, SFN, SFamily, SGiven,
       	  SLBDay, SLCTRY, SLEMail, SLFN, SLFamily, SLGiven, SLLocality,
       	  SLMiddle, SLNickname, SLOrgName, SLOrgUnit, SLocality, SMiddle,
       	  SNickname, SOrgName, SOrgUnit, SVCARD, Username) ->
           ejabberd_odbc:sql_transaction(
             LServer,
      -      [["delete from vcard where username='", LUsername, "';"],
      -       ["insert into vcard(username, vcard) "
      -	"values ('", LUsername, "', '", SVCARD, "');"],
      -       ["delete from vcard_search where lusername='", LUsername, "';"],
      -       ["insert into vcard_search("
      -	"        username, lusername, fn, lfn, family, lfamily,"
      -	"        given, lgiven, middle, lmiddle, nickname, lnickname,"
      -	"        bday, lbday, ctry, lctry, locality, llocality,"
      -	"        email, lemail, orgname, lorgname, orgunit, lorgunit)"
      -	"values (",
      -	"        '", Username,  "', '", LUsername,  "',"
      -	"        '", SFN,       "', '", SLFN,       "',"
      -	"        '", SFamily,   "', '", SLFamily,   "',"
      -	"        '", SGiven,    "', '", SLGiven,    "',"
      -	"        '", SMiddle,   "', '", SLMiddle,   "',"
      -	"        '", SNickname, "', '", SLNickname, "',"
      -	"        '", SBDay,     "', '", SLBDay,	   "',"
      -	"        '", SCTRY,     "', '", SLCTRY,	   "',"
      -	"        '", SLocality, "', '", SLLocality, "',"
      -	"        '", SEMail,    "', '", SLEMail,	   "',"
      -	"        '", SOrgName,  "', '", SLOrgName,  "',"
      -	"        '", SOrgUnit,  "', '", SLOrgUnit,  "');"]]).
      +      fun() ->
      +	      update_t("vcard", ["username", "vcard"],
      +		       [LUsername, SVCARD],
      +		       ["username='", LUsername, "'"]),
      +	      update_t("vcard_search",
      +		       ["username", "lusername", "fn", "lfn", "family",
      +			"lfamily", "given", "lgiven", "middle", "lmiddle",
      +			"nickname", "lnickname", "bday", "lbday", "ctry",
      +			"lctry", "locality", "llocality", "email", "lemail",
      +			"orgname", "lorgname", "orgunit", "lorgunit"],
      +		       [Username, LUsername, SFN, SLFN, SFamily, SLFamily,
      +			SGiven, SLGiven, SMiddle, SLMiddle, SNickname,
      +			SLNickname, SBDay, SLBDay, SCTRY, SLCTRY,
      +			SLocality, SLLocality, SEMail, SLEMail, SOrgName,
      +			SLOrgName, SOrgUnit, SLOrgUnit],
      +		       ["lusername='", LUsername, "'"])
      +      end).
       
       get_vcard(LServer, Username) ->
           ejabberd_odbc:sql_query(
      @@ -416,6 +442,103 @@ get_vcard(LServer, Username) ->
             ["select vcard from vcard "
              "where username='", Username, "';"]).
       
      +get_default_privacy_list(LServer, Username) ->
      +    ejabberd_odbc:sql_query(
      +      LServer,
      +      ["select name from privacy_default_list "
      +       "where username='", Username, "';"]).
      +
      +get_default_privacy_list_t(Username) ->
      +    ejabberd_odbc:sql_query_t(
      +      ["select name from privacy_default_list "
      +       "where username='", Username, "';"]).
      +
      +get_privacy_list_names(LServer, Username) ->
      +    ejabberd_odbc:sql_query(
      +      LServer,
      +      ["select name from privacy_list "
      +       "where username='", Username, "';"]).
      +
      +get_privacy_list_names_t(Username) ->
      +    ejabberd_odbc:sql_query_t(
      +      ["select name from privacy_list "
      +       "where username='", Username, "';"]).
      +
      +get_privacy_list_id(LServer, Username, SName) ->
      +    ejabberd_odbc:sql_query(
      +      LServer,
      +      ["select id from privacy_list "
      +       "where username='", Username, "' and name='", SName, "';"]).
      +
      +get_privacy_list_id_t(Username, SName) ->
      +    ejabberd_odbc:sql_query_t(
      +      ["select id from privacy_list "
      +       "where username='", Username, "' and name='", SName, "';"]).
      +
      +get_privacy_list_data(LServer, Username, SName) ->
      +    ejabberd_odbc:sql_query(
      +      LServer,
      +      ["select t, value, action, ord, match_all, match_iq, "
      +       "match_message, match_presence_in, match_presence_out "
      +       "from privacy_list_data "
      +       "where id = (select id from privacy_list where "
      +       "            username='", Username, "' and name='", SName, "') "
      +       "order by ord;"]).
      +
      +get_privacy_list_data_by_id(LServer, ID) ->
      +    ejabberd_odbc:sql_query(
      +      LServer,
      +      ["select t, value, action, ord, match_all, match_iq, "
      +       "match_message, match_presence_in, match_presence_out "
      +       "from privacy_list_data "
      +       "where id='", ID, "' order by ord;"]).
      +
      +set_default_privacy_list(Username, SName) ->
      +    update_t("privacy_default_list", ["username", "name"],
      +	     [Username, SName], ["username='", Username, "'"]).
      +
      +unset_default_privacy_list(LServer, Username) ->
      +    ejabberd_odbc:sql_query(
      +      LServer,
      +      ["delete from privacy_default_list "
      +       "      where username='", Username, "';"]).
      +
      +remove_privacy_list(Username, SName) ->
      +    ejabberd_odbc:sql_query_t(
      +      ["delete from privacy_list "
      +       "where username='", Username, "' and name='", SName, "';"]).
      +
      +add_privacy_list(Username, SName) ->
      +    ejabberd_odbc:sql_query_t(
      +      ["insert into privacy_list(username, name) "
      +       "values ('", Username, "', '", SName, "');"]).
      +
      +set_privacy_list(ID, RItems) ->
      +    ejabberd_odbc:sql_query_t(
      +      ["delete from privacy_list_data "
      +       "where id='", ID, "';"]),
      +    lists:foreach(fun(Items) ->
      +			  ejabberd_odbc:sql_query_t(
      +			    ["insert into privacy_list_data("
      +			     "id, t, value, action, ord, match_all, match_iq, "
      +			     "match_message, match_presence_in, "
      +			     "match_presence_out "
      +			     ") "
      +			     "values ('", ID, "', '",
      +			     join(Items, "', '"), "');"])
      +		  end, RItems).
      +
      +del_privacy_lists(LServer, Server, Username) ->
      +    ejabberd_odbc:sql_query(
      +      LServer,
      +      ["delete from privacy_list where username='", Username, "';"]),
      +    ejabberd_odbc:sql_query(
      +      LServer,
      +      ["delete from privacy_list_data where value='", Username++"@"++Server, "';"]),
      +    ejabberd_odbc:sql_query(
      +      LServer,
      +      ["delete from privacy_default_list where username='", Username, "';"]).
      +
       %% Characters to escape
       escape($\0) -> "\\0";
       escape($\n) -> "\\n";
      diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl
      index 6f004b7e5..a43e92cd0 100644
      --- a/src/web/ejabberd_web_admin.erl
      +++ b/src/web/ejabberd_web_admin.erl
      @@ -1447,15 +1447,24 @@ user_info(User, Server, Query, Lang) ->
       	    _ ->
       		[?XE('ul',
       		     lists:map(fun(R) ->
      -				       FIP = case ejabberd_sm:get_user_ip(
      +				       FIP = case ejabberd_sm:get_user_info(
       						    User, Server, R) of
      -						 undefined ->
      +						 offline ->
       						     "";
      -						 {IP, Port} ->
      +						 [{node, Node}, {conn, Conn}, {ip, {IP, Port}}] ->
      +						     ConnS = case Conn of
      +								 c2s -> "plain";
      +								 c2s_tls -> "tls";
      +								 c2s_compressed -> "zlib";
      +								 http_bind -> "http-bind";
      +								 http_poll -> "http-poll"
      +							     end,
       						     " (" ++
      +						         ConnS ++ "://" ++
       							 inet_parse:ntoa(IP) ++
       							 ":" ++
       							 integer_to_list(Port)
      +						         ++ "#" ++ atom_to_list(Node)
       							 ++ ")"
       					     end,
       				       ?LI([?C(R ++ FIP)])
      
      From 25009ff9f414bffc7ff782e7367b6312ad0a5bef Mon Sep 17 00:00:00 2001
      From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?=
       
      Date: Mon, 19 Jan 2009 11:59:40 +0000
      Subject: [PATCH 169/582] Merge from trunk (r1764 to r1787).
      
      Warning: Ejabberd may be broken until the merge is completly finished.
      
      PR:		EJABP-1
      
      SVN Revision: 1827
      ---
       ChangeLog                           | 41 ++++++++++++-
       doc/guide.html                      | 12 +++-
       doc/guide.tex                       | 12 ++++
       src/ejabberd_app.erl                |  2 +-
       src/ejabberd_auth.erl               |  4 +-
       src/ejabberd_auth_internal.erl      |  4 +-
       src/ejabberd_auth_odbc.erl          |  4 +-
       src/ejabberd_c2s.erl                |  8 ++-
       src/ejabberd_ctl.erl                |  9 +--
       src/ejabberd_listener.erl           |  8 ++-
       src/ejabberd_s2s_out.erl            |  6 +-
       src/mod_configure.erl               | 92 ++++++++++++++++++-----------
       src/mod_last.erl                    |  2 +-
       src/mod_last_odbc.erl               |  2 +-
       src/mod_pubsub/mod_pubsub.erl       | 12 ++--
       src/mod_pubsub/node_default.erl     |  4 +-
       src/mod_pubsub/node_mb.erl          |  1 +
       src/mod_pubsub/nodetree_default.erl | 10 ++--
       src/mod_pubsub/nodetree_virtual.erl | 12 ++--
       src/mod_roster.erl                  | 25 +++++++-
       src/mod_roster_odbc.erl             | 25 +++++++-
       src/mod_shared_roster.erl           |  4 +-
       src/msgs/ru.msg                     |  2 +-
       src/msgs/ru.po                      |  2 +-
       src/tls/tls.erl                     | 10 +++-
       src/tls/tls_drv.c                   |  7 +++
       src/web/ejabberd_web_admin.erl      | 53 +++++++++++++----
       src/web/ejabberd_web_admin.hrl      | 14 +++++
       28 files changed, 289 insertions(+), 98 deletions(-)
      
      diff --git a/ChangeLog b/ChangeLog
      index 64f489264..8a3b0c38b 100644
      --- a/ChangeLog
      +++ b/ChangeLog
      @@ -1,6 +1,6 @@
       2009-01-19  Jean-Sébastien Pédron  
       
      -	Merge from trunk (r1752 to r1764).
      +	Merge from trunk (r1752 to r1787).
       
       2009-01-19  Jean-Sébastien Pédron  
       
      @@ -77,6 +77,16 @@
       	* src/ejabberd_c2s.erl: Fix bug in handle_info/3 when dealing with
       	VCARD requests: convert to IQ struct before invoking gen_iq_handler.
       
      +2009-01-09  Badlop  
      +
      +	* src/mod_configure.erl: Fix access check for vhost configuration
      +
      +2009-01-08  Mickael Remond  
      +
      +	* src/ejabberd_listener.erl: Define send timeout option to avoid
      +	blocking on socket send (EJAB-746).
      +	* src/ejabberd_s2s_out.erl: Likewise.
      +
       2009-01-08  Christophe Romain 
       
       	* src/mod_pubsub/mod_pubsub.erl: completely support subscription using
      @@ -143,6 +153,35 @@
       	ejabberd_sm, ejabberd_router, ejabberd_hooks, mod_last, mod_roster to
       	use binary() storage.
       
      +2009-01-07  Badlop  
      +
      +	* src/mod_roster.erl: Show hyperlinks to local contacts when
      +	browsing roster of account in Web Admin (EJAB-480)
      +	* src/mod_roster_odbc.erl: Likewise
      +
      +	* src/web/ejabberd_web_admin.erl: WebAdmin serves Guide and links
      +	to related sections; the path to guide.html can be configured with
      +	option doc_path (EJAB-837)
      +	* src/web/ejabberd_web_admin.hrl: Likewise
      +	* src/mod_shared_roster.erl: Likewise
      +	* doc/guide.tex: Likewise
      +	* doc/guide.html: Likewise
      +
      +2009-01-06  Badlop  
      +
      +	* src/msgs/ru.po: Fix typo (thanks to Dominges)
      +	* src/msgs/ru.msg: Likewise
      +
      +2009-01-05  Alexey Shchepin  
      +
      +	* src/tls/tls_drv.c: Added a flag to avoid certificate validation
      +	* src/tls/tls.erl: Likewise
      +	* src/ejabberd_c2s.erl: Likewise
      +
      +2009-01-03  Badlop  
      +
      +	* src/*.erl: Fix EDoc comments
      +
       2009-01-03  Christophe Romain 
       
       	* src/mod_pubsub/mod_pubsub.erl: deliver notification depending on
      diff --git a/doc/guide.html b/doc/guide.html
      index 6d143c335..b7466955e 100644
      --- a/doc/guide.html
      +++ b/doc/guide.html
      @@ -3072,7 +3072,17 @@ web browser to https://192.168.1.1:5280/admin/:
                                   tls, {certfile, "/usr/local/etc/server.pem"}]},
         ...
        ]}.
      -

      +

      Certain pages in the ejabberd Web Admin contain a link to a related +section in the ejabberd Installation and Operation Guide. +In order to view such links, a copy in HTML format of the Guide must +be installed in the system. +The file is searched by default in +"/share/doc/ejabberd/guide.html". +The directory of the documentation can be specified in +ejabberd.cfg with the option doc_path. +For example: +

      {doc_path, "/usr/local/share/doc/ejabberd/"}.
      +

      4.3  Ad-hoc Commands

      If you enable mod_configure and mod_adhoc, you can perform several administrative tasks in ejabberd with a Jabber client. diff --git a/doc/guide.tex b/doc/guide.tex index afc63a3ff..c3fb6db07 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -3943,6 +3943,18 @@ Examples: \end{verbatim} \end{itemize} +Certain pages in the ejabberd Web Admin contain a link to a related +section in the ejabberd Installation and Operation Guide. +In order to view such links, a copy in HTML format of the Guide must +be installed in the system. +The file is searched by default in +\term{"/share/doc/ejabberd/guide.html"}. +The directory of the documentation can be specified in +\term{ejabberd.cfg} with the option \term{doc\_path}. +For example: +\begin{verbatim} +{doc_path, "/usr/local/share/doc/ejabberd/"}. +\end{verbatim} \makesection{adhoccommands}{Ad-hoc Commands} diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index afe700a76..ea193eebb 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -163,7 +163,7 @@ connect_nodes() -> end. %% @spec () -> string() -%% Returns the full path to the ejabberd log file. +%% @doc Returns the full path to the ejabberd log file. %% It first checks for application configuration parameter 'log_path'. %% If not defined it checks the environment variable EJABBERD_LOG_PATH. %% And if that one is neither defined, returns the default value: diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 6462b6edd..8f089afe6 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -260,7 +260,7 @@ is_user_exists_in_other_modules(Module, User, Server) -> end, auth_modules(Server)--[Module]). %% @spec (User, Server) -> ok | error | {error, not_allowed} -%% Remove user. +%% @doc Remove user. %% Note: it may return ok even if there was some problem removing the user. remove_user(User, Server) -> R = lists:foreach( @@ -274,7 +274,7 @@ remove_user(User, Server) -> R. %% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request | error -%% Try to remove user if the provided password is correct. +%% @doc Try to remove user if the provided password is correct. %% The removal is attempted in each auth method provided: %% when one returns 'ok' the loop stops; %% if no method returns 'ok' then it returns the error message indicated by the last method attempted. diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index ae4ef4989..15f073866 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -254,7 +254,7 @@ is_user_exists(User, Server) -> end. %% @spec (User, Server) -> ok -%% Remove user. +%% @doc Remove user. %% Note: it returns ok even if there was some problem removing the user. remove_user(User, Server) -> try @@ -272,7 +272,7 @@ remove_user(User, Server) -> end. %% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request -%% Remove user if the provided password is correct. +%% @doc Remove user if the provided password is correct. remove_user(User, Server, Password) -> try LUser = exmpp_stringprep:nodeprep(User), diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index 1f0a97b0c..e2f106b88 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -227,7 +227,7 @@ is_user_exists(User, Server) -> end. %% @spec (User, Server) -> ok | error -%% Remove user. +%% @doc Remove user. %% Note: it may return ok even if there was some problem removing the user. remove_user(User, Server) -> try @@ -242,7 +242,7 @@ remove_user(User, Server) -> end. %% @spec (User, Server, Password) -> ok | error | not_exists | not_allowed -%% Remove user if the provided password is correct. +%% @doc Remove user if the provided password is correct. remove_user(User, Server, Password) -> try LUser = exmpp_stringprep:nodeprep(User), diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 649eadf6d..c850ccf13 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -175,9 +175,11 @@ init([{SockMod, Socket}, Opts]) -> StartTLSRequired = lists:member(starttls_required, Opts), TLSEnabled = lists:member(tls, Opts), TLS = StartTLS orelse StartTLSRequired orelse TLSEnabled, - TLSOpts = lists:filter(fun({certfile, _}) -> true; - (_) -> false - end, Opts), + TLSOpts1 = + lists:filter(fun({certfile, _}) -> true; + (_) -> false + end, Opts), + TLSOpts = [verify_none | TLSOpts1], IP = peerip(SockMod, Socket), %% Check if IP is blacklisted: case is_ip_blacklisted(IP) of diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl index 328974189..b7b1b9963 100644 --- a/src/ejabberd_ctl.erl +++ b/src/ejabberd_ctl.erl @@ -226,8 +226,7 @@ process2(Args) -> %% Command calling %%----------------------------- -%% @spec (Args::[string()]) -> -%% String::string() | Code::integer() | {String::string(), Code::integer()} +%% @spec (Args::[string()]) -> string() | integer() | {string(), integer()} try_run_ctp(Args) -> try ejabberd_hooks:run_fold(ejabberd_ctl_process, false, [Args]) of false when Args /= [] -> @@ -248,8 +247,7 @@ try_run_ctp(Args) -> {io_lib:format("Error in ejabberd ctl process: '~p' ~p", [Error, Why]), ?STATUS_USAGE} end. -%% @spec (Args::[string()]) -> -%% String::string() | Code::integer() | {String::string(), Code::integer()} +%% @spec (Args::[string()]) -> string() | integer() | {string(), integer()} try_call_command(Args) -> try call_command(Args) of {error, command_unknown} -> @@ -264,8 +262,7 @@ try_call_command(Args) -> {io_lib:format("Problem '~p ~p' occurred executing the command.~nStacktrace: ~p", [A, Why, Stack]), ?STATUS_ERROR} end. -%% @spec (Args::[string()]) -> -%% String::string() | Code::integer() | {String::string(), Code::integer()} | {error, ErrorType} +%% @spec (Args::[string()]) -> string() | integer() | {string(), integer()} | {error, ErrorType} call_command([CmdString | Args]) -> {ok, CmdStringU, _} = regexp:gsub(CmdString, "-", "_"), Command = list_to_atom(CmdStringU), diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 9c46f6d4c..6992c6a53 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -38,6 +38,9 @@ -include("ejabberd.hrl"). +%% We do not block on send anymore. +-define(TCP_SEND_TIMEOUT, 15000). + start_link() -> supervisor:start_link({local, ejabberd_listeners}, ?MODULE, []). @@ -96,10 +99,11 @@ init(Port, Module, Opts) -> end, Opts), Res = gen_tcp:listen(Port, [binary, - {packet, 0}, + {packet, 0}, {active, false}, {reuseaddr, true}, {nodelay, true}, + {send_timeout, ?TCP_SEND_TIMEOUT}, {keepalive, true} | SockOpts]), case Res of diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 553609a97..bdb67c095 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -96,6 +96,9 @@ %% -define(FSMLIMITS, [{max_queue, 2000}]). -define(FSMTIMEOUT, 30000). +%% We do not block on send anymore. +-define(TCP_SEND_TIMEOUT, 15000). + %% Maximum delay to wait before retrying to connect after a failed attempt. %% Specified in miliseconds. Default value is 5 minutes. -define(MAX_RETRY_DELAY, 300000). @@ -259,6 +262,7 @@ open_socket2(Type, Addr, Port) -> Timeout = outgoing_s2s_timeout(), case (catch ejabberd_socket:connect(Addr, Port, [binary, {packet, 0}, + {send_timeout, ?TCP_SEND_TIMEOUT}, {active, false}, Type], Timeout)) of {ok, _Socket} = R -> R; diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 00fcee006..5e91e15dc 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -319,8 +319,10 @@ adhoc_local_items(Acc, From, To, Lang) -> {result, Its} -> Its; empty -> [] end, + PermLev = get_permission_level(From), %% Recursively get all configure commands - Nodes = recursively_get_local_items(LServer, "", exmpp_jid:domain(To), Lang), + Nodes = recursively_get_local_items(PermLev, LServer, "", exmpp_jid:domain_as_list(Server), + Lang), Nodes1 = lists:filter( fun(N) -> Nd = exmpp_xml:get_attribute(N, 'node', ""), @@ -337,15 +339,15 @@ adhoc_local_items(Acc, From, To, Lang) -> Acc end. -recursively_get_local_items(_LServer, "online users", _Server, _Lang) -> +recursively_get_local_items(_PermLev, _LServer, "online users", _Server, _Lang) -> []; -recursively_get_local_items(_LServer, "all users", _Server, _Lang) -> +recursively_get_local_items(_PermLev, _LServer, "all users", _Server, _Lang) -> []; -recursively_get_local_items(LServer, Node, Server, Lang) -> +recursively_get_local_items(PermLev, LServer, Node, Server, Lang) -> LNode = tokenize(Node), - Items = case get_local_items(LServer, LNode, Server, Lang) of + Items = case get_local_items({PermLev, LServer}, LNode, Server, Lang) of {result, Res} -> Res; {error, _Error} -> @@ -360,11 +362,17 @@ recursively_get_local_items(LServer, Node, Server, Lang) -> []; true -> [N, recursively_get_local_items( - LServer, Nd, Server, Lang)] + PermLev, LServer, Nd, Server, Lang)] end end, Items)), Nodes. +get_permission_level(JID) -> + case acl:match_rule(global, configure, JID) of + allow -> global; + deny -> vhost + end. + %%%----------------------------------------------------------------------- -define(ITEMS_RESULT(Allow, LNode, Fallback), @@ -372,7 +380,8 @@ recursively_get_local_items(LServer, Node, Server, Lang) -> deny -> Fallback; allow -> - case get_local_items(LServer, LNode, + PermLev = get_permission_level(From), + case get_local_items({PermLev, LServer}, LNode, exmpp_jid:jid_to_binary(To), Lang) of {result, Res} -> {result, Res}; @@ -396,7 +405,8 @@ get_local_items(Acc, From, To, <<>>, Lang) -> deny -> {result, Items}; allow -> - case get_local_items(LServer, [], + PermLev = get_permission_level(From), + case get_local_items({PermLev, LServer}, [], exmpp_jid:jid_to_binary(To), Lang) of {result, Res} -> {result, Items ++ Res}; @@ -462,6 +472,9 @@ get_local_items(Acc, From, To, Node, Lang) -> %%%----------------------------------------------------------------------- +%% @spec ({PermissionLevel, Host}, [string()], Server::string(), Lang) +%% -> {result, [xmlelement()]} +%% PermissionLevel = global | vhost get_local_items(_Host, [], Server, Lang) -> {result, [?NODE("Configuration", <<"config">>), @@ -498,13 +511,13 @@ get_local_items(_Host, ["user"], Server, Lang) -> get_local_items(_Host, ["http:" | _], _Server, _Lang) -> {result, []}; -get_local_items(Host, ["online users"], _Server, _Lang) -> +get_local_items({_, Host}, ["online users"], _Server, _Lang) -> {result, get_online_vh_users(Host)}; -get_local_items(Host, ["all users"], _Server, _Lang) -> +get_local_items({_, Host}, ["all users"], _Server, _Lang) -> {result, get_all_vh_users(Host)}; -get_local_items(Host, ["all users", [$@ | Diap]], _Server, _Lang) -> +get_local_items({_, Host}, ["all users", [$@ | Diap]], _Server, _Lang) -> case catch ejabberd_auth:get_vh_registered_users(Host) of {'EXIT', _Reason} -> {error, 'internal-server-error'}; @@ -528,10 +541,10 @@ get_local_items(Host, ["all users", [$@ | Diap]], _Server, _Lang) -> end end; -get_local_items(Host, ["outgoing s2s"], _Server, Lang) -> +get_local_items({_, Host}, ["outgoing s2s"], _Server, Lang) -> {result, get_outgoing_s2s(Host, Lang)}; -get_local_items(Host, ["outgoing s2s", To], _Server, Lang) -> +get_local_items({_, Host}, ["outgoing s2s", To], _Server, Lang) -> {result, get_outgoing_s2s(Host, Lang, To)}; get_local_items(_Host, ["running nodes"], Server, Lang) -> @@ -540,7 +553,7 @@ get_local_items(_Host, ["running nodes"], Server, Lang) -> get_local_items(_Host, ["stopped nodes"], _Server, Lang) -> {result, get_stopped_nodes(Lang)}; -get_local_items(_Host, ["running nodes", ENode], Server, Lang) -> +get_local_items({global, _Host}, ["running nodes", ENode], Server, Lang) -> ENodeB = list_to_binary(ENode), {result, [?NODE("Database", <<"running nodes/", ENodeB/binary, "/DB">>), @@ -552,6 +565,11 @@ get_local_items(_Host, ["running nodes", ENode], Server, Lang) -> ?NODE("Shut Down Service", <<"running nodes/", ENodeB/binary, "/shutdown">>) ]}; +get_local_items({vhost, _Host}, ["running nodes", ENode], Server, Lang) -> + {result, + [?NODE("Modules", "running nodes/" ++ ENode ++ "/modules") + ]}; + get_local_items(_Host, ["running nodes", _ENode, "DB"], _Server, _Lang) -> {result, []}; @@ -721,8 +739,8 @@ get_stopped_nodes(_Lang) -> %%------------------------------------------------------------------------- --define(COMMANDS_RESULT(Allow, From, To, Request), - case Allow of +-define(COMMANDS_RESULT(LServerOrGlobal, From, To, Request), + case acl:match_rule(LServerOrGlobal, configure, From) of deny -> {error, 'forbidden'}; allow -> @@ -732,24 +750,23 @@ get_stopped_nodes(_Lang) -> adhoc_local_commands(Acc, From, To, #adhoc_request{node = Node} = Request) -> LServer = exmpp_jid:ldomain_as_list(To), LNode = tokenize(Node), - Allow = acl:match_rule(LServer, configure, From), case LNode of ["running nodes", _ENode, "DB"] -> - ?COMMANDS_RESULT(Allow, From, To, Request); + ?COMMANDS_RESULT(global, From, To, Request); ["running nodes", _ENode, "modules", _] -> - ?COMMANDS_RESULT(Allow, From, To, Request); + ?COMMANDS_RESULT(LServer, From, To, Request); ["running nodes", _ENode, "backup", _] -> - ?COMMANDS_RESULT(Allow, From, To, Request); + ?COMMANDS_RESULT(global, From, To, Request); ["running nodes", _ENode, "import", _] -> - ?COMMANDS_RESULT(Allow, From, To, Request); + ?COMMANDS_RESULT(global, From, To, Request); ["running nodes", _ENode, "restart"] -> - ?COMMANDS_RESULT(Allow, From, To, Request); + ?COMMANDS_RESULT(global, From, To, Request); ["running nodes", _ENode, "shutdown"] -> - ?COMMANDS_RESULT(Allow, From, To, Request); + ?COMMANDS_RESULT(global, From, To, Request); ["config", _] -> - ?COMMANDS_RESULT(Allow, From, To, Request); + ?COMMANDS_RESULT(LServer, From, To, Request); ?NS_ADMINL(_) -> - ?COMMANDS_RESULT(Allow, From, To, Request); + ?COMMANDS_RESULT(LServer, From, To, Request); _ -> Acc end. @@ -1545,7 +1562,7 @@ set_form(_From, Host, ["config", "access"], _Lang, XData) -> {error, 'bad-request'} end; -set_form(_From, _Host, ?NS_ADMINL("add-user"), _Lang, XData) -> +set_form(From, Host, ?NS_ADMINL("add-user"), _Lang, XData) -> AccountString = get_value("accountjid", XData), Password = get_value("password", XData), Password = get_value("password-verify", XData), @@ -1553,17 +1570,19 @@ set_form(_From, _Host, ?NS_ADMINL("add-user"), _Lang, XData) -> User = exmpp_jid:lnode_as_list(AccountJID), Server = exmpp_jid:ldomain_as_list(AccountJID), true = lists:member(Server, ?MYHOSTS), + true = (Server == Host) orelse (get_permission_level(From) == global), ejabberd_auth:try_register(User, Server, Password), {result, []}; -set_form(_From, _Host, ?NS_ADMINL("delete-user"), _Lang, XData) -> +set_form(From, Host, ?NS_ADMINL("delete-user"), _Lang, XData) -> AccountStringList = get_values("accountjids", XData), [_|_] = AccountStringList, ASL2 = lists:map( fun(AccountString) -> - JID = exmpp_jid:list_to_jid(AccountString), + JID = exmpp_jid:parse_jid(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), - Server = exmpp_jid:ldomain_as_list(JID), + Server = exmpp_jid:ldomain_as_list(JID), + true = (Server == Host) orelse (get_permission_level(From) == global), true = ejabberd_auth:is_user_exists(User, Server), {User, Server} end, @@ -1571,11 +1590,12 @@ set_form(_From, _Host, ?NS_ADMINL("delete-user"), _Lang, XData) -> [ejabberd_auth:remove_user(User, Server) || {User, Server} <- ASL2], {result, []}; -set_form(_From, _Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> +set_form(From, Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> AccountString = get_value("accountjid", XData), JID = exmpp_jid:list_to_jid(AccountString), LUser = [_|_] = exmpp_jid:lnode_as_list(JID), LServer = exmpp_jid:ldomain_as_list(JID), + true = (LServer == Host) orelse (get_permission_level(From) == global), %% Code copied from ejabberd_sm.erl case exmpp_jid:lresource_as_list(JID) of undefined -> @@ -1589,11 +1609,12 @@ set_form(_From, _Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> end, {result, []}; -set_form(_From, _Host, ?NS_ADMINL("get-user-password"), Lang, XData) -> +set_form(From, Host, ?NS_ADMINL("get-user-password"), Lang, XData) -> AccountString = get_value("accountjid", XData), JID = exmpp_jid:list_to_jid(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), Server = exmpp_jid:ldomain_as_list(JID), + true = (Server == Host) orelse (get_permission_level(From) == global), Password = ejabberd_auth:get_password(User, Server), true = is_list(Password), {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = @@ -1602,21 +1623,23 @@ set_form(_From, _Host, ?NS_ADMINL("get-user-password"), Lang, XData) -> ?XFIELD(<<"text-single">>, "Password", <<"password">>, list_to_binary(Password)) ]}]}; -set_form(_From, _Host, ?NS_ADMINL("change-user-password"), _Lang, XData) -> +set_form(From, Host, ?NS_ADMINL("change-user-password"), _Lang, XData) -> AccountString = get_value("accountjid", XData), Password = get_value("password", XData), JID = exmpp_jid:list_to_jid(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), Server = exmpp_jid:ldomain_as_list(JID), + true = (Server == Host) orelse (get_permission_level(From) == global), true = ejabberd_auth:is_user_exists(User, Server), ejabberd_auth:set_password(User, Server, Password), {result, []}; -set_form(_From, _Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> +set_form(From, Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> AccountString = get_value("accountjid", XData), JID = exmpp_jid:list_to_jid(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), Server = exmpp_jid:ldomain_as_list(JID), + true = (Server == Host) orelse (get_permission_level(From) == global), %% Code copied from web/ejabberd_web_admin.erl %% TODO: Update time format to XEP-0202: Entity Time @@ -1649,11 +1672,12 @@ set_form(_From, _Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> ?XFIELD(<<"text-single">>, "Last login", <<"lastlogin">>, list_to_binary(FLast)) ]}]}; -set_form(_From, _Host, ?NS_ADMINL("user-stats"), Lang, XData) -> +set_form(From, Host, ?NS_ADMINL("user-stats"), Lang, XData) -> AccountString = get_value("accountjid", XData), JID = exmpp_jid:list_to_jid(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), Server = exmpp_jid:ldomain_as_list(JID), + true = (Server == Host) orelse (get_permission_level(From) == global), Resources = ejabberd_sm:get_user_resources(exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID)), diff --git a/src/mod_last.erl b/src/mod_last.erl index 4ddb716f3..613e49317 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -168,7 +168,7 @@ store_last_info(User, Server, TimeStamp, Status) ok end. -%% @spec (LUser::string(), LServer::string() -> +%% @spec (LUser::string(), LServer::string()) -> %% {ok, Timestamp::integer(), Status::string()} | not_found get_last_info(LUser, LServer) when is_binary(LUser), is_binary(LServer) -> case catch mnesia:dirty_read(last_activity, {LUser, LServer}) of diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 4d8ea152d..c8533f5d8 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -168,7 +168,7 @@ store_last_info(User, Server, TimeStamp, Status) ok end. -%% @spec (LUser::string(), LServer::string() -> +%% @spec (LUser::string(), LServer::string()) -> %% {ok, Timestamp::integer(), Status::string()} | not_found get_last_info(LUser, LServer) -> Username = ejabberd_odbc:escape(LUser), diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 045cedf8c..a78ac6bad 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -33,7 +33,7 @@ %%% This module uses version 1.12 of the specification as a base. %%% Most of the specification is implemented. %%% Functions concerning configuration should be rewritten. -%%% Code is derivated from the original pubsub v1.7, by Alexey Shchepin +%%% Code is derivated from the original pubsub v1.7, by Alexey Shchepin %%% TODO %%% plugin: generate Reply (do not use broadcast atom anymore) @@ -1749,10 +1749,11 @@ get_items(Host, Node, From) -> send_last_item(Host, Node, LJID) -> send_items(Host, Node, LJID, last). -%% @spec (Host, Node, LJID) -> any() +%% @spec (Host, Node, LJID, Number) -> any() %% Host = host() %% Node = pubsubNode() %% LJID = {U, S, []} +%% Number = last | integer() %% @doc

      Resend the items of a node to the user.

      %% @todo use cache-last-item feature send_items(Host, Node, {LU, LS, LR} = LJID, Number) -> @@ -2157,10 +2158,9 @@ is_to_deliver({User, Server, _}, _, true) -> end, false, Ss) end. -%% @spec (Elem, Payload) -> int() -%% Elem = atom() +%% @spec (Payload) -> int() %% Payload = term() -%% @doc

      Count occurence of given element in payload.

      +%% @doc

      Count occurence of XML elements in payload.

      payload_xmlelements(Payload) -> payload_xmlelements(Payload, 0). payload_xmlelements([], Count) -> Count; payload_xmlelements([#xmlel{}|Tail], Count) -> payload_xmlelements(Tail, Count+1); @@ -2168,7 +2168,7 @@ payload_xmlelements([_|Tail], Count) -> payload_xmlelements(Tail, Count). %% @spec (Els) -> stanza() %% Els = [xmlelement()] -%% @doc

      Build pubsub event stanza +%% @doc

      Build pubsub event stanza

      event_stanza(Els) -> #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = Els}]}. diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 8acf2449d..91d4e7054 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -677,7 +677,7 @@ set_state(_) -> del_state(StateId) -> mnesia:delete({pubsub_state, StateId}). -%% @spec (Host, Node) -> [Items] | [] +%% @spec (Host, Node, From) -> [Items] | [] %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() %% Items = mod_pubsub:pubsubItems() @@ -784,7 +784,7 @@ set_item(Item) when is_record(Item, pubsub_item) -> set_item(_) -> {error, 'internal-server-error'}. -%% @spec (ItemId) -> ok | {error, Reason::stanzaError()} +%% @spec (Host, Node, ItemId) -> ok | {error, Reason::stanzaError()} %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() %% ItemId = string() diff --git a/src/mod_pubsub/node_mb.erl b/src/mod_pubsub/node_mb.erl index d90f2391f..a05ea883c 100644 --- a/src/mod_pubsub/node_mb.erl +++ b/src/mod_pubsub/node_mb.erl @@ -30,6 +30,7 @@ %%% {plugins, ["default", "pep","mb"]}, %%% {pep_mapping, [{"urn:xmpp:microblog", "mb"}]} %%% ]}, +%%%

      %%%

      PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.

      -module(node_mb). diff --git a/src/mod_pubsub/nodetree_default.erl b/src/mod_pubsub/nodetree_default.erl index 126ea7f75..6bac99434 100644 --- a/src/mod_pubsub/nodetree_default.erl +++ b/src/mod_pubsub/nodetree_default.erl @@ -97,12 +97,12 @@ set_node(Record) when is_record(Record, pubsub_node) -> set_node(_) -> {error, 'internal-server-error'}. -%% @spec (Host, Node) -> pubsubNode() | {error, Reason} -%% Host = mod_pubsub:host() -%% Node = mod_pubsub:pubsubNode() get_node(Host, Node, _From) -> get_node(Host, Node). +%% @spec (Host, Node) -> pubsubNode() | {error, Reason} +%% Host = mod_pubsub:host() +%% Node = mod_pubsub:pubsubNode() get_node(Host, Node) -> case catch mnesia:read({pubsub_node, {Host, Node}}) of [Record] when is_record(Record, pubsub_node) -> Record; @@ -110,11 +110,11 @@ get_node(Host, Node) -> Error -> Error end. -%% @spec (Key) -> [pubsubNode()] | {error, Reason} -%% Key = mod_pubsub:host() | mod_pubsub:jid() get_nodes(Key, _From) -> get_nodes(Key). +%% @spec (Key) -> [pubsubNode()] | {error, Reason} +%% Key = mod_pubsub:host() | mod_pubsub:jid() get_nodes(Key) -> mnesia:match_object(#pubsub_node{nodeid = {Key, '_'}, _ = '_'}). diff --git a/src/mod_pubsub/nodetree_virtual.erl b/src/mod_pubsub/nodetree_virtual.erl index 2df61e70a..b76419b6c 100644 --- a/src/mod_pubsub/nodetree_virtual.erl +++ b/src/mod_pubsub/nodetree_virtual.erl @@ -84,24 +84,24 @@ options() -> set_node(_NodeRecord) -> ok. +get_node(Host, Node, _From) -> + get_node(Host, Node). + %% @spec (Host, Node) -> pubsubNode() %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() %% @doc

      Virtual node tree does not handle a node database. Any node is considered %% as existing. Node record contains default values.

      -get_node(Host, Node, _From) -> - get_node(Host, Node). - get_node(Host, Node) -> #pubsub_node{nodeid = {Host, Node}}. +get_nodes(Key, _From) -> + get_nodes(Key). + %% @spec (Key) -> [pubsubNode()] %% Host = mod_pubsub:host() | mod_pubsub:jid() %% @doc

      Virtual node tree does not handle a node database. Any node is considered %% as existing. Nodes list can not be determined.

      -get_nodes(Key, _From) -> - get_nodes(Key). - get_nodes(_Key) -> []. diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 05f0381ac..569c30b2d 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -883,10 +883,9 @@ user_roster(User, Server, Query, Lang) -> [?C(Group), ?BR] end, R#roster.groups), Pending = ask_to_pending(R#roster.ask), - {U, S, R} = R#roster.jid, + TDJID = build_contact_jid_td(R#roster.jid), ?XE("tr", - [?XAC("td", [{"class", "valign"}], - catch exmpp_jid:jid_to_list(U, S, R)), + [TDJID, ?XAC("td", [{"class", "valign"}], binary_to_list(R#roster.name)), ?XAC("td", [{"class", "valign"}], @@ -934,6 +933,26 @@ user_roster(User, Server, Query, Lang) -> ])] end. +build_contact_jid_td({U, S, R}) -> + %% Convert {U, S, R} into {jid, U, S, R, U, S, R}: + ContactJID = exmpp_jid:make_jid(U, S, R), + JIDURI = case {exmpp_jid:lnode(ContactJID), exmpp_jid:ldomain(ContactJID)} of + {undefined, _} -> ""; + {CUser, CServer} -> + CUser_S = binary_to_list(CUser), + CServer_S = binary_to_list(CServer), + case lists:member(CServer_S, ?MYHOSTS) of + false -> ""; + true -> "/admin/server/" ++ CServer_S ++ "/user/" ++ CUser_S ++ "/" + end + end, + case JIDURI of + [] -> + ?XAC('td', [#xmlattr{name = 'class', value = <<"valign">>}], exmpp_jid:jid_to_list(ContactJID)); + URI when is_list(URI) -> + ?XAE('td', [#xmlattr{name = 'class', value = <<"valign">>}], [?AC(JIDURI, exmpp_jid:jid_to_list(ContactJID))]) + end. + user_roster_parse_query(User, Server, Items, Query) -> case lists:keysearch("addjid", 1, Query) of {value, _} -> diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 3860a09c7..d41b911ce 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -922,10 +922,9 @@ user_roster(User, Server, Query, Lang) -> [?C(Group), ?BR] end, R#roster.groups), Pending = ask_to_pending(R#roster.ask), - {U, S, R} = R#roster.jid, + TDJID = build_contact_jid_td(R#roster.jid), ?XE("tr", - [?XAC("td", [{"class", "valign"}], - catch exmpp_jid:jid_to_list(U, S, R)), + [TDJID, ?XAC("td", [{"class", "valign"}], binary_to_list(R#roster.name)), ?XAC("td", [{"class", "valign"}], @@ -973,6 +972,26 @@ user_roster(User, Server, Query, Lang) -> ])] end. +build_contact_jid_td({U, S, R}) -> + %% Convert {U, S, R} into {jid, U, S, R, U, S, R}: + ContactJID = exmpp_jid:make_jid(U, S, R), + JIDURI = case {exmpp_jid:lnode(ContactJID), exmpp_jid:ldomain(ContactJID)} of + {undefined, _} -> ""; + {CUser, CServer} -> + CUser_S = binary_to_list(CUser), + CServer_S = binary_to_list(CServer), + case lists:member(CServer_S, ?MYHOSTS) of + false -> ""; + true -> "/admin/server/" ++ CServer_S ++ "/user/" ++ CUser_S ++ "/" + end + end, + case JIDURI of + [] -> + ?XAC('td', [#xmlattr{name = 'class', value = <<"valign">>}], exmpp_jid:jid_to_list(ContactJID)); + URI when is_list(URI) -> + ?XAE('td', [#xmlattr{name = 'class', value = <<"valign">>}], [?AC(JIDURI, exmpp_jid:jid_to_list(ContactJID))]) + end. + user_roster_parse_query(User, Server, Items, Query) -> case lists:keysearch("addjid", 1, Query) of {value, _} -> diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 6ed4fbb0c..d3bbd9aab 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -740,7 +740,7 @@ list_shared_roster_groups(Host, Query, Lang) -> ] )] )]), - [?XC("h1", ?T("Shared Roster Groups"))] ++ + ?H1GL(?T("Shared Roster Groups"), "modsharedroster", "mod_shared_roster") ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; @@ -839,7 +839,7 @@ shared_roster_group(Host, Group, Query, Lang) -> ] )] )]), - [?XC("h1", ?T("Shared Roster Groups"))] ++ + ?H1GL(?T("Shared Roster Groups"), "modsharedroster", "mod_shared_roster") ++ [?XC("h2", ?T("Group ") ++ Group)] ++ case Res of ok -> [?CT("Submitted"), ?P]; diff --git a/src/msgs/ru.msg b/src/msgs/ru.msg index 94bc74f42..93ca02cc6 100644 --- a/src/msgs/ru.msg +++ b/src/msgs/ru.msg @@ -166,7 +166,7 @@ {"Name","Название"}. {"Never","Никогда"}. {"Nickname is already in use by another occupant","Псевдоним занят кем-то из присутствующих"}. -{"Nickname is registered by another person","Псевдоним зарегистирован кем-то другим"}. +{"Nickname is registered by another person","Псевдоним зарегистрирован кем-то другим"}. {"Nickname Registration at ","Регистрация псевдонима на "}. {"Nickname ~s does not exist in the room","Псевдоним ~s в комнате отсутствует"}. {"Nickname","Псевдоним"}. diff --git a/src/msgs/ru.po b/src/msgs/ru.po index 347eafa40..8c6aa6207 100644 --- a/src/msgs/ru.po +++ b/src/msgs/ru.po @@ -723,7 +723,7 @@ msgstr "Псевдоним занят кем-то из присутствующ #: mod_muc/mod_muc_room.erl:973 mod_muc/mod_muc_room.erl:1492 msgid "Nickname is registered by another person" -msgstr "Псевдоним зарегистирован кем-то другим" +msgstr "Псевдоним зарегистрирован кем-то другим" #: mod_muc/mod_muc_room.erl:1473 msgid "You have been banned from this room" diff --git a/src/tls/tls.erl b/src/tls/tls.erl index 72897cf08..7281fd475 100644 --- a/src/tls/tls.erl +++ b/src/tls/tls.erl @@ -59,6 +59,7 @@ -define(GET_DECRYPTED_INPUT, 6). -define(GET_PEER_CERTIFICATE, 7). -define(GET_VERIFY_RESULT, 8). +-define(VERIFY_NONE, 16#10000). -record(tlssock, {tcpsock, tlsport}). @@ -120,13 +121,20 @@ tcp_to_tls(TCPSocket, Options) -> {error, already_loaded} -> ok end, Port = open_port({spawn, tls_drv}, [binary]), + Flags = + case lists:member(verify_none, Options) of + true -> + ?VERIFY_NONE; + false -> + 0 + end, Command = case lists:member(connect, Options) of true -> ?SET_CERTIFICATE_FILE_CONNECT; false -> ?SET_CERTIFICATE_FILE_ACCEPT end, - case port_control(Port, Command, CertFile ++ [0]) of + case port_control(Port, Command bor Flags, CertFile ++ [0]) of <<0>> -> {ok, #tlssock{tcpsock = TCPSocket, tlsport = Port}}; <<1, Error/binary>> -> diff --git a/src/tls/tls_drv.c b/src/tls/tls_drv.c index b90cab87c..2f8e56150 100644 --- a/src/tls/tls_drv.c +++ b/src/tls/tls_drv.c @@ -272,6 +272,7 @@ static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) #define GET_DECRYPTED_INPUT 6 #define GET_PEER_CERTIFICATE 7 #define GET_VERIFY_RESULT 8 +#define VERIFY_NONE 0x10000 #define die_unless(cond, errstr) \ @@ -312,6 +313,9 @@ static int tls_drv_control(ErlDrvData handle, int size; ErlDrvBinary *b; X509 *cert; + unsigned int flags = command; + + command &= 0xffff; ERR_clear_error(); switch (command) @@ -354,6 +358,9 @@ static int tls_drv_control(ErlDrvData handle, d->ssl = SSL_new(ssl_ctx); die_unless(d->ssl, "SSL_new failed"); + if (flags & VERIFY_NONE) + SSL_set_verify(d->ssl, SSL_VERIFY_NONE, verify_callback); + d->bio_read = BIO_new(BIO_s_mem()); d->bio_write = BIO_new(BIO_s_mem()); diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index a43e92cd0..fbac03762 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -40,6 +40,30 @@ -include("ejabberd_web_admin.hrl"). +process(["doc", LocalFile], _Request) -> + DocPath = case ejabberd_config:get_global_option(doc_path) of + P when is_list(P) -> P; + _ -> "/share/doc/ejabberd/" + end, + %% Code based in mod_http_fileserver + FileName = filename:join(DocPath, LocalFile), + case file:read_file(FileName) of + {ok, FileContents} -> + ?DEBUG("Delivering content.", []), + {200, + [{"Server", "ejabberd"}], + FileContents}; + {error, Error} -> + ?DEBUG("Delivering error: ~p", [Error]), + Help = " " ++ FileName ++ " - Try to specify the path to ejabberd guide.html " + "with the option doc_path. Check the ejabberd Guide for more information", + case Error of + eacces -> {403, [], "Forbidden"++Help}; + enoent -> {404, [], "Not found"++Help}; + _Else -> {404, [], atom_to_list(Error)++Help} + end + end; + process(["server", SHost | RPath], #request{auth = Auth} = Request) -> Host = exmpp_stringprep:nameprep(SHost), case lists:member(Host, ?MYHOSTS) of @@ -108,7 +132,7 @@ get_auth(Auth) -> make_xhtml(Els, Host, Lang) -> make_xhtml(Els, Host, cluster, Lang). -%% @spec (Els, Host, Node, Lang) +%% @spec (Els, Host, Node, Lang) -> {200, [html], xmlelement()} %% where Host = global | string() %% Node = cluster | atom() make_xhtml(Els, Host, Node, Lang) -> @@ -513,8 +537,13 @@ h3 { padding-top: 5px; } -*.alignright { +div.guidelink { text-align: right; + padding-right: 1em; +} + +*.alignright { + font-size: 10pt; } ". @@ -560,8 +589,8 @@ process_admin(global, lang = Lang}) -> Base = get_base_path(global, cluster), MenuItems2 = make_menu_items(global, cluster, Base, Lang), - make_xhtml([?XCT('h1', "Administration"), - ?XE('ul', + make_xhtml(?H1GL(?T("Administration"), "toc", "Contents") ++ + [?XE('ul', [?LI([?ACT("/admin/acls/", "Access Control Lists"), ?C(" "), ?ACT("/admin/acls-raw/", "(Raw)")]), ?LI([?ACT("/admin/access/", "Access Rules"), ?C(" "), @@ -635,7 +664,7 @@ process_admin(Host, "~p.", [lists:keysort( 2, ets:select(acl, [{{acl, {'$1', Host}, '$2'}, [], [{{acl, '$1', '$2'}}]}]))])), - make_xhtml([?XCT('h1', "Access Control Lists")] ++ + make_xhtml(?H1GL(?T("Access Control Lists"), "ACLDefinition", "ACL Definition") ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; @@ -678,7 +707,7 @@ process_admin(Host, ACLs = lists:keysort( 2, ets:select(acl, [{{acl, {'$1', Host}, '$2'}, [], [{{acl, '$1', '$2'}}]}])), - make_xhtml([?XCT('h1', "Access Control Lists")] ++ + make_xhtml(?H1GL(?T("Access Control Lists"), "ACLDefinition", "ACL Definition") ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; @@ -746,7 +775,7 @@ process_admin(Host, [{{config, {access, '$1', Host}, '$2'}, [], [{{access, '$1', '$2'}}]}])])), - make_xhtml([?XCT('h1', "Access Rules")] ++ + make_xhtml(?H1GL(?T("Access Rules"), "AccessRights", "Access Rights") ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; @@ -784,7 +813,7 @@ process_admin(Host, [{{config, {access, '$1', Host}, '$2'}, [], [{{access, '$1', '$2'}}]}]), - make_xhtml([?XCT('h1', "Access Rules")] ++ + make_xhtml(?H1GL(?T("Access Rules"), "AccessRights", "Access Rights") ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; @@ -841,7 +870,7 @@ process_admin(global, #request{path = ["vhosts"], lang = Lang}) -> Res = list_vhosts(Lang), - make_xhtml([?XCT('h1', "ejabberd virtual hosts")] ++ Res, global, Lang); + make_xhtml(?H1GL(?T("ejabberd virtual hosts"), "virtualhost", "Virtual Hosting") ++ Res, global, Lang); process_admin(Host, #request{path = ["users"], @@ -1791,7 +1820,8 @@ get_node(global, Node, ["ports"], Query, Lang) -> end, NewPorts = lists:sort( rpc:call(Node, ejabberd_config, get_local_option, [listen])), - [?XC('h1', ?T("Listened Ports at ") ++ atom_to_list(Node))] ++ + H1String = ?T("Listened Ports at ") ++ atom_to_list(Node), + ?H1GL(H1String, "listened", "Listening Ports") ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; @@ -1814,7 +1844,8 @@ get_node(Host, Node, ["modules"], Query, Lang) when is_list(Host) -> end, NewModules = lists:sort( rpc:call(Node, gen_mod, loaded_modules_with_opts, [Host])), - [?XC('h1', ?T("Modules at ") ++ atom_to_list(Node))] ++ + H1String = ?T("Modules at ") ++ atom_to_list(Node), + ?H1GL(H1String, "modoverview", "Modules Overview") ++ case Res of ok -> [?CT("Submitted"), ?P]; error -> [?CT("Bad format"), ?P]; diff --git a/src/web/ejabberd_web_admin.hrl b/src/web/ejabberd_web_admin.hrl index bfa7475e1..1469b83d8 100644 --- a/src/web/ejabberd_web_admin.hrl +++ b/src/web/ejabberd_web_admin.hrl @@ -52,3 +52,17 @@ #xmlattr{name = 'size', value = Size}])). -define(INPUTST(Type, Name, Value, Size), ?INPUT(Type, Name, ?T(Value), Size)). -define(ACLINPUT(Text), ?XE('td', [?INPUT("text", "value" ++ ID, Text)])). + +%% Guide Link +-define(GL(Ref, Title), + ?XAE('div', + [#xmlattr{name = 'class', value = <<"guidelink">>}], + [?XAE('a', + [#xmlattr{name = "href", value = list_to_binary("/admin/doc/guide.html#"++ Ref)}, + #xmlattr{name = "target", value = <<"_blank">>}], + [?C("[Guide: " ++ Title ++ "]")]) + ])). + + +%% h1 with a Guide Link +-define(H1GL(Name, Ref, Title), [?XC('h1', Name), ?GL(Ref, Title)]). From e2ee44617ce59082e6199dbb884cd0819cd7883c Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Mon, 19 Jan 2009 13:44:43 +0000 Subject: [PATCH 170/582] translate.erl: Bugfix, ?MYLANG macro returns a list(). SVN Revision: 1828 --- ChangeLog | 4 ++++ src/translate.erl | 9 ++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8a3b0c38b..e283e15f7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-01-19 Pablo Polvorin + + * src/translate.erl: Bugfix, ?MYLANG macro returns a list(). + 2009-01-19 Jean-Sébastien Pédron Merge from trunk (r1752 to r1787). diff --git a/src/translate.erl b/src/translate.erl index df76d145e..f54fe6f86 100644 --- a/src/translate.erl +++ b/src/translate.erl @@ -105,6 +105,7 @@ load_file(Lang, File) -> end. translate(Lang, Msg) -> + io:format("translate(~p, ~p) ~n",[Lang, Msg]), LLang = ascii_tolower(Lang), case ets:lookup(translations, {LLang, Msg}) of [{_, Trans}] -> @@ -132,13 +133,15 @@ translate(Lang, Msg) -> end. translate(Msg) -> + %%TODO: ?MYLANG macro returns lang as a list(). Lang should be a binary. case ?MYLANG of undefined -> Msg; - <<"en">> -> + "en" -> Msg; Lang -> - LLang = ascii_tolower(Lang), + BLang = list_to_binary(Lang), + LLang = ascii_tolower(BLang), case ets:lookup(translations, {LLang, Msg}) of [{_, Trans}] -> Trans; @@ -152,7 +155,7 @@ translate(Msg) -> case ShortLang of <<"en">> -> Msg; - Lang -> + BLang -> Msg; _ -> case ets:lookup(translations, {ShortLang, Msg}) of From ff500d829796cf76ae58c8a96413e233b84cca36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 19 Jan 2009 14:47:33 +0000 Subject: [PATCH 171/582] Merge from trunk (r1787 to r1804). Included are fixes to src/mod_configure.erl and src/mod_caps.erl. Note: this merge doesn't include the following revisions because it was made by previous commits: r1766, r1768, r1781, r1783, r1794, r1797, r1799, r1802. Warning: Ejabberd may be broken until the merge is completly finished. PR: EJABP-1 SVN Revision: 1829 --- ChangeLog | 80 ++++++++++++++++--------- doc/guide.html | 19 +++++- doc/guide.tex | 19 +++++- src/acl.erl | 4 +- src/adhoc.erl | 4 +- src/adhoc.hrl | 4 +- src/configure.erl | 4 +- src/cyrsasl.erl | 4 +- src/cyrsasl_anonymous.erl | 4 +- src/cyrsasl_plain.erl | 4 +- src/ejabberd.erl | 4 +- src/ejabberd.hrl | 4 +- src/ejabberd_admin.erl | 4 +- src/ejabberd_app.erl | 4 +- src/ejabberd_auth.erl | 4 +- src/ejabberd_auth_anonymous.erl | 4 +- src/ejabberd_auth_external.erl | 4 +- src/ejabberd_auth_internal.erl | 4 +- src/ejabberd_auth_ldap.erl | 4 +- src/ejabberd_auth_odbc.erl | 4 +- src/ejabberd_auth_pam.erl | 4 +- src/ejabberd_c2s.erl | 4 +- src/ejabberd_c2s_config.erl | 4 +- src/ejabberd_check.erl | 4 +- src/ejabberd_commands.erl | 2 +- src/ejabberd_commands.hrl | 2 +- src/ejabberd_config.erl | 4 +- src/ejabberd_config.hrl | 4 +- src/ejabberd_ctl.erl | 2 +- src/ejabberd_ctl.hrl | 4 +- src/ejabberd_frontend_socket.erl | 4 +- src/ejabberd_hooks.erl | 4 +- src/ejabberd_listener.erl | 2 +- src/ejabberd_local.erl | 4 +- src/ejabberd_logger_h.erl | 4 +- src/ejabberd_loglevel.erl | 4 +- src/ejabberd_node_groups.erl | 4 +- src/ejabberd_rdbms.erl | 2 +- src/ejabberd_receiver.erl | 4 +- src/ejabberd_router.erl | 4 +- src/ejabberd_s2s.erl | 4 +- src/ejabberd_s2s_in.erl | 4 +- src/ejabberd_s2s_out.erl | 2 +- src/ejabberd_service.erl | 4 +- src/ejabberd_sm.erl | 4 +- src/ejabberd_socket.erl | 4 +- src/ejabberd_sup.erl | 4 +- src/ejabberd_system_monitor.erl | 4 +- src/ejabberd_tmp_sup.erl | 4 +- src/ejabberd_update.erl | 4 +- src/ejabberd_zlib/ejabberd_zlib.erl | 4 +- src/ejabberd_zlib/ejabberd_zlib_drv.c | 2 +- src/ejd2odbc.erl | 4 +- src/eldap/eldap.hrl | 4 +- src/eldap/eldap_filter.erl | 4 +- src/eldap/eldap_pool.erl | 4 +- src/eldap/eldap_utils.erl | 4 +- src/extauth.erl | 4 +- src/gen_iq_handler.erl | 4 +- src/gen_mod.erl | 4 +- src/idna.erl | 4 +- src/jd2ejd.erl | 4 +- src/jlib.erl | 4 +- src/jlib.hrl | 4 +- src/mod_adhoc.erl | 4 +- src/mod_announce.erl | 4 +- src/mod_caps.erl | 6 +- src/mod_configure.erl | 6 +- src/mod_configure2.erl | 4 +- src/mod_disco.erl | 4 +- src/mod_echo.erl | 4 +- src/mod_ip_blacklist.erl | 4 +- src/mod_irc/iconv.erl | 4 +- src/mod_irc/iconv_erl.c | 2 +- src/mod_irc/mod_irc.erl | 6 +- src/mod_irc/mod_irc_connection.erl | 4 +- src/mod_last.erl | 4 +- src/mod_last_odbc.erl | 4 +- src/mod_muc/mod_muc.erl | 6 +- src/mod_muc/mod_muc_log.erl | 4 +- src/mod_muc/mod_muc_room.erl | 4 +- src/mod_muc/mod_muc_room.hrl | 4 +- src/mod_offline.erl | 4 +- src/mod_offline_odbc.erl | 4 +- src/mod_privacy.erl | 4 +- src/mod_privacy.hrl | 4 +- src/mod_privacy_odbc.erl | 2 +- src/mod_private.erl | 4 +- src/mod_private_odbc.erl | 4 +- src/mod_proxy65/mod_proxy65.erl | 4 +- src/mod_proxy65/mod_proxy65.hrl | 4 +- src/mod_proxy65/mod_proxy65_lib.erl | 4 +- src/mod_proxy65/mod_proxy65_service.erl | 6 +- src/mod_proxy65/mod_proxy65_sm.erl | 4 +- src/mod_proxy65/mod_proxy65_stream.erl | 4 +- src/mod_pubsub/gen_pubsub_node.erl | 6 +- src/mod_pubsub/gen_pubsub_nodetree.erl | 6 +- src/mod_pubsub/mod_pubsub.erl | 8 +-- src/mod_pubsub/node.template | 6 +- src/mod_pubsub/node_buddy.erl | 6 +- src/mod_pubsub/node_club.erl | 6 +- src/mod_pubsub/node_default.erl | 6 +- src/mod_pubsub/node_dispatch.erl | 6 +- src/mod_pubsub/node_flat.erl | 6 +- src/mod_pubsub/node_mb.erl | 6 +- src/mod_pubsub/node_pep.erl | 6 +- src/mod_pubsub/node_private.erl | 6 +- src/mod_pubsub/node_public.erl | 6 +- src/mod_pubsub/nodetree_default.erl | 6 +- src/mod_pubsub/nodetree_virtual.erl | 6 +- src/mod_pubsub/pubsub.hrl | 6 +- src/mod_register.erl | 4 +- src/mod_roster.erl | 4 +- src/mod_roster.hrl | 4 +- src/mod_roster_odbc.erl | 2 +- src/mod_service_log.erl | 4 +- src/mod_shared_roster.erl | 4 +- src/mod_stats.erl | 4 +- src/mod_time.erl | 4 +- src/mod_vcard.erl | 8 +-- src/mod_vcard_ldap.erl | 8 +-- src/mod_vcard_odbc.erl | 6 +- src/mod_version.erl | 4 +- src/odbc/ejabberd_odbc.erl | 4 +- src/odbc/ejabberd_odbc_sup.erl | 2 +- src/odbc/mssql2000.sql | 2 +- src/odbc/mssql2005.sql | 2 +- src/odbc/mysql.sql | 2 +- src/odbc/odbc_queries.erl | 2 +- src/odbc/pg.sql | 2 +- src/p1_fsm.erl | 2 +- src/p1_mnesia.erl | 2 +- src/pam/epam.c | 2 +- src/pam/epam.erl | 4 +- src/randoms.erl | 4 +- src/sha.erl | 4 +- src/shaper.erl | 4 +- src/stringprep/stringprep.erl | 4 +- src/stringprep/stringprep_drv.c | 2 +- src/stringprep/stringprep_sup.erl | 4 +- src/tls/tls.erl | 4 +- src/tls/tls_drv.c | 2 +- src/translate.erl | 4 +- src/treap.erl | 2 +- src/web/ejabberd_http.erl | 4 +- src/web/ejabberd_http.hrl | 4 +- src/web/ejabberd_http_poll.erl | 4 +- src/web/ejabberd_web.erl | 4 +- src/web/ejabberd_web_admin.erl | 6 +- src/web/ejabberd_web_admin.hrl | 4 +- src/xml.erl | 4 +- src/xml_stream.erl | 4 +- 152 files changed, 388 insertions(+), 338 deletions(-) diff --git a/ChangeLog b/ChangeLog index e283e15f7..6620ad0bc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,11 +1,15 @@ +2009-01-19 Jean-Sébastien Pédron + + Merge from trunk (r1752 to r1804). + + Note: this merge doesn't include the following revisions because it + was made by previous commits: + r1766, r1768, r1781, r1783, r1794, r1797, r1799, r1802. + 2009-01-19 Pablo Polvorin * src/translate.erl: Bugfix, ?MYLANG macro returns a list(). -2009-01-19 Jean-Sébastien Pédron - - Merge from trunk (r1752 to r1787). - 2009-01-19 Jean-Sébastien Pédron * src/ejabberd_auth_anonymous.erl: Fix accesses to the new #jid opaque @@ -29,6 +33,18 @@ Use document_to_iolist/1 and iolist_size/1 instead of document_to_list/1. +2009-01-12 Alexey Shchepin + + * src/odbc/ejabberd_odbc.erl: Fixed processing of UPDATE results + with pgsql + +2009-01-12 Badlop + + * doc/guide.tex: Update copyright date 2008 to 2009 (EJAB-842) + * doc/guide.html: Likewise + * src/*/*.erl: Likewise + * src/*/*.erl: Remove unneeded blankspaces in license text + 2009-01-11 Pablo Polvorin * src/mod_pubsub/mod_pubsub.erl: Fix typo, initial update @@ -83,6 +99,12 @@ 2009-01-09 Badlop + * doc/guide.tex: Improve explanation of backup commands (EJAB-832) + * doc/guide.html: Likewise + + * src/web/ejabberd_web_admin.erl: New appearance of WebAdmin logo, + fixed logo-fill. + * src/mod_configure.erl: Fix access check for vhost configuration 2009-01-08 Mickael Remond @@ -127,10 +149,35 @@ disco_local_items, disco_local_features, disco_local_identity, disco_sm_items and disco_sm_identity. +2009-01-07 Badlop + + * src/mod_roster.erl: Show hyperlinks to local contacts when + browsing roster of account in Web Admin (EJAB-480) + * src/mod_roster_odbc.erl: Likewise + + * src/web/ejabberd_web_admin.erl: WebAdmin serves Guide and links + to related sections; the path to guide.html can be configured with + option doc_path (EJAB-837) + * src/web/ejabberd_web_admin.hrl: Likewise + * src/mod_shared_roster.erl: Likewise + * doc/guide.tex: Likewise + * doc/guide.html: Likewise + +2009-01-06 Badlop + + * src/msgs/ru.po: Fix typo (thanks to Dominges) + * src/msgs/ru.msg: Likewise + 2009-01-05 Pablo Polvorin * src/mod_roster.erl: Fix typo. +2009-01-05 Alexey Shchepin + + * src/tls/tls_drv.c: Added a flag to avoid certificate validation + * src/tls/tls.erl: Likewise + * src/ejabberd_c2s.erl: Likewise + 2009-01-03 Pablo Polvorin * src/mod_pubsub_node_default.erl: Fix typo. @@ -157,31 +204,6 @@ ejabberd_sm, ejabberd_router, ejabberd_hooks, mod_last, mod_roster to use binary() storage. -2009-01-07 Badlop - - * src/mod_roster.erl: Show hyperlinks to local contacts when - browsing roster of account in Web Admin (EJAB-480) - * src/mod_roster_odbc.erl: Likewise - - * src/web/ejabberd_web_admin.erl: WebAdmin serves Guide and links - to related sections; the path to guide.html can be configured with - option doc_path (EJAB-837) - * src/web/ejabberd_web_admin.hrl: Likewise - * src/mod_shared_roster.erl: Likewise - * doc/guide.tex: Likewise - * doc/guide.html: Likewise - -2009-01-06 Badlop - - * src/msgs/ru.po: Fix typo (thanks to Dominges) - * src/msgs/ru.msg: Likewise - -2009-01-05 Alexey Shchepin - - * src/tls/tls_drv.c: Added a flag to avoid certificate validation - * src/tls/tls.erl: Likewise - * src/ejabberd_c2s.erl: Likewise - 2009-01-03 Badlop * src/*.erl: Fix EDoc comments diff --git a/doc/guide.html b/doc/guide.html index b7466955e..9d0fde157 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -2929,8 +2929,21 @@ The more interesting ones are:
      reopen-log
      Reopen the log files after they were renamed. If the old files were not renamed before calling this command, they are automatically renamed to "*-old.log". See section 7.1. -
      backup, restore, install-fallback, dump, load
      You can use these -commands to create and restore backups. +
      backup ejabberd.backup
      +Store internal Mnesia database to a binary backup file. +
      restore ejabberd.backup
      +Restore immediately from a binary backup file the internal Mnesia database. +This will comsume quite some memory for big servers. +
      install-fallback ejabberd.backup
      +The binary backup file is installed as fallback: +it will be used to restore the database at the next ejabberd start. +Similar to restore, but requires less memory. +
      dump ejabberd.dump
      +Dump internal Mnesia database to a text file dump. +
      load ejabberd.dump
      +Restore immediately from a text file dump. +This is not recommended for big databases, as it will consume much time, +memory and processor. In that case it’s preferable to use backup and install-fallback.
      import-file, import-dir
      These options can be used to migrate from other Jabber/XMPP servers. There exist tutorials to migrate from other software to ejabberd. @@ -3371,7 +3384,7 @@ Alexey Shchepin (xmpp:aleksey@jabber.ru
    • Vsevolod Pelipas (xmpp:vsevoload@jabber.ru)
    • Appendix D  Copyright Information

      Ejabberd Installation and Operation Guide.
      -Copyright © 2003 — 2008 ProcessOne

      This document is free software; you can redistribute it and/or +Copyright © 2003 — 2009 ProcessOne

      This document 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 document is distributed in the hope that it will be useful, diff --git a/doc/guide.tex b/doc/guide.tex index c3fb6db07..49b270f14 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -3771,8 +3771,21 @@ The more interesting ones are: \titem{reopen-log} Reopen the log files after they were renamed. If the old files were not renamed before calling this command, they are automatically renamed to \term{"*-old.log"}. See section \ref{logfiles}. -\titem {backup, restore, install-fallback, dump, load} You can use these - commands to create and restore backups. +\titem {backup ejabberd.backup} + Store internal Mnesia database to a binary backup file. +\titem {restore ejabberd.backup} + Restore immediately from a binary backup file the internal Mnesia database. + This will comsume quite some memory for big servers. +\titem {install-fallback ejabberd.backup} + The binary backup file is installed as fallback: + it will be used to restore the database at the next ejabberd start. + Similar to \term{restore}, but requires less memory. +\titem {dump ejabberd.dump} + Dump internal Mnesia database to a text file dump. +\titem {load ejabberd.dump} + Restore immediately from a text file dump. + This is not recommended for big databases, as it will consume much time, + memory and processor. In that case it's preferable to use \term{backup} and \term{install-fallback}. %%More information about backuping can %% be found in section~\ref{backup}. \titem{import-file, import-dir} \ind{migration from other software} @@ -4445,7 +4458,7 @@ Thanks to all people who contributed to this guide: \makechapter{copyright}{Copyright Information} Ejabberd Installation and Operation Guide.\\ -Copyright \copyright{} 2003 --- 2008 ProcessOne +Copyright \copyright{} 2003 --- 2009 ProcessOne This document is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/src/acl.erl b/src/acl.erl index e3fd76020..b72402c4d 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -5,7 +5,7 @@ %%% Created : 18 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/adhoc.erl b/src/adhoc.erl index 32f4d4038..d2720e685 100644 --- a/src/adhoc.erl +++ b/src/adhoc.erl @@ -5,7 +5,7 @@ %%% Created : 31 Oct 2005 by Magnus Henoch %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/adhoc.hrl b/src/adhoc.hrl index ab8a6f163..e47efec5f 100644 --- a/src/adhoc.hrl +++ b/src/adhoc.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -11,7 +11,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/configure.erl b/src/configure.erl index 379c79a82..cd7e48710 100644 --- a/src/configure.erl +++ b/src/configure.erl @@ -5,7 +5,7 @@ %%% Created : 27 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/cyrsasl.erl b/src/cyrsasl.erl index 7813df772..9dedd0b75 100644 --- a/src/cyrsasl.erl +++ b/src/cyrsasl.erl @@ -5,7 +5,7 @@ %%% Created : 8 Mar 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/cyrsasl_anonymous.erl b/src/cyrsasl_anonymous.erl index fb033b3a7..c8f913ce6 100644 --- a/src/cyrsasl_anonymous.erl +++ b/src/cyrsasl_anonymous.erl @@ -6,7 +6,7 @@ %%% Created : 23 Aug 2005 by Magnus Henoch %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/cyrsasl_plain.erl b/src/cyrsasl_plain.erl index 1533c463d..b3ecff83c 100644 --- a/src/cyrsasl_plain.erl +++ b/src/cyrsasl_plain.erl @@ -5,7 +5,7 @@ %%% Created : 8 Mar 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd.erl b/src/ejabberd.erl index 86113d97b..bc23dd80e 100644 --- a/src/ejabberd.erl +++ b/src/ejabberd.erl @@ -5,7 +5,7 @@ %%% Created : 16 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd.hrl b/src/ejabberd.hrl index 658037274..717496fac 100644 --- a/src/ejabberd.hrl +++ b/src/ejabberd.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -11,7 +11,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl index 993ac64ce..98b1f4919 100644 --- a/src/ejabberd_admin.erl +++ b/src/ejabberd_admin.erl @@ -5,7 +5,7 @@ %%% Created : 7 May 2006 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index ea193eebb..41e7444d8 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -5,7 +5,7 @@ %%% Created : 31 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 8f089afe6..209373174 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -5,7 +5,7 @@ %%% Created : 23 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index 622c6c500..3135c6dd3 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -5,7 +5,7 @@ %%% Created : 17 Feb 2006 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl index b86a94bb8..af7c5b048 100644 --- a/src/ejabberd_auth_external.erl +++ b/src/ejabberd_auth_external.erl @@ -5,7 +5,7 @@ %%% Created : 12 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index 15f073866..527c183b7 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -5,7 +5,7 @@ %%% Created : 12 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl index 7fd8487ad..b8c6a971e 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -5,7 +5,7 @@ %%% Created : 12 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index e2f106b88..92a8493b6 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -5,7 +5,7 @@ %%% Created : 12 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_auth_pam.erl b/src/ejabberd_auth_pam.erl index 5f67bedba..c8a8031c2 100644 --- a/src/ejabberd_auth_pam.erl +++ b/src/ejabberd_auth_pam.erl @@ -5,7 +5,7 @@ %%% Created : 5 Jul 2007 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index c850ccf13..1e60065aa 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -5,7 +5,7 @@ %%% Created : 16 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_c2s_config.erl b/src/ejabberd_c2s_config.erl index 4c1dae8fc..2f747b1c4 100644 --- a/src/ejabberd_c2s_config.erl +++ b/src/ejabberd_c2s_config.erl @@ -6,7 +6,7 @@ %%% Created : 2 Nov 2007 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_check.erl b/src/ejabberd_check.erl index 260c54175..370f554e0 100644 --- a/src/ejabberd_check.erl +++ b/src/ejabberd_check.erl @@ -5,7 +5,7 @@ %%% Created : 27 Feb 2008 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl index 6440959a4..e4e7d4bb1 100644 --- a/src/ejabberd_commands.erl +++ b/src/ejabberd_commands.erl @@ -5,7 +5,7 @@ %%% Created : 20 May 2008 by Badlop %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_commands.hrl b/src/ejabberd_commands.hrl index ce7aadb9b..0be918172 100644 --- a/src/ejabberd_commands.hrl +++ b/src/ejabberd_commands.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 1708c7aa2..c933c1b2f 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -5,7 +5,7 @@ %%% Created : 14 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_config.hrl b/src/ejabberd_config.hrl index 982bbe23f..aec9a82fa 100644 --- a/src/ejabberd_config.hrl +++ b/src/ejabberd_config.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -11,7 +11,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl index b7b1b9963..62d208e37 100644 --- a/src/ejabberd_ctl.erl +++ b/src/ejabberd_ctl.erl @@ -5,7 +5,7 @@ %%% Created : 11 Jan 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_ctl.hrl b/src/ejabberd_ctl.hrl index 9b5ec0a4b..a95cfda69 100644 --- a/src/ejabberd_ctl.hrl +++ b/src/ejabberd_ctl.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -11,7 +11,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_frontend_socket.erl b/src/ejabberd_frontend_socket.erl index 99f0b1964..b8a36f3b0 100644 --- a/src/ejabberd_frontend_socket.erl +++ b/src/ejabberd_frontend_socket.erl @@ -5,7 +5,7 @@ %%% Created : 23 Aug 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl index d317c6a87..e506aea89 100644 --- a/src/ejabberd_hooks.erl +++ b/src/ejabberd_hooks.erl @@ -5,7 +5,7 @@ %%% Created : 8 Aug 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 6992c6a53..93ae78a7c 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -5,7 +5,7 @@ %%% Created : 16 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 190e958b1..78d67784d 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -5,7 +5,7 @@ %%% Created : 30 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_logger_h.erl b/src/ejabberd_logger_h.erl index e8e6f3baa..e356c649b 100644 --- a/src/ejabberd_logger_h.erl +++ b/src/ejabberd_logger_h.erl @@ -5,7 +5,7 @@ %%% Created : 23 Oct 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_loglevel.erl b/src/ejabberd_loglevel.erl index 59c415196..3134d4d03 100644 --- a/src/ejabberd_loglevel.erl +++ b/src/ejabberd_loglevel.erl @@ -9,7 +9,7 @@ %%% Created : 29 Nov 2006 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_node_groups.erl b/src/ejabberd_node_groups.erl index d5d8ce068..f1195c89b 100644 --- a/src/ejabberd_node_groups.erl +++ b/src/ejabberd_node_groups.erl @@ -5,7 +5,7 @@ %%% Created : 1 Nov 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_rdbms.erl b/src/ejabberd_rdbms.erl index d57a1ad54..2496e56a5 100644 --- a/src/ejabberd_rdbms.erl +++ b/src/ejabberd_rdbms.erl @@ -5,7 +5,7 @@ %%% Created : 31 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_receiver.erl b/src/ejabberd_receiver.erl index 7386fed07..05f8ddfb6 100644 --- a/src/ejabberd_receiver.erl +++ b/src/ejabberd_receiver.erl @@ -5,7 +5,7 @@ %%% Created : 10 Nov 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index 5d39e9924..915f4379a 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -5,7 +5,7 @@ %%% Created : 27 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index 8073518bf..a3a89c1ca 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -5,7 +5,7 @@ %%% Created : 7 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 703e20cd9..63088437a 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -5,7 +5,7 @@ %%% Created : 6 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index bdb67c095..0d8c56176 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -5,7 +5,7 @@ %%% Created : 6 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index bc8266b19..591d0d0ed 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -5,7 +5,7 @@ %%% Created : 6 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 18d664680..646f15999 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -5,7 +5,7 @@ %%% Created : 24 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl index 01e1eddcb..566ee1e43 100644 --- a/src/ejabberd_socket.erl +++ b/src/ejabberd_socket.erl @@ -5,7 +5,7 @@ %%% Created : 23 Aug 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_sup.erl b/src/ejabberd_sup.erl index 01efbfd76..7a650cc35 100644 --- a/src/ejabberd_sup.erl +++ b/src/ejabberd_sup.erl @@ -5,7 +5,7 @@ %%% Created : 31 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl index 3e0bc6840..2a5418329 100644 --- a/src/ejabberd_system_monitor.erl +++ b/src/ejabberd_system_monitor.erl @@ -5,7 +5,7 @@ %%% Created : 21 Mar 2007 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_tmp_sup.erl b/src/ejabberd_tmp_sup.erl index 7438f6628..15d690dad 100644 --- a/src/ejabberd_tmp_sup.erl +++ b/src/ejabberd_tmp_sup.erl @@ -5,7 +5,7 @@ %%% Created : 18 Jul 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_update.erl b/src/ejabberd_update.erl index 787f93fd7..7d5ae36c9 100644 --- a/src/ejabberd_update.erl +++ b/src/ejabberd_update.erl @@ -5,7 +5,7 @@ %%% Created : 27 Jan 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_zlib/ejabberd_zlib.erl b/src/ejabberd_zlib/ejabberd_zlib.erl index 18d5a3abf..3c3879b71 100644 --- a/src/ejabberd_zlib/ejabberd_zlib.erl +++ b/src/ejabberd_zlib/ejabberd_zlib.erl @@ -5,7 +5,7 @@ %%% Created : 19 Jan 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/ejabberd_zlib/ejabberd_zlib_drv.c b/src/ejabberd_zlib/ejabberd_zlib_drv.c index d1442d773..39039aa4f 100644 --- a/src/ejabberd_zlib/ejabberd_zlib_drv.c +++ b/src/ejabberd_zlib/ejabberd_zlib_drv.c @@ -1,5 +1,5 @@ /* - * ejabberd, Copyright (C) 2002-2008 ProcessOne + * ejabberd, Copyright (C) 2002-2009 ProcessOne * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/ejd2odbc.erl b/src/ejd2odbc.erl index 86b42679a..86850a49d 100644 --- a/src/ejd2odbc.erl +++ b/src/ejd2odbc.erl @@ -5,7 +5,7 @@ %%% Created : 22 Aug 2005 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/eldap/eldap.hrl b/src/eldap/eldap.hrl index d006c14df..5ffc464c9 100644 --- a/src/eldap/eldap.hrl +++ b/src/eldap/eldap.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -11,7 +11,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/eldap/eldap_filter.erl b/src/eldap/eldap_filter.erl index 2feed1083..46510e0d6 100644 --- a/src/eldap/eldap_filter.erl +++ b/src/eldap/eldap_filter.erl @@ -6,7 +6,7 @@ %%% Author: Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -17,7 +17,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/eldap/eldap_pool.erl b/src/eldap/eldap_pool.erl index 7b9024de3..f714129b5 100644 --- a/src/eldap/eldap_pool.erl +++ b/src/eldap/eldap_pool.erl @@ -5,7 +5,7 @@ %%% Created : 12 Nov 2006 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/eldap/eldap_utils.erl b/src/eldap/eldap_utils.erl index 759725c53..bf9cf1567 100644 --- a/src/eldap/eldap_utils.erl +++ b/src/eldap/eldap_utils.erl @@ -5,7 +5,7 @@ %%% Created : 12 Oct 2006 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/extauth.erl b/src/extauth.erl index 9a239d732..d216fd18c 100644 --- a/src/extauth.erl +++ b/src/extauth.erl @@ -5,7 +5,7 @@ %%% Created : 30 Jul 2004 by Leif Johansson %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index 130934ca3..039a30759 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.erl @@ -5,7 +5,7 @@ %%% Created : 22 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/gen_mod.erl b/src/gen_mod.erl index 49f4991a7..a37ec51e6 100644 --- a/src/gen_mod.erl +++ b/src/gen_mod.erl @@ -5,7 +5,7 @@ %%% Created : 24 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/idna.erl b/src/idna.erl index 319262349..d83b5e48b 100644 --- a/src/idna.erl +++ b/src/idna.erl @@ -5,7 +5,7 @@ %%% Created : 10 Apr 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/jd2ejd.erl b/src/jd2ejd.erl index 67d489c81..75963e5cc 100644 --- a/src/jd2ejd.erl +++ b/src/jd2ejd.erl @@ -5,7 +5,7 @@ %%% Created : 2 Feb 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/jlib.erl b/src/jlib.erl index d76946fb0..06bee3377 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -5,7 +5,7 @@ %%% Created : 23 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/jlib.hrl b/src/jlib.hrl index 93d2a5dce..479781431 100644 --- a/src/jlib.hrl +++ b/src/jlib.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -11,7 +11,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl index 3769eb330..a53d8339e 100644 --- a/src/mod_adhoc.erl +++ b/src/mod_adhoc.erl @@ -5,7 +5,7 @@ %%% Created : 15 Nov 2005 by Magnus Henoch %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_announce.erl b/src/mod_announce.erl index f3a7cbb37..6285fe623 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -5,7 +5,7 @@ %%% Created : 11 Aug 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 9d694c5db..f98b2fcd6 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -5,7 +5,7 @@ %%% Created : 7 Oct 2006 by Magnus Henoch %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -101,7 +101,7 @@ clear_caps(JID) -> BUID = exmpp_jid:bare_jid_to_binary(JID), catch mnesia:dirty_delete({user_caps, BJID}), case catch mnesia:dirty_read({user_caps_default, BUID}) of - [#user_caps_default{resource=R}] -> + [#user_caps_default{resource=_R}] -> catch mnesia:dirty_delete({user_caps_default, BUID}); _ -> ok diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 5e91e15dc..3335d9c6e 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -5,7 +5,7 @@ %%% Created : 19 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -321,7 +321,7 @@ adhoc_local_items(Acc, From, To, Lang) -> end, PermLev = get_permission_level(From), %% Recursively get all configure commands - Nodes = recursively_get_local_items(PermLev, LServer, "", exmpp_jid:domain_as_list(Server), + Nodes = recursively_get_local_items(PermLev, LServer, "", exmpp_jid:domain_as_list(To), Lang), Nodes1 = lists:filter( fun(N) -> diff --git a/src/mod_configure2.erl b/src/mod_configure2.erl index d5effc743..26fed15fa 100644 --- a/src/mod_configure2.erl +++ b/src/mod_configure2.erl @@ -5,7 +5,7 @@ %%% Created : 26 Oct 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 6febc2453..00b90c697 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -5,7 +5,7 @@ %%% Created : 1 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_echo.erl b/src/mod_echo.erl index 4eef833e4..0c0f86009 100644 --- a/src/mod_echo.erl +++ b/src/mod_echo.erl @@ -5,7 +5,7 @@ %%% Created : 15 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_ip_blacklist.erl b/src/mod_ip_blacklist.erl index 17280857e..9e990e39e 100644 --- a/src/mod_ip_blacklist.erl +++ b/src/mod_ip_blacklist.erl @@ -7,7 +7,7 @@ %%% {mod_ip_blacklist, []} %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -18,7 +18,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_irc/iconv.erl b/src/mod_irc/iconv.erl index 77c1ea56c..8cccf2df8 100644 --- a/src/mod_irc/iconv.erl +++ b/src/mod_irc/iconv.erl @@ -5,7 +5,7 @@ %%% Created : 16 Feb 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_irc/iconv_erl.c b/src/mod_irc/iconv_erl.c index 3835aecbd..c9ce801ff 100644 --- a/src/mod_irc/iconv_erl.c +++ b/src/mod_irc/iconv_erl.c @@ -1,5 +1,5 @@ /* - * ejabberd, Copyright (C) 2002-2008 ProcessOne + * ejabberd, Copyright (C) 2002-2009 ProcessOne * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/mod_irc/mod_irc.erl b/src/mod_irc/mod_irc.erl index 341a97df2..bcc61a4b8 100644 --- a/src/mod_irc/mod_irc.erl +++ b/src/mod_irc/mod_irc.erl @@ -5,7 +5,7 @@ %%% Created : 15 Feb 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -322,7 +322,7 @@ iq_get_vcard(Lang) -> [#xmlcdata{cdata = list_to_binary(?EJABBERD_URI)}]}, #xmlel{ns = ?NS_VCARD, name = 'DESC', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "ejabberd IRC module") ++ - "\nCopyright (c) 2003-2008 Alexey Shchepin")}]}]. + "\nCopyright (c) 2003-2009 Alexey Shchepin")}]}]. process_register(Host, From, To, DefEnc, #iq{} = IQ_Rec) -> case catch process_irc_register(Host, From, To, DefEnc, IQ_Rec) of diff --git a/src/mod_irc/mod_irc_connection.erl b/src/mod_irc/mod_irc_connection.erl index 0679a411b..7fcb8c651 100644 --- a/src/mod_irc/mod_irc_connection.erl +++ b/src/mod_irc/mod_irc_connection.erl @@ -5,7 +5,7 @@ %%% Created : 15 Feb 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_last.erl b/src/mod_last.erl index 613e49317..e8d14cb6f 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -5,7 +5,7 @@ %%% Created : 24 Oct 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index c8533f5d8..97b72a682 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -5,7 +5,7 @@ %%% Created : 24 Oct 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index daa953371..5970bbce1 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -5,7 +5,7 @@ %%% Created : 19 Mar 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -745,7 +745,7 @@ iq_get_vcard(Lang) -> #xmlel{ns = ?NS_VCARD, name = 'DESC', children = [#xmlcdata{cdata = translate:translate(Lang, "ejabberd MUC module") ++ - "\nCopyright (c) 2003-2008 Alexey Shchepin"}]}]}. + "\nCopyright (c) 2003-2009 Alexey Shchepin"}]}]}. broadcast_service_message(Host, Msg) -> diff --git a/src/mod_muc/mod_muc_log.erl b/src/mod_muc/mod_muc_log.erl index 328f8b736..080fb4874 100644 --- a/src/mod_muc/mod_muc_log.erl +++ b/src/mod_muc/mod_muc_log.erl @@ -5,7 +5,7 @@ %%% Created : 12 Mar 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index ccd3c9db0..df515c5c4 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -5,7 +5,7 @@ %%% Created : 19 Mar 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_muc/mod_muc_room.hrl b/src/mod_muc/mod_muc_room.hrl index 1cc8cb1df..3acf1013a 100644 --- a/src/mod_muc/mod_muc_room.hrl +++ b/src/mod_muc/mod_muc_room.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -11,7 +11,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_offline.erl b/src/mod_offline.erl index bbf50fb80..6d9fbcdb1 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -5,7 +5,7 @@ %%% Created : 5 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index e9b24e1fe..849f3546c 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -5,7 +5,7 @@ %%% Created : 5 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index b159c3983..51234e148 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -5,7 +5,7 @@ %%% Created : 21 Jul 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_privacy.hrl b/src/mod_privacy.hrl index 50b07ab34..24e097cda 100644 --- a/src/mod_privacy.hrl +++ b/src/mod_privacy.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -11,7 +11,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 88fa29daf..7ad8323a0 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -5,7 +5,7 @@ %%% Created : 5 Oct 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_private.erl b/src/mod_private.erl index f4a30132e..629a3feeb 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -5,7 +5,7 @@ %%% Created : 16 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_private_odbc.erl b/src/mod_private_odbc.erl index 59f9947d7..a52bb3399 100644 --- a/src/mod_private_odbc.erl +++ b/src/mod_private_odbc.erl @@ -5,7 +5,7 @@ %%% Created : 5 Oct 2006 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_proxy65/mod_proxy65.erl b/src/mod_proxy65/mod_proxy65.erl index cf00777af..9a9fbda8b 100644 --- a/src/mod_proxy65/mod_proxy65.erl +++ b/src/mod_proxy65/mod_proxy65.erl @@ -5,7 +5,7 @@ %%% Created : 12 Oct 2006 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_proxy65/mod_proxy65.hrl b/src/mod_proxy65/mod_proxy65.hrl index 310cbac20..7bc681eaf 100644 --- a/src/mod_proxy65/mod_proxy65.hrl +++ b/src/mod_proxy65/mod_proxy65.hrl @@ -2,7 +2,7 @@ %%% RFC 1928 constants. %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -13,7 +13,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_proxy65/mod_proxy65_lib.erl b/src/mod_proxy65/mod_proxy65_lib.erl index 9f3a84fd0..2e7d44578 100644 --- a/src/mod_proxy65/mod_proxy65_lib.erl +++ b/src/mod_proxy65/mod_proxy65_lib.erl @@ -5,7 +5,7 @@ %%% Created : 12 Oct 2006 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_proxy65/mod_proxy65_service.erl b/src/mod_proxy65/mod_proxy65_service.erl index 0e1734480..3acc70b0a 100644 --- a/src/mod_proxy65/mod_proxy65_service.erl +++ b/src/mod_proxy65/mod_proxy65_service.erl @@ -5,7 +5,7 @@ %%% Created : 12 Oct 2006 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -214,7 +214,7 @@ iq_vcard(Lang) -> [#xmlcdata{cdata = list_to_binary(?EJABBERD_URI)}]}, #xmlel{ns = ?NS_VCARD, name = 'DESC', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "ejabberd SOCKS5 Bytestreams module") ++ - "\nCopyright (c) 2003-2008 Alexey Shchepin")}]}]. + "\nCopyright (c) 2003-2009 Alexey Shchepin")}]}]. parse_options(ServerHost, Opts) -> MyHost = gen_mod:get_opt_host(ServerHost, Opts, "proxy.@HOST@"), diff --git a/src/mod_proxy65/mod_proxy65_sm.erl b/src/mod_proxy65/mod_proxy65_sm.erl index 0db1f1537..92ae1a26d 100644 --- a/src/mod_proxy65/mod_proxy65_sm.erl +++ b/src/mod_proxy65/mod_proxy65_sm.erl @@ -5,7 +5,7 @@ %%% Created : 12 Oct 2006 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_proxy65/mod_proxy65_stream.erl b/src/mod_proxy65/mod_proxy65_stream.erl index 38ca75147..fbbe68380 100644 --- a/src/mod_proxy65/mod_proxy65_stream.erl +++ b/src/mod_proxy65/mod_proxy65_stream.erl @@ -4,7 +4,7 @@ %%% Purpose : Bytestream process. %%% Created : 12 Oct 2006 by Evgeniy Khramtsov %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -15,7 +15,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_pubsub/gen_pubsub_node.erl b/src/mod_pubsub/gen_pubsub_node.erl index f3fc16ff8..91b8163bc 100644 --- a/src/mod_pubsub/gen_pubsub_node.erl +++ b/src/mod_pubsub/gen_pubsub_node.erl @@ -11,12 +11,12 @@ %%% under the License. %%% %%% The Initial Developer of the Original Code is ProcessOne. -%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, ProcessOne. +%%% This software is copyright 2006-2009, ProcessOne. %%% %%% -%%% @copyright 2006-2008 ProcessOne +%%% @copyright 2006-2009 ProcessOne %%% @author Christophe Romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/gen_pubsub_nodetree.erl b/src/mod_pubsub/gen_pubsub_nodetree.erl index c249ff43d..8bd35f51d 100644 --- a/src/mod_pubsub/gen_pubsub_nodetree.erl +++ b/src/mod_pubsub/gen_pubsub_nodetree.erl @@ -11,12 +11,12 @@ %%% under the License. %%% %%% The Initial Developer of the Original Code is ProcessOne. -%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, ProcessOne. +%%% This software is copyright 2006-2009, ProcessOne. %%% %%% -%%% @copyright 2006-2008 ProcessOne +%%% @copyright 2006-2009 ProcessOne %%% @author Christophe Romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index a78ac6bad..f4b7200b4 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -11,11 +11,11 @@ %%% under the License. %%% %%% The Initial Developer of the Original Code is ProcessOne. -%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, ProcessOne. +%%% This software is copyright 2006-2009, ProcessOne. %%% -%%% @copyright 2006-2008 ProcessOne +%%% @copyright 2006-2009 ProcessOne %%% @author Christophe Romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} @@ -857,7 +857,7 @@ iq_get_vcard(Lang) -> [#xmlcdata{cdata = list_to_binary( translate:translate(Lang, "ejabberd Publish-Subscribe module") ++ - "\nCopyright (c) 2004-2008 Process-One")}]}]. + "\nCopyright (c) 2004-2009 Process-One")}]}]. iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang) -> iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, all, plugins(ServerHost)). diff --git a/src/mod_pubsub/node.template b/src/mod_pubsub/node.template index 7b7fb175c..a9f45e1ef 100644 --- a/src/mod_pubsub/node.template +++ b/src/mod_pubsub/node.template @@ -11,11 +11,11 @@ %%% under the License. %%% %%% The Initial Developer of the Original Code is ProcessOne. -%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, ProcessOne. +%%% This software is copyright 2006-2009, ProcessOne. %%% -%%% @copyright 2006-2008 ProcessOne +%%% @copyright 2006-2009 ProcessOne %%% @author Christophe romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl index 832e0dd31..91834e708 100644 --- a/src/mod_pubsub/node_buddy.erl +++ b/src/mod_pubsub/node_buddy.erl @@ -11,12 +11,12 @@ %%% under the License. %%% %%% The Initial Developer of the Original Code is ProcessOne. -%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, ProcessOne. +%%% This software is copyright 2006-2009, ProcessOne. %%% %%% -%%% @copyright 2006-2008 ProcessOne +%%% @copyright 2006-2009 ProcessOne %%% @author Christophe romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl index 8fd13cf47..d62da7201 100644 --- a/src/mod_pubsub/node_club.erl +++ b/src/mod_pubsub/node_club.erl @@ -11,12 +11,12 @@ %%% under the License. %%% %%% The Initial Developer of the Original Code is ProcessOne. -%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, ProcessOne. +%%% This software is copyright 2006-2009, ProcessOne. %%% %%% -%%% @copyright 2006-2008 ProcessOne +%%% @copyright 2006-2009 ProcessOne %%% @author Christophe romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 91d4e7054..7087ef11a 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -11,12 +11,12 @@ %%% under the License. %%% %%% The Initial Developer of the Original Code is ProcessOne. -%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, ProcessOne. +%%% This software is copyright 2006-2009, ProcessOne. %%% %%% -%%% @copyright 2006-2008 ProcessOne +%%% @copyright 2006-2009 ProcessOne %%% @author Christophe Romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/node_dispatch.erl b/src/mod_pubsub/node_dispatch.erl index a646a3373..2d9e245e9 100644 --- a/src/mod_pubsub/node_dispatch.erl +++ b/src/mod_pubsub/node_dispatch.erl @@ -11,12 +11,12 @@ %%% under the License. %%% %%% The Initial Developer of the Original Code is ProcessOne. -%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, ProcessOne. +%%% This software is copyright 2006-2009, ProcessOne. %%% %%% -%%% @copyright 2006-2008 ProcessOne +%%% @copyright 2006-2009 ProcessOne %%% @author Christophe romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/node_flat.erl b/src/mod_pubsub/node_flat.erl index 6996912b0..2d1f8b234 100644 --- a/src/mod_pubsub/node_flat.erl +++ b/src/mod_pubsub/node_flat.erl @@ -11,11 +11,11 @@ %%% under the License. %%% %%% The Initial Developer of the Original Code is ProcessOne. -%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, ProcessOne. +%%% This software is copyright 2006-2009, ProcessOne. %%% -%%% @copyright 2006-2008 ProcessOne +%%% @copyright 2006-2009 ProcessOne %%% @author Christophe romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/node_mb.erl b/src/mod_pubsub/node_mb.erl index a05ea883c..d1071d863 100644 --- a/src/mod_pubsub/node_mb.erl +++ b/src/mod_pubsub/node_mb.erl @@ -11,12 +11,12 @@ %%% under the License. %%% %%% The Initial Developer of the Original Code is ProcessOne. -%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, ProcessOne. +%%% This software is copyright 2006-2009, ProcessOne. %%% %%% -%%% @copyright 2006-2008 ProcessOne +%%% @copyright 2006-2009 ProcessOne %%% @author Eric Cestari %%% @version {@vsn}, {@date} {@time} %%% @end diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index abc3e2ed3..47041b83d 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -11,12 +11,12 @@ %%% under the License. %%% %%% The Initial Developer of the Original Code is ProcessOne. -%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, ProcessOne. +%%% This software is copyright 2006-2009, ProcessOne. %%% %%% -%%% @copyright 2006-2008 ProcessOne +%%% @copyright 2006-2009 ProcessOne %%% @author Christophe Romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl index ae9768344..a1fe4783b 100644 --- a/src/mod_pubsub/node_private.erl +++ b/src/mod_pubsub/node_private.erl @@ -11,12 +11,12 @@ %%% under the License. %%% %%% The Initial Developer of the Original Code is ProcessOne. -%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, ProcessOne. +%%% This software is copyright 2006-2009, ProcessOne. %%% %%% -%%% @copyright 2006-2008 ProcessOne +%%% @copyright 2006-2009 ProcessOne %%% @author Christophe romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl index 5276c4d26..0a3d9d7cb 100644 --- a/src/mod_pubsub/node_public.erl +++ b/src/mod_pubsub/node_public.erl @@ -11,12 +11,12 @@ %%% under the License. %%% %%% The Initial Developer of the Original Code is ProcessOne. -%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, ProcessOne. +%%% This software is copyright 2006-2009, ProcessOne. %%% %%% -%%% @copyright 2006-2008 ProcessOne +%%% @copyright 2006-2009 ProcessOne %%% @author Christophe romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/nodetree_default.erl b/src/mod_pubsub/nodetree_default.erl index 6bac99434..b8a6b6f26 100644 --- a/src/mod_pubsub/nodetree_default.erl +++ b/src/mod_pubsub/nodetree_default.erl @@ -11,12 +11,12 @@ %%% under the License. %%% %%% The Initial Developer of the Original Code is ProcessOne. -%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, ProcessOne. +%%% This software is copyright 2006-2009, ProcessOne. %%% %%% -%%% @copyright 2006-2008 ProcessOne +%%% @copyright 2006-2009 ProcessOne %%% @author Christophe Romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/nodetree_virtual.erl b/src/mod_pubsub/nodetree_virtual.erl index b76419b6c..92864a272 100644 --- a/src/mod_pubsub/nodetree_virtual.erl +++ b/src/mod_pubsub/nodetree_virtual.erl @@ -11,12 +11,12 @@ %%% under the License. %%% %%% The Initial Developer of the Original Code is ProcessOne. -%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, ProcessOne. +%%% This software is copyright 2006-2009, ProcessOne. %%% %%% -%%% @copyright 2006-2008 ProcessOne +%%% @copyright 2006-2009 ProcessOne %%% @author Christophe Romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} diff --git a/src/mod_pubsub/pubsub.hrl b/src/mod_pubsub/pubsub.hrl index 61ed88dbe..46cbe9b95 100644 --- a/src/mod_pubsub/pubsub.hrl +++ b/src/mod_pubsub/pubsub.hrl @@ -11,12 +11,12 @@ %%% under the License. %%% %%% The Initial Developer of the Original Code is ProcessOne. -%%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %%% All Rights Reserved.'' -%%% This software is copyright 2006-2008, ProcessOne. +%%% This software is copyright 2006-2009, ProcessOne. %%% %%% -%%% copyright 2006-2008 ProcessOne +%%% copyright 2006-2009 ProcessOne %%% %%% This file contains pubsub types definition. %%% ==================================================================== diff --git a/src/mod_register.erl b/src/mod_register.erl index a51408920..8fbd09696 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -5,7 +5,7 @@ %%% Created : 8 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 569c30b2d..00a3ffa5c 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -5,7 +5,7 @@ %%% Created : 11 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_roster.hrl b/src/mod_roster.hrl index 8fd0be57f..4278a57b1 100644 --- a/src/mod_roster.hrl +++ b/src/mod_roster.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -11,7 +11,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index d41b911ce..ee7718224 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -5,7 +5,7 @@ %%% Created : 15 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/mod_service_log.erl b/src/mod_service_log.erl index 7ecf11a84..ab9463d24 100644 --- a/src/mod_service_log.erl +++ b/src/mod_service_log.erl @@ -5,7 +5,7 @@ %%% Created : 24 Aug 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index d3bbd9aab..ee41de61f 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -5,7 +5,7 @@ %%% Created : 5 Mar 2005 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_stats.erl b/src/mod_stats.erl index f0b549660..8282b94b0 100644 --- a/src/mod_stats.erl +++ b/src/mod_stats.erl @@ -5,7 +5,7 @@ %%% Created : 11 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_time.erl b/src/mod_time.erl index 24ee78489..4e12ac528 100644 --- a/src/mod_time.erl +++ b/src/mod_time.erl @@ -5,7 +5,7 @@ %%% Created : 18 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index d66912c65..c4c8ff1b1 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -5,7 +5,7 @@ %%% Created : 2 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -159,7 +159,7 @@ process_local_iq(_From, _To, #iq{type = get, lang = Lang} = IQ_Rec) -> ?EJABBERD_URI), exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'DESC'}, translate:translate(Lang, "Erlang Jabber Server") ++ - "\nCopyright (c) 2002-2008 ProcessOne"), + "\nCopyright (c) 2002-2009 ProcessOne"), exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'BDAY'}, "2002-11-16") ]}, @@ -430,7 +430,7 @@ iq_get_vcard(Lang) -> #xmlel{ns = ?NS_SEARCH, name ='DESC', children = [ #xmlcdata{cdata = list_to_binary( translate:translate(Lang, "ejabberd vCard module") ++ - "\nCopyright (c) 2003-2008 ProcessOne")}]} + "\nCopyright (c) 2003-2009 ProcessOne")}]} ]. find_xdata_el(#xmlel{children = SubEls}) -> diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index 1279bcd7a..f625a1cf7 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -5,7 +5,7 @@ %%% Created : 2 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -229,7 +229,7 @@ process_local_iq(_From, _To, #iq{type = get, lang = Lang} = IQ_Rec) -> ?EJABBERD_URI), exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'DESC'}, translate:translate(Lang, "Erlang Jabber Server") ++ - "\nCopyright (c) 2002-2008 ProcessOne"), + "\nCopyright (c) 2002-2009 ProcessOne"), exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'BDAY'}, "2002-11-16") ]}, @@ -521,7 +521,7 @@ iq_get_vcard(Lang) -> #xmlel{ns = ?NS_SEARCH, name ='DESC', children = [ #xmlcdata{cdata = list_to_binary( translate:translate(Lang, "ejabberd vCard module") ++ - "\nCopyright (c) 2003-2008 ProcessOne")}]} + "\nCopyright (c) 2003-2009 ProcessOne")}]} ]. search_result(Lang, JID, State, Data) -> diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl index c1f46b685..96bad68bb 100644 --- a/src/mod_vcard_odbc.erl +++ b/src/mod_vcard_odbc.erl @@ -5,7 +5,7 @@ %%% Created : 2 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -121,7 +121,7 @@ process_local_iq(_From, _To, #iq{type = get, lang = Lang} = IQ_Rec) -> ?EJABBERD_URI), exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'DESC'}, translate:translate(Lang, "Erlang Jabber Server") ++ - "\nCopyright (c) 2002-2008 ProcessOne"), + "\nCopyright (c) 2002-2009 ProcessOne"), exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'BDAY'}, "2002-11-16") ]}, @@ -393,7 +393,7 @@ iq_get_vcard(Lang) -> #xmlel{ns = ?NS_SEARCH, name ='DESC', children = [ #xmlcdata{cdata = list_to_binary( translate:translate(Lang, "ejabberd vCard module") ++ - "\nCopyright (c) 2003-2008 ProcessOne")}]} + "\nCopyright (c) 2003-2009 ProcessOne")}]} ]. find_xdata_el(#xmlel{children = SubEls}) -> diff --git a/src/mod_version.erl b/src/mod_version.erl index 07d6dfec4..23d49a6c7 100644 --- a/src/mod_version.erl +++ b/src/mod_version.erl @@ -5,7 +5,7 @@ %%% Created : 18 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/odbc/ejabberd_odbc.erl b/src/odbc/ejabberd_odbc.erl index 3a75b8a6e..d40cb7588 100644 --- a/src/odbc/ejabberd_odbc.erl +++ b/src/odbc/ejabberd_odbc.erl @@ -5,7 +5,7 @@ %%% Created : 8 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -326,6 +326,8 @@ pgsql_item_to_odbc("INSERT " ++ OIDN) -> {updated, list_to_integer(N)}; pgsql_item_to_odbc("DELETE " ++ N) -> {updated, list_to_integer(N)}; +pgsql_item_to_odbc("UPDATE " ++ N) -> + {updated, list_to_integer(N)}; pgsql_item_to_odbc({error, Error}) -> {error, Error}; pgsql_item_to_odbc(_) -> diff --git a/src/odbc/ejabberd_odbc_sup.erl b/src/odbc/ejabberd_odbc_sup.erl index 80f0a36ca..5422769da 100644 --- a/src/odbc/ejabberd_odbc_sup.erl +++ b/src/odbc/ejabberd_odbc_sup.erl @@ -5,7 +5,7 @@ %%% Created : 22 Dec 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/odbc/mssql2000.sql b/src/odbc/mssql2000.sql index c9313ede1..d305784fb 100644 --- a/src/odbc/mssql2000.sql +++ b/src/odbc/mssql2000.sql @@ -1,5 +1,5 @@ /* - * ejabberd, Copyright (C) 2002-2008 ProcessOne + * ejabberd, Copyright (C) 2002-2009 ProcessOne * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/odbc/mssql2005.sql b/src/odbc/mssql2005.sql index f61980c0a..0ac89a434 100644 --- a/src/odbc/mssql2005.sql +++ b/src/odbc/mssql2005.sql @@ -1,5 +1,5 @@ /* - * ejabberd, Copyright (C) 2002-2008 Process-one + * ejabberd, Copyright (C) 2002-2009 Process-one * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/odbc/mysql.sql b/src/odbc/mysql.sql index 376164a5d..cdc20062c 100644 --- a/src/odbc/mysql.sql +++ b/src/odbc/mysql.sql @@ -1,5 +1,5 @@ -- --- ejabberd, Copyright (C) 2002-2008 ProcessOne +-- ejabberd, Copyright (C) 2002-2009 ProcessOne -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License as diff --git a/src/odbc/odbc_queries.erl b/src/odbc/odbc_queries.erl index 080a353c8..b878184a8 100644 --- a/src/odbc/odbc_queries.erl +++ b/src/odbc/odbc_queries.erl @@ -5,7 +5,7 @@ %%% Created : by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/odbc/pg.sql b/src/odbc/pg.sql index 971cde42f..1cb9eeb4d 100644 --- a/src/odbc/pg.sql +++ b/src/odbc/pg.sql @@ -1,5 +1,5 @@ -- --- ejabberd, Copyright (C) 2002-2008 ProcessOne +-- ejabberd, Copyright (C) 2002-2009 ProcessOne -- -- This program is free software; you can redistribute it and/or -- modify it under the terms of the GNU General Public License as diff --git a/src/p1_fsm.erl b/src/p1_fsm.erl index f280286b9..40ae33465 100644 --- a/src/p1_fsm.erl +++ b/src/p1_fsm.erl @@ -14,7 +14,7 @@ %% AB. All Rights Reserved.'' %% %% The code has been modified and improved by ProcessOne. -%% Copyright 2007-2008, ProcessOne +%% Copyright 2007-2009, ProcessOne %% %% The change adds the following features: %% - You can send exit(priority_shutdown) to the p1_fsm process to diff --git a/src/p1_mnesia.erl b/src/p1_mnesia.erl index 417a7cc08..d173e43c9 100644 --- a/src/p1_mnesia.erl +++ b/src/p1_mnesia.erl @@ -10,7 +10,7 @@ %% under the License. %% %% The Initial Developer of the Original Code is ProcessOne. -%% Portions created by ProcessOne are Copyright 2006-2008, ProcessOne +%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne %% All Rights Reserved.'' -module(p1_mnesia). diff --git a/src/pam/epam.c b/src/pam/epam.c index 715de9049..3a24d7ce2 100644 --- a/src/pam/epam.c +++ b/src/pam/epam.c @@ -1,5 +1,5 @@ /* - * ejabberd, Copyright (C) 2002-2008 ProcessOne + * ejabberd, Copyright (C) 2002-2009 ProcessOne * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/pam/epam.erl b/src/pam/epam.erl index dc97da64b..6582088b1 100644 --- a/src/pam/epam.erl +++ b/src/pam/epam.erl @@ -5,7 +5,7 @@ %%% Created : 5 Jul 2007 by Evgeniy Khramtsov %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/randoms.erl b/src/randoms.erl index bb71a23f8..d3c29b444 100644 --- a/src/randoms.erl +++ b/src/randoms.erl @@ -5,7 +5,7 @@ %%% Created : 13 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/sha.erl b/src/sha.erl index 2b19f55f9..aec6d562d 100644 --- a/src/sha.erl +++ b/src/sha.erl @@ -5,7 +5,7 @@ %%% Created : 20 Dec 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/shaper.erl b/src/shaper.erl index cc707dff6..6a5916cf8 100644 --- a/src/shaper.erl +++ b/src/shaper.erl @@ -5,7 +5,7 @@ %%% Created : 9 Feb 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/stringprep/stringprep.erl b/src/stringprep/stringprep.erl index 3acfa87b7..eac3745b7 100644 --- a/src/stringprep/stringprep.erl +++ b/src/stringprep/stringprep.erl @@ -5,7 +5,7 @@ %%% Created : 16 Feb 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/stringprep/stringprep_drv.c b/src/stringprep/stringprep_drv.c index ac89eaca7..2d31020c5 100644 --- a/src/stringprep/stringprep_drv.c +++ b/src/stringprep/stringprep_drv.c @@ -1,5 +1,5 @@ /* - * ejabberd, Copyright (C) 2002-2008 ProcessOne + * ejabberd, Copyright (C) 2002-2009 ProcessOne * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/stringprep/stringprep_sup.erl b/src/stringprep/stringprep_sup.erl index ba885139a..354d52d07 100644 --- a/src/stringprep/stringprep_sup.erl +++ b/src/stringprep/stringprep_sup.erl @@ -5,7 +5,7 @@ %%% Created : 29 Jun 2007 by Mickael Remond %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/tls/tls.erl b/src/tls/tls.erl index 7281fd475..3ba164d65 100644 --- a/src/tls/tls.erl +++ b/src/tls/tls.erl @@ -5,7 +5,7 @@ %%% Created : 24 Jul 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/tls/tls_drv.c b/src/tls/tls_drv.c index 2f8e56150..ac438ebca 100644 --- a/src/tls/tls_drv.c +++ b/src/tls/tls_drv.c @@ -1,5 +1,5 @@ /* - * ejabberd, Copyright (C) 2002-2008 ProcessOne + * ejabberd, Copyright (C) 2002-2009 ProcessOne * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/src/translate.erl b/src/translate.erl index f54fe6f86..8929ccd06 100644 --- a/src/translate.erl +++ b/src/translate.erl @@ -5,7 +5,7 @@ %%% Created : 6 Jan 2003 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/treap.erl b/src/treap.erl index efe0d477f..ab5c4d33f 100644 --- a/src/treap.erl +++ b/src/treap.erl @@ -5,7 +5,7 @@ %%% Created : 22 Apr 2008 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as diff --git a/src/web/ejabberd_http.erl b/src/web/ejabberd_http.erl index bd7f7db98..de8529224 100644 --- a/src/web/ejabberd_http.erl +++ b/src/web/ejabberd_http.erl @@ -5,7 +5,7 @@ %%% Created : 27 Feb 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/web/ejabberd_http.hrl b/src/web/ejabberd_http.hrl index c8f8a4e21..81dbfdfb9 100644 --- a/src/web/ejabberd_http.hrl +++ b/src/web/ejabberd_http.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -11,7 +11,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/web/ejabberd_http_poll.erl b/src/web/ejabberd_http_poll.erl index 7f8c70807..bd006db25 100644 --- a/src/web/ejabberd_http_poll.erl +++ b/src/web/ejabberd_http_poll.erl @@ -5,7 +5,7 @@ %%% Created : 4 Mar 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/web/ejabberd_web.erl b/src/web/ejabberd_web.erl index fc5ce9a40..5d1abff76 100644 --- a/src/web/ejabberd_web.erl +++ b/src/web/ejabberd_web.erl @@ -5,7 +5,7 @@ %%% Created : 28 Feb 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index fbac03762..2e8f5c59d 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -5,7 +5,7 @@ %%% Created : 9 Apr 2004 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA @@ -179,7 +179,7 @@ make_xhtml(Els, Host, Node, Lang) -> [?XAE('div', [#xmlattr{name = 'id', value = "copyright"}], [?XC('p', - "ejabberd (c) 2002-2008 ProcessOne") + "ejabberd (c) 2002-2009 ProcessOne") ])])]) ]}}. diff --git a/src/web/ejabberd_web_admin.hrl b/src/web/ejabberd_web_admin.hrl index 1469b83d8..b79b9152e 100644 --- a/src/web/ejabberd_web_admin.hrl +++ b/src/web/ejabberd_web_admin.hrl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -11,7 +11,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/xml.erl b/src/xml.erl index 1eb4a8606..c55ca0d6e 100644 --- a/src/xml.erl +++ b/src/xml.erl @@ -5,7 +5,7 @@ %%% Created : 20 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/xml_stream.erl b/src/xml_stream.erl index 332bb4d34..13295285b 100644 --- a/src/xml_stream.erl +++ b/src/xml_stream.erl @@ -5,7 +5,7 @@ %%% Created : 17 Nov 2002 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne +%%% ejabberd, Copyright (C) 2002-2009 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ %%% 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., 59 Temple Place, Suite 330, Boston, MA From fc77b48344c0267e5b51d4d83f9da8649c04ff9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 19 Jan 2009 15:27:07 +0000 Subject: [PATCH 172/582] Merge from trunk (r1804 to r1829). The merge party is over, you may now double-check that everything is in place. PR: EJABP-1 SVN Revision: 1830 --- ChangeLog | 71 ++++++ doc/guide.html | 144 ++++++++---- doc/guide.tex | 165 ++++++++++---- doc/release_notes_2.0.3.txt | 35 +++ src/ejabberd_admin.erl | 8 +- src/ejabberd_c2s.erl | 20 +- src/ejabberd_config.erl | 12 +- src/ejabberd_listener.erl | 169 +++++++++++--- src/jd2ejd.erl | 2 +- src/mod_configure.erl | 6 +- src/mod_muc/mod_muc_room.erl | 4 +- src/mod_offline.erl | 2 +- src/mod_offline_odbc.erl | 2 +- src/mod_privacy.erl | 7 +- src/mod_privacy_odbc.erl | 7 +- src/mod_proxy65/mod_proxy65_service.erl | 22 +- src/mod_proxy65/mod_proxy65_stream.erl | 3 +- src/mod_pubsub/mod_pubsub.erl | 2 +- src/mod_roster.erl | 4 +- src/mod_roster_odbc.erl | 4 +- src/mod_shared_roster.erl | 35 +-- src/mod_stats.erl | 4 +- src/msgs/ca.msg | 14 +- src/msgs/ca.po | 26 +-- src/msgs/cs.msg | 16 +- src/msgs/cs.po | 26 +-- src/msgs/de.msg | 14 +- src/msgs/de.po | 24 +- src/msgs/ejabberd.pot | 8 +- src/msgs/eo.msg | 14 +- src/msgs/eo.po | 26 +-- src/msgs/es.msg | 14 +- src/msgs/es.po | 22 +- src/msgs/fr.msg | 14 +- src/msgs/fr.po | 24 +- src/msgs/gl.msg | 14 +- src/msgs/gl.po | 22 +- src/msgs/it.msg | 18 +- src/msgs/it.po | 30 +-- src/msgs/ja.msg | 14 +- src/msgs/ja.po | 26 +-- src/msgs/nl.msg | 14 +- src/msgs/nl.po | 20 +- src/msgs/no.msg | 14 +- src/msgs/no.po | 26 +-- src/msgs/pl.msg | 18 +- src/msgs/pl.po | 28 +-- src/msgs/pt-br.msg | 14 +- src/msgs/pt-br.po | 26 +-- src/msgs/pt.msg | 6 +- src/msgs/pt.po | 24 +- src/msgs/ru.msg | 14 +- src/msgs/ru.po | 26 +-- src/msgs/sk.msg | 16 +- src/msgs/sk.po | 28 +-- src/msgs/sv.msg | 14 +- src/msgs/sv.po | 26 +-- src/msgs/th.msg | 14 +- src/msgs/th.po | 26 +-- src/msgs/tr.msg | 14 +- src/msgs/tr.po | 26 +-- src/msgs/uk.msg | 14 +- src/msgs/uk.po | 26 +-- src/msgs/vi.msg | 14 +- src/msgs/vi.po | 26 +-- src/msgs/wa.msg | 14 +- src/msgs/wa.po | 24 +- src/msgs/zh.msg | 14 +- src/msgs/zh.po | 24 +- src/tls/Makefile.win32 | 2 +- src/tls/stdint.h | 232 +++++++++++++++++++ src/tls/tls_drv.c | 2 - src/web/ejabberd_web_admin.erl | 289 ++++++++++++++---------- src/web/ejabberd_web_admin.hrl | 14 +- 74 files changed, 1420 insertions(+), 763 deletions(-) create mode 100644 doc/release_notes_2.0.3.txt create mode 100755 src/tls/stdint.h diff --git a/ChangeLog b/ChangeLog index 6620ad0bc..4d5e64392 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-01-19 Jean-Sébastien Pédron + + Merge from trunk (r1804 to r1829). + 2009-01-19 Jean-Sébastien Pédron Merge from trunk (r1752 to r1804). @@ -15,6 +19,10 @@ * src/ejabberd_auth_anonymous.erl: Fix accesses to the new #jid opaque type. +2009-01-17 Mickael Remond + + * src/ejabberd_c2s.erl: Added comments. + 2009-01-16 Jean-Sébastien Pédron Merge from trunk (r1734 to r1752). @@ -26,6 +34,12 @@ * src/jlib.hrl: Any deprecated content was removed from jlib.hrl. This leaves only the new RSM records. +2009-01-16 Badlop + + * src/mod_privacy.erl: Privacy list items must be processed in the + specified order (EJAB-848) + * src/mod_privacy_odbc.erl: Likewise + 2009-01-15 Pablo Polvorin * src/mod_muc/mod_muc.erl, src/mod_muc/mod_muc_room.erl: @@ -33,6 +47,63 @@ Use document_to_iolist/1 and iolist_size/1 instead of document_to_list/1. +2009-01-13 Badlop + + * doc/release_notes_2.0.3.txt: Add release notes + +2009-01-13 Mickael Remond + + * src/tls/Makefile.win32: Windows compilation support. + * src/tls/tls_drv.c: Likewise. + * src/tls/stdint.h: Likewise. + + * doc/guide.tex: Update Erlang version in Windows compilation + documentation. + +2009-01-13 Badlop + + * src/msgs/pl.po: Fix typo (thanks to Apag0r)(EJAB-844) + +2009-01-12 Badlop + + * src/web/ejabberd_web_admin.erl: Use textareas for large input + like ejabberd module options and listening port options. Show + result of POST more clearly. Ensure access rules are shown with + some minimum separation. Improve menu headers. (EJAB-562) + * src/web/ejabberd_web_admin.hrl: Likewise + * src/mod_offline.erl: Likewise + * src/mod_offline_odbc.erl: Likewise + * src/mod_roster.erl: Likewise + * src/mod_roster_odbc.erl: Likewise + * src/mod_shared_roster.erl: Likewise + + * src/ejabberd_listener.erl: New way to configure IP address and + IP version of listener. Support for definition of IP address in + string format, and implicit definition of IP + version (EJAB-388). Support for defining several listeners: all + with same port number but different IP addresses (EJAB-389)(thanks + to Fabrice Colliot and Sergei Golovan). Better report in WebAdmin + of problem when starting a listener. The old configuration method + of ip tuple and inet6 is fully supported for backwards + compatibility, but is not documented in the Guide anymore. + * src/ejabberd_config.erl: Likewise + * src/mod_proxy65/mod_proxy65_stream.erl: Likewise + * src/mod_proxy65/mod_proxy65_service.erl: Likewise + * src/web/ejabberd_web_admin.erl: Likewise + + * doc/guide.tex: Document the new way to configure IP address and + IP version of listener, undocument options ip and inet6 + * doc/guide.html: Likewise + + * src/web/ejabberd_web_admin.erl: New appearance of WebAdmin logo, + fixed logo-fill. + + * doc/guide.tex: Fix some English strings: JID -> Jabber ID; + jabberd 1.4 -> jabberd14; commited -> committed + * src/*/*.erl: Likewise + * src/msgs/*.msg: Likewise + * src/msgs/*.po: Likewise + 2009-01-12 Alexey Shchepin * src/odbc/ejabberd_odbc.erl: Fixed processing of UPDATE results diff --git a/doc/guide.html b/doc/guide.html index 9d0fde157..3282fc3d8 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -622,31 +622,59 @@ other different modules for some specific virtual hosts: will listen and what services will be run on them. Each element of the list is a tuple with the following elements:

      • -Port number. -
      • Module that serves this port. -
      • Options to this module. -

      +Port number. Optionally also the IP address. +

    • Listening module that serves this port. +
    • Options for the TCP socket and for the listening module. +
    • With the basic syntax the ports will listen on all IPv4 network addresses: +

      {listen, [
      +          {<port-number>, <module>, [<options>]},
      +          {<port-number>, <module>, [<options>]},
      +          ...
      +          {<port-number>, <module>, [<options>]}
      +         ]}.
      +

      It is possible to specify the IP address for a port using the full syntax: +

                {{<port-number>, <ip-address>}, <module>, [<options>]}
      +

      +

      Port Number and IP Address

      The port number defines which port to listen for incoming connections. +It can be a Jabber/XMPP standard port +(see section 5.1) or any other valid port number.

      The IP address can be represented with a string +or an Erlang tuple with decimal or hexadecimal numbers. +The socket will listen only in that network interface. +It is possible to specify a generic address, +so ejabberd will listen in all addresses. +Depending in the type of the IP address, IPv4 or IPv6 will be used.

      Some example values for IP address: +

      • +"0.0.0.0" to listen in all IPv4 network interfaces. This is the default value when no IP is specified. +
      • "::" to listen in all IPv6 network interfaces +
      • "10.11.12.13" is the IPv4 address 10.11.12.13 +
      • "::FFFF:127.0.0.1" is the IPv6 address ::FFFF:127.0.0.1/128 +
      • {10, 11, 12, 13} is the IPv4 address 10.11.12.13 +
      • {0, 0, 0, 0, 0, 65535, 32512, 1} is the IPv6 address ::FFFF:127.0.0.1/128 +
      • {16#fdca, 16#8ab6, 16#a243, 16#75ef, 0, 0, 0, 1} is the IPv6 address FDCA:8AB6:A243:75EF::1/128 +

      +

      Listening Module

      The available modules, their purpose and the options allowed by each one are:

      ejabberd_c2s
      Handles c2s connections.
      - Options: access, certfile, inet6, -ip, max_stanza_size, shaper, + Options: access, certfile, +max_stanza_size, shaper, starttls, starttls_required, tls, zlib
      ejabberd_s2s_in
      Handles incoming s2s connections.
      - Options: inet6, ip, max_stanza_size + Options: max_stanza_size
      ejabberd_service
      Interacts with an external component (as defined in the Jabber Component Protocol (XEP-0114).
      - Options: access, hosts, inet6, -ip, shaper, service_check_from + Options: access, hosts, +shaper, service_check_from
      ejabberd_http
      Handles incoming HTTP connections.
      Options: certfile, http_bind, http_poll, -inet6, ip, request_handlers, tls, web_admin
      -

      This is a detailed description of each option allowed by the listening modules: +request_handlers, tls, web_admin
      +

      +

      Options

      This is a detailed description of each option allowed by the listening modules:

      {access, <access rule>}
      This option defines access to the port. The default value is all. @@ -685,13 +713,7 @@ do not allow outgoing sockets on port 5222.

      If HTTP Polling is enabled, it wil is also needed in the Jabber client. Remark also that HTTP Polling can be interesting to host a web-based Jabber client such as JWChat. -

      inet6
      Set up the socket for IPv6 instead of IPv4. -Note: this option is not required for S2S outgoing connections, -because when ejabberd attempts to establish a S2S outgoing connection -it first tries IPv4, and if that fails it attempts with IPv6. -
      {ip, IPAddress}
      This option specifies which network -interface to listen for. For example {ip, {192, 168, 1, 1}}. -
      {max_stanza_size, Size}
      +

      {max_stanza_size, Size}
      This option specifies an approximate maximum size in bytes of XML stanzas. Approximate, because it is calculated with the precision of one block of readed @@ -736,7 +758,7 @@ is available on connections to the port. Client connections cannot use stream compression and stream encryption simultaneously. Hence, if you specify both tls (or ssl) and zlib, the latter option will not affect connections (there will be no stream compression). -

      There are some additional global options: +

      There are some additional global options that can be specified in the ejabberd configuration file (outside listen):

      {s2s_use_starttls, true|false}
      This option defines whether to @@ -759,17 +781,18 @@ with a small list of trusted servers, or to block some specific servers.
      {s2s_max_retry_delay, Seconds}
      The maximum allowed delay for retry to connect after a failed connection attempt. Specified in seconds. The default value is 300 seconds (5 minutes). -

      For example, the following simple configuration defines: +

      +

      Examples

      For example, the following simple configuration defines:

      • There are three domains. The default certificate file is server.pem. However, the c2s and s2s connections to the domain example.com use the file example_com.pem.
      • Port 5222 listens for c2s connections with STARTTLS, and also allows plain connections for old clients.
      • Port 5223 listens for c2s connections with the old SSL. -
      • Port 5269 listens for s2s connections with STARTTLS. +
      • Port 5269 listens for s2s connections with STARTTLS. The socket is set for IPv6 instead of IPv4.
      • Port 5280 listens for HTTP requests, and serves the HTTP Poll service.
      • Port 5281 listens for HTTP requests, and serves the Web Admin using HTTPS as explained in -section 4.2. +section 4.2. The socket only listens connections to the IP address 127.0.0.1.
      {hosts, ["example.com", "example.org", "example.net"]}.
       {listen,
        [
      @@ -785,17 +808,17 @@ section 4.2.
                               tls, {certfile, "/etc/ejabberd/server.pem"},
                               {max_stanza_size, 65536}
                              ]},
      -  {5269, ejabberd_s2s_in, [
      -                           {shaper, s2s_shaper},
      -                           {max_stanza_size, 131072}
      -                          ]},
      +  {{5269, "::"}, ejabberd_s2s_in, [
      +                                   {shaper, s2s_shaper},
      +                                   {max_stanza_size, 131072}
      +                                  ]},
         {5280, ejabberd_http, [
                                http_poll
                               ]},
      -  {5281, ejabberd_http, [
      -                         web_admin,
      -                         tls, {certfile, "/etc/ejabberd/server.pem"},
      -                        ]}
      +  {{5281, "127.0.0.1"}, ejabberd_http, [
      +                                        web_admin,
      +                                        tls, {certfile, "/etc/ejabberd/server.pem"},
      +                                       ]}
        ]
       }.
       {s2s_use_starttls, true}.
      @@ -803,21 +826,23 @@ section 4.2.
       {domain_certfile, "example.com", "/etc/ejabberd/example_com.pem"}.
       

      In this example, the following configuration defines that:

      • -c2s connections are listened for on port 5222 and 5223 (SSL) and denied +c2s connections are listened for on port 5222 (all IPv4 addresses) and +on port 5223 (SSL, IP 192.168.0.1 and fdca:8ab6:a243:75ef::1) and denied for the user called ‘bad’. -
      • s2s connections are listened for on port 5269 with STARTTLS for secured -traffic enabled. +
      • s2s connections are listened for on port 5269 (all IPv4 addresses) +with STARTTLS for secured traffic enabled. Incoming and outgoing connections of remote Jabber servers are denied, only two servers can connect: "jabber.example.org" and "example.com". -
      • Port 5280 is serving the Web Admin and the HTTP Polling service. Note +
      • Port 5280 is serving the Web Admin and the HTTP Polling service +in all the IPv4 addresses. Note that it is also possible to serve them on different ports. The second example in section 4.2 shows how exactly this can be done. -
      • All users except for the administrators have a traffic of limit +
      • All users except for the administrators have a traffic of limit 1,000 Bytes/second
      • The AIM transport -aim.example.org is connected to port 5233 with password -‘aimsecret’. +aim.example.org is connected to port 5233 on localhost IP addresses +(127.0.0.1 and ::1) with password ‘aimsecret’.
      • The ICQ transport JIT (icq.example.org and sms.example.org) is connected to port 5234 with password ‘jitsecret’. @@ -843,13 +868,32 @@ connected to port 5237 with password ‘ggsecret’. {access, c2s_shaper, [{none, admin}, {normal, all}]}. {listen, - [{5222, ejabberd_c2s, [{access, c2s}, {shaper, c2s_shaper}]}, - {5223, ejabberd_c2s, [{access, c2s}, - ssl, {certfile, "/path/to/ssl.pem"}]}, - {5269, ejabberd_s2s_in, []}, - {5280, ejabberd_http, [http_poll, web_admin]}, - {5233, ejabberd_service, [{hosts, ["aim.example.org"], - [{password, "aimsecret"}]}]}, + [{5222, ejabberd_c2s, [ + {access, c2s}, + {shaper, c2s_shaper} + ]}, + {{5223, {192, 168, 0, 1}}, ejabberd_c2s, [ + {access, c2s}, + ssl, {certfile, "/path/to/ssl.pem"} + ]}, + {{5223, {16#fdca, 16#8ab6, 16#a243, 16#75ef, 0, 0, 0, 1}}, + ejabberd_c2s, [ + {access, c2s}, + ssl, {certfile, "/path/to/ssl.pem"} + ]}, + {5269, ejabberd_s2s_in, []}, + {{5280, {0, 0, 0, 0}}, ejabberd_http, [ + http_poll, + web_admin + ]}, + {{5233, {127, 0, 0, 1}}, ejabberd_service, [ + {hosts, ["aim.example.org"], + [{password, "aimsecret"}]} + ]}, + {{5233, "::1"}, ejabberd_service, [ + {hosts, ["aim.example.org"], + [{password, "aimsecret"}]} + ]}, {5234, ejabberd_service, [{hosts, ["icq.example.org", "sms.example.org"], [{password, "jitsecret"}]}]}, {5235, ejabberd_service, [{hosts, ["msn.example.org"], @@ -3073,16 +3117,20 @@ administer the virtual host example.com.
      • For security reasons, you can serve the Web Admin on a secured connection, on a port differing from the HTTP Polling interface, and bind it to the internal LAN IP. The Web Admin will be accessible by pointing your -web browser to https://192.168.1.1:5280/admin/: +web browser to https://192.168.1.1:5282/admin/:
         {hosts, ["example.org"]}.
         
         {listen,
          [
           ...
        -  {5270, ejabberd_http,    [http_poll]},
        -  {5280, ejabberd_http,    [web_admin, {ip, {192, 168, 1, 1}},
        -                            tls, {certfile, "/usr/local/etc/server.pem"}]},
        +  {5280, ejabberd_http, [
        +                         http_poll
        +                        ]},
        +  {{5282, "192.168.1.1"}, ejabberd_http, [
        +                                          web_admin,
        +                                          tls, {certfile, "/usr/local/etc/server.pem"}
        +                                         ]},
           ...
          ]}.
         

      Certain pages in the ejabberd Web Admin contain a link to a related diff --git a/doc/guide.tex b/doc/guide.tex index 49b270f14..9ee7be777 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -524,7 +524,7 @@ We assume that we will try to put as much library as possible into \verb|C:\sdk\ \item Install OpenSSL in \verb|C:\sdk\OpenSSL| and add \verb|C:\sdk\OpenSSL\lib\VC| to your path or copy the binaries to your system directory. \item Install ZLib in \verb|C:\sdk\gnuWin32|. Copy \verb|C:\sdk\GnuWin32\bin\zlib1.dll| to your system directory. If you change your path it should already be set after libiconv install. -\item Make sure the you can access Erlang binaries from your path. For example: \verb|set PATH=%PATH%;"C:\sdk\erl5.5.5\bin"| +\item Make sure the you can access Erlang binaries from your path. For example: \verb|set PATH=%PATH%;"C:\sdk\erl5.6.5\bin"| \item Depending on how you end up actually installing the library you might need to check and tweak the paths in the file configure.erl. \item While in the directory \verb|ejabberd\src| run: \begin{verbatim} @@ -735,34 +735,80 @@ The option \option{listen} defines for which addresses and ports \ejabberd{} will listen and what services will be run on them. Each element of the list is a tuple with the following elements: \begin{itemize} -\item Port number. -\item Module that serves this port. -\item Options to this module. +\item Port number. Optionally also the IP address. +\item Listening module that serves this port. +\item Options for the TCP socket and for the listening module. \end{itemize} +With the basic syntax the ports will listen on all IPv4 network addresses: +\begin{verbatim} +{listen, [ + {, , []}, + {, , []}, + ... + {, , []} + ]}. +\end{verbatim} + +It is possible to specify the IP address for a port using the full syntax: +\begin{verbatim} + {{, }, , []} +\end{verbatim} + + +\makesubsubsection{listened-port}{Port Number and IP Address} + +The port number defines which port to listen for incoming connections. +It can be a Jabber/XMPP standard port +(see section \ref{firewall}) or any other valid port number. + +The IP address can be represented with a string +or an Erlang tuple with decimal or hexadecimal numbers. +The socket will listen only in that network interface. +It is possible to specify a generic address, +so \ejabberd{} will listen in all addresses. +Depending in the type of the IP address, IPv4 or IPv6 will be used. + +Some example values for IP address: +\begin{itemize} +\item \verb|"0.0.0.0"| to listen in all IPv4 network interfaces. This is the default value when no IP is specified. +\item \verb|"::"| to listen in all IPv6 network interfaces +\item \verb|"10.11.12.13"| is the IPv4 address \verb|10.11.12.13| +\item \verb|"::FFFF:127.0.0.1"| is the IPv6 address \verb|::FFFF:127.0.0.1/128| +\item \verb|{10, 11, 12, 13}| is the IPv4 address \verb|10.11.12.13| +\item \verb|{0, 0, 0, 0, 0, 65535, 32512, 1}| is the IPv6 address \verb|::FFFF:127.0.0.1/128| +\item \verb|{16#fdca, 16#8ab6, 16#a243, 16#75ef, 0, 0, 0, 1}| is the IPv6 address \verb|FDCA:8AB6:A243:75EF::1/128| +\end{itemize} + + +\makesubsubsection{listened-module}{Listening Module} + \ind{modules!ejabberd\_c2s}\ind{modules!ejabberd\_s2s\_in}\ind{modules!ejabberd\_service}\ind{modules!ejabberd\_http}\ind{protocols!XEP-0114: Jabber Component Protocol} The available modules, their purpose and the options allowed by each one are: \begin{description} \titem{\texttt{ejabberd\_c2s}} Handles c2s connections.\\ - Options: \texttt{access}, \texttt{certfile}, \texttt{inet6}, - \texttt{ip}, \texttt{max\_stanza\_size}, \texttt{shaper}, + Options: \texttt{access}, \texttt{certfile}, + \texttt{max\_stanza\_size}, \texttt{shaper}, \texttt{starttls}, \texttt{starttls\_required}, \texttt{tls}, \texttt{zlib} \titem{\texttt{ejabberd\_s2s\_in}} Handles incoming s2s connections.\\ - Options: \texttt{inet6}, \texttt{ip}, \texttt{max\_stanza\_size} + Options: \texttt{max\_stanza\_size} \titem{\texttt{ejabberd\_service}} Interacts with an \footahref{http://www.ejabberd.im/tutorials-transports}{external component} (as defined in the Jabber Component Protocol (\xepref{0114}).\\ - Options: \texttt{access}, \texttt{hosts}, \texttt{inet6}, - \texttt{ip}, \texttt{shaper}, \texttt{service\_check\_from} + Options: \texttt{access}, \texttt{hosts}, + \texttt{shaper}, \texttt{service\_check\_from} \titem{\texttt{ejabberd\_http}} Handles incoming HTTP connections.\\ Options: \texttt{certfile}, \texttt{http\_bind}, \texttt{http\_poll}, - \texttt{inet6}, \texttt{ip}, \texttt{request\_handlers}, \texttt{tls}, \texttt{web\_admin}\\ + \texttt{request\_handlers}, \texttt{tls}, \texttt{web\_admin}\\ \end{description} + +\makesubsubsection{listened-options}{Options} + This is a detailed description of each option allowed by the listening modules: \begin{description} \titem{\{access, \}} \ind{options!access}This option defines @@ -808,13 +854,7 @@ This is a detailed description of each option allowed by the listening modules: is also needed in the \Jabber{} client. Remark also that HTTP Polling can be interesting to host a web-based \Jabber{} client such as \footahref{http://jwchat.sourceforge.net/}{JWChat}. - \titem{inet6} \ind{options!inet6}\ind{IPv6}Set up the socket for IPv6 instead of IPv4. - Note: this option is not required for S2S outgoing connections, - because when ejabberd attempts to establish a S2S outgoing connection - it first tries IPv4, and if that fails it attempts with IPv6. - \titem{\{ip, IPAddress\}} \ind{options!ip}This option specifies which network - interface to listen for. For example \verb|{ip, {192, 168, 1, 1}}|. - \titem{\{max\_stanza\_size, Size\}} + \titem{\{max\_stanza\_size, Size\}} \ind{options!max\_stanza\_size}This option specifies an approximate maximum size in bytes of XML stanzas. Approximate, because it is calculated with the precision of one block of readed @@ -861,7 +901,7 @@ This is a detailed description of each option allowed by the listening modules: option will not affect connections (there will be no stream compression). \end{description} -There are some additional global options: +There are some additional global options that can be specified in the ejabberd configuration file (outside \term{listen}): \begin{description} \titem{\{s2s\_use\_starttls, true|false\}} \ind{options!s2s\_use\_starttls}\ind{STARTTLS}This option defines whether to @@ -886,6 +926,8 @@ There are some additional global options: Specified in seconds. The default value is 300 seconds (5 minutes). \end{description} +\makesubsubsection{listened-examples}{Examples} + For example, the following simple configuration defines: \begin{itemize} \item There are three domains. The default certificate file is \term{server.pem}. @@ -893,10 +935,10 @@ However, the c2s and s2s connections to the domain \term{example.com} use the fi \item Port 5222 listens for c2s connections with STARTTLS, and also allows plain connections for old clients. \item Port 5223 listens for c2s connections with the old SSL. -\item Port 5269 listens for s2s connections with STARTTLS. +\item Port 5269 listens for s2s connections with STARTTLS. The socket is set for IPv6 instead of IPv4. \item Port 5280 listens for HTTP requests, and serves the HTTP Poll service. \item Port 5281 listens for HTTP requests, and serves the Web Admin using HTTPS as explained in - section~\ref{webadmin}. + section~\ref{webadmin}. The socket only listens connections to the IP address 127.0.0.1. \end{itemize} \begin{verbatim} {hosts, ["example.com", "example.org", "example.net"]}. @@ -914,17 +956,17 @@ However, the c2s and s2s connections to the domain \term{example.com} use the fi tls, {certfile, "/etc/ejabberd/server.pem"}, {max_stanza_size, 65536} ]}, - {5269, ejabberd_s2s_in, [ - {shaper, s2s_shaper}, - {max_stanza_size, 131072} - ]}, + {{5269, "::"}, ejabberd_s2s_in, [ + {shaper, s2s_shaper}, + {max_stanza_size, 131072} + ]}, {5280, ejabberd_http, [ http_poll ]}, - {5281, ejabberd_http, [ - web_admin, - tls, {certfile, "/etc/ejabberd/server.pem"}, - ]} + {{5281, "127.0.0.1"}, ejabberd_http, [ + web_admin, + tls, {certfile, "/etc/ejabberd/server.pem"}, + ]} ] }. {s2s_use_starttls, true}. @@ -934,21 +976,23 @@ However, the c2s and s2s connections to the domain \term{example.com} use the fi In this example, the following configuration defines that: \begin{itemize} -\item c2s connections are listened for on port 5222 and 5223 (SSL) and denied +\item c2s connections are listened for on port 5222 (all IPv4 addresses) and + on port 5223 (SSL, IP 192.168.0.1 and fdca:8ab6:a243:75ef::1) and denied for the user called `\term{bad}'. -\item s2s connections are listened for on port 5269 with STARTTLS for secured - traffic enabled. +\item s2s connections are listened for on port 5269 (all IPv4 addresses) + with STARTTLS for secured traffic enabled. Incoming and outgoing connections of remote Jabber servers are denied, only two servers can connect: "jabber.example.org" and "example.com". -\item Port 5280 is serving the Web Admin and the HTTP Polling service. Note +\item Port 5280 is serving the Web Admin and the HTTP Polling service + in all the IPv4 addresses. Note that it is also possible to serve them on different ports. The second example in section~\ref{webadmin} shows how exactly this can be done. -\item All users except for the administrators have a traffic of limit +\item All users except for the administrators have a traffic of limit 1,000\,Bytes/second \item \ind{transports!AIM}The \footahref{http://www.ejabberd.im/pyaimt}{AIM transport} - \jid{aim.example.org} is connected to port 5233 with password - `\term{aimsecret}'. + \jid{aim.example.org} is connected to port 5233 on localhost IP addresses + (127.0.0.1 and ::1) with password `\term{aimsecret}'. \item \ind{transports!ICQ}The ICQ transport JIT (\jid{icq.example.org} and \jid{sms.example.org}) is connected to port 5234 with password `\term{jitsecret}'. @@ -976,13 +1020,32 @@ In this example, the following configuration defines that: {access, c2s_shaper, [{none, admin}, {normal, all}]}. {listen, - [{5222, ejabberd_c2s, [{access, c2s}, {shaper, c2s_shaper}]}, - {5223, ejabberd_c2s, [{access, c2s}, - ssl, {certfile, "/path/to/ssl.pem"}]}, - {5269, ejabberd_s2s_in, []}, - {5280, ejabberd_http, [http_poll, web_admin]}, - {5233, ejabberd_service, [{hosts, ["aim.example.org"], - [{password, "aimsecret"}]}]}, + [{5222, ejabberd_c2s, [ + {access, c2s}, + {shaper, c2s_shaper} + ]}, + {{5223, {192, 168, 0, 1}}, ejabberd_c2s, [ + {access, c2s}, + ssl, {certfile, "/path/to/ssl.pem"} + ]}, + {{5223, {16#fdca, 16#8ab6, 16#a243, 16#75ef, 0, 0, 0, 1}}, + ejabberd_c2s, [ + {access, c2s}, + ssl, {certfile, "/path/to/ssl.pem"} + ]}, + {5269, ejabberd_s2s_in, []}, + {{5280, {0, 0, 0, 0}}, ejabberd_http, [ + http_poll, + web_admin + ]}, + {{5233, {127, 0, 0, 1}}, ejabberd_service, [ + {hosts, ["aim.example.org"], + [{password, "aimsecret"}]} + ]}, + {{5233, "::1"}, ejabberd_service, [ + {hosts, ["aim.example.org"], + [{password, "aimsecret"}]} + ]}, {5234, ejabberd_service, [{hosts, ["icq.example.org", "sms.example.org"], [{password, "jitsecret"}]}]}, {5235, ejabberd_service, [{hosts, ["msn.example.org"], @@ -1004,8 +1067,8 @@ In this example, the following configuration defines that: {{s2s_host,"jabber.example.org"}, allow}. {{s2s_host,"example.com"}, allow}. \end{verbatim} -Note, that for \ind{jabberd 1.4}jabberd 1.4- or \ind{WPJabber}WPJabber-based -services you have to make the transports log and do \ind{XDB}XDB by themselves: +Note, that for services based in \ind{jabberd14}jabberd14 or \ind{WPJabber}WPJabber +you have to make the transports log and do \ind{XDB}XDB by themselves: \begin{verbatim} + /usr/lib/jabber/xdb_file.so @@ -3940,7 +4003,7 @@ Examples: \item For security reasons, you can serve the Web Admin on a secured connection, on a port differing from the HTTP Polling interface, and bind it to the internal LAN IP. The Web Admin will be accessible by pointing your - web browser to \verb|https://192.168.1.1:5280/admin/|: + web browser to \verb|https://192.168.1.1:5282/admin/|: \begin{verbatim} {hosts, ["example.org"]}. @@ -3948,9 +4011,13 @@ Examples: {listen, [ ... - {5270, ejabberd_http, [http_poll]}, - {5280, ejabberd_http, [web_admin, {ip, {192, 168, 1, 1}}, - tls, {certfile, "/usr/local/etc/server.pem"}]}, + {5280, ejabberd_http, [ + http_poll + ]}, + {{5282, "192.168.1.1"}, ejabberd_http, [ + web_admin, + tls, {certfile, "/usr/local/etc/server.pem"} + ]}, ... ]}. \end{verbatim} diff --git a/doc/release_notes_2.0.3.txt b/doc/release_notes_2.0.3.txt new file mode 100644 index 000000000..13fe9a174 --- /dev/null +++ b/doc/release_notes_2.0.3.txt @@ -0,0 +1,35 @@ + + Release Notes + ejabberd 2.0.3 + 14 January 2009 + + ejabberd 2.0.3 is the third bugfix release for ejabberd 2.0.x branch. + + ejabberd 2.0.3 includes several bugfixes and a few improvements. + A complete list of changes can be retrieved from: + http://redir.process-one.net/ejabberd-2.0.3 + + The new code can be downloaded from ejabberd download page: + http://www.process-one.net/en/ejabberd/ + + + Recent changes include: + +- Do not ask certificate for client (c2s) +- Check digest-uri in SASL digest authentication +- Use send timeout to avoid locking on gen_tcp:send +- Fix ejabberd reconnection to database +- HTTP-Bind: handle wrong order of packets +- MUC: Improve traffic regulation management +- PubSub: Several bugfixes and improvements for best coverage of XEP-0060 v1.12 +- Shared Roster Groups: push immediately membership changes +- Rotate also sasl.log on "reopen-log" command +- Binary Windows installer: better detect "Error running Post Install Script" + + + Bug reports + + You can officially report bugs on ProcessOne support site: + http://support.process-one.net/ + +END diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl index 98b1f4919..8caf6e5ff 100644 --- a/src/ejabberd_admin.erl +++ b/src/ejabberd_admin.erl @@ -96,11 +96,11 @@ commands() -> result = {users, {list, {username, string}}}}, #ejabberd_commands{name = import_file, tags = [mnesia], - desc = "Import user data from jabberd-1.4 spool file", + desc = "Import user data from jabberd14 spool file", module = ?MODULE, function = import_file, args = [{file, string}], result = {res, restuple}}, #ejabberd_commands{name = import_dir, tags = [mnesia], - desc = "Import user data from jabberd-1.4 spool dir", + desc = "Import user data from jabberd14 spool dir", module = ?MODULE, function = import_dir, args = [{file, string}], result = {res, restuple}}, @@ -215,7 +215,7 @@ import_file(Path) -> ok -> {ok, ""}; {error, Reason} -> - String = io_lib:format("Can't import jabberd 1.4 spool file ~p at node ~p: ~p", + String = io_lib:format("Can't import jabberd14 spool file ~p at node ~p: ~p", [filename:absname(Path), node(), Reason]), {cannot_import_file, String} end. @@ -225,7 +225,7 @@ import_dir(Path) -> ok -> {ok, ""}; {error, Reason} -> - String = io_lib:format("Can't import jabberd 1.4 spool dir ~p at node ~p: ~p", + String = io_lib:format("Can't import jabberd14 spool dir ~p at node ~p: ~p", [filename:absname(Path), node(), Reason]), {cannot_import_dir, String} end. diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 1e60065aa..b0a722733 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -758,7 +758,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> pres_t = ?SETS:from_list(Ts1), privacy_list = PrivList}); _ -> - ejabberd_hooks:run(forbidden_session_hook, + ejabberd_hooks:run(forbidden_session_hook, StateData#state.server, [JID]), ?INFO_MSG("(~w) Forbidden session for ~s", [StateData#state.socket, @@ -819,7 +819,8 @@ session_established({xmlstreamerror, _}, StateData) -> session_established(closed, StateData) -> {stop, normal, StateData}. - +%% Process packets sent by user (coming from user on c2s XMPP +%% connection) session_established2(El, StateData) -> try User = StateData#state.user, @@ -990,6 +991,7 @@ handle_info(replaced, _StateName, StateData) -> send_element(StateData, exmpp_stream:error('conflict')), send_element(StateData, exmpp_stream:closing()), {stop, normal, StateData#state{authenticated = replaced}}; +%% Process Packets that are to be send to the user handle_info({route, From, To, Packet}, StateName, StateData) -> {Pass, NewAttrs, NewState} = case Packet of @@ -1061,12 +1063,12 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> Els = Packet#xmlel.children, case exmpp_presence:get_type(Packet) of 'unavailable' -> - mod_caps:clear_caps(From); + mod_caps:clear_caps(From); _ -> - ServerString = binary_to_list(StateData#state.server), - Caps = mod_caps:read_caps(Els), - mod_caps:note_caps(ServerString, From, Caps) - end, + ServerString = binary_to_list(StateData#state.server), + Caps = mod_caps:read_caps(Els), + mod_caps:note_caps(ServerString, From, Caps) + end, case ?SETS:is_element( LFrom, StateData#state.pres_a) orelse ?SETS:is_element( @@ -1383,6 +1385,7 @@ process_presence_probe(From, To, StateData) -> end end. +%% User updates his presence (non-directed presence packet) presence_update(From, Packet, StateData) -> case exmpp_presence:get_type(Packet) of 'unavailable' -> @@ -1493,6 +1496,7 @@ presence_update(From, Packet, StateData) -> NewState end. +%% User sends a directed presence packet presence_track(From, To, Packet, StateData) -> LTo = jlib:short_prepd_jid(To), BFrom = exmpp_jid:jid_to_bare_jid(From), @@ -1884,7 +1888,7 @@ fsm_reply(Reply, StateName, StateData) -> %% Used by c2s blacklist plugins is_ip_blacklisted({IP,_Port}) -> - ejabberd_hooks:run_fold(check_bl_c2s, false, [IP]). + ejabberd_hooks:run_fold(check_bl_c2s, false, [IP]). %% Check from attributes %% returns invalid-from|NewElement diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index c933c1b2f..9b9af443f 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -325,8 +325,16 @@ process_term(Term, State) -> {host_config, Host, Terms} -> lists:foldl(fun(T, S) -> process_host_term(T, Host, S) end, State, Terms); - {listen, Val} -> - add_option(listen, Val, State); + {listen, Listeners} -> + Listeners2 = + lists:map( + fun({PortIP, Module, Opts}) -> + {Port, IPT, _, _, OptsClean} = + ejabberd_listener:parse_listener_portip(PortIP, Opts), + {{Port, IPT}, Module, OptsClean} + end, + Listeners), + add_option(listen, Listeners2, State); {language, Val} -> add_option(language, Val, State); {outgoing_s2s_port, Port} -> diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 93ae78a7c..cd5ca0898 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -32,6 +32,7 @@ start_listeners/0, start_listener/3, stop_listener/2, + parse_listener_portip/2, add_listener/3, delete_listener/2 ]). @@ -53,12 +54,25 @@ start_listeners() -> undefined -> ignore; Ls -> - lists:map( - fun({Port, Module, Opts}) -> - start_listener(Port, Module, Opts) - end, Ls) + Ls2 = lists:map( + fun({Port, Module, Opts}) -> + start_listener(Port, Module, Opts) + end, Ls), + report_duplicated_portips(Ls), + {ok, {{one_for_one, 10, 1}, Ls2}} end. +report_duplicated_portips(L) -> + LKeys = [Port || {Port, _, _} <- L], + LNoDupsKeys = proplists:get_keys(L), + case LKeys -- LNoDupsKeys of + [] -> ok; + Dups -> + ?CRITICAL_MSG("In the ejabberd configuration there are duplicated " + "Port number + IP address:~n ~p", + [Dups]) + end. + start(Port, Module, Opts) -> %% Check if the module is an ejabberd listener or an independent listener ModuleRaw = strip_frontend(Module), @@ -67,11 +81,11 @@ start(Port, Module, Opts) -> _ -> start_dependent(Port, Module, Opts) end. +%% -> {ok, Pid} | {error, ErrorMessage} start_dependent(Port, Module, Opts) -> case includes_deprecated_ssl_option(Opts) of false -> - {ok, proc_lib:spawn_link(?MODULE, init, - [Port, Module, Opts])}; + proc_lib:start_link(?MODULE, init, [Port, Module, Opts]); true -> SSLErr="There is a problem with your ejabberd configuration file: " "the option 'ssl' for listening sockets is no longer available." @@ -91,13 +105,16 @@ includes_deprecated_ssl_option(Opts) -> lists:member(ssl, Opts) end. -init(Port, Module, Opts) -> +init(PortIP, Module, Opts1) -> + {Port, IPT, IPS, IPV, OptsClean} = parse_listener_portip(PortIP, Opts1), + %% The first inet|inet6 and the last {ip, _} work, + %% so overriding those in Opts + Opts = [IPV | OptsClean] ++ [{ip, IPT}], SockOpts = lists:filter(fun({ip, _}) -> true; (inet6) -> true; (inet) -> true; (_) -> false end, Opts), - Res = gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}, @@ -108,13 +125,82 @@ init(Port, Module, Opts) -> SockOpts]), case Res of {ok, ListenSocket} -> + %% Inform my parent that this port was opened succesfully + proc_lib:init_ack({ok, self()}), + %% And now start accepting connection attempts accept(ListenSocket, Module, Opts); {error, Reason} -> - ?ERROR_MSG("Failed to open socket for ~p: ~p", - [{Port, Module, Opts}, Reason]), - error + ReasonT = case Reason of + eaddrnotavail -> "IP address not available: " ++ IPS; + _ -> atom_to_list(Reason) + end, + ?ERROR_MSG("Failed to open socket:~n ~p~nReason: ~s", + [{Port, Module, SockOpts}, ReasonT]), + throw(ReasonT) end. +%% @spec (PortIP, Opts) -> {Port, IPT, IPS, IPV, OptsClean} +%% where +%% PortIP = Port | {Port, IPT | IPS} +%% Port = integer() +%% IPT = tuple() +%% IPS = string() +%% IPV = inet | inet6 +%% Opts = [IPV | {ip, IPT} | atom() | tuple()] +%% OptsClean = [atom() | tuple()] +%% @doc Parse any kind of ejabberd listener specification. +%% The parsed options are returned in several formats. +%% OptsClean does not include inet/inet6 or ip options. +%% Opts can include the options inet6 and {ip, Tuple}, +%% but they are only used when no IP address was specified in the PortIP. +%% The IP version (either IPv4 or IPv6) is inferred from the IP address type, +%% so the option inet/inet6 is only used when no IP is specified at all. +parse_listener_portip(PortIP, Opts) -> + {IPOpt, Opts2} = strip_ip_option(Opts), + {IPVOpt, OptsClean} = case lists:member(inet6, Opts2) of + true -> {inet6, Opts2 -- [inet6]}; + false -> {inet, Opts2} + end, + {Port, IPT, IPS} = case PortIP of + P when is_integer(P) -> + T = get_ip_tuple(IPOpt, IPVOpt), + S = inet_parse:ntoa(T), + {P, T, S}; + {P, T} when is_integer(P) and is_tuple(T) -> + S = inet_parse:ntoa(T), + {P, T, S}; + {P, S} when is_integer(P) and is_list(S) -> + [S | _] = string:tokens(S, "/"), + {ok, T} = inet_parse:address(S), + {P, T, S} + end, + IPV = case size(IPT) of + 4 -> inet; + 8 -> inet6 + end, + {Port, IPT, IPS, IPV, OptsClean}. + +strip_ip_option(Opts) -> + {IPL, OptsNoIP} = lists:partition( + fun({ip, _}) -> true; + (_) -> false + end, + Opts), + case IPL of + %% Only the first ip option is considered + [{ip, T1} | _] when is_tuple(T1) -> + {T1, OptsNoIP}; + [] -> + {no_ip_option, OptsNoIP} + end. + +get_ip_tuple(no_ip_option, inet) -> + {0, 0, 0, 0}; +get_ip_tuple(no_ip_option, inet6) -> + {0, 0, 0, 0, 0, 0, 0, 0}; +get_ip_tuple(IPOpt, _IPVOpt) -> + IPOpt. + accept(ListenSocket, Module, Opts) -> case gen_tcp:accept(ListenSocket) of {ok, Socket} -> @@ -137,11 +223,14 @@ accept(ListenSocket, Module, Opts) -> accept(ListenSocket, Module, Opts) end. +%% @spec (Port, Module, Opts) -> {ok, Pid} | {error, Error} start_listener(Port, Module, Opts) -> + %% It is only required to start the supervisor in some cases. + %% But it doesn't hurt to attempt to start it for any listener. + %% So, it's normal (and harmless) that in most cases this call returns: {error, {already_started, pid()}} start_module_sup(Port, Module), start_listener_sup(Port, Module, Opts). -%% Only required for some listeners, but doing for all doesn't hurt start_module_sup(_Port, Module) -> Proc1 = gen_mod:get_module_proc("sup", Module), ChildSpec1 = @@ -151,7 +240,7 @@ start_module_sup(_Port, Module) -> infinity, supervisor, [ejabberd_tmp_sup]}, - catch supervisor:start_child(ejabberd_sup, ChildSpec1). + supervisor:start_child(ejabberd_sup, ChildSpec1). start_listener_sup(Port, Module, Opts) -> ChildSpec = {Port, @@ -165,33 +254,55 @@ start_listener_sup(Port, Module, Opts) -> stop_listener(Port, Module) -> supervisor:terminate_child(ejabberd_listeners, Port), supervisor:delete_child(ejabberd_listeners, Port), - Proc1 = gen_mod:get_module_proc("sup", Module), supervisor:terminate_child(ejabberd_sup, Proc1), supervisor:delete_child(ejabberd_sup, Proc1). -add_listener(Port, Module, Opts) -> +%% @spec (PortIP, Module, Opts) -> {ok, Pid} | {error, Error} +%% where +%% PortIP = {Port, IPT | IPS} +%% Port = integer() +%% IPT = tuple() +%% IPS = string() +%% IPV = inet | inet6 +%% Module = atom() +%% Opts = [IPV | {ip, IPT} | atom() | tuple()] +%% @doc Add a listener and store in config if success +add_listener(PortIP, Module, Opts) -> + case start_listener(PortIP, Module, Opts) of + {ok, _Pid} -> + Ports = case ejabberd_config:get_local_option(listen) of + undefined -> + []; + Ls -> + Ls + end, + Ports1 = lists:keydelete(PortIP, 1, Ports), + Ports2 = [{PortIP, Module, Opts} | Ports1], + ejabberd_config:add_local_option(listen, Ports2), + ok; + {error, {already_started, _Pid}} -> + {error, {already_started, PortIP}}; + {error, Error} -> + {error, Error} + end. + +%% @spec (PortIP) -> ok +%% where +%% PortIP = {Port, IPT | IPS} +%% Port = integer() +%% IPT = tuple() +%% IPS = string() +delete_listener(PortIP, Module) -> Ports = case ejabberd_config:get_local_option(listen) of undefined -> []; Ls -> Ls end, - Ports1 = lists:keydelete(Port, 1, Ports), - Ports2 = [{Port, Module, Opts} | Ports1], - ejabberd_config:add_local_option(listen, Ports2), - start_listener(Port, Module, Opts). - -delete_listener(Port, Module) -> - Ports = case ejabberd_config:get_local_option(listen) of - undefined -> - []; - Ls -> - Ls - end, - Ports1 = lists:keydelete(Port, 1, Ports), + Ports1 = lists:keydelete(PortIP, 1, Ports), ejabberd_config:add_local_option(listen, Ports1), - stop_listener(Port, Module). + stop_listener(PortIP, Module). is_frontend({frontend, _Module}) -> true; is_frontend(_) -> false. diff --git a/src/jd2ejd.erl b/src/jd2ejd.erl index 75963e5cc..86a6df3d6 100644 --- a/src/jd2ejd.erl +++ b/src/jd2ejd.erl @@ -1,7 +1,7 @@ %%%---------------------------------------------------------------------- %%% File : jd2ejd.erl %%% Author : Alexey Shchepin -%%% Purpose : Import of jabberd1.4 user spool file +%%% Purpose : Import of jabberd14 user spool file %%% Created : 2 Feb 2003 by Alexey Shchepin %%% %%% diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 3335d9c6e..a382a0920 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -559,7 +559,7 @@ get_local_items({global, _Host}, ["running nodes", ENode], Server, Lang) -> [?NODE("Database", <<"running nodes/", ENodeB/binary, "/DB">>), ?NODE("Modules", <<"running nodes/", ENodeB/binary, "/modules">>), ?NODE("Backup Management", <<"running nodes/", ENodeB/binary, "/backup">>), - ?NODE("Import Users From jabberd 1.4 Spool Files", + ?NODE("Import Users From jabberd14 Spool Files", <<"running nodes/", ENodeB/binary, "/import">>), ?NODE("Restart Service", <<"running nodes/", ENodeB/binary, "/restart">>), ?NODE("Shut Down Service", <<"running nodes/", ENodeB/binary, "/shutdown">>) @@ -1009,7 +1009,7 @@ get_form(_Host, ["running nodes", ENode, "import", "file"], Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = [#xmlcdata{cdata = list_to_binary(?T( - Lang, "Enter path to jabberd1.4 spool file"))}]}, + Lang, "Enter path to jabberd14 spool file"))}]}, ?XFIELD(<<"text-single">>, "Path to File", <<"path">>, <<"">>) ]}]}; @@ -1023,7 +1023,7 @@ get_form(_Host, ["running nodes", ENode, "import", "dir"], Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = [#xmlcdata{cdata = list_to_binary(?T( - Lang, "Enter path to jabberd1.4 spool dir"))}]}, + Lang, "Enter path to jabberd14 spool dir"))}]}, ?XFIELD(<<"text-single">>, "Path to Dir", <<"path">>, <<"">>) ]}]}; diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index df515c5c4..e05fc53ce 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -2235,7 +2235,7 @@ find_changed_items(UJID, UAffiliation, URole, ErrText = io_lib:format( translate:translate( Lang, - "JID ~s is invalid"), [S]), + "Jabber ID ~s is invalid"), [S]), {error, ?ERR(Item, 'not-acceptable', Lang, ErrText)} end; _ -> @@ -2789,7 +2789,7 @@ get_config(Lang, StateData, From) -> #xmlel{name = 'field', attrs = [ #xmlattr{name = 'type', value = "list-single"}, #xmlattr{name = 'label', - value = translate:translate(Lang, "Present real JIDs to")}, + value = translate:translate(Lang, "Present real Jabber IDs to")}, #xmlattr{name = 'var', value = "muc#roomconfig_whois"}], children = [#xmlel{name = 'value', children = [#xmlcdata{cdata = diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 6d9fbcdb1..ecd5185b1 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -584,7 +584,7 @@ user_queue(User, Server, Query, Lang) -> [?XC("h1", io_lib:format(?T("~s's Offline Messages Queue"), [us_to_list(US)]))] ++ case Res of - ok -> [?CT("Submitted"), ?P]; + ok -> [?XREST("Submitted")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index 849f3546c..15d7f2545 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -367,7 +367,7 @@ user_queue(User, Server, Query, Lang) -> [?XC("h1", io_lib:format(?T("~s's Offline Messages Queue"), [us_to_list(US)]))] ++ case Res of - ok -> [?CT("Submitted"), ?P]; + ok -> [?XREST("Submitted")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 51234e148..ddfc5b608 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -413,7 +413,12 @@ parse_items(Els) -> parse_items(Els, []). parse_items([], Res) -> - lists:reverse(Res); + %% Sort the items by their 'order' attribute + %% 5 is the position of 'order' attribute in a #listitem tuple + %% This integer can be calculated at runtime with: + %% 2 + length(lists:takewhile(fun(E) -> E =/= order end, + %% record_info(fields, listitem))), + lists:keysort(5, Res); parse_items([El = #xmlel{name = item} | Els], Res) -> Type = exmpp_xml:get_attribute(El, type, false), Value = exmpp_xml:get_attribute(El, value, false), diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 7ad8323a0..7cf9aba96 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -414,7 +414,12 @@ parse_items(Els) -> parse_items(Els, []). parse_items([], Res) -> - lists:reverse(Res); + %% Sort the items by their 'order' attribute + %% 5 is the position of 'order' attribute in a #listitem tuple + %% This integer can be calculated at runtime with: + %% 2 + length(lists:takewhile(fun(E) -> E =/= order end, + %% record_info(fields, listitem))), + lists:keysort(5, Res); parse_items([El = #xmlel{name = item} | Els], Res) -> Type = exmpp_xml:get_attribute(El, type, false), Value = exmpp_xml:get_attribute(El, value, false), diff --git a/src/mod_proxy65/mod_proxy65_service.erl b/src/mod_proxy65/mod_proxy65_service.erl index 3acc70b0a..654873853 100644 --- a/src/mod_proxy65/mod_proxy65_service.erl +++ b/src/mod_proxy65/mod_proxy65_service.erl @@ -53,6 +53,7 @@ name, stream_addr, port, + ip, acl }). @@ -66,7 +67,7 @@ start_link(Host, Opts) -> gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []). init([Host, Opts]) -> - {_IP, State} = parse_options(Host, Opts), + State = parse_options(Host, Opts), ejabberd_router:register_route(State#state.myhost), {ok, State}. @@ -91,8 +92,8 @@ handle_info({route, From, To, Packet}, State) when ?IS_IQ(Packet) -> handle_info(_Info, State) -> {noreply, State}. -handle_call(get_port, _From, State) -> - {reply, {port, State#state.port}, State}; +handle_call(get_port_ip, _From, State) -> + {reply, {port_ip, State#state.port, State#state.ip}, State}; handle_call(_Request, _From, State) -> {reply, ok, State}. @@ -107,14 +108,14 @@ code_change(_OldVsn, State, _Extra) -> %%%------------------------ add_listener(Host, Opts) -> - {IP, State} = parse_options(Host, Opts), - NewOpts = [Host, {ip, IP} | Opts], - ejabberd_listener:add_listener(State#state.port,mod_proxy65_stream,NewOpts). + State = parse_options(Host, Opts), + NewOpts = [Host | Opts], + ejabberd_listener:add_listener({State#state.port, State#state.ip}, mod_proxy65_stream, NewOpts). delete_listener(Host) -> Proc = gen_mod:get_module_proc(Host, ?PROCNAME), - {port, Port} = gen_server:call(Proc, get_port), - catch ejabberd_listener:delete_listener(Port, mod_proxy65_stream). + {port_ip, Port, IP} = gen_server:call(Proc, get_port_ip), + catch ejabberd_listener:delete_listener({Port, IP}, mod_proxy65_stream). %%%------------------------ %%% IQ Processing @@ -227,12 +228,13 @@ parse_options(ServerHost, Opts) -> end, StrIP = inet_parse:ntoa(IP), StreamAddr = [#xmlattr{name = 'jid', value = MyHost}, #xmlattr{name = 'host', value = StrIP}, #xmlattr{name = 'port', value = integer_to_list(Port)}], - {IP, #state{myhost = MyHost, + #state{myhost = MyHost, serverhost = ServerHost, name = Name, port = Port, + ip = IP, stream_addr = StreamAddr, - acl = ACL}}. + acl = ACL}. %% Return the IP of the proxy host, or if not found, the ip of the xmpp domain get_proxy_or_domainip(ServerHost, MyHost) -> diff --git a/src/mod_proxy65/mod_proxy65_stream.erl b/src/mod_proxy65/mod_proxy65_stream.erl index fbbe68380..045965439 100644 --- a/src/mod_proxy65/mod_proxy65_stream.erl +++ b/src/mod_proxy65/mod_proxy65_stream.erl @@ -78,7 +78,8 @@ code_change(_OldVsn, StateName, StateData, _Extra) -> {ok, StateName, StateData}. %%------------------------------- -start({gen_tcp, Socket}, [Host | Opts]) -> +start({gen_tcp, Socket}, Opts1) -> + {[Host], Opts} = lists:partition(fun(O) -> is_list(O) end, Opts1), Supervisor = gen_mod:get_module_proc(Host, ejabberd_mod_proxy65_sup), supervisor:start_child(Supervisor, [Socket, Host, Opts]). diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index f4b7200b4..ce9f9b7ae 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -1029,7 +1029,7 @@ send_authorization_request(Host, Node, Subscriber) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'var', value = "pubsub#allow"}, #xmlattr{name = 'type', value = "boolean"}, - #xmlattr{name = 'label', value = translate:translate(Lang, "Allow this JID to subscribe to this pubsub node?")}], children = + #xmlattr{name = 'label', value = translate:translate(Lang, "Allow this Jabber ID to subscribe to this pubsub node?")}], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"false">>}]}]}]}]}, case tree_action(Host, get_node, [Host, Node, Subscriber]) of #pubsub_node{owners = Owners} -> diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 00a3ffa5c..b63642b8b 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -912,8 +912,8 @@ user_roster(User, Server, Query, Lang) -> end, [?XC("h1", ?T("Roster of ") ++ us_to_list(US))] ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index ee7718224..4ea9de82d 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -951,8 +951,8 @@ user_roster(User, Server, Query, Lang) -> end, [?XC("h1", ?T("Roster of ") ++ us_to_list(US))] ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index ee41de61f..2f37a5001 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -742,8 +742,8 @@ list_shared_roster_groups(Host, Query, Lang) -> )]), ?H1GL(?T("Shared Roster Groups"), "modsharedroster", "mod_shared_roster") ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], @@ -806,8 +806,9 @@ shared_roster_group(Host, Group, Query, Lang) -> [] end ++ [[us_to_list(Member), $\n] || Member <- Members], FDisplayedGroups = [[DG, $\n] || DG <- DisplayedGroups], + DescNL = length(element(2, regexp:split(Description, "\n"))), FGroup = - ?XAE("table", [], + ?XAE("table", [{"class", "withtextareas"}], [?XE("tbody", [?XE("tr", [?XCT("td", "Name:"), @@ -816,34 +817,34 @@ shared_roster_group(Host, Group, Query, Lang) -> ), ?XE("tr", [?XCT("td", "Description:"), - ?XE("td", [?XAC("textarea", [{"name", "description"}, - {"rows", "3"}, - {"cols", "20"}], - Description)]) + ?XE("td", [ + ?TEXTAREA("description", integer_to_list(lists:max([3, DescNL])), "20", Description) + ] + ) ] ), ?XE("tr", [?XCT("td", "Members:"), - ?XE("td", [?XAC("textarea", [{"name", "members"}, - {"rows", "3"}, - {"cols", "20"}], - FMembers)]) + ?XE("td", [ + ?TEXTAREA("members", integer_to_list(lists:max([3, length(FMembers)])), "20", FMembers) + ] + ) ] ), ?XE("tr", [?XCT("td", "Displayed Groups:"), - ?XE("td", [?XAC("textarea", [{"name", "dispgroups"}, - {"rows", "3"}, - {"cols", "20"}], - FDisplayedGroups)]) + ?XE("td", [ + ?TEXTAREA("dispgroups", integer_to_list(lists:max([3, length(FDisplayedGroups)])), "20", FDisplayedGroups) + ] + ) ] )] )]), ?H1GL(?T("Shared Roster Groups"), "modsharedroster", "mod_shared_roster") ++ [?XC("h2", ?T("Group ") ++ Group)] ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], diff --git a/src/mod_stats.erl b/src/mod_stats.erl index 8282b94b0..a3430f437 100644 --- a/src/mod_stats.erl +++ b/src/mod_stats.erl @@ -94,7 +94,7 @@ get_local_stats(_Server, ["running nodes", _], []) -> [?STAT(<<"time/uptime">>), ?STAT(<<"time/cputime">>), ?STAT(<<"users/online">>), - ?STAT(<<"transactions/commited">>), + ?STAT(<<"transactions/committed">>), ?STAT(<<"transactions/aborted">>), ?STAT(<<"transactions/restarted">>), ?STAT(<<"transactions/logged">>) @@ -193,7 +193,7 @@ get_node_stat(Node, Name) when Name == <<"users/online">> -> ?STATVAL(list_to_binary(integer_to_list(length(Users))), <<"users">>) end; -get_node_stat(Node, Name) when Name == <<"transactions/commited">> -> +get_node_stat(Node, Name) when Name == <<"transactions/committed">> -> case catch rpc:call(Node, mnesia, system_info, [transaction_commits]) of {badrpc, _Reason} -> ?STATERR(<<"500">>, <<"Internal Server Error">>); diff --git a/src/msgs/ca.msg b/src/msgs/ca.msg index b4abbcb44..f227aa851 100644 --- a/src/msgs/ca.msg +++ b/src/msgs/ca.msg @@ -14,7 +14,7 @@ {"Administrator privileges required","Es necessita tenir privilegis d'administrador"}. {"A friendly name for the node","Un nom per al node"}. {"All activity","Tota l'activitat"}. -{"Allow this JID to subscribe to this pubsub node?","Permetre que aquesta JID es puga subscriure a aquest node pubsub"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Permetre que aquesta JID es puga subscriure a aquest node pubsub"}. {"Allow users to change subject","Permetre que els usuaris canvien el tema"}. {"Allow users to query other users","Permetre que els usuaris fagen peticions a altres usuaris"}. {"Allow users to send invites","Permetre que els usuaris envien invitacions"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","Introdueix llista de {mòdul, [opcions]}"}. {"Enter nickname you want to register","Introdueix el nickname que vols registrar"}. {"Enter path to backup file","Introdueix ruta al fitxer de còpia de seguretat"}. -{"Enter path to jabberd1.4 spool dir","Introdueix la ruta al directori de jabberd1.4 spools"}. -{"Enter path to jabberd1.4 spool file","Introdueix ruta al fitxer jabberd1.4 spool"}. +{"Enter path to jabberd14 spool dir","Introdueix la ruta al directori de jabberd14 spools"}. +{"Enter path to jabberd14 spool file","Introdueix ruta al fitxer jabberd14 spool"}. {"Enter path to text file","Introdueix ruta al fitxer de text"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Introdueix el nom d'usuari i les codificacions de caràcters per a utilitzar als servidors de IRC"}. {"Erlang Jabber Server","Servidor Erlang Jabber"}. @@ -113,7 +113,7 @@ {"Import File","Importar fitxer"}. {"Import User from File at ","Importa usuari des de fitxer en "}. {"Import Users from Dir at ","Importar usuaris des del directori en "}. -{"Import Users From jabberd 1.4 Spool Files","Importar usuaris de jabberd 1.4"}. +{"Import Users From jabberd14 Spool Files","Importar usuaris de jabberd14"}. {"Improper message type","Tipus de missatge incorrecte"}. {"Incorrect password","Password incorrecte"}. {"Invalid affiliation: ~s","Afiliació invàlida: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages to the conference","No està permés l'enviament de missatges privats a la sala"}. {"Jabber ID","ID Jabber"}. {"January","Gener"}. -{"JID ~s is invalid","El JID ~s no és vàlid"}. +{"Jabber ID ~s is invalid","El JID ~s no és vàlid"}. {"joins the room","Entrar a la sala"}. {"July","Juliol"}. {"June","Juny"}. @@ -219,7 +219,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","Port"}. -{"Present real JIDs to","Presentar JID's reals a"}. +{"Present real Jabber IDs to","Presentar JID's reals a"}. {"private, ","privat"}. {"Publish-Subscribe","Publicar-subscriure't"}. {"PubSub subscriber request","Petició de PubSub subscriure"}. @@ -307,7 +307,7 @@ {"To ~s","A ~s"}. {"Traffic rate limit is exceeded","El llímit de tràfic ha sigut sobrepassat"}. {"Transactions Aborted:","Transaccions Avortades"}. -{"Transactions Commited:","Transaccions Realitzades:"}. +{"Transactions Committed:","Transaccions Realitzades:"}. {"Transactions Logged:","Transaccions registrades"}. {"Transactions Restarted:","Transaccions reiniciades"}. {"Tuesday","Dimarts"}. diff --git a/src/msgs/ca.po b/src/msgs/ca.po index 63393dd2d..661a6085e 100644 --- a/src/msgs/ca.po +++ b/src/msgs/ca.po @@ -224,8 +224,8 @@ msgid "Backup Management" msgstr "Gestió de còpia de seguretat" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" -msgstr "Importar usuaris de jabberd 1.4" +msgid "Import Users From jabberd14 Spool Files" +msgstr "Importar usuaris de jabberd14" #: mod_configure.erl:649 msgid "To ~s" @@ -309,16 +309,16 @@ msgid "Import User from File at " msgstr "Importa usuari des de fitxer en " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Introdueix ruta al fitxer jabberd1.4 spool" +msgid "Enter path to jabberd14 spool file" +msgstr "Introdueix ruta al fitxer jabberd14 spool" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Importar usuaris des del directori en " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Introdueix la ruta al directori de jabberd1.4 spools" +msgid "Enter path to jabberd14 spool dir" +msgstr "Introdueix la ruta al directori de jabberd14 spools" #: mod_configure.erl:995 msgid "Path to Dir" @@ -757,8 +757,8 @@ msgid "Moderator privileges required" msgstr "Es necessita tenir privilegis de moderador" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "El JID ~s no és vàlid" +msgid "Jabber ID ~s is invalid" +msgstr "El Jabber ID ~s no és vàlid" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -810,8 +810,8 @@ msgid "No limit" msgstr "Sense Llímit" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "Presentar JID's reals a" +msgid "Present real Jabber IDs to" +msgstr "Presentar Jabber ID's reals a" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -953,8 +953,8 @@ msgid "Subscriber Address" msgstr "Adreça del Subscriptor" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "Permetre que aquesta JID es puga subscriure a aquest node pubsub" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "Permetre que aquesta Jabber ID es puga subscriure a aquest node pubsub" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1437,7 +1437,7 @@ msgid "CPU Time:" msgstr "Temps de CPU" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Transaccions Realitzades:" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/cs.msg b/src/msgs/cs.msg index 2e3be06e4..b78f67ecb 100644 --- a/src/msgs/cs.msg +++ b/src/msgs/cs.msg @@ -6,7 +6,7 @@ {"Access rules","Pravidla přístupů"}. {"Access Rules","Pravidla přístupů"}. {"Action on user","Akce aplikovaná na uživatele"}. -{"Add Jabber ID","Přidat JID"}. +{"Add Jabber ID","Přidat Jabber ID"}. {"Add New","Přidat nový"}. {"Add User","Přidat uživatele"}. {"Administration","Administrace"}. @@ -14,7 +14,7 @@ {"Administrator privileges required","Jsou potřebná práva administrátora"}. {"A friendly name for the node","Přívětivé jméno pro uzel"}. {"All activity","Všechny aktivity"}. -{"Allow this JID to subscribe to this pubsub node?","Povolit tomuto JID odebírat tento pubsub uzel?"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Povolit tomuto JID odebírat tento pubsub uzel?"}. {"Allow users to change subject","Povolit uživatelům měnit téma místnosti"}. {"Allow users to query other users","Povolit uživatelům odesílat požadavky (query) ostatním uživatelům"}. {"Allow users to send invites","Povolit uživatelům posílání pozvánek"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","Vložte seznam modulů {Modul, [Parametry]}"}. {"Enter nickname you want to register","Zadejte přezdívku, kterou chcete zaregistrovat"}. {"Enter path to backup file","Zadajte cestu k souboru se zálohou"}. -{"Enter path to jabberd1.4 spool dir","Zadejte cestu k jabberd1.4 spool adresáři"}. -{"Enter path to jabberd1.4 spool file","Zadejte cestu k spool souboru jabberd1.4"}. +{"Enter path to jabberd14 spool dir","Zadejte cestu k jabberd14 spool adresáři"}. +{"Enter path to jabberd14 spool file","Zadejte cestu k spool souboru jabberd14"}. {"Enter path to text file","Zadajte cestu k textovému souboru"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Vložte jméno uživatele a kódování, které chcete používat při připojení na IRC server"}. {"Erlang Jabber Server","Erlang Jabber Server"}. @@ -113,7 +113,7 @@ {"Import File","Import souboru"}. {"Import User from File at ","Importovat uživatele ze souboru na "}. {"Import Users from Dir at ","Importovat uživatele z adresáře na "}. -{"Import Users From jabberd 1.4 Spool Files","Importovat uživatele z jabberd 1.4 spool souborů"}. +{"Import Users From jabberd14 Spool Files","Importovat uživatele z jabberd14 spool souborů"}. {"Improper message type","Nesprávný typ zprávy"}. {"Incorrect password","Nesprávné heslo"}. {"Invalid affiliation: ~s","Neplatné přiřazení: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages to the conference","Není povoleno odesílat soukromé zprávy do konference"}. {"Jabber ID","Jabber ID"}. {"January",". ledna"}. -{"JID ~s is invalid","JID ~s je neplatné"}. +{"Jabber ID ~s is invalid","JID ~s je neplatné"}. {"joins the room","vstoupil(a) do místnosti"}. {"July",". července"}. {"June",". června"}. @@ -219,7 +219,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","Port"}. -{"Present real JIDs to","Odhalovat skutečná Jabber ID"}. +{"Present real Jabber IDs to","Odhalovat skutečná Jabber ID"}. {"private, ","soukromá, "}. {"Publish-Subscribe","Publish-Subscribe"}. {"PubSub subscriber request","Žádost odběratele PubSub"}. @@ -307,7 +307,7 @@ {"To ~s","Pro ~s"}. {"Traffic rate limit is exceeded","Byl překročen limit"}. {"Transactions Aborted:","Transakce zrušena"}. -{"Transactions Commited:","Transakce potvrzena"}. +{"Transactions Committed:","Transakce potvrzena"}. {"Transactions Logged:","Transakce zaznamenána"}. {"Transactions Restarted:","Transakce restartována"}. {"Tuesday","Úterý"}. diff --git a/src/msgs/cs.po b/src/msgs/cs.po index e02387e6e..7f1e857b2 100644 --- a/src/msgs/cs.po +++ b/src/msgs/cs.po @@ -224,8 +224,8 @@ msgid "Backup Management" msgstr "Správa zálohování" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" -msgstr "Importovat uživatele z jabberd 1.4 spool souborů" +msgid "Import Users From jabberd14 Spool Files" +msgstr "Importovat uživatele z jabberd14 spool souborů" #: mod_configure.erl:649 msgid "To ~s" @@ -309,16 +309,16 @@ msgid "Import User from File at " msgstr "Importovat uživatele ze souboru na " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Zadejte cestu k spool souboru jabberd1.4" +msgid "Enter path to jabberd14 spool file" +msgstr "Zadejte cestu k spool souboru jabberd14" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Importovat uživatele z adresáře na " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Zadejte cestu k jabberd1.4 spool adresáři" +msgid "Enter path to jabberd14 spool dir" +msgstr "Zadejte cestu k jabberd14 spool adresáři" #: mod_configure.erl:995 msgid "Path to Dir" @@ -749,8 +749,8 @@ msgid "Moderator privileges required" msgstr "Jsou potřebná práva moderátora" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "JID ~s je neplatné" +msgid "Jabber ID ~s is invalid" +msgstr "Jabber ID ~s je neplatné" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -802,7 +802,7 @@ msgid "No limit" msgstr "Bez limitu" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" +msgid "Present real Jabber IDs to" msgstr "Odhalovat skutečná Jabber ID" #: mod_muc/mod_muc_room.erl:2741 @@ -943,8 +943,8 @@ msgid "Subscriber Address" msgstr "Adresa odběratele" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "Povolit tomuto JID odebírat tento pubsub uzel?" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "Povolit tomuto Jabber ID odebírat tento pubsub uzel?" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1056,7 +1056,7 @@ msgstr "Nesprávný formát" #: mod_roster.erl:855 mod_roster_odbc.erl:962 msgid "Add Jabber ID" -msgstr "Přidat JID" +msgstr "Přidat Jabber ID" #: mod_roster.erl:936 mod_roster_odbc.erl:1043 msgid "Roster" @@ -1427,7 +1427,7 @@ msgid "CPU Time:" msgstr "Čas procesoru" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Transakce potvrzena" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/de.msg b/src/msgs/de.msg index 8e45f01ed..f85b405da 100644 --- a/src/msgs/de.msg +++ b/src/msgs/de.msg @@ -14,7 +14,7 @@ {"Administrator privileges required","Administratorenrechte benötigt"}. {"A friendly name for the node","Ein passender Name für den Knoten"}. {"All activity","Alle Aktivitäten"}. -{"Allow this JID to subscribe to this pubsub node?","Erlauben Sie dieser JID das Abonnement dieses pubsub Knotens?"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Erlauben Sie dieser JID das Abonnement dieses pubsub Knotens?"}. {"Allow users to change subject","Erlaube Benutzern das Thema zu ändern"}. {"Allow users to query other users","Erlaube Benutzern andere Benutzer abzufragen"}. {"Allow users to send invites","Erlaube Benutzern Einladungen zu senden"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","Geben Sie eine Liste bestehend aus {Modul, [Optionen]} ein"}. {"Enter nickname you want to register","Geben Sie den zu registrierenden Spitznamen ein"}. {"Enter path to backup file","Geben Sie den Pfad zur Datensicherung ein"}. -{"Enter path to jabberd1.4 spool dir","Geben Sie den Pfad zum jabberd1.4 spool Verzeichnis ein"}. -{"Enter path to jabberd1.4 spool file","Geben Sie den Pfad zur jabberd1.4 spool Datei ein"}. +{"Enter path to jabberd14 spool dir","Geben Sie den Pfad zum jabberd14 spool Verzeichnis ein"}. +{"Enter path to jabberd14 spool file","Geben Sie den Pfad zur jabberd14 spool Datei ein"}. {"Enter path to text file","Geben Sie den Pfad zur Textdatei ein"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Geben Sie Benutzernamen und Kodierung für die Verbindung zum IRC Server an"}. {"Erlang Jabber Server","Erlang Jabber Server"}. @@ -113,7 +113,7 @@ {"Import File","Datei importieren"}. {"Import User from File at ","Benutzer aus dieser Datei importieren "}. {"Import Users from Dir at ","Benutzer vom Verzeichnis importieren "}. -{"Import Users From jabberd 1.4 Spool Files","Importiere Benutzer von jabberd 1.4 Spool Dateien"}. +{"Import Users From jabberd14 Spool Files","Importiere Benutzer von jabberd14 Spool Dateien"}. {"Improper message type","Unzulässiger Nachrichtentyp"}. {"Incorrect password","Falsches Passwort"}. {"Invalid affiliation: ~s","Ungültige Mitgliedschaft: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages to the conference","Es ist nicht erlaubt private Nachrichten an den Raum zu schicken"}. {"Jabber ID","Jabber ID"}. {"January","Januar"}. -{"JID ~s is invalid","JID ~s ist ungültig"}. +{"Jabber ID ~s is invalid","JID ~s ist ungültig"}. {"joins the room","kommt in den Raum"}. {"July","Juli"}. {"June","Juni"}. @@ -219,7 +219,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","Port"}. -{"Present real JIDs to","Echte Jabber IDs anzeigen für"}. +{"Present real Jabber IDs to","Echte Jabber IDs anzeigen für"}. {"private, ","privat, "}. {"Publish-Subscribe","Publish-Subscribe"}. {"PubSub subscriber request","PubSub Abonnenten Anfrage"}. @@ -307,7 +307,7 @@ {"To","Zu"}. {"Traffic rate limit is exceeded","Datenrate ist zu hoch"}. {"Transactions Aborted:","Vorgänge abgebrochen:"}. -{"Transactions Commited:","Vorgänge durchgeführt:"}. +{"Transactions Committed:","Vorgänge durchgeführt:"}. {"Transactions Logged:","Vorgänge protokolliert:"}. {"Transactions Restarted:","Vorgänge neu gestartet:"}. {"Tuesday","Dienstag"}. diff --git a/src/msgs/de.po b/src/msgs/de.po index 6537c1dda..6b5dab270 100644 --- a/src/msgs/de.po +++ b/src/msgs/de.po @@ -230,8 +230,8 @@ msgid "Backup Management" msgstr "Datensicherungsmanagement" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" -msgstr "Importiere Benutzer von jabberd 1.4 Spool Dateien" +msgid "Import Users From jabberd14 Spool Files" +msgstr "Importiere Benutzer von jabberd14 Spool Dateien" #: mod_configure.erl:649 msgid "To ~s" @@ -315,16 +315,16 @@ msgid "Import User from File at " msgstr "Benutzer aus dieser Datei importieren " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Geben Sie den Pfad zur jabberd1.4 spool Datei ein" +msgid "Enter path to jabberd14 spool file" +msgstr "Geben Sie den Pfad zur jabberd14 spool Datei ein" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Benutzer vom Verzeichnis importieren " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Geben Sie den Pfad zum jabberd1.4 spool Verzeichnis ein" +msgid "Enter path to jabberd14 spool dir" +msgstr "Geben Sie den Pfad zum jabberd14 spool Verzeichnis ein" #: mod_configure.erl:995 msgid "Path to Dir" @@ -762,8 +762,8 @@ msgid "Moderator privileges required" msgstr "Moderatorrechte benötigt" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "JID ~s ist ungültig" +msgid "Jabber ID ~s is invalid" +msgstr "Jabber ID ~s ist ungültig" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -815,7 +815,7 @@ msgid "No limit" msgstr "keine Begrenzung" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" +msgid "Present real Jabber IDs to" msgstr "Echte Jabber IDs anzeigen für" #: mod_muc/mod_muc_room.erl:2741 @@ -959,8 +959,8 @@ msgid "Subscriber Address" msgstr "Abonnenten Adresse" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "Erlauben Sie dieser JID das Abonnement dieses pubsub Knotens?" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "Erlauben Sie dieser Jabber ID das Abonnement dieses pubsub Knotens?" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1444,7 +1444,7 @@ msgid "CPU Time:" msgstr "CPU Zeit:" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Vorgänge durchgeführt:" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/ejabberd.pot b/src/msgs/ejabberd.pot index 0f4a204cd..47c6da98b 100644 --- a/src/msgs/ejabberd.pot +++ b/src/msgs/ejabberd.pot @@ -223,7 +223,7 @@ msgid "Backup Management" msgstr "" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" +msgid "Import Users From jabberd14 Spool Files" msgstr "" #: mod_configure.erl:649 @@ -308,7 +308,7 @@ msgid "Import User from File at " msgstr "" #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" +msgid "Enter path to jabberd14 spool file" msgstr "" #: mod_configure.erl:990 @@ -316,7 +316,7 @@ msgid "Import Users from Dir at " msgstr "" #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" +msgid "Enter path to jabberd14 spool dir" msgstr "" #: mod_configure.erl:995 @@ -1407,7 +1407,7 @@ msgid "CPU Time:" msgstr "" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/eo.msg b/src/msgs/eo.msg index eee050c2f..f4806fd0d 100644 --- a/src/msgs/eo.msg +++ b/src/msgs/eo.msg @@ -14,7 +14,7 @@ {"Administrator privileges required","Administrantaj rajtoj bezonata"}. {"A friendly name for the node","Kromnomo por ĉi tiu nodo"}. {"All activity","Ĉiu aktiveco"}. -{"Allow this JID to subscribe to this pubsub node?","Ĉu permesi ĉi tiun JID aboni al la jena PubAbo-nodo"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Ĉu permesi ĉi tiun JID aboni al la jena PubAbo-nodo"}. {"Allow users to change subject","Permesu uzantojn ŝanĝi la temon"}. {"Allow users to query other users","Permesu uzantojn informpeti aliajn uzantojn"}. {"Allow users to send invites","Permesu uzantojn sendi invitojn"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","Enmetu liston de {Modulo, [Elektebloj]}"}. {"Enter nickname you want to register","Enmetu kaŝnomon kiun vi volas registri"}. {"Enter path to backup file","Enmetu vojon por sekurkopio"}. -{"Enter path to jabberd1.4 spool dir","Enmetu vojon al jabberd1.4-uzantdosierujo"}. -{"Enter path to jabberd1.4 spool file","Enmetu vojon al jabberd1.4-uzantdosiero"}. +{"Enter path to jabberd14 spool dir","Enmetu vojon al jabberd14-uzantdosierujo"}. +{"Enter path to jabberd14 spool file","Enmetu vojon al jabberd14-uzantdosiero"}. {"Enter path to text file","Enmetu vojon al plata teksto"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Enmetu uzantnomon kaj enkodigoj kiujn vi volas uzi por konektoj al IRC-serviloj"}. {"Erlang Jabber Server","Erlang-a Jabber-Servilo"}. @@ -113,7 +113,7 @@ {"Import File","Importu dosieron"}. {"Import User from File at ","Importu uzanton de dosiero el "}. {"Import Users from Dir at ","Importu uzantojn de dosierujo ĉe "}. -{"Import Users From jabberd 1.4 Spool Files","Importu uzantojn de jabberd1.4-uzantdosieroj"}. +{"Import Users From jabberd14 Spool Files","Importu uzantojn de jabberd14-uzantdosieroj"}. {"Improper message type","Malĝusta mesaĝo-tipo"}. {"Incorrect password","Nekorekta pasvorto"}. {"Invalid affiliation: ~s","Nevalida aparteneco: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages to the conference","Nur partoprenantoj rajtas sendi privatajn mesaĝojn al la babilejo"}. {"Jabber ID","Jabber ID"}. {"January","Januaro"}. -{"JID ~s is invalid","JID ~s estas nevalida"}. +{"Jabber ID ~s is invalid","JID ~s estas nevalida"}. {"joins the room","eniras la babilejo"}. {"July","Julio"}. {"June","Junio"}. @@ -219,7 +219,7 @@ {"Ping","Sondaĵo"}. {"Pong","Resondaĵo"}. {"Port","Pordo"}. -{"Present real JIDs to","Montru verajn JID-ojn al"}. +{"Present real Jabber IDs to","Montru verajn JID-ojn al"}. {"private, ","privata, "}. {"Publish-Subscribe","Public-Abonado"}. {"PubSub subscriber request","PubAbo abonpeto"}. @@ -307,7 +307,7 @@ {"To ~s","Al ~s"}. {"Traffic rate limit is exceeded","Trafikrapida limigo superita"}. {"Transactions Aborted:","Transakcioj nuligitaj"}. -{"Transactions Commited:","Transakcioj enmetitaj"}. +{"Transactions Committed:","Transakcioj enmetitaj"}. {"Transactions Logged:","Transakcioj protokolitaj"}. {"Transactions Restarted:","Transakcioj restartitaj"}. {"Tuesday","Mardo"}. diff --git a/src/msgs/eo.po b/src/msgs/eo.po index 8b4d55693..9d4bf5b06 100644 --- a/src/msgs/eo.po +++ b/src/msgs/eo.po @@ -224,8 +224,8 @@ msgid "Backup Management" msgstr "Mastrumado de sekurkopioj" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" -msgstr "Importu uzantojn de jabberd1.4-uzantdosieroj" +msgid "Import Users From jabberd14 Spool Files" +msgstr "Importu uzantojn de jabberd14-uzantdosieroj" #: mod_configure.erl:649 msgid "To ~s" @@ -309,16 +309,16 @@ msgid "Import User from File at " msgstr "Importu uzanton de dosiero el " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Enmetu vojon al jabberd1.4-uzantdosiero" +msgid "Enter path to jabberd14 spool file" +msgstr "Enmetu vojon al jabberd14-uzantdosiero" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Importu uzantojn de dosierujo ĉe " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Enmetu vojon al jabberd1.4-uzantdosierujo" +msgid "Enter path to jabberd14 spool dir" +msgstr "Enmetu vojon al jabberd14-uzantdosierujo" #: mod_configure.erl:995 msgid "Path to Dir" @@ -752,8 +752,8 @@ msgid "Moderator privileges required" msgstr "Moderantaj rajtoj bezonata" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "JID ~s estas nevalida" +msgid "Jabber ID ~s is invalid" +msgstr "Jabber ID ~s estas nevalida" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -805,8 +805,8 @@ msgid "No limit" msgstr "Neniu limigo" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "Montru verajn JID-ojn al" +msgid "Present real Jabber IDs to" +msgstr "Montru verajn Jabber ID-ojn al" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -948,8 +948,8 @@ msgid "Subscriber Address" msgstr "Abonanta adreso" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "Ĉu permesi ĉi tiun JID aboni al la jena PubAbo-nodo" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "Ĉu permesi ĉi tiun Jabber ID aboni al la jena PubAbo-nodo" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1430,7 +1430,7 @@ msgid "CPU Time:" msgstr "CPU-tempo" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Transakcioj enmetitaj" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/es.msg b/src/msgs/es.msg index 1a30803f7..97cbcf35c 100644 --- a/src/msgs/es.msg +++ b/src/msgs/es.msg @@ -14,7 +14,7 @@ {"Administrator privileges required","Se necesita privilegios de administrador"}. {"A friendly name for the node","Un nombre sencillo para el nodo"}. {"All activity","Toda la actividad"}. -{"Allow this JID to subscribe to this pubsub node?","¿Deseas permitir a este JabberID que se subscriba a este nodo PubSub?"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","¿Deseas permitir a este JabberID que se subscriba a este nodo PubSub?"}. {"Allow users to change subject","Permitir a los usuarios cambiar el asunto"}. {"Allow users to query other users","Permitir a los usuarios consultar a otros usuarios"}. {"Allow users to send invites","Permitir a los usuarios enviar invitaciones"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","Introduce lista de {módulo, [opciones]}"}. {"Enter nickname you want to register","Introduce el apodo que quieras registrar"}. {"Enter path to backup file","Introduce ruta al fichero de copia de seguridad"}. -{"Enter path to jabberd1.4 spool dir","Introduce la ruta al directorio de jabberd1.4 spools"}. -{"Enter path to jabberd1.4 spool file","Introduce ruta al fichero jabberd1.4 spool"}. +{"Enter path to jabberd14 spool dir","Introduce la ruta al directorio de jabberd14 spools"}. +{"Enter path to jabberd14 spool file","Introduce ruta al fichero jabberd14 spool"}. {"Enter path to text file","Introduce ruta al fichero de texto"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Introduce el nombre de usuario y codificaciones de carácteres que quieras usar al conectar en los servidores de IRC"}. {"Erlang Jabber Server","Servidor Jabber en Erlang"}. @@ -113,7 +113,7 @@ {"Import File","Importar fichero"}. {"Import User from File at ","Importa usuario desde fichero en "}. {"Import Users from Dir at ","Importar usuarios desde el directorio en "}. -{"Import Users From jabberd 1.4 Spool Files","Importar usuarios de ficheros spool de jabberd-1.4"}. +{"Import Users From jabberd14 Spool Files","Importar usuarios de ficheros spool de jabberd-1.4"}. {"Improper message type","Tipo de mensaje incorrecto"}. {"Incorrect password","Contraseña incorrecta"}. {"Invalid affiliation: ~s","Afiliación no válida: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages to the conference","Impedir el envio de mensajes privados a la sala"}. {"Jabber ID","Jabber ID"}. {"January","enero"}. -{"JID ~s is invalid","El JID ~s no es válido"}. +{"Jabber ID ~s is invalid","El JID ~s no es válido"}. {"joins the room","entra en la sala"}. {"July","julio"}. {"June","junio"}. @@ -219,7 +219,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","Puerto"}. -{"Present real JIDs to","Los JID reales pueden verlos"}. +{"Present real Jabber IDs to","Los JID reales pueden verlos"}. {"private, ","privado"}. {"Publish-Subscribe","Servicio de Publicar-Subscribir"}. {"PubSub subscriber request","Petición de subscriptor de PubSub"}. @@ -307,7 +307,7 @@ {"To ~s","A ~s"}. {"Traffic rate limit is exceeded","Se ha exedido el límite de tráfico"}. {"Transactions Aborted:","Transacciones abortadas:"}. -{"Transactions Commited:","Transacciones finalizadas:"}. +{"Transactions Committed:","Transacciones finalizadas:"}. {"Transactions Logged:","Transacciones registradas:"}. {"Transactions Restarted:","Transacciones reiniciadas:"}. {"Tuesday","martes"}. diff --git a/src/msgs/es.po b/src/msgs/es.po index 7ae471974..b0d52e934 100644 --- a/src/msgs/es.po +++ b/src/msgs/es.po @@ -225,7 +225,7 @@ msgid "Backup Management" msgstr "Gestión de copia de seguridad" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" +msgid "Import Users From jabberd14 Spool Files" msgstr "Importar usuarios de ficheros spool de jabberd-1.4" #: mod_configure.erl:649 @@ -310,16 +310,16 @@ msgid "Import User from File at " msgstr "Importa usuario desde fichero en " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Introduce ruta al fichero jabberd1.4 spool" +msgid "Enter path to jabberd14 spool file" +msgstr "Introduce ruta al fichero jabberd14 spool" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Importar usuarios desde el directorio en " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Introduce la ruta al directorio de jabberd1.4 spools" +msgid "Enter path to jabberd14 spool dir" +msgstr "Introduce la ruta al directorio de jabberd14 spools" #: mod_configure.erl:995 msgid "Path to Dir" @@ -759,8 +759,8 @@ msgid "Moderator privileges required" msgstr "Se necesita privilegios de moderador" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "El JID ~s no es válido" +msgid "Jabber ID ~s is invalid" +msgstr "El Jabber ID ~s no es válido" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -812,8 +812,8 @@ msgid "No limit" msgstr "Sin límite" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "Los JID reales pueden verlos" +msgid "Present real Jabber IDs to" +msgstr "Los Jabber ID reales pueden verlos" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -957,7 +957,7 @@ msgid "Subscriber Address" msgstr "Dirección del subscriptor" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" msgstr "¿Deseas permitir a este JabberID que se subscriba a este nodo PubSub?" #: mod_pubsub/mod_pubsub.erl:2497 @@ -1442,7 +1442,7 @@ msgid "CPU Time:" msgstr "Tiempo consumido de CPU:" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Transacciones finalizadas:" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/fr.msg b/src/msgs/fr.msg index 831f0fc8e..6fbb9612a 100644 --- a/src/msgs/fr.msg +++ b/src/msgs/fr.msg @@ -14,7 +14,7 @@ {"Administrator privileges required","Les droits d'administrateur sont nécessaires"}. {"A friendly name for the node","Un nom convivial pour le noeud"}. {"All activity","Toute activité"}. -{"Allow this JID to subscribe to this pubsub node?","Autoriser ce JID à s'abonner à ce noeud pubsub"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Autoriser ce JID à s'abonner à ce noeud pubsub"}. {"Allow users to change subject","Autoriser les utilisateurs à changer le sujet"}. {"Allow users to query other users","Permettre aux utilisateurs d'envoyer des requêtes aux autres utilisateurs"}. {"Allow users to send invites","Permettre aux utilisateurs d'envoyer des invitations"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","Entrez une liste de {Module, [Options]}"}. {"Enter nickname you want to register","Entrez le pseudo que vous souhaitez enregistrer"}. {"Enter path to backup file","Entrez le chemin vers le fichier de sauvegarde"}. -{"Enter path to jabberd1.4 spool dir","Entrez le chemin vers le répertoire de spool jabberd1.4"}. -{"Enter path to jabberd1.4 spool file","Entrez le chemin vers le fichier spool jabberd1.4"}. +{"Enter path to jabberd14 spool dir","Entrez le chemin vers le répertoire de spool jabberd14"}. +{"Enter path to jabberd14 spool file","Entrez le chemin vers le fichier spool jabberd14"}. {"Enter path to text file","Entrez le chemin vers le fichier texte"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Entrez le nom d'utilisateur et les encodages que vous souhaitez utiliser pour vous connecter aux serveurs IRC"}. {"Erlang Jabber Server","Serveur Jabber Erlang"}. @@ -113,7 +113,7 @@ {"Import File","Importer un fichier"}. {"Import User from File at ","Importer un utilisateur depuis le fichier sur "}. {"Import Users from Dir at ","Importer des utilisateurs depuis le répertoire sur "}. -{"Import Users From jabberd 1.4 Spool Files","Importer des utilisateurs depuis un fichier spool Jabberd 1.4"}. +{"Import Users From jabberd14 Spool Files","Importer des utilisateurs depuis un fichier spool Jabberd 1.4"}. {"Improper message type","Mauvais type de message"}. {"Incorrect password","Mot de passe incorrect"}. {"Invalid affiliation: ~s","Affiliation invalide: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages to the conference","Il n'est pas permis d'envoyer des messages \"normaux\" à la conférence"}. {"Jabber ID","Jabber ID"}. {"January","Janvier"}. -{"JID ~s is invalid","Le JID ~s n'est pas valide"}. +{"Jabber ID ~s is invalid","Le JID ~s n'est pas valide"}. {"joins the room","rejoint le salon"}. {"July","Juillet"}. {"June","Juin"}. @@ -219,7 +219,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","Port"}. -{"Present real JIDs to","Rendre le JID réel visible pour"}. +{"Present real Jabber IDs to","Rendre le JID réel visible pour"}. {"private, ","privé"}. {"Publish-Subscribe","Publication-Abonnement"}. {"PubSub subscriber request","Demande d'abonnement PubSub"}. @@ -307,7 +307,7 @@ {"To ~s","A ~s"}. {"Traffic rate limit is exceeded","La limite de trafic a été dépassée"}. {"Transactions Aborted:","Transactions annulées:"}. -{"Transactions Commited:","Transactions commitées:"}. +{"Transactions Committed:","Transactions commitées:"}. {"Transactions Logged:","Transactions journalisées:"}. {"Transactions Restarted:","Transactions redémarrées:"}. {"Tuesday","Mardi"}. diff --git a/src/msgs/fr.po b/src/msgs/fr.po index 30f30d52c..b1d232bb5 100644 --- a/src/msgs/fr.po +++ b/src/msgs/fr.po @@ -229,7 +229,7 @@ msgid "Backup Management" msgstr "Gestion des sauvegardes" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" +msgid "Import Users From jabberd14 Spool Files" msgstr "Importer des utilisateurs depuis un fichier spool Jabberd 1.4" #: mod_configure.erl:649 @@ -314,16 +314,16 @@ msgid "Import User from File at " msgstr "Importer un utilisateur depuis le fichier sur " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Entrez le chemin vers le fichier spool jabberd1.4" +msgid "Enter path to jabberd14 spool file" +msgstr "Entrez le chemin vers le fichier spool jabberd14" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Importer des utilisateurs depuis le répertoire sur " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Entrez le chemin vers le répertoire de spool jabberd1.4" +msgid "Enter path to jabberd14 spool dir" +msgstr "Entrez le chemin vers le répertoire de spool jabberd14" #: mod_configure.erl:995 msgid "Path to Dir" @@ -766,8 +766,8 @@ msgid "Moderator privileges required" msgstr "Les droits de modérateur sont nécessaires" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "Le JID ~s n'est pas valide" +msgid "Jabber ID ~s is invalid" +msgstr "Le Jabber ID ~s n'est pas valide" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -819,8 +819,8 @@ msgid "No limit" msgstr "Pas de limite" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "Rendre le JID réel visible pour" +msgid "Present real Jabber IDs to" +msgstr "Rendre le Jabber ID réel visible pour" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -964,8 +964,8 @@ msgid "Subscriber Address" msgstr "Adresse de l'abonné" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "Autoriser ce JID à s'abonner à ce noeud pubsub" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "Autoriser ce Jabber ID à s'abonner à ce noeud pubsub" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1452,7 +1452,7 @@ msgid "CPU Time:" msgstr "Temps CPU:" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Transactions commitées:" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/gl.msg b/src/msgs/gl.msg index fbfe06a95..5b30993e2 100644 --- a/src/msgs/gl.msg +++ b/src/msgs/gl.msg @@ -13,7 +13,7 @@ {"Administration of ","Administración de "}. {"Administrator privileges required","Necesítase privilexios de administrador"}. {"All activity","Toda a actividade"}. -{"Allow this JID to subscribe to this pubsub node?","Desexas permitir a este JabberID que se subscriba a este nodo PubSub?"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Desexas permitir a este JabberID que se subscriba a este nodo PubSub?"}. {"Allow users to change subject","Permitir aos usuarios cambiar o asunto"}. {"Allow users to query other users","Permitir aos usuarios consultar a outros usuarios"}. {"Allow users to send invites","Permitir aos usuarios enviar invitacións"}. @@ -77,8 +77,8 @@ {"Enter list of {Module, [Options]}","Introduce lista de {módulo, [opcións]}"}. {"Enter nickname you want to register","Introduce o alcume que queiras rexistrar"}. {"Enter path to backup file","Introduce ruta ao ficheiro de copia de seguridade"}. -{"Enter path to jabberd1.4 spool dir","Introduce a ruta ao directorio de jabberd1.4 spools"}. -{"Enter path to jabberd1.4 spool file","Introduce ruta ao ficheiro jabberd1.4 spool"}. +{"Enter path to jabberd14 spool dir","Introduce a ruta ao directorio de jabberd14 spools"}. +{"Enter path to jabberd14 spool file","Introduce ruta ao ficheiro jabberd14 spool"}. {"Enter path to text file","Introduce ruta ao ficheiro de texto"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Introduce o nome de usuario e codificaciones de carácteres que queiras usar ao conectar nos servidores de IRC"}. {"Erlang Jabber Server","Servidor Jabber en Erlang"}. @@ -110,7 +110,7 @@ {"Import File","Importar ficheiro"}. {"Import User from File at ","Importa usuario desde ficheiro en "}. {"Import Users from Dir at ","Importar usuarios desde o directorio en "}. -{"Import Users From jabberd 1.4 Spool Files","Importar usuarios de ficheiros spool de jabberd-1.4"}. +{"Import Users From jabberd14 Spool Files","Importar usuarios de ficheiros spool de jabberd-1.4"}. {"Improper message type","Tipo de mensaxe incorrecta"}. {"Incorrect password","Contraseña incorrecta"}. {"Invalid affiliation: ~s","Afiliación non válida: ~s"}. @@ -123,7 +123,7 @@ {"It is not allowed to send private messages to the conference","Impedir o envio de mensaxes privadas á sala"}. {"Jabber ID","Jabber ID"}. {"January","Xaneiro"}. -{"JID ~s is invalid","O JID ~s non é válido"}. +{"Jabber ID ~s is invalid","O JID ~s non é válido"}. {"joins the room","entra en la sala"}. {"July","Xullo"}. {"June","Xuño"}. @@ -215,7 +215,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","Porto"}. -{"Present real JIDs to","Os JID reais poden velos"}. +{"Present real Jabber IDs to","Os JID reais poden velos"}. {"private, ","privado"}. {"Publish-Subscribe","Publicar-Subscribir"}. {"PubSub subscriber request","Petición de subscriptor de PubSub"}. @@ -303,7 +303,7 @@ {"To ~s","A ~s"}. {"Traffic rate limit is exceeded","Hase exedido o límite de tráfico"}. {"Transactions Aborted:","Transaccións abortadas:"}. -{"Transactions Commited:","Transaccións finalizadas:"}. +{"Transactions Committed:","Transaccións finalizadas:"}. {"Transactions Logged:","Transaccións rexistradas:"}. {"Transactions Restarted:","Transaccións reiniciadas:"}. {"Tuesday","Martes"}. diff --git a/src/msgs/gl.po b/src/msgs/gl.po index 499e67dbb..7f35d1864 100644 --- a/src/msgs/gl.po +++ b/src/msgs/gl.po @@ -224,7 +224,7 @@ msgid "Backup Management" msgstr "Xestión de copia de seguridade" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" +msgid "Import Users From jabberd14 Spool Files" msgstr "Importar usuarios de ficheiros spool de jabberd-1.4" #: mod_configure.erl:649 @@ -309,16 +309,16 @@ msgid "Import User from File at " msgstr "Importa usuario desde ficheiro en " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Introduce ruta ao ficheiro jabberd1.4 spool" +msgid "Enter path to jabberd14 spool file" +msgstr "Introduce ruta ao ficheiro jabberd14 spool" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Importar usuarios desde o directorio en " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Introduce a ruta ao directorio de jabberd1.4 spools" +msgid "Enter path to jabberd14 spool dir" +msgstr "Introduce a ruta ao directorio de jabberd14 spools" #: mod_configure.erl:995 msgid "Path to Dir" @@ -756,8 +756,8 @@ msgid "Moderator privileges required" msgstr "Necesítase privilexios de moderador" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "O JID ~s non é válido" +msgid "Jabber ID ~s is invalid" +msgstr "O Jabber ID ~s non é válido" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -809,8 +809,8 @@ msgid "No limit" msgstr "Sen límite" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "Os JID reais poden velos" +msgid "Present real Jabber IDs to" +msgstr "Os Jabber ID reais poden velos" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -954,7 +954,7 @@ msgid "Subscriber Address" msgstr "Dirección do subscriptor" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" msgstr "Desexas permitir a este JabberID que se subscriba a este nodo PubSub?" #: mod_pubsub/mod_pubsub.erl:2497 @@ -1440,7 +1440,7 @@ msgid "CPU Time:" msgstr "Tempo consumido de CPU:" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Transaccións finalizadas:" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/it.msg b/src/msgs/it.msg index e10994b7a..f2928492f 100644 --- a/src/msgs/it.msg +++ b/src/msgs/it.msg @@ -6,7 +6,7 @@ {"Access rules","Regole di accesso"}. {"Access Rules","Regole di accesso"}. {"Action on user","Azione sull'utente"}. -{"Add Jabber ID","Aggiungere un Jabber ID (JID)"}. +{"Add Jabber ID","Aggiungere un Jabber ID (Jabber ID)"}. {"Add New","Aggiungere nuovo"}. {"Add User","Aggiungere un utente"}. {"Administration","Amministrazione"}. @@ -14,7 +14,7 @@ {"Administrator privileges required","Necessari i privilegi di amministratore"}. {"A friendly name for the node","Un nome comodo per il nodo"}. {"All activity","Tutta l'attività"}. -{"Allow this JID to subscribe to this pubsub node?","Consentire a questo JID l'iscrizione a questo nodo pubsub?"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Consentire a questo JID l'iscrizione a questo nodo pubsub?"}. {"Allow users to change subject","Consentire agli utenti di cambiare l'oggetto"}. {"Allow users to query other users","Consentire agli utenti query verso altri utenti"}. {"Allow users to send invites","Consentire agli utenti l'invio di inviti"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","Immettere un elenco di {Modulo, [Opzioni]}"}. {"Enter nickname you want to register","Immettere il nickname che si vuole registrare"}. {"Enter path to backup file","Immettere il percorso del file di salvataggio"}. -{"Enter path to jabberd1.4 spool dir","Immettere il percorso della directory di spool di jabberd1.4"}. -{"Enter path to jabberd1.4 spool file","Immettere il percorso del file di spool di jabberd1.4"}. +{"Enter path to jabberd14 spool dir","Immettere il percorso della directory di spool di jabberd14"}. +{"Enter path to jabberd14 spool file","Immettere il percorso del file di spool di jabberd14"}. {"Enter path to text file","Immettere il percorso del file di testo"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Immettere il nome utente e le codifiche che si desidera utilizzare per la connessione ai server IRC"}. {"Erlang Jabber Server","Erlang Jabber Server"}. @@ -113,7 +113,7 @@ {"Import File","Importare un file"}. {"Import User from File at ","Importare un utente dal file "}. {"Import Users from Dir at ","Importare utenti dalla directory "}. -{"Import Users From jabberd 1.4 Spool Files","Importare utenti da file di spool di jabberd 1.4"}. +{"Import Users From jabberd14 Spool Files","Importare utenti da file di spool di jabberd14"}. {"Improper message type","Tipo di messaggio non corretto"}. {"Incorrect password","Password non esatta"}. {"Invalid affiliation: ~s","Affiliazione non valida: ~s"}. @@ -125,9 +125,9 @@ {"It is not allowed to send private messages","Non è consentito l'invio di messaggi privati"}. {"It is not allowed to send private messages of type \"groupchat\"","Non è consentito l'invio di messaggi privati di tipo \"groupchat\""}. {"It is not allowed to send private messages to the conference","Non è consentito l'invio di messaggi privati alla conferenza"}. -{"Jabber ID","Jabber ID (JID)"}. +{"Jabber ID","Jabber ID (Jabber ID)"}. {"January","Gennaio"}. -{"JID ~s is invalid","Il JID ~s non è valido"}. +{"Jabber ID ~s is invalid","Il JID ~s non è valido"}. {"joins the room","entra nella stanza"}. {"July","Luglio"}. {"June","Giugno"}. @@ -219,7 +219,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","Porta"}. -{"Present real JIDs to","Rendere visibile il JID reale a"}. +{"Present real Jabber IDs to","Rendere visibile il JID reale a"}. {"private, ","privato, "}. {"Publish-Subscribe","Pubblicazione-Iscrizione"}. {"PubSub subscriber request","Richiesta di iscrizione per PubSub"}. @@ -307,7 +307,7 @@ {"To ~s","A ~s"}. {"Traffic rate limit is exceeded","Limite di traffico superato"}. {"Transactions Aborted:","Transazioni abortite:"}. -{"Transactions Commited:","Transazioni avvenute:"}. +{"Transactions Committed:","Transazioni avvenute:"}. {"Transactions Logged:","Transazioni con log:"}. {"Transactions Restarted:","Transazioni riavviate:"}. {"Tuesday","Martedì"}. diff --git a/src/msgs/it.po b/src/msgs/it.po index 3f436c9bb..fd3dc6296 100644 --- a/src/msgs/it.po +++ b/src/msgs/it.po @@ -228,8 +228,8 @@ msgid "Backup Management" msgstr "Gestione dei salvataggi" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" -msgstr "Importare utenti da file di spool di jabberd 1.4" +msgid "Import Users From jabberd14 Spool Files" +msgstr "Importare utenti da file di spool di jabberd14" #: mod_configure.erl:649 msgid "To ~s" @@ -313,16 +313,16 @@ msgid "Import User from File at " msgstr "Importare un utente dal file " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Immettere il percorso del file di spool di jabberd1.4" +msgid "Enter path to jabberd14 spool file" +msgstr "Immettere il percorso del file di spool di jabberd14" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Importare utenti dalla directory " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Immettere il percorso della directory di spool di jabberd1.4" +msgid "Enter path to jabberd14 spool dir" +msgstr "Immettere il percorso della directory di spool di jabberd14" #: mod_configure.erl:995 msgid "Path to Dir" @@ -354,7 +354,7 @@ msgstr "Regole di accesso" #: mod_configure.erl:1667 mod_roster.erl:803 mod_roster_odbc.erl:910 #: mod_vcard.erl:460 mod_vcard_ldap.erl:544 mod_vcard_odbc.erl:457 msgid "Jabber ID" -msgstr "Jabber ID (JID)" +msgstr "Jabber ID (Jabber ID)" #: mod_configure.erl:1156 mod_configure.erl:1214 mod_configure.erl:1600 #: mod_configure.erl:1809 mod_muc/mod_muc_room.erl:2702 @@ -760,8 +760,8 @@ msgid "Moderator privileges required" msgstr "Necessari i privilegi di moderatore" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "Il JID ~s non è valido" +msgid "Jabber ID ~s is invalid" +msgstr "Il Jabber ID ~s non è valido" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -813,8 +813,8 @@ msgid "No limit" msgstr "Nessun limite" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "Rendere visibile il JID reale a" +msgid "Present real Jabber IDs to" +msgstr "Rendere visibile il Jabber ID reale a" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -959,8 +959,8 @@ msgid "Subscriber Address" msgstr "Indirizzo dell'iscritta/o" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "Consentire a questo JID l'iscrizione a questo nodo pubsub?" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "Consentire a questo Jabber ID l'iscrizione a questo nodo pubsub?" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1074,7 +1074,7 @@ msgstr "Formato non valido" #: mod_roster.erl:855 mod_roster_odbc.erl:962 msgid "Add Jabber ID" -msgstr "Aggiungere un Jabber ID (JID)" +msgstr "Aggiungere un Jabber ID (Jabber ID)" #: mod_roster.erl:936 mod_roster_odbc.erl:1043 msgid "Roster" @@ -1446,7 +1446,7 @@ msgid "CPU Time:" msgstr "Tempo CPU:" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Transazioni avvenute:" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/ja.msg b/src/msgs/ja.msg index 08de9b203..ba05d8d1a 100644 --- a/src/msgs/ja.msg +++ b/src/msgs/ja.msg @@ -14,7 +14,7 @@ {"Administrator privileges required","管理者権限が必要です"}. {"A friendly name for the node","ノードの為のフレンドリネーム"}. {"All activity","全て"}. -{"Allow this JID to subscribe to this pubsub node?","この JID をこの pubsubノードへ購読することを許可しますか?"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","この JID をこの pubsubノードへ購読することを許可しますか?"}. {"Allow users to change subject","ユーザーによる件名の変更を許可する"}. {"Allow users to query other users","ユーザーによる他のユーザーへの問い合わせを許可する"}. {"Allow users to send invites","ユーザーによる招待を許可する"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","{モジュール, [オプション]}のリストを入力して下さい"}. {"Enter nickname you want to register","登録するニックネームを入力して下さい"}. {"Enter path to backup file","バックアップファイルのパスを入力して下さい"}. -{"Enter path to jabberd1.4 spool dir","jabberd1.4 spool ディレクトリのパスを入力して下さい"}. -{"Enter path to jabberd1.4 spool file","jabberd1.4 spool ファイルのパスを入力して下さい"}. +{"Enter path to jabberd14 spool dir","jabberd14 spool ディレクトリのパスを入力して下さい"}. +{"Enter path to jabberd14 spool file","jabberd14 spool ファイルのパスを入力して下さい"}. {"Enter path to text file","テキストファイルのパスを入力して下さい"}. {"Enter username and encodings you wish to use for connecting to IRC servers","IRCサーバーに接続先する為のユーザー名と文字エンコーディングを入力して下さい"}. {"Erlang Jabber Server","Erlang Jabber Server"}. @@ -113,7 +113,7 @@ {"Import File","ファイルかインポート"}. {"Import User from File at ","ファイルからユーザーをインポート"}. {"Import Users from Dir at ","ディレクトリからユーザーをインポート"}. -{"Import Users From jabberd 1.4 Spool Files","jabberd 1.4 Spool ファイルからユーザーをインポート"}. +{"Import Users From jabberd14 Spool Files","jabberd14 Spool ファイルからユーザーをインポート"}. {"Improper message type","誤ったメッセージタイプです"}. {"Incorrect password","パスワードが違います"}. {"Invalid affiliation: ~s","無効な提携です: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages","プライベートメッセージを送信することは許可されませんでした"}. {"Jabber ID","Jabber ID"}. {"January","1月"}. -{"JID ~s is invalid","JID ~s は無効です"}. +{"Jabber ID ~s is invalid","JID ~s は無効です"}. {"joins the room","チャットルームに参加"}. {"July","7月"}. {"June","6月"}. @@ -219,7 +219,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","ポート"}. -{"Present real JIDs to","本当の JID を公開する"}. +{"Present real Jabber IDs to","本当の JID を公開する"}. {"private, ","プライベート"}. {"Publish-Subscribe","Publish-Subscribe"}. {"PubSub subscriber request","PubSub 購読リクエスト"}. @@ -307,7 +307,7 @@ {"To","宛先"}. {"Traffic rate limit is exceeded","トラフィックレートの制限を超えました"}. {"Transactions Aborted:","トランザクションの失敗:"}. -{"Transactions Commited:","トランザクションのコミット:"}. +{"Transactions Committed:","トランザクションのコミット:"}. {"Transactions Logged:","トランザクションのログ: "}. {"Transactions Restarted:","トランザクションの再起動:"}. {"Tuesday","火曜日"}. diff --git a/src/msgs/ja.po b/src/msgs/ja.po index 76ed42510..4fcc1476c 100644 --- a/src/msgs/ja.po +++ b/src/msgs/ja.po @@ -223,8 +223,8 @@ msgid "Backup Management" msgstr "バックアップ管理" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" -msgstr "jabberd 1.4 Spool ファイルからユーザーをインポート" +msgid "Import Users From jabberd14 Spool Files" +msgstr "jabberd14 Spool ファイルからユーザーをインポート" #: mod_configure.erl:649 msgid "To ~s" @@ -308,16 +308,16 @@ msgid "Import User from File at " msgstr "ファイルからユーザーをインポート" #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "jabberd1.4 spool ファイルのパスを入力して下さい" +msgid "Enter path to jabberd14 spool file" +msgstr "jabberd14 spool ファイルのパスを入力して下さい" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "ディレクトリからユーザーをインポート" #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "jabberd1.4 spool ディレクトリのパスを入力して下さい" +msgid "Enter path to jabberd14 spool dir" +msgstr "jabberd14 spool ディレクトリのパスを入力して下さい" #: mod_configure.erl:995 msgid "Path to Dir" @@ -745,8 +745,8 @@ msgid "Moderator privileges required" msgstr "モデレーター権限が必要です" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "JID ~s は無効です" +msgid "Jabber ID ~s is invalid" +msgstr "Jabber ID ~s は無効です" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -798,8 +798,8 @@ msgid "No limit" msgstr "制限無し" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "本当の JID を公開する" +msgid "Present real Jabber IDs to" +msgstr "本当の Jabber ID を公開する" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -942,8 +942,8 @@ msgid "Subscriber Address" msgstr "購読アドレス" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "この JID をこの pubsubノードへ購読することを許可しますか?" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "この Jabber ID をこの pubsubノードへ購読することを許可しますか?" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1424,7 +1424,7 @@ msgid "CPU Time:" msgstr "CPU時間:" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "トランザクションのコミット:" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/nl.msg b/src/msgs/nl.msg index cb49db6f1..778596334 100644 --- a/src/msgs/nl.msg +++ b/src/msgs/nl.msg @@ -14,7 +14,7 @@ {"Administrator privileges required","U hebt beheerdersprivileges nodig"}. {"A friendly name for the node","Bijnaam voor deze knoop"}. {"All activity","Alle activiteit"}. -{"Allow this JID to subscribe to this pubsub node?","Deze gebruiker toestaan te abonneren op deze pubsub node?"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Deze gebruiker toestaan te abonneren op deze pubsub node?"}. {"Allow users to change subject","Gebruikers mogen het onderwerp veranderen"}. {"Allow users to query other users","Gebruikers mogen naar andere gebruikers verzoeken verzenden"}. {"Allow users to send invites","Gebruikers mogen uitnodigingen verzenden"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","Voer lijst met op te starten modules als volgt in: {Module, [Opties]}"}. {"Enter nickname you want to register","Voer de bijnaam in die u wilt registreren"}. {"Enter path to backup file","Voer pad naar backupbestand in"}. -{"Enter path to jabberd1.4 spool dir","Voer pad naar jabberd 1.4-spool-directory in"}. -{"Enter path to jabberd1.4 spool file","Voer pad naar jabberd 1.4-spool-bestand in"}. +{"Enter path to jabberd14 spool dir","Voer pad naar jabberd14-spool-directory in"}. +{"Enter path to jabberd14 spool file","Voer pad naar jabberd14-spool-bestand in"}. {"Enter path to text file","Voer pad naar backupbestand in"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Voer de gebruikersnaam en de coderingen in die u wilt gebruiken voor verbindingen met IRC-servers"}. {"Erlang Jabber Server","Erlang Jabber Server"}. @@ -113,7 +113,7 @@ {"Import File","Bestand importeren"}. {"Import User from File at ","Importeer gebruiker via bestand op "}. {"Import Users from Dir at ","Gebruikers importeren vanaf directory op "}. -{"Import Users From jabberd 1.4 Spool Files","Importeer gebruikers via spool-bestanden van jabberd 1.4"}. +{"Import Users From jabberd14 Spool Files","Importeer gebruikers via spool-bestanden van jabberd14"}. {"Improper message type","Onjuist berichttype"}. {"Incorrect password","Foutief wachtwoord"}. {"Invalid affiliation: ~s","Ongeldige affiliatie: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages to the conference","Er mogen geen privéberichten naar de chatruimte worden verzonden"}. {"Jabber ID","Jabber ID"}. {"January","januari"}. -{"JID ~s is invalid","De Jabber ID ~s is ongeldig"}. +{"Jabber ID ~s is invalid","De Jabber ID ~s is ongeldig"}. {"joins the room","betrad de chatruimte"}. {"July","juli"}. {"June","juni"}. @@ -219,7 +219,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","Poort"}. -{"Present real JIDs to","Jabber ID's kunnen achterhaald worden door"}. +{"Present real Jabber IDs to","Jabber ID's kunnen achterhaald worden door"}. {"private, ","privé, "}. {"Publish-Subscribe","Publish-Subscribe"}. {"PubSub subscriber request","PubSub abonnee verzoek"}. @@ -307,7 +307,7 @@ {"To ~s","Naar ~s"}. {"Traffic rate limit is exceeded","Dataverkeerslimiet overschreden"}. {"Transactions Aborted:","Afgebroken transacties:"}. -{"Transactions Commited:","Bevestigde transacties:"}. +{"Transactions Committed:","Bevestigde transacties:"}. {"Transactions Logged:","Gelogde transacties:"}. {"Transactions Restarted:","Herstarte transacties:"}. {"Tuesday","dinsdag"}. diff --git a/src/msgs/nl.po b/src/msgs/nl.po index 9bea8ba03..a4253801f 100644 --- a/src/msgs/nl.po +++ b/src/msgs/nl.po @@ -226,8 +226,8 @@ msgid "Backup Management" msgstr "Backup" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" -msgstr "Importeer gebruikers via spool-bestanden van jabberd 1.4" +msgid "Import Users From jabberd14 Spool Files" +msgstr "Importeer gebruikers via spool-bestanden van jabberd14" #: mod_configure.erl:649 msgid "To ~s" @@ -311,16 +311,16 @@ msgid "Import User from File at " msgstr "Importeer gebruiker via bestand op " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Voer pad naar jabberd 1.4-spool-bestand in" +msgid "Enter path to jabberd14 spool file" +msgstr "Voer pad naar jabberd14-spool-bestand in" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Gebruikers importeren vanaf directory op " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Voer pad naar jabberd 1.4-spool-directory in" +msgid "Enter path to jabberd14 spool dir" +msgstr "Voer pad naar jabberd14-spool-directory in" #: mod_configure.erl:995 msgid "Path to Dir" @@ -766,7 +766,7 @@ msgid "Moderator privileges required" msgstr "U hebt moderatorprivileges nodig" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" +msgid "Jabber ID ~s is invalid" msgstr "De Jabber ID ~s is ongeldig" #: mod_muc/mod_muc_room.erl:2212 @@ -819,7 +819,7 @@ msgid "No limit" msgstr "Geen limiet" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" +msgid "Present real Jabber IDs to" msgstr "Jabber ID's kunnen achterhaald worden door" #: mod_muc/mod_muc_room.erl:2741 @@ -964,7 +964,7 @@ msgid "Subscriber Address" msgstr "Abonnee Adres" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" msgstr "Deze gebruiker toestaan te abonneren op deze pubsub node?" #: mod_pubsub/mod_pubsub.erl:2497 @@ -1448,7 +1448,7 @@ msgid "CPU Time:" msgstr "Processortijd:" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Bevestigde transacties:" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/no.msg b/src/msgs/no.msg index 195381574..d8f407aa1 100644 --- a/src/msgs/no.msg +++ b/src/msgs/no.msg @@ -14,7 +14,7 @@ {"Administrator privileges required","Administratorprivilegier kreves"}. {"A friendly name for the node","Et vennlig navn for noden"}. {"All activity","All aktivitet"}. -{"Allow this JID to subscribe to this pubsub node?","Tillat denne JID å abonnere på denne pubsub noden?"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Tillat denne JID å abonnere på denne pubsub noden?"}. {"Allow users to change subject","Tillat brukere å endre emne"}. {"Allow users to query other users","Tillat brukere å sende forespørsel til andre brukere"}. {"Allow users to send invites","Tillat brukere å sende invitasjoner"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","Skriv inn en liste av {Module, [Options]}"}. {"Enter nickname you want to register","Skriv inn kallenavnet du ønsker å registrere"}. {"Enter path to backup file","Skriv inn sti til sikkerhetskopi filen"}. -{"Enter path to jabberd1.4 spool dir","Skriv inn sti til jabberd1.4 spoolkatalog"}. -{"Enter path to jabberd1.4 spool file","Skriv inn sti til jabberd1.4 spoolfil"}. +{"Enter path to jabberd14 spool dir","Skriv inn sti til jabberd14 spoolkatalog"}. +{"Enter path to jabberd14 spool file","Skriv inn sti til jabberd14 spoolfil"}. {"Enter path to text file","Skriv inn sti til tekstfil"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Skriv inn brukernavn og tekstkoding du ønsker å bruke for å koble til IRC tjenere"}. {"Erlang Jabber Server","Erlang Jabber Server"}. @@ -113,7 +113,7 @@ {"Import File","Importer File"}. {"Import User from File at ","Importer Bruker fra Fil på "}. {"Import Users from Dir at ","Importer Brukere fra Katalog på "}. -{"Import Users From jabberd 1.4 Spool Files","Importer Brukere Fra jabberd 1.4 Spoolfiler"}. +{"Import Users From jabberd14 Spool Files","Importer Brukere Fra jabberd14 Spoolfiler"}. {"Improper message type","Feilaktig meldingstype"}. {"Incorrect password","Feil passord"}. {"Invalid affiliation: ~s","Ugyldig rang: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages to the conference","Det er ikke tillatt å sende private meldinger til konferansen"}. {"Jabber ID","Jabber ID"}. {"January","januar"}. -{"JID ~s is invalid","Ugyldig JID ~s"}. +{"Jabber ID ~s is invalid","Ugyldig JID ~s"}. {"joins the room","kommer inn i rommet"}. {"July","juli"}. {"June","juni"}. @@ -219,7 +219,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","Port"}. -{"Present real JIDs to","Presenter ekte JIDer til"}. +{"Present real Jabber IDs to","Presenter ekte JIDer til"}. {"private, ","privat, "}. {"Publish-Subscribe","Publish-Subscribe"}. {"PubSub subscriber request","PubSub abonements forespørsel"}. @@ -307,7 +307,7 @@ {"To","Til"}. {"Traffic rate limit is exceeded","Trafikkmengde grense overskredet"}. {"Transactions Aborted:","Avbrutte Transasksjoner:"}. -{"Transactions Commited:","Sendte Transaksjoner:"}. +{"Transactions Committed:","Sendte Transaksjoner:"}. {"Transactions Logged:","Loggede Transasksjoner:"}. {"Transactions Restarted:","Omstartede Transasksjoner:"}. {"Tuesday","tirsdag"}. diff --git a/src/msgs/no.po b/src/msgs/no.po index 7a8448eee..081c21ef8 100644 --- a/src/msgs/no.po +++ b/src/msgs/no.po @@ -223,8 +223,8 @@ msgid "Backup Management" msgstr "Håndtere Sikkerehetskopiering" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" -msgstr "Importer Brukere Fra jabberd 1.4 Spoolfiler" +msgid "Import Users From jabberd14 Spool Files" +msgstr "Importer Brukere Fra jabberd14 Spoolfiler" #: mod_configure.erl:649 msgid "To ~s" @@ -308,16 +308,16 @@ msgid "Import User from File at " msgstr "Importer Bruker fra Fil på " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Skriv inn sti til jabberd1.4 spoolfil" +msgid "Enter path to jabberd14 spool file" +msgstr "Skriv inn sti til jabberd14 spoolfil" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Importer Brukere fra Katalog på " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Skriv inn sti til jabberd1.4 spoolkatalog" +msgid "Enter path to jabberd14 spool dir" +msgstr "Skriv inn sti til jabberd14 spoolkatalog" #: mod_configure.erl:995 msgid "Path to Dir" @@ -753,8 +753,8 @@ msgid "Moderator privileges required" msgstr "Redaktørprivilegier kreves" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "Ugyldig JID ~s" +msgid "Jabber ID ~s is invalid" +msgstr "Ugyldig Jabber ID ~s" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -806,8 +806,8 @@ msgid "No limit" msgstr "Ingen grense" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "Presenter ekte JIDer til" +msgid "Present real Jabber IDs to" +msgstr "Presenter ekte Jabber IDer til" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -947,8 +947,8 @@ msgid "Subscriber Address" msgstr "Abonnements Adresse" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "Tillat denne JID å abonnere på denne pubsub noden?" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "Tillat denne Jabber ID å abonnere på denne pubsub noden?" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1430,7 +1430,7 @@ msgid "CPU Time:" msgstr "CPU Tid:" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Sendte Transaksjoner:" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/pl.msg b/src/msgs/pl.msg index bc849bea3..b856b0c47 100644 --- a/src/msgs/pl.msg +++ b/src/msgs/pl.msg @@ -6,7 +6,7 @@ {"Access rules","Zasady dostępu"}. {"Access Rules","Zasady dostępu"}. {"Action on user","Akcja dla użytkownika"}. -{"Add Jabber ID","Dodaj JID"}. +{"Add Jabber ID","Dodaj Jabber ID"}. {"Add New","Dodaj nowe"}. {"Add User","Dodaj użytkownika"}. {"Administration","Administracja"}. @@ -14,7 +14,7 @@ {"Administrator privileges required","Wymagane prawa administratora"}. {"A friendly name for the node","Przyjazna nazwa węzła"}. {"All activity","Cała aktywność"}. -{"Allow this JID to subscribe to this pubsub node?","Pozwól temu JID na zapisanie się do tego noda pubsub"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Pozwól temu JID na zapisanie się do tego noda pubsub"}. {"Allow users to change subject","Pozwól użytkownikom zmienić tytuł pokoju"}. {"Allow users to query other users","Pozwól użytkownikom pobierać informacje o innych użytkownikach"}. {"Allow users to send invites","Pozwól użytkownikom wysyłać zaproszenia"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","Wprowadź listę {Moduł, [Opcje]}"}. {"Enter nickname you want to register","Wprowadz nicka którego chcesz zarejestrować"}. {"Enter path to backup file","Wprowadź scieżkę do pliku kopii zapasowej"}. -{"Enter path to jabberd1.4 spool dir","Wprowadź ścieżkę do katalogu spool serwera jabberd1.4"}. -{"Enter path to jabberd1.4 spool file","Wprowadź ścieżkę do pliku spool dla serwera jabberd1.4"}. +{"Enter path to jabberd14 spool dir","Wprowadź ścieżkę do katalogu spool serwera jabberd14"}. +{"Enter path to jabberd14 spool file","Wprowadź ścieżkę do pliku spool dla serwera jabberd14"}. {"Enter path to text file","Wprowadź scieżkę do pliku tekstowego"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Wprowadź nazwę użytkownika i kodowanie których chcesz używać do łączenia z serwerami IRC"}. {"Erlang Jabber Server","Erlang Jabber Server"}. @@ -113,7 +113,7 @@ {"Import File","Importuj plik"}. {"Import User from File at ","Importuj użytkownika z pliku na "}. {"Import Users from Dir at ","Importuj użytkowników z katalogu na "}. -{"Import Users From jabberd 1.4 Spool Files","Importuj użytkowników z plików spool serwera jabber 1.4"}. +{"Import Users From jabberd14 Spool Files","Importuj użytkowników z plików spool serwera jabber 1.4"}. {"Improper message type","Nieprawidłowy typ wiadomości"}. {"Incorrect password","Nieprawidłowe hasło"}. {"Invalid affiliation: ~s","Nieprawidłowe powiązanie: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages","Wysyłanie prywatnych wiadomości jest zabronione"}. {"Jabber ID","Jabber ID"}. {"January","Styczeń"}. -{"JID ~s is invalid","JID ~s jest niepoprawny"}. +{"Jabber ID ~s is invalid","JID ~s jest niepoprawny"}. {"joins the room","dołączył(a) się do pokoju"}. {"July","Lipiec"}. {"June","Czerwiec"}. @@ -135,7 +135,7 @@ {"Last login","Ostatnie logowanie"}. {"Last month","Ostatni miesiąc"}. {"Last year","Ostatni rok"}. -{"leaves the room","opóścił(a) pokój"}. +{"leaves the room","opuścił(a) pokój"}. {"Listened Ports at ","Porty nasłuchujące "}. {"Listened Ports","Porty nasłuchujące"}. {"List of modules to start","Lista modułów do uruchomienia"}. @@ -219,7 +219,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","Port"}. -{"Present real JIDs to","Kto może widzieć prawdziwe JID-y?"}. +{"Present real Jabber IDs to","Kto może widzieć prawdziwe JID-y?"}. {"private, ","prywatny, "}. {"Publish-Subscribe","PubSub"}. {"PubSub subscriber request","Rządzanie subskrybenta PubSub"}. @@ -307,7 +307,7 @@ {"To ~s","Do ~s"}. {"Traffic rate limit is exceeded","Limit transferu przekroczony"}. {"Transactions Aborted:","Transakcje anulowane"}. -{"Transactions Commited:","Transakcje zakończone"}. +{"Transactions Committed:","Transakcje zakończone"}. {"Transactions Logged:","Transakcje logowane"}. {"Transactions Restarted:","Transakcje uruchomione ponownie"}. {"Tuesday","Wtorek"}. diff --git a/src/msgs/pl.po b/src/msgs/pl.po index b960a22db..b92561c9e 100644 --- a/src/msgs/pl.po +++ b/src/msgs/pl.po @@ -227,7 +227,7 @@ msgid "Backup Management" msgstr "Zarządzanie kopiami zapasowymi" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" +msgid "Import Users From jabberd14 Spool Files" msgstr "Importuj użytkowników z plików spool serwera jabber 1.4" #: mod_configure.erl:649 @@ -312,16 +312,16 @@ msgid "Import User from File at " msgstr "Importuj użytkownika z pliku na " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Wprowadź ścieżkę do pliku spool dla serwera jabberd1.4" +msgid "Enter path to jabberd14 spool file" +msgstr "Wprowadź ścieżkę do pliku spool dla serwera jabberd14" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Importuj użytkowników z katalogu na " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Wprowadź ścieżkę do katalogu spool serwera jabberd1.4" +msgid "Enter path to jabberd14 spool dir" +msgstr "Wprowadź ścieżkę do katalogu spool serwera jabberd14" #: mod_configure.erl:995 msgid "Path to Dir" @@ -522,7 +522,7 @@ msgstr "dołączył(a) się do pokoju" #: mod_muc/mod_muc_log.erl:344 mod_muc/mod_muc_log.erl:347 msgid "leaves the room" -msgstr "opóścił(a) pokój" +msgstr "opuścił(a) pokój" #: mod_muc/mod_muc_log.erl:350 mod_muc/mod_muc_log.erl:353 msgid "has been banned" @@ -753,8 +753,8 @@ msgid "Moderator privileges required" msgstr "Wymagane prawa moderatora" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "JID ~s jest niepoprawny" +msgid "Jabber ID ~s is invalid" +msgstr "Jabber ID ~s jest niepoprawny" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -806,8 +806,8 @@ msgid "No limit" msgstr "Bez limitu" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "Kto może widzieć prawdziwe JID-y?" +msgid "Present real Jabber IDs to" +msgstr "Kto może widzieć prawdziwe Jabber ID-y?" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -948,8 +948,8 @@ msgid "Subscriber Address" msgstr "Adres subskrybenta" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "Pozwól temu JID na zapisanie się do tego noda pubsub" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "Pozwól temu Jabber ID na zapisanie się do tego noda pubsub" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1064,7 +1064,7 @@ msgstr "Zły format" #: mod_roster.erl:855 mod_roster_odbc.erl:962 msgid "Add Jabber ID" -msgstr "Dodaj JID" +msgstr "Dodaj Jabber ID" #: mod_roster.erl:936 mod_roster_odbc.erl:1043 msgid "Roster" @@ -1434,7 +1434,7 @@ msgid "CPU Time:" msgstr "Czas CPU" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Transakcje zakończone" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/pt-br.msg b/src/msgs/pt-br.msg index 97f2fca49..d313e37ab 100644 --- a/src/msgs/pt-br.msg +++ b/src/msgs/pt-br.msg @@ -14,7 +14,7 @@ {"Administrator privileges required","Se necessita privilégios de administrador"}. {"A friendly name for the node","Um nome familiar para o nó"}. {"All activity","Toda la atividade"}. -{"Allow this JID to subscribe to this pubsub node?","Autorizar este JID para a inscrição neste tópico pubsub ?"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Autorizar este JID para a inscrição neste tópico pubsub ?"}. {"Allow users to change subject","Permitir a usuários modificar o assunto"}. {"Allow users to query other users","Permitir a usuários pesquisar informações sobre os demais"}. {"Allow users to send invites","Permitir a usuários envio de convites"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","Introduza lista de {módulo, [opções]}"}. {"Enter nickname you want to register","Introduza o apelido que quer registrar"}. {"Enter path to backup file","Introduza o caminho do arquivo de cópia de segurança"}. -{"Enter path to jabberd1.4 spool dir","Introduza o caminho para o diretório de spools do jabberd1.4"}. -{"Enter path to jabberd1.4 spool file","Introduza o caminho para o arquivo de spool do jabberd1.4"}. +{"Enter path to jabberd14 spool dir","Introduza o caminho para o diretório de spools do jabberd14"}. +{"Enter path to jabberd14 spool file","Introduza o caminho para o arquivo de spool do jabberd14"}. {"Enter path to text file","Introduza caminho para o arquivo de texto"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Introduza o nome de usuário e codificações de caracteres que quer usar ao conectar-se aos servidores de IRC"}. {"Erlang Jabber Server","Servidor Jabber em Erlang"}. @@ -113,7 +113,7 @@ {"Import File","Importar arquivo"}. {"Import User from File at ","Importar usuário a partir do arquivo em "}. {"Import Users from Dir at ","Importar usuários a partir do diretório em "}. -{"Import Users From jabberd 1.4 Spool Files","Importar usuários de arquivos jabberd 1.4"}. +{"Import Users From jabberd14 Spool Files","Importar usuários de arquivos jabberd14"}. {"Improper message type","Tipo de mensagem incorreto"}. {"Incorrect password","Senha incorreta"}. {"Invalid affiliation: ~s","Afiliação não válida: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages to the conference","Impedir o envio de mensagens privados a la sala"}. {"Jabber ID","ID Jabber"}. {"January","Janeiro"}. -{"JID ~s is invalid","O JID ~s não es válido"}. +{"Jabber ID ~s is invalid","O JID ~s não es válido"}. {"joins the room","Entrar na sala"}. {"July","Julho"}. {"June","Junho"}. @@ -219,7 +219,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","Porta"}. -{"Present real JIDs to","Tornar o JID real visível por"}. +{"Present real Jabber IDs to","Tornar o JID real visível por"}. {"private, ","privado"}. {"Publish-Subscribe","Publicação de Tópico"}. {"PubSub subscriber request","PubSub requisição de assinante"}. @@ -307,7 +307,7 @@ {"To ~s","Para ~s"}. {"Traffic rate limit is exceeded","Limite de banda excedido"}. {"Transactions Aborted:","Transações abortadas:"}. -{"Transactions Commited:","Transações:"}. +{"Transactions Committed:","Transações:"}. {"Transactions Logged:","Transações de log:"}. {"Transactions Restarted:","Transações restauradas:"}. {"Tuesday","Terça"}. diff --git a/src/msgs/pt-br.po b/src/msgs/pt-br.po index 791d2d755..5d7bd1a30 100644 --- a/src/msgs/pt-br.po +++ b/src/msgs/pt-br.po @@ -228,8 +228,8 @@ msgid "Backup Management" msgstr "Gestão de copia de segurança" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" -msgstr "Importar usuários de arquivos jabberd 1.4" +msgid "Import Users From jabberd14 Spool Files" +msgstr "Importar usuários de arquivos jabberd14" #: mod_configure.erl:649 msgid "To ~s" @@ -313,16 +313,16 @@ msgid "Import User from File at " msgstr "Importar usuário a partir do arquivo em " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Introduza o caminho para o arquivo de spool do jabberd1.4" +msgid "Enter path to jabberd14 spool file" +msgstr "Introduza o caminho para o arquivo de spool do jabberd14" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Importar usuários a partir do diretório em " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Introduza o caminho para o diretório de spools do jabberd1.4" +msgid "Enter path to jabberd14 spool dir" +msgstr "Introduza o caminho para o diretório de spools do jabberd14" #: mod_configure.erl:995 msgid "Path to Dir" @@ -761,8 +761,8 @@ msgid "Moderator privileges required" msgstr "Se necessita privilégios de moderador" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "O JID ~s não es válido" +msgid "Jabber ID ~s is invalid" +msgstr "O Jabber ID ~s não es válido" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -814,8 +814,8 @@ msgid "No limit" msgstr "Ilimitado" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "Tornar o JID real visível por" +msgid "Present real Jabber IDs to" +msgstr "Tornar o Jabber ID real visível por" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -955,8 +955,8 @@ msgid "Subscriber Address" msgstr "Enderço dos Assinantes" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "Autorizar este JID para a inscrição neste tópico pubsub ?" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "Autorizar este Jabber ID para a inscrição neste tópico pubsub ?" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1439,7 +1439,7 @@ msgid "CPU Time:" msgstr "Tempo de CPU" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Transações:" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/pt.msg b/src/msgs/pt.msg index 71cce8fb6..415424f70 100644 --- a/src/msgs/pt.msg +++ b/src/msgs/pt.msg @@ -38,8 +38,8 @@ {"Enter list of {Module, [Options]}","Introduza lista de {módulos, [opções]}"}. {"Enter nickname you want to register","Introduza a alcunha que quer registar"}. {"Enter path to backup file","Introduza o caminho do ficheiro de cópia de segurança"}. -{"Enter path to jabberd1.4 spool dir","Introduza o caminho para o directório de spools do jabberd1.4"}. -{"Enter path to jabberd1.4 spool file","Introduza o caminho para o ficheiro de spool do jabberd1.4"}. +{"Enter path to jabberd14 spool dir","Introduza o caminho para o directório de spools do jabberd14"}. +{"Enter path to jabberd14 spool file","Introduza o caminho para o ficheiro de spool do jabberd14"}. {"Enter path to text file","Introduza caminho para o ficheiro de texto"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Introduza o nome de utilizador e codificações de caracteres que quer usar ao conectar-se aos servidores de IRC"}. {"Erlang Jabber Server","Servidor Jabber em Erlang"}. @@ -62,7 +62,7 @@ {"IRC Username","Nome do utilizador de IRC"}. {"It is not allowed to send private messages of type \"groupchat\"","Não é permitido enviar mensagens privadas do tipo \"groupchat\""}. {"It is not allowed to send private messages to the conference","Impedir o envio de mensagens privadas para a sala"}. -{"JID ~s is invalid","O JID ~s não é válido"}. +{"Jabber ID ~s is invalid","O JID ~s não é válido"}. {"Last Activity","Última actividade"}. {"Listened Ports at ","Portas em escuta em "}. {"List of modules to start","Lista de módulos a iniciar"}. diff --git a/src/msgs/pt.po b/src/msgs/pt.po index 5afcc47e0..eb158e93f 100644 --- a/src/msgs/pt.po +++ b/src/msgs/pt.po @@ -236,8 +236,8 @@ msgstr "Gestão de cópias de segurança" #: mod_configure.erl:534 #, fuzzy -msgid "Import Users From jabberd 1.4 Spool Files" -msgstr "Importar utilizadores a partir de ficheiros da spool do jabberd1.4" +msgid "Import Users From jabberd14 Spool Files" +msgstr "Importar utilizadores a partir de ficheiros da spool do jabberd14" #: mod_configure.erl:649 msgid "To ~s" @@ -322,16 +322,16 @@ msgid "Import User from File at " msgstr "Importar utilizador a partir do ficheiro em " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Introduza o caminho para o ficheiro de spool do jabberd1.4" +msgid "Enter path to jabberd14 spool file" +msgstr "Introduza o caminho para o ficheiro de spool do jabberd14" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Importar utilizadores a partir do directório em " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Introduza o caminho para o directório de spools do jabberd1.4" +msgid "Enter path to jabberd14 spool dir" +msgstr "Introduza o caminho para o directório de spools do jabberd14" #: mod_configure.erl:995 msgid "Path to Dir" @@ -773,8 +773,8 @@ msgid "Moderator privileges required" msgstr "São necessários privilégios de moderador" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "O JID ~s não é válido" +msgid "Jabber ID ~s is invalid" +msgstr "O Jabber ID ~s não é válido" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -830,7 +830,7 @@ msgid "No limit" msgstr "" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" +msgid "Present real Jabber IDs to" msgstr "" #: mod_muc/mod_muc_room.erl:2741 @@ -987,7 +987,7 @@ msgid "Subscriber Address" msgstr "" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" msgstr "" #: mod_pubsub/mod_pubsub.erl:2497 @@ -1104,7 +1104,7 @@ msgstr "formato inválido" #: mod_roster.erl:855 mod_roster_odbc.erl:962 #, fuzzy msgid "Add Jabber ID" -msgstr "Adicionar JID" +msgstr "Adicionar Jabber ID" #: mod_roster.erl:936 mod_roster_odbc.erl:1043 msgid "Roster" @@ -1501,7 +1501,7 @@ msgstr "Tempo de processador consumido" #: web/ejabberd_web_admin.erl:1874 #, fuzzy -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Transacções realizadas" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/ru.msg b/src/msgs/ru.msg index 93ca02cc6..4ef272f95 100644 --- a/src/msgs/ru.msg +++ b/src/msgs/ru.msg @@ -14,7 +14,7 @@ {"Administrator privileges required","Требуются права администратора"}. {"A friendly name for the node","Легко запоминаемое имя для узла"}. {"All activity","Вся статистика"}. -{"Allow this JID to subscribe to this pubsub node?","Разрешить этому JID подписаться на данный узел?"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Разрешить этому JID подписаться на данный узел?"}. {"Allow users to change subject","Разрешить пользователям изменять тему"}. {"Allow users to query other users","Разрешить iq-запросы к пользователям"}. {"Allow users to send invites","Разрешить пользователям посылать приглашения"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","Введите список вида {Module, [Options]}"}. {"Enter nickname you want to register","Введите псевдоним, который Вы хотели бы зарегистрировать"}. {"Enter path to backup file","Введите путь к резервному файлу"}. -{"Enter path to jabberd1.4 spool dir","Введите путь к директории спула jabberd1.4"}. -{"Enter path to jabberd1.4 spool file","Введите путь к файлу из спула jabberd1.4"}. +{"Enter path to jabberd14 spool dir","Введите путь к директории спула jabberd14"}. +{"Enter path to jabberd14 spool file","Введите путь к файлу из спула jabberd14"}. {"Enter path to text file","Введите путь к текстовому файлу"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Введите имя пользователя и кодировки, которые будут использоваться при подключении к IRC-серверам"}. {"Erlang Jabber Server","Erlang Jabber Server"}. @@ -113,7 +113,7 @@ {"Import File","Импорт из файла"}. {"Import User from File at ","Импорт пользователя из файла на "}. {"Import Users from Dir at ","Импорт пользователей из директории на "}. -{"Import Users From jabberd 1.4 Spool Files","Импорт пользователей из спула jabberd 1.4"}. +{"Import Users From jabberd14 Spool Files","Импорт пользователей из спула jabberd14"}. {"Improper message type","Неправильный тип сообщения"}. {"Incorrect password","Неправильный пароль"}. {"Invalid affiliation: ~s","Недопустимый ранг: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages","Запрещено посылать приватные сообщения"}. {"Jabber ID","Jabber ID"}. {"January","января"}. -{"JID ~s is invalid","JID ~s недопустимый"}. +{"Jabber ID ~s is invalid","JID ~s недопустимый"}. {"joins the room","вошёл(а) в комнату"}. {"July","июля"}. {"June","июня"}. @@ -219,7 +219,7 @@ {"Ping","Пинг"}. {"Pong","Понг"}. {"Port","Порт"}. -{"Present real JIDs to","Сделать реальные JID участников видимыми"}. +{"Present real Jabber IDs to","Сделать реальные JID участников видимыми"}. {"private, ","приватная, "}. {"Publish-Subscribe","Публикация-Подписка"}. {"PubSub subscriber request","Запрос подписчика PubSub"}. @@ -307,7 +307,7 @@ {"To","Кому"}. {"Traffic rate limit is exceeded","Превышен лимит скорости посылки информации"}. {"Transactions Aborted:","Транзакции отмененные:"}. -{"Transactions Commited:","Транзакции завершенные:"}. +{"Transactions Committed:","Транзакции завершенные:"}. {"Transactions Logged:","Транзакции запротоколированные:"}. {"Transactions Restarted:","Транзакции перезапущенные:"}. {"Tuesday","Вторник"}. diff --git a/src/msgs/ru.po b/src/msgs/ru.po index 8c6aa6207..f46e372b3 100644 --- a/src/msgs/ru.po +++ b/src/msgs/ru.po @@ -229,8 +229,8 @@ msgid "Backup Management" msgstr "Управление резервным копированием" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" -msgstr "Импорт пользователей из спула jabberd 1.4" +msgid "Import Users From jabberd14 Spool Files" +msgstr "Импорт пользователей из спула jabberd14" #: mod_configure.erl:649 msgid "To ~s" @@ -314,16 +314,16 @@ msgid "Import User from File at " msgstr "Импорт пользователя из файла на " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Введите путь к файлу из спула jabberd1.4" +msgid "Enter path to jabberd14 spool file" +msgstr "Введите путь к файлу из спула jabberd14" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Импорт пользователей из директории на " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Введите путь к директории спула jabberd1.4" +msgid "Enter path to jabberd14 spool dir" +msgstr "Введите путь к директории спула jabberd14" #: mod_configure.erl:995 msgid "Path to Dir" @@ -754,8 +754,8 @@ msgid "Moderator privileges required" msgstr "Требуются права модератора" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "JID ~s недопустимый" +msgid "Jabber ID ~s is invalid" +msgstr "Jabber ID ~s недопустимый" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -807,8 +807,8 @@ msgid "No limit" msgstr "Не ограничено" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "Сделать реальные JID участников видимыми" +msgid "Present real Jabber IDs to" +msgstr "Сделать реальные Jabber ID участников видимыми" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -951,8 +951,8 @@ msgid "Subscriber Address" msgstr "Адрес подписчика" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "Разрешить этому JID подписаться на данный узел?" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "Разрешить этому Jabber ID подписаться на данный узел?" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1436,7 +1436,7 @@ msgid "CPU Time:" msgstr "Процессорное время:" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Транзакции завершенные:" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/sk.msg b/src/msgs/sk.msg index 25b1f9b03..be3539991 100644 --- a/src/msgs/sk.msg +++ b/src/msgs/sk.msg @@ -6,7 +6,7 @@ {"Access rules","Prístupové pravidlá"}. {"Access Rules","Prístupové pravidlá"}. {"Action on user","Operácia aplikovaná na užívateľa"}. -{"Add Jabber ID","Pridať JID"}. +{"Add Jabber ID","Pridať Jabber ID"}. {"Add New","Pridať nový"}. {"Add User","Pridať používateľa"}. {"Administration","Administrácia"}. @@ -14,7 +14,7 @@ {"Administrator privileges required","Sú potrebné práva administrátora"}. {"A friendly name for the node","Prístupný názov pre uzol"}. {"All activity","Všetky aktivity"}. -{"Allow this JID to subscribe to this pubsub node?","Dovoliť tomuto JID odoberať PubSub uzol?"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Dovoliť tomuto JID odoberať PubSub uzol?"}. {"Allow users to change subject","Povoliť užívateľom zmeniť tému tejto miestnosti"}. {"Allow users to query other users","Povoliť užívateľom dotazovať sa informácie o iných užívateľoch"}. {"Allow users to send invites","Povoliť používateľom posielanie pozvánok"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","Vložte zoznam modulov {Modul, [Parametre]}"}. {"Enter nickname you want to register","Zadajte prezývku, ktorú chcete registrovať"}. {"Enter path to backup file","Zadajte cestu k súboru so zálohou"}. -{"Enter path to jabberd1.4 spool dir","Zadajte cestu k jabberd1.4 spool adresáru"}. -{"Enter path to jabberd1.4 spool file","Zadajte cestu k spool súboru jabberd1.4"}. +{"Enter path to jabberd14 spool dir","Zadajte cestu k jabberd14 spool adresáru"}. +{"Enter path to jabberd14 spool file","Zadajte cestu k spool súboru jabberd14"}. {"Enter path to text file","Zadajte cestu k textovému súboru"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Vložte meno používateľa a kódovanie, ktoré chcete používať pri pripojení na IRC server"}. {"Erlang Jabber Server","Erlang Jabber Server"}. @@ -113,7 +113,7 @@ {"Import File","Import súboru"}. {"Import User from File at ","Importovať užívateľa zo súboru na "}. {"Import Users from Dir at ","Importovať užívateľov z adresára na "}. -{"Import Users From jabberd 1.4 Spool Files","Importovať užívateľov z jabberd 1.4 spool súborov"}. +{"Import Users From jabberd14 Spool Files","Importovať užívateľov z jabberd14 spool súborov"}. {"Improper message type","Nesprávny typ správy"}. {"Incorrect password","Nesprávne heslo"}. {"Invalid affiliation: ~s","Neplatné priradenie: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages to the conference","Nie je povolené odosielať súkromné správy do konferencie"}. {"Jabber ID","Jabber ID"}. {"January","Január"}. -{"JID ~s is invalid","JID ~s je neplatné"}. +{"Jabber ID ~s is invalid","JID ~s je neplatné"}. {"joins the room","vstúpil(a) do miestnosti"}. {"July","Júl"}. {"June","Jún"}. @@ -219,7 +219,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","Port"}. -{"Present real JIDs to","Zobrazovať skutočné JID"}. +{"Present real Jabber IDs to","Zobrazovať skutočné JID"}. {"private, ","súkromná, "}. {"Publish-Subscribe","Publish-Subscribe"}. {"PubSub subscriber request","Žiadosť odberateľa PubSub"}. @@ -307,7 +307,7 @@ {"To ~s","Pre ~s"}. {"Traffic rate limit is exceeded","Bol prekročený prenosový limit"}. {"Transactions Aborted:","Transakcie zrušená"}. -{"Transactions Commited:","Transakcie potvrdená"}. +{"Transactions Committed:","Transakcie potvrdená"}. {"Transactions Logged:","Transakcie zaznamenaná"}. {"Transactions Restarted:","Transakcie reštartovaná"}. {"Tuesday","Utorok"}. diff --git a/src/msgs/sk.po b/src/msgs/sk.po index faa0edd18..1501c2f51 100644 --- a/src/msgs/sk.po +++ b/src/msgs/sk.po @@ -226,8 +226,8 @@ msgid "Backup Management" msgstr "Správa zálohovania" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" -msgstr "Importovať užívateľov z jabberd 1.4 spool súborov" +msgid "Import Users From jabberd14 Spool Files" +msgstr "Importovať užívateľov z jabberd14 spool súborov" #: mod_configure.erl:649 msgid "To ~s" @@ -311,16 +311,16 @@ msgid "Import User from File at " msgstr "Importovať užívateľa zo súboru na " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Zadajte cestu k spool súboru jabberd1.4" +msgid "Enter path to jabberd14 spool file" +msgstr "Zadajte cestu k spool súboru jabberd14" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Importovať užívateľov z adresára na " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Zadajte cestu k jabberd1.4 spool adresáru" +msgid "Enter path to jabberd14 spool dir" +msgstr "Zadajte cestu k jabberd14 spool adresáru" #: mod_configure.erl:995 msgid "Path to Dir" @@ -752,8 +752,8 @@ msgid "Moderator privileges required" msgstr "Sú potrebné práva moderátora" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "JID ~s je neplatné" +msgid "Jabber ID ~s is invalid" +msgstr "Jabber ID ~s je neplatné" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -805,8 +805,8 @@ msgid "No limit" msgstr "Bez limitu" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "Zobrazovať skutočné JID" +msgid "Present real Jabber IDs to" +msgstr "Zobrazovať skutočné Jabber ID" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -946,8 +946,8 @@ msgid "Subscriber Address" msgstr "Adresa odberateľa" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "Dovoliť tomuto JID odoberať PubSub uzol?" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "Dovoliť tomuto Jabber ID odoberať PubSub uzol?" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1059,7 +1059,7 @@ msgstr "Zlý formát" #: mod_roster.erl:855 mod_roster_odbc.erl:962 msgid "Add Jabber ID" -msgstr "Pridať JID" +msgstr "Pridať Jabber ID" #: mod_roster.erl:936 mod_roster_odbc.erl:1043 msgid "Roster" @@ -1430,7 +1430,7 @@ msgid "CPU Time:" msgstr "Čas procesoru" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Transakcie potvrdená" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/sv.msg b/src/msgs/sv.msg index 833839131..4f1d05d1b 100644 --- a/src/msgs/sv.msg +++ b/src/msgs/sv.msg @@ -14,7 +14,7 @@ {"Administrator privileges required","Administrationsprivilegier krävs"}. {"A friendly name for the node","Ett vänligt namn for noden"}. {"All activity","All aktivitet"}. -{"Allow this JID to subscribe to this pubsub node?","Tillåt denna JID att prenumerera på denna pubsub node"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Tillåt denna JID att prenumerera på denna pubsub node"}. {"Allow users to change subject","Tillåt användare att byta ämne"}. {"Allow users to query other users","Tillåt användare att söka efter andra användare"}. {"Allow users to send invites","Tillåt användare att skicka inbjudningar"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","Skriv in en lista av {Module, [Options]}"}. {"Enter nickname you want to register","Skriv in smeknamnet du vill registrera"}. {"Enter path to backup file","Skriv in sökväg till fil för säkerhetskopia"}. -{"Enter path to jabberd1.4 spool dir","Skriv in sökväg till spoolkatalog från jabberd1.4"}. -{"Enter path to jabberd1.4 spool file","Skriv in sökväg till spoolfil från jabberd1.4"}. +{"Enter path to jabberd14 spool dir","Skriv in sökväg till spoolkatalog från jabberd14"}. +{"Enter path to jabberd14 spool file","Skriv in sökväg till spoolfil från jabberd14"}. {"Enter path to text file","Skriv in sökväg till textfil"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Skriv in användarnamn och textkodning du vill använda för att ansluta till IRC-servrar"}. {"Erlang Jabber Server","Erlang Jabber Server"}. @@ -113,7 +113,7 @@ {"Import File","Importera fil"}. {"Import User from File at ","Importera användare från fil på "}. {"Import Users from Dir at ","Importera användare från katalog på "}. -{"Import Users From jabberd 1.4 Spool Files","Importera användare från jabberd 1.4 Spool filer"}. +{"Import Users From jabberd14 Spool Files","Importera användare från jabberd14 Spool filer"}. {"Improper message type","Felaktig medelandetyp"}. {"Incorrect password","Fel lösenord"}. {"Invalid affiliation: ~s","Ogiltlig rang: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages to the conference","Det är inte tillåtet att skicka privata medelanden till den här konferensen"}. {"Jabber ID","Jabber ID"}. {"January","Januari"}. -{"JID ~s is invalid","Otillåtet JID ~s"}. +{"Jabber ID ~s is invalid","Otillåtet JID ~s"}. {"joins the room","joinar rummet"}. {"July","Juli"}. {"June","Juni"}. @@ -219,7 +219,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","Port"}. -{"Present real JIDs to","Nuvarande äkta JIDs till"}. +{"Present real Jabber IDs to","Nuvarande äkta JIDs till"}. {"private, ","privat, "}. {"Publish-Subscribe","Publikprenumeration"}. {"PubSub subscriber request","Pubsub prenumerationsforfrågan"}. @@ -307,7 +307,7 @@ {"To","Till"}. {"Traffic rate limit is exceeded","Trafikgränsen har överstigits"}. {"Transactions Aborted:","Transaktioner borttagna"}. -{"Transactions Commited:","Transaktioner kommittade"}. +{"Transactions Committed:","Transaktioner kommittade"}. {"Transactions Logged:","Transaktioner loggade "}. {"Transactions Restarted:","Transaktioner omstartade"}. {"Tuesday","Tisdag"}. diff --git a/src/msgs/sv.po b/src/msgs/sv.po index 06b5ebec1..bee475848 100644 --- a/src/msgs/sv.po +++ b/src/msgs/sv.po @@ -227,8 +227,8 @@ msgid "Backup Management" msgstr "Hantera säkerhetskopior" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" -msgstr "Importera användare från jabberd 1.4 Spool filer" +msgid "Import Users From jabberd14 Spool Files" +msgstr "Importera användare från jabberd14 Spool filer" #: mod_configure.erl:649 msgid "To ~s" @@ -312,16 +312,16 @@ msgid "Import User from File at " msgstr "Importera användare från fil på " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Skriv in sökväg till spoolfil från jabberd1.4" +msgid "Enter path to jabberd14 spool file" +msgstr "Skriv in sökväg till spoolfil från jabberd14" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Importera användare från katalog på " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Skriv in sökväg till spoolkatalog från jabberd1.4" +msgid "Enter path to jabberd14 spool dir" +msgstr "Skriv in sökväg till spoolkatalog från jabberd14" #: mod_configure.erl:995 msgid "Path to Dir" @@ -756,8 +756,8 @@ msgid "Moderator privileges required" msgstr "Moderatorprivilegier krävs" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "Otillåtet JID ~s" +msgid "Jabber ID ~s is invalid" +msgstr "Otillåtet Jabber ID ~s" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -809,8 +809,8 @@ msgid "No limit" msgstr "Ingen gräns" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "Nuvarande äkta JIDs till" +msgid "Present real Jabber IDs to" +msgstr "Nuvarande äkta Jabber IDs till" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -950,8 +950,8 @@ msgid "Subscriber Address" msgstr "Prenumerationsadress" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "Tillåt denna JID att prenumerera på denna pubsub node" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "Tillåt denna Jabber ID att prenumerera på denna pubsub node" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1432,7 +1432,7 @@ msgid "CPU Time:" msgstr "CPU tid" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Transaktioner kommittade" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/th.msg b/src/msgs/th.msg index 4f26865ff..667e52afa 100644 --- a/src/msgs/th.msg +++ b/src/msgs/th.msg @@ -13,7 +13,7 @@ {"Administration of ","การดูแล "}. {"Administrator privileges required","ต้องมีสิทธิพิเศษของผู้ดูแลระบบ"}. {"All activity","กิจกรรมทั้งหมด"}. -{"Allow this JID to subscribe to this pubsub node?","อนุญาตให้ JID นี้เข้าร่วมเป็นสมาชิกของโหนด pubsub หรือไม่"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","อนุญาตให้ JID นี้เข้าร่วมเป็นสมาชิกของโหนด pubsub หรือไม่"}. {"Allow users to change subject","อนุญาตให้ผู้ใช้เปลี่ยนหัวข้อได้"}. {"Allow users to query other users","อนุญาตให้ผู้ใช้ถามคำถามกับผู้ใช้คนอื่นๆ ได้"}. {"Allow users to send invites","อนุญาตให้ผู้ใช้ส่งคำเชิญถึงกันได้"}. @@ -76,8 +76,8 @@ {"Enter list of {Module, [Options]}","ป้อนรายการของ {โมดูล, [ตัวเลือก]}"}. {"Enter nickname you want to register","ป้อนชื่อเล่นที่คุณต้องการลงทะเบียน"}. {"Enter path to backup file","ป้อนพาธเพื่อสำรองไฟล์ข้อมูล"}. -{"Enter path to jabberd1.4 spool dir","ป้อนพาธไปยัง jabberd 1.4 spool dir"}. -{"Enter path to jabberd1.4 spool file","ป้อนพาธไปยังไฟล์เก็บพักข้อมูล jabberd 1.4"}. +{"Enter path to jabberd14 spool dir","ป้อนพาธไปยัง jabberd14 spool dir"}. +{"Enter path to jabberd14 spool file","ป้อนพาธไปยังไฟล์เก็บพักข้อมูล jabberd14"}. {"Enter path to text file","ป้อนพาธของไฟล์ข้อความ"}. {"Enter username and encodings you wish to use for connecting to IRC servers","ป้อนชื่อผู้ใช้และการเข้ารหัสที่คุณต้องการใช้สำหรับเชื่อมต่อกับเซิร์ฟเวอร์ IRC"}. {"Erlang Jabber Server","Erlang Jabber Server"}. @@ -106,7 +106,7 @@ {"Import File","อิมพอร์ตไฟล์"}. {"Import User from File at ","อิมพอร์ตผู้ใช้จากไฟล์ที่"}. {"Import Users from Dir at ","อิมพอร์ตผู้ใช้จาก Dir ที่"}. -{"Import Users From jabberd 1.4 Spool Files","อิมพอร์ตผู้ใช้จากไฟล์เก็บพักข้อมูล jabberd 1.4"}. +{"Import Users From jabberd14 Spool Files","อิมพอร์ตผู้ใช้จากไฟล์เก็บพักข้อมูล jabberd14"}. {"Improper message type","ประเภทข้อความไม่เหมาะสม"}. {"Incorrect password","รหัสผ่านไม่ถูกต้อง"}. {"Invalid affiliation: ~s","การเข้าร่วมที่ไม่ถูกต้อง: ~s"}. @@ -119,7 +119,7 @@ {"It is not allowed to send private messages to the conference","ไม่อนุญาตให้ส่งข้อความส่วนตัวไปยังห้องประชุม"}. {"Jabber ID","Jabber ID"}. {"January","มกราคม"}. -{"JID ~s is invalid","JID ~s ไม่ถูกต้อง"}. +{"Jabber ID ~s is invalid","JID ~s ไม่ถูกต้อง"}. {"joins the room","เข้าห้องสนทนานี้"}. {"July","กรกฎาคม"}. {"June","มิถุนายน"}. @@ -210,7 +210,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","พอร์ท"}. -{"Present real JIDs to","แสดง JIDs ที่ถูกต้องแก่"}. +{"Present real Jabber IDs to","แสดง JIDs ที่ถูกต้องแก่"}. {"private, ","ส่วนตัว, "}. {"Publish-Subscribe","เผยแพร่-สมัครเข้าใช้งาน"}. {"PubSub subscriber request","คำร้องขอของผู้สมัครเข้าใช้งาน PubSub"}. @@ -294,7 +294,7 @@ {"To ~s","ถึง ~s"}. {"Traffic rate limit is exceeded","อัตราของปริมาณการเข้าใช้เกินขีดจำกัด"}. {"Transactions Aborted:","ทรานแซกชันที่ถูกยกเลิก:"}. -{"Transactions Commited:","ทรานแซกชันที่ได้รับมอบหมาย:"}. +{"Transactions Committed:","ทรานแซกชันที่ได้รับมอบหมาย:"}. {"Transactions Logged:","ทรานแซกชันที่บันทึก:"}. {"Transactions Restarted:","ทรานแซกชันที่เริ่มทำงานใหม่อีกครั้ง:"}. {"Tuesday","วันอังคาร"}. diff --git a/src/msgs/th.po b/src/msgs/th.po index de3beb8ce..c53a2c708 100644 --- a/src/msgs/th.po +++ b/src/msgs/th.po @@ -223,8 +223,8 @@ msgid "Backup Management" msgstr "การจัดการข้อมูลสำรอง" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" -msgstr "อิมพอร์ตผู้ใช้จากไฟล์เก็บพักข้อมูล jabberd 1.4" +msgid "Import Users From jabberd14 Spool Files" +msgstr "อิมพอร์ตผู้ใช้จากไฟล์เก็บพักข้อมูล jabberd14" #: mod_configure.erl:649 msgid "To ~s" @@ -308,16 +308,16 @@ msgid "Import User from File at " msgstr "อิมพอร์ตผู้ใช้จากไฟล์ที่" #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "ป้อนพาธไปยังไฟล์เก็บพักข้อมูล jabberd 1.4" +msgid "Enter path to jabberd14 spool file" +msgstr "ป้อนพาธไปยังไฟล์เก็บพักข้อมูล jabberd14" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "อิมพอร์ตผู้ใช้จาก Dir ที่" #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "ป้อนพาธไปยัง jabberd 1.4 spool dir" +msgid "Enter path to jabberd14 spool dir" +msgstr "ป้อนพาธไปยัง jabberd14 spool dir" #: mod_configure.erl:995 msgid "Path to Dir" @@ -744,8 +744,8 @@ msgid "Moderator privileges required" msgstr "ต้องมีสิทธิพิเศษของผู้ดูแลการสนทนา" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "JID ~s ไม่ถูกต้อง" +msgid "Jabber ID ~s is invalid" +msgstr "Jabber ID ~s ไม่ถูกต้อง" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -797,8 +797,8 @@ msgid "No limit" msgstr "ไม่จำกัด" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "แสดง JIDs ที่ถูกต้องแก่" +msgid "Present real Jabber IDs to" +msgstr "แสดง Jabber IDs ที่ถูกต้องแก่" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -941,8 +941,8 @@ msgid "Subscriber Address" msgstr "ที่อยู่ของผู้สมัคร" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "อนุญาตให้ JID นี้เข้าร่วมเป็นสมาชิกของโหนด pubsub หรือไม่" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "อนุญาตให้ Jabber ID นี้เข้าร่วมเป็นสมาชิกของโหนด pubsub หรือไม่" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1425,7 +1425,7 @@ msgid "CPU Time:" msgstr "เวลาการทำงานของ CPU:" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "ทรานแซกชันที่ได้รับมอบหมาย:" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/tr.msg b/src/msgs/tr.msg index 26bdf85f8..19ab8b577 100644 --- a/src/msgs/tr.msg +++ b/src/msgs/tr.msg @@ -14,7 +14,7 @@ {"Administrator privileges required","Yönetim yetkileri gerekli"}. {"A friendly name for the node","Düğüm için dostane bir isim"}. {"All activity","Tüm aktivite"}. -{"Allow this JID to subscribe to this pubsub node?","Bu JID bu pubsub düğümüne üye olmasına izin verilsin mi?"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Bu JID bu pubsub düğümüne üye olmasına izin verilsin mi?"}. {"Allow users to change subject","Kullanıcıların konu değiştirmesine izin ver"}. {"Allow users to query other users","Kullanıcıların diğer kullanıcıları sorgulamalarına izin ver"}. {"Allow users to send invites","Kullanıcıların davetiye göndermelerine izin ver"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","{Module, [Options]} listesi giriniz"}. {"Enter nickname you want to register","Kaydettirmek istediğiniz takma ismi giriniz"}. {"Enter path to backup file","Yedek dosyasının yolunu giriniz"}. -{"Enter path to jabberd1.4 spool dir","jabberd1.4 spool dosyası için yol giriniz"}. -{"Enter path to jabberd1.4 spool file","jabberd1.4 spool dosyası için yol giriniz"}. +{"Enter path to jabberd14 spool dir","jabberd14 spool dosyası için yol giriniz"}. +{"Enter path to jabberd14 spool file","jabberd14 spool dosyası için yol giriniz"}. {"Enter path to text file","Metin dosyasının yolunu giriniz"}. {"Enter username and encodings you wish to use for connecting to IRC servers","IRC sunuculara bağlanmak için kullanmak istediğiniz kullanıcı isimleri ve kodlamaları giriniz"}. {"Erlang Jabber Server","Erlang Jabber Sunucusu"}. @@ -113,7 +113,7 @@ {"Import File","Dosyayı İçe Aktar"}. {"Import User from File at ","Dosyadan Kullanıcıları İçe Aktar : "}. {"Import Users from Dir at ","Dizinden Kullanıcıları İçe Aktar : "}. -{"Import Users From jabberd 1.4 Spool Files","Jabberd 1.4 Spool Dosyalarından Kullanıcıları İçeri Aktar"}. +{"Import Users From jabberd14 Spool Files","Jabberd 1.4 Spool Dosyalarından Kullanıcıları İçeri Aktar"}. {"Improper message type","Uygunsuz mesaj tipi"}. {"Incorrect password","Yanlış parola"}. {"Invalid affiliation: ~s","Geçersiz ilişki: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages to the conference","Konferansa özel mesajlar gönderilmesine izin verilmiyor"}. {"Jabber ID","Jabber ID"}. {"January","Ocak"}. -{"JID ~s is invalid","JID ~s geçersiz"}. +{"Jabber ID ~s is invalid","JID ~s geçersiz"}. {"joins the room","odaya katıldı"}. {"July","Temmuz"}. {"June","Haziran"}. @@ -219,7 +219,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","Kapı (Port)"}. -{"Present real JIDs to","Gerçek JID'lerini göster :"}. +{"Present real Jabber IDs to","Gerçek JID'lerini göster :"}. {"private, ","özel"}. {"Publish-Subscribe","Yayınla-Üye Ol"}. {"PubSub subscriber request","PubSub üye isteği"}. @@ -307,7 +307,7 @@ {"To ~s","Kime ~s"}. {"Traffic rate limit is exceeded","Trafik oran sınırı aşıldı"}. {"Transactions Aborted:","İptal Edilen Hareketler (Transactions):"}. -{"Transactions Commited:","Tamamlanan Hareketler (Transactions Commited):"}. +{"Transactions Committed:","Tamamlanan Hareketler (Transactions Committed):"}. {"Transactions Logged:","Kaydı Tutulan Hareketler (Transactions):"}. {"Transactions Restarted:","Tekrar Başlatılan Hareketler (Transactions):"}. {"Tuesday","Salı"}. diff --git a/src/msgs/tr.po b/src/msgs/tr.po index f8baf6615..49b9821c2 100644 --- a/src/msgs/tr.po +++ b/src/msgs/tr.po @@ -224,7 +224,7 @@ msgid "Backup Management" msgstr "Yedek Yönetimi" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" +msgid "Import Users From jabberd14 Spool Files" msgstr "Jabberd 1.4 Spool Dosyalarından Kullanıcıları İçeri Aktar" #: mod_configure.erl:649 @@ -309,16 +309,16 @@ msgid "Import User from File at " msgstr "Dosyadan Kullanıcıları İçe Aktar : " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "jabberd1.4 spool dosyası için yol giriniz" +msgid "Enter path to jabberd14 spool file" +msgstr "jabberd14 spool dosyası için yol giriniz" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Dizinden Kullanıcıları İçe Aktar : " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "jabberd1.4 spool dosyası için yol giriniz" +msgid "Enter path to jabberd14 spool dir" +msgstr "jabberd14 spool dosyası için yol giriniz" #: mod_configure.erl:995 msgid "Path to Dir" @@ -755,8 +755,8 @@ msgid "Moderator privileges required" msgstr "Moderatör yetkileri gerekli" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "JID ~s geçersiz" +msgid "Jabber ID ~s is invalid" +msgstr "Jabber ID ~s geçersiz" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -808,8 +808,8 @@ msgid "No limit" msgstr "Sınırsız" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "Gerçek JID'lerini göster :" +msgid "Present real Jabber IDs to" +msgstr "Gerçek Jabber ID'lerini göster :" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -952,8 +952,8 @@ msgid "Subscriber Address" msgstr "Üye Olanın Adresi" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "Bu JID bu pubsub düğümüne üye olmasına izin verilsin mi?" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "Bu Jabber ID bu pubsub düğümüne üye olmasına izin verilsin mi?" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1437,8 +1437,8 @@ msgid "CPU Time:" msgstr "İşlemci Zamanı:" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" -msgstr "Tamamlanan Hareketler (Transactions Commited):" +msgid "Transactions Committed:" +msgstr "Tamamlanan Hareketler (Transactions Committed):" #: web/ejabberd_web_admin.erl:1877 msgid "Transactions Aborted:" diff --git a/src/msgs/uk.msg b/src/msgs/uk.msg index a35bc83ef..e37b1d163 100644 --- a/src/msgs/uk.msg +++ b/src/msgs/uk.msg @@ -14,7 +14,7 @@ {"Administrator privileges required","Необхідні права адміністратора"}. {"A friendly name for the node","Псевдонім для вузла"}. {"All activity","Вся статистика"}. -{"Allow this JID to subscribe to this pubsub node?","Чи дозволити цьому JID абонувати новини наданого вузла"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Чи дозволити цьому JID абонувати новини наданого вузла"}. {"Allow users to change subject","Дозволити користувачам змінювати тему"}. {"Allow users to query other users","Дозволити iq-запити до користувачів"}. {"Allow users to send invites","Дозволити користувачам надсилати запрошення"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","Введіть перелік такого виду {Module, [Options]}"}. {"Enter nickname you want to register","Введіть псевдонім, який ви хочете зареєструвати"}. {"Enter path to backup file","Введіть шлях до резервного файла"}. -{"Enter path to jabberd1.4 spool dir","Введіть шлях до директорії спула jabberd1.4"}. -{"Enter path to jabberd1.4 spool file","Введіть шлях до файла зі спула jabberd1.4"}. +{"Enter path to jabberd14 spool dir","Введіть шлях до директорії спула jabberd14"}. +{"Enter path to jabberd14 spool file","Введіть шлях до файла зі спула jabberd14"}. {"Enter path to text file","Введіть шлях до текстового файла"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Введіть ім'я користувача та кодування, які будуть використовуватися при підключенні до IRC-серверів"}. {"Erlang Jabber Server","Erlang Jabber Server"}. @@ -113,7 +113,7 @@ {"Import File","Імпорт з файла"}. {"Import User from File at ","Імпортування користувача з файла на "}. {"Import Users from Dir at ","Імпортування користувача з директорії на "}. -{"Import Users From jabberd 1.4 Spool Files","Імпорт користувачів зі спулу jabberd 1.4"}. +{"Import Users From jabberd14 Spool Files","Імпорт користувачів зі спулу jabberd14"}. {"Improper message type","Неправильний тип повідомлення"}. {"Incorrect password","Неправильний пароль"}. {"Invalid affiliation: ~s","Недопустимий ранг: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages","Приватні повідомлення не дозволені"}. {"Jabber ID","Jabber ID"}. {"January","січня"}. -{"JID ~s is invalid","JID ~s недопустимий"}. +{"Jabber ID ~s is invalid","JID ~s недопустимий"}. {"joins the room","увійшов(ла) в кімнату"}. {"July","липня"}. {"June","червня"}. @@ -219,7 +219,7 @@ {"Ping","Пінг"}. {"Pong","Понг"}. {"Port","Порт"}. -{"Present real JIDs to","Зробити реальні JID учасників видимими"}. +{"Present real Jabber IDs to","Зробити реальні JID учасників видимими"}. {"private, ","приватна, "}. {"Publish-Subscribe","Опублікувати-Абонувати"}. {"PubSub subscriber request","Запит на абонування PubSub"}. @@ -307,7 +307,7 @@ {"To","Кому"}. {"Traffic rate limit is exceeded","Швидкість передачі інформації було перевищено"}. {"Transactions Aborted:","Транзакції відмінені:"}. -{"Transactions Commited:","Транзакції завершені:"}. +{"Transactions Committed:","Транзакції завершені:"}. {"Transactions Logged:","Транзакції запротокольовані:"}. {"Transactions Restarted:","Транзакції перезапущені:"}. {"Tuesday","Вівторок"}. diff --git a/src/msgs/uk.po b/src/msgs/uk.po index 2eebfdad0..d43a85438 100644 --- a/src/msgs/uk.po +++ b/src/msgs/uk.po @@ -229,8 +229,8 @@ msgid "Backup Management" msgstr "Керування резервним копіюванням" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" -msgstr "Імпорт користувачів зі спулу jabberd 1.4" +msgid "Import Users From jabberd14 Spool Files" +msgstr "Імпорт користувачів зі спулу jabberd14" #: mod_configure.erl:649 msgid "To ~s" @@ -314,16 +314,16 @@ msgid "Import User from File at " msgstr "Імпортування користувача з файла на " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Введіть шлях до файла зі спула jabberd1.4" +msgid "Enter path to jabberd14 spool file" +msgstr "Введіть шлях до файла зі спула jabberd14" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Імпортування користувача з директорії на " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Введіть шлях до директорії спула jabberd1.4" +msgid "Enter path to jabberd14 spool dir" +msgstr "Введіть шлях до директорії спула jabberd14" #: mod_configure.erl:995 msgid "Path to Dir" @@ -756,8 +756,8 @@ msgid "Moderator privileges required" msgstr "Необхідні права модератора" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "JID ~s недопустимий" +msgid "Jabber ID ~s is invalid" +msgstr "Jabber ID ~s недопустимий" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -809,8 +809,8 @@ msgid "No limit" msgstr "Без обмежень" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "Зробити реальні JID учасників видимими" +msgid "Present real Jabber IDs to" +msgstr "Зробити реальні Jabber ID учасників видимими" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -953,8 +953,8 @@ msgid "Subscriber Address" msgstr "Адреса абонента" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "Чи дозволити цьому JID абонувати новини наданого вузла" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "Чи дозволити цьому Jabber ID абонувати новини наданого вузла" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1438,7 +1438,7 @@ msgid "CPU Time:" msgstr "Процесорний час:" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Транзакції завершені:" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/vi.msg b/src/msgs/vi.msg index 77783bd42..01b3d99b4 100644 --- a/src/msgs/vi.msg +++ b/src/msgs/vi.msg @@ -13,7 +13,7 @@ {"Administration","Quản trị"}. {"Administrator privileges required","Yêu cầu đặc quyền của nhà quản trị"}. {"All activity","Tất cả hoạt động"}. -{"Allow this JID to subscribe to this pubsub node?","Cho phép JID đăng ký nút môđun xuất bản đăng ký này không?"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Cho phép JID đăng ký nút môđun xuất bản đăng ký này không?"}. {"Allow users to change subject","Cho phép người sử dụng thay đổi chủ đề"}. {"Allow users to query other users","Cho phép người sử dụng hỏi người sử dụng khác"}. {"Allow users to send invites","Cho phép người sử dụng gửi lời mời"}. @@ -76,8 +76,8 @@ {"Enter list of {Module, [Options]}","Nhập danh sách {Môđun, [Các Tùy Chọn]}"}. {"Enter nickname you want to register","Nhập bí danh bạn muốn đăng ký"}. {"Enter path to backup file","Nhập đường dẫn đến tập tin sao lưu dự phòng"}. -{"Enter path to jabberd1.4 spool dir","Nhập đường dẫn đến thư mục spool jabberd1,4"}. -{"Enter path to jabberd1.4 spool file","Nhập đường dẫn đến tập tin spool jabberd1,4"}. +{"Enter path to jabberd14 spool dir","Nhập đường dẫn đến thư mục spool jabberd14"}. +{"Enter path to jabberd14 spool file","Nhập đường dẫn đến tập tin spool jabberd14"}. {"Enter path to text file","Nhập đường dẫn đến tập tin văn bản"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Nhập tên truy cập và mã hóa mà bạn muốn sử dụng khi kết nối với các máy chủ IRC"}. {"Erlang Jabber Server","Erlang Jabber Server Bản quyền"}. @@ -106,7 +106,7 @@ {"Import File","Nhập Tập Tin"}. {"Import User from File at ","Nhập Người Sử Dụng từ Tập Tin tại"}. {"Import Users from Dir at ","Nhập Người Sử Dụng từ Thư Mục tại"}. -{"Import Users From jabberd 1.4 Spool Files","Nhập Người Sử Dụng Từ Các Tập Tin Spool jabberd 1,4"}. +{"Import Users From jabberd14 Spool Files","Nhập Người Sử Dụng Từ Các Tập Tin Spool jabberd14"}. {"Improper message type","Loại thư không phù hợp"}. {"Incorrect password","Mật khẩu sai"}. {"Invalid affiliation: ~s","Tư cách không hợp lệ: ~s"}. @@ -119,7 +119,7 @@ {"It is not allowed to send private messages to the conference","Không được phép gửi những thư riêng đến phòng họp"}. {"Jabber ID","Jabber ID"}. {"January","Tháng Một"}. -{"JID ~s is invalid","JID ~s không hợp lệ"}. +{"Jabber ID ~s is invalid","JID ~s không hợp lệ"}. {"joins the room","tham gia phòng này"}. {"July","Tháng Bảy"}. {"June","Tháng Sáu"}. @@ -210,7 +210,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","Cổng"}. -{"Present real JIDs to","JID thực tế hiện hành đến"}. +{"Present real Jabber IDs to","JID thực tế hiện hành đến"}. {"private, ","riêng,"}. {"Publish-Subscribe","Xuất Bản-Đăng Ký"}. {"PubSub subscriber request","Yêu cầu người đăng ký môđun Xuất Bản Đăng Ký"}. @@ -294,7 +294,7 @@ {"To ~s","Gửi đến ~s"}. {"Traffic rate limit is exceeded","Quá giới hạn tỷ lệ lưu lượng truyền tải"}. {"Transactions Aborted:","Giao Dịch Hủy Bỏ:"}. -{"Transactions Commited:","Giao Dịch Được Cam Kết:"}. +{"Transactions Committed:","Giao Dịch Được Cam Kết:"}. {"Transactions Logged:","Giao Dịch Được Ghi Nhận:"}. {"Transactions Restarted:","Giao Dịch Khởi Động Lại:"}. {"Tuesday","Thứ Ba"}. diff --git a/src/msgs/vi.po b/src/msgs/vi.po index 8cdb0c945..963841636 100644 --- a/src/msgs/vi.po +++ b/src/msgs/vi.po @@ -226,8 +226,8 @@ msgid "Backup Management" msgstr "Quản lý Sao Lưu Dự Phòng" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" -msgstr "Nhập Người Sử Dụng Từ Các Tập Tin Spool jabberd 1,4" +msgid "Import Users From jabberd14 Spool Files" +msgstr "Nhập Người Sử Dụng Từ Các Tập Tin Spool jabberd14" #: mod_configure.erl:649 msgid "To ~s" @@ -311,16 +311,16 @@ msgid "Import User from File at " msgstr "Nhập Người Sử Dụng từ Tập Tin tại" #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Nhập đường dẫn đến tập tin spool jabberd1,4" +msgid "Enter path to jabberd14 spool file" +msgstr "Nhập đường dẫn đến tập tin spool jabberd14" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Nhập Người Sử Dụng từ Thư Mục tại" #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Nhập đường dẫn đến thư mục spool jabberd1,4" +msgid "Enter path to jabberd14 spool dir" +msgstr "Nhập đường dẫn đến thư mục spool jabberd14" #: mod_configure.erl:995 msgid "Path to Dir" @@ -757,8 +757,8 @@ msgid "Moderator privileges required" msgstr "Yêu cầu đặc quyền của nhà điều phối" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "JID ~s không hợp lệ" +msgid "Jabber ID ~s is invalid" +msgstr "Jabber ID ~s không hợp lệ" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -810,8 +810,8 @@ msgid "No limit" msgstr "Không giới hạn" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "JID thực tế hiện hành đến" +msgid "Present real Jabber IDs to" +msgstr "Jabber ID thực tế hiện hành đến" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -957,8 +957,8 @@ msgid "Subscriber Address" msgstr "Địa Chỉ Người Đăng Ký" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "Cho phép JID đăng ký nút môđun xuất bản đăng ký này không?" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "Cho phép Jabber ID đăng ký nút môđun xuất bản đăng ký này không?" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1446,7 +1446,7 @@ msgid "CPU Time:" msgstr "Thời Gian CPU:" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Giao Dịch Được Cam Kết:" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/wa.msg b/src/msgs/wa.msg index c032ca866..5b5c8f9cd 100644 --- a/src/msgs/wa.msg +++ b/src/msgs/wa.msg @@ -14,7 +14,7 @@ {"Administrator privileges required","I fåt des priviledjes di manaedjeu"}. {"A friendly name for the node","On no uzeu-ahessåve pol nuk"}. {"All activity","Dispoy todi"}. -{"Allow this JID to subscribe to this pubsub node?","Permete ki ci JID ci si poye abouner a ç' nuk eplaidaedje-abounmint ci?"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","Permete ki ci JID ci si poye abouner a ç' nuk eplaidaedje-abounmint ci?"}. {"Allow users to change subject","Les uzeus polèt candjî l' tite"}. {"Allow users to query other users","Les uzeus polèt cweri ls ôtes uzeus"}. {"Allow users to send invites","Les uzeus polèt evoyî priyaedjes"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","Dinez ene djivêye del cogne {Module, [Tchuzes]}"}. {"Enter nickname you want to register","Dinez l' metou no ki vos vloz edjîstrer"}. {"Enter path to backup file","Dinez l' tchimin viè l' fitchî copeye di såvrité"}. -{"Enter path to jabberd1.4 spool dir","Dinez l' tchimin viè l' ridant di spool jabberd1.4"}. -{"Enter path to jabberd1.4 spool file","Dinez l' tchimin viè l' fitchî di spool jabberd1.4"}. +{"Enter path to jabberd14 spool dir","Dinez l' tchimin viè l' ridant di spool jabberd14"}. +{"Enter path to jabberd14 spool file","Dinez l' tchimin viè l' fitchî di spool jabberd14"}. {"Enter path to text file","Dinez l' tchimin viè l' fitchî tecse"}. {"Enter username and encodings you wish to use for connecting to IRC servers","Dinez les nos d' uzeu et ls ecôdaedjes ki vos vloz eployî po vs raloyî åzès sierveus IRC"}. {"Erlang Jabber Server","Sierveu Jabber Erlang"}. @@ -113,7 +113,7 @@ {"Import File","Sititchî d' on fitchî"}. {"Import User from File at ","Sititchî uzeu d' on fitchî so "}. {"Import Users from Dir at ","Sitichî des uzeus d' on ridant so "}. -{"Import Users From jabberd 1.4 Spool Files","Sititchî des uzeus Jabberd 1.4"}. +{"Import Users From jabberd14 Spool Files","Sititchî des uzeus Jabberd 1.4"}. {"Improper message type","Sôre di messaedje nén valide"}. {"Incorrect password","Sicret nén corek"}. {"Invalid affiliation: ~s","Afiyaedje nén valide: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages to the conference","On n' pout nén evoyî des messaedjes privés dins cisse conferince ci"}. {"Jabber ID","ID Jabber"}. {"January","djanvî"}. -{"JID ~s is invalid","Li JID ~s n' est nén valide"}. +{"Jabber ID ~s is invalid","Li JID ~s n' est nén valide"}. {"joins the room","arive sol såle"}. {"July","djulete"}. {"June","djun"}. @@ -219,7 +219,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","Pôrt"}. -{"Present real JIDs to","Mostrer les vraiys JIDs a"}. +{"Present real Jabber IDs to","Mostrer les vraiys JIDs a"}. {"private, ","privé, "}. {"Publish-Subscribe","Eplaidaedje-abounmint"}. {"PubSub subscriber request","Dimande d' eplaidaedje-abounmint d' èn abouné"}. @@ -307,7 +307,7 @@ {"To ~s","Viè ~s"}. {"Traffic rate limit is exceeded","Li limite pol volume di trafik a stî passêye"}. {"Transactions Aborted:","Transaccions arestêyes:"}. -{"Transactions Commited:","Transaccions evoyeyes:"}. +{"Transactions Committed:","Transaccions evoyeyes:"}. {"Transactions Logged:","Transaccions wårdêyes e djournå:"}. {"Transactions Restarted:","Transaccions renondêyes:"}. {"Tuesday","mårdi"}. diff --git a/src/msgs/wa.po b/src/msgs/wa.po index 9dd938183..024844d1e 100644 --- a/src/msgs/wa.po +++ b/src/msgs/wa.po @@ -224,7 +224,7 @@ msgid "Backup Management" msgstr "Manaedjaedje des copeyes di såvrité" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" +msgid "Import Users From jabberd14 Spool Files" msgstr "Sititchî des uzeus Jabberd 1.4" #: mod_configure.erl:649 @@ -309,16 +309,16 @@ msgid "Import User from File at " msgstr "Sititchî uzeu d' on fitchî so " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "Dinez l' tchimin viè l' fitchî di spool jabberd1.4" +msgid "Enter path to jabberd14 spool file" +msgstr "Dinez l' tchimin viè l' fitchî di spool jabberd14" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "Sitichî des uzeus d' on ridant so " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "Dinez l' tchimin viè l' ridant di spool jabberd1.4" +msgid "Enter path to jabberd14 spool dir" +msgstr "Dinez l' tchimin viè l' ridant di spool jabberd14" #: mod_configure.erl:995 msgid "Path to Dir" @@ -760,8 +760,8 @@ msgid "Moderator privileges required" msgstr "I fåt des priviledjes di moderateu" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "Li JID ~s n' est nén valide" +msgid "Jabber ID ~s is invalid" +msgstr "Li Jabber ID ~s n' est nén valide" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -813,8 +813,8 @@ msgid "No limit" msgstr "Pont d' limite" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "Mostrer les vraiys JIDs a" +msgid "Present real Jabber IDs to" +msgstr "Mostrer les vraiys Jabber IDs a" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -958,9 +958,9 @@ msgid "Subscriber Address" msgstr "Adresse di l' abouné" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" msgstr "" -"Permete ki ci JID ci si poye abouner a ç' nuk eplaidaedje-abounmint ci?" +"Permete ki ci Jabber ID ci si poye abouner a ç' nuk eplaidaedje-abounmint ci?" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1445,7 +1445,7 @@ msgid "CPU Time:" msgstr "Tins CPU:" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "Transaccions evoyeyes:" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/msgs/zh.msg b/src/msgs/zh.msg index 82d0d1fae..1187bc2c4 100644 --- a/src/msgs/zh.msg +++ b/src/msgs/zh.msg @@ -14,7 +14,7 @@ {"Administrator privileges required","需要管理员权限"}. {"A friendly name for the node","该节点的友好名称"}. {"All activity","所有活动"}. -{"Allow this JID to subscribe to this pubsub node?","允许该JID订阅该pubsub节点?"}. +{"Allow this Jabber ID to subscribe to this pubsub node?","允许该JID订阅该pubsub节点?"}. {"Allow users to change subject","允许用户更改主题"}. {"Allow users to query other users","允许用户查询其它用户"}. {"Allow users to send invites","允许用户发送邀请"}. @@ -80,8 +80,8 @@ {"Enter list of {Module, [Options]}","请输入{模块, [选项]}列表"}. {"Enter nickname you want to register","请输入您想要注册的昵称"}. {"Enter path to backup file","请输入备份文件的路径"}. -{"Enter path to jabberd1.4 spool dir","请输入jabberd1.4 spool目录的路径"}. -{"Enter path to jabberd1.4 spool file","请输入jabberd1.4 spool文件的路径"}. +{"Enter path to jabberd14 spool dir","请输入jabberd14 spool目录的路径"}. +{"Enter path to jabberd14 spool file","请输入jabberd14 spool文件的路径"}. {"Enter path to text file","请输入文本文件的路径"}. {"Enter username and encodings you wish to use for connecting to IRC servers","请输入您想使用的用来连接到IRC服务器的用户名和编码"}. {"Erlang Jabber Server","Erlang Jabber 服务器"}. @@ -113,7 +113,7 @@ {"Import File","导入文件"}. {"Import User from File at ","导入用户的文件位于 "}. {"Import Users from Dir at ","导入用户的目录位于 "}. -{"Import Users From jabberd 1.4 Spool Files","从Jabberd 1.4 Spool文件导入用户"}. +{"Import Users From jabberd14 Spool Files","从Jabberd 1.4 Spool文件导入用户"}. {"Improper message type","消息类型不恰当"}. {"Incorrect password","密码不正确"}. {"Invalid affiliation: ~s","无效加入: ~s"}. @@ -127,7 +127,7 @@ {"It is not allowed to send private messages","不允许发送私聊消息"}. {"Jabber ID","Jabber ID"}. {"January","一月"}. -{"JID ~s is invalid","JID ~s无效"}. +{"Jabber ID ~s is invalid","JID ~s无效"}. {"joins the room","加入房间"}. {"July","七月"}. {"June","六月"}. @@ -219,7 +219,7 @@ {"Ping","Ping"}. {"Pong","Pong"}. {"Port","端口"}. -{"Present real JIDs to","将真实JID显示给"}. +{"Present real Jabber IDs to","将真实JID显示给"}. {"private, ","保密"}. {"Publish-Subscribe","发布-订阅"}. {"PubSub subscriber request","PubSub订阅人请求"}. @@ -307,7 +307,7 @@ {"To","到"}. {"Traffic rate limit is exceeded","已经超过传输率限制"}. {"Transactions Aborted:","取消的事务:"}. -{"Transactions Commited:","提交的事务:"}. +{"Transactions Committed:","提交的事务:"}. {"Transactions Logged:","记入日志的事务:"}. {"Transactions Restarted:","重启的事务:"}. {"Tuesday","星期二"}. diff --git a/src/msgs/zh.po b/src/msgs/zh.po index 91169c305..06e67e682 100644 --- a/src/msgs/zh.po +++ b/src/msgs/zh.po @@ -225,7 +225,7 @@ msgid "Backup Management" msgstr "备份管理" #: mod_configure.erl:534 -msgid "Import Users From jabberd 1.4 Spool Files" +msgid "Import Users From jabberd14 Spool Files" msgstr "从Jabberd 1.4 Spool文件导入用户" #: mod_configure.erl:649 @@ -310,16 +310,16 @@ msgid "Import User from File at " msgstr "导入用户的文件位于 " #: mod_configure.erl:980 -msgid "Enter path to jabberd1.4 spool file" -msgstr "请输入jabberd1.4 spool文件的路径" +msgid "Enter path to jabberd14 spool file" +msgstr "请输入jabberd14 spool文件的路径" #: mod_configure.erl:990 msgid "Import Users from Dir at " msgstr "导入用户的目录位于 " #: mod_configure.erl:994 -msgid "Enter path to jabberd1.4 spool dir" -msgstr "请输入jabberd1.4 spool目录的路径" +msgid "Enter path to jabberd14 spool dir" +msgstr "请输入jabberd14 spool目录的路径" #: mod_configure.erl:995 msgid "Path to Dir" @@ -743,8 +743,8 @@ msgid "Moderator privileges required" msgstr "需要调解人权限" #: mod_muc/mod_muc_room.erl:2198 -msgid "JID ~s is invalid" -msgstr "JID ~s无效" +msgid "Jabber ID ~s is invalid" +msgstr "Jabber ID ~s无效" #: mod_muc/mod_muc_room.erl:2212 msgid "Nickname ~s does not exist in the room" @@ -796,8 +796,8 @@ msgid "No limit" msgstr "不限" #: mod_muc/mod_muc_room.erl:2733 -msgid "Present real JIDs to" -msgstr "将真实JID显示给" +msgid "Present real Jabber IDs to" +msgstr "将真实Jabber ID显示给" #: mod_muc/mod_muc_room.erl:2741 msgid "moderators only" @@ -937,8 +937,8 @@ msgid "Subscriber Address" msgstr "订阅人地址" #: mod_pubsub/mod_pubsub.erl:1016 -msgid "Allow this JID to subscribe to this pubsub node?" -msgstr "允许该JID订阅该pubsub节点?" +msgid "Allow this Jabber ID to subscribe to this pubsub node?" +msgstr "允许该Jabber ID订阅该pubsub节点?" #: mod_pubsub/mod_pubsub.erl:2497 msgid "Deliver payloads with event notifications" @@ -1416,7 +1416,7 @@ msgid "CPU Time:" msgstr "CPU时间:" #: web/ejabberd_web_admin.erl:1874 -msgid "Transactions Commited:" +msgid "Transactions Committed:" msgstr "提交的事务:" #: web/ejabberd_web_admin.erl:1877 diff --git a/src/tls/Makefile.win32 b/src/tls/Makefile.win32 index 93ec8471d..4ead4f26e 100644 --- a/src/tls/Makefile.win32 +++ b/src/tls/Makefile.win32 @@ -23,7 +23,7 @@ $(OUTDIR)\tls.beam : tls.erl erlc -W $(EFLAGS) -o $(OUTDIR) tls.erl CC=cl.exe -CC_FLAGS=-nologo -D__WIN32__ -DWIN32 -DWINDOWS -D_WIN32 -DNT -MD -Ox -I"$(ERLANG_DIR)\usr\include" -I"$(EI_DIR)\include" -I"$(OPENSSL_DIR)\include" +CC_FLAGS=-nologo -D__WIN32__ -DWIN32 -DWINDOWS -D_WIN32 -DNT -MD -Ox -I"$(ERLANG_DIR)\usr\include" -I"$(EI_DIR)\include" -I"$(OPENSSL_DIR)\include" -I"." LD=link.exe LD_FLAGS=-release -nologo -incremental:no -dll "$(EI_DIR)\lib\ei_md.lib" "$(EI_DIR)\lib\erl_interface_md.lib" "$(OPENSSL_DIR)\lib\VC\ssleay32MD.lib" "$(OPENSSL_DIR)\lib\VC\libeay32MD.lib" MSVCRT.LIB kernel32.lib advapi32.lib gdi32.lib user32.lib comctl32.lib comdlg32.lib shell32.lib diff --git a/src/tls/stdint.h b/src/tls/stdint.h new file mode 100755 index 000000000..e032ff160 --- /dev/null +++ b/src/tls/stdint.h @@ -0,0 +1,232 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2008 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include + +// For Visual Studio 6 in C++ mode wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#if (_MSC_VER < 1300) && defined(__cplusplus) + extern "C++" { +#endif +# include +#if (_MSC_VER < 1300) && defined(__cplusplus) + } +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types +typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +#define INTMAX_C INT64_C +#define UINTMAX_C UINT64_C + +#endif // __STDC_CONSTANT_MACROS ] + + +#endif // _MSC_STDINT_H_ ] diff --git a/src/tls/tls_drv.c b/src/tls/tls_drv.c index ac438ebca..3ca8ba777 100644 --- a/src/tls/tls_drv.c +++ b/src/tls/tls_drv.c @@ -25,10 +25,8 @@ #include #include #include -#include #include - #define BUF_SIZE 1024 typedef struct { diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 2e8f5c59d..aa5121bfd 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -161,7 +161,7 @@ make_xhtml(Els, Host, Node, Lang) -> [?XAE('div', [#xmlattr{name = 'id', value = "header"}], [?XE('h1', - [?ACT("/admin/", "Administration")] + [?ACT("/admin/", "ejabberd Web Admin")] )]), ?XAE('div', [#xmlattr{name = 'id', value = "navigation"}], @@ -316,6 +316,7 @@ ul li #navhead a, ul li #navheadsub a, ul li #navheadsubsub a { text-align: center; border-top: 2px solid #d47911; border-bottom: 1px solid #d47911; + background: #FED6A6; } #navheadsub, #navitemsub { @@ -371,10 +372,6 @@ textarea { border: 1px solid #d6760e; color: #723202; background-color: #fff2e8; - vertical-align: middle; - margin-top: 7px; - margin-bottom: 5px; - padding: 0.1em; } select { @@ -542,6 +539,19 @@ div.guidelink { padding-right: 1em; } +table.withtextareas>tbody>tr>td { + vertical-align: top; +} + +p.result { + border: 1px; + border-style: dashed; + border-color: #FE8A02; + padding: 1em; + margin-right: 1em; + background: #FFE3C9; +} + *.alignright { font-size: 10pt; } @@ -561,27 +571,26 @@ favicon() -> logo() -> jlib:decode_base64( - "iVBORw0KGgoAAAANSUhEUgAAAVcAAAA3CAMAAACPbPnEAAAAYFBMVEX///8C" - "AgJyMgL+vm7Wdg7+igL+/v7+slb+qkb+4sr+ojP+nir+lhr+1qb+khL+wnb+" - "wn7+zpb+jgb+yoz+xo7+tmL+pj7+mib+jg7+5sb+rlL+rkr+mh7+tl7+2q7+" - "umpJ0uikAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIA" - "AAsSAdLdfvwAAAAHdElNRQfUBAUJBhWzc9qJAAABQ0lEQVR42u2bXU/CQBBF" - "UUZFURAU5Ev4//+S3Ow+tFl3s6adtE3Oebghzc4DJ/Nw04WZgQczexJkz4lX" - "vOKVxKuXV6APTCFXAq94xSte8ermFYbrA6+ilemZRxGz+fxBxMydL0/Vz5an" - "vkUrPfb1IPCKV7ziFa9uXsG/DzyLPz7ndjS3tc3tSbcwPdl9tmYq3dHmk9x3" - "r8mtiM11KfCKV7ziFa9uXmEc7wf+u6+5TtlXf62fKu9rl3wX9ibsLPCKV7zi" - "Fa9uXmF87wf67aBT6a+hp4bOehFxU0/CbgKveMUrXvHq5hXG+vuBcpss75zH" - "/VZ5X7vcb4W7q5A/wvbCXoTNhX0JvOIVr3jFq5tX4P8Fw2V6g7UQ9itsLeKm" - "fgi84hWveMWrm1egDwyX6Q3WTtinsI2wq7CjwCte8YpXvLp5BQ/utIiGbwh9" - "RAEAAAAASUVORK5CYII="). + "iVBORw0KGgoAAAANSUhEUgAAAVcAAAA3CAMAAACPbPnEAAAAAXNSR0IArs4c" + "6QAAAEtQTFRFcTIA1XcE/YsA/40E/pIH/JYc/5kg/54i/KIu/6U6/apE/61H" + "/61P/bFX/7Vh/bda/rpq/L5s/8J2/cJ8/8qI/86Y/9aj/9mt/+bJ7EGiPwAA" + "AZRJREFUeNrt28lug0AQhGHajrPv+/s/aVwpDlgE0gQ3tqO/DhxihMg33VJ7" + "JmmCVKSJlVJ4bZQ93Jl/zjJv+8tzcMUVV1xxLXIlRfPAZptYrbf5YeW618PW" + "yvG8w/g9ZwquuJ6Y6+bbdY0rrifhSmrmgUulVXbVDq3H39Zy6Cf9+8c7JNM/" + "mXeY8+SMRmuIK6644oprkSupmQdulLhQdup1qJKmrmWmVpb5NN9LUyddu7nn" + "LYkrrrjiimuVK6mZB+6VuFbiXJk8v/bnv0PVa+Yd5tdr/x7vCfqbgPsfV1xx" + "xRXXKldSMw+8KPGgxJWyU7WZE538p0vOr/lOm/q7dPf+bOVKvVXiUcEVV1xx" + "xbXMldTMA29KPCtxp7T6XpvxE6/9nm/l987mnG9l5u/8jO4Ot9uTEq8Krrji" + "iiuuZa6kZh74UFpli3sO61btMfyHyWGv/RMs7wB67ne32/BdwRVXXHHFtcyV" + "1MwDn0qrbHHvyPT/Dsarla/R/1GpQydYPhf0bqC/A7jz7YkrrrjiimuVK6nI" + "F5dWoNvcLcs/AAAAAElFTkSuQmCC"). logo_fill() -> jlib:decode_base64( - "iVBORw0KGgoAAAANSUhEUgAAAAYAAAA3BAMAAADdxCZzAAAAHlBMVEXWdg7+" - "igL+jg7+khL+nir+rkr+umr+yoz+1qb+5sbOf9L8AAAACXBIWXMAAA9hAAAP" - "YQGoP6dpAAAAQUlEQVQI12XDSxHAIBAFQT6BJEcsYAELWMACFtYCFnAL7zxd" - "1c5dvhSU2BpKqBXl6R0ljYGS50R5zVC+tVD+vfE6YyUexE9x7g4AAAAASUVO" - "RK5CYII="). + "iVBORw0KGgoAAAANSUhEUgAAAAYAAAA3BAMAAADdxCZzAAAAAXNSR0IArs4c" + "6QAAAB5QTFRF1nYO/ooC/o4O/pIS/p4q/q5K/rpq/sqM/tam/ubGzn/S/AAA" + "AEFJREFUCNdlw0sRwCAQBUE+gSRHLGABC1jAAhbWAhZwC+88XdXOXb4UlFAr" + "SmwN5ekdJY2BkudEec1QvrVQ/r3xOlK9HsTvertmAAAAAElFTkSuQmCC"). process_admin(global, @@ -638,6 +647,7 @@ process_admin(Host, #request{path = ["acls-raw"], q = Query, lang = Lang}) -> + Res = case lists:keysearch("acls", 1, Query) of {value, {_, String}} -> case erl_scan:string(String) of @@ -659,22 +669,17 @@ process_admin(Host, _ -> nothing end, - ACLs = lists:flatten( - io_lib:format( - "~p.", [lists:keysort( - 2, ets:select(acl, [{{acl, {'$1', Host}, '$2'}, - [], [{{acl, '$1', '$2'}}]}]))])), + ACLs = lists:keysort(2, ets:select(acl, [{{acl, {'$1', Host}, '$2'}, + [], [{{acl, '$1', '$2'}}]}])), + {NumLines, ACLsP} = term_to_paragraph(ACLs, 80), make_xhtml(?H1GL(?T("Access Control Lists"), "ACLDefinition", "ACL Definition") ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], - [?XAC('textarea', [#xmlattr{name = 'name', value = "acls"}, - #xmlattr{name = 'rows', value = "16"}, - #xmlattr{name = 'cols', value = "80"}], - ACLs), + [?TEXTAREA("acls", integer_to_list(lists:max([16, NumLines])), "80", ACLsP++"."), ?BR, ?INPUTT("submit", "submit", "Submit") ]) @@ -709,8 +714,8 @@ process_admin(Host, [], [{{acl, '$1', '$2'}}]}])), make_xhtml(?H1GL(?T("Access Control Lists"), "ACLDefinition", "ACL Definition") ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XE('p', [?ACT("../acls-raw/", "Raw")])] ++ @@ -769,23 +774,19 @@ process_admin(Host, nothing end, Access = - lists:flatten( - io_lib:format( - "~p.", [ets:select(config, + ets:select(config, [{{config, {access, '$1', Host}, '$2'}, [], - [{{access, '$1', '$2'}}]}])])), + [{{access, '$1', '$2'}}]}]), + {NumLines, AccessP} = term_to_paragraph(Access, 80), make_xhtml(?H1GL(?T("Access Rules"), "AccessRights", "Access Rights") ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], - [?XAC('textarea', [#xmlattr{name = 'name', value = "access"}, - #xmlattr{name = 'rows', value = "16"}, - #xmlattr{name = 'cols', value = "80"}], - Access), + [?TEXTAREA("access", integer_to_list(lists:max([16, NumLines])), "80", AccessP++"."), ?BR, ?INPUTT("submit", "submit", "Submit") ]) @@ -815,8 +816,8 @@ process_admin(Host, [{{access, '$1', '$2'}}]}]), make_xhtml(?H1GL(?T("Access Rules"), "AccessRights", "Access Rights") ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XE('p', [?ACT("../access-raw/", "Raw")])] ++ @@ -855,8 +856,8 @@ process_admin(Host, make_xhtml([?XC('h1', io_lib:format(?T("~s access rule configuration"), [SName]))] ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], @@ -1059,12 +1060,20 @@ acl_spec_select(ID, Opt) -> node_regexp, user_glob, server_glob, node_glob, all, raw]))]). +%% @spec (T::any()) -> StringLine::string() term_to_string(T) -> StringParagraph = lists:flatten(io_lib:format("~1000000p", [T])), %% Remove from the string all the carriage returns characters {ok, StringLine, _} = regexp:gsub(StringParagraph, "\\n ", ""), StringLine. +%% @spec (T::any()) -> {NumLines::integer(), Paragraph::string()} +term_to_paragraph(T, Cols) -> + Paragraph = erl_prettypr:format(erl_syntax:abstract(T), [{paper, Cols}]), + {ok, FieldList} = regexp:split(Paragraph, "\n"), + NumLines = length(FieldList), + {NumLines, Paragraph}. + term_to_id(T) -> jlib:encode_base64(binary_to_list(term_to_binary(T))). @@ -1232,7 +1241,7 @@ access_rule_to_xhtml(Rules) -> fun({Access, ACL} = _Rule) -> SAccess = element_to_list(Access), SACL = atom_to_list(ACL), - SAccess ++ "\t" ++ SACL ++ "\n" + SAccess ++ "\s\t" ++ SACL ++ "\n" end, Rules), ?XAC('textarea', [{"name", "rules"}, {"rows", "16"}, @@ -1309,8 +1318,8 @@ list_users(Host, Query, Lang, URLFunc) -> end, lists:seq(1, N, M)) end, case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], @@ -1506,8 +1515,8 @@ user_info(User, Server, Query, Lang) -> [User, Server, Lang]), [?XC('h1', ?T("User ") ++ us_to_list(US))] ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], @@ -1674,8 +1683,8 @@ get_node(global, Node, [], Query, Lang) -> MenuItems2 = make_menu_items(global, Node, Base, Lang), [?XC('h1', ?T("Node ") ++ atom_to_list(Node))] ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XE('ul', @@ -1704,7 +1713,10 @@ get_node(global, Node, ["db"], Query, Lang) -> {badrpc, _Reason} -> [?XCT('h1', "RPC Call Error")]; Tables -> - node_db_parse_query(Node, Tables, Query), + ResS = case node_db_parse_query(Node, Tables, Query) of + nothing -> []; + ok -> [?XREST("Submitted")] + end, STables = lists:sort(Tables), Rows = lists:map( fun(Table) -> @@ -1741,7 +1753,7 @@ get_node(global, Node, ["db"], Query, Lang) -> ]) end, STables), [?XC('h1', ?T("Database Tables at ") ++ atom_to_list(Node))] ++ - [?CT("Submitted"), ?P] ++ + ResS ++ [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], [?XAE('table', [], [?XE('thead', @@ -1763,10 +1775,15 @@ get_node(global, Node, ["db"], Query, Lang) -> end; get_node(global, Node, ["backup"], Query, Lang) -> - _Res = node_backup_parse_query(Node, Query), - [?XC('h1', ?T("Backup of ") ++ atom_to_list(Node)), - ?XCT('p', "Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately."), - ?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + ResS = case node_backup_parse_query(Node, Query) of + nothing -> []; + ok -> [?XREST("Submitted")]; + {error, Error} -> [?XRES(?T("Error") ++": " ++ io_lib:format("~p", [Error]))] + end, + [?XC('h1', ?T("Backup of ") ++ atom_to_list(Node))] ++ + ResS ++ + [?XCT('p', "Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately."), + ?XAE('form', [#xmlattr{name = 'action', value = <<>>}, #xmlattr{name = 'method', value = <<"post">>}], [?XAE('table', [], [?XE('tbody', [?XE('tr', @@ -1815,16 +1832,22 @@ get_node(global, Node, ["ports"], Query, Lang) -> ok; {'EXIT', _Reason} -> error; + {is_added, ok} -> + ok; + {is_added, {error, Reason}} -> + {error, io_lib:format("~p", [Reason])}; _ -> nothing end, + %% TODO: This sorting does not work when [{{Port, IP}, Module, Opts}] NewPorts = lists:sort( rpc:call(Node, ejabberd_config, get_local_option, [listen])), H1String = ?T("Listened Ports at ") ++ atom_to_list(Node), ?H1GL(H1String, "listened", "Listening Ports") ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; + {error, ReasonT} -> [?XRES(?T("Error") ++ ": " ++ ReasonT)]; nothing -> [] end ++ [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], @@ -1847,8 +1870,8 @@ get_node(Host, Node, ["modules"], Query, Lang) when is_list(Host) -> H1String = ?T("Modules at ") ++ atom_to_list(Node), ?H1GL(H1String, "modoverview", "Modules Overview") ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], @@ -1861,7 +1884,7 @@ get_node(global, Node, ["stats"], _Query, Lang) -> CPUTime = rpc:call(Node, erlang, statistics, [runtime]), CPUTimeS = io_lib:format("~.3f", [element(1, CPUTime)/1000]), OnlineUsers = mnesia:table_info(session, size), - TransactionsCommited = + TransactionsCommitted = rpc:call(Node, mnesia, system_info, [transaction_commits]), TransactionsAborted = rpc:call(Node, mnesia, system_info, [transaction_failures]), @@ -1882,9 +1905,9 @@ get_node(global, Node, ["stats"], _Query, Lang) -> ?XE('tr', [?XCT('td', "Online Users:"), ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], integer_to_list(OnlineUsers))]), - ?XE('tr', [?XCT('td', "Transactions Commited:"), + ?XE('tr', [?XCT('td', "Transactions Committed:"), ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], - integer_to_list(TransactionsCommited))]), + integer_to_list(TransactionsCommitted))]), ?XE('tr', [?XCT('td', "Transactions Aborted:"), ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], integer_to_list(TransactionsAborted))]), @@ -1916,17 +1939,19 @@ get_node(global, Node, ["update"], Query, Lang) -> FmtLowLevelScript = ?XC('pre', io_lib:format("~p", [LowLevelScript])), [?XC('h1', ?T("Update ") ++ atom_to_list(Node))] ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], - [?INPUTT("submit", "update", "Update"), + [ ?XCT('h2', "Update plan"), - ?XCT('h3', "Updated modules"), Mods, + ?XCT('h3', "Modified modules"), Mods, ?XCT('h3', "Update script"), FmtScript, ?XCT('h3', "Low level update script"), FmtLowLevelScript, - ?XCT('h3', "Script check"), ?C(atom_to_list(Check))]) + ?XCT('h3', "Script check"), ?XC("pre", atom_to_list(Check)), + ?INPUTT("submit", "update", "Update") + ]) ]; get_node(Host, Node, NPath, Query, Lang) -> @@ -1981,6 +2006,8 @@ db_storage_select(ID, Opt, Lang) -> {disc_only_copies, "Disc only copy"}, {unknown, "Remote copy"}])). +node_db_parse_query(_Node, _Tables, [{nokey,[]}]) -> + nothing; node_db_parse_query(Node, Tables, Query) -> lists:foreach( fun(Table) -> @@ -2014,6 +2041,8 @@ node_db_parse_query(Node, Tables, Query) -> end, Tables), ok. +node_backup_parse_query(_Node, [{nokey,[]}]) -> + nothing; node_backup_parse_query(Node, Query) -> lists:foldl( fun(Action, nothing) -> @@ -2040,15 +2069,15 @@ node_backup_parse_query(Node, Query) -> load_textfile, [Path]) end, case Res of - {error, _Reason} -> - error; - {badrpc, _Reason} -> - error; + {error, Reason} -> + {error, Reason}; + {badrpc, Reason} -> + {badrpc, Reason}; _ -> ok end; - _ -> - error + OtherError -> + {error, OtherError} end; _ -> nothing @@ -2059,62 +2088,81 @@ node_backup_parse_query(Node, Query) -> node_ports_to_xhtml(Ports, Lang) -> - ?XAE('table', [], + ?XAE('table', [#xmlattr{name = 'class', value = <<"withtextareas">>}], [?XE('thead', [?XE('tr', [?XCT('td', "Port"), + ?XCT('td', "IP"), ?XCT('td', "Module"), ?XCT('td', "Options") ])]), ?XE('tbody', lists:map( - fun({Port, Module, Opts} = _E) -> - SPort = integer_to_list(Port), + fun({PortIP, Module, Opts} = _E) -> + {_Port, SPort, _TIP, SIP, SSPort, OptsClean} = + get_port_data(PortIP, Opts), SModule = atom_to_list(Module), + {NumLines, SOptsClean} = term_to_paragraph(OptsClean, 40), %%ID = term_to_id(E), ?XE('tr', - [?XC('td', SPort), - ?XE('td', [?INPUT("text", "module" ++ SPort, - SModule)]), - ?XE('td', [?INPUTS("text", "opts" ++ SPort, - term_to_string(Opts), "40")]), - ?XE('td', [?INPUTT("submit", "add" ++ SPort, + [?XAE('td', [#xmlattr{name = 'size', value = <<"6">>}], [?C(SPort)]), + ?XAE('td', [#xmlattr{name = 'size', value = <<"15">>}], [?C(SIP)]), + ?XE('td', [?INPUTS("text", "module" ++ SSPort, + SModule, "15")]), + ?XE('td', [?TEXTAREA("opts" ++ SSPort, integer_to_list(NumLines), "35", SOptsClean)]), + ?XE('td', [?INPUTT("submit", "add" ++ SSPort, "Update")]), - ?XE('td', [?INPUTT("submit", "delete" ++ SPort, + ?XE('td', [?INPUTT("submit", "delete" ++ SSPort, "Delete")]) ] ) end, Ports) ++ [?XE('tr', [?XE('td', [?INPUTS("text", "portnew", "", "6")]), - ?XE('td', [?INPUT("text", "modulenew", "")]), - ?XE('td', [?INPUTS("text", "optsnew", "", "40")]), - ?XAE('td', [#xmlattr{name = 'colspan', value = "2"}], + ?XE('td', [?INPUTS("text", "ipnew", "0.0.0.0", "15")]), + ?XE('td', [?INPUTS("text", "modulenew", "", "15")]), + ?XE('td', [?TEXTAREA("optsnew", "2", "35", "[]")]), + ?XAE('td', [{"colspan", "2"}], [?INPUTT("submit", "addnew", "Add New")]) ] )] )]). +get_port_data(PortIP, Opts) -> + {Port, IPT, IPS, _IPV, OptsClean} = ejabberd_listener:parse_listener_portip(PortIP, Opts), + SPort = io_lib:format("~p", [Port]), + + SSPort = lists:flatten( + lists:map( + fun(N) -> io_lib:format("~.16b", [N]) end, + binary_to_list(crypto:md5(SPort++IPS)))), + {Port, SPort, IPT, IPS, SSPort, OptsClean}. + node_ports_parse_query(Node, Ports, Query) -> lists:foreach( - fun({Port, Module1, _Opts1}) -> - SPort = integer_to_list(Port), - case lists:keysearch("add" ++ SPort, 1, Query) of + fun({PortIP, Module1, Opts1}) -> + {Port, _SPort, TIP, _SIP, SSPort, _OptsClean} = + get_port_data(PortIP, Opts1), + case lists:keysearch("add" ++ SSPort, 1, Query) of {value, _} -> + PortIP2 = {Port, TIP}, {{value, {_, SModule}}, {value, {_, SOpts}}} = - {lists:keysearch("module" ++ SPort, 1, Query), - lists:keysearch("opts" ++ SPort, 1, Query)}, + {lists:keysearch("module" ++ SSPort, 1, Query), + lists:keysearch("opts" ++ SSPort, 1, Query)}, Module = list_to_atom(SModule), {ok, Tokens, _} = erl_scan:string(SOpts ++ "."), {ok, Opts} = erl_parse:parse_term(Tokens), - rpc:call(Node, ejabberd_listener, delete_listener, [Port, Module]), - rpc:call(Node, ejabberd_listener, add_listener, [Port, Module, Opts]), - throw(submitted); + rpc:call(Node, ejabberd_listener, delete_listener, + [PortIP2, Module1]), + R=rpc:call(Node, ejabberd_listener, add_listener, + [PortIP2, Module, Opts]), + throw({is_added, R}); _ -> - case lists:keysearch("delete" ++ SPort, 1, Query) of + case lists:keysearch("delete" ++ SSPort, 1, Query) of {value, _} -> - rpc:call(Node, ejabberd_listener, delete_listener, [Port, Module1]), + rpc:call(Node, ejabberd_listener, delete_listener, + [PortIP, Module1]), throw(submitted); _ -> ok @@ -2124,23 +2172,34 @@ node_ports_parse_query(Node, Ports, Query) -> case lists:keysearch("addnew", 1, Query) of {value, _} -> {{value, {_, SPort}}, + {value, {_, STIP}}, %% It is a string that may represent a tuple {value, {_, SModule}}, {value, {_, SOpts}}} = {lists:keysearch("portnew", 1, Query), + lists:keysearch("ipnew", 1, Query), lists:keysearch("modulenew", 1, Query), lists:keysearch("optsnew", 1, Query)}, - Port = list_to_integer(SPort), + {ok, Toks, _} = erl_scan:string(SPort ++ "."), + {ok, Port2} = erl_parse:parse_term(Toks), + {ok, ToksIP, _} = erl_scan:string(STIP ++ "."), + STIP2 = case erl_parse:parse_term(ToksIP) of + {ok, IPTParsed} -> IPTParsed; + {error, _} -> STIP + end, Module = list_to_atom(SModule), {ok, Tokens, _} = erl_scan:string(SOpts ++ "."), {ok, Opts} = erl_parse:parse_term(Tokens), - rpc:call(Node, ejabberd_listener, add_listener, [Port, Module, Opts]), - throw(submitted); + {Port2, _SPort, IP2, _SIP, _SSPort, OptsClean} = + get_port_data({Port2, STIP2}, Opts), + R=rpc:call(Node, ejabberd_listener, add_listener, + [{Port2, IP2}, Module, OptsClean]), + throw({is_added, R}); _ -> ok end. node_modules_to_xhtml(Modules, Lang) -> - ?XAE('table', [], + ?XAE('table', [#xmlattr{name = 'class', value = <<"withtextareas">>}], [?XE('thead', [?XE('tr', [?XCT('td', "Module"), @@ -2150,11 +2209,11 @@ node_modules_to_xhtml(Modules, Lang) -> lists:map( fun({Module, Opts} = _E) -> SModule = atom_to_list(Module), + {NumLines, SOpts} = term_to_paragraph(Opts, 40), %%ID = term_to_id(E), ?XE('tr', [?XC('td', SModule), - ?XE('td', [?INPUTS("text", "opts" ++ SModule, - term_to_string(Opts), "40")]), + ?XE('td', [?TEXTAREA("opts" ++ SModule, integer_to_list(NumLines), "40", SOpts)]), ?XE('td', [?INPUTT("submit", "restart" ++ SModule, "Restart")]), ?XE('td', [?INPUTT("submit", "stop" ++ SModule, @@ -2164,8 +2223,8 @@ node_modules_to_xhtml(Modules, Lang) -> end, Modules) ++ [?XE('tr', [?XE('td', [?INPUT("text", "modulenew", "")]), - ?XE('td', [?INPUTS("text", "optsnew", "", "40")]), - ?XAE('td', [#xmlattr{name = 'colspan', value = "2"}], + ?XE('td', [?TEXTAREA("optsnew", "2", "40", "[]")]), + ?XAE('td', [{"colspan", "2"}], [?INPUTT("submit", "start", "Start")]) ] )] @@ -2365,11 +2424,11 @@ make_menu_items2(Lang, Deep, {MURI, MName, [Item | Items]}, Res) -> make_menu_items2(Lang, Deep, {MURI, MName, Items}, Res2). make_menu_item(header, 1, URI, Name, _Lang) -> - ?LI([?XAE('div', [#xmlattr{name = 'id', value = "navhead"}], [?AC(URI, "~ "++Name++" ~")] )]); + ?LI([?XAE('div', [#xmlattr{name = 'id', value = <<"navhead">>}], [?AC(URI, Name)] )]); make_menu_item(header, 2, URI, Name, _Lang) -> - ?LI([?XAE('div', [#xmlattr{name = 'id', value = "navheadsub"}], [?AC(URI, "~ "++Name++" ~")] )]); + ?LI([?XAE('div', [#xmlattr{name = 'id', value = <<"navheadsub">>}], [?AC(URI, Name)] )]); make_menu_item(header, 3, URI, Name, _Lang) -> - ?LI([?XAE('div', [#xmlattr{name = 'id', value = "navheadsubsub"}], [?AC(URI, "~ "++Name++" ~")] )]); + ?LI([?XAE('div', [#xmlattr{name = 'id', value = <<"navheadsubsub">>}], [?AC(URI, Name)] )]); make_menu_item(item, 1, URI, Name, Lang) -> ?LI([?XAE('div', [#xmlattr{name = 'id', value = "navitem"}], [?ACT(URI, Name)] )]); make_menu_item(item, 2, URI, Name, Lang) -> diff --git a/src/web/ejabberd_web_admin.hrl b/src/web/ejabberd_web_admin.hrl index b79b9152e..b896e693e 100644 --- a/src/web/ejabberd_web_admin.hrl +++ b/src/web/ejabberd_web_admin.hrl @@ -53,13 +53,23 @@ -define(INPUTST(Type, Name, Value, Size), ?INPUT(Type, Name, ?T(Value), Size)). -define(ACLINPUT(Text), ?XE('td', [?INPUT("text", "value" ++ ID, Text)])). +-define(TEXTAREA(Name, Rows, Cols, Value), + ?XAC('textarea', [#xmlattr{name = 'name', value = list_to_binary(Name)}, + #xmlattr{name = 'rows', value = list_to_binary(Rows)}, + #xmlattr{name = 'cols', value = list_to_binary(Cols)}], + Value)). + +%% Build an xmlelement for result +-define(XRES(Text), ?XAC('p', [#xmlattr{name = 'class', value = <<"result">>}], Text)). +-define(XREST(Text), ?XRES(?T(Text))). + %% Guide Link -define(GL(Ref, Title), ?XAE('div', [#xmlattr{name = 'class', value = <<"guidelink">>}], [?XAE('a', - [#xmlattr{name = "href", value = list_to_binary("/admin/doc/guide.html#"++ Ref)}, - #xmlattr{name = "target", value = <<"_blank">>}], + [#xmlattr{name = 'href', value = list_to_binary("/admin/doc/guide.html#"++ Ref)}, + #xmlattr{name = 'target', value = <<"_blank">>}], [?C("[Guide: " ++ Title ++ "]")]) ])). From 38c0f3cdc89ce678455de92ee749f407ce6eb455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Mon, 19 Jan 2009 15:58:16 +0000 Subject: [PATCH 174/582] Replace remaining calls to deprecated API: o In src/cyrsasl_digest.erl, replace hijacked usage of xml:get_attr_s/2 by proper calls to proplists:get_value/3. o Still in src/cyrsasl_digest.erl, replace a call to stringprep:tolower/1 by exmpp_stringprep:to_lower/1. o In src/ejabberd_service.erl, replace a call to xml:crypt/1 by exmpp_xml:escape_using_entities/1. PR: EJABP-1 SVN Revision: 1832 --- ChangeLog | 9 +++++++++ src/cyrsasl_digest.erl | 20 ++++++++++---------- src/ejabberd_service.erl | 2 +- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4d5e64392..7ad1e9bc2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2009-01-19 Jean-Sébastien Pédron + + * src/cyrsasl_digest.erl: Replace hijacked usage of xml:get_attr_s/2 + by proper calls to proplists:get_value/3. Replace a call to + stringprep:tolower/1 by exmpp_stringprep:to_lower/1. + + * src/ejabberd_service.erl: Replace a call to xml:crypt/1 by + exmpp_xml:escape_using_entities/1. + 2009-01-19 Jean-Sébastien Pédron Merge from trunk (r1804 to r1829). diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl index 533fc4265..aec10c0b6 100644 --- a/src/cyrsasl_digest.erl +++ b/src/cyrsasl_digest.erl @@ -43,22 +43,22 @@ mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) -> bad -> {error, 'bad-protocol'}; KeyVals -> - DigestURI = xml:get_attr_s("digest-uri", KeyVals), - UserName = xml:get_attr_s("username", KeyVals), + DigestURI = prolists:get_value("digest-uri", KeyVals, ""), + UserName = proplists:get_value("username", KeyVals, ""), case is_digesturi_valid(DigestURI, State#state.host) of false -> ?DEBUG("User login not authorized because digest-uri " "seems invalid: ~p", [DigestURI]), {error, 'not-authorized', UserName}; true -> - AuthzId = xml:get_attr_s("authzid", KeyVals), + AuthzId = proplists:get_value("authzid", KeyVals, ""), case (State#state.get_password)(UserName) of {false, _} -> {error, 'not-authorized', UserName}; {Passwd, AuthModule} -> Response = response(KeyVals, UserName, Passwd, Nonce, AuthzId, "AUTHENTICATE"), - case xml:get_attr_s("response", KeyVals) of + case proplists:get_value("response", KeyVals, "") of Response -> RspAuth = response(KeyVals, UserName, Passwd, @@ -135,7 +135,7 @@ parse4([], Key, Val, Ts) -> %% then digest-uri can be like xmpp/server3.example.org/jabber.example.org %% In that case, ejabberd only checks the service name, not the host. is_digesturi_valid(DigestURICase, JabberHost) -> - DigestURI = stringprep:tolower(DigestURICase), + DigestURI = exmpp_stringprep:to_lower(DigestURICase), case catch string:tokens(DigestURI, "/") of ["xmpp", Host] when Host == JabberHost -> true; @@ -164,11 +164,11 @@ hex([N | Ns], Res) -> response(KeyVals, User, Passwd, Nonce, AuthzId, A2Prefix) -> - Realm = xml:get_attr_s("realm", KeyVals), - CNonce = xml:get_attr_s("cnonce", KeyVals), - DigestURI = xml:get_attr_s("digest-uri", KeyVals), - NC = xml:get_attr_s("nc", KeyVals), - QOP = xml:get_attr_s("qop", KeyVals), + Realm = proplists:get_value("realm", KeyVals, ""), + CNonce = proplists:get_value("cnonce", KeyVals, ""), + DigestURI = proplists:get_value("digest-uri", KeyVals, ""), + NC = proplists:get_value("nc", KeyVals, ""), + QOP = proplists:get_value("qop", KeyVals, ""), A1 = case AuthzId of "" -> binary_to_list( diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 591d0d0ed..2ff624ae2 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -155,7 +155,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS, attrs = Attrs}}, StateData) -> %% However several transports don't respect that, %% so ejabberd doesn't check 'to' attribute (EJAB-717) To = binary_to_list(exmpp_stanza:get_recipient_from_attrs(Attrs)), - Opening_Reply = exmpp_stream:opening_reply(xml:crypt(To), + Opening_Reply = exmpp_stream:opening_reply(exmpp_xml:escape_using_entities(To), ?NS_COMPONENT_ACCEPT, {0, 0}, StateData#state.streamid), send_element(StateData, Opening_Reply), From 03f2de75f59fc757d3df144e64685b8ea03a45cf Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Mon, 19 Jan 2009 17:45:11 +0000 Subject: [PATCH 175/582] Typo (prolists -> proplists). SVN Revision: 1833 --- ChangeLog | 4 ++++ src/cyrsasl_digest.erl | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 7ad1e9bc2..6cc41b2dc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-01-19 Pablo Polvorin + + * src/cyrsasl_digest.erl: Typo (prolists -> proplists). + 2009-01-19 Jean-Sébastien Pédron * src/cyrsasl_digest.erl: Replace hijacked usage of xml:get_attr_s/2 diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl index aec10c0b6..b585c6e6c 100644 --- a/src/cyrsasl_digest.erl +++ b/src/cyrsasl_digest.erl @@ -43,7 +43,7 @@ mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) -> bad -> {error, 'bad-protocol'}; KeyVals -> - DigestURI = prolists:get_value("digest-uri", KeyVals, ""), + DigestURI = proplists:get_value("digest-uri", KeyVals, ""), UserName = proplists:get_value("username", KeyVals, ""), case is_digesturi_valid(DigestURI, State#state.host) of false -> From 8a413018c2c1c341df0f3c8b47c5a001d9065250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 21 Jan 2009 12:44:36 +0000 Subject: [PATCH 176/582] In match_acl/3, use string() version of User/Server/Resource to match an ACL. PR: EJABP-1 SVN Revision: 1837 --- ChangeLog | 5 +++++ src/acl.erl | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 6cc41b2dc..988146db7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-01-21 Jean-Sébastien Pédron + + * src/acl.erl (match_acl/3): Use string() version of + User/Server/Resource to match an ACL. + 2009-01-19 Pablo Polvorin * src/cyrsasl_digest.erl: Typo (prolists -> proplists). diff --git a/src/acl.erl b/src/acl.erl index b72402c4d..aa672b4bf 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -158,7 +158,9 @@ match_acl(ACL, JID, Host) -> all -> true; none -> false; _ -> - {User, Server, Resource} = jlib:short_prepd_jid(JID), + User = exmpp_jid:lnode_as_list(JID), + Server = exmpp_jid:ldomain_as_list(JID), + Resource = exmpp_jid:lresource_as_list(JID), lists:any(fun(#acl{aclspec = Spec}) -> case Spec of all -> From cdbb000638542c48cbfb6cc8f5f0fb9cf85c3ab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 21 Jan 2009 13:07:55 +0000 Subject: [PATCH 177/582] Return invalid-mechanism when a mechanism isn't supported instead of no-mechanism, which wasn't standard-compliant. PR: EJABP-1 SVN Revision: 1838 --- ChangeLog | 3 +++ src/cyrsasl.erl | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 988146db7..b71b7a526 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,9 @@ * src/acl.erl (match_acl/3): Use string() version of User/Server/Resource to match an ACL. + * src/cyrsasl.erl: Return invalid-mechanism when a mechanism isn't + supported instead of no-mechanism, which wasn't standard-compliant. + 2009-01-19 Pablo Polvorin * src/cyrsasl_digest.erl: Typo (prolists -> proplists). diff --git a/src/cyrsasl.erl b/src/cyrsasl.erl index 9dedd0b75..e742cee17 100644 --- a/src/cyrsasl.erl +++ b/src/cyrsasl.erl @@ -133,10 +133,10 @@ server_start(State, Mech, ClientIn) -> mech_state = MechState}, ClientIn); _ -> - {error, 'no-mechanism'} + {error, 'invalid-mechanism'} end; false -> - {error, 'no-mechanism'} + {error, 'invalid-mechanism'} end. server_step(State, ClientIn) -> From 2f1397c50ec393739355ccb502bc4a69aabb75fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 21 Jan 2009 13:30:18 +0000 Subject: [PATCH 178/582] Use string() version of UserName and UserHost. PR: EJABP-1 SVN Revision: 1839 --- ChangeLog | 3 +++ src/mod_pubsub/nodetree_virtual.erl | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index b71b7a526..76c3adbfd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,9 @@ * src/cyrsasl.erl: Return invalid-mechanism when a mechanism isn't supported instead of no-mechanism, which wasn't standard-compliant. + * src/mod_pubsub/nodetree_virtual.erl (create_node/5): Use string() + version of UserName and UserHost. + 2009-01-19 Pablo Polvorin * src/cyrsasl_digest.erl: Typo (prolists -> proplists). diff --git a/src/mod_pubsub/nodetree_virtual.erl b/src/mod_pubsub/nodetree_virtual.erl index 92864a272..a850f26e6 100644 --- a/src/mod_pubsub/nodetree_virtual.erl +++ b/src/mod_pubsub/nodetree_virtual.erl @@ -130,8 +130,8 @@ get_subnodes_tree(_Host, _Node) -> %% is considered as already created.

      %%

      default allowed nodes: /home/host/user/any/node/name

      create_node(_Host, Node, _Type, Owner, _Options) -> - UserName = Owner#jid.lnode, - UserHost = Owner#jid.ldomain, + UserName = exmpp_jid:lnode_as_list(Owner), + UserHost = exmpp_jid:ldomain_as_list(Owner), case Node of ["home", UserHost, UserName | _] -> {error, 'conflict'}; _ -> {error, 'not-allowed'} From 376ee2ed90283957dd7ea86cb5c4af5c7526f84c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 21 Jan 2009 13:31:14 +0000 Subject: [PATCH 179/582] o In process_iq_get/3 and process_iq_set/3, use binary() version of LUser and LServer. o In convert_to_exmpp2/2, user and server are stored as binary(). PR: EJABP-1 SVN Revision: 1840 --- ChangeLog | 4 ++++ src/mod_private.erl | 28 +++++++++++++--------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index 76c3adbfd..3a76aaaef 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,10 @@ * src/mod_pubsub/nodetree_virtual.erl (create_node/5): Use string() version of UserName and UserHost. + * src/mod_private.erl (process_iq_get/3, process_iq_set/3): Use + binary() version of LUser and LServer. + (convert_to_exmpp2/2): User and server are stored as binary(). + 2009-01-19 Pablo Polvorin * src/cyrsasl_digest.erl: Typo (prolists -> proplists). diff --git a/src/mod_private.erl b/src/mod_private.erl index 629a3feeb..7edf4d433 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -73,8 +73,8 @@ process_sm_iq(From, To, #iq{type = Type} = IQ_Rec) -> end. process_iq_get(From, _To, #iq{payload = SubEl} = IQ_Rec) -> - LUser = exmpp_jid:lnode_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), + LUser = exmpp_jid:lnode(From), + LServer = exmpp_jid:ldomain(From), case catch get_data(LUser, LServer, exmpp_xml:get_child_elements(SubEl)) of @@ -88,8 +88,8 @@ process_iq_get(From, _To, #iq{payload = SubEl} = IQ_Rec) -> process_iq_set(From, _To, #iq{payload = SubEl} = IQ_Rec) -> - LUser = exmpp_jid:lnode_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), + LUser = exmpp_jid:lnode(From), + LServer = exmpp_jid:ldomain(From), F = fun() -> lists:foreach( fun(El) -> @@ -240,14 +240,11 @@ convert_to_exmpp() -> case mnesia:first(private_storage) of '$end_of_table' -> none; - Key -> - case mnesia:read({private_storage, Key}) of - [#private_storage{xml = #xmlel{}}] -> - none; - [#private_storage{xml = #xmlelement{}}] -> - mnesia:foldl(fun convert_to_exmpp2/2, - done, private_storage, write) - end + {U, _S, _NS} when is_binary(U) -> + none; + {U, _S, _NS} when is_list(U) -> + mnesia:foldl(fun convert_to_exmpp2/2, + done, private_storage, write) end end, mnesia:transaction(Fun). @@ -255,12 +252,13 @@ convert_to_exmpp() -> convert_to_exmpp2(#private_storage{usns = {U, S, NS} = Key, xml = El} = R, Acc) -> mnesia:delete({private_storage, Key}), + U1 = list_to_binary(U), + S1 = list_to_binary(S), NS1 = list_to_atom(NS), - El0 = exmpp_xml:xmlelement_to_xmlel(El, + El1 = exmpp_xml:xmlelement_to_xmlel(El, [?NS_PRIVATE], [{?NS_XMPP, ?NS_XMPP_pfx}]), - El1 = exmpp_xml:remove_whitespaces_deeply(El0), New_R = R#private_storage{ - usns = {U, S, NS1}, + usns = {U1, S1, NS1}, xml = El1}, mnesia:write(New_R), Acc. From 842ebfcca0ba349cdd62dc9dc55a0a8ccdfefcdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Wed, 21 Jan 2009 13:34:26 +0000 Subject: [PATCH 180/582] A lot of bug fixes regarding attribute values type: o Fix some bugs by getting attributes as list() instead of binary(). o Instead creating #xmlattr directly, use the new ?XMLATTR macro; it'll take care of the anything-to-binary() conversion. o Fix a bug where recipient and sender were used as binary() instead of list(), which is required by the rest of the S2S code. o Fix a bug where binary_to_list/1 was called on a list(). Now concerning JIDs : o Now that #jid{} isn't part of the API of Exmppp anymore, replace remaining direct usages by calls to exmpp_jid. o Replace exmpp_jid:make_bare_jid() by exmpp_jid:make_jid(). o Replace exmpp_jid:*_to_jid/1 by exmpp_jid:parse_jid/1. PR: EJABP-1 SVN Revision: 1841 --- ChangeLog | 37 +++ src/adhoc.erl | 16 +- src/ejabberd_c2s.erl | 10 +- src/ejabberd_s2s.erl | 4 +- src/ejabberd_s2s_in.erl | 20 +- src/ejabberd_s2s_out.erl | 4 +- src/ejabberd_service.erl | 4 +- src/ejabberd_sm.erl | 2 +- src/ejabberd_system_monitor.erl | 4 +- src/jd2ejd.erl | 16 +- src/jlib.erl | 6 +- src/mod_adhoc.erl | 37 ++- src/mod_announce.erl | 38 +-- src/mod_caps.erl | 10 +- src/mod_configure.erl | 302 ++++++++++++------------ src/mod_configure2.erl | 29 +-- src/mod_disco.erl | 40 ++-- src/mod_irc/mod_irc.erl | 40 ++-- src/mod_irc/mod_irc_connection.erl | 66 +++--- src/mod_last.erl | 4 +- src/mod_last_odbc.erl | 4 +- src/mod_muc/mod_muc.erl | 58 ++--- src/mod_muc/mod_muc_log.erl | 2 +- src/mod_muc/mod_muc_room.erl | 201 ++++++++-------- src/mod_offline.erl | 2 +- src/mod_offline_odbc.erl | 8 +- src/mod_privacy.erl | 30 +-- src/mod_privacy_odbc.erl | 32 +-- src/mod_proxy65/mod_proxy65_service.erl | 14 +- src/mod_pubsub/mod_pubsub.erl | 262 ++++++++++---------- src/mod_register.erl | 10 +- src/mod_roster.erl | 24 +- src/mod_roster_odbc.erl | 26 +- src/mod_service_log.erl | 4 +- src/mod_shared_roster.erl | 10 +- src/mod_stats.erl | 14 +- src/mod_vcard.erl | 34 ++- src/mod_vcard_ldap.erl | 31 +-- src/mod_vcard_odbc.erl | 31 +-- src/web/ejabberd_http_poll.erl | 8 +- src/web/ejabberd_web.erl | 16 +- src/web/ejabberd_web_admin.erl | 159 +++++++------ 42 files changed, 848 insertions(+), 821 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3a76aaaef..c40f7c383 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,43 @@ binary() version of LUser and LServer. (convert_to_exmpp2/2): User and server are stored as binary(). + * src/adhoc.erl, src/ejabberd_c2s.erl, src/ejabberd_s2s.erl, + src/ejabberd_s2s_in.erl, src/ejabberd_s2s_out.erl, + src/ejabberd_service.erl, src/ejabberd_sm.erl, + src/ejabberd_system_monitor.erl, src/jd2ejd.erl, src/jlib.erl, + src/mod_adhoc.erl, src/mod_announce.erl, src/mod_caps.erl, + src/mod_configure.erl, src/mod_configure2.erl, src/mod_disco.erl, + src/mod_irc/mod_irc.erl, src/mod_irc/mod_irc_connection.erl, + src/mod_last.erl, src/mod_last_odbc.erl, src/mod_muc/mod_muc.erl, + src/mod_muc/mod_muc_log.erl, src/mod_muc/mod_muc_room.erl, + src/mod_offline.erl, src/mod_offline_odbc.erl, src/mod_privacy.erl, + src/mod_privacy_odbc.erl, src/mod_proxy65/mod_proxy65_service.erl, + src/mod_pubsub/mod_pubsub.erl, src/mod_register.erl, + src/mod_roster.erl, src/mod_roster_odbc.erl, src/mod_service_log.erl, + src/mod_shared_roster.erl, src/mod_stats.erl, src/mod_vcard.erl, + src/mod_vcard_ldap.erl, src/mod_vcard_odbc.erl, + src/web/ejabberd_http_poll.erl, src/web/ejabberd_web.erl, + src/web/ejabberd_web_admin.erl: Now that #jid{} isn't part of the API + of Exmppp anymore, replace remaining direct usages by calls to + exmpp_jid. Replace exmpp_jid:make_bare_jid() by exmpp_jid:make_jid(). + Replace exmpp_jid:*_to_jid/1 by exmpp_jid:parse_jid/1. Instead + creating #xmlattr directly, use the new ?XMLATTR macro; it'll take + care of the anything-to-binary() conversion. + + * src/adhoc.erl, src/mod_caps.erl (read_caps/2), src/mod_offline.erl + (find_x_expire/2), src/mod_offline_odbc.erl, src/jd2ejd.erl, + src/mod_muc/mod_muc.erl, src/mod_irc/mod_irc_connection.erl, + src/mod_privacy_odbc.erl, src/mod_privacy.erl, src/jlib.erl, + src/mod_pubsub/mod_pubsub.erl, src/mod_stats.erl: Fix some bugs by + getting attributes as list() instead of binary(). + + * src/mod_muc/mod_muc.erl (terminate/2): Fix a bug where + binary_to_list/1 was called on a list(). + + * src/ejabberd_s2s_in.erl (is_packet_key/1): Fix a bug where recipient + and sender were used as binary() instead of list(), which is required + by the rest of the S2S code. + 2009-01-19 Pablo Polvorin * src/cyrsasl_digest.erl: Typo (prolists -> proplists). diff --git a/src/adhoc.erl b/src/adhoc.erl index d2720e685..df2104980 100644 --- a/src/adhoc.erl +++ b/src/adhoc.erl @@ -43,9 +43,9 @@ parse_request(#iq{type = Type, ns = NS, payload = SubEl, lang = Lang}) -> case {Type, NS} of {set, ?NS_ADHOC} -> ?DEBUG("entering parse_request...", []), - Node = exmpp_xml:get_attribute(SubEl, 'node', ""), - SessionID = exmpp_xml:get_attribute(SubEl, 'sessionid', ""), - Action = exmpp_xml:get_attribute(SubEl, 'action', ""), + Node = exmpp_xml:get_attribute_as_list(SubEl, 'node', ""), + SessionID = exmpp_xml:get_attribute_as_list(SubEl, 'sessionid', ""), + Action = exmpp_xml:get_attribute_as_list(SubEl, 'action', ""), XData = find_xdata_el(SubEl), AllEls = exmpp_xml:get_child_elements(SubEl), if XData -> @@ -113,7 +113,7 @@ produce_response(#adhoc_response{lang = _Lang, "" -> ActionsElAttrs = []; _ -> - ActionsElAttrs = [#xmlattr{name = 'execute', value = list_to_binary(DefaultAction)}] + ActionsElAttrs = [?XMLATTR('execute', DefaultAction)] end, ActionsEls = [#xmlel{ns = ?NS_ADHOC, name = 'actions', attrs = ActionsElAttrs, children = @@ -121,11 +121,11 @@ produce_response(#adhoc_response{lang = _Lang, end, NotesEls = lists:map(fun({Type, Text}) -> #xmlel{ns = ?NS_ADHOC, name = 'note', attrs = - [#xmlattr{name = 'type', value = list_to_binary(Type)}], + [?XMLATTR('type', Type)], children = [#xmlcdata{cdata = list_to_binary(Text)}]} end, Notes), #xmlel{ns = ?NS_ADHOC, name = 'command', attrs = - [#xmlattr{name = 'sessionid', value = list_to_binary(SessionID)}, - #xmlattr{name = 'node', value = list_to_binary(Node)}, - #xmlattr{name = 'status', value = list_to_binary(atom_to_list(Status))}], children = + [?XMLATTR('sessionid', SessionID), + ?XMLATTR('node', Node), + ?XMLATTR('status', Status)], children = ActionsEls ++ NotesEls ++ Elements}. diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index b0a722733..f0bebca5f 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -241,7 +241,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> true -> Lang = exmpp_stream:get_lang(Opening), change_shaper(StateData, - exmpp_jid:make_bare_jid(Server)), + exmpp_jid:make_jid(Server)), case exmpp_stream:get_version(Opening) of {1, 0} -> send_element(StateData, Header), @@ -398,7 +398,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> {auth, _ID, set, {U, P, D, R}} -> try JID = exmpp_jid:make_jid(U, StateData#state.server, R), - UBinary = exmpp_jid:lnode(JID), + UBinary = exmpp_jid:lnode(JID), case acl:match_rule(ServerString, StateData#state.access, JID) of allow -> @@ -506,7 +506,7 @@ wait_for_feature_request({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, {?NS_SASL, 'auth'} when not ((SockMod == gen_tcp) and TLSRequired) -> {auth, Mech, ClientIn} = exmpp_server_sasl:next_step(El), case cyrsasl:server_start(StateData#state.sasl_state, - Mech, + binary_to_list(Mech), ClientIn) of {ok, Props} -> (StateData#state.sockmod):reset_stream( @@ -833,7 +833,7 @@ session_established2(El, StateData) -> undefined -> exmpp_jid:jid_to_bare_jid(StateData#state.jid); _ -> - exmpp_jid:binary_to_jid(To) + exmpp_jid:parse_jid(To) end, NewEl = case exmpp_stanza:get_lang(El) of undefined -> @@ -1848,7 +1848,7 @@ process_unauthenticated_stanza(StateData, El) when ?IS_IQ(El) -> ResIQ = exmpp_iq:error_without_original(El, 'service-unavailable'), Res1 = exmpp_stanza:set_sender(ResIQ, - exmpp_jid:make_bare_jid(StateData#state.server)), + exmpp_jid:make_jid(StateData#state.server)), Res2 = exmpp_stanza:remove_recipient(Res1), send_element(StateData, Res2); _ -> diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index a3a89c1ca..139e0f8c9 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -406,14 +406,14 @@ new_connection(MyServer, Server, From, FromTo, max_s2s_connections_number({From, To}) -> case acl:match_rule( - From, max_s2s_connections, exmpp_jid:make_bare_jid(To)) of + From, max_s2s_connections, exmpp_jid:make_jid(To)) of Max when is_integer(Max) -> Max; _ -> ?DEFAULT_MAX_S2S_CONNECTIONS_NUMBER end. max_s2s_connections_number_per_node({From, To}) -> case acl:match_rule( - From, max_s2s_connections_per_node, exmpp_jid:make_bare_jid(To)) of + From, max_s2s_connections_per_node, exmpp_jid:make_jid(To)) of Max when is_integer(Max) -> Max; _ -> ?DEFAULT_MAX_S2S_CONNECTIONS_NUMBER_PER_NODE end. diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 63088437a..b2bd7fd8e 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -346,7 +346,7 @@ stream_established({xmlstreamelement, El}, StateData) -> Conns = ?DICT:store({LFrom, LTo}, wait_for_verification, StateData#state.connections), change_shaper(StateData, LTo, - exmpp_jid:make_bare_jid(LFrom)), + exmpp_jid:make_jid(LFrom)), {next_state, stream_established, StateData#state{connections = Conns, @@ -371,7 +371,7 @@ stream_established({xmlstreamelement, El}, StateData) -> error; F -> try - exmpp_jid:binary_to_jid(F) + exmpp_jid:parse_jid(F) catch _Exception1 -> error end @@ -381,7 +381,7 @@ stream_established({xmlstreamelement, El}, StateData) -> error; T -> try - exmpp_jid:binary_to_jid(T) + exmpp_jid:parse_jid(T) catch _Exception2 -> error end @@ -580,15 +580,15 @@ cancel_timer(Timer) -> is_key_packet(#xmlel{ns = ?NS_DIALBACK, name = 'result', attrs = Attrs} = El) -> {key, - exmpp_stanza:get_recipient_from_attrs(Attrs), - exmpp_stanza:get_sender_from_attrs(Attrs), + binary_to_list(exmpp_stanza:get_recipient_from_attrs(Attrs)), + binary_to_list(exmpp_stanza:get_sender_from_attrs(Attrs)), exmpp_stanza:get_id_from_attrs(Attrs), exmpp_xml:get_cdata_as_list(El)}; is_key_packet(#xmlel{ns = ?NS_DIALBACK, name = 'verify', attrs = Attrs} = El) -> {verify, - exmpp_stanza:get_recipient_from_attrs(Attrs), - exmpp_stanza:get_sender_from_attrs(Attrs), + binary_to_list(exmpp_stanza:get_recipient_from_attrs(Attrs)), + binary_to_list(exmpp_stanza:get_sender_from_attrs(Attrs)), exmpp_stanza:get_id_from_attrs(Attrs), exmpp_xml:get_cdata_as_list(El)}; is_key_packet(_) -> @@ -612,7 +612,7 @@ get_cert_domains(Cert) -> end, if D /= error -> - JID = exmpp_jid:list_to_jid(D), + JID = exmpp_jid:parse_jid(D), case {exmpp_jid:lnode_as_list(JID), exmpp_jid:ldomain_as_list(JID), exmpp_jid:lresource_as_list(JID)} of @@ -648,7 +648,7 @@ get_cert_domains(Cert) -> case 'XmppAddr':decode( 'XmppAddr', XmppAddr) of {ok, D} when is_binary(D) -> - JID2 = exmpp_jid:list_to_jid(binary_to_list(D)), + JID2 = exmpp_jid:parse_jid(binary_to_list(D)), case {exmpp_jid:lnode_as_list(JID2), exmpp_jid:ldomain_as_list(JID2), exmpp_jid:lresource_as_list(JID2)} of @@ -666,7 +666,7 @@ get_cert_domains(Cert) -> [] end; ({dNSName, D}) when is_list(D) -> - JID3 = exmpp_jid:list_to_jid(D), + JID3 = exmpp_jid:parse_jid(D), case {exmpp_jid:lnode_as_list(JID3), exmpp_jid:ldomain_as_list(JID3), exmpp_jid:lresource_as_list(JID3)} of diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 0d8c56176..8833309e5 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -819,8 +819,8 @@ bounce_element(El, Condition) -> <<"result">> -> ok; _ -> Err = exmpp_stanza:reply_with_error(El, Condition), - From = exmpp_jid:binary_to_jid(exmpp_stanza:get_sender(El)), - To = exmpp_jid:binary_to_jid(exmpp_stanza:get_recipient(El)), + From = exmpp_jid:parse_jid(exmpp_stanza:get_sender(El)), + To = exmpp_jid:parse_jid(exmpp_stanza:get_recipient(El)), % No namespace conversion (:server <-> :client) is done. % This is handled by C2S and S2S send_element functions. ejabberd_router:route(To, From, Err) diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 2ff624ae2..41a78e0a7 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -227,10 +227,10 @@ stream_established({xmlstreamelement, El}, StateData) -> %% when accept packets from any address. %% In this case, the component can send packet of %% behalf of the server users. - false -> exmpp_jid:binary_to_jid(From); + false -> exmpp_jid:parse_jid(From); %% The default is the standard behaviour in XEP-0114 _ -> - FromJID1 = exmpp_jid:binary_to_jid(From), + FromJID1 = exmpp_jid:parse_jid(From), Server = exmpp_jid:ldomain_as_list(FromJID1), case lists:member(Server, StateData#state.hosts) of true -> FromJID1; diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 646f15999..1cdaf92bd 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -142,7 +142,7 @@ bounce_offline_message(From, To, Packet) -> disconnect_removed_user(User, Server) -> ejabberd_sm:route(exmpp_jid:make_jid(), - exmpp_jid:make_bare_jid(User, + exmpp_jid:make_jid(User, Server), #xmlel{name = 'broadcast', children = [{exit, "User removed"}]}). diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl index 2a5418329..f4e8c3774 100644 --- a/src/ejabberd_system_monitor.erl +++ b/src/ejabberd_system_monitor.erl @@ -174,7 +174,7 @@ process_large_heap(Pid, Info) -> lists:foreach( fun(S) -> try - JID = exmpp_jid:list_to_jid(S), + JID = exmpp_jid:parse_jid(S), send_message(From, JID, Body) catch _ -> @@ -196,7 +196,7 @@ get_admin_jids() -> lists:flatmap( fun(S) -> try - JID = exmpp_jid:list_to_jid(S), + JID = exmpp_jid:parse_jid(S), [{exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID), exmpp_jid:lresource(JID)}] diff --git a/src/jd2ejd.erl b/src/jd2ejd.erl index 86a6df3d6..4ee7577f4 100644 --- a/src/jd2ejd.erl +++ b/src/jd2ejd.erl @@ -115,7 +115,7 @@ process_xdb(_User, _Server, _El) -> xdb_data(_User, _Server, #xmlcdata{}) -> ok; xdb_data(User, Server, #xmlel{ns = NS} = El) -> - From = exmpp_jid:make_bare_jid(User, Server), + From = exmpp_jid:make_jid(User, Server), LServer = exmpp_stringprep:nameprep(Server), case NS of ?NS_LEGACY_AUTH -> @@ -132,7 +132,7 @@ xdb_data(User, Server, #xmlel{ns = NS} = El) -> end, ok; ?NS_LAST_ACTIVITY -> - TimeStamp = exmpp_xml:get_attribute(El, 'last', ""), + TimeStamp = exmpp_xml:get_attribute_as_list(El, 'last', ""), Status = exmpp_xml:get_cdata(El), case lists:member(mod_last_odbc, gen_mod:loaded_modules(LServer)) of @@ -156,12 +156,12 @@ xdb_data(User, Server, #xmlel{ns = NS} = El) -> true -> catch mod_vcard_odbc:process_sm_iq( From, - exmpp_jid:make_bare_jid(Server), + exmpp_jid:make_jid(Server), #iq{kind = request, type = set, ns = ?NS_VCARD, payload = El, iq_ns = ?NS_JABBER_CLIENT}); false -> catch mod_vcard:process_sm_iq( From, - exmpp_jid:make_bare_jid(Server), + exmpp_jid:make_jid(Server), #iq{kind = request, type = set, ns = ?NS_VCARD, payload = El, iq_ns = ?NS_JABBER_CLIENT}) end, ok; @@ -169,11 +169,11 @@ xdb_data(User, Server, #xmlel{ns = NS} = El) -> process_offline(Server, From, El), ok; XMLNS -> - case exmpp_xml:get_attribute(El, "j_private_flag", "") of + case exmpp_xml:get_attribute_as_list(El, "j_private_flag", "") of "1" -> catch mod_private:process_sm_iq( From, - exmpp_jid:make_bare_jid(Server), + exmpp_jid:make_jid(Server), #iq{kind = request, type = set, ns = ?NS_PRIVATE, iq_ns = ?NS_JABBER_CLIENT, payload = #xmlel{name = 'query', children = @@ -192,10 +192,10 @@ process_offline(Server, To, #xmlel{children = Els}) -> FromS = exmpp_stanza:get_sender(El), From = case FromS of undefined -> - exmpp_jid:make_bare_jid(Server); + exmpp_jid:make_jid(Server); _ -> try - exmpp_jid:list_to_jid(FromS) + exmpp_jid:parse_jid(FromS) catch _ -> error diff --git a/src/jlib.erl b/src/jlib.erl index 06bee3377..aba42c935 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -51,7 +51,7 @@ parse_xdata_submit(#xmlel{attrs = Attrs, children = Els}) -> - case exmpp_xml:get_attribute_from_list(Attrs, 'type', "") of + case exmpp_xml:get_attribute_from_list_as_list(Attrs, 'type', "") of "submit" -> lists:reverse(parse_xdata_fields(Els, [])); _ -> @@ -62,7 +62,7 @@ parse_xdata_fields([], Res) -> Res; parse_xdata_fields([#xmlel{name = 'field', attrs = Attrs, children = SubEls} | Els], Res) -> - case exmpp_xml:get_attribute_from_list(Attrs, 'var', "") of + case exmpp_xml:get_attribute_from_list_as_list(Attrs, 'var', "") of "" -> parse_xdata_fields(Els, Res); Var -> @@ -132,7 +132,7 @@ rsm_encode_first(undefined, undefined, Arr) -> rsm_encode_first(First, undefined, Arr) -> [#xmlel{ns = ?NS_RSM, name = 'first', children = [#xmlcdata{cdata = list_to_binary(First)}]}|Arr]; rsm_encode_first(First, Index, Arr) -> - [#xmlel{ns = ?NS_RSM, name = 'first', attrs = [#xmlattr{name = 'index', value = i2b(Index)}], children = [#xmlcdata{cdata = list_to_binary(First)}]}|Arr]. + [#xmlel{ns = ?NS_RSM, name = 'first', attrs = [?XMLATTR('index', Index)], children = [#xmlcdata{cdata = list_to_binary(First)}]}|Arr]. rsm_encode_last(undefined, Arr) -> Arr; rsm_encode_last(Last, Arr) -> diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl index a53d8339e..19dfcd9d8 100644 --- a/src/mod_adhoc.erl +++ b/src/mod_adhoc.erl @@ -95,10 +95,9 @@ get_local_commands(Acc, _From, To, <<>>, Lang) -> end, Nodes = [#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = Server}, - #xmlattr{name = 'node', value = list_to_binary(?NS_ADHOC_s)}, - #xmlattr{name = 'name', - value = list_to_binary(translate:translate(Lang, "Commands"))}] + [?XMLATTR('jid', Server), + ?XMLATTR('node', ?NS_ADHOC_s), + ?XMLATTR('name', translate:translate(Lang, "Commands"))] }], {result, Items ++ Nodes} end; @@ -127,9 +126,9 @@ get_sm_commands(Acc, _From, To, <<>>, Lang) -> end, Nodes = [#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(To)}, - #xmlattr{name = 'node', value = list_to_binary(?NS_ADHOC_s)}, - #xmlattr{name = 'name', value = list_to_binary(translate:translate(Lang, "Commands"))}] + [?XMLATTR('jid', exmpp_jid:jid_to_binary(To)), + ?XMLATTR('node', ?NS_ADHOC_s), + ?XMLATTR('name', translate:translate(Lang, "Commands"))] }], {result, Items ++ Nodes} end; @@ -145,15 +144,15 @@ get_sm_commands(Acc, _From, _To, _Node, _Lang) -> %% On disco info request to the ad-hoc node, return automation/command-list. get_local_identity(Acc, _From, _To, ?NS_ADHOC_b, Lang) -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = - [#xmlattr{name = 'category', value = <<"automation">>}, - #xmlattr{name = 'type', value = <<"command-list">>}, - #xmlattr{name = 'name', value = list_to_binary(translate:translate(Lang, "Commands"))}]} | Acc]; + [?XMLATTR('category', <<"automation">>), + ?XMLATTR('type', <<"command-list">>), + ?XMLATTR('name', translate:translate(Lang, "Commands"))]} | Acc]; get_local_identity(Acc, _From, _To, <<"ping">>, Lang) -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = - [#xmlattr{name = 'category', value = <<"automation">>}, - #xmlattr{name = 'type', value = <<"command-node">>}, - #xmlattr{name = 'name', value = list_to_binary(translate:translate(Lang, "Ping"))}]} | Acc]; + [?XMLATTR('category', <<"automation">>), + ?XMLATTR('type', <<"command-node">>), + ?XMLATTR('name', translate:translate(Lang, "Ping"))]} | Acc]; get_local_identity(Acc, _From, _To, _Node, _Lang) -> Acc. @@ -163,9 +162,9 @@ get_local_identity(Acc, _From, _To, _Node, _Lang) -> %% On disco info request to the ad-hoc node, return automation/command-list. get_sm_identity(Acc, _From, _To, ?NS_ADHOC_s, Lang) -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = - [#xmlattr{name = 'category', value = <<"automation">>}, - #xmlattr{name = 'type', value = <<"command-list">>}, - #xmlattr{name = 'name', value = list_to_binary(translate:translate(Lang, "Commands"))}]} | Acc]; + [?XMLATTR('category', <<"automation">>), + ?XMLATTR('type', <<"command-list">>), + ?XMLATTR('name', translate:translate(Lang, "Commands"))]} | Acc]; get_sm_identity(Acc, _From, _To, _Node, _Lang) -> Acc. @@ -245,9 +244,9 @@ ping_item(Acc, _From, To, Lang) -> [] end, Nodes = [#xmlel{ns = ?NS_DISCO_INFO, name = 'item', attrs = - [#xmlattr{name = 'jid', value = Server}, - #xmlattr{name = 'node', value = <<"ping">>}, - #xmlattr{name = 'name', value = list_to_binary(translate:translate(Lang, "Ping"))}]}], + [?XMLATTR('jid', Server), + ?XMLATTR('node', <<"ping">>), + ?XMLATTR('name', translate:translate(Lang, "Ping"))]}], {result, Items ++ Nodes}. diff --git a/src/mod_announce.erl b/src/mod_announce.erl index 6285fe623..5a419fef2 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -179,9 +179,9 @@ announce(From, To, Packet) -> %% Announcing via ad-hoc commands -define(INFO_COMMAND(Lang, Node), [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = - [#xmlattr{name = 'category', value = <<"automation">>}, - #xmlattr{name = 'type', value = <<"command-node">>}, - #xmlattr{name = 'name', value = list_to_binary(get_title(Lang, Node))}]}]). + [?XMLATTR('category', <<"automation">>), + ?XMLATTR('type', <<"command-node">>), + ?XMLATTR('name', get_title(Lang, Node))]}]). disco_identity(Acc, _From, _To, Node, Lang) -> LNode = tokenize(binary_to_list(Node)), @@ -277,9 +277,9 @@ disco_features(Acc, From, To, Node, _Lang) -> -define(NODE_TO_ITEM(Lang, Server, Node), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = Server}, - #xmlattr{name = 'node', value = Node}, - #xmlattr{name = 'name', value = list_to_binary(get_title(Lang, Node))}]}). + [?XMLATTR('jid', Server), + ?XMLATTR('node', Node), + ?XMLATTR('name', get_title(Lang, Node))]}). -define(ITEMS_RESULT(Allow, Items), case Allow of @@ -488,8 +488,8 @@ announce_commands(From, To, _ -> [?VVALUE(Val)] end). -define(TVFIELD(Type, Var, Val), - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'var', value = Var}], children = + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', Type), + ?XMLATTR('var', Var)], children = ?VVALUEL(Val)}). -define(HFIELD(), ?TVFIELD(<<"hidden">>, <<"FORM_TYPE">>, list_to_binary(?NS_ADMIN_s))). @@ -502,28 +502,28 @@ generate_adhoc_form(Lang, Node, ServerHost) -> {[], []} end, #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = - [#xmlattr{name = 'type', value = <<"form">>}], children = + [?XMLATTR('type', <<"form">>)], children = [?HFIELD(), #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(get_title(Lang, Node))}]}] ++ if (LNode == ?NS_ADMINL("delete-motd")) or (LNode == ?NS_ADMINL("delete-motd-allhosts")) -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = <<"confirm">>}, - #xmlattr{name = 'type', value = <<"boolean">>}, - #xmlattr{name = 'label', value = list_to_binary(translate:translate(Lang, "Really delete message of the day?"))}], children = + [?XMLATTR('var', <<"confirm">>), + ?XMLATTR('type', <<"boolean">>), + ?XMLATTR('label', translate:translate(Lang, "Really delete message of the day?"))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"true">>}]}]}]; true -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = <<"subject">>}, - #xmlattr{name = 'type', value = <<"text-single">>}, - #xmlattr{name = 'label', value = list_to_binary(translate:translate(Lang, "Subject"))}], children = + [?XMLATTR('var', <<"subject">>), + ?XMLATTR('type', <<"text-single">>), + ?XMLATTR('label', translate:translate(Lang, "Subject"))], children = ?VVALUEL(list_to_binary(OldSubject))}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = <<"body">>}, - #xmlattr{name = 'type', value = <<"text-multi">>}, - #xmlattr{name = 'label', value = list_to_binary(translate:translate(Lang, "Message body"))}], children = + [?XMLATTR('var', <<"body">>), + ?XMLATTR('type', <<"text-multi">>), + ?XMLATTR('label', translate:translate(Lang, "Message body"))], children = ?VVALUEL(list_to_binary(OldBody))}] end}. @@ -569,7 +569,7 @@ handle_adhoc_form(From, To, node = Node, sessionid = SessionID, status = completed}, - Packet = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', attrs = [#xmlattr{name = 'type', value = <<"normal">>}], children = + Packet = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', attrs = [?XMLATTR('type', <<"normal">>)], children = if Subject /= [] -> [#xmlel{ns = ?NS_JABBER_CLIENT, name = 'subject', children = [#xmlcdata{cdata = list_to_binary(Subject)}]}]; diff --git a/src/mod_caps.erl b/src/mod_caps.erl index f98b2fcd6..c7483a121 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -74,9 +74,9 @@ read_caps(Els) -> read_caps(Els, nothing). read_caps([#xmlel{ns = ?NS_CAPS, name = 'c'} = El | Tail], _Result) -> - Node = exmpp_xml:get_attribute(El, 'node', ""), - Version = exmpp_xml:get_attribute(El, 'ver', ""), - Exts = string:tokens(exmpp_xml:get_attribute(El, 'ext', ""), " "), + Node = exmpp_xml:get_attribute_as_list(El, 'node', ""), + Version = exmpp_xml:get_attribute_as_list(El, 'ver', ""), + Exts = string:tokens(exmpp_xml:get_attribute_as_list(El, 'ext', ""), " "), read_caps(Tail, #caps{node = Node, version = Version, exts = Exts}); read_caps([#xmlel{ns = ?NS_MUC_USER, name = 'x'} | _Tail], _Result) -> nothing; @@ -263,7 +263,7 @@ handle_cast({note_caps, From, Stanza = exmpp_iq:get(?NS_JABBER_CLIENT, Query, ID), ejabberd_local:register_iq_response_handler (list_to_binary(Host), ID, ?MODULE, handle_disco_response), - ejabberd_router:route(exmpp_jid:make_bare_jid(Host), + ejabberd_router:route(exmpp_jid:make_jid(Host), From, Stanza), timer:send_after(?CAPS_QUERY_TIMEOUT, self(), {disco_timeout, ID}), ?DICT:store(ID, {Node, SubNode}, Dict) @@ -281,7 +281,7 @@ handle_cast({disco_response, From, _To, #iq{id = ID, type = Type, payload = Payl {ok, {Node, SubNode}} -> Features = lists:flatmap(fun(#xmlel{name = 'feature'} = F) -> - [exmpp_xml:get_attribute(F, 'var', "")]; + [exmpp_xml:get_attribute_as_list(F, 'var', "")]; (_) -> [] end, Els), diff --git a/src/mod_configure.erl b/src/mod_configure.erl index a382a0920..490e60858 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -91,24 +91,24 @@ stop(Host) -> -define(INFO_IDENTITY(Category, Type, Name, Lang), [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = - [#xmlattr{name = 'category', value = Category}, - #xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'name', value = ?T(Lang, Name)}]}]). + [?XMLATTR('category', Category), + ?XMLATTR('type', Type), + ?XMLATTR('name', ?T(Lang, Name))]}]). -define(INFO_COMMAND(Name, Lang), ?INFO_IDENTITY(<<"automation">>, <<"command-node">>, Name, Lang)). -define(NODEJID(To, Name, Node), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(To)}, - #xmlattr{name = 'name', value = ?T(Lang, Name)}, - #xmlattr{name = 'node', value = Node}]}). + [?XMLATTR('jid', exmpp_jid:jid_to_binary(To)), + ?XMLATTR('name', ?T(Lang, Name)), + ?XMLATTR('node', Node)]}). -define(NODE(Name, Node), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = Server}, - #xmlattr{name = 'name', value = ?T(Lang, Name)}, - #xmlattr{name = 'node', value = Node}]}). + [?XMLATTR('jid', Server), + ?XMLATTR('name', ?T(Lang, Name)), + ?XMLATTR('node', Node)]}). -define(NS_ADMINX(Sub), <>). -define(NS_ADMINL(Sub), ["http:","jabber.org","protocol","admin", Sub]). @@ -263,9 +263,9 @@ adhoc_sm_items(Acc, From, To, Lang) -> empty -> [] end, Nodes = [#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_binary(To)}, - #xmlattr{name = 'name', value = ?T(Lang, "Configuration")}, - #xmlattr{name = 'node', value = <<"config">>}]}], + [?XMLATTR('jid', exmpp_jid:jid_to_binary(To)), + ?XMLATTR('name', ?T(Lang, "Configuration")), + ?XMLATTR('node', <<"config">>)]}], {result, Items ++ Nodes}; _ -> Acc @@ -302,11 +302,11 @@ get_user_resources(BareJID) -> exmpp_jid:ldomain(BareJID)), lists:map(fun(R) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', - value = exmpp_jid:jid_to_binary( - exmpp_jid:bare_jid_to_jid(BareJID, R))}, - #xmlattr{name = 'name', - value = exmpp_jid:lnode(BareJID)}]} + [?XMLATTR('jid', + exmpp_jid:jid_to_binary( + exmpp_jid:bare_jid_to_jid(BareJID, R))), + ?XMLATTR('name', + exmpp_jid:lnode(BareJID))]} end, lists:sort(Rs)). %%%----------------------------------------------------------------------- @@ -325,7 +325,7 @@ adhoc_local_items(Acc, From, To, Lang) -> Lang), Nodes1 = lists:filter( fun(N) -> - Nd = exmpp_xml:get_attribute(N, 'node', ""), + Nd = exmpp_xml:get_attribute_as_list(N, 'node', ""), F = get_local_features([], From, To, Nd, Lang), case F of {result, [?NS_ADHOC_s]} -> @@ -356,8 +356,8 @@ recursively_get_local_items(PermLev, LServer, Node, Server, Lang) -> Nodes = lists:flatten( lists:map( fun(N) -> - S = exmpp_xml:get_attribute(N, 'jid', ""), - Nd = exmpp_xml:get_attribute(N, 'node', ""), + S = exmpp_xml:get_attribute_as_list(N, 'jid', ""), + Nd = exmpp_xml:get_attribute_as_list(N, 'node', ""), if (S /= Server) or (Nd == "") -> []; true -> @@ -530,8 +530,8 @@ get_local_items({_, Host}, ["all users", [$@ | Diap]], _Server, _Lang) -> Sub = lists:sublist(SUsers, N1, N2 - N1 + 1), lists:map(fun({S, U}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(U, S)}, - #xmlattr{name = 'name', value = exmpp_jid:jid_to_binary(U, S)}]} + [?XMLATTR('jid', exmpp_jid:jid_to_binary(U, S)), + ?XMLATTR('name', exmpp_jid:jid_to_binary(U, S))]} end, Sub) end of {'EXIT', _Reason} -> @@ -623,8 +623,8 @@ get_online_vh_users(Host) -> SURs = lists:sort([{S, U, R} || {U, S, R} <- USRs]), lists:map(fun({S, U, R}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_binary(U, S, R)}, - #xmlattr{name = 'name', value = exmpp_jid:jid_to_binary(U, S)}]} + [?XMLATTR('jid', exmpp_jid:jid_to_binary(U, S, R)), + ?XMLATTR('name', exmpp_jid:jid_to_binary(U, S))]} end, SURs) end. @@ -638,8 +638,8 @@ get_all_vh_users(Host) -> N when N =< 100 -> lists:map(fun({S, U}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(U, S)}, - #xmlattr{name = 'name', value = exmpp_jid:jid_to_binary(U, S)}]} + [?XMLATTR('jid', exmpp_jid:jid_to_binary(U, S)), + ?XMLATTR('name', exmpp_jid:jid_to_binary(U, S))]} end, SUsers); N -> NParts = trunc(math:sqrt(N * 0.618)) + 1, @@ -658,9 +658,9 @@ get_all_vh_users(Host) -> <<(list_to_binary(FU))/binary, "@", (list_to_binary(FS))/binary, " -- ", (list_to_binary(LU))/binary, "@", (list_to_binary(LS))/binary>>, #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = list_to_binary(Host)}, - #xmlattr{name = 'node', value = <<"all users/", Node/binary>>}, - #xmlattr{name = 'name', value = Name}]} + [?XMLATTR('jid', Host), + ?XMLATTR('node', <<"all users/", Node/binary>>), + ?XMLATTR('name', Name)]} end, lists:seq(1, N, M)) end end. @@ -676,12 +676,10 @@ get_outgoing_s2s(Host, Lang) -> lists:map( fun(T) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = list_to_binary(Host)}, - #xmlattr{name = 'node', value = <<"outgoing s2s/", (list_to_binary(T))/binary>>}, - #xmlattr{name = 'name', value = - list_to_binary( - io_lib:format( - ?T(Lang, "To ~s"), [T]))}]} + [?XMLATTR('jid', Host), + ?XMLATTR('node', <<"outgoing s2s/", (list_to_binary(T))/binary>>), + ?XMLATTR('name', + io_lib:format(?T(Lang, "To ~s"), [T]))]} end, lists:usort(TConns)) end. @@ -693,12 +691,10 @@ get_outgoing_s2s(Host, Lang, To) -> lists:map( fun({F, _T}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = list_to_binary(Host)}, - #xmlattr{name = 'node', value = <<"outgoing s2s/", (list_to_binary(To))/binary, "/", (list_to_binary(F))/binary>>}, - #xmlattr{name = 'name', value = - list_to_binary( - io_lib:format( - ?T(Lang, "From ~s"), [F]))}]} + [?XMLATTR('jid', Host), + ?XMLATTR('node', <<"outgoing s2s/", (list_to_binary(To))/binary, "/", (list_to_binary(F))/binary>>), + ?XMLATTR('name', + io_lib:format(?T(Lang, "From ~s"), [F]))]} end, lists:keysort(1, lists:filter(fun(E) -> element(2, E) == To end, Connections))) @@ -714,9 +710,9 @@ get_running_nodes(Server, _Lang) -> fun(N) -> S = list_to_binary(atom_to_list(N)), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = list_to_binary(Server)}, - #xmlattr{name = 'node', value = <<"running nodes/", (list_to_binary(S))/binary>>}, - #xmlattr{name = 'name', value = S}]} + [?XMLATTR('jid', Server), + ?XMLATTR('node', <<"running nodes/", (list_to_binary(S))/binary>>), + ?XMLATTR('name', S)]} end, lists:sort(DBNodes)) end. @@ -731,9 +727,9 @@ get_stopped_nodes(_Lang) -> fun(N) -> S = list_to_binary(atom_to_list(N)), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = list_to_binary(?MYNAME)}, - #xmlattr{name = 'node', value = <<"stopped nodes/", S/binary>>}, - #xmlattr{name = 'name', value = S}]} + [?XMLATTR('jid', ?MYNAME), + ?XMLATTR('node', <<"stopped nodes/", S/binary>>), + ?XMLATTR('name', S)]} end, lists:sort(DBNodes)) end. @@ -832,46 +828,46 @@ adhoc_local_commands(From, To, -define(TVFIELD(Type, Var, Val), - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'var', value = Var}], + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', Type), + ?XMLATTR('var', Var)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = Val}]}]}). -define(HFIELD(), ?TVFIELD(<<"hidden">>, <<"FORM_TYPE">>, list_to_binary(?NS_ADMIN_s))). -define(TLFIELD(Type, Label, Var), - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'label', value = ?T(Lang, Label)}, - #xmlattr{name = 'var', value = Var}]}). + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', Type), + ?XMLATTR('label', ?T(Lang, Label)), + ?XMLATTR('var', Var)]}). -define(XFIELD(Type, Label, Var, Val), - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'label', value = ?T(Lang, Label)}, - #xmlattr{name = 'var', value = Var}], + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', Type), + ?XMLATTR('label', ?T(Lang, Label)), + ?XMLATTR('var', Var)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = Val}]}]}). -define(XMFIELD(Type, Label, Var, Vals), - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'label', value = ?T(Lang, Label)}, - #xmlattr{name = 'var', value = Var}], + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', Type), + ?XMLATTR('label', ?T(Lang, Label)), + ?XMLATTR('var', Var)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Val)}]} || Val <- Vals]}). -define(TABLEFIELD(Table, Val), - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = <<"list-single">>}, - #xmlattr{name = 'label', value = list_to_binary(atom_to_list(Table))}, - #xmlattr{name = 'var', value = list_to_binary(atom_to_list(Table))}], + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', <<"list-single">>), + ?XMLATTR('label', Table), + ?XMLATTR('var', Table)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(atom_to_list(Val))}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = [#xmlattr{name = 'label', value = - ?T(Lang, "RAM copy")}], + #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = [?XMLATTR('label', + ?T(Lang, "RAM copy"))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"ram_copies">>}]}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = [#xmlattr{name = 'label', value = + #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = [?XMLATTR('label', ?T(Lang, - "RAM and disc copy")}], + "RAM and disc copy"))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"disc_copies">>}]}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = [#xmlattr{name = 'label', value = + #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = [?XMLATTR('label', ?T(Lang, - "Disc only copy")}], + "Disc only copy"))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"disc_only_copies">>}]}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = [#xmlattr{name = 'label', value = - ?T(Lang, "Remote copy")}], + #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = [?XMLATTR('label', + ?T(Lang, "Remote copy"))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"unknown">>}]}]} ]}). @@ -1031,7 +1027,7 @@ get_form(_Host, ["running nodes", _ENode, "restart"], Lang) -> Make_option = fun(LabelNum, LabelUnit, Value)-> #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = - [#xmlattr{name = 'label', value = <<(list_to_binary(LabelNum))/binary, (?T(Lang, LabelUnit))/binary>>}], children = + [?XMLATTR('label', LabelNum ++ ?T(Lang, LabelUnit))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Value)}]}]} end, {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = @@ -1039,9 +1035,9 @@ get_form(_Host, ["running nodes", _ENode, "restart"], Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "Restart Service"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"list-single">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Time delay")}, - #xmlattr{name = 'var', value = <<"delay">>}], children = + [?XMLATTR('type', <<"list-single">>), + ?XMLATTR('label', ?T(Lang, "Time delay")), + ?XMLATTR('var', <<"delay">>)], children = [Make_option("", "immediately", "1"), Make_option("15 ", "seconds", "15"), Make_option("30 ", "seconds", "30"), @@ -1057,23 +1053,23 @@ get_form(_Host, ["running nodes", _ENode, "restart"], Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'required'} ]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"fixed">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Send announcement to all online users on all hosts")}]}, + [?XMLATTR('type', <<"fixed">>), + ?XMLATTR('label', ?T(Lang, "Send announcement to all online users on all hosts"))]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = <<"subject">>}, - #xmlattr{name = 'type', value = <<"text-single">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Subject")}]}, + [?XMLATTR('var', <<"subject">>), + ?XMLATTR('type', <<"text-single">>), + ?XMLATTR('label', ?T(Lang, "Subject"))]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = <<"announcement">>}, - #xmlattr{name = 'type', value = <<"text-multi">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Message body")}]} + [?XMLATTR('var', <<"announcement">>), + ?XMLATTR('type', <<"text-multi">>), + ?XMLATTR('label', ?T(Lang, "Message body"))]} ]}]}; get_form(_Host, ["running nodes", _ENode, "shutdown"], Lang) -> Make_option = fun(LabelNum, LabelUnit, Value)-> #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = - [#xmlattr{name = 'label', value = <<(list_to_binary(LabelNum))/binary, (?T(Lang, LabelUnit))/binary>>}], children = + [?XMLATTR('label', LabelNum ++ ?T(Lang, LabelUnit))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Value)}]}]} end, {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = @@ -1081,9 +1077,9 @@ get_form(_Host, ["running nodes", _ENode, "shutdown"], Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "Shut Down Service"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"list-single">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Time delay")}, - #xmlattr{name = 'var', value = <<"delay">>}], children = + [?XMLATTR('type', <<"list-single">>), + ?XMLATTR('label', ?T(Lang, "Time delay")), + ?XMLATTR('var', <<"delay">>)], children = [Make_option("", "immediately", "1"), Make_option("15 ", "seconds", "15"), Make_option("30 ", "seconds", "30"), @@ -1099,16 +1095,16 @@ get_form(_Host, ["running nodes", _ENode, "shutdown"], Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'required'} ]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"fixed">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Send announcement to all online users on all hosts")}]}, + [?XMLATTR('type', <<"fixed">>), + ?XMLATTR('label', ?T(Lang, "Send announcement to all online users on all hosts"))]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = <<"subject">>}, - #xmlattr{name = 'type', value = <<"text-single">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Subject")}]}, + [?XMLATTR('var', <<"subject">>), + ?XMLATTR('type', <<"text-single">>), + ?XMLATTR('label', ?T(Lang, "Subject"))]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = <<"announcement">>}, - #xmlattr{name = 'type', value = <<"text-multi">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Message body")}]} + [?XMLATTR('var', <<"announcement">>), + ?XMLATTR('type', <<"text-multi">>), + ?XMLATTR('label', ?T(Lang, "Message body"))]} ]}]}; get_form(Host, ["config", "acls"], Lang) -> @@ -1118,11 +1114,11 @@ get_form(Host, ["config", "acls"], Lang) -> [#xmlcdata{cdata = list_to_binary(?T( Lang, "Access Control List Configuration"))}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = <<"text-multi">>}, - #xmlattr{name = 'label', value = + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', <<"text-multi">>), + ?XMLATTR('label', ?T( - Lang, "Access control lists")}, - #xmlattr{name = 'var', value = <<"acls">>}], + Lang, "Access control lists")), + ?XMLATTR('var', <<"acls">>)], children = lists:map(fun(S) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(S)}]} end, @@ -1146,11 +1142,11 @@ get_form(Host, ["config", "access"], Lang) -> [#xmlcdata{cdata = list_to_binary(?T( Lang, "Access Configuration"))}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs =[#xmlattr{name = 'type', value = <<"text-multi">>}, - #xmlattr{name = 'label', value = + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs =[?XMLATTR('type', <<"text-multi">>), + ?XMLATTR('label', ?T( - Lang, "Access rules")}, - #xmlattr{name = 'var', value = <<"access">>}], + Lang, "Access rules")), + ?XMLATTR('var', <<"access">>)], children = lists:map(fun(S) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'value', children =[#xmlcdata{cdata = list_to_binary(S)}]} end, @@ -1173,19 +1169,19 @@ get_form(_Host, ?NS_ADMINL("add-user"), Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "Add User"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"jid-single">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, - #xmlattr{name = 'var', value = <<"accountjid">>}], children = + [?XMLATTR('type', <<"jid-single">>), + ?XMLATTR('label', ?T(Lang, "Jabber ID")), + ?XMLATTR('var', <<"accountjid">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"text-private">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Password")}, - #xmlattr{name = 'var', value = <<"password">>}], children = + [?XMLATTR('type', <<"text-private">>), + ?XMLATTR('label', ?T(Lang, "Password")), + ?XMLATTR('var', <<"password">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"text-private">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Password Verification")}, - #xmlattr{name = 'var', value = <<"password-verify">>}], children = + [?XMLATTR('type', <<"text-private">>), + ?XMLATTR('label', ?T(Lang, "Password Verification")), + ?XMLATTR('var', <<"password-verify">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; @@ -1195,9 +1191,9 @@ get_form(_Host, ?NS_ADMINL("delete-user"), Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "Delete User"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"jid-multi">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, - #xmlattr{name = 'var', value = <<"accountjids">>}], children = + [?XMLATTR('type', <<"jid-multi">>), + ?XMLATTR('label', ?T(Lang, "Jabber ID")), + ?XMLATTR('var', <<"accountjids">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; @@ -1207,9 +1203,9 @@ get_form(_Host, ?NS_ADMINL("end-user-session"), Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "End User Session"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"jid-single">>}, - #xmlattr{name = 'label', value = list_to_binary(?T(Lang, "Jabber ID"))}, - #xmlattr{name = 'var', value = <<"accountjid">>}], children = + [?XMLATTR('type', <<"jid-single">>), + ?XMLATTR('label', ?T(Lang, "Jabber ID")), + ?XMLATTR('var', <<"accountjid">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; @@ -1219,9 +1215,9 @@ get_form(_Host, ?NS_ADMINL("get-user-password"), Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "Get User Password"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"jid-single">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, - #xmlattr{name = 'var', value = <<"accountjid">>}], children = + [?XMLATTR('type', <<"jid-single">>), + ?XMLATTR('label', ?T(Lang, "Jabber ID")), + ?XMLATTR('var', <<"accountjid">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; @@ -1231,14 +1227,14 @@ get_form(_Host, ?NS_ADMINL("change-user-password"), Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "Get User Password"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"jid-single">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, - #xmlattr{name = 'var', value = <<"accountjid">>}], children = + [?XMLATTR('type', <<"jid-single">>), + ?XMLATTR('label', ?T(Lang, "Jabber ID")), + ?XMLATTR('var', <<"accountjid">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"text-private">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Password")}, - #xmlattr{name = 'var', value = <<"password">>}], children = + [?XMLATTR('type', <<"text-private">>), + ?XMLATTR('label', ?T(Lang, "Password")), + ?XMLATTR('var', <<"password">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; @@ -1248,9 +1244,9 @@ get_form(_Host, ?NS_ADMINL("get-user-lastlogin"), Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "Get User Last Login Time"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"jid-single">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, - #xmlattr{name = 'var', value = <<"accountjid">>}], children = + [?XMLATTR('type', <<"jid-single">>), + ?XMLATTR('label', ?T(Lang, "Jabber ID")), + ?XMLATTR('var', <<"accountjid">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; @@ -1260,9 +1256,9 @@ get_form(_Host, ?NS_ADMINL("user-stats"), Lang) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(?T(Lang, "Get User Statistics"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"jid-single">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Jabber ID")}, - #xmlattr{name = 'var', value = <<"accountjid">>}], children = + [?XMLATTR('type', <<"jid-single">>), + ?XMLATTR('label', ?T(Lang, "Jabber ID")), + ?XMLATTR('var', <<"accountjid">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'required'}]} ]}]}; @@ -1272,9 +1268,9 @@ get_form(Host, ?NS_ADMINL("get-registered-users-num"), Lang) -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"text-single">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Number of registered users")}, - #xmlattr{name = 'var', value = <<"registeredusersnum">>}], children = + [?XMLATTR('type', <<"text-single">>), + ?XMLATTR('label', ?T(Lang, "Number of registered users")), + ?XMLATTR('var', <<"registeredusersnum">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Num)}]}] }]}]}; @@ -1284,9 +1280,9 @@ get_form(Host, ?NS_ADMINL("get-online-users-num"), Lang) -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = [?HFIELD(), #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"text-single">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Number of online users")}, - #xmlattr{name = 'var', value = <<"onlineusersnum">>}], children = + [?XMLATTR('type', <<"text-single">>), + ?XMLATTR('label', ?T(Lang, "Number of online users")), + ?XMLATTR('var', <<"onlineusersnum">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Num)}]}] }]}]}; @@ -1566,7 +1562,7 @@ set_form(From, Host, ?NS_ADMINL("add-user"), _Lang, XData) -> AccountString = get_value("accountjid", XData), Password = get_value("password", XData), Password = get_value("password-verify", XData), - AccountJID = exmpp_jid:list_to_jid(AccountString), + AccountJID = exmpp_jid:parse_jid(AccountString), User = exmpp_jid:lnode_as_list(AccountJID), Server = exmpp_jid:ldomain_as_list(AccountJID), true = lists:member(Server, ?MYHOSTS), @@ -1592,7 +1588,7 @@ set_form(From, Host, ?NS_ADMINL("delete-user"), _Lang, XData) -> set_form(From, Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> AccountString = get_value("accountjid", XData), - JID = exmpp_jid:list_to_jid(AccountString), + JID = exmpp_jid:parse_jid(AccountString), LUser = [_|_] = exmpp_jid:lnode_as_list(JID), LServer = exmpp_jid:ldomain_as_list(JID), true = (LServer == Host) orelse (get_permission_level(From) == global), @@ -1611,7 +1607,7 @@ set_form(From, Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> set_form(From, Host, ?NS_ADMINL("get-user-password"), Lang, XData) -> AccountString = get_value("accountjid", XData), - JID = exmpp_jid:list_to_jid(AccountString), + JID = exmpp_jid:parse_jid(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), Server = exmpp_jid:ldomain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), @@ -1626,7 +1622,7 @@ set_form(From, Host, ?NS_ADMINL("get-user-password"), Lang, XData) -> set_form(From, Host, ?NS_ADMINL("change-user-password"), _Lang, XData) -> AccountString = get_value("accountjid", XData), Password = get_value("password", XData), - JID = exmpp_jid:list_to_jid(AccountString), + JID = exmpp_jid:parse_jid(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), Server = exmpp_jid:ldomain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), @@ -1636,7 +1632,7 @@ set_form(From, Host, ?NS_ADMINL("change-user-password"), _Lang, XData) -> set_form(From, Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> AccountString = get_value("accountjid", XData), - JID = exmpp_jid:list_to_jid(AccountString), + JID = exmpp_jid:parse_jid(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), Server = exmpp_jid:ldomain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), @@ -1666,7 +1662,7 @@ set_form(From, Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> _ -> ?T(Lang, "Online") end, - {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', value = <<"result">>}], children = + {result, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"result">>)], children = [?HFIELD(), ?XFIELD(<<"jid-single">>, "Jabber ID", <<"accountjid">>, list_to_binary(AccountString)), ?XFIELD(<<"text-single">>, "Last login", <<"lastlogin">>, list_to_binary(FLast)) @@ -1674,7 +1670,7 @@ set_form(From, Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> set_form(From, Host, ?NS_ADMINL("user-stats"), Lang, XData) -> AccountString = get_value("accountjid", XData), - JID = exmpp_jid:list_to_jid(AccountString), + JID = exmpp_jid:parse_jid(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), Server = exmpp_jid:ldomain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), @@ -1726,12 +1722,12 @@ stop_node(From, Host, ENode, Action, XData) -> Delay = list_to_integer(get_value("delay", XData)), Subject = case get_value("subject", XData) of [] -> []; - S -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'var', value = <<"subject">>}], children = + S -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('var', <<"subject">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(S)}]}]}] end, Announcement = case get_values("announcement", XData) of [] -> []; - As -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'var', value = <<"body">>}], children = + As -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('var', <<"body">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Line)}]} || Line <- As] }] end, case Subject ++ Announcement of @@ -1741,10 +1737,10 @@ stop_node(From, Host, ENode, Action, XData) -> node = binary_to_list(?NS_ADMINX(<<"announce-allhosts">>)), action = "complete", xdata = #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = - [#xmlattr{name = 'type', value = <<"submit">>}], children = + [?XMLATTR('type', <<"submit">>)], children = SubEls}, others= [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = - [#xmlattr{name = 'type', value = <<"submit">>}], children = + [?XMLATTR('type', <<"submit">>)], children = SubEls}] }, To = exmpp_jid:make_jid(Host), @@ -1826,15 +1822,15 @@ get_sm_form(User, Server, "config", Lang) -> list_to_binary(?T( Lang, "Administration of ") ++ User)}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'type', value = <<"list-single">>}, - #xmlattr{name = 'label', value = ?T(Lang, "Action on user")}, - #xmlattr{name = 'var', value = <<"action">>}], children = + [?XMLATTR('type', <<"list-single">>), + ?XMLATTR('label', ?T(Lang, "Action on user")), + ?XMLATTR('var', <<"action">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"edit">>}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = - [#xmlattr{name = 'label', value = ?T(Lang, "Edit Properties")}], children = + [?XMLATTR('label', ?T(Lang, "Edit Properties"))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"edit">>}]}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'option', attrs = - [#xmlattr{name = 'label', value = ?T(Lang, "Remove User")}], children = + [?XMLATTR('label', ?T(Lang, "Remove User"))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"remove">>}]}]} ]}, ?XFIELD(<<"text-private">>, "Password", <<"password">>, diff --git a/src/mod_configure2.erl b/src/mod_configure2.erl index 26fed15fa..33c698ab9 100644 --- a/src/mod_configure2.erl +++ b/src/mod_configure2.erl @@ -45,8 +45,8 @@ start(Host, Opts) -> gen_iq_handler:add_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_ECONFIGURE, ?MODULE, process_local_iq, IQDisc), % Add nss/names/attrs used by this module to the known lists of Exmpp. - exmpp_xml:add_autoload_known_nss([?NS_ECONFIGURE]), - exmpp_xml:add_autoload_known_names([ + exmpp_xml:add_known_nss(xmpp, [?NS_ECONFIGURE]), + exmpp_xml:add_known_elems(xmpp, [ 'access', 'acls', 'body', @@ -57,7 +57,7 @@ start(Host, Opts) -> 'subject', 'welcome-message' ]), - exmpp_xml:add_autoload_known_attrs([ + exmpp_xml:add_known_attrs(xmpp, [ 'online-users', 'outgoing-s2s-servers', 'registered-users', @@ -124,19 +124,16 @@ process_local_iq(From, To, #iq{type = Type, payload = Request} = IQ_Rec) -> process_get(#xmlel{ns = ?NS_ECONFIGURE, name = 'info'}) -> S2SConns = ejabberd_s2s:dirty_get_connections(), TConns = lists:usort([element(2, C) || C <- S2SConns]), - Attrs = [#xmlattr{name = 'registered-users', value = - list_to_binary(integer_to_list(mnesia:table_info(passwd, size)))}, - #xmlattr{name = 'online-users', value = - list_to_binary(integer_to_list(mnesia:table_info(presence, size)))}, - #xmlattr{name = 'running-nodes', value = - list_to_binary(integer_to_list(length(mnesia:system_info(running_db_nodes))))}, - #xmlattr{name = 'stopped-nodes', value = - list_to_binary(integer_to_list( - length(lists:usort(mnesia:system_info(db_nodes) ++ - mnesia:system_info(extra_db_nodes)) -- - mnesia:system_info(running_db_nodes))))}, - #xmlattr{name = 'outgoing-s2s-servers', value = - list_to_binary(integer_to_list(length(TConns)))}], + Attrs = [?XMLATTR('registered-users', mnesia:table_info(passwd, size)), + ?XMLATTR('online-users', mnesia:table_info(presence, size)), + ?XMLATTR('running-nodes', + length(mnesia:system_info(running_db_nodes))), + ?XMLATTR('stopped-nodes', + length(lists:usort(mnesia:system_info(db_nodes) ++ + mnesia:system_info(extra_db_nodes)) -- + mnesia:system_info(running_db_nodes))), + ?XMLATTR('outgoing-s2s-servers', + length(TConns))], {result, #xmlel{ns = ?NS_ECONFIGURE, name = 'info', attrs = Attrs}}; process_get(#xmlel{ns = ?NS_ECONFIGURE, name = 'welcome-message', attrs = Attrs}) -> {Subj, Body} = case ejabberd_config:get_local_option(welcome_message) of diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 00b90c697..345a56ff7 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -139,7 +139,7 @@ process_local_iq_items(From, To, #iq{type = get, payload = SubEl, {result, Items} -> ANode = case Node of <<>> -> []; - _ -> [#xmlattr{name = 'node', value = Node}] + _ -> [?XMLATTR('node', Node)] end, Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', attrs = ANode, children = Items}, @@ -165,7 +165,7 @@ process_local_iq_info(From, To, #iq{type = get, payload = SubEl, {result, Features} -> ANode = case Node of <<>> -> []; - _ -> [#xmlattr{name = 'node', value = Node}] + _ -> [?XMLATTR('node', Node)] end, Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', attrs = ANode, @@ -180,9 +180,9 @@ process_local_iq_info(_From, _To, #iq{type = set} = IQ_Rec) -> get_local_identity(Acc, _From, _To, <<>>, _Lang) -> Acc ++ [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [ - #xmlattr{name = 'category', value = <<"server">>}, - #xmlattr{name = 'type', value = <<"im">>}, - #xmlattr{name = 'name', value = <<"ejabberd">>} + ?XMLATTR('category', <<"server">>), + ?XMLATTR('type', <<"im">>), + ?XMLATTR('name', <<"ejabberd">>) ]}]; get_local_identity(Acc, _From, _To, _Node, _Lang) -> @@ -214,7 +214,7 @@ feature_to_xml({{Feature, _Host}}) -> feature_to_xml(Feature) when is_binary(Feature) -> #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ - #xmlattr{name = 'var', value = Feature} + ?XMLATTR('var', Feature) ]}; feature_to_xml(Feature) when is_list(Feature) -> @@ -226,7 +226,7 @@ domain_to_xml({Domain}) -> domain_to_xml(Domain); domain_to_xml(Domain) when is_binary(Domain)-> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [ - #xmlattr{name = 'jid', value = Domain} + ?XMLATTR('jid', Domain) ]}; domain_to_xml(Domain) when is_list(Domain) -> domain_to_xml(list_to_binary(Domain)). @@ -280,7 +280,7 @@ process_sm_iq_items(From, To, #iq{type = get, payload = SubEl, {result, Items} -> ANode = case Node of <<>> -> []; - _ -> [#xmlattr{name = 'node', value = Node}] + _ -> [?XMLATTR('node', Node)] end, Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', attrs = ANode, children = Items}, @@ -294,7 +294,7 @@ process_sm_iq_items(From, To, #iq{type = set, payload = SubEl} = IQ_Rec) -> LFrom = exmpp_jid:lnode_as_list(From), LServer = exmpp_jid:ldomain_as_list(From), Self = (LTo == LFrom) andalso (ToServer == LServer), - Node = exmpp_xml:get_attribute(SubEl, 'node', ""), + Node = exmpp_xml:get_attribute_as_list(SubEl, 'node', ""), if Self, Node /= [] -> %% Here, we treat disco publish attempts to your own JID. @@ -358,7 +358,7 @@ process_sm_iq_info(From, To, #iq{type = get, payload = SubEl, {result, Features} -> ANode = case Node of <<>> -> []; - _ -> [#xmlattr{name = 'node', value = Node}] + _ -> [?XMLATTR('node', Node)] end, Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', attrs = ANode, @@ -396,9 +396,9 @@ get_user_resources(JID) -> exmpp_jid:ldomain(JID)), lists:map(fun(R) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [ - #xmlattr{name = 'jid', value = - exmpp_jid:jid_to_binary(exmpp_jid:bare_jid_to_jid(JID, R))}, - #xmlattr{name = 'name', value = exmpp_jid:lnode(JID)} + ?XMLATTR('jid', + exmpp_jid:jid_to_binary(exmpp_jid:bare_jid_to_jid(JID, R))), + ?XMLATTR('name', exmpp_jid:lnode(JID)) ]} end, lists:sort(Rs)). @@ -421,10 +421,10 @@ process_disco_publish(User, Node, Items) -> F = fun() -> lists:foreach( fun(#xmlel{} = Item) -> - Action = exmpp_xml:get_attribute(Item, 'action', ""), - Jid = exmpp_xml:get_attribute(Item, 'jid', ""), - PNode = exmpp_xml:get_attribute(Item, 'node', ""), - Name = exmpp_xml:get_attribute(Item, 'name', ""), + Action = exmpp_xml:get_attribute_as_list(Item, 'action', ""), + Jid = exmpp_xml:get_attribute_as_list(Item, 'jid', ""), + PNode = exmpp_xml:get_attribute_as_list(Item, 'node', ""), + Name = exmpp_xml:get_attribute_as_list(Item, 'name', ""), ?INFO_MSG("Disco publish: ~p ~p ~p ~p ~p ~p~n", [User, Action, Node, Jid, PNode, Name]), @@ -488,18 +488,18 @@ retrieve_disco_publish(User, Node) -> name = Name, node = PNode}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - lists:append([[#xmlattr{name = 'jid', value = list_to_binary(Jid)}], + lists:append([[?XMLATTR('jid', Jid)], case Name of "" -> []; _ -> - [#xmlattr{name = 'name', value = list_to_binary(Name)}] + [?XMLATTR('name', Name)] end, case PNode of "" -> []; _ -> - [#xmlattr{name = 'node', value = list_to_binary(PNode)}] + [?XMLATTR('node', PNode)] end])} end, Items)} end. diff --git a/src/mod_irc/mod_irc.erl b/src/mod_irc/mod_irc.erl index bcc61a4b8..eb4d5fa7f 100644 --- a/src/mod_irc/mod_irc.erl +++ b/src/mod_irc/mod_irc.erl @@ -303,17 +303,17 @@ closed_connection(Host, From, Server) -> iq_disco(Lang) -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = - [#xmlattr{name = 'category', value = <<"conference">>}, - #xmlattr{name = 'type', value = <<"irc">>}, - #xmlattr{name = 'name', value = list_to_binary(translate:translate(Lang, "IRC Transport"))}]}, + [?XMLATTR('category', <<"conference">>), + ?XMLATTR('type', <<"irc">>), + ?XMLATTR('name', translate:translate(Lang, "IRC Transport"))]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [#xmlattr{name = 'var', value = list_to_binary(?NS_DISCO_INFO_s)}]}, + [?XMLATTR('var', ?NS_DISCO_INFO_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [#xmlattr{name = 'var', value = list_to_binary(?NS_MUC_s)}]}, + [?XMLATTR('var', ?NS_MUC_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [#xmlattr{name = 'var', value = list_to_binary(?NS_INBAND_REGISTER_s)}]}, + [?XMLATTR('var', ?NS_INBAND_REGISTER_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [#xmlattr{name = 'var', value = list_to_binary(?NS_VCARD_s)}]}]. + [?XMLATTR('var', ?NS_VCARD_s)]}]. iq_get_vcard(Lang) -> [#xmlel{ns = ?NS_VCARD, name = 'FN', children = @@ -354,7 +354,7 @@ process_irc_register(Host, From, _To, DefEnc, #iq{type = get, ns = XMLNS, lang = Lang, payload = SubEl} = IQ_Rec) -> Node = - string:tokens(exmpp_xml:get_attribute(SubEl, 'node', ""), "/"), + string:tokens(exmpp_xml:get_attribute_as_list(SubEl, 'node', ""), "/"), case get_form(Host, From, Node, Lang ,DefEnc) of {result, Res} -> Result = #xmlel{ns = XMLNS, name = 'query', children = Res}, @@ -381,7 +381,7 @@ process_irc_register(Host, From, _To, _DefEnc, exmpp_iq:error(IQ_Rec, 'bad-request'); _ -> Node = string:tokens( - exmpp_xml:get_attribute(SubEl, "node", ""), + exmpp_xml:get_attribute_as_list(SubEl, "node", ""), "/"), case set_form( Host, From, Node, Lang, XData) of @@ -439,13 +439,13 @@ get_form(Host, From, [], Lang, DefEnc) -> Lang, "Enter username and encodings you wish to use for " "connecting to IRC servers"))}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = <<"text-single">>}, - #xmlattr{name = 'label', value = - list_to_binary(translate:translate( - Lang, "IRC Username"))}, - #xmlattr{name = 'var', value = <<"username">>}], children = + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', <<"text-single">>), + ?XMLATTR('label', + translate:translate( + Lang, "IRC Username")), + ?XMLATTR('var', <<"username">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Username)}]}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = <<"fixed">>}], children = + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', <<"fixed">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary( lists:flatten( @@ -457,7 +457,7 @@ get_form(Host, From, [], Lang, DefEnc) -> "in format '{\"irc server\", \"encoding\"}'. " "By default this service use \"~s\" encoding."), [DefEnc])))}]}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = <<"fixed">>}], children = + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', <<"fixed">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary( translate:translate( @@ -465,10 +465,10 @@ get_form(Host, From, [], Lang, DefEnc) -> "Example: [{\"irc.lucky.net\", \"koi8-r\"}, " "{\"vendetta.fef.net\", \"iso8859-1\"}]." ))}]}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = <<"text-multi">>}, - #xmlattr{name = 'label', value = - list_to_binary(translate:translate(Lang, "Encodings"))}, - #xmlattr{name = 'var', value = <<"encodings">>}], children = + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', <<"text-multi">>), + ?XMLATTR('label', + translate:translate(Lang, "Encodings")), + ?XMLATTR('var', <<"encodings">>)], children = lists:map( fun(S) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(S)}]} diff --git a/src/mod_irc/mod_irc_connection.erl b/src/mod_irc/mod_irc_connection.erl index 7fcb8c651..c7d07113e 100644 --- a/src/mod_irc/mod_irc_connection.erl +++ b/src/mod_irc/mod_irc_connection.erl @@ -590,8 +590,8 @@ terminate(_Reason, _StateName, StateData) -> lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, StateData#state.nick), StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = <<"error">>}], children = - [#xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', attrs = [#xmlattr{name = 'code', value = <<"502">>}], children = + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [?XMLATTR('type', <<"error">>)], children = + [#xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', attrs = [?XMLATTR('code', <<"502">>)], children = [#xmlcdata{cdata = <<"Server Connect Failed">>}]}]}) end, dict:fetch_keys(StateData#state.channels)), case StateData#state.socket of @@ -629,11 +629,11 @@ bounce_messages(Reason) -> ok; _ -> Error = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', - attrs = [#xmlattr{name = 'code', value = <<"502">>}], + attrs = [?XMLATTR('code', <<"502">>)], children = [#xmlcdata{cdata = Reason}]}, Err = exmpp_stanza:reply_with_error(El, Error), - From = exmpp_jid:binary_to_jid(exmpp_stanza:get_sender(El)), - To = exmpp_jid:binary_to_jid(exmpp_stanza:get_recipient(El)), + From = exmpp_jid:parse_jid(exmpp_stanza:get_sender(El)), + To = exmpp_jid:parse_jid(exmpp_stanza:get_recipient(El)), ejabberd_router:route(To, From, Err) end, bounce_messages(Reason) @@ -692,8 +692,8 @@ process_channel_list_user(StateData, Chan, User) -> #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [#xmlattr{name = 'affiliation', value = Affiliation}, - #xmlattr{name = 'role', value = Role}]}]}]}), + [?XMLATTR('affiliation', Affiliation), + ?XMLATTR('role', Role)]}]}]}), case catch dict:update(Chan, fun(Ps) -> ?SETS:add_element(User2, Ps) @@ -893,11 +893,11 @@ process_part(StateData, Chan, From, String) -> exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = <<"unavailable">>}], children = + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [?XMLATTR('type', <<"unavailable">>)], children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [#xmlattr{name = 'affiliation', value = <<"member">>}, - #xmlattr{name = 'role', value = <<"none">>}]}]}, + [?XMLATTR('affiliation', <<"member">>), + ?XMLATTR('role', <<"none">>)]}]}, #xmlel{ns = ?NS_MUC_USER, name = 'status', children = [#xmlcdata{cdata = list_to_binary(Msg1 ++ " (" ++ FromIdent ++ ")")}]}] }), @@ -927,11 +927,11 @@ process_quit(StateData, From, String) -> lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = <<"unavailable">>}], children = + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [?XMLATTR('type', <<"unavailable">>)], children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [#xmlattr{name = 'affiliation', value = <<"member">>}, - #xmlattr{name = 'role', value = <<"none">>}]}]}, + [?XMLATTR('affiliation', <<"member">>), + ?XMLATTR('role', <<"none">>)]}]}, #xmlel{ns = ?NS_MUC_USER, name = 'status', children = [#xmlcdata{cdata = list_to_binary(Msg1 ++ " (" ++ FromIdent ++ ")")}]} ]}), @@ -953,8 +953,8 @@ process_join(StateData, Channel, From, _String) -> #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [#xmlattr{name = 'affiliation', value = <<"member">>}, - #xmlattr{name = 'role', value = <<"participant">>}]}]}, + [?XMLATTR('affiliation', <<"member">>), + ?XMLATTR('role', <<"participant">>)]}]}, #xmlel{ns = ?NS_MUC_USER, name = 'status', children = [#xmlcdata{cdata = list_to_binary(FromIdent)}]}]}), @@ -979,8 +979,8 @@ process_mode_o(StateData, Chan, _From, Nick, Affiliation, Role) -> #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [#xmlattr{name = 'affiliation', value = list_to_binary(Affiliation)}, - #xmlattr{name = 'role', value = list_to_binary(Role)}]}]}]}). + [?XMLATTR('affiliation', Affiliation), + ?XMLATTR('role', Role)]}]}]}). process_kick(StateData, Chan, From, Nick, String) -> Msg = lists:last(string:tokens(String, ":")), @@ -994,12 +994,12 @@ process_kick(StateData, Chan, From, Nick, String) -> exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, Nick), StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = <<"unavailable">>}], children = + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [?XMLATTR('type', <<"unavailable">>)], children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [#xmlattr{name = 'affiliation', value = <<"none">>}, - #xmlattr{name = 'role', value = <<"none">>}]}, - #xmlel{ns = ?NS_MUC_USER, name = 'status', attrs = [#xmlattr{name = 'code', value = <<"307">>}]} + [?XMLATTR('affiliation', <<"none">>), + ?XMLATTR('role', <<"none">>)]}, + #xmlel{ns = ?NS_MUC_USER, name = 'status', attrs = [?XMLATTR('code', <<"307">>)]} ]}]}). process_nick(StateData, From, NewNick) -> @@ -1015,13 +1015,13 @@ process_nick(StateData, From, NewNick) -> lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = <<"unavailable">>}], children = + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [?XMLATTR('type', <<"unavailable">>)], children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [#xmlattr{name = 'affiliation', value = <<"member">>}, - #xmlattr{name = 'role', value = <<"participant">>}, - #xmlattr{name = 'nick', value = list_to_binary(Nick)}]}, - #xmlel{ns = ?NS_MUC_USER, name = 'status', attrs = [#xmlattr{name = 'code', value = <<"303">>}]} + [?XMLATTR('affiliation', <<"member">>), + ?XMLATTR('role', <<"participant">>), + ?XMLATTR('nick', Nick)]}, + #xmlel{ns = ?NS_MUC_USER, name = 'status', attrs = [?XMLATTR('code', <<"303">>)]} ]}]}), ejabberd_router:route( exmpp_jid:make_jid( @@ -1031,8 +1031,8 @@ process_nick(StateData, From, NewNick) -> #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [#xmlattr{name = 'affiliation', value = <<"member">>}, - #xmlattr{name = 'role', value = <<"participant">>}]} + [?XMLATTR('affiliation', <<"member">>), + ?XMLATTR('role', <<"participant">>)]} ]}]}), ?SETS:add_element(Nick, remove_element(FromUser, Ps)); @@ -1051,8 +1051,8 @@ process_error(StateData, String) -> lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, StateData#state.nick), StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [#xmlattr{name = 'type', value = <<"error">>}], children = - [#xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', attrs = [#xmlattr{name = 'code', value = <<"502">>}], children = + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [?XMLATTR('type', <<"error">>)], children = + [#xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', attrs = [?XMLATTR('code', <<"502">>)], children = [#xmlcdata{cdata = list_to_binary(String)}]}]}) end, dict:fetch_keys(StateData#state.channels)). @@ -1098,9 +1098,9 @@ process_iq_admin(StateData, Channel, set, SubEl) -> false -> {error, 'bad-request'}; ItemEl -> - Nick = exmpp_xml:get_attribute(ItemEl, 'nick', ""), - Affiliation = exmpp_xml:get_attribute(ItemEl, 'affiliation', ""), - Role = exmpp_xml:get_attribute(ItemEl, 'role', ""), + Nick = exmpp_xml:get_attribute_as_list(ItemEl, 'nick', ""), + Affiliation = exmpp_xml:get_attribute_as_list(ItemEl, 'affiliation', ""), + Role = exmpp_xml:get_attribute_as_list(ItemEl, 'role', ""), Reason = exmpp_xml:get_path(ItemEl, [{element, 'reason'}, cdata_as_list]), process_admin(StateData, Channel, Nick, Affiliation, Role, Reason) end; diff --git a/src/mod_last.erl b/src/mod_last.erl index e8d14cb6f..321ef8327 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -78,7 +78,7 @@ stop(Host) -> process_local_iq(_From, _To, #iq{type = get} = IQ_Rec) -> Sec = get_node_uptime(), Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = - [#xmlattr{name = 'seconds', value = list_to_binary(integer_to_list(Sec))}]}, + [?XMLATTR('seconds', Sec)]}, exmpp_iq:result(IQ_Rec, Response); process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> exmpp_iq:error(IQ_Rec, 'not-allowed'). @@ -142,7 +142,7 @@ get_last(IQ_Rec, LUser, LServer) -> TimeStamp2 = now_to_seconds(now()), Sec = TimeStamp2 - TimeStamp, Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', - attrs = [#xmlattr{name = 'seconds', value = list_to_binary(integer_to_list(Sec))}], + attrs = [?XMLATTR('seconds', Sec)], children = [#xmlcdata{cdata = Status}]}, exmpp_iq:result(IQ_Rec, Response) end. diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 97b72a682..961a20329 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -71,7 +71,7 @@ stop(Host) -> process_local_iq(_From, _To, #iq{type = get} = IQ_Rec) -> Sec = get_node_uptime(), Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs = - [#xmlattr{name = 'seconds', value = list_to_binary(integer_to_list(Sec))}]}, + [?XMLATTR('seconds', Sec)]}, exmpp_iq:result(IQ_Rec, Response); process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> exmpp_iq:error(IQ_Rec, 'not-allowed'). @@ -137,7 +137,7 @@ get_last(IQ_Rec, LUser, LServer) -> TimeStamp2 = now_to_seconds(now()), Sec = TimeStamp2 - TimeStamp, Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', - attrs = [#xmlattr{name = 'seconds', value = list_to_binary(integer_to_list(Sec))}], + attrs = [?XMLATTR('seconds', Sec)], children = [#xmlcdata{cdata = list_to_binary(Status)}]}, exmpp_iq:result(IQ_Rec, Response); _ -> diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index 5970bbce1..62c292d52 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -265,7 +265,7 @@ handle_info(_Info, State) -> %% The return value is ignored. %%-------------------------------------------------------------------- terminate(_Reason, State) -> - ejabberd_router:unregister_route(State#state.host), + ejabberd_router:unregister_route(binary_to_list(State#state.host)), ok. %%-------------------------------------------------------------------- @@ -378,7 +378,7 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, ok end; 'message' -> - case exmpp_xml:get_attribute(Packet,type, "chat") of + case exmpp_xml:get_attribute_as_list(Packet,type, "chat") of "error" -> ok; _ -> @@ -496,30 +496,30 @@ register_room(Host, Room, Pid) when is_binary(Host), is_binary(Room) -> iq_disco_info(Lang) -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', - attrs = [#xmlattr{name = 'category', - value = "conference"}, - #xmlattr{name = 'type', - value = "text"}, - #xmlattr{name = 'name', - value = translate:translate(Lang, "Chatrooms")}]}, + attrs = [?XMLATTR('category', + <<"conference">>), + ?XMLATTR('type', + <<"text">>), + ?XMLATTR('name', + translate:translate(Lang, "Chatrooms"))]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [#xmlattr{name = 'var', - value = ?NS_DISCO_INFO_s}]}, + [?XMLATTR('var', + ?NS_DISCO_INFO_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [#xmlattr{name = 'var', - value = ?NS_DISCO_ITEMS_s}]}, + [?XMLATTR('var', + ?NS_DISCO_ITEMS_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [#xmlattr{name = 'var', - value = ?NS_MUC_s}]}, + [?XMLATTR('var', + ?NS_MUC_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [#xmlattr{name = 'var', - value = ?NS_INBAND_REGISTER_s}]}, + [?XMLATTR('var', + ?NS_INBAND_REGISTER_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [#xmlattr{name = 'var', - value = ?NS_RSM_s}]}, + [?XMLATTR('var', + ?NS_RSM_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [#xmlattr{name = 'var', - value = ?NS_VCARD_s}]}]. + [?XMLATTR('var', + ?NS_VCARD_s)]}]. iq_disco_items(Host, From, Lang, none) when is_binary(Host) -> @@ -530,11 +530,11 @@ iq_disco_items(Host, From, Lang, none) when is_binary(Host) -> flush(), {true, #xmlel{name = 'item', - attrs = [#xmlattr{name = 'jid', - value = exmpp_jid:jid_to_binary(Name, - Host)}, - #xmlattr{name = 'name', - value = Desc}]}}; + attrs = [?XMLATTR('jid', + exmpp_jid:jid_to_binary(Name, + Host)), + ?XMLATTR('name', + Desc)]}}; _ -> false end @@ -615,10 +615,10 @@ flush() -> -define(XFIELD(Type, Label, Var, Val), #xmlel{name = "field", - attrs = [#xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'label', - value = translate:translate(Lang, Label)}, - #xmlattr{name = 'var', value = Var}], + attrs = [?XMLATTR('type', Type), + ?XMLATTR('label', + translate:translate(Lang, Label)), + ?XMLATTR('var', Var)], children = [#xmlel{name = 'value', children = [#xmlcdata{cdata = Val}]}]}). diff --git a/src/mod_muc/mod_muc_log.erl b/src/mod_muc/mod_muc_log.erl index 080fb4874..ae8c89645 100644 --- a/src/mod_muc/mod_muc_log.erl +++ b/src/mod_muc/mod_muc_log.erl @@ -271,7 +271,7 @@ build_filename_string(TimeStamp, OutDir, RoomJID, DirType, DirName, FileFormat) {Fd, Fn, Fnrel}. get_room_name(RoomJID) -> - JID = exmpp_jid:list_to_jid(RoomJID), + JID = exmpp_jid:parse_jid(RoomJID), exmpp_jid:node_as_list(JID). %% calculate day before diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index e05fc53ce..95400ed78 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -554,7 +554,7 @@ normal_state(_Event, StateData) -> %%---------------------------------------------------------------------- handle_event({service_message, Msg}, _StateName, StateData) -> MessagePkt = #xmlel{name = 'message', - attrs = [#xmlattr{name = 'type', value = "groupchat"}], + attrs = [?XMLATTR('type', <<"groupchat">>)], children = [#xmlel{name = 'body', children = [#xmlcdata{cdata = Msg}]}]}, lists:foreach( @@ -1523,7 +1523,7 @@ add_new_user(From, Nick, Packet, StateData) -> if not (NewState#state.config)#config.anonymous -> WPacket = #xmlel{name = 'message', - attrs = [#xmlattr{name = 'type', value = "groupchat"}], + attrs = [?XMLATTR('type', <<"groupchat">>)], children = [ #xmlel{name = 'body', children = [#xmlcdata{cdata = @@ -1766,12 +1766,12 @@ send_new_presence(NJID, Reason, StateData) -> case (Info#user.role == moderator) orelse ((StateData#state.config)#config.anonymous == false) of true -> - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(RealJID)}, - #xmlattr{name = 'affiliation', value = SAffiliation}, - #xmlattr{name = 'role', value = SRole}]; + [?XMLATTR('jid', exmpp_jid:jid_to_binary(RealJID)), + ?XMLATTR('affiliation', SAffiliation), + ?XMLATTR('role', SRole)]; _ -> - [#xmlattr{name = 'affiliation', value = SAffiliation}, - #xmlattr{name = 'role', value = SRole}] + [?XMLATTR('affiliation', SAffiliation), + ?XMLATTR('role', SRole)] end, ItemEls = case Reason of <<>> -> @@ -1783,7 +1783,7 @@ send_new_presence(NJID, Reason, StateData) -> Status = case StateData#state.just_created of true -> [#xmlel{name = 'status', - attrs = [#xmlattr{name = 'code', value = "201"}]}]; + attrs = [?XMLATTR('code', <<"201">>)]}]; false -> [] end, @@ -1822,14 +1822,14 @@ send_existing_presences(ToJID, StateData) -> ((StateData#state.config)#config.anonymous == false) of true -> - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(FromJID)}, - #xmlattr{name = 'affiliation', - value = affiliation_to_binary(FromAffiliation)}, - #xmlattr{name = 'role', value = role_to_binary(FromRole)}]; + [?XMLATTR('jid', exmpp_jid:jid_to_binary(FromJID)), + ?XMLATTR('affiliation', + affiliation_to_binary(FromAffiliation)), + ?XMLATTR('role', role_to_binary(FromRole))]; _ -> - [#xmlattr{name = 'affiliation', - value = affiliation_to_binary(FromAffiliation)}, - #xmlattr{name = 'role', value = role_to_binary(FromRole)}] + [?XMLATTR('affiliation', + affiliation_to_binary(FromAffiliation)), + ?XMLATTR('role', role_to_binary(FromRole))] end, Packet = exmpp_xml:append_child(Presence, #xmlel{ns = ?NS_MUC_USER, name = 'x', @@ -1879,37 +1879,37 @@ send_nick_changing(JID, OldNick, StateData) -> case (Info#user.role == moderator) orelse ((StateData#state.config)#config.anonymous == false) of true -> - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(RealJID)}, - #xmlattr{name = 'affiliation', value = SAffiliation}, - #xmlattr{name = 'role', value = SRole}, - #xmlattr{name = 'nick', value = Nick}]; + [?XMLATTR('jid', exmpp_jid:jid_to_binary(RealJID)), + ?XMLATTR('affiliation', SAffiliation), + ?XMLATTR('role', SRole), + ?XMLATTR('nick', Nick)]; _ -> - [#xmlattr{name = 'affiliation', value = SAffiliation}, - #xmlattr{name = 'role', value = SRole}, - #xmlattr{name = 'nick', value = Nick}] + [?XMLATTR('affiliation', SAffiliation), + ?XMLATTR('role', SRole), + ?XMLATTR('nick', Nick)] end, ItemAttrs2 = case (Info#user.role == moderator) orelse ((StateData#state.config)#config.anonymous == false) of true -> - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(RealJID)}, - #xmlattr{name = 'affiliation', value = SAffiliation}, - #xmlattr{name = 'role', value = SRole}]; + [?XMLATTR('jid', exmpp_jid:jid_to_binary(RealJID)), + ?XMLATTR('affiliation', SAffiliation), + ?XMLATTR('role', SRole)]; _ -> - [#xmlattr{name = 'affiliation', value = SAffiliation}, - #xmlattr{name = 'role', value = SRole}] + [?XMLATTR('affiliation', SAffiliation), + ?XMLATTR('role', SRole)] end, Packet1 = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', - attrs = [#xmlattr{name = 'type', value = <<"unavailable">>}], + attrs = [?XMLATTR('type', <<"unavailable">>)], children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [ #xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = ItemAttrs1}, #xmlel{ns = ?NS_MUC_USER, name = 'status', - attrs = [#xmlattr{name = 'code', - value = "303"}]}]}]}, + attrs = [?XMLATTR('code', + <<"303">>)]}]}]}, Packet2 = exmpp_xml:append_child( Presence, @@ -2081,20 +2081,20 @@ items_with_affiliation(SAffiliation, StateData) -> fun({JID, {Affiliation, Reason}}) -> {N, D, R} = JID, #xmlel{name = 'item', - attrs = [#xmlattr{name = 'affiliation', - value = affiliation_to_binary(Affiliation)}, - #xmlattr{name = 'jid', - value = exmpp_jid:jid_to_binary(N, D, R)}], + attrs = [?XMLATTR('affiliation', + affiliation_to_binary(Affiliation)), + ?XMLATTR('jid', + exmpp_jid:jid_to_binary(N, D, R))], children = [ #xmlel{name = 'reason', children = [#xmlcdata{cdata = Reason}]}]}; ({JID, Affiliation}) -> {N, D, R} = JID, #xmlel{name = 'item', - attrs = [#xmlattr{name = 'affiliation', - value = affiliation_to_binary(Affiliation)}, - #xmlattr{name = 'jid', - value = exmpp_jid:jid_to_binary(N, D, R)}]} + attrs = [?XMLATTR('affiliation', + affiliation_to_binary(Affiliation)), + ?XMLATTR('jid', + exmpp_jid:jid_to_binary(N, D, R))]} end, search_affiliation(SAffiliation, StateData)). user_to_item(#user{role = Role, @@ -2104,10 +2104,10 @@ user_to_item(#user{role = Role, Affiliation = get_affiliation(JID, StateData), #xmlel{name = 'item', attrs = [ - #xmlattr{name = 'role', value = role_to_binary(Role)}, - #xmlattr{name = 'affiliation', value = affiliation_to_binary(Affiliation)}, - #xmlattr{name = 'nick', value = Nick}, - #xmlattr{name = 'jid', value = exmpp_jid:jid_to_binary(JID)}] + ?XMLATTR('role', role_to_binary(Role)), + ?XMLATTR('affiliation', affiliation_to_binary(Affiliation)), + ?XMLATTR('nick', Nick), + ?XMLATTR('jid', exmpp_jid:jid_to_binary(JID))] }. search_role(Role, StateData) -> @@ -2227,7 +2227,7 @@ find_changed_items(UJID, UAffiliation, URole, Lang, StateData, Res) -> TJID = case exmpp_xml:get_attribute_as_binary(Item, 'jid',false) of S when S =/= false -> - try exmpp_jid:binary_to_jid(S) of + try exmpp_jid:parse_jid(S) of J -> {value, J} catch @@ -2239,7 +2239,7 @@ find_changed_items(UJID, UAffiliation, URole, {error, ?ERR(Item, 'not-acceptable', Lang, ErrText)} end; _ -> - case exmpp_xml:get_attribute(Item, 'nick', false) of + case exmpp_xml:get_attribute_as_list(Item, 'nick', false) of N when N =/= false -> case find_jid_by_nick(N, StateData) of false -> @@ -2569,8 +2569,8 @@ send_kickban_presence1(UJID, Reason, Code, StateData) -> SAffiliation = affiliation_to_binary(Affiliation), lists:foreach( fun({_LJID, Info}) -> - ItemAttrs = [#xmlattr{name = 'affiliation', value = SAffiliation}, - #xmlattr{name = 'role', value = "none"}], + ItemAttrs = [?XMLATTR('affiliation', SAffiliation), + ?XMLATTR('role', <<"none">>)], ItemEls = case Reason of <<>> -> []; @@ -2581,15 +2581,15 @@ send_kickban_presence1(UJID, Reason, Code, StateData) -> Packet = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', - attrs = [#xmlattr{name = 'type', value = "unavailable"}], + attrs = [?XMLATTR('type', <<"unavailable">>)], children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = [ #xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = ItemAttrs, children = ItemEls}, #xmlel{ns = ?NS_MUC_USER, name = 'status', - attrs = [#xmlattr{name='code', - value = Code}]}]}]}, + attrs = [?XMLATTR('code', + Code)]}]}]}, ejabberd_router:route( jid_replace_resource(StateData#state.jid, Nick), Info#user.jid, @@ -2688,9 +2688,9 @@ check_allowed_persistent_change(XEl, StateData, From) -> -define(XFIELD(Type, Label, Var, Val), #xmlel{name = 'field', - attrs = [#xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'label', value = translate:translate(Lang, Label)}, - #xmlattr{name = 'var', value = Var}], + attrs = [?XMLATTR('type', Type), + ?XMLATTR('label', translate:translate(Lang, Label)), + ?XMLATTR('var', Var)], children = [#xmlel{name = 'value', children = [#xmlcdata{cdata = Val} ]}]}). @@ -2729,8 +2729,8 @@ get_config(Lang, StateData, From) -> [#xmlel{name = 'title', children = [ #xmlcdata{cdata = translate:translate(Lang, "Configuration for ") ++ exmpp_jid:jid_to_list(StateData#state.jid)}]}, - #xmlel{name = 'field', attrs = [#xmlattr{name = 'type', value = "hidden"}, - #xmlattr{name = 'var', value = "FORM_TYPE"}], + #xmlel{name = 'field', attrs = [?XMLATTR('type', <<"hidden">>), + ?XMLATTR('var', <<"FORM_TYPE">>)], children = [#xmlel{name = 'value', children = [#xmlcdata{cdata = <<"http://jabber.org/protocol/muc#roomconfig">> }]}]}, @@ -2765,46 +2765,45 @@ get_config(Lang, StateData, From) -> false -> "" end), #xmlel{name = 'field', attrs = [ - #xmlattr{name = 'type', value = "list-single"}, - #xmlattr{name = 'label', value = translate:translate(Lang, - "Maximum Number of Occupants")}, - #xmlattr{name = 'var', value = "muc#roomconfig_maxusers"}], + ?XMLATTR('type', <<"list-single">>), + ?XMLATTR('label', translate:translate(Lang, + "Maximum Number of Occupants")), + ?XMLATTR('var', <<"muc#roomconfig_maxusers">>)], children = [#xmlel{name = 'value', children = [#xmlcdata{cdata = MaxUsersRoomString}]}] ++ if is_integer(ServiceMaxUsers) -> []; true -> - [#xmlel{name = 'option', attrs = [#xmlattr{name = 'label', - value = translate:translate(Lang, "No limit")}], + [#xmlel{name = 'option', attrs = [?XMLATTR('label', + translate:translate(Lang, "No limit"))], children = [#xmlel{name = 'value', children = [#xmlcdata{ cdata = <<"none">>}]}]}] end ++ - [#xmlel{name = 'option', attrs = [#xmlattr{name = 'label', - value = erlang:integer_to_list(N)}], + [#xmlel{name = 'option', attrs = [?XMLATTR('label', N)], children = [#xmlel{name = 'value', children = [ #xmlcdata{cdata = erlang:integer_to_list(N)}]}]} || N <- lists:usort([ServiceMaxUsers, DefaultRoomMaxUsers, MaxUsersRoomInteger | ?MAX_USERS_DEFAULT_LIST]), N =< ServiceMaxUsers]}, #xmlel{name = 'field', attrs = [ - #xmlattr{name = 'type', value = "list-single"}, - #xmlattr{name = 'label', - value = translate:translate(Lang, "Present real Jabber IDs to")}, - #xmlattr{name = 'var', value = "muc#roomconfig_whois"}], + ?XMLATTR('type', <<"list-single">>), + ?XMLATTR('label', + translate:translate(Lang, "Present real Jabber IDs to")), + ?XMLATTR('var', <<"muc#roomconfig_whois">>)], children = [#xmlel{name = 'value', children = [#xmlcdata{cdata = if Config#config.anonymous -> <<"moderators">>; true -> <<"anyone">> end}]}, #xmlel{name = 'option', attrs = [ - #xmlattr{name = 'label', value = - translate:translate(Lang, "moderators only")}], + ?XMLATTR('label', + translate:translate(Lang, "moderators only"))], children = [#xmlel{name = 'value', children = [#xmlcdata{cdata = <<"moderators">>}]}]}, #xmlel{name = 'option', attrs = [ - #xmlattr{name = 'label', value = - translate:translate(Lang, "anyone")}], + ?XMLATTR('label', + translate:translate(Lang, "anyone"))], children = [#xmlel{name = 'value', children = [#xmlcdata{cdata = <<"anyone">>}]}]}]}, @@ -2851,7 +2850,7 @@ get_config(Lang, StateData, From) -> #xmlcdata{cdata = translate:translate(Lang, "You need an x:data capable client to configure room")}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'x', - attrs = [#xmlattr{name = 'type', value = "form"}], + attrs = [?XMLATTR('type', <<"form">>)], children = Res}], StateData}. @@ -3072,12 +3071,12 @@ destroy_room(DEl, StateData) -> lists:foreach( fun({_LJID, Info}) -> Nick = Info#user.nick, - ItemAttrs = [#xmlattr{name = 'affiliation', value = "none"}, - #xmlattr{name = 'role', value = "none"}], + ItemAttrs = [?XMLATTR('affiliation', <<"none">>), + ?XMLATTR('role', <<"none">>)], Packet = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', - attrs = [#xmlattr{name = 'type', - value = "unavailable"}], + attrs = [?XMLATTR('type', + <<"unavailable">>)], children = [ #xmlel{ns = ?NS_MUC_USER, name = 'x', children = [#xmlel{name = 'item', attrs = ItemAttrs}, @@ -3102,7 +3101,7 @@ destroy_room(DEl, StateData) -> % Disco -define(FEATURE(Var), #xmlel{name = 'feature', - attrs = [#xmlattr{name = 'var', value = Var}]}). + attrs = [?XMLATTR('var', Var)]}). -define(CONFIG_OPT_TO_FEATURE(Opt, Fiftrue, Fiffalse), case Opt of @@ -3118,13 +3117,13 @@ process_iq_disco_info(_From, set, _Lang, _StateData) -> process_iq_disco_info(_From, get, Lang, StateData) -> Config = StateData#state.config, {result, [ #xmlel{name = 'identity', - attrs = [#xmlattr{name = 'category', - value = "conference"}, - #xmlattr{name = 'type', value = "text"}, - #xmlattr{name = 'name', - value = get_title(StateData)}]}, + attrs = [?XMLATTR('category', + <<"conference">>), + ?XMLATTR('type', <<"text">>), + ?XMLATTR('name', + get_title(StateData))]}, #xmlel{name = 'feature', - attrs = [#xmlattr{name = 'var', value = ?NS_MUC_s}]}, + attrs = [?XMLATTR('var', ?NS_MUC_s)]}, ?CONFIG_OPT_TO_FEATURE(Config#config.public, "muc_public", "muc_hidden"), @@ -3141,15 +3140,15 @@ process_iq_disco_info(_From, get, Lang, StateData) -> ] ++ iq_disco_info_extras(Lang, StateData), StateData}. -define(RFIELDT(Type, Var, Val), - #xmlel{name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'var', value = Var}], + #xmlel{name = 'field', attrs = [?XMLATTR('type', Type), + ?XMLATTR('var', Var)], children = [#xmlel{name = 'value', children = [#xmlcdata{cdata = Val}]}]}). -define(RFIELD(Label, Var, Val), - #xmlel{name = 'field', attrs = [#xmlattr{name = 'label', value = - translate:translate(Lang, Label)}, - #xmlattr{name = 'var', value = Var}], + #xmlel{name = 'field', attrs = [?XMLATTR('label', + translate:translate(Lang, Label)), + ?XMLATTR('var', Var)], children = [#xmlel{name = 'value', children = [ #xmlcdata{cdata = Val}]}]}). @@ -3157,7 +3156,7 @@ iq_disco_info_extras(Lang, StateData) -> Len = length(?DICT:to_list(StateData#state.users)), RoomDescription = (StateData#state.config)#config.description, [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', - attrs = [#xmlattr{name = 'type', value = "result"}], + attrs = [?XMLATTR('type', <<"result">>)], children = [?RFIELDT("hidden", "FORM_TYPE", "http://jabber.org/protocol/muc#roominfo"), @@ -3182,13 +3181,13 @@ process_iq_disco_items(From, get, _Lang, StateData) -> lists:map( fun({_LJID, Info}) -> Nick = Info#user.nick, - #xmlel{name = 'item', attrs = [#xmlattr{name = 'jid', - value = exmpp_jid:jid_to_binary( + #xmlel{name = 'item', attrs = [?XMLATTR('jid', + exmpp_jid:jid_to_binary( StateData#state.room, StateData#state.host, - Nick)}, - #xmlattr{name = 'name', - value = Nick}]} + Nick)), + ?XMLATTR('name', + Nick)]} end, ?DICT:to_list(StateData#state.users)), {result, UList, StateData}; @@ -3227,7 +3226,7 @@ check_invitation(From, Els, Lang, StateData) -> _ -> throw({error, 'bad-request'}) end, - JID = try exmpp_jid:binary_to_jid(exmpp_xml:get_attribute_as_binary(InviteEl, + JID = try exmpp_jid:parse_jid(exmpp_xml:get_attribute_as_binary(InviteEl, 'to', false)) of JID1 -> JID1 @@ -3253,8 +3252,8 @@ check_invitation(From, Els, Lang, StateData) -> IEl = [#xmlel{ns = ?NS_MUC_USER, name = 'invite', - attrs = [#xmlattr{name = 'from', - value = exmpp_jid:jid_to_binary(From)}], + attrs = [?XMLATTR('from', + exmpp_jid:jid_to_binary(From))], children = [#xmlel{ns =?NS_MUC_USER, name = 'reason', children = [#xmlcdata{cdata = Reason} ]}] ++ ContinueEl}], @@ -3295,15 +3294,15 @@ check_invitation(From, Els, Lang, StateData) -> %%TODO: always NS_JABBER_CLIENT? Msg = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', - attrs = [#xmlattr{name = 'type', value = "normal"}], + attrs = [?XMLATTR('type', <<"normal">>)], children = [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = IEl ++ PasswdEl}, #xmlel{ns = 'jabber:x:conference', name = 'x', - attrs = [#xmlattr{name = 'jid', - value = exmpp_jid:jid_to_binary( + attrs = [?XMLATTR('jid', + exmpp_jid:jid_to_binary( StateData#state.room, StateData#state.host) - }], + )], children = [#xmlcdata{cdata = Reason}]}, Body]}, ejabberd_router:route(StateData#state.jid, JID, Msg), @@ -3330,7 +3329,7 @@ check_decline_invitation(Packet) -> #xmlel{ns = ?NS_MUC_USER} = XEl = exmpp_xml:get_element(Packet, 'x'), DEl = exmpp_xml:get_element(XEl, 'decline'), ToString = exmpp_xml:get_attribute_as_binary(DEl, 'to', false), - ToJID = exmpp_jid:binary_to_jid(ToString), + ToJID = exmpp_jid:parse_jid(ToString), {true, {Packet, XEl, DEl, ToJID}}. %% Send the decline to the inviter user. diff --git a/src/mod_offline.erl b/src/mod_offline.erl index ecd5185b1..80342c8e7 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -220,7 +220,7 @@ find_x_event([_ | Els]) -> find_x_expire(_, []) -> never; find_x_expire(TimeStamp, [#xmlel{ns = ?NS_MESSAGE_EXPIRE} = El | _Els]) -> - Val = exmpp_xml:get_attribute(El, 'seconds', ""), + Val = exmpp_xml:get_attribute_as_list(El, 'seconds', ""), case catch list_to_integer(Val) of {'EXIT', _} -> never; diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index 15d7f2545..77d4d806f 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -198,7 +198,7 @@ check_event(From, To, Packet) -> undefined -> true; _ -> - ID = case exmpp_xml:get_attribute(Packet, 'id', "") of + ID = case exmpp_xml:get_attribute_as_list(Packet, 'id', "") of "" -> #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'id'}; S -> @@ -226,7 +226,7 @@ find_x_event([_ | Els]) -> find_x_expire(_, []) -> never; find_x_expire(TimeStamp, [#xmlel{ns = ?NS_MESSAGE_EXPIRE} = El | _Els]) -> - Val = exmpp_xml:get_attribute(El, 'seconds', ""), + Val = exmpp_xml:get_attribute_as_list(El, 'seconds', ""), case catch list_to_integer(Val) of {'EXIT', _} -> never; @@ -257,9 +257,9 @@ pop_offline_messages(Ls, User, Server) [El] = exmpp_xml:parse_document(XML, [names_as_atom, {check_elems, xmpp}, {check_nss,xmpp}, {check_attrs,xmpp}]), - To = exmpp_jid:binary_to_jid( + To = exmpp_jid:parse_jid( exmpp_stanza:get_recipient(El)), - From = exmpp_jid:binary_to_jid( + From = exmpp_jid:parse_jid( exmpp_stanza:get_sender(El)), [{route, From, To, El}] catch diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index ddfc5b608..5bc30db0c 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -95,7 +95,7 @@ process_iq_get(_, From, _To, #iq{payload = SubEl}, [#xmlel{name = Name} = Child] -> case Name of list -> - ListName = exmpp_xml:get_attribute(Child, name, false), + ListName = exmpp_xml:get_attribute_as_list(Child, name, false), process_list_get(LUser, LServer, ListName); _ -> {error, 'bad-request'} @@ -161,14 +161,14 @@ process_list_get(LUser, LServer, Name) -> item_to_xml(Item) -> - Attrs1 = [#xmlattr{name = 'action', value = action_to_binary(Item#listitem.action)}, - #xmlattr{name = 'order', value = order_to_binary(Item#listitem.order)}], + Attrs1 = [?XMLATTR('action', action_to_binary(Item#listitem.action)), + ?XMLATTR('order', order_to_binary(Item#listitem.order))], Attrs2 = case Item#listitem.type of none -> Attrs1; Type -> - [#xmlattr{name = 'type', value = type_to_binary(Item#listitem.type)}, - #xmlattr{name = 'value', value = value_to_binary(Type, Item#listitem.value)} | + [?XMLATTR('type', type_to_binary(Item#listitem.type)), + ?XMLATTR('value', value_to_binary(Type, Item#listitem.value)) | Attrs1] end, SubEls = case Item#listitem.match_all of @@ -250,7 +250,7 @@ process_iq_set(_, From, _To, #iq{payload = SubEl}) -> LServer = exmpp_jid:ldomain_as_list(From), case exmpp_xml:get_child_elements(SubEl) of [#xmlel{name = Name} = Child] -> - ListName = exmpp_xml:get_attribute(Child, 'name', false), + ListName = exmpp_xml:get_attribute_as_list(Child, 'name', false), case Name of list -> process_list_set(LUser, LServer, ListName, @@ -362,8 +362,8 @@ process_list_set(LUser, LServer, Name, Els) -> Error; {atomic, {result, _} = Res} -> ejabberd_router:route( - exmpp_jid:make_bare_jid(LUser, LServer), - exmpp_jid:make_bare_jid(LUser, LServer), + exmpp_jid:make_jid(LUser, LServer), + exmpp_jid:make_jid(LUser, LServer), #xmlel{name = 'broadcast', children=[{privacy_list, #userlist{name = Name, list = []}, @@ -393,8 +393,8 @@ process_list_set(LUser, LServer, Name, Els) -> Error; {atomic, {result, _} = Res} -> ejabberd_router:route( - exmpp_jid:make_bare_jid(LUser, LServer), - exmpp_jid:make_bare_jid(LUser, LServer), + exmpp_jid:make_jid(LUser, LServer), + exmpp_jid:make_jid(LUser, LServer), #xmlel{name = 'broadcast', children=[{privacy_list, #userlist{name = Name, list = List}, @@ -420,10 +420,10 @@ parse_items([], Res) -> %% record_info(fields, listitem))), lists:keysort(5, Res); parse_items([El = #xmlel{name = item} | Els], Res) -> - Type = exmpp_xml:get_attribute(El, type, false), - Value = exmpp_xml:get_attribute(El, value, false), - SAction =exmpp_xml:get_attribute(El, action, false), - SOrder = exmpp_xml:get_attribute(El, order, false), + Type = exmpp_xml:get_attribute_as_list(El, type, false), + Value = exmpp_xml:get_attribute_as_list(El, value, false), + SAction =exmpp_xml:get_attribute_as_list(El, action, false), + SOrder = exmpp_xml:get_attribute_as_list(El, order, false), Action = case catch list_to_action(SAction) of {'EXIT', _} -> false; Val -> Val @@ -447,7 +447,7 @@ parse_items([El = #xmlel{name = item} | Els], Res) -> case T of "jid" -> try - JID = exmpp_jid:list_to_jid(V), + JID = exmpp_jid:parse_jid(V), I1#listitem{ type = jid, value = jlib:short_prepd_jid(JID)} diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 7cf9aba96..5aded06af 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -91,7 +91,7 @@ process_iq_get(_, From, _To, #iq{payload = SubEl}, [#xmlel{name = Name} = Child] -> case Name of list -> - ListName = exmpp_xml:get_attribute(Child, name, false), + ListName = exmpp_xml:get_attribute_as_list(Child, name, false), process_list_get(LUser, LServer, ListName); _ -> {error, 'bad-request'} @@ -167,14 +167,14 @@ process_list_get(LUser, LServer, Name) -> item_to_xml(Item) -> - Attrs1 = [#xmlattr{name = 'action', value = action_to_binary(Item#listitem.action)}, - #xmlattr{name = 'order', value = order_to_binary(Item#listitem.order)}], + Attrs1 = [?XMLATTR('action', action_to_binary(Item#listitem.action)), + ?XMLATTR('order', order_to_binary(Item#listitem.order))], Attrs2 = case Item#listitem.type of none -> Attrs1; Type -> - [#xmlattr{name = 'type', value = type_to_binary(Item#listitem.type)}, - #xmlattr{name = 'value', value = value_to_binary(Type, Item#listitem.value)} | + [?XMLATTR('type', type_to_binary(Item#listitem.type)), + ?XMLATTR('value', value_to_binary(Type, Item#listitem.value)) | Attrs1] end, SubEls = case Item#listitem.match_all of @@ -256,7 +256,7 @@ process_iq_set(_, From, _To, #iq{payload = SubEl}) -> LServer = exmpp_jid:ldomain_as_list(From), case exmpp_xml:get_child_elements(SubEl) of [#xmlel{name = Name} = Child] -> - ListName = exmpp_xml:get_attribute(Child, 'name', false), + ListName = exmpp_xml:get_attribute_as_list(Child, 'name', false), case Name of list -> process_list_set(LUser, LServer, ListName, @@ -362,8 +362,8 @@ process_list_set(LUser, LServer, Name, Els) -> Error; {atomic, {result, _} = Res} -> ejabberd_router:route( - exmpp_jid:make_bare_jid(LUser, LServer), - exmpp_jid:make_bare_jid(LUser, LServer), + exmpp_jid:make_jid(LUser, LServer), + exmpp_jid:make_jid(LUser, LServer), #xmlel{name = 'broadcast', children=[{privacy_list, #userlist{name = Name, list = []}, @@ -394,8 +394,8 @@ process_list_set(LUser, LServer, Name, Els) -> Error; {atomic, {result, _} = Res} -> ejabberd_router:route( - exmpp_jid:make_bare_jid(LUser, LServer), - exmpp_jid:make_bare_jid(LUser, LServer), + exmpp_jid:make_jid(LUser, LServer), + exmpp_jid:make_jid(LUser, LServer), #xmlel{name = 'broadcast', children=[{privacy_list, #userlist{name = Name, list = List}, @@ -421,10 +421,10 @@ parse_items([], Res) -> %% record_info(fields, listitem))), lists:keysort(5, Res); parse_items([El = #xmlel{name = item} | Els], Res) -> - Type = exmpp_xml:get_attribute(El, type, false), - Value = exmpp_xml:get_attribute(El, value, false), - SAction =exmpp_xml:get_attribute(El, action, false), - SOrder = exmpp_xml:get_attribute(El, order, false), + Type = exmpp_xml:get_attribute_as_list(El, type, false), + Value = exmpp_xml:get_attribute_as_list(El, value, false), + SAction =exmpp_xml:get_attribute_as_list(El, action, false), + SOrder = exmpp_xml:get_attribute_as_list(El, order, false), Action = case catch list_to_action(SAction) of {'EXIT', _} -> false; Val -> Val @@ -448,7 +448,7 @@ parse_items([El = #xmlel{name = item} | Els], Res) -> case T of "jid" -> try - JID = exmpp_jid:list_to_jid(V), + JID = exmpp_jid:parse_jid(V), I1#listitem{ type = jid, value = jlib:short_prepd_jid(JID)} @@ -700,7 +700,7 @@ raw_to_item({SType, SValue, SAction, SOrder, SMatchAll, SMatchIQ, "n" -> {none, none}; "j" -> - JID = exmpp_jid:list_to_jid(SValue), + JID = exmpp_jid:parse_jid(SValue), {jid, jlib:short_prepd_jid(JID)}; "g" -> {group, SValue}; diff --git a/src/mod_proxy65/mod_proxy65_service.erl b/src/mod_proxy65/mod_proxy65_service.erl index 654873853..3f9ba61c8 100644 --- a/src/mod_proxy65/mod_proxy65_service.erl +++ b/src/mod_proxy65/mod_proxy65_service.erl @@ -159,8 +159,8 @@ process_iq(InitiatorJID, #iq{type = set, payload = SubEl, ns = ?NS_BYTESTREAMS} case acl:match_rule(ServerHost, ACL, InitiatorJID) of allow -> ActivateEl = exmpp_xml:get_path(SubEl, [{element, 'activate'}]), - SID = exmpp_xml:get_attribute(SubEl, 'sid', ""), - case catch exmpp_jid:list_to_jid(exmpp_xml:get_cdata_as_string(ActivateEl)) of + SID = exmpp_xml:get_attribute_as_list(SubEl, 'sid', ""), + case catch exmpp_jid:parse_jid(exmpp_xml:get_cdata_as_string(ActivateEl)) of TargetJID when ?IS_JID(TargetJID), SID /= "", length(SID) =< 128, TargetJID /= InitiatorJID -> Target = exmpp_jid:prepd_jid_to_list(TargetJID), @@ -197,13 +197,13 @@ process_iq(_, _, _) -> %%% Auxiliary functions. %%%------------------------- -define(FEATURE(Feat), #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', - attrs = [#xmlattr{name = 'var', value = Feat}]}). + attrs = [?XMLATTR('var', Feat)]}). iq_disco_info(Lang, Name) -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = - [#xmlattr{name = 'category', value = "proxy"}, - #xmlattr{name = 'type', value = "bytestreams"}, - #xmlattr{name = 'name', value = translate:translate(Lang, Name)}]}, + [?XMLATTR('category', <<"proxy">>), + ?XMLATTR('type', <<"bytestreams">>), + ?XMLATTR('name', translate:translate(Lang, Name))]}, ?FEATURE(?NS_DISCO_INFO_s), ?FEATURE(?NS_VCARD_s), ?FEATURE(?NS_BYTESTREAMS_s)]. @@ -227,7 +227,7 @@ parse_options(ServerHost, Opts) -> Addr -> Addr end, StrIP = inet_parse:ntoa(IP), - StreamAddr = [#xmlattr{name = 'jid', value = MyHost}, #xmlattr{name = 'host', value = StrIP}, #xmlattr{name = 'port', value = integer_to_list(Port)}], + StreamAddr = [?XMLATTR('jid', MyHost), ?XMLATTR('host', StrIP), ?XMLATTR('port', Port)], #state{myhost = MyHost, serverhost = ServerHost, name = Name, diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index ce9f9b7ae..622fc6b6d 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -311,18 +311,18 @@ update_database(Host) -> identity(Host) -> Identity = case lists:member(?PEPNODE, plugins(Host)) of - true -> [#xmlattr{name = 'category', value = "pubsub"}, #xmlattr{name = 'type', value = "pep"}]; - false -> [#xmlattr{name = 'category', value = "pubsub"}, #xmlattr{name = 'type', value = "service"}] + true -> [?XMLATTR('category', <<"pubsub">>), ?XMLATTR('type', <<"pep">>)]; + false -> [?XMLATTR('category', <<"pubsub">>), ?XMLATTR('type', <<"service">>)] end, #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = Identity}. disco_local_identity(Acc, _From, To, <<>>, _Lang) -> - Acc ++ [identity(To#jid.ldomain)]; + Acc ++ [identity(exmpp_jid:ldomain_as_list(To))]; disco_local_identity(Acc, _From, _To, _Node, _Lang) -> Acc. disco_local_features(Acc, _From, To, <<>>, _Lang) -> - Host = To#jid.ldomain, + Host = exmpp_jid:ldomain_as_list(To), Feats = case Acc of {result, I} -> I; _ -> [] @@ -339,7 +339,7 @@ disco_local_items(Acc, _From, _To, _Node, _Lang) -> Acc. disco_sm_identity(Acc, _From, To, <<>>, _Lang) -> - Acc ++ [identity(To#jid.ldomain)]; + Acc ++ [identity(exmpp_jid:ldomain_as_list(To))]; disco_sm_identity(Acc, From, To, Node, _Lang) -> LOwner = jlib:short_prepd_bare_jid(To), Acc ++ case node_disco_identity(LOwner, From, Node) of @@ -363,7 +363,7 @@ disco_sm_features(Acc, From, To, Node, _Lang) -> disco_sm_items(Acc, From, To, <<>>, _Lang) -> %% TODO, use iq_disco_items(Host, [], From) - Host = To#jid.ldomain, + Host = exmpp_jid:ldomain_as_list(To), LJID = jlib:short_prepd_bare_jid(To), case tree_action(Host, get_nodes, [Host, From]) of [] -> @@ -376,8 +376,8 @@ disco_sm_items(Acc, From, To, <<>>, _Lang) -> NodeItems = lists:map( fun(Node) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(LJID)}, - #xmlattr{name = 'node', value = node_to_string(Node)}]} + [?XMLATTR('jid', exmpp_jid:jid_to_binary(LJID)), + ?XMLATTR('node', node_to_string(Node))]} end, Nodes), {result, NodeItems ++ Items} end; @@ -385,7 +385,7 @@ disco_sm_items(Acc, From, To, <<>>, _Lang) -> disco_sm_items(Acc, From, To, NodeB, _Lang) -> Node = binary_to_list(NodeB), %% TODO, use iq_disco_items(Host, Node, From) - Host = To#jid.ldomain, + Host = exmpp_jid:ldomain_as_list(To), LJID = jlib:short_prepd_bare_jid(To), case get_items(Host, Node, From) of [] -> @@ -401,8 +401,8 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) -> %% "node" is forbidden by XEP-0060. {result, Name} = node_action(Host, Node, get_item_name, [Host, Node, Id]), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(LJID)}, - #xmlattr{name = 'name', value = Name}]} + [?XMLATTR('jid', exmpp_jid:jid_to_binary(LJID)), + ?XMLATTR('name', Name)]} end, AllItems), {result, NodeItems ++ Items} end. @@ -522,7 +522,7 @@ handle_cast({presence, JID, Pid}, State) -> handle_cast({remove_user, LUser, LServer}, State) -> Host = State#state.host, - Owner = exmpp_jid:make_bare_jid(LUser, LServer), + Owner = exmpp_jid:make_jid(LUser, LServer), %% remove user's subscriptions lists:foreach(fun(Type) -> {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, Owner]), @@ -555,7 +555,7 @@ handle_info({route, From, To, Packet}, #state{server_host = ServerHost, access = Access, plugins = Plugins} = State) -> - case catch do_route(ServerHost, Access, Plugins, To#jid.ldomain, From, To, Packet) of + case catch do_route(ServerHost, Access, Plugins, exmpp_jid:ldomain_as_list(To), From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); _ -> ok end, @@ -608,15 +608,17 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- do_route(ServerHost, Access, Plugins, Host, From, To, Packet) -> #xmlel{name = Name} = Packet, - case To of - #jid{lnode = undefined, lresource = undefined} -> + LNode = exmpp_jid:lnode(To), + LRes = exmpp_jid:lresource(To), + case {LNode, LRes} of + {undefined, undefined} -> case Name of 'iq' -> case exmpp_iq:xmlel_to_iq(Packet) of #iq{type = get, ns = ?NS_DISCO_INFO, payload = SubEl, lang = Lang} -> QAttrs = SubEl#xmlel.attrs, - Node = exmpp_xml:get_attribute_from_list(QAttrs, + Node = exmpp_xml:get_attribute_from_list_as_list(QAttrs, 'node', ""), Res = case iq_disco_info(Host, Node, From, Lang) of {result, IQRes} -> @@ -631,7 +633,7 @@ do_route(ServerHost, Access, Plugins, Host, From, To, Packet) -> #iq{type = get, ns = ?NS_DISCO_ITEMS, payload = SubEl} -> QAttrs = SubEl#xmlel.attrs, - Node = exmpp_xml:get_attribute_from_list(QAttrs, + Node = exmpp_xml:get_attribute_from_list_as_list(QAttrs, 'node', ""), Res = case iq_disco_items(Host, Node, From) of {result, IQRes} -> @@ -732,17 +734,17 @@ node_disco_info(Host, Node, From, Identity, Features) -> end end, lists:map(fun(T) -> - #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [#xmlattr{name = 'category', value = "pubsub"}, - #xmlattr{name = 'type', value = T}]} + #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [?XMLATTR('category', <<"pubsub">>), + ?XMLATTR('type', T)]} end, Types) end, F = case Features of false -> []; true -> - [#xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [#xmlattr{name = 'var', value = ?NS_PUBSUB_s}]} | + [#xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]} | lists:map(fun(T) -> - #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [#xmlattr{name = 'var', value = ?NS_PUBSUB_s++"#"++T}]} + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s++"#"++T)]} end, features(Type))] end, %% TODO: add meta-data info (spec section 5.4) @@ -756,15 +758,15 @@ iq_disco_info(Host, SNode, From, Lang) -> [] -> {result, [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = - [#xmlattr{name = 'category', value = "pubsub"}, - #xmlattr{name = 'type', value = "service"}, - #xmlattr{name = 'name', value = translate:translate(Lang, "Publish-Subscribe")}]}, - #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [#xmlattr{name = 'var', value = ?NS_DISCO_INFO_s}]}, - #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [#xmlattr{name = 'var', value = ?NS_DISCO_ITEMS_s}]}, - #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [#xmlattr{name = 'var', value = ?NS_PUBSUB_s}]}, - #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [#xmlattr{name = 'var', value = ?NS_VCARD_s}]}] ++ + [?XMLATTR('category', "pubsub"), + ?XMLATTR('type', "service"), + ?XMLATTR('name', translate:translate(Lang, "Publish-Subscribe"))]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_DISCO_INFO_s)]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_DISCO_ITEMS_s)]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_VCARD_s)]}] ++ lists:map(fun(Feature) -> - #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [#xmlattr{name = 'var', value = ?NS_PUBSUB_s++"#"++Feature}]} + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s++"#"++Feature)]} end, features(Host, SNode))}; _ -> node_disco_info(Host, Node, From) @@ -776,9 +778,9 @@ iq_disco_items(Host, [], From) -> SN = node_to_string(SubNode), RN = lists:last(SubNode), %% remove name attribute - #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [#xmlattr{name = 'jid', value = Host}, - #xmlattr{name = 'node', value = SN}, - #xmlattr{name = 'name', value = RN}]} + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), + ?XMLATTR('node', SN), + ?XMLATTR('name', RN)]} end, tree_action(Host, get_subnodes, [Host, [], From]))}; iq_disco_items(Host, Item, From) -> case string:tokens(Item, "!") of @@ -800,15 +802,15 @@ iq_disco_items(Host, Item, From) -> fun(#pubsub_node{nodeid = {_, SubNode}}) -> SN = node_to_string(SubNode), RN = lists:last(SubNode), - #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [#xmlattr{name = 'jid', value = Host}, #xmlattr{name = 'node', value = SN}, - #xmlattr{name = 'name', value = RN}]} + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), + ?XMLATTR('name', RN)]} end, tree_call(Host, get_subnodes, [Host, Node, From])), Items = lists:map( fun(#pubsub_item{itemid = {RN, _}}) -> SN = node_to_string(Node) ++ "!" ++ RN, {result, Name} = node_call(Type, get_item_name, [Host, Node, RN]), - #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [#xmlattr{name = 'jid', value = Host}, #xmlattr{name = 'node', value = SN}, - #xmlattr{name = 'name', value = Name}]} + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), + ?XMLATTR('name', Name)]} end, NodeItems), {result, Nodes ++ Items} end, @@ -819,10 +821,11 @@ iq_local(From, To, #iq{type = Type, payload = SubEl, ns = XMLNS, lang = Lang} = IQ_Rec) -> - ServerHost = To#jid.ldomain, + ServerHost = exmpp_jid:ldomain_as_list(To), + FromHost = exmpp_jid:ldomain_as_list(To), %% Accept IQs to server only from our own users. if - From#jid.ldomain /= ServerHost -> + FromHost /= ServerHost -> exmpp_iq:error(IQ_Rec, 'forbidden'); true -> LOwner = jlib:short_prepd_bare_jid(From), @@ -838,7 +841,7 @@ iq_local(From, To, #iq{type = Type, end. iq_sm(From, To, #iq{type = Type, payload = SubEl, ns = XMLNS, lang = Lang} = IQ_Rec) -> - ServerHost = To#jid.ldomain, + ServerHost = exmpp_jid:ldomain_as_list(To), LOwner = jlib:short_prepd_bare_jid(To), Res = case XMLNS of ?NS_PUBSUB -> iq_pubsub(LOwner, ServerHost, From, Type, SubEl, Lang); @@ -871,15 +874,15 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) -> case Action of [#xmlel{name = Name, attrs = Attrs, children = Els}] -> Node = case Host of - {_, _, _} -> exmpp_xml:get_attribute_from_list(Attrs, 'node', false); - _ -> string_to_node(exmpp_xml:get_attribute_from_list(Attrs, 'node', false)) + {_, _, _} -> exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false); + _ -> string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false)) end, case {IQType, Name} of {set, 'create'} -> case Configuration of [#xmlel{name = 'configure', children = Config}] -> %% Get the type of the node - Type = case exmpp_xml:get_attribute_from_list(Attrs, 'type', "") of + Type = case exmpp_xml:get_attribute_from_list_as_list(Attrs, 'type', "") of [] -> hd(Plugins); T -> T end, @@ -904,7 +907,7 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) -> {set, 'publish'} -> case exmpp_xml:remove_cdata_from_list(Els) of [#xmlel{name = 'item', attrs = ItemAttrs, children = Payload}] -> - ItemId = exmpp_xml:get_attribute_from_list(ItemAttrs, 'id', ""), + ItemId = exmpp_xml:get_attribute_from_list_as_list(ItemAttrs, 'id', ""), publish_item(Host, ServerHost, Node, From, ItemId, Payload); [] -> %% Publisher attempts to publish to persistent node with no item @@ -916,14 +919,14 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) -> "invalid-payload")} end; {set, 'retract'} -> - ForceNotify = case exmpp_xml:get_attribute_from_list(Attrs, 'notify', "") of + ForceNotify = case exmpp_xml:get_attribute_from_list_as_list(Attrs, 'notify', "") of "1" -> true; "true" -> true; _ -> false end, case exmpp_xml:remove_cdata_from_list(Els) of [#xmlel{name = 'item', attrs = ItemAttrs}] -> - ItemId = exmpp_xml:get_attribute_from_list(ItemAttrs, 'id', ""), + ItemId = exmpp_xml:get_attribute_from_list_as_list(ItemAttrs, 'id', ""), delete_item(Host, Node, From, ItemId, ForceNotify); _ -> %% Request does not specify an item @@ -931,18 +934,18 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) -> "item-required")} end; {set, 'subscribe'} -> - JID = exmpp_xml:get_attribute_from_list(Attrs, 'jid', ""), + JID = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'jid', ""), subscribe_node(Host, Node, From, JID); {set, 'unsubscribe'} -> - JID = exmpp_xml:get_attribute_from_list(Attrs, 'jid', ""), - SubId = exmpp_xml:get_attribute_from_list(Attrs, 'subid', ""), + JID = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'jid', ""), + SubId = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'subid', ""), unsubscribe_node(Host, Node, From, JID, SubId); {get, 'items'} -> - MaxItems = exmpp_xml:get_attribute_from_list(Attrs, 'max_items', ""), - SubId = exmpp_xml:get_attribute_from_list(Attrs, 'subid', ""), + MaxItems = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'max_items', ""), + SubId = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'subid', ""), ItemIDs = lists:foldl(fun (#xmlel{name = 'item', attrs = ItemAttrs}, Acc) -> - case exmpp_xml:get_attribute_from_list(ItemAttrs, 'id', "") of + case exmpp_xml:get_attribute_from_list_as_list(ItemAttrs, 'id', "") of "" -> Acc; ItemID -> [ItemID|Acc] end; @@ -972,8 +975,8 @@ iq_pubsub_owner(Host, From, IQType, SubEl, Lang) -> case Action of [#xmlel{name = Name, attrs = Attrs, children = Els}] -> Node = case Host of - {_, _, _} -> exmpp_xml:get_attribute_from_list(Attrs, 'node', ""); - _ -> string_to_node(exmpp_xml:get_attribute_from_list(Attrs, 'node', "")) + {_, _, _} -> exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', ""); + _ -> string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', "")) end, case {IQType, Name} of {get, 'configure'} -> @@ -1008,28 +1011,28 @@ send_authorization_request(Host, Node, Subscriber) -> Lang = "en", %% TODO fix {U, S, R} = Subscriber, Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = - [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', value = "form"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "PubSub subscriber request"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Choose whether to approve this entity's subscription."))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = "FORM_TYPE"}, #xmlattr{name = 'type', value = "hidden"}], children = + [?XMLATTR('var', <<"FORM_TYPE">>), ?XMLATTR('type', <<"hidden">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(?NS_PUBSUB_SUBSCRIBE_AUTH_s)}]}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = "pubsub#node"}, #xmlattr{name = 'type', value = "text-single"}, - #xmlattr{name = 'label', value = translate:translate(Lang, "Node ID")}], children = + [?XMLATTR('var', <<"pubsub#node">>), ?XMLATTR('type', <<"text-single">>), + ?XMLATTR('label', translate:translate(Lang, "Node ID"))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = node_to_string(Node)}]}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'var', value = "pubsub#subscriber_jid"}, - #xmlattr{name = 'type', value = "jid-single"}, - #xmlattr{name = 'label', value = translate:translate(Lang, "Subscriber Address")}], children = + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('var', <<"pubsub#subscriber_jid">>), + ?XMLATTR('type', <<"jid-single">>), + ?XMLATTR('label', translate:translate(Lang, "Subscriber Address"))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = exmpp_jid:jid_to_binary(U, S, R)}]}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = "pubsub#allow"}, - #xmlattr{name = 'type', value = "boolean"}, - #xmlattr{name = 'label', value = translate:translate(Lang, "Allow this Jabber ID to subscribe to this pubsub node?")}], children = + [?XMLATTR('var', <<"pubsub#allow">>), + ?XMLATTR('type', <<"boolean">>), + ?XMLATTR('label', translate:translate(Lang, "Allow this Jabber ID to subscribe to this pubsub node?"))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"false">>}]}]}]}]}, case tree_action(Host, get_node, [Host, Node, Subscriber]) of #pubsub_node{owners = Owners} -> @@ -1045,7 +1048,7 @@ send_authorization_request(Host, Node, Subscriber) -> find_authorization_response(Packet) -> Els = Packet#xmlel.children, XData1 = lists:map(fun(#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = XAttrs} = XEl) -> - case exmpp_xml:get_attribute_from_list(XAttrs, 'type', "") of + case exmpp_xml:get_attribute_from_list_as_list(XAttrs, 'type', "") of "cancel" -> none; _ -> @@ -1077,9 +1080,9 @@ find_authorization_response(Packet) -> send_authorization_approval(Host, JID, Node, Subscription) -> Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'subscription', attrs = - [#xmlattr{name = 'node', value = Node}, - #xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(JID)}, - #xmlattr{name = 'subscription', value = subscription_to_string(Subscription)}]}]), + [?XMLATTR('node', Node), + ?XMLATTR('jid', exmpp_jid:jid_to_binary(JID)), + ?XMLATTR('subscription', subscription_to_string(Subscription))]}]), ejabberd_router ! {route, service_jid(Host), JID, Stanza}. handle_authorization_response(Host, From, To, Packet, XFields) -> @@ -1092,7 +1095,7 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> {_, _, _} -> [SNode]; _ -> string:tokens(SNode, "/") end, - Subscriber = exmpp_jid:list_to_jid(SSubscriber), + Subscriber = exmpp_jid:parse_jid(SSubscriber), Allow = case SAllow of "1" -> true; "true" -> true; @@ -1137,9 +1140,9 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> end. -define(XFIELD(Type, Label, Var, Val), - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'label', value = translate:translate(Lang, Label)}, - #xmlattr{name = 'var', value = Var}], children = + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', Type), + ?XMLATTR('label', translate:translate(Lang, Label)), + ?XMLATTR('var', Var)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Val)}]}]}). -define(BOOLXFIELD(Label, Var, Val), @@ -1153,9 +1156,9 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> ?XFIELD("text-single", Label, Var, Val)). -define(XFIELDOPT(Type, Label, Var, Val, Opts), - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'label', value = translate:translate(Lang, Label)}, - #xmlattr{name = 'var', value = Var}], children = + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', Type), + ?XMLATTR('label', translate:translate(Lang, Label)), + ?XMLATTR('var', Var)], children = lists:map(fun(Opt) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'option', children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = @@ -1202,7 +1205,7 @@ create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) -> {result, []} -> {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = - [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = [#xmlattr{name = 'node', value = node_to_string(NewNode)}]}]}]}; + [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = [?XMLATTR('node', node_to_string(NewNode))]}]}]}; Error -> Error end; false -> @@ -1254,7 +1257,7 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> end end, Reply = [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = - [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}]}]}], + [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = [?XMLATTR('node', node_to_string(Node))]}]}], case transaction(CreateNode, transaction) of {error, Error} -> %% in case we change transaction to sync_dirty... @@ -1359,7 +1362,7 @@ delete_node(Host, Node, Owner) -> %% subscribe_node(Host, Node, From, JID) -> Subscriber = try - jlib:short_prepd_jid(exmpp_jid:list_to_jid(JID)) + jlib:short_prepd_jid(exmpp_jid:parse_jid(JID)) catch _:_ -> {undefined, undefined, undefined} @@ -1397,13 +1400,13 @@ subscribe_node(Host, Node, From, JID) -> Reply = fun(Subscription) -> %% TODO, this is subscription-notification, should depends on node features Fields = - [#xmlattr{name = 'node', value = node_to_string(Node)}, - #xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(Subscriber)}, - #xmlattr{name = 'subscription', value = subscription_to_string(Subscription)}], + [?XMLATTR('node', node_to_string(Node)), + ?XMLATTR('jid', exmpp_jid:jid_to_binary(Subscriber)), + ?XMLATTR('subscription', subscription_to_string(Subscription))], [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = case Subscription of - subscribed -> [#xmlattr{name = 'subid', value = SubId}|Fields]; + subscribed -> [?XMLATTR('subid', SubId)|Fields]; _ -> Fields end}]}] end, @@ -1447,7 +1450,7 @@ subscribe_node(Host, Node, From, JID) -> %%
    • The request specifies a subscription ID that is not valid or current.
    • %% unsubscribe_node(Host, Node, From, JID, SubId) when is_list(JID) -> - Subscriber = try jlib:short_prepd_jid(exmpp_jid:list_to_jid(JID)) + Subscriber = try jlib:short_prepd_jid(exmpp_jid:parse_jid(JID)) catch _:_ -> {undefined, undefined, undefined} @@ -1725,12 +1728,12 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> payload = Payload}) -> ItemAttrs = case ItemId of "" -> []; - _ -> [#xmlattr{name = 'id', value = ItemId}] + _ -> [?XMLATTR('id', ItemId)] end, #xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = ItemAttrs, children = Payload} end, lists:sublist(SendItems, MaxItems)), {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = - [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = + [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = ItemsEls}]}]} end end. @@ -1785,12 +1788,12 @@ send_items(Host, Node, {LU, LS, LR} = LJID, Number) -> fun(#pubsub_item{itemid = {ItemId, _}, payload = Payload}) -> ItemAttrs = case ItemId of "" -> []; - _ -> [#xmlattr{name = 'id', value = ItemId}] + _ -> [?XMLATTR('id', ItemId)] end, #xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = ItemAttrs, children = Payload} end, ToSend), Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = ItemsEls}]), ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(LU, LS, LR), Stanza}. @@ -1821,8 +1824,8 @@ get_affiliations(Host, JID, Plugins) when is_list(Plugins) -> fun({_, none}) -> []; ({Node, Affiliation}) -> [#xmlel{ns = ?NS_PUBSUB, name = 'affiliation', attrs = - [#xmlattr{name = 'node', value = node_to_string(Node)}, - #xmlattr{name = 'affiliation', value = affiliation_to_string(Affiliation)}]}] + [?XMLATTR('node', node_to_string(Node)), + ?XMLATTR('affiliation', affiliation_to_string(Affiliation))]}] end, lists:usort(lists:flatten(Affiliations))), {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'affiliations', children = @@ -1856,11 +1859,11 @@ get_affiliations(Host, Node, JID) -> fun({_, none}) -> []; ({{AU, AS, AR}, Affiliation}) -> [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'affiliation', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(AU, AS, AR)}, - #xmlattr{name = 'affiliation', value = affiliation_to_string(Affiliation)}]}] + [?XMLATTR('jid', exmpp_jid:jid_to_binary(AU, AS, AR)), + ?XMLATTR('affiliation', affiliation_to_string(Affiliation))]}] end, Affiliations), {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = - [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'affiliations', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'affiliations', attrs = [?XMLATTR('node', node_to_string(Node))], children = Entities}]}]} end. @@ -1876,13 +1879,13 @@ set_affiliations(Host, Node, From, EntitiesEls) -> case El of #xmlel{name = 'affiliation', attrs = Attrs} -> JID = try - exmpp_jid:list_to_jid( - exmpp_xml:get_attribute_from_list(Attrs, 'jid', "")) + exmpp_jid:parse_jid( + exmpp_xml:get_attribute_from_list_as_list(Attrs, 'jid', "")) catch _:_ -> error end, Affiliation = string_to_affiliation( - exmpp_xml:get_attribute_from_list(Attrs, 'affiliation', false)), + exmpp_xml:get_attribute_from_list_as_list(Attrs, 'affiliation', false)), if (JID == error) or (Affiliation == false) -> @@ -1958,14 +1961,14 @@ get_subscriptions(Host, JID, Plugins) when is_list(Plugins) -> fun({_, none}) -> []; ({Node, Subscription}) -> [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = - [#xmlattr{name = 'node', value = node_to_string(Node)}, - #xmlattr{name = 'subscription', value = subscription_to_string(Subscription)}]}]; + [?XMLATTR('node', node_to_string(Node)), + ?XMLATTR('subscription', subscription_to_string(Subscription))]}]; ({_, none, _}) -> []; ({Node, Subscription, SubJID}) -> [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = - [#xmlattr{name = 'node', value = node_to_string(Node)}, - #xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(SubJID)}, - #xmlattr{name = 'subscription', value = subscription_to_string(Subscription)}]}] + [?XMLATTR('node', node_to_string(Node)), + ?XMLATTR('jid', exmpp_jid:jid_to_binary(SubJID)), + ?XMLATTR('subscription', subscription_to_string(Subscription))]}] end, lists:usort(lists:flatten(Subscriptions))), {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'subscriptions', children = @@ -1999,16 +2002,16 @@ get_subscriptions(Host, Node, JID) -> fun({_, none}) -> []; ({{AU, AS, AR}, Subscription}) -> [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscription', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(AU, AS, AR)}, - #xmlattr{name = 'subscription', value = subscription_to_string(Subscription)}]}]; + [?XMLATTR('jid', exmpp_jid:jid_to_binary(AU, AS, AR)), + ?XMLATTR('subscription', subscription_to_string(Subscription))]}]; ({{AU, AS, AR}, Subscription, SubId}) -> [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscription', attrs = - [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(AU, AS, AR)}, - #xmlattr{name = 'subscription', value = subscription_to_string(Subscription)}, - #xmlattr{name = 'subid', value =SubId}]}] + [?XMLATTR('jid', exmpp_jid:jid_to_binary(AU, AS, AR)), + ?XMLATTR('subscription', subscription_to_string(Subscription)), + ?XMLATTR('subid', SubId)]}] end, Subscriptions), {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = - [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscriptions', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscriptions', attrs = [?XMLATTR('node', node_to_string(Node))], children = Entities}]}]} end. @@ -2024,14 +2027,14 @@ set_subscriptions(Host, Node, From, EntitiesEls) -> case El of #xmlel{name = 'subscription', attrs = Attrs} -> JID = try - exmpp_jid:list_to_jid( - exmpp_xml:get_attribute_from_list(Attrs, 'jid', "")) + exmpp_jid:parse_jid( + exmpp_xml:get_attribute_from_list_as_list(Attrs, 'jid', "")) catch _:_ -> error end, Subscription = string_to_subscription( - exmpp_xml:get_attribute_from_list(Attrs, 'subscription', false)), + exmpp_xml:get_attribute_from_list_as_list(Attrs, 'subscription', false)), if (JID == error) or (Subscription == false) -> @@ -2137,8 +2140,8 @@ string_to_node(SNode) -> %% @doc

      Generate pubsub service JID.

      service_jid(Host) -> case Host of - {U,S,_} -> #jid{node = U, domain = S, lnode = U, ldomain = S}; - _ -> #jid{domain = Host, ldomain = Host} + {U,S,_} -> exmpp_jid:make_jid(U, S); + _ -> exmpp_jid:make_jid(Host) end. %% @spec (LJID, Subscription, PresenceDelivery) -> boolean() @@ -2188,10 +2191,10 @@ broadcast_publish_item(Host, Node, ItemId, _From, Payload) -> end, ItemAttrs = case ItemId of "" -> []; - _ -> [#xmlattr{name = 'id', value = ItemId}] + _ -> [?XMLATTR('id', ItemId)] end, Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = ItemAttrs, children = Content}]}]), broadcast_stanza(Host, Options, States, Stanza), broadcast_by_caps(Host, Node, Type, Stanza), @@ -2217,12 +2220,12 @@ broadcast_retract_items(Host, Node, ItemIds, ForceNotify) -> fun(ItemId) -> ItemAttrs = case ItemId of "" -> []; - _ -> [#xmlattr{name = 'id', value = ItemId}] + _ -> [?XMLATTR('id', ItemId)] end, #xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = ItemAttrs} end, ItemIds), Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = RetractEls}]), broadcast_stanza(Host, Options, States, Stanza), broadcast_by_caps(Host, Node, Type, Stanza), @@ -2246,7 +2249,7 @@ broadcast_purge_node(Host, Node) -> {result, false}; {result, States} -> Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'purge', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}]}]), + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'purge', attrs = [?XMLATTR('node', node_to_string(Node))]}]), broadcast_stanza(Host, Options, States, Stanza), broadcast_by_caps(Host, Node, Type, Stanza), {result, true}; @@ -2269,7 +2272,7 @@ broadcast_removed_node(Host, Node) -> {result, false}; {result, States} -> Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'delete', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}]}]), + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'delete', attrs = [?XMLATTR('node', node_to_string(Node))]}]), broadcast_stanza(Host, Options, States, Stanza), broadcast_by_caps(Host, Node, Type, Stanza), {result, true}; @@ -2293,14 +2296,14 @@ broadcast_config_notification(Host, Node, Lang) -> {result, States} -> Content = case get_option(Options, deliver_payloads) of true -> - [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', value = "form"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = get_configure_xfields(Type, Options, Lang, Owners)}]; false -> [] end, Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [#xmlattr{name = 'node', value = node_to_string(Node)}], children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = [#xmlattr{name = 'id', value = "configuration"}], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = [?XMLATTR('id', <<"configuration">>)], children = Content}]}]), broadcast_stanza(Host, Options, States, Stanza), broadcast_by_caps(Host, Node, Type, Stanza), @@ -2404,9 +2407,9 @@ get_configure(Host, Node, From, Lang) -> {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'configure', attrs = - [#xmlattr{name = 'node', value = node_to_string(Node)}], children = + [?XMLATTR('node', node_to_string(Node))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = - [#xmlattr{name = 'type', value = "form"}], children = + [?XMLATTR('type', <<"form">>)], children = get_configure_xfields(Type, Options, Lang, Owners) }]}]}]}; _ -> @@ -2420,7 +2423,7 @@ get_default(Host, Node, _From, Lang) -> Options = node_options(Type), {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'default', children = - [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [#xmlattr{name = 'type', value = "form"}], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = get_configure_xfields(Type, Options, Lang, []) }]}]}]}. @@ -2507,9 +2510,9 @@ get_configure_xfields(_Type, Options, Lang, _Owners) -> ?ALIST_CONFIG_FIELD("Specify the access model", access_model, [open, authorize, presence, roster, whitelist]), %% XXX: change to list-multi, include current roster groups as options - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [#xmlattr{name = 'type', value = "text-multi"}, - #xmlattr{name = 'label', value = translate:translate(Lang, "Roster groups allowed to subscribe")}, - #xmlattr{name = 'var', value = "pubsub#roster_groups_allowed"}], children = + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', <<"text-multi">>), + ?XMLATTR('label', translate:translate(Lang, "Roster groups allowed to subscribe")), + ?XMLATTR('var', <<"pubsub#roster_groups_allowed">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Value)}]} || Value <- get_option(Options, roster_groups_allowed, [])]}, ?ALIST_CONFIG_FIELD("Specify the publisher model", publish_model, @@ -2531,7 +2534,7 @@ get_configure_xfields(_Type, Options, Lang, _Owners) -> set_configure(Host, Node, From, Els, Lang) -> case exmpp_xml:remove_cdata_from_list(Els) of [#xmlel{ns = ?NS_DATA_FORMS, name = 'x'} = XEl] -> - case exmpp_xml:get_attribute(XEl, 'type', undefined) of + case exmpp_xml:get_attribute_as_list(XEl, 'type', undefined) of "cancel" -> {result, []}; "submit" -> @@ -2660,9 +2663,8 @@ set_xoption([_ | Opts], NewOpts) -> %%%% plugin handling -plugins(Host) when is_binary(Host) -> - HostL = binary_to_list(Host), - case ets:lookup(gen_mod:get_module_proc(HostL, pubsub_state), plugins) of +plugins(Host) -> + case ets:lookup(gen_mod:get_module_proc(Host, pubsub_state), plugins) of [{plugins, PL}] -> PL; _ -> [?STDNODE] end. @@ -2812,7 +2814,7 @@ extended_error(Error, Ext) -> extended_error(Error, Ext, []). extended_error(Error, unsupported, Feature) -> extended_error(Error, unsupported, - [#xmlattr{name = 'feature', value = Feature}]); + [?XMLATTR('feature', Feature)]); extended_error(Error, Ext, ExtAttrs) -> Pubsub_Err = #xmlel{ns = ?NS_PUBSUB_ERRORS, name = Ext, attrs = ExtAttrs}, exmpp_xml:append_child(exmpp_stanza:error(?NS_JABBER_CLIENT, Error), diff --git a/src/mod_register.erl b/src/mod_register.erl index 8fbd09696..f7800e0b2 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -76,7 +76,7 @@ unauthenticated_iq_register(_Acc, {A, _Port} -> A; _ -> undefined end, - BareJID = exmpp_jid:make_bare_jid(Server), + BareJID = exmpp_jid:make_jid(Server), ResIQ = process_iq(exmpp_jid:make_jid(), BareJID, IQ_Rec, @@ -204,7 +204,7 @@ try_register(User, Server, Password, Source, Lang) -> false -> {error, 'bad-request'}; _ -> - JID = exmpp_jid:make_bare_jid(User, + JID = exmpp_jid:make_jid(User, Server), Access = gen_mod:get_module_opt(Server, ?MODULE, access, all), case acl:match_rule(Server, Access, JID) of @@ -247,7 +247,7 @@ send_welcome_message(JID) -> ok; {Subj, Body} -> ejabberd_router:route( - exmpp_jid:make_bare_jid(Host), + exmpp_jid:make_jid(Host), JID, exmpp_message:normal(Subj, Body)); _ -> @@ -266,9 +266,9 @@ send_registration_notifications(UJID) -> lists:foreach( fun(S) -> try - JID = exmpp_jid:list_to_jid(S), + JID = exmpp_jid:parse_jid(S), ejabberd_router:route( - exmpp_jid:make_bare_jid(Host), + exmpp_jid:make_jid(Host), JID, exmpp_message:chat(Body)) catch diff --git a/src/mod_roster.erl b/src/mod_roster.erl index b63642b8b..d16898e42 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -190,7 +190,7 @@ process_iq_set(From, To, #iq{payload = Request} = IQ_Rec) -> process_item_set(From, To, #xmlel{} = El) -> try - JID1 = exmpp_jid:binary_to_jid(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), + JID1 = exmpp_jid:parse_jid(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), User = exmpp_jid:node(From), LUser = exmpp_jid:lnode(From), LServer = exmpp_jid:ldomain(From), @@ -311,7 +311,7 @@ process_item_els(Item, []) -> push_item(User, Server, From, Item) when is_binary(User), is_binary(Server) -> ejabberd_sm:route(exmpp_jid:make_jid(), - exmpp_jid:make_bare_jid(User, Server), + exmpp_jid:make_jid(User, Server), #xmlel{name = 'broadcast', children = [{item, Item#roster.jid, @@ -438,7 +438,7 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) ok; _ -> ejabberd_router:route( - exmpp_jid:make_bare_jid(User, Server), JID1, + exmpp_jid:make_jid(User, Server), JID1, exmpp_presence:AutoReply()) end, case Push of @@ -449,7 +449,7 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) ok; true -> push_item(User, Server, - exmpp_jid:make_bare_jid(User, Server), Item) + exmpp_jid:make_jid(User, Server), Item) end, true; none -> @@ -596,7 +596,7 @@ set_items(User, Server, #xmlel{children = Els}) -> process_item_set_t(LUser, LServer, #xmlel{} = El) -> try - JID1 = exmpp_jid:binary_to_jid(exmpp_xml:get_attribute(El, 'jid', <<>>)), + JID1 = exmpp_jid:parse_jid(exmpp_xml:get_attribute_as_list(El, 'jid', <<>>)), JID = jlib:short_jid(JID1), LJID = jlib:short_prepd_jid(JID1), Item = #roster{usj = {LUser, LServer, LJID}, @@ -651,7 +651,7 @@ process_item_attrs_ws(Item, []) -> get_in_pending_subscriptions(Ls, User, Server) when is_binary(User), is_binary(Server) -> - JID = exmpp_jid:make_bare_jid(User, Server), + JID = exmpp_jid:make_jid(User, Server), US = {exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID)}, case mnesia:dirty_index_read(roster, US, #roster.us) of Result when list(Result) -> @@ -948,9 +948,9 @@ build_contact_jid_td({U, S, R}) -> end, case JIDURI of [] -> - ?XAC('td', [#xmlattr{name = 'class', value = <<"valign">>}], exmpp_jid:jid_to_list(ContactJID)); + ?XAC('td', [?XMLATTR('class', <<"valign">>)], exmpp_jid:jid_to_list(ContactJID)); URI when is_list(URI) -> - ?XAE('td', [#xmlattr{name = 'class', value = <<"valign">>}], [?AC(JIDURI, exmpp_jid:jid_to_list(ContactJID))]) + ?XAE('td', [?XMLATTR('class', <<"valign">>)], [?AC(JIDURI, exmpp_jid:jid_to_list(ContactJID))]) end. user_roster_parse_query(User, Server, Items, Query) -> @@ -961,7 +961,7 @@ user_roster_parse_query(User, Server, Items, Query) -> error; {value, {_, SJID}} -> try - JID = exmpp_jid:list_to_jid(SJID), + JID = exmpp_jid:parse_jid(SJID), user_roster_subscribe_jid(User, Server, JID), ok catch @@ -986,7 +986,7 @@ user_roster_parse_query(User, Server, Items, Query) -> user_roster_subscribe_jid(User, Server, JID) -> out_subscription(User, Server, JID, subscribe), - UJID = exmpp_jid:make_bare_jid(User, Server), + UJID = exmpp_jid:make_jid(User, Server), ejabberd_router:route( UJID, JID, exmpp_presence:subscribe()). @@ -1001,7 +1001,7 @@ user_roster_item_parse_query(User, Server, Items, Query) -> JID1 = exmpp_jid:make_jid(U, S, R), out_subscription( User, Server, JID1, subscribed), - UJID = exmpp_jid:make_bare_jid(User, Server), + UJID = exmpp_jid:make_jid(User, Server), ejabberd_router:route( UJID, JID1, exmpp_presence:subscribed()), throw(submitted); @@ -1009,7 +1009,7 @@ user_roster_item_parse_query(User, Server, Items, Query) -> case lists:keysearch( "remove" ++ ejabberd_web_admin:term_to_id(JID), 1, Query) of {value, _} -> - UJID = exmpp_jid:make_bare_jid(User, Server), + UJID = exmpp_jid:make_jid(User, Server), Attrs1 = exmpp_xml:set_attribute_in_list([], 'jid', exmpp_jid:jid_to_list(JID)), Attrs2 = exmpp_xml:set_attribute_in_list(Attrs1, diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 4ea9de82d..e56b70a77 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -216,7 +216,7 @@ process_iq_set(From, To, #iq{payload = Request} = IQ_Rec) -> process_item_set(From, To, #xmlel{} = El) -> try - JID1 = exmpp_jid:binary_to_jid(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), + JID1 = exmpp_jid:parse_jid(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), LUser = exmpp_jid:lnode_as_list(From), LServer = exmpp_jid:ldomain_as_list(From), {U0, S0, R0} = LJID = jlib:short_prepd_jid(JID1), @@ -346,7 +346,7 @@ process_item_els(Item, []) -> push_item(User, Server, From, Item) when is_binary(User), is_binary(Server) -> ejabberd_sm:route(exmpp_jid:make_jid(), - exmpp_jid:make_bare_jid(User, Server), + exmpp_jid:make_jid(User, Server), #xmlel{name = 'broadcast', children = [{item, Item#roster.jid, @@ -503,7 +503,7 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) ok; _ -> ejabberd_router:route( - exmpp_jid:make_bare_jid(User, Server), JID1, + exmpp_jid:make_jid(User, Server), JID1, exmpp_presence:AutoReply()) end, case Push of @@ -514,7 +514,7 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) ok; true -> push_item(User, Server, - exmpp_jid:make_bare_jid(User, Server), Item) + exmpp_jid:make_jid(User, Server), Item) end, true; none -> @@ -650,7 +650,7 @@ set_items(User, Server, #xmlel{children = Els}) -> process_item_set_t(LUser, LServer, #xmlel{} = El) -> try - JID1 = exmpp_jid:binary_to_jid(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), + JID1 = exmpp_jid:parse_jid(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), {U0, S0, R0} = LJID = jlib:short_prepd_jid(JID1), Username = ejabberd_odbc:escape(LUser), SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(U0, S0, R0)), @@ -708,7 +708,7 @@ process_item_attrs_ws(Item, []) -> get_in_pending_subscriptions(Ls, User, Server) when is_binary(User), is_binary(Server) -> - JID = exmpp_jid:make_bare_jid(User, Server), + JID = exmpp_jid:make_jid(User, Server), LUser = exmpp_jid:lnode_as_list(JID), LServer = exmpp_jid:ldomain_as_list(JID), Username = ejabberd_odbc:escape(LUser), @@ -809,7 +809,7 @@ get_jid_info(_, User, Server, JID) when is_binary(User), is_binary(Server) -> raw_to_record(LServer, {User, SJID, Nick, SSubscription, SAsk, SAskMessage, _SServer, _SSubscribe, _SType}) when is_binary(LServer) -> try - JID = exmpp_jid:list_to_jid(SJID), + JID = exmpp_jid:parse_jid(SJID), LJID = jlib:short_prepd_jid(JID), Subscription = case SSubscription of "B" -> both; @@ -987,9 +987,9 @@ build_contact_jid_td({U, S, R}) -> end, case JIDURI of [] -> - ?XAC('td', [#xmlattr{name = 'class', value = <<"valign">>}], exmpp_jid:jid_to_list(ContactJID)); + ?XAC('td', [?XMLATTR('class', <<"valign">>)], exmpp_jid:jid_to_list(ContactJID)); URI when is_list(URI) -> - ?XAE('td', [#xmlattr{name = 'class', value = <<"valign">>}], [?AC(JIDURI, exmpp_jid:jid_to_list(ContactJID))]) + ?XAE('td', [?XMLATTR('class', <<"valign">>)], [?AC(JIDURI, exmpp_jid:jid_to_list(ContactJID))]) end. user_roster_parse_query(User, Server, Items, Query) -> @@ -1000,7 +1000,7 @@ user_roster_parse_query(User, Server, Items, Query) -> error; {value, {_, SJID}} -> try - JID = exmpp_jid:list_to_jid(SJID), + JID = exmpp_jid:parse_jid(SJID), user_roster_subscribe_jid(User, Server, JID), ok catch @@ -1025,7 +1025,7 @@ user_roster_parse_query(User, Server, Items, Query) -> user_roster_subscribe_jid(User, Server, JID) -> out_subscription(User, Server, JID, subscribe), - UJID = exmpp_jid:make_bare_jid(User, Server), + UJID = exmpp_jid:make_jid(User, Server), ejabberd_router:route( UJID, JID, exmpp_presence:subscribe()). @@ -1040,7 +1040,7 @@ user_roster_item_parse_query(User, Server, Items, Query) -> JID1 = exmpp_jid:make_jid(U, S, R), out_subscription( User, Server, JID1, subscribed), - UJID = exmpp_jid:make_bare_jid(User, Server), + UJID = exmpp_jid:make_jid(User, Server), ejabberd_router:route( UJID, JID1, exmpp_presence:subscribed()), throw(submitted); @@ -1048,7 +1048,7 @@ user_roster_item_parse_query(User, Server, Items, Query) -> case lists:keysearch( "remove" ++ ejabberd_web_admin:term_to_id(JID), 1, Query) of {value, _} -> - UJID = exmpp_jid:make_bare_jid(User, Server), + UJID = exmpp_jid:make_jid(User, Server), Attrs1 = exmpp_xml:set_attribute_in_list([], 'jid', exmpp_jid:jid_to_list(JID)), Attrs2 = exmpp_xml:set_attribute_in_list(Attrs1, diff --git a/src/mod_service_log.erl b/src/mod_service_log.erl index ab9463d24..499f96e70 100644 --- a/src/mod_service_log.erl +++ b/src/mod_service_log.erl @@ -63,13 +63,13 @@ log_user_receive(_JID, From, To, Packet) -> log_packet(From, To, Packet, Host) -> Loggers = gen_mod:get_module_opt(Host, ?MODULE, loggers, []), - ServerJID = exmpp_jid:make_bare_jid(Host), + ServerJID = exmpp_jid:make_jid(Host), FixedPacket = exmpp_stanza:set_jids(Packet, From, To), lists:foreach( fun(Logger) -> ejabberd_router:route( ServerJID, - exmpp_jid:make_bare_jid(Logger), + exmpp_jid:make_jid(Logger), #xmlel{name = 'route', children = [FixedPacket]}) end, Loggers). diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 2f37a5001..bac6cf5c9 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -224,9 +224,9 @@ set_new_rosteritems(UserFrom, ServerFrom, RIFrom = build_roster_record(UserFrom, ServerFrom, UserTo, ServerTo, NameTo, GroupsFrom), set_item(UserFrom, ServerFrom, ResourceTo, RIFrom), - JIDTo = exmpp_jid:make_bare_jid(UserTo, ServerTo), + JIDTo = exmpp_jid:make_jid(UserTo, ServerTo), - JIDFrom = exmpp_jid:make_bare_jid(UserFrom, ServerFrom), + JIDFrom = exmpp_jid:make_jid(UserFrom, ServerFrom), RITo = build_roster_record(UserTo, ServerTo, UserFrom, ServerFrom, UserFrom,[]), set_item(UserTo, ServerTo, undefined, RITo), @@ -256,7 +256,7 @@ set_item(User, Server, Resource, Item) -> "push" ++ randoms:get_string()), ejabberd_router:route( exmpp_jid:make_jid(User, Server, Resource), - exmpp_jid:make_bare_jid(Server), + exmpp_jid:make_jid(Server), ResIQ). @@ -634,7 +634,7 @@ push_item(User, Server, From, Item) -> %% ejabberd_sm:route(jlib:make_jid("", "", ""), %% jlib:make_jid(User, Server, "") %% why? - ejabberd_sm:route(From, exmpp_jid:make_bare_jid(User, Server), + ejabberd_sm:route(From, exmpp_jid:make_jid(User, Server), #xmlel{name = 'broadcast', children = [{item, Item#roster.jid, @@ -890,7 +890,7 @@ shared_roster_group_parse_query(Host, Group, Query) -> USs; _ -> try - JID = exmpp_jid:list_to_jid(SJID), + JID = exmpp_jid:parse_jid(SJID), [{exmpp_jid:lnode_as_list(JID), exmpp_jid:ldomain_as_list(JID)} | USs] catch _ -> diff --git a/src/mod_stats.erl b/src/mod_stats.erl index a3430f437..f20e1580f 100644 --- a/src/mod_stats.erl +++ b/src/mod_stats.erl @@ -46,7 +46,7 @@ stop(Host) -> process_local_iq(_From, To, #iq{type = get, ns = XMLNS, payload = SubEl} = IQ_Rec) -> - Node = string:tokens(exmpp_xml:get_attribute(SubEl, 'node', ""), "/"), + Node = string:tokens(exmpp_xml:get_attribute_as_list(SubEl, 'node', ""), "/"), Names = get_names(exmpp_xml:get_child_elements(SubEl), []), case get_local_stats(exmpp_jid:domain_as_list(To), Node, Names) of @@ -74,7 +74,7 @@ get_names([_ | Els], Res) -> get_names(Els, Res). --define(STAT(Name), #xmlel{ns = ?NS_STATS, name = 'stat', attrs = [#xmlattr{name = 'name', value = Name}]}). +-define(STAT(Name), #xmlel{ns = ?NS_STATS, name = 'stat', attrs = [?XMLATTR('name', Name)]}). get_local_stats(_Server, [], []) -> {result, @@ -116,16 +116,16 @@ get_local_stats(_Server, _, _) -> -define(STATVAL(Val, Unit), #xmlel{ns = ?NS_STATS, name = 'stat', attrs = - [#xmlattr{name = 'name', value = Name}, - #xmlattr{name = 'units', value = Unit}, - #xmlattr{name = 'value', value = Val} + [?XMLATTR('name', Name), + ?XMLATTR('units', Unit), + ?XMLATTR('value', Val) ]}). -define(STATERR(Code, Desc), #xmlel{ns = ?NS_STATS, name = 'stat', attrs= - [#xmlattr{name = 'name', value = Name}], children = + [?XMLATTR('name', Name)], children = [#xmlel{ns = ?NS_STATS, name = 'error', attrs = - [#xmlattr{name = 'code', value = Code}], children = + [?XMLATTR('code', Code)], children = [#xmlcdata{cdata = Desc}]}]}). diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index c4c8ff1b1..c98802b80 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -275,16 +275,16 @@ set_vcard(User, LServer, VCARD) -> -define(TLFIELD(Type, Label, Var), #xmlel{ns = ?NS_VCARD, name = 'field', attrs = [ - #xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'label', value = translate:translate(Lang, Label)}, - #xmlattr{name = 'var', value = Var}]}). + ?XMLATTR('type', Type), + ?XMLATTR('label', translate:translate(Lang, Label)), + ?XMLATTR('var', Var)]}). -define(FORM(JID), [#xmlel{ns = ?NS_SEARCH, name = 'instructions', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "You need an x:data capable client to search"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = - [#xmlattr{name = 'type', value = <<"form">>}], children = + [?XMLATTR('type', <<"form">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ exmpp_jid:jid_to_list(JID))}]}, #xmlel{ns = ?NS_SEARCH, name = 'instructions', children = @@ -345,8 +345,8 @@ do_route(ServerHost, From, To, Packet) -> #xmlel{ ns = ?NS_DATA_FORMS, name = 'x', - attrs = [#xmlattr{name = 'type', - value = <<"result">>}], + attrs = [?XMLATTR('type', + <<"result">>)], children = search_result(Lang, To, ServerHost, XData)}]}, ResIQ = exmpp_iq:result(Packet, @@ -370,25 +370,19 @@ do_route(ServerHost, From, To, Packet) -> children = [ #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [ - #xmlattr{name = 'category', - value = <<"directory">>}, - #xmlattr{name = 'type', - value = <<"user">>}, - #xmlattr{name = 'name', - value = list_to_binary(translate:translate(Lang, - "vCard User Search"))}]}, + ?XMLATTR('category', <<"directory">>), + ?XMLATTR('type', <<"user">>), + ?XMLATTR('name', translate:translate(Lang, + "vCard User Search"))]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ - #xmlattr{name = 'var', - value = list_to_binary(?NS_DISCO_INFO_s)}]}, + ?XMLATTR('var', ?NS_DISCO_INFO_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ - #xmlattr{name = 'var', - value = list_to_binary(?NS_SEARCH_s)}]}, + ?XMLATTR('var', ?NS_SEARCH_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ - #xmlattr{name = 'var', - value = list_to_binary(?NS_VCARD_s)}]} + ?XMLATTR('var', ?NS_VCARD_s)]} ]}, ResIQ = exmpp_iq:result(Packet, Result), ejabberd_router:route(To, @@ -465,7 +459,7 @@ search_result(Lang, JID, ServerHost, Data) -> -define(FIELD(Var, Val), #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = Var}], children = + [?XMLATTR('var', Var)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = Val}]}]}). diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index f625a1cf7..4f907be80 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -385,15 +385,15 @@ ldap_attribute_to_vcard(_, _) -> -define(TLFIELD(Type, Label, Var), #xmlel{ns = ?NS_VCARD, name = 'field', attrs = [ - #xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'label', value = translate:translate(Lang, Label)}, - #xmlattr{name = 'var', value = Var}]}). + ?XMLATTR('type', Type), + ?XMLATTR('label', translate:translate(Lang, Label)), + ?XMLATTR('var', Var)]}). -define(FORM(JID, SearchFields), [#xmlel{ns = ?NS_SEARCH, name = 'instructions', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "You need an x:data capable client to search"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = - [#xmlattr{name = 'type', value = <<"form">>}], children = + [?XMLATTR('type', <<"form">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ exmpp_jid:jid_to_list(JID))}]}, @@ -440,8 +440,8 @@ route(State, From, To, Packet) -> #xmlel{ ns = ?NS_DATA_FORMS, name = 'x', - attrs = [#xmlattr{name = 'type', - value = <<"result">>}], + attrs = [?XMLATTR('type', + <<"result">>)], children = search_result(Lang, To, State, XData)}]}, ResIQ = exmpp_iq:result(Packet, Result), @@ -465,21 +465,16 @@ route(State, From, To, Packet) -> children = [ #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [ - #xmlattr{name = 'category', - value = <<"directory">>}, - #xmlattr{name = 'type', - value = <<"user">>}, - #xmlattr{name = 'name', - value = list_to_binary(translate:translate(Lang, - "vCard User Search"))}]}, + ?XMLATTR('category', <<"directory">>), + ?XMLATTR('type', <<"user">>), + ?XMLATTR('name', translate:translate(Lang, + "vCard User Search"))]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ - #xmlattr{name = 'var', - value = list_to_binary(?NS_SEARCH_s)}]}, + ?XMLATTR('var', ?NS_SEARCH_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ - #xmlattr{name = 'var', - value = list_to_binary(?NS_VCARD_s)}]} + ?XMLATTR('var', ?NS_VCARD_s)]} ]}, ResIQ = exmpp_iq:result(Packet, Result), ejabberd_router:route(To, @@ -544,7 +539,7 @@ search_result(Lang, JID, State, Data) -> -define(FIELD(Var, Val), #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = Var}], children = + [?XMLATTR('var', Var)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = Val}]}]}). diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl index 96bad68bb..d2db1f9e0 100644 --- a/src/mod_vcard_odbc.erl +++ b/src/mod_vcard_odbc.erl @@ -249,16 +249,16 @@ set_vcard(User, LServer, VCARD) -> -define(TLFIELD(Type, Label, Var), #xmlel{ns = ?NS_VCARD, name = 'field', attrs = [ - #xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'label', value = list_to_binary(translate:translate(Lang, Label))}, - #xmlattr{name = 'var', value = Var}]}). + ?XMLATTR('type', Type), + ?XMLATTR('label', translate:translate(Lang, Label)), + ?XMLATTR('var', Var)]}). -define(FORM(JID), [#xmlel{ns = ?NS_SEARCH, name = 'instructions', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "You need an x:data capable client to search"))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = - [#xmlattr{name = 'type', value = <<"form">>}], children = + [?XMLATTR('type', <<"form">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ exmpp_jid:jid_to_list(JID))}]}, #xmlel{ns = ?NS_SEARCH, name = 'instructions', children = @@ -313,8 +313,8 @@ do_route(ServerHost, From, To, Packet) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [ - #xmlattr{name = 'type', - value = <<"result">>}], + ?XMLATTR('type', + <<"result">>)], children = search_result(Lang, To, ServerHost, XData)}]}, ResIQ = exmpp_iq:result(Packet, Result), @@ -337,21 +337,16 @@ do_route(ServerHost, From, To, Packet) -> children = [ #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [ - #xmlattr{name = 'category', - value = <<"directory">>}, - #xmlattr{name = 'type', - value = <<"user">>}, - #xmlattr{name = 'name', - value = list_to_binary(translate:translate(Lang, - "vCard User Search"))}]}, + ?XMLATTR('category', <<"directory">>), + ?XMLATTR('type', <<"user">>), + ?XMLATTR('name', translate:translate(Lang, + "vCard User Search"))]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ - #xmlattr{name = 'var', - value = list_to_binary(?NS_SEARCH_s)}]}, + ?XMLATTR('var', ?NS_SEARCH_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [ - #xmlattr{name = 'var', - value = list_to_binary(?NS_VCARD_s)}]} + ?XMLATTR('var', ?NS_VCARD_s)]} ]}, ResIQ = exmpp_iq:result(Packet, Result), ejabberd_router:route(To, @@ -429,7 +424,7 @@ search_result(Lang, JID, ServerHost, Data) -> -define(FIELD(Var, Val), #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = - [#xmlattr{name = 'var', value = Var}], children = + [?XMLATTR('var', Var)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = Val}]}]}). diff --git a/src/web/ejabberd_http_poll.erl b/src/web/ejabberd_http_poll.erl index bd006db25..257a6f821 100644 --- a/src/web/ejabberd_http_poll.erl +++ b/src/web/ejabberd_http_poll.erl @@ -414,14 +414,14 @@ resend_message(Packet) -> get_jid("from", ParsedPacket) -> case exmpp_stanza:get_sender(ParsedPacket) of undefined -> - #jid{}; + exmpp_jid:make_jid(); From -> - exmpp_jid:binary_to_jid(From) + exmpp_jid:parse_jid(From) end; get_jid("to", ParsedPacket) -> case exmpp_stanza:get_recipient(ParsedPacket) of undefined -> - #jid{}; + exmpp_jid:make_jid(); From -> - exmpp_jid:binary_to_jid(From) + exmpp_jid:parse_jid(From) end. diff --git a/src/web/ejabberd_web.erl b/src/web/ejabberd_web.erl index 5d1abff76..0d675dee4 100644 --- a/src/web/ejabberd_web.erl +++ b/src/web/ejabberd_web.erl @@ -47,12 +47,12 @@ make_xhtml(Els) -> make_xhtml(HeadEls, Els) -> #xmlel{ns = ?NS_XHTML, name = 'html', attrs = [ - #xmlattr{ns = ?NS_XML, name = 'lang', value = "en"}, - #xmlattr{name = 'lang', value = "en"}], children = [ + exmpp_xml:attribute(?NS_XML, 'lang', <<"en">>), + ?XMLATTR('lang', <<"en">>)], children = [ #xmlel{ns = ?NS_XHTML, name = 'head', children = [ #xmlel{ns = ?NS_XHTML, name = 'meta', attrs = [ - #xmlattr{name = 'http-equiv', value = "Content-Type"}, - #xmlattr{name = 'content', value = "text/html; charset=utf-8"} + ?XMLATTR('http-equiv', <<"Content-Type">>), + ?XMLATTR('content', <<"text/html; charset=utf-8">>) ]} | HeadEls ]}, @@ -70,14 +70,14 @@ make_xhtml(HeadEls, Els) -> -define(XAC(Name, Attrs, Text), ?XAE(Name, Attrs, [?C(Text)])). -define(LI(Els), ?XE('li', Els)). --define(A(URL, Els), ?XAE('a', [#xmlattr{name = 'href', value = URL}], Els)). +-define(A(URL, Els), ?XAE('a', [?XMLATTR('href', URL)], Els)). -define(AC(URL, Text), ?A(URL, [?C(Text)])). -define(P, ?X('p')). -define(BR, ?X('br')). -define(INPUT(Type, Name, Value), - ?XA('input', [#xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'name', value = Name}, - #xmlattr{name = 'value', value = Value}])). + ?XA('input', [?XMLATTR('type', Type), + ?XMLATTR('name', Name), + ?XMLATTR('value', Value)])). error(not_found) -> {404, [], make_xhtml([?XC('h1', "404 Not Found")])}; diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index aa5121bfd..dc3f7201b 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -71,7 +71,7 @@ process(["server", SHost | RPath], #request{auth = Auth} = Request) -> case get_auth(Auth) of {User, Server} -> case acl:match_rule( - Host, configure, exmpp_jid:make_bare_jid(User, Server)) of + Host, configure, exmpp_jid:make_jid(User, Server)) of deny -> ejabberd_web:error(not_allowed); allow -> @@ -93,7 +93,7 @@ process(RPath, #request{auth = Auth} = Request) -> case get_auth(Auth) of {User, Server} -> case acl:match_rule( - global, configure, exmpp_jid:make_bare_jid(User, Server)) of + global, configure, exmpp_jid:make_jid(User, Server)) of deny -> ejabberd_web:error(not_allowed); allow -> @@ -114,7 +114,9 @@ get_auth(Auth) -> case Auth of {SJID, P} -> try - #jid{node = U, domain = S} = exmpp_jid:list_to_jid(SJID), + JID = exmpp_jid:parse_jid(SJID), + U = exmpp_jid:node_as_list(JID), + S = exmpp_jid:domain_as_list(JID), case ejabberd_auth:check_password(U, S, P) of true -> {U, S}; @@ -140,44 +142,44 @@ make_xhtml(Els, Host, Node, Lang) -> MenuItems = make_navigation(Host, Node, Lang), {200, [html], #xmlel{ns = ?NS_XHTML, name = 'html', attrs = [ - #xmlattr{ns = ?NS_XML, name = 'lang', value = Lang}, - #xmlattr{name = 'lang', value = Lang}], children = + exmpp_xml:attribute(?NS_XML, 'lang', Lang), + ?XMLATTR('lang', Lang)], children = [#xmlel{ns = ?NS_XHTML, name = 'head', children = [?XCT('title', "ejabberd Web Admin"), #xmlel{ns = ?NS_XHTML, name = 'meta', attrs = [ - #xmlattr{name = 'http-equiv', value = "Content-Type"}, - #xmlattr{name = 'content', value = "text/html; charset=utf-8"}]}, + ?XMLATTR('http-equiv', <<"Content-Type">>), + ?XMLATTR('content', <<"text/html; charset=utf-8">>)]}, #xmlel{ns = ?NS_XHTML, name = 'link', attrs = [ - #xmlattr{name = 'href', value = Base ++ "favicon.ico"}, - #xmlattr{name = 'type', value = "image/x-icon"}, - #xmlattr{name = 'rel', value = "shortcut icon"}]}, + ?XMLATTR('href', Base ++ "favicon.ico"), + ?XMLATTR('type', <<"image/x-icon">>), + ?XMLATTR('rel', <<"shortcut icon">>)]}, #xmlel{ns = ?NS_XHTML, name = 'link', attrs = [ - #xmlattr{name = 'href', value = Base ++ "style.css"}, - #xmlattr{name = 'type', value = "text/css"}, - #xmlattr{name = 'rel', value = "stylesheet"}]}]}, + ?XMLATTR('href', Base ++ "style.css"), + ?XMLATTR('type', <<"text/css">>), + ?XMLATTR('rel', <<"stylesheet">>)]}]}, ?XE('body', [?XAE('div', - [#xmlattr{name = 'id', value = "container"}], + [?XMLATTR('id', <<"container">>)], [?XAE('div', - [#xmlattr{name = 'id', value = "header"}], + [?XMLATTR('id', <<"header">>)], [?XE('h1', [?ACT("/admin/", "ejabberd Web Admin")] )]), ?XAE('div', - [#xmlattr{name = 'id', value = "navigation"}], + [?XMLATTR('id', <<"navigation">>)], [?XE('ul', MenuItems )]), ?XAE('div', - [#xmlattr{name = 'id', value = "content"}], + [?XMLATTR('id', <<"content">>)], Els), ?XAE('div', - [#xmlattr{name = 'id', value = "clearcopyright"}], + [?XMLATTR('id', <<"clearcopyright">>)], [#xmlcdata{cdata = <<>>}])]), ?XAE('div', - [#xmlattr{name = 'id', value = "copyrightouter"}], + [?XMLATTR('id', <<"copyrightouter">>)], [?XAE('div', - [#xmlattr{name = 'id', value = "copyright"}], + [?XMLATTR('id', <<"copyright">>)], [?XC('p', "ejabberd (c) 2002-2009 ProcessOne") ])])]) @@ -678,7 +680,7 @@ process_admin(Host, error -> [?XREST("Bad format")]; nothing -> [] end ++ - [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XAE('form', [?XMLATTR('action', <<>>), ?XMLATTR('method', <<"post">>)], [?TEXTAREA("acls", integer_to_list(lists:max([16, NumLines])), "80", ACLsP++"."), ?BR, ?INPUTT("submit", "submit", "Submit") @@ -719,7 +721,7 @@ process_admin(Host, nothing -> [] end ++ [?XE('p', [?ACT("../acls-raw/", "Raw")])] ++ - [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XAE('form', [?XMLATTR('action', <<>>), ?XMLATTR('method', <<"post">>)], [acls_to_xhtml(ACLs), ?BR, ?INPUTT("submit", "delete", "Delete Selected"), @@ -785,7 +787,7 @@ process_admin(Host, error -> [?XREST("Bad format")]; nothing -> [] end ++ - [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XAE('form', [?XMLATTR('action', <<>>), ?XMLATTR('method', <<"post">>)], [?TEXTAREA("access", integer_to_list(lists:max([16, NumLines])), "80", AccessP++"."), ?BR, ?INPUTT("submit", "submit", "Submit") @@ -821,7 +823,7 @@ process_admin(Host, nothing -> [] end ++ [?XE('p', [?ACT("../access-raw/", "Raw")])] ++ - [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XAE('form', [?XMLATTR('action', <<>>), ?XMLATTR('method', <<"post">>)], [access_rules_to_xhtml(AccessRules, Lang), ?BR, ?INPUTT("submit", "delete", "Delete Selected") @@ -860,7 +862,7 @@ process_admin(Host, error -> [?XREST("Bad format")]; nothing -> [] end ++ - [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XAE('form', [?XMLATTR('action', <<>>), ?XMLATTR('method', <<"post">>)], [access_rule_to_xhtml(Rules), ?BR, ?INPUTT("submit", "submit", "Submit") @@ -911,17 +913,17 @@ process_admin(Host, list_last_activity(Host, Lang, true, Month) end, make_xhtml([?XCT('h1', "Users Last Activity")] ++ - [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XAE('form', [?XMLATTR('action', <<>>), ?XMLATTR('method', <<"post">>)], [?CT("Period: "), - ?XAE('select', [#xmlattr{name = 'name', value = "period"}], + ?XAE('select', [?XMLATTR('name', <<"period">>)], lists:map( fun({O, V}) -> Sel = if - O == Month -> [#xmlattr{name = 'selected', value = "selected"}]; + O == Month -> [?XMLATTR('selected', <<"selected">>)]; true -> [] end, ?XAC('option', - Sel ++ [#xmlattr{name = 'value', value = O}], V) + Sel ++ [?XMLATTR('value', O)], V) end, [{"month", ?T("Last month")}, {"year", ?T("Last year")}, {"all", ?T("All activity")}])), @@ -1046,15 +1048,15 @@ acl_spec_to_xhtml(ID, Spec) -> acl_spec_select(ID, Opt) -> ?XE('td', - [?XAE('select', [#xmlattr{name = 'name', value = "type" ++ ID}], + [?XAE('select', [?XMLATTR('name', "type" ++ ID)], lists:map( fun(O) -> Sel = if - O == Opt -> [#xmlattr{name = 'selected', value = "selected"}]; + O == Opt -> [?XMLATTR('selected', <<"selected">>)]; true -> [] end, ?XAC('option', - Sel ++ [#xmlattr{name = 'value', value = atom_to_list(O)}], + Sel ++ [?XMLATTR('value', O)], atom_to_list(O)) end, [user, server, user_regexp, server_regexp, node_regexp, user_glob, server_glob, node_glob, all, raw]))]). @@ -1135,14 +1137,20 @@ string_to_spec("user_regexp", Val) -> string_to_spec("server_regexp", Val) -> {server_regexp, Val}; string_to_spec("node_regexp", Val) -> - #jid{lnode = U, ldomain = S, resource = undefined} = exmpp_jid:list_to_jid(Val), + JID = exmpp_jid:parse_jid(Val), + U = exmpp_jid:lnode_as_list(JID), + S = exmpp_jid:ldomain_as_list(JID), + undefined = exmpp_jid:resource(JID), {node_regexp, U, S}; string_to_spec("user_glob", Val) -> string_to_spec2(user_glob, Val); string_to_spec("server_glob", Val) -> {server_glob, Val}; string_to_spec("node_glob", Val) -> - #jid{lnode = U, ldomain = S, resource = undefined} = exmpp_jid:list_to_jid(Val), + JID = exmpp_jid:parse_jid(Val), + U = exmpp_jid:lnode_as_list(JID), + S = exmpp_jid:ldomain_as_list(JID), + undefined = exmpp_jid:resource(JID), {node_glob, U, S}; string_to_spec("all", _) -> all; @@ -1152,9 +1160,12 @@ string_to_spec("raw", Val) -> NewSpec. string_to_spec2(ACLName, Val) -> - #jid{lnode = U, ldomain = S, resource = undefined} = exmpp_jid:list_to_jid(Val), + JID = exmpp_jid:parse_jid(Val), + U = exmpp_jid:lnode_as_list(JID), + S = exmpp_jid:ldomain_as_list(JID), + undefined = exmpp_jid:resource(JID), case U of - "" -> + undefined -> {ACLName, S}; _ -> {ACLName, U, S} @@ -1322,7 +1333,7 @@ list_users(Host, Query, Lang, URLFunc) -> error -> [?XREST("Bad format")]; nothing -> [] end ++ - [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XAE('form', [?XMLATTR('action', <<>>), ?XMLATTR('method', <<"post">>)], [?XE('table', [?XE('tr', [?XC('td', ?T("User") ++ ":"), @@ -1336,7 +1347,7 @@ list_users(Host, Query, Lang, URLFunc) -> ]), ?XE('tr', [?X('td'), - ?XAE('td', [#xmlattr{name = 'class', value = "alignright"}], + ?XAE('td', [?XMLATTR('class', <<"alignright">>)], [?INPUTT("submit", "addnewuser", "Add User")]), ?X('td') ])]), @@ -1352,7 +1363,9 @@ list_users_parse_query(Query, Host) -> {value, {_, Password}} = lists:keysearch("newuserpassword", 1, Query), try - #jid{node = User, domain = Server} = exmpp_jid:list_to_jid(Username++"@"++Host), + JID = exmpp_jid:parse_jid(Username++"@"++Host), + User = exmpp_jid:node(JID), + Server = exmpp_jid:domain(JID), case ejabberd_auth:try_register(User, Server, Password) of {error, _Reason} -> error; @@ -1519,7 +1532,7 @@ user_info(User, Server, Query, Lang) -> error -> [?XREST("Bad format")]; nothing -> [] end ++ - [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XAE('form', [?XMLATTR('action', <<>>), ?XMLATTR('method', <<"post">>)], [?XCT('h3', "Connected Resources:")] ++ FResources ++ [?XCT('h3', "Password:")] ++ FPassword ++ UserItems ++ @@ -1598,11 +1611,11 @@ list_last_activity(Host, Lang, Integral, Period) -> end, Max = lists:max(Hist), [?XAE('ol', - [#xmlattr{name = 'id', value = "lastactivity"}, #xmlattr{name = 'start', value = "0"}], + [?XMLATTR('id', <<"lastactivity">>), ?XMLATTR('start', <<"0">>)], [?XAE('li', - [#xmlattr{name = 'style', value = + [?XMLATTR('style', "width:" ++ integer_to_list( - trunc(90 * V / Max)) ++ "%;"}], + trunc(90 * V / Max)) ++ "%;")], [#xmlcdata{cdata = list_to_binary(integer_to_list(V))}]) || V <- Hist ++ Tail])] end @@ -1694,7 +1707,7 @@ get_node(global, Node, [], Query, Lang) -> ?LI([?ACT(Base ++ "stats/", "Statistics")]), ?LI([?ACT(Base ++ "update/", "Update")]) ] ++ MenuItems2), - ?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + ?XAE('form', [?XMLATTR('action', <<>>), ?XMLATTR('method', <<"post">>)], [?INPUTT('submit', "restart", "Restart"), ?C(" "), ?INPUTT('submit', "stop", "Stop")]) @@ -1746,15 +1759,15 @@ get_node(global, Node, ["db"], Query, Lang) -> [?XC('td', STable), ?XE('td', [db_storage_select( STable, Type, Lang)]), - ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], + ?XAC('td', [?XMLATTR('class', <<"alignright">>)], integer_to_list(Size)), - ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], + ?XAC('td', [?XMLATTR('class', <<"alignright">>)], integer_to_list(Memory)) ]) end, STables), [?XC('h1', ?T("Database Tables at ") ++ atom_to_list(Node))] ++ ResS ++ - [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XAE('form', [?XMLATTR('action', <<>>), ?XMLATTR('method', <<"post">>)], [?XAE('table', [], [?XE('thead', [?XE('tr', @@ -1766,8 +1779,8 @@ get_node(global, Node, ["db"], Query, Lang) -> ?XE('tbody', Rows ++ [?XE('tr', - [?XAE('td', [#xmlattr{name = 'colspan', value = "4"}, - #xmlattr{name = 'class', value = "alignright"}], + [?XAE('td', [?XMLATTR('colspan', <<"4">>), + ?XMLATTR('class', <<"alignright">>)], [?INPUTT("submit", "submit", "Submit")]) ])] @@ -1783,7 +1796,7 @@ get_node(global, Node, ["backup"], Query, Lang) -> [?XC('h1', ?T("Backup of ") ++ atom_to_list(Node))] ++ ResS ++ [?XCT('p', "Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately."), - ?XAE('form', [#xmlattr{name = 'action', value = <<>>}, #xmlattr{name = 'method', value = <<"post">>}], + ?XAE('form', [?XMLATTR('action', <<>>), ?XMLATTR('method', <<"post">>)], [?XAE('table', [], [?XE('tbody', [?XE('tr', @@ -1850,7 +1863,7 @@ get_node(global, Node, ["ports"], Query, Lang) -> {error, ReasonT} -> [?XRES(?T("Error") ++ ": " ++ ReasonT)]; nothing -> [] end ++ - [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XAE('form', [?XMLATTR('action', <<>>), ?XMLATTR('method', <<"post">>)], [node_ports_to_xhtml(NewPorts, Lang)]) ]; @@ -1874,7 +1887,7 @@ get_node(Host, Node, ["modules"], Query, Lang) when is_list(Host) -> error -> [?XREST("Bad format")]; nothing -> [] end ++ - [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XAE('form', [?XMLATTR('action', <<>>), ?XMLATTR('method', <<"post">>)], [node_modules_to_xhtml(NewModules, Lang)]) ]; @@ -1897,25 +1910,25 @@ get_node(global, Node, ["stats"], _Query, Lang) -> ?XAE('table', [], [?XE('tbody', [?XE('tr', [?XCT('td', "Uptime:"), - ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], + ?XAC('td', [?XMLATTR('class', <<"alignright">>)], UpTimeS)]), ?XE('tr', [?XCT('td', "CPU Time:"), - ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], + ?XAC('td', [?XMLATTR('class', <<"alignright">>)], CPUTimeS)]), ?XE('tr', [?XCT('td', "Online Users:"), - ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], + ?XAC('td', [?XMLATTR('class', <<"alignright">>)], integer_to_list(OnlineUsers))]), ?XE('tr', [?XCT('td', "Transactions Committed:"), - ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], + ?XAC('td', [?XMLATTR('class', <<"alignright">>)], integer_to_list(TransactionsCommitted))]), ?XE('tr', [?XCT('td', "Transactions Aborted:"), - ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], + ?XAC('td', [?XMLATTR('class', <<"alignright">>)], integer_to_list(TransactionsAborted))]), ?XE('tr', [?XCT('td', "Transactions Restarted:"), - ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], + ?XAC('td', [?XMLATTR('class', <<"alignright">>)], integer_to_list(TransactionsRestarted))]), ?XE('tr', [?XCT('td', "Transactions Logged:"), - ?XAC('td', [#xmlattr{name = 'class', value = "alignright"}], + ?XAC('td', [?XMLATTR('class', <<"alignright">>)], integer_to_list(TransactionsLogged))]) ]) ])]; @@ -1943,7 +1956,7 @@ get_node(global, Node, ["update"], Query, Lang) -> error -> [?XREST("Bad format")]; nothing -> [] end ++ - [?XAE('form', [#xmlattr{name = 'action', value = ""}, #xmlattr{name = 'method', value = "post"}], + [?XAE('form', [?XMLATTR('action', <<>>), ?XMLATTR('method', <<"post">>)], [ ?XCT('h2', "Update plan"), ?XCT('h3', "Modified modules"), Mods, @@ -1991,15 +2004,15 @@ node_parse_query(Node, Query) -> db_storage_select(ID, Opt, Lang) -> - ?XAE('select', [#xmlattr{name = 'name', value = "table" ++ ID}], + ?XAE('select', [?XMLATTR('name', "table" ++ ID)], lists:map( fun({O, Desc}) -> Sel = if - O == Opt -> [#xmlattr{name = 'selected', value = "selected"}]; + O == Opt -> [?XMLATTR('selected', <<"selected">>)]; true -> [] end, ?XACT('option', - Sel ++ [#xmlattr{name = 'value', value = atom_to_list(O)}], + Sel ++ [?XMLATTR('value', O)], Desc) end, [{ram_copies, "RAM copy"}, {disc_copies, "RAM and disc copy"}, @@ -2088,7 +2101,7 @@ node_backup_parse_query(Node, Query) -> node_ports_to_xhtml(Ports, Lang) -> - ?XAE('table', [#xmlattr{name = 'class', value = <<"withtextareas">>}], + ?XAE('table', [?XMLATTR('class', <<"withtextareas">>)], [?XE('thead', [?XE('tr', [?XCT('td', "Port"), @@ -2105,8 +2118,8 @@ node_ports_to_xhtml(Ports, Lang) -> {NumLines, SOptsClean} = term_to_paragraph(OptsClean, 40), %%ID = term_to_id(E), ?XE('tr', - [?XAE('td', [#xmlattr{name = 'size', value = <<"6">>}], [?C(SPort)]), - ?XAE('td', [#xmlattr{name = 'size', value = <<"15">>}], [?C(SIP)]), + [?XAE('td', [?XMLATTR('size', <<"6">>)], [?C(SPort)]), + ?XAE('td', [?XMLATTR('size', <<"15">>)], [?C(SIP)]), ?XE('td', [?INPUTS("text", "module" ++ SSPort, SModule, "15")]), ?XE('td', [?TEXTAREA("opts" ++ SSPort, integer_to_list(NumLines), "35", SOptsClean)]), @@ -2199,7 +2212,7 @@ node_ports_parse_query(Node, Ports, Query) -> end. node_modules_to_xhtml(Modules, Lang) -> - ?XAE('table', [#xmlattr{name = 'class', value = <<"withtextareas">>}], + ?XAE('table', [?XMLATTR('class', <<"withtextareas">>)], [?XE('thead', [?XE('tr', [?XCT('td', "Module"), @@ -2424,14 +2437,14 @@ make_menu_items2(Lang, Deep, {MURI, MName, [Item | Items]}, Res) -> make_menu_items2(Lang, Deep, {MURI, MName, Items}, Res2). make_menu_item(header, 1, URI, Name, _Lang) -> - ?LI([?XAE('div', [#xmlattr{name = 'id', value = <<"navhead">>}], [?AC(URI, Name)] )]); + ?LI([?XAE('div', [?XMLATTR('id', <<"navhead">>)], [?AC(URI, Name)] )]); make_menu_item(header, 2, URI, Name, _Lang) -> - ?LI([?XAE('div', [#xmlattr{name = 'id', value = <<"navheadsub">>}], [?AC(URI, Name)] )]); + ?LI([?XAE('div', [?XMLATTR('id', <<"navheadsub">>)], [?AC(URI, Name)] )]); make_menu_item(header, 3, URI, Name, _Lang) -> - ?LI([?XAE('div', [#xmlattr{name = 'id', value = <<"navheadsubsub">>}], [?AC(URI, Name)] )]); + ?LI([?XAE('div', [?XMLATTR('id', <<"navheadsubsub">>)], [?AC(URI, Name)] )]); make_menu_item(item, 1, URI, Name, Lang) -> - ?LI([?XAE('div', [#xmlattr{name = 'id', value = "navitem"}], [?ACT(URI, Name)] )]); + ?LI([?XAE('div', [?XMLATTR('id', <<"navitem">>)], [?ACT(URI, Name)] )]); make_menu_item(item, 2, URI, Name, Lang) -> - ?LI([?XAE('div', [#xmlattr{name = 'id', value = "navitemsub"}], [?ACT(URI, Name)] )]); + ?LI([?XAE('div', [?XMLATTR('id', <<"navitemsub">>)], [?ACT(URI, Name)] )]); make_menu_item(item, 3, URI, Name, Lang) -> - ?LI([?XAE('div', [#xmlattr{name = 'id', value = "navitemsubsub"}], [?ACT(URI, Name)] )]). + ?LI([?XAE('div', [?XMLATTR('id', <<"navitemsubsub">>)], [?ACT(URI, Name)] )]). From 0cf0992f78fc982071861ca381e2dea0d214afcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 22 Jan 2009 15:50:43 +0000 Subject: [PATCH 181/582] Fix some eDoc @spec directives. PR: EJABP-1 SVN Revision: 1844 --- ChangeLog | 5 +++++ src/ejabberd_listener.erl | 3 ++- src/web/ejabberd_web_admin.erl | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index c40f7c383..2d11ae76e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-01-22 Jean-Sébastien Pédron + + * src/web/ejabberd_web_admin.erl, src/ejabberd_listener.erl: Fix some + eDoc @spec directives. + 2009-01-21 Jean-Sébastien Pédron * src/acl.erl (match_acl/3): Use string() version of diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index cd5ca0898..03948120f 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -287,12 +287,13 @@ add_listener(PortIP, Module, Opts) -> {error, Error} end. -%% @spec (PortIP) -> ok +%% @spec (PortIP, Module) -> ok %% where %% PortIP = {Port, IPT | IPS} %% Port = integer() %% IPT = tuple() %% IPS = string() +%% Module = atom() delete_listener(PortIP, Module) -> Ports = case ejabberd_config:get_local_option(listen) of undefined -> diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index dc3f7201b..ef68160d5 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -1069,7 +1069,7 @@ term_to_string(T) -> {ok, StringLine, _} = regexp:gsub(StringParagraph, "\\n ", ""), StringLine. -%% @spec (T::any()) -> {NumLines::integer(), Paragraph::string()} +%% @spec (T::any(), Cols::integer()) -> {NumLines::integer(), Paragraph::string()} term_to_paragraph(T, Cols) -> Paragraph = erl_prettypr:format(erl_syntax:abstract(T), [{paper, Cols}]), {ok, FieldList} = regexp:split(Paragraph, "\n"), From a105dcb06020a3a713834a116b35d95bf079d7a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 22 Jan 2009 15:52:30 +0000 Subject: [PATCH 182/582] In get_vh_session_list/1, remove a bad list_to_binary/1; now that exmpp_stringprep return the correct type, it was used on a binary(). PR: EJABP-1 SVN Revision: 1845 --- ChangeLog | 4 ++++ src/ejabberd_sm.erl | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2d11ae76e..9790c6b9e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,10 @@ * src/web/ejabberd_web_admin.erl, src/ejabberd_listener.erl: Fix some eDoc @spec directives. + * src/ejabberd_sm.erl (get_vh_session_list/1): Remove a bad + list_to_binary/1; now that exmpp_stringprep return the correct type, + it was used on a binary(). + 2009-01-21 Jean-Sébastien Pédron * src/acl.erl (match_acl/3): Use string() version of diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 1cdaf92bd..3d3190620 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -241,8 +241,7 @@ dirty_get_my_sessions_list() -> ['$_']}]). get_vh_session_list(Server) when is_binary(Server) -> - LServer = list_to_binary( - exmpp_stringprep:nameprep(Server)), + LServer = exmpp_stringprep:nameprep(Server), mnesia:dirty_select( session, [{#session{usr = '$1', _ = '_'}, From 4417608b27598cf15e261de47f6d4f099e74f684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 22 Jan 2009 15:54:03 +0000 Subject: [PATCH 183/582] Document every functions to clarify the types to give and returned. PR: EJABP-1 SVN Revision: 1846 --- ChangeLog | 3 ++ src/acl.erl | 97 ++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 92 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9790c6b9e..7d721dd10 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,9 @@ list_to_binary/1; now that exmpp_stringprep return the correct type, it was used on a binary(). + * src/acl.erl: Document every functions to clarify the types to + give and returned. + 2009-01-21 Jean-Sébastien Pédron * src/acl.erl (match_acl/3): Use string() version of diff --git a/src/acl.erl b/src/acl.erl index aa672b4bf..976d70a84 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -37,8 +37,38 @@ -include("ejabberd.hrl"). +%% @type aclspec() = all | JID_Exact | JID_Regexp | JID_Glob | Shared_Group +%% JID_Exact = {user, U} | {user, U, S} | {server, S} | {resource, R} +%% U = string() +%% S = string() +%% R = string() +%% JID_Regexp = {user_regexp, UR} | {user_regexp, UR, S} | {server_regexp, SR} | {resource_regexp, RR} | {node_regexp, UR, SR} +%% UR = string() +%% SR = string() +%% RR = string() +%% JID_Glob = {user_glob, UG} | {user_glob, UG, S} | {server_glob, SG} | {resource_glob, RG} | {node_glob, UG, SG} +%% UG = string() +%% SG = string() +%% RG = string() +%% Shared_Group = {shared_group, G} | {shared_group, G, H} +%% G = string() +%% H = string(). + +%% @type acl() = {acl, ACLName, ACLSpec} +%% ACLName = atom() +%% ACLSpec = aclspec(). +%% Record in its Ejabberd-configuration-file variant. + +%% @type storedacl() = {acl, {ACLName, Host}, ACLSpec} +%% ACLName = atom() +%% Host = global | string() +%% ACLSpec = aclspec(). +%% Record in its Mnesia-table-record variant. + -record(acl, {aclname, aclspec}). +%% @spec () -> ok + start() -> mnesia:create_table(acl, [{disc_copies, [node()]}, @@ -47,9 +77,20 @@ start() -> mnesia:add_table_copy(acl, node(), ram_copies), ok. +%% @spec (Host, ACLName, ACLSpec) -> storedacl() +%% Host = global | string() +%% ACLName = atom() +%% ACLSpec = aclspec() + to_record(Host, ACLName, ACLSpec) -> #acl{aclname = {ACLName, Host}, aclspec = normalize_spec(ACLSpec)}. +%% @spec (Host, ACLName, ACLSpec) -> {atomic, ok} | {aborted, Reason} +%% Host = global | string() +%% ACLName = atom() +%% ACLSpec = all | none | aclspec() +%% Reason = term() + add(Host, ACLName, ACLSpec) -> F = fun() -> mnesia:write(#acl{aclname = {ACLName, Host}, @@ -57,6 +98,11 @@ add(Host, ACLName, ACLSpec) -> end, mnesia:transaction(F). +%% @spec (Host, ACLs, Clear) -> ok | false +%% Host = global | string() +%% ACLs = [acl()] +%% Clear = bool() + add_list(Host, ACLs, Clear) -> F = fun() -> if @@ -86,8 +132,17 @@ add_list(Host, ACLs, Clear) -> false end. -normalize(A) -> - exmpp_stringprep:nodeprep(A). +%% @spec (String) -> Prepd_String +%% String = string() +%% Prepd_String = string() + +normalize(String) -> + exmpp_stringprep:nodeprep(String). + +%% @spec (ACLSpec) -> Normalized_ACLSpec +%% ACLSpec = all | none | aclspec() +%% Normalized_ACLSpec = aclspec() + normalize_spec({A, B}) -> {A, normalize(B)}; normalize_spec({A, B, C}) -> @@ -99,6 +154,12 @@ normalize_spec(none) -> +%% @spec (Host, Rule, JID) -> Access +%% Host = global | string() +%% Rule = all | none | atom() +%% JID = exmpp_jid:jid() +%% Access = allow | deny | atom() + match_rule(global, Rule, JID) -> case Rule of all -> allow; @@ -143,18 +204,30 @@ match_rule(Host, Rule, JID) -> end end. +%% @spec (ACLs, JID, Host) -> Access +%% ACLs = [{Access, ACLName}] +%% Access = deny | atom() +%% ACLName = atom() +%% JID = exmpp_jid:jid() +%% Host = string() + match_acls([], _, _Host) -> deny; -match_acls([{Access, ACL} | ACLs], JID, Host) -> - case match_acl(ACL, JID, Host) of +match_acls([{Access, ACLName} | ACLs], JID, Host) -> + case match_acl(ACLName, JID, Host) of true -> Access; _ -> match_acls(ACLs, JID, Host) end. -match_acl(ACL, JID, Host) -> - case ACL of +%% @spec (ACLName, JID, Host) -> bool() +%% ACLName = all | none | atom() +%% JID = exmpp_jid:jid() +%% Host = string() + +match_acl(ACLName, JID, Host) -> + case ACLName of all -> true; none -> false; _ -> @@ -220,10 +293,14 @@ match_acl(ACL, JID, Host) -> false end end, - ets:lookup(acl, {ACL, global}) ++ - ets:lookup(acl, {ACL, Host})) + ets:lookup(acl, {ACLName, global}) ++ + ets:lookup(acl, {ACLName, Host})) end. +%% @spec (String, RegExp) -> bool() +%% String = string() +%% RegExp = string() + is_regexp_match(String, RegExp) -> case regexp:first_match(String, RegExp) of nomatch -> @@ -237,6 +314,10 @@ is_regexp_match(String, RegExp) -> false end. +%% @spec (String, Glob) -> bool() +%% String = string() +%% Glob = string() + is_glob_match(String, Glob) -> is_regexp_match(String, regexp:sh_to_awk(Glob)). From d1cf37bbec9648ff015290a16640ac67e6e75905 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Thu, 22 Jan 2009 22:19:03 +0000 Subject: [PATCH 186/582] Small fixes SVN Revision: 1849 --- ChangeLog | 7 +++++++ src/ejabberd_c2s.erl | 2 +- src/ejabberd_sm.erl | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7d721dd10..dbeab220d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-01-22 Pablo Polvorin + + * src/ejabberd_sm.erl: Fix typo (node -> lnode). + + * src/ejabberd_c2s.erl: Reuse the domain in binary() format to + make the jid. + 2009-01-22 Jean-Sébastien Pédron * src/web/ejabberd_web_admin.erl, src/ejabberd_listener.erl: Fix some diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index f0bebca5f..bb97dc317 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -241,7 +241,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> true -> Lang = exmpp_stream:get_lang(Opening), change_shaper(StateData, - exmpp_jid:make_jid(Server)), + exmpp_jid:make_jid(ServerB)), case exmpp_stream:get_version(Opening) of {1, 0} -> send_element(StateData, Header), diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 3d3190620..9f22b2ba4 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -384,8 +384,8 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- set_session(SID, JID, Priority, Info) -> - US = {exmpp_jid:node(JID), exmpp_jid:ldomain(JID)}, - USR = {exmpp_jid:node(JID), + US = {exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID)}, + USR = {exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID), exmpp_jid:lresource(JID)}, F = fun() -> From 35926b96b44914c3ab4c115a3213cec8d76fd7f1 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 23 Jan 2009 00:10:00 +0000 Subject: [PATCH 187/582] * src/odbc/mysql.sql: Fix complain about comment syntax * src/odbc/pg.sql: Likewise SVN Revision: 1850 --- ChangeLog | 5 +++++ src/odbc/mysql.sql | 2 +- src/odbc/pg.sql | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index dbeab220d..84da75bbf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-01-23 Badlop + + * src/odbc/mysql.sql: Fix complain about comment syntax + * src/odbc/pg.sql: Likewise + 2009-01-22 Pablo Polvorin * src/ejabberd_sm.erl: Fix typo (node -> lnode). diff --git a/src/odbc/mysql.sql b/src/odbc/mysql.sql index cdc20062c..e975b9231 100644 --- a/src/odbc/mysql.sql +++ b/src/odbc/mysql.sql @@ -148,7 +148,7 @@ CREATE TABLE private_storage ( CREATE INDEX i_private_storage_username USING BTREE ON private_storage(username); CREATE UNIQUE INDEX i_private_storage_username_namespace USING BTREE ON private_storage(username(75), namespace(75)); ---- To update from 1.x: +-- To update from 1.x: -- ALTER TABLE rosterusers ADD COLUMN askmessage text AFTER ask; -- UPDATE rosterusers SET askmessage = ''; -- ALTER TABLE rosterusers ALTER COLUMN askmessage SET NOT NULL; diff --git a/src/odbc/pg.sql b/src/odbc/pg.sql index 1cb9eeb4d..3cf3a0949 100644 --- a/src/odbc/pg.sql +++ b/src/odbc/pg.sql @@ -146,14 +146,14 @@ CREATE INDEX i_private_storage_username ON private_storage USING btree (username CREATE UNIQUE INDEX i_private_storage_username_namespace ON private_storage USING btree (username, namespace); ---- To update from 0.9.8: +-- To update from 0.9.8: -- CREATE SEQUENCE spool_seq_seq; -- ALTER TABLE spool ADD COLUMN seq integer; -- ALTER TABLE spool ALTER COLUMN seq SET DEFAULT nextval('spool_seq_seq'); -- UPDATE spool SET seq = DEFAULT; -- ALTER TABLE spool ALTER COLUMN seq SET NOT NULL; ---- To update from 1.x: +-- To update from 1.x: -- ALTER TABLE rosterusers ADD COLUMN askmessage text; -- UPDATE rosterusers SET askmessage = ''; -- ALTER TABLE rosterusers ALTER COLUMN askmessage SET NOT NULL; From b5c8b99272687e0237e78de27dddc5d29f9f2174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 23 Jan 2009 10:10:33 +0000 Subject: [PATCH 188/582] Document every functions to clarify the types to give and returned. PR: EJABP-1 SVN Revision: 1852 --- ChangeLog | 6 ++ src/cyrsasl.erl | 132 ++++++++++++++++++++++++++++++-------- src/cyrsasl_anonymous.erl | 24 +++++++ src/cyrsasl_digest.erl | 69 ++++++++++++++++++++ src/cyrsasl_plain.erl | 30 +++++++++ 5 files changed, 236 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index 84da75bbf..2dd027adf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-01-23 Jean-Sébastien Pédron + + * src/cyrsasl.erl, src/cyrsasl_plain.erl, src/cyrsasl_anonymous.erl, + src/cyrsasl_digest.erl: Document every functions to clarify the types + to give and returned. + 2009-01-23 Badlop * src/odbc/mysql.sql: Fix complain about comment syntax diff --git a/src/cyrsasl.erl b/src/cyrsasl.erl index e742cee17..1f99f63ee 100644 --- a/src/cyrsasl.erl +++ b/src/cyrsasl.erl @@ -34,18 +34,39 @@ server_start/3, server_step/2]). +%% @type saslmechanism() = {sasl_mechanism, Mechanism, Module, Require_Plain} +%% Mechanism = string() +%% Module = atom() +%% Require_Plain = bool(). +%% Registry entry of a supported SASL mechanism. + -record(sasl_mechanism, {mechanism, module, require_plain_password}). + +%% @type saslstate() = {sasl_state, Service, Myname, Realm, GetPassword, CheckPassword, Mech_Mod, Mech_State} +%% Service = string() +%% Myname = string() +%% Realm = string() +%% GetPassword = function() +%% CheckPassword = function() +%% Mech_Mod = atom() +%% Mech_State = term(). +%% State of this process. + -record(sasl_state, {service, myname, realm, get_password, check_password, mech_mod, mech_state}). -export([behaviour_info/1]). +%% @hidden + behaviour_info(callbacks) -> [{mech_new, 3}, {mech_step, 2}]; behaviour_info(_Other) -> undefined. +%% @spec () -> ok + start() -> ets:new(sasl_mechanism, [named_table, public, @@ -55,35 +76,46 @@ start() -> cyrsasl_anonymous:start([]), ok. +%% @spec (Mechanism, Module, Require_Plain) -> true +%% Mechanism = string() +%% Module = atom() +%% Require_Plain = bool() + register_mechanism(Mechanism, Module, RequirePlainPassword) -> ets:insert(sasl_mechanism, #sasl_mechanism{mechanism = Mechanism, module = Module, require_plain_password = RequirePlainPassword}). -%%% TODO: use callbacks -%%-include("ejabberd.hrl"). -%%-include("jlib.hrl"). -%%check_authzid(_State, Props) -> -%% AuthzId = xml:get_attr_s(authzid, Props), -%% case jlib:string_to_jid(AuthzId) of -%% error -> -%% {error, "invalid-authzid"}; -%% JID -> -%% LUser = jlib:nodeprep(xml:get_attr_s(username, Props)), -%% {U, S, R} = jlib:jid_tolower(JID), -%% case R of -%% "" -> -%% {error, "invalid-authzid"}; -%% _ -> -%% case {LUser, ?MYNAME} of -%% {U, S} -> -%% ok; -%% _ -> -%% {error, "invalid-authzid"} -%% end -%% end -%% end. +% TODO use callbacks +%-include("ejabberd.hrl"). +%-include("jlib.hrl"). +%check_authzid(_State, Props) -> +% AuthzId = xml:get_attr_s(authzid, Props), +% case jlib:string_to_jid(AuthzId) of +% error -> +% {error, "invalid-authzid"}; +% JID -> +% LUser = jlib:nodeprep(xml:get_attr_s(username, Props)), +% {U, S, R} = jlib:jid_tolower(JID), +% case R of +% "" -> +% {error, "invalid-authzid"}; +% _ -> +% case {LUser, ?MYNAME} of +% {U, S} -> +% ok; +% _ -> +% {error, "invalid-authzid"} +% end +% end +% end. + +%% @spec (State, Props) -> ok | {error, 'not-authorized'} +%% State = saslstate() +%% Props = [{Key, Value}] +%% Key = atom() +%% Value = string() check_credentials(_State, Props) -> case proplists:get_value(username, Props) of @@ -96,6 +128,10 @@ check_credentials(_State, Props) -> end end. +%% @spec (Host) -> [Mechanism] +%% Host = string() +%% Mechanism = string() + listmech(Host) -> RequirePlainPassword = ejabberd_auth:plain_password_required(Host), @@ -112,6 +148,14 @@ listmech(Host) -> ['$1']}]), filter_anonymous(Host, Mechs). +%% @spec (Service, ServerFQDN, UserRealm, SecFlags, GetPassword, CheckPassword) -> saslstate() +%% Service = string() +%% ServerFQDN = string() +%% UserRealm = string() +%% SecFlags = [term()] +%% GetPassword = function() +%% CheckPassword = function() + server_new(Service, ServerFQDN, UserRealm, _SecFlags, GetPassword, CheckPassword) -> #sasl_state{service = Service, @@ -120,6 +164,22 @@ server_new(Service, ServerFQDN, UserRealm, _SecFlags, get_password = GetPassword, check_password = CheckPassword}. +%% @spec (State, Mech, ClientIn) -> Ok | Continue | Error +%% State = saslstate() +%% Mech = string() +%% ClientIn = string() +%% Ok = {ok, Props} +%% Props = [Prop] +%% Prop = [{Key, Value}] +%% Key = atom() +%% Value = string() +%% Continue = {continue, ServerOut, New_State} +%% ServerOut = string() +%% New_State = saslstate() +%% Error = {error, Reason} | {error, Username, Reason} +%% Reason = term() +%% Username = string() + server_start(State, Mech, ClientIn) -> case lists:member(Mech, listmech(State#sasl_state.myname)) of true -> @@ -139,6 +199,21 @@ server_start(State, Mech, ClientIn) -> {error, 'invalid-mechanism'} end. +%% @spec (State, ClientIn) -> Ok | Continue | Error +%% State = saslstate() +%% ClientIn = string() +%% Ok = {ok, Props} +%% Props = [Prop] +%% Prop = [{Key, Value}] +%% Key = atom() +%% Value = string() +%% Continue = {continue, ServerOut, New_State} +%% ServerOut = string() +%% New_State = saslstate() +%% Error = {error, Reason} | {error, Username, Reason} +%% Reason = term() +%% Username = string() + server_step(State, ClientIn) -> Module = State#sasl_state.mech_mod, MechState = State#sasl_state.mech_state, @@ -159,8 +234,15 @@ server_step(State, ClientIn) -> {error, Error} end. -%% Remove the anonymous mechanism from the list if not enabled for the given -%% host +%% @spec (Host, Mechs) -> [Filtered_Mechs] +%% Host = string() +%% Mechs = [Mech] +%% Mech = string() +%% Filtered_Mechs = [Mech] +%% +%% @doc Remove the anonymous mechanism from the list if not enabled for +%% the given host. + filter_anonymous(Host, Mechs) -> case ejabberd_auth_anonymous:is_sasl_anonymous_enabled(Host) of true -> Mechs; diff --git a/src/cyrsasl_anonymous.erl b/src/cyrsasl_anonymous.erl index c8f913ce6..84dc24831 100644 --- a/src/cyrsasl_anonymous.erl +++ b/src/cyrsasl_anonymous.erl @@ -31,18 +31,42 @@ -behaviour(cyrsasl). +%% @type mechstate() = {state, Server} +%% Server = string(). + -record(state, {server}). +%% @spec (Opts) -> true +%% Opts = term() + start(_Opts) -> cyrsasl:register_mechanism("ANONYMOUS", ?MODULE, false), ok. +%% @spec () -> ok + stop() -> ok. +%% @spec (Host, GetPassword, CheckPassword) -> {ok, State} +%% Host = string() +%% GetPassword = function() +%% CheckPassword = function() +%% State = mechstate() + mech_new(Host, _GetPassword, _CheckPassword) -> {ok, #state{server = Host}}. +%% @spec (State, ClientIn) -> Ok | Error +%% State = mechstate() +%% ClientIn = string() +%% Ok = {ok, Props} +%% Props = [Prop] +%% Prop = {username, Username} | {auth_module, AuthModule} +%% Username = string() +%% AuthModule = ejabberd_auth_anonymous +%% Error = {error, 'not-authorized'} + mech_step(State, _ClientIn) -> %% We generate a random username: User = lists:concat([randoms:get_string() | tuple_to_list(now())]), diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl index b585c6e6c..1f07e407f 100644 --- a/src/cyrsasl_digest.erl +++ b/src/cyrsasl_digest.erl @@ -18,21 +18,56 @@ -behaviour(cyrsasl). +%% @type mechstate() = {state, Step, Nonce, Username, AuthzId, GetPassword, AuthModule, Host} +%% Step = 1 | 3 | 5 +%% Nonce = string() +%% Username = string() +%% AuthzId = string() +%% GetPassword = function() +%% AuthModule = atom() +%% Host = string(). + -record(state, {step, nonce, username, authzid, get_password, auth_module, host}). +%% @spec (Opts) -> true +%% Opts = term() + start(_Opts) -> cyrsasl:register_mechanism("DIGEST-MD5", ?MODULE, true). +%% @spec () -> ok + stop() -> ok. +%% @spec (Host, GetPassword, CheckPassword) -> {ok, State} +%% Host = string() +%% GetPassword = function() +%% CheckPassword = function() +%% State = mechstate() + mech_new(Host, GetPassword, _CheckPassword) -> {ok, #state{step = 1, nonce = randoms:get_string(), host = Host, get_password = GetPassword}}. +%% @spec (State, ClientIn) -> Ok | Continue | Error +%% State = mechstate() +%% ClientIn = string() +%% Ok = {ok, Props} +%% Props = [Prop] +%% Prop = {username, Username} | {authzid, AuthzId} | {auth_module, AuthModule} +%% Username = string() +%% AuthzId = string() +%% AuthModule = atom() +%% Continue = {continue, ServerOut, New_State} +%% ServerOut = string() +%% New_State = mechstate() +%% Error = {error, Reason} | {error, Reason, Username} +%% Reason = term() + mech_step(#state{step = 1, nonce = Nonce} = State, _) -> {continue, "nonce=\"" ++ Nonce ++ @@ -85,9 +120,16 @@ mech_step(A, B) -> ?DEBUG("SASL DIGEST: A ~p B ~p", [A,B]), {error, 'bad-protocol'}. +%% @spec (S) -> [{Key, Value}] | bad +%% S = string() +%% Key = string() +%% Value = string() + parse(S) -> parse1(S, "", []). +%% @hidden + parse1([$= | Cs], S, Ts) -> parse2(Cs, lists:reverse(S), "", Ts); parse1([$, | Cs], [], Ts) -> @@ -101,6 +143,8 @@ parse1([], [], T) -> parse1([], _S, _T) -> bad. +%% @hidden + parse2([$\" | Cs], Key, Val, Ts) -> parse3(Cs, Key, Val, Ts); parse2([C | Cs], Key, Val, Ts) -> @@ -108,6 +152,8 @@ parse2([C | Cs], Key, Val, Ts) -> parse2([], _, _, _) -> bad. +%% @hidden + parse3([$\" | Cs], Key, Val, Ts) -> parse4(Cs, Key, Val, Ts); parse3([$\\, C | Cs], Key, Val, Ts) -> @@ -117,6 +163,8 @@ parse3([C | Cs], Key, Val, Ts) -> parse3([], _, _, _) -> bad. +%% @hidden + parse4([$, | Cs], Key, Val, Ts) -> parse1(Cs, "", [{Key, lists:reverse(Val)} | Ts]); parse4([$\s | Cs], Key, Val, Ts) -> @@ -127,6 +175,10 @@ parse4([], Key, Val, Ts) -> parse1([], "", [{Key, lists:reverse(Val)} | Ts]). +%% @spec (DigestURICase, JabberHost) -> bool() +%% DigestURICase = string() +%% JabberHost = string() +%% %% @doc Check if the digest-uri is valid. %% RFC-2831 allows to provide the IP address in Host, %% however ejabberd doesn't allow that. @@ -134,6 +186,7 @@ parse4([], Key, Val, Ts) -> %% is provided by several hosts (being one of them server3.example.org), %% then digest-uri can be like xmpp/server3.example.org/jabber.example.org %% In that case, ejabberd only checks the service name, not the host. + is_digesturi_valid(DigestURICase, JabberHost) -> DigestURI = exmpp_stringprep:to_lower(DigestURICase), case catch string:tokens(DigestURI, "/") of @@ -148,14 +201,20 @@ is_digesturi_valid(DigestURICase, JabberHost) -> +%% @hidden + digit_to_xchar(D) when (D >= 0) and (D < 10) -> D + 48; digit_to_xchar(D) -> D + 87. +%% @hidden + hex(S) -> hex(S, []). +%% @hidden + hex([], Res) -> lists:reverse(Res); hex([N | Ns], Res) -> @@ -163,6 +222,16 @@ hex([N | Ns], Res) -> digit_to_xchar(N div 16) | Res]). +%% @spec (KeyVals, User, Passwd, Nonce, AuthzId, A2Prefix) -> string() +%% KeyVals = [{Key, Value}] +%% Key = string() +%% Value = string() +%% User = string() +%% Passwd = string() +%% Nonce = string() +%% AuthzId = nil() | string() +%% A2Prefix = string() + response(KeyVals, User, Passwd, Nonce, AuthzId, A2Prefix) -> Realm = proplists:get_value("realm", KeyVals, ""), CNonce = proplists:get_value("cnonce", KeyVals, ""), diff --git a/src/cyrsasl_plain.erl b/src/cyrsasl_plain.erl index b3ecff83c..ffcf4b104 100644 --- a/src/cyrsasl_plain.erl +++ b/src/cyrsasl_plain.erl @@ -31,18 +31,44 @@ -behaviour(cyrsasl). +%% @type mechstate() = {state, CheckPassword} +%% CheckPassword = function(). + -record(state, {check_password}). +%% @spec (Opts) -> true +%% Opts = term() + start(_Opts) -> cyrsasl:register_mechanism("PLAIN", ?MODULE, false), ok. +%% @spec () -> ok + stop() -> ok. +%% @spec (Host, GetPassword, CheckPassword) -> {ok, State} +%% Host = string() +%% GetPassword = function() +%% CheckPassword = function() +%% State = mechstate() + mech_new(_Host, _GetPassword, CheckPassword) -> {ok, #state{check_password = CheckPassword}}. +%% @spec (State, ClientIn) -> Ok | Error +%% State = mechstate() +%% ClientIn = string() +%% Ok = {ok, Props} +%% Props = [Prop] +%% Prop = {username, Username} | {authzid, AuthzId} | {auth_module, AuthModule} +%% Username = string() +%% AuthzId = string() +%% AuthModule = atom() +%% Error = {error, Reason} | {error, Reason, Username} +%% Reason = term() + mech_step(State, ClientIn) -> case parse(ClientIn) of [AuthzId, User, Password] -> @@ -58,9 +84,13 @@ mech_step(State, ClientIn) -> end. +%% @hidden + parse(S) -> parse1(S, "", []). +%% @hidden + parse1([0 | Cs], S, T) -> parse1(Cs, "", [lists:reverse(S) | T]); parse1([C | Cs], S, T) -> From 69a2194efe565701335ca84c5137ebc3d2fc46ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 23 Jan 2009 14:06:48 +0000 Subject: [PATCH 189/582] exmpp_server_sasl:next_step/1 returns the mechanism as list() again, so the call to binary_to_list/1 isn't necessary anymore. PR: EJABP-1 SVN Revision: 1853 --- ChangeLog | 4 ++++ src/ejabberd_c2s.erl | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 2dd027adf..17cca2be9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,10 @@ src/cyrsasl_digest.erl: Document every functions to clarify the types to give and returned. + * src/ejabberd_c2s.erl: exmpp_server_sasl:next_step/1 returns the + mechanism as list() again, so the call to binary_to_list/1 isn't + necessary anymore. + 2009-01-23 Badlop * src/odbc/mysql.sql: Fix complain about comment syntax diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index bb97dc317..e1d70770d 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -506,7 +506,7 @@ wait_for_feature_request({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, {?NS_SASL, 'auth'} when not ((SockMod == gen_tcp) and TLSRequired) -> {auth, Mech, ClientIn} = exmpp_server_sasl:next_step(El), case cyrsasl:server_start(StateData#state.sasl_state, - binary_to_list(Mech), + Mech, ClientIn) of {ok, Props} -> (StateData#state.sockmod):reset_stream( From 4badd3b6ac0eaeaa891ff6a3b185ab652d20326c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 30 Jan 2009 15:50:13 +0000 Subject: [PATCH 190/582] Disable "TODO:" interpretation in eDoc because usually, the following text isn't in eDoc format. PR: EJABP-1 SVN Revision: 1857 --- ChangeLog | 5 +++++ doc/api/Makefile | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 17cca2be9..f0a4cbbaa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-01-30 Jean-Sébastien Pédron + + * doc/api/Makefile: Disable "TODO:" interpretation in eDoc because + usually, the following text isn't in eDoc format. + 2009-01-23 Jean-Sébastien Pédron * src/cyrsasl.erl, src/cyrsasl_plain.erl, src/cyrsasl_anonymous.erl, diff --git a/doc/api/Makefile b/doc/api/Makefile index de356ef20..248e3c55d 100644 --- a/doc/api/Makefile +++ b/doc/api/Makefile @@ -15,4 +15,4 @@ clean: docs: erl -noshell -run edoc_run application \ - "'$(APPNAME)'" '"$(SRCDIR)"' '[{dir,"$(DOCDIR)"},{packages, false},{todo,true},{private,true},{def,{vsn,"$(VSN)"}},{stylesheet,"process-one.css"},{overview,"$(DOCDIR)/overview.edoc"}]' -s init stop + "'$(APPNAME)'" '"$(SRCDIR)"' '[{dir,"$(DOCDIR)"},{packages, false},{todo,false},{private,true},{def,{vsn,"$(VSN)"}},{stylesheet,"process-one.css"},{overview,"$(DOCDIR)/overview.edoc"}]' -s init stop From 829002694030f805386745043598ca9b498f9345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 5 Feb 2009 11:13:01 +0000 Subject: [PATCH 191/582] o Document the type of the argument(s) and the returned type of every functions. o Add guardians expression to many functions of ejabberd_auth and ejabberd_auth_anonymous to ensure at an early stage that we were given the right arguments. Other modules are not changed because they are only used by ejabberd_auth which already does the check. PR: EJABP-1 SVN Revision: 1863 --- ChangeLog | 14 +++ src/ejabberd_auth.erl | 197 ++++++++++++++++++++++++-------- src/ejabberd_auth_anonymous.erl | 160 ++++++++++++++++++++------ src/ejabberd_auth_external.erl | 58 +++++++++- src/ejabberd_auth_internal.erl | 92 ++++++++++++++- src/ejabberd_auth_ldap.erl | 87 ++++++++++++++ src/ejabberd_auth_odbc.erl | 78 ++++++++++++- src/ejabberd_auth_pam.erl | 78 +++++++++++-- 8 files changed, 672 insertions(+), 92 deletions(-) diff --git a/ChangeLog b/ChangeLog index f0a4cbbaa..263a79620 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2009-02-05 Jean-Sébastien Pédron + + * src/ejabberd_auth.erl, src/ejabberd_auth_anonymous.erl, + src/ejabberd_auth_external.erl, src/ejabberd_auth_internal.erl, + src/ejabberd_auth_ldap.erl, src/ejabberd_auth_odbc.erl, + src/ejabberd_auth_pam.erl: Document the type of the argument(s) and + the returned type of every functions. + + * src/ejabberd_auth.erl, src/ejabberd_auth_anonymous.erl: Add + guardians expression to many functions to ensure at an early stage + that we were given the right arguments. Other modules are not changed + because they are only used by ejabberd_auth which already does the + check. + 2009-01-30 Jean-Sébastien Pédron * doc/api/Makefile: Disable "TODO:" interpretation in eDoc because diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 209373174..6156b13bc 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -56,9 +56,16 @@ -include("ejabberd.hrl"). +%% @type authmodule() = ejabberd_auth_anonymous | ejabberd_auth_external | +%% ejabberd_auth_internal | ejabberd_auth_ldap | +%% ejabberd_auth_odbc | ejabberd_auth_pam | atom(). + %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- + +%% @spec () -> term() + start() -> lists:foreach( fun(Host) -> @@ -68,42 +75,56 @@ start() -> end, auth_modules(Host)) end, ?MYHOSTS). -plain_password_required(Server) -> +%% @spec (Server) -> bool() +%% Server = string() + +plain_password_required(Server) when is_list(Server) -> lists:any( fun(M) -> M:plain_password_required() end, auth_modules(Server)). +%% @spec (User, Server, Password) -> bool() +%% User = string() +%% Server = string() +%% Password = string() %% @doc Check if the user and password can login in server. -%% @spec (User::string(), Server::string(), Password::string()) -> -%% true | false -check_password(User, Server, Password) -> + +check_password(User, Server, Password) + when is_list(User), is_list(Server), is_list(Password) -> lists:any( fun(M) -> M:check_password(User, Server, Password) end, auth_modules(Server)). +%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% User = string() +%% Server = string() +%% Password = string() +%% StreamID = string() +%% Digest = string() %% @doc Check if the user and password can login in server. -%% @spec (User::string(), Server::string(), Password::string(), -%% StreamID::string(), Digest::string()) -> -%% true | false -check_password(User, Server, Password, StreamID, Digest) -> + +check_password(User, Server, Password, StreamID, Digest) + when is_list(User), is_list(Server), is_list(Password), + is_list(StreamID), is_list(Digest) -> lists:any( fun(M) -> M:check_password(User, Server, Password, StreamID, Digest) end, auth_modules(Server)). +%% @spec (User, Server, Password) -> {true, AuthModule} | false +%% User = string() +%% Server = string() +%% Password = string() +%% AuthModule = authmodule() %% @doc Check if the user and password can login in server. %% The user can login if at least an authentication method accepts the user %% and the password. %% The first authentication method that accepts the credentials is returned. -%% @spec (User::string(), Server::string(), Password::string()) -> -%% {true, AuthModule} | false -%% where -%% AuthModule = ejabberd_auth_anonymous | ejabberd_auth_external -%% | ejabberd_auth_internal | ejabberd_auth_ldap -%% | ejabberd_auth_odbc | ejabberd_auth_pam -check_password_with_authmodule(User, Server, Password) -> + +check_password_with_authmodule(User, Server, Password) + when is_list(User), is_list(Server), is_list(Password) -> Res = lists:dropwhile( fun(M) -> not apply(M, check_password, @@ -114,7 +135,17 @@ check_password_with_authmodule(User, Server, Password) -> [AuthMod | _] -> {true, AuthMod} end. -check_password_with_authmodule(User, Server, Password, StreamID, Digest) -> +%% @spec (User, Server, Password, StreamID, Digest) -> {true, AuthModule} | false +%% User = string() +%% Server = string() +%% Password = string() +%% StreamID = string() +%% Digest = string() +%% AuthModule = authmodule() + +check_password_with_authmodule(User, Server, Password, StreamID, Digest) + when is_list(User), is_list(Server), is_list(Password), + is_list(StreamID), is_list(Digest) -> Res = lists:dropwhile( fun(M) -> not apply(M, check_password, @@ -125,13 +156,17 @@ check_password_with_authmodule(User, Server, Password, StreamID, Digest) -> [AuthMod | _] -> {true, AuthMod} end. -%% @spec (User::string(), Server::string(), Password::string()) -> -%% ok | {error, ErrorType} -%% where ErrorType = empty_password | not_allowed | invalid_jid +%% @spec (User, Server, Password) -> ok | {error, ErrorType} +%% User = string() +%% Server = string() +%% Password = string() +%% ErrorType = empty_password | not_allowed | invalid_jid + set_password(_User, _Server, "") -> %% We do not allow empty password {error, empty_password}; -set_password(User, Server, Password) -> +set_password(User, Server, Password) + when is_list(User), is_list(Server), is_list(Password) -> lists:foldl( fun(M, {error, _}) -> M:set_password(User, Server, Password); @@ -140,10 +175,15 @@ set_password(User, Server, Password) -> end, {error, not_allowed}, auth_modules(Server)). %% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() | nil() + try_register(_User, _Server, "") -> %% We do not allow empty password {error, not_allowed}; -try_register(User, Server, Password) -> +try_register(User, Server, Password) + when is_list(User), is_list(Server), is_list(Password) -> case is_user_exists(User,Server) of true -> {atomic, exists}; @@ -168,27 +208,48 @@ try_register(User, Server, Password) -> end end. -%% Registered users list do not include anonymous users logged +%% @spec () -> [{LUser, LServer}] +%% LUser = string() +%% LServer = string() +%% @doc Registered users list do not include anonymous users logged. + dirty_get_registered_users() -> lists:flatmap( fun(M) -> M:dirty_get_registered_users() end, auth_modules()). -%% Registered users list do not include anonymous users logged -get_vh_registered_users(Server) -> +%% @spec (Server) -> [{LUser, LServer}] +%% Server = string() +%% LUser = string() +%% LServer = string() +%% @doc Registered users list do not include anonymous users logged. + +get_vh_registered_users(Server) when is_list(Server) -> lists:flatmap( fun(M) -> M:get_vh_registered_users(Server) end, auth_modules(Server)). -get_vh_registered_users(Server, Opts) -> +%% @spec (Server, Opts) -> [{LUser, LServer}] +%% Server = string() +%% Opts = [{Opt, Val}] +%% Opt = atom() +%% Val = term() +%% LUser = string() +%% LServer = string() + +get_vh_registered_users(Server, Opts) when is_list(Server) -> lists:flatmap( fun(M) -> M:get_vh_registered_users(Server, Opts) end, auth_modules(Server)). -get_vh_registered_users_number(Server) -> +%% @spec (Server) -> Users_Number +%% Server = string() +%% Users_Number = integer() + +get_vh_registered_users_number(Server) when is_list(Server) -> lists:sum( lists:map( fun(M) -> @@ -201,7 +262,14 @@ get_vh_registered_users_number(Server) -> end end, auth_modules(Server))). -get_vh_registered_users_number(Server, Opts) -> +%% @spec (Server, Opts) -> Users_Number +%% Server = string() +%% Opts = [{Opt, Val}] +%% Opt = atom() +%% Val = term() +%% Users_Number = integer() + +get_vh_registered_users_number(Server, Opts) when is_list(Server) -> lists:sum( lists:map( fun(M) -> @@ -214,9 +282,13 @@ get_vh_registered_users_number(Server, Opts) -> end end, auth_modules(Server))). +%% @spec (User, Server) -> Password | false +%% User = string() +%% Server = string() +%% Password = string() %% @doc Get the password of the user. -%% @spec (User::string(), Server::string()) -> Password::string() -get_password(User, Server) -> + +get_password(User, Server) when is_list(User), is_list(Server) -> lists:foldl( fun(M, false) -> M:get_password(User, Server); @@ -224,7 +296,13 @@ get_password(User, Server) -> Password end, false, auth_modules(Server)). -get_password_s(User, Server) -> +%% @spec (User, Server) -> Password | nil() +%% User = string() +%% Server = string() +%% Password = string() +%% @doc Get the password of the user. + +get_password_s(User, Server) when is_list(User), is_list(Server) -> case get_password(User, Server) of false -> ""; @@ -232,10 +310,15 @@ get_password_s(User, Server) -> Password end. +%% @spec (User, Server) -> {Password, AuthModule} | {false, none} +%% User = string() +%% Server = string() +%% Password = string() +%% AuthModule = authmodule() %% @doc Get the password of the user and the auth module. -%% @spec (User::string(), Server::string()) -> -%% {Password::string(), AuthModule::atom()} | {false, none} -get_password_with_authmodule(User, Server) -> + +get_password_with_authmodule(User, Server) + when is_list(User), is_list(Server) -> lists:foldl( fun(M, {false, _}) -> {M:get_password(User, Server), M}; @@ -243,26 +326,39 @@ get_password_with_authmodule(User, Server) -> {Password, AuthModule} end, {false, none}, auth_modules(Server)). -%% Returns true if the user exists in the DB or if an anonymous user is logged -%% under the given name -is_user_exists(User, Server) -> +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() +%% @doc Returns true if the user exists in the DB or if an anonymous +%% user is logged under the given name. + +is_user_exists(User, Server) when is_list(User), is_list(Server) -> lists:any( fun(M) -> M:is_user_exists(User, Server) end, auth_modules(Server)). -%% Check if the user exists in all authentications module except the module -%% passed as parameter -is_user_exists_in_other_modules(Module, User, Server) -> +%% @spec (Module, User, Server) -> bool +%% Module = authmodule() +%% User = string() +%% Server = string() +%% @doc Check if the user exists in all authentications module except +%% the module passed as parameter. + +is_user_exists_in_other_modules(Module, User, Server) + when is_list(User), is_list(Server) -> lists:any( fun(M) -> M:is_user_exists(User, Server) end, auth_modules(Server)--[Module]). %% @spec (User, Server) -> ok | error | {error, not_allowed} +%% User = string() +%% Server = string() %% @doc Remove user. %% Note: it may return ok even if there was some problem removing the user. -remove_user(User, Server) -> + +remove_user(User, Server) when is_list(User), is_list(Server) -> R = lists:foreach( fun(M) -> M:remove_user(User, Server) @@ -274,11 +370,16 @@ remove_user(User, Server) -> R. %% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request | error +%% User = string() +%% Server = string() +%% Password = string() %% @doc Try to remove user if the provided password is correct. %% The removal is attempted in each auth method provided: %% when one returns 'ok' the loop stops; %% if no method returns 'ok' then it returns the error message indicated by the last method attempted. -remove_user(User, Server, Password) -> + +remove_user(User, Server, Password) + when is_list(User), is_list(Server), is_list(Password) -> R = lists:foldl( fun(_M, ok = Res) -> Res; @@ -295,8 +396,11 @@ remove_user(User, Server, Password) -> %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- -%% Return the lists of all the auth modules actually used in the -%% configuration + +%% @spec () -> [authmodule()] +%% @doc Return the lists of all the auth modules actually used in the +%% configuration. + auth_modules() -> lists:usort( lists:flatmap( @@ -304,8 +408,11 @@ auth_modules() -> auth_modules(Server) end, ?MYHOSTS)). -%% Return the list of authenticated modules for a given host -auth_modules(Server) -> +%% @spec (Server) -> [authmodule()] +%% Server = string() +%% @doc Return the list of authenticated modules for a given host. + +auth_modules(Server) when is_list(Server) -> LServer = exmpp_stringprep:nameprep(Server), Method = ejabberd_config:get_local_option({auth_method, LServer}), Methods = if diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index 3135c6dd3..419398fc2 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -53,12 +53,18 @@ remove_user/3, plain_password_required/0]). +-include_lib("exmpp/include/exmpp_xmpp.hrl"). + -include("ejabberd.hrl"). -record(anonymous, {us, sid}). -%% Create the anonymous table if at least one virtual host has anonymous features enabled -%% Register to login / logout events -start(Host) -> +%% @spec (Host) -> ok +%% Host = string() +%% @doc Create the anonymous table if at least one virtual host has +%% anonymous features enabled. +%% Register to login / logout events. + +start(Host) when is_list(Host) -> %% TODO: Check cluster mode mnesia:create_table(anonymous, [{ram_copies, [node()]}, {type, bag}, @@ -70,13 +76,20 @@ start(Host) -> ?MODULE, unregister_connection, 100), ok. -%% Return true if anonymous is allowed for host or false otherwise -allow_anonymous(Host) -> +%% @spec (Host) -> bool() +%% Host = string() +%% @doc Return true if anonymous is allowed for host or false otherwise. + +allow_anonymous(Host) when is_list(Host) -> lists:member(?MODULE, ejabberd_auth:auth_modules(Host)). -%% Return true if anonymous mode is enabled and if anonymous protocol is SASL -%% anonymous protocol can be: sasl_anon|login_anon|both -is_sasl_anonymous_enabled(Host) -> +%% @spec (Host) -> bool() +%% Host = string() +%% @doc Return true if anonymous mode is enabled and if anonymous +%% protocol is SASL anonymous. +%% protocol can be: sasl_anon|login_anon|both + +is_sasl_anonymous_enabled(Host) when is_list(Host) -> case allow_anonymous(Host) of false -> false; true -> @@ -87,10 +100,13 @@ is_sasl_anonymous_enabled(Host) -> end end. -%% Return true if anonymous login is enabled on the server +%% @spec (Host) -> bool() +%% Host = string() +%% @doc Return true if anonymous login is enabled on the server. %% anonymous login can be use using standard authentication method (i.e. with %% clients that do not support anonymous login) -is_login_anonymous_enabled(Host) -> + +is_login_anonymous_enabled(Host) when is_list(Host) -> case allow_anonymous(Host) of false -> false; true -> @@ -101,9 +117,12 @@ is_login_anonymous_enabled(Host) -> end end. -%% Return the anonymous protocol to use: sasl_anon|login_anon|both +%% @spec (Host) -> sasl_anon | login_anon | both +%% Host = string() +%% @doc Return the anonymous protocol to use: sasl_anon|login_anon|both. %% defaults to login_anon -anonymous_protocol(Host) -> + +anonymous_protocol(Host) when is_list(Host) -> case ejabberd_config:get_local_option({anonymous_protocol, Host}) of sasl_anon -> sasl_anon; login_anon -> login_anon; @@ -111,16 +130,24 @@ anonymous_protocol(Host) -> _Other -> sasl_anon end. -%% Return true if multiple connections have been allowed in the config file +%% @spec (Host) -> bool() +%% Host = string() +%% @doc Return true if multiple connections have been allowed in the +%% config file. %% defaults to false -allow_multiple_connections(Host) -> + +allow_multiple_connections(Host) when is_list(Host) -> case ejabberd_config:get_local_option({allow_multiple_connections, Host}) of true -> true; _Other -> false end. -%% Check if user exist in the anonymus database -anonymous_user_exist(User, Server) -> +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() +%% @doc Check if user exist in the anonymus database. + +anonymous_user_exist(User, Server) when is_list(User), is_list(Server) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, @@ -131,16 +158,26 @@ anonymous_user_exist(User, Server) -> true end. -%% Remove connection from Mnesia tables -remove_connection(SID, LUser, LServer) -> +%% @spec (SID, LUser, LServer) -> term() +%% SID = term() +%% LUser = string() +%% LServer = string() +%% @doc Remove connection from Mnesia tables. + +remove_connection(SID, LUser, LServer) when is_list(LUser), is_list(LServer) -> US = {LUser, LServer}, F = fun() -> mnesia:delete_object({anonymous, US, SID}) end, mnesia:transaction(F). -%% Register connection -register_connection(SID, JID, Info) -> +%% @spec (SID, JID, Info) -> term() +%% SID = term() +%% JID = exmpp_jid:jid() +%% Info = [term()] +%% @doc Register connection. + +register_connection(SID, JID, Info) when ?IS_JID(JID) -> LUser = exmpp_jid:lnode(JID), LServer = exmpp_jid:ldomain(JID), case proplists:get_value(auth_module, Info) of @@ -155,26 +192,40 @@ register_connection(SID, JID, Info) -> ok end. -%% Remove an anonymous user from the anonymous users table -unregister_connection(SID, JID, _) -> +%% @spec (SID, JID, Ignored) -> term() +%% SID = term() +%% JID = exmpp_jid:jid() +%% Ignored = term() +%% @doc Remove an anonymous user from the anonymous users table. + +unregister_connection(SID, JID, _) when ?IS_JID(JID) -> LUser = exmpp_jid:lnode(JID), LServer = exmpp_jid:ldomain(JID), purge_hook(anonymous_user_exist(LUser, LServer), LUser, LServer), remove_connection(SID, LUser, LServer). -%% Launch the hook to purge user data only for anonymous users +%% @spec (bool(), LUser, LServer) -> term() +%% LUser = string() +%% LServer = string() +%% @doc Launch the hook to purge user data only for anonymous users. + purge_hook(false, _LUser, _LServer) -> ok; -purge_hook(true, LUser, LServer) -> +purge_hook(true, LUser, LServer) when is_list(LUser), is_list(LServer) -> ejabberd_hooks:run(anonymous_purge_hook, LServer, [LUser, LServer]). %% --------------------------------- %% Specific anonymous auth functions %% --------------------------------- -%% When anonymous login is enabled, check the password for permenant users -%% before allowing access +%% @spec (User, Server, Password) -> bool() +%% User = string() +%% Server = string() +%% Password = string() +%% @doc When anonymous login is enabled, check the password for +%% permenant users before allowing access. + check_password(User, Server, Password) -> check_password(User, Server, Password, undefined, undefined). check_password(User, Server, _Password, _StreamID, _Digest) -> @@ -186,6 +237,10 @@ check_password(User, Server, _Password, _StreamID, _Digest) -> false -> login(User, Server) end. +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + login(User, Server) -> case is_login_anonymous_enabled(Server) of false -> false; @@ -200,8 +255,13 @@ login(User, Server) -> end end. -%% When anonymous login is enabled, check that the user is permanent before -%% changing its password +%% @spec (User, Server, Password) -> ok | {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() +%% @doc When anonymous login is enabled, check that the user is +%% permanent before changing its password. + set_password(User, Server, _Password) -> case anonymous_user_exist(User, Server) of true -> @@ -210,22 +270,41 @@ set_password(User, Server, _Password) -> {error, not_allowed} end. -%% When anonymous login is enabled, check if permanent users are allowed on -%% the server: +%% @spec (User, Server, Password) -> {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() +%% @doc When anonymous login is enabled, check if permanent users are +%% allowed on the server: + try_register(_User, _Server, _Password) -> {error, not_allowed}. +%% @spec () -> nil() + dirty_get_registered_users() -> []. +%% @spec (Server) -> nil() +%% Server = string() + get_vh_registered_users(_Server) -> []. +%% @spec (User, Server) -> Password | false +%% User = string() +%% Server = string() +%% Password = nil() +%% @doc Return password of permanent user or false for anonymous users. -%% Return password of permanent user or false for anonymous users get_password(User, Server) -> get_password(User, Server, ""). +%% @spec (User, Server, DefaultValue) -> DefaultValue | false +%% User = string() +%% Server = string() +%% DefaultValue = string() + get_password(User, Server, DefaultValue) -> case anonymous_user_exist(User, Server) of %% We return the default value if the user is anonymous @@ -236,17 +315,32 @@ get_password(User, Server, DefaultValue) -> false end. -%% Returns true if the user exists in the DB or if an anonymous user is logged -%% under the given name +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() +%% @doc Returns true if the user exists in the DB or if an anonymous +%% user is logged under the given name. + is_user_exists(User, Server) -> anonymous_user_exist(User, Server). +%% @spec (User, Server) -> {error, not_allowed} +%% User = string() +%% Server = string() + remove_user(_User, _Server) -> {error, not_allowed}. +%% @spec (User, Server, Password) -> {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() + remove_user(_User, _Server, _Password) -> not_allowed. +%% @spec () -> bool() + plain_password_required() -> false. diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl index af7c5b048..9c6dec870 100644 --- a/src/ejabberd_auth_external.erl +++ b/src/ejabberd_auth_external.erl @@ -46,49 +46,103 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- + +%% @spec (Host) -> ok +%% Host = string() + start(Host) -> extauth:start( Host, ejabberd_config:get_local_option({extauth_program, Host})), ok. +%% @spec () -> bool() + plain_password_required() -> true. +%% @spec (User, Server, Password) -> bool() +%% User = string() +%% Server = string() +%% Password = string() + check_password(User, Server, Password) -> extauth:check_password(User, Server, Password) andalso Password /= "". +%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% User = string() +%% Server = string() +%% Password = string() +%% StreamID = string() +%% Digest = string() + check_password(User, Server, Password, _StreamID, _Digest) -> check_password(User, Server, Password). +%% @spec (User, Server, Password) -> ok | {error, unknown_problem} +%% User = string() +%% Server = string() +%% Password = string() + set_password(User, Server, Password) -> case extauth:set_password(User, Server, Password) of true -> ok; _ -> {error, unknown_problem} end. +%% @spec (User, Server, Password) -> {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() + try_register(_User, _Server, _Password) -> {error, not_allowed}. -%% TODO -%% Return the list of all users handled by external +%% @spec () -> nil() +%% @todo Write it. +%% @doc Return the list of all users handled by external. + dirty_get_registered_users() -> []. +%% @spec (Server) -> nil() +%% Server = string() + get_vh_registered_users(_Server) -> []. +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + get_password(_User, _Server) -> false. +%% @spec (User, Server) -> nil() +%% User = string() +%% Server = string() + get_password_s(_User, _Server) -> "". +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + is_user_exists(User, Server) -> extauth:is_user_exists(User, Server). +%% @spec (User, Server) -> {error, not_allowed} +%% User = string() +%% Server = string() + remove_user(_User, _Server) -> {error, not_allowed}. +%% @spec (User, Server, Password) -> not_allowed +%% User = string() +%% Server = string() +%% Password = string() + remove_user(_User, _Server, _Password) -> not_allowed. diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index 527c183b7..2df3cab39 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -53,15 +53,26 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- + +%% @spec (Host) -> ok +%% Host = string() + start(_Host) -> mnesia:create_table(passwd, [{disc_copies, [node()]}, {attributes, record_info(fields, passwd)}]), update_table(), ok. +%% @spec () -> bool() + plain_password_required() -> false. +%% @spec (User, Server, Password) -> bool() +%% User = string() +%% Server = string() +%% Password = string() + check_password(User, Server, Password) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), @@ -73,6 +84,13 @@ check_password(User, Server, Password) -> false end. +%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% User = string() +%% Server = string() +%% Password = string() +%% StreamID = string() +%% Digest = string() + check_password(User, Server, Password, StreamID, Digest) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), @@ -94,8 +112,11 @@ check_password(User, Server, Password, StreamID, Digest) -> false end. -%% @spec (User::string(), Server::string(), Password::string()) -> -%% ok | {error, invalid_jid} +%% @spec (User, Server, Password) -> ok | {error, invalid_jid} +%% User = string() +%% Server = string() +%% Password = string() + set_password(User, Server, Password) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), @@ -113,6 +134,10 @@ set_password(User, Server, Password) -> end. %% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, invalid_jid} | {aborted, Reason} +%% User = string() +%% Server = string() +%% Password = string() + try_register(User, Server, Password) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), @@ -134,10 +159,19 @@ try_register(User, Server, Password) -> mnesia:transaction(F) end. -%% Get all registered users in Mnesia +%% @spec () -> [{LUser, LServer}] +%% LUser = string() +%% LServer = string() +%% @doc Get all registered users in Mnesia. + dirty_get_registered_users() -> mnesia:dirty_all_keys(passwd). +%% @spec (Server) -> [{LUser, LServer}] +%% Server = string() +%% LUser = string() +%% LServer = string() + get_vh_registered_users(Server) -> LServer = exmpp_stringprep:nameprep(Server), mnesia:dirty_select( @@ -146,6 +180,24 @@ get_vh_registered_users(Server) -> [{'==', {element, 2, '$1'}, LServer}], ['$1']}]). +%% @spec (Server, Opts) -> [{LUser, LServer}] +%% Server = string() +%% Opts = [{Opt, Val}] +%% Opt = atom() +%% Val = term() +%% LUser = string() +%% LServer = string() +%% @doc Return the registered users for the specified host. +%% +%% `Opts' can be one of the following: +%%
        +%%
      • `[{from, integer()}, {to, integer()}]'
      • +%%
      • `[{limit, integer()}, {offset, integer()}]'
      • +%%
      • `[{prefix, string()}]'
      • +%%
      • `[{prefix, string()}, {from, integer()}, {to, integer()}]'
      • +%%
      • `[{prefix, string()}, {limit, integer()}, {offset, integer()}]'
      • +%%
      + get_vh_registered_users(Server, [{from, Start}, {to, End}]) when is_integer(Start) and is_integer(End) -> get_vh_registered_users(Server, [{limit, End-Start+1}, {offset, Start}]); @@ -192,10 +244,19 @@ get_vh_registered_users(Server, [{prefix, Prefix}, {limit, Limit}, {offset, Offs get_vh_registered_users(Server, _) -> get_vh_registered_users(Server). +%% @spec (Server) -> Users_Number +%% Server = string() +%% Users_Number = integer() + get_vh_registered_users_number(Server) -> Set = get_vh_registered_users(Server), length(Set). +%% @spec (Server, [{prefix, Prefix}]) -> Users_Number +%% Server = string() +%% Prefix = string() +%% Users_Number = integer() + get_vh_registered_users_number(Server, [{prefix, Prefix}]) when is_list(Prefix) -> Set = [{U, S} || {U, S} <- get_vh_registered_users(Server), lists:prefix(Prefix, U)], length(Set); @@ -203,6 +264,11 @@ get_vh_registered_users_number(Server, [{prefix, Prefix}]) when is_list(Prefix) get_vh_registered_users_number(Server, _) -> get_vh_registered_users_number(Server). +%% @spec (User, Server) -> Password | false +%% User = string() +%% Server = string() +%% Password = string() + get_password(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -219,6 +285,11 @@ get_password(User, Server) -> false end. +%% @spec (User, Server) -> Password | nil() +%% User = string() +%% Server = string() +%% Password = string() + get_password_s(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -235,6 +306,10 @@ get_password_s(User, Server) -> [] end. +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + is_user_exists(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -254,8 +329,11 @@ is_user_exists(User, Server) -> end. %% @spec (User, Server) -> ok +%% User = string() +%% Server = string() %% @doc Remove user. %% Note: it returns ok even if there was some problem removing the user. + remove_user(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -272,7 +350,11 @@ remove_user(User, Server) -> end. %% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request +%% User = string() +%% Server = string() +%% Password = string() %% @doc Remove user if the provided password is correct. + remove_user(User, Server, Password) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -302,11 +384,15 @@ remove_user(User, Server, Password) -> bad_request end. +%% @spec () -> term() update_table() -> Fields = record_info(fields, passwd), case mnesia:table_info(passwd, attributes) of Fields -> + % No conversion is needed when the table comes from an exmpp-less + % Ejabberd because ejabberd_auth* modules use string() and not + % binary(). ok; [user, password] -> ?INFO_MSG("Converting passwd table from " diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl index b8c6a971e..c73ad0a55 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -94,6 +94,9 @@ handle_info(_Info, State) -> %%% API %%%---------------------------------------------------------------------- +%% @spec (Host) -> term() +%% Host = string() + start(Host) -> Proc = gen_mod:get_module_proc(Host, ?MODULE), ChildSpec = { @@ -102,19 +105,31 @@ start(Host) -> }, supervisor:start_child(ejabberd_sup, ChildSpec). +%% @spec (Host) -> term() +%% Host = string() + stop(Host) -> Proc = gen_mod:get_module_proc(Host, ?MODULE), gen_server:call(Proc, stop), supervisor:terminate_child(ejabberd_sup, Proc), supervisor:delete_child(ejabberd_sup, Proc). +%% @spec (Host) -> term() +%% Host = string() + start_link(Host) -> Proc = gen_mod:get_module_proc(Host, ?MODULE), gen_server:start_link({local, Proc}, ?MODULE, Host, []). +%% @hidden + terminate(_Reason, _State) -> ok. +%% @spec (Host) -> {ok, State} +%% Host = string() +%% State = term() + init(Host) -> State = parse_options(Host), eldap_pool:start_link(State#state.eldap_id, @@ -131,9 +146,16 @@ init(Host) -> State#state.password), {ok, State}. +%% @spec () -> true + plain_password_required() -> true. +%% @spec (User, Server, Password) -> bool() +%% User = string() +%% Server = string() +%% Password = string() + check_password(User, Server, Password) -> %% In LDAP spec: empty password means anonymous authentication. %% As ejabberd is providing other anonymous authentication mechanisms @@ -147,16 +169,36 @@ check_password(User, Server, Password) -> end end. +%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% User = string() +%% Server = string() +%% Password = string() +%% StreamID = string() +%% Digest = string() + check_password(User, Server, Password, _StreamID, _Digest) -> check_password(User, Server, Password). +%% @spec (User, Server, Password) -> {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() + set_password(_User, _Server, _Password) -> {error, not_allowed}. %% @spec (User, Server, Password) -> {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() + try_register(_User, _Server, _Password) -> {error, not_allowed}. +%% @spec () -> [{LUser, LServer}] +%% LUser = string() +%% LServer = string() + dirty_get_registered_users() -> Servers = ejabberd_config:get_vh_by_auth_method(ldap), lists:flatmap( @@ -164,21 +206,42 @@ dirty_get_registered_users() -> get_vh_registered_users(Server) end, Servers). +%% @spec (Server) -> [{LUser, LServer}] +%% Server = string() +%% LUser = string() +%% LServer = string() + get_vh_registered_users(Server) -> case catch get_vh_registered_users_ldap(Server) of {'EXIT', _} -> []; Result -> Result end. +%% @spec (Server) -> Users_Number +%% Server = string() +%% Users_Number = integer() + get_vh_registered_users_number(Server) -> length(get_vh_registered_users(Server)). +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + get_password(_User, _Server) -> false. +%% @spec (User, Server) -> nil() +%% User = string() +%% Server = string() + get_password_s(_User, _Server) -> "". +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + is_user_exists(User, Server) -> case catch is_user_exists_ldap(User, Server) of {'EXIT', _} -> @@ -187,15 +250,30 @@ is_user_exists(User, Server) -> Result end. +%% @spec (User, Server) -> {error, not_allowed} +%% User = string() +%% Server = string() + remove_user(_User, _Server) -> {error, not_allowed}. +%% @spec (User, Server, Password) -> not_allowed +%% User = string() +%% Server = string() +%% Password = string() + remove_user(_User, _Server, _Password) -> not_allowed. %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- + +%% @spec (User, Server, Password) -> bool() +%% User = string() +%% Server = string() +%% Password = string() + check_password_ldap(User, Server, Password) -> {ok, State} = eldap_utils:get_state(Server, ?MODULE), case find_user_dn(User, State) of @@ -208,6 +286,11 @@ check_password_ldap(User, Server, Password) -> end end. +%% @spec (Server) -> [{LUser, LServer}] +%% Server = string() +%% LUser = string() +%% LServer = string() + get_vh_registered_users_ldap(Server) -> {ok, State} = eldap_utils:get_state(Server, ?MODULE), UIDs = State#state.uids, @@ -250,6 +333,10 @@ get_vh_registered_users_ldap(Server) -> [] end. +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + is_user_exists_ldap(User, Server) -> {ok, State} = eldap_utils:get_state(Server, ?MODULE), case find_user_dn(User, State) of diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index 92a8493b6..bee6d9013 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -51,12 +51,23 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- + +%% @spec (Host) -> ok +%% Host = string() + start(_Host) -> ok. +%% @spec () -> bool() + plain_password_required() -> false. +%% @spec (User, Server, Password) -> bool() +%% User = string() +%% Server = string() +%% Password = string() + check_password(User, Server, Password) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -73,6 +84,13 @@ check_password(User, Server, Password) -> false end. +%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% User = string() +%% Server = string() +%% Password = string() +%% StreamID = string() +%% Digest = string() + check_password(User, Server, Password, StreamID, Digest) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -99,8 +117,11 @@ check_password(User, Server, Password, StreamID, Digest) -> false end. -%% @spec (User::string(), Server::string(), Password::string()) -> -%% ok | {error, invalid_jid} +%% @spec (User, Server, Password) -> ok | {error, invalid_jid} +%% User = string() +%% Server = string() +%% Password = string() + set_password(User, Server, Password) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -118,6 +139,10 @@ set_password(User, Server, Password) -> %% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, invalid_jid} +%% User = string() +%% Server = string() +%% Password = string() + try_register(User, Server, Password) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -135,6 +160,10 @@ try_register(User, Server, Password) -> {error, invalid_jid} end. +%% @spec () -> [{LUser, LServer}] +%% LUser = string() +%% LServer = string() + dirty_get_registered_users() -> Servers = ejabberd_config:get_vh_by_auth_method(odbc), lists:flatmap( @@ -142,6 +171,11 @@ dirty_get_registered_users() -> get_vh_registered_users(Server) end, Servers). +%% @spec (Server) -> [{LUser, LServer}] +%% Server = string() +%% LUser = string() +%% LServer = string() + get_vh_registered_users(Server) -> LServer = exmpp_stringprep:nameprep(Server), case catch odbc_queries:list_users(LServer) of @@ -151,6 +185,14 @@ get_vh_registered_users(Server) -> [] end. +%% @spec (Server, Opts) -> [{LUser, LServer}] +%% Server = string() +%% Opts = [{Opt, Val}] +%% Opt = atom() +%% Val = term() +%% LUser = string() +%% LServer = string() + get_vh_registered_users(Server, Opts) -> LServer = exmpp_stringprep:nameprep(Server), case catch odbc_queries:list_users(LServer, Opts) of @@ -160,6 +202,10 @@ get_vh_registered_users(Server, Opts) -> [] end. +%% @spec (Server) -> Users_Number +%% Server = string() +%% Users_Number = integer() + get_vh_registered_users_number(Server) -> LServer = exmpp_stringprep:nameprep(Server), case catch odbc_queries:users_number(LServer) of @@ -169,6 +215,13 @@ get_vh_registered_users_number(Server) -> 0 end. +%% @spec (Server, Opts) -> Users_Number +%% Server = string() +%% Opts = [{Opt, Val}] +%% Opt = atom() +%% Val = term() +%% Users_Number = integer() + get_vh_registered_users_number(Server, Opts) -> LServer = exmpp_stringprep:nameprep(Server), case catch odbc_queries:users_number(LServer, Opts) of @@ -178,6 +231,11 @@ get_vh_registered_users_number(Server, Opts) -> 0 end. +%% @spec (User, Server) -> Password | false +%% User = string() +%% Server = string() +%% Password = string() + get_password(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -194,6 +252,11 @@ get_password(User, Server) -> false end. +%% @spec (User, Server) -> Password | nil() +%% User = string() +%% Server = string() +%% Password = string() + get_password_s(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -210,6 +273,10 @@ get_password_s(User, Server) -> "" end. +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + is_user_exists(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -227,8 +294,11 @@ is_user_exists(User, Server) -> end. %% @spec (User, Server) -> ok | error +%% User = string() +%% Server = string() %% @doc Remove user. %% Note: it may return ok even if there was some problem removing the user. + remove_user(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -242,7 +312,11 @@ remove_user(User, Server) -> end. %% @spec (User, Server, Password) -> ok | error | not_exists | not_allowed +%% User = string() +%% Server = string() +%% Password = string() %% @doc Remove user if the provided password is correct. + remove_user(User, Server, Password) -> try LUser = exmpp_stringprep:nodeprep(User), diff --git a/src/ejabberd_auth_pam.erl b/src/ejabberd_auth_pam.erl index c8a8031c2..a09bbac65 100644 --- a/src/ejabberd_auth_pam.erl +++ b/src/ejabberd_auth_pam.erl @@ -45,6 +45,10 @@ %%==================================================================== %% API %%==================================================================== + +%% @spec (Host) -> ok | term() +%% Host = string() + start(_Host) -> case epam:start() of {ok, _} -> ok; @@ -52,55 +56,115 @@ start(_Host) -> Err -> Err end. +%% @spec (User, Server, Password) -> {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() + set_password(_User, _Server, _Password) -> {error, not_allowed}. +%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% User = string() +%% Server = string() +%% Password = string() +%% StreamID = string() +%% Digest = string() + check_password(User, Server, Password, _StreamID, _Digest) -> check_password(User, Server, Password). -check_password(User, Host, Password) -> - Service = get_pam_service(Host), +%% @spec (User, Server, Password) -> bool() +%% User = string() +%% Server = string() +%% Password = string() + +check_password(User, Server, Password) -> + Service = get_pam_service(Server), case catch epam:authenticate(Service, User, Password) of true -> true; _ -> false end. +%% @spec (User, Server, Password) -> {error, not_allowed} +%% User = string() +%% Server = string() +%% Password = string() + try_register(_User, _Server, _Password) -> {error, not_allowed}. +%% @spec () -> [{LUser, LServer}] +%% LUser = string() +%% LServer = string() + dirty_get_registered_users() -> []. -get_vh_registered_users(_Host) -> +%% @spec (Server) -> [{LUser, LServer}] +%% Server = string() +%% LUser = string() +%% LServer = string() + +get_vh_registered_users(_Server) -> []. +%% @spec (User, Server) -> Password | false +%% User = string() +%% Server = string() +%% Password = string() + get_password(_User, _Server) -> false. +%% @spec (User, Server) -> Password | nil() +%% User = string() +%% Server = string() +%% Password = string() + get_password_s(_User, _Server) -> "". -is_user_exists(User, Host) -> - Service = get_pam_service(Host), +%% @spec (User, Server) -> bool() +%% User = string() +%% Server = string() + +is_user_exists(User, Server) -> + Service = get_pam_service(Server), case catch epam:acct_mgmt(Service, User) of true -> true; _ -> false end. +%% @spec (User, Server) -> {error, not_allowed} +%% User = string() +%% Server = string() + remove_user(_User, _Server) -> {error, not_allowed}. +%% @spec (User, Server, Password) -> not_allowed +%% User = string() +%% Server = string() +%% Password = string() + remove_user(_User, _Server, _Password) -> not_allowed. +%% @spec () -> bool() + plain_password_required() -> true. %%==================================================================== %% Internal functions %%==================================================================== -get_pam_service(Host) -> - case ejabberd_config:get_local_option({pam_service, Host}) of + +%% @spec (Server) -> string() +%% Server = string() + +get_pam_service(Server) -> + case ejabberd_config:get_local_option({pam_service, Server}) of undefined -> "ejabberd"; Service -> Service end. From 93b26d947c8cc116cdc5f7f364ff517be5818ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 6 Feb 2009 13:34:12 +0000 Subject: [PATCH 192/582] Add documentation stub for some types. This will be filled later. PR: EJABP-1 SVN Revision: 1865 --- ChangeLog | 5 +++++ src/web/ejabberd_http.erl | 3 +++ src/web/ejabberd_web.erl | 1 + 3 files changed, 9 insertions(+) diff --git a/ChangeLog b/ChangeLog index 263a79620..9e1c5c57b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-02-06 Jean-Sébastien Pédron + + * src/web/ejabberd_web.erl, src/web/ejabberd_http.erl: Add + documentation stub for some types. This will be filled later. + 2009-02-05 Jean-Sébastien Pédron * src/ejabberd_auth.erl, src/ejabberd_auth_anonymous.erl, diff --git a/src/web/ejabberd_http.erl b/src/web/ejabberd_http.erl index de8529224..1a1546bfd 100644 --- a/src/web/ejabberd_http.erl +++ b/src/web/ejabberd_http.erl @@ -40,6 +40,9 @@ -include("ejabberd.hrl"). -include("ejabberd_http.hrl"). +%% @type request() = term() +%% @type query() = list() + -record(state, {sockmod, socket, request_method, diff --git a/src/web/ejabberd_web.erl b/src/web/ejabberd_web.erl index 0d675dee4..7c0a5e158 100644 --- a/src/web/ejabberd_web.erl +++ b/src/web/ejabberd_web.erl @@ -36,6 +36,7 @@ -include("ejabberd.hrl"). -include("ejabberd_http.hrl"). +%% @type html() = term() %% XXX bard: there are variants of make_xhtml in ejabberd_http and %% ejabberd_web_admin. It might be a good idea to centralize it here From 25bd2bc7fe95fc7d102ed706c2b55b0f1f039c32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 6 Feb 2009 13:35:40 +0000 Subject: [PATCH 193/582] Document the short JID type. PR: EJABP-1 SVN Revision: 1866 --- ChangeLog | 2 ++ src/jlib.erl | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index 9e1c5c57b..b9bcbc526 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,8 @@ * src/web/ejabberd_web.erl, src/web/ejabberd_http.erl: Add documentation stub for some types. This will be filled later. + * src/jlib.erl: Document the short JID type. + 2009-02-05 Jean-Sébastien Pédron * src/ejabberd_auth.erl, src/ejabberd_auth_anonymous.erl, diff --git a/src/jlib.erl b/src/jlib.erl index aba42c935..f19dd052e 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -49,6 +49,10 @@ -include("jlib.hrl"). +%% @type shortjid() = {U, S, R} +%% U = binary() +%% S = binary() +%% R = binary(). parse_xdata_submit(#xmlel{attrs = Attrs, children = Els}) -> case exmpp_xml:get_attribute_from_list_as_list(Attrs, 'type', "") of From bf82bac328c1669e8bc3db479d40fe52fe96a9f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Fri, 6 Feb 2009 13:43:40 +0000 Subject: [PATCH 194/582] o Document the type of the argument(s) and the returned type of every functions. o Add guardians expression to exported functions to ensure at an early stage that we were given the right arguments. o Fix table conversion to exmpp; many fields were left as string(), preventing matching from working correctly. o In user_roster_item_parse_query/4, fix a bug where the same variable was used for two distinct purpose. o In user_roster_item_parse_query/4, fix a bad usage of exmpp_jid:jid_to_list/1. PR: EJABP-1 SVN Revision: 1867 --- ChangeLog | 9 ++ src/mod_roster.erl | 319 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 284 insertions(+), 44 deletions(-) diff --git a/ChangeLog b/ChangeLog index b9bcbc526..d8bb35775 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,15 @@ * src/jlib.erl: Document the short JID type. + * src/mod_roster.erl: Document the type of the argument(s) and the + returned type of every functions. Add guardians expression to exported + functions to ensure at an early stage that we were given the right + arguments. Fix table conversion to exmpp; many fields were left as + string(), preventing matching from working correctly. + (user_roster_item_parse_query/4): Fix a bug where the same variable + was used for two distinct purpose. Fix a bad usage of + exmpp_jid:jid_to_list/1. + 2009-02-05 Jean-Sébastien Pédron * src/ejabberd_auth.erl, src/ejabberd_auth_anonymous.erl, diff --git a/src/mod_roster.erl b/src/mod_roster.erl index d16898e42..c4d6237e0 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -51,8 +51,25 @@ -include("web/ejabberd_http.hrl"). -include("web/ejabberd_web_admin.hrl"). +%% @type rosteritem() = {roster, USJ, US, Contact_JID, Name, Subscription, Ask, Groups, Askmessage, Xs} +%% USJ = {LUser, LServer, Prepd_Contact_JID} +%% LUser = binary() +%% LServer = binary() +%% Prepd_Contact_JID = jlib:shortjid() +%% US = {LUser, LServer} +%% Contact_JID = jlib:shortjid() +%% Name = binary() +%% Subscription = none | to | from | both +%% Ask = none | out | in | both +%% Groups = [binary()] +%% Askmessage = binary() +%% Xs = [exmpp_xml:xmlel()] -start(Host, Opts) -> +%% @spec (Host, Opts) -> term() +%% Host = string() +%% Opts = list() + +start(Host, Opts) when is_list(Host) -> HostB = list_to_binary(Host), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), mnesia:create_table(roster,[{disc_copies, [node()]}, @@ -82,7 +99,10 @@ start(Host, Opts) -> gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_ROSTER, ?MODULE, process_iq, IQDisc). -stop(Host) -> +%% @spec (Host) -> term() +%% Host = string() + +stop(Host) when is_list(Host) -> HostB = list_to_binary(Host), ejabberd_hooks:delete(roster_get, HostB, ?MODULE, get_user_roster, 50), @@ -107,8 +127,14 @@ stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_ROSTER). +%% @spec (From, To, IQ_Rec) -> IQ_Result +%% From = exmpp_jid:jid() +%% To = exmpp_jid:jid() +%% IQ_Rec = exmpp_iq:iq() +%% IQ_Result = exmpp_iq:iq() -process_iq(From, To, IQ_Rec) -> +process_iq(From, To, IQ_Rec) + when ?IS_JID(From), ?IS_JID(To), ?IS_IQ_RECORD(IQ_Rec) -> LServer = exmpp_jid:ldomain_as_list(From), case lists:member(LServer, ?MYHOSTS) of true -> @@ -117,12 +143,24 @@ process_iq(From, To, IQ_Rec) -> exmpp_iq:error(IQ_Rec, 'item-not-found') end. -process_local_iq(From, To, #iq{type = get} = IQ_Rec) -> +%% @spec (From, To, IQ_Rec) -> IQ_Result +%% From = exmpp_jid:jid() +%% To = exmpp_jid:jid() +%% IQ_Rec = exmpp_iq:iq() +%% IQ_Result = exmpp_iq:iq() + +process_local_iq(From, To, #iq{type = get} = IQ_Rec) + when ?IS_JID(From), ?IS_JID(To), ?IS_IQ_RECORD(IQ_Rec) -> process_iq_get(From, To, IQ_Rec); -process_local_iq(From, To, #iq{type = set} = IQ_Rec) -> +process_local_iq(From, To, #iq{type = set} = IQ_Rec) + when ?IS_JID(From), ?IS_JID(To), ?IS_IQ_RECORD(IQ_Rec) -> process_iq_set(From, To, IQ_Rec). - +%% @spec (From, To, IQ_Rec) -> IQ_Result +%% From = exmpp_jid:jid() +%% To = exmpp_jid:jid() +%% IQ_Rec = exmpp_iq:iq() +%% IQ_Result = exmpp_iq:iq() process_iq_get(From, To, IQ_Rec) -> US = {exmpp_jid:lnode(From), exmpp_jid:ldomain(From)}, @@ -136,7 +174,14 @@ process_iq_get(From, To, IQ_Rec) -> exmpp_iq:error(IQ_Rec, 'internal-server-error') end. -get_user_roster(Acc, US) -> +%% @spec (Acc, US) -> New_Acc +%% Acc = [rosteritem()] +%% US = {User, Server} +%% User = binary() +%% Server = binary() +%% New_Acc = [rosteritem()] + +get_user_roster(Acc, {U, S} = US) when is_binary(U), is_binary(S) -> case catch mnesia:dirty_index_read(roster, US, #roster.us) of Items when is_list(Items) -> lists:filter(fun(#roster{subscription = none, ask = in}) -> @@ -148,6 +193,9 @@ get_user_roster(Acc, US) -> Acc end. +%% @spec (Item) -> XML +%% Item = rosteritem() +%% XML = exmpp_xml:xmlel() item_to_xml(Item) -> {U, S, R} = Item#roster.jid, @@ -178,6 +226,11 @@ item_to_xml(Item) -> SubEls = SubEls1 ++ Item#roster.xs, #xmlel{ns = ?NS_ROSTER, name = 'item', attrs = Attrs4, children = SubEls}. +%% @spec (From, To, IQ_Rec) -> IQ_Result +%% From = exmpp_jid:jid() +%% To = exmpp_jid:jid() +%% IQ_Rec = exmpp_iq:iq() +%% IQ_Result = exmpp_iq:iq() process_iq_set(From, To, #iq{payload = Request} = IQ_Rec) -> case Request of @@ -188,12 +241,17 @@ process_iq_set(From, To, #iq{payload = Request} = IQ_Rec) -> end, exmpp_iq:result(IQ_Rec). +%% @spec (From, To, El) -> ok +%% From = exmpp_jid:jid() +%% To = exmpp_jid:jid() +%% El = exmpp_xml:xmlel() + process_item_set(From, To, #xmlel{} = El) -> try JID1 = exmpp_jid:parse_jid(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), - User = exmpp_jid:node(From), - LUser = exmpp_jid:lnode(From), - LServer = exmpp_jid:ldomain(From), + User = exmpp_jid:node(From), + LUser = exmpp_jid:lnode(From), + LServer = exmpp_jid:ldomain(From), JID = jlib:short_jid(JID1), LJID = jlib:short_prepd_jid(JID1), F = fun() -> @@ -268,6 +326,11 @@ process_item_set(From, To, #xmlel{} = El) -> process_item_set(_From, _To, _) -> ok. +%% @spec (Item, Attrs) -> New_Item +%% Item = rosteritem() +%% Attrs = [exmpp_xml:xmlnsattribute()] +%% New_Item = rosteritem() + process_item_attrs(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> case Attr of 'name' -> @@ -288,6 +351,10 @@ process_item_attrs(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> process_item_attrs(Item, []) -> Item. +%% @spec (Item, Els) -> New_Item +%% Item = rosteritem() +%% Els = [exmpp_xml:xmlel()] +%% New_Item = rosteritem() process_item_els(Item, [#xmlel{ns = NS, name = Name} = El | Els]) -> case Name of @@ -308,8 +375,14 @@ process_item_els(Item, [_ | Els]) -> process_item_els(Item, []) -> Item. +%% @spec (User, Server, From, Item) -> term() +%% User = binary() +%% Server = binary() +%% From = exmpp_jid:jid() +%% Item = rosteritem() -push_item(User, Server, From, Item) when is_binary(User), is_binary(Server) -> +push_item(User, Server, From, Item) + when is_binary(User), is_binary(Server), ?IS_JID(From) -> ejabberd_sm:route(exmpp_jid:make_jid(), exmpp_jid:make_jid(User, Server), #xmlel{name = 'broadcast', children = @@ -320,9 +393,17 @@ push_item(User, Server, From, Item) when is_binary(User), is_binary(Server) -> push_item(User, Server, Resource, From, Item) end, ejabberd_sm:get_user_resources(User, Server)). +%% @spec (User, Server, Resource, From, Item) -> term() +%% User = binary() +%% Server = binary() +%% Resource = binary() +%% From = exmpp_jid:jid() +%% Item = rosteritem() + % TODO: don't push to those who didn't load roster -push_item(User, Server, Resource, From, Item) when is_binary(User), - is_binary(Server) -> +push_item(User, Server, Resource, From, Item) + when is_binary(User), is_binary(Server), is_binary(Resource), + ?IS_JID(From) -> Request = #xmlel{ns = ?NS_ROSTER, name = 'query', children = [item_to_xml(Item)]}, ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request, @@ -332,8 +413,16 @@ push_item(User, Server, Resource, From, Item) when is_binary(User), exmpp_jid:make_jid(User, Server, Resource), ResIQ). +%% @spec (Ignored, User, Server) -> Subscription_Lists +%% Ignored = term() +%% User = binary() +%% Server = binary() +%% Subscription_Lists = {F, T} +%% F = [jlib:shortjid()] +%% T = [jlib:shortjid()] + get_subscription_lists(_, User, Server) - when is_binary(User), is_binary(Server) -> + when is_binary(User), is_binary(Server) -> try US = {User,Server}, case mnesia:dirty_index_read(roster, US, #roster.us) of @@ -347,6 +436,13 @@ get_subscription_lists(_, User, Server) {[], []} end. +%% @spec (Items, F, T) -> {New_F, New_T} +%% Items = [rosteritem()] +%% F = [jlib:shortjid()] +%% T = [jlib:shortjid()] +%% New_F = [jlib:shortjid()] +%% New_T = [jlib:shortjid()] + fill_subscription_lists([I | Is], F, T) -> J = element(3, I#roster.usj), case I#roster.subscription of @@ -362,20 +458,44 @@ fill_subscription_lists([I | Is], F, T) -> fill_subscription_lists([], F, T) -> {F, T}. +%% @hidden + ask_to_pending(subscribe) -> out; ask_to_pending(unsubscribe) -> none; ask_to_pending(Ask) -> Ask. +%% @spec (Ignored, User, Server, JID, Type, Reason) -> bool() +%% Ignored = term() +%% User = binary() +%% Server = binary() +%% JID = exmpp_jid:jid() +%% Type = subscribe | subscribed | unsubscribe | unsubscribed +%% Reason = binary() | undefined - -in_subscription(_, User, Server, JID, Type, Reason) -> +in_subscription(_, User, Server, JID, Type, Reason) + when is_binary(User), is_binary(Server), ?IS_JID(JID) -> process_subscription(in, User, Server, JID, Type, Reason). -out_subscription(User, Server, JID, Type) -> +%% @spec (User, Server, JID, Type) -> bool() +%% User = binary() +%% Server = binary() +%% JID = exmpp_jid:jid() +%% Type = subscribe | subscribed | unsubscribe | unsubscribed + +out_subscription(User, Server, JID, Type) + when is_binary(User), is_binary(Server), ?IS_JID(JID) -> process_subscription(out, User, Server, JID, Type, <<>>). +%% @spec (Direction, User, Server, JID1, Type, Reason) -> bool() +%% Direction = in | out +%% User = binary() +%% Server = binary() +%% JID1 = exmpp_jid:jid() +%% Type = subscribe | subscribed | unsubscribe | unsubscribed +%% Reason = binary() | undefined + process_subscription(Direction, User, Server, JID1, Type, Reason) - when is_binary(User), is_binary(Server) -> + when is_binary(User), is_binary(Server) -> try US = {User, Server}, LJID = jlib:short_prepd_jid(JID1), @@ -558,9 +678,12 @@ in_auto_reply(from, out, unsubscribe) -> unsubscribed; in_auto_reply(both, none, unsubscribe) -> unsubscribed; in_auto_reply(_, _, _) -> none. +%% @spec (User, Server) -> term() +%% User = binary() +%% Server = binary() remove_user(User, Server) - when is_binary(User), is_binary(Server) -> + when is_binary(User), is_binary(Server) -> try LUser = list_to_binary(exmpp_stringprep:nodeprep(User)), LServer = list_to_binary(exmpp_stringprep:nameprep(Server)), @@ -579,7 +702,13 @@ remove_user(User, Server) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -set_items(User, Server, #xmlel{children = Els}) -> +%% @spec (User, Server, El) -> term() +%% User = binary() +%% Server = binary() +%% El = exmpp_xml:xmlel() + +set_items(User, Server, #xmlel{children = Els}) + when is_binary(User), is_binary(Server) -> try LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), @@ -594,6 +723,11 @@ set_items(User, Server, #xmlel{children = Els}) -> ok end. +%% @spec (LUser, LServer, El) -> term() +%% LUser = binary() +%% LServer = binary() +%% El = exmpp_xml:xmlel() + process_item_set_t(LUser, LServer, #xmlel{} = El) -> try JID1 = exmpp_jid:parse_jid(exmpp_xml:get_attribute_as_list(El, 'jid', <<>>)), @@ -617,6 +751,11 @@ process_item_set_t(LUser, LServer, #xmlel{} = El) -> process_item_set_t(_LUser, _LServer, _) -> ok. +%% @spec (Item, Attrs) -> New_Item +%% Item = rosteritem() +%% Attrs = [exmpp_xml:xmlnsattribute()] +%% New_Item = rosteritem() + process_item_attrs_ws(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> case Attr of 'name' -> @@ -649,8 +788,14 @@ process_item_attrs_ws(Item, [#xmlattr{name = Attr, value = Val} | Attrs]) -> process_item_attrs_ws(Item, []) -> Item. +%% @spec (Ls, User, Server) -> New_Ls +%% Ls = [exmpp_xml:xmlel()] +%% User = binary() +%% Server = binary() +%% New_Ls = [exmpp_xml:xmlel()] + get_in_pending_subscriptions(Ls, User, Server) - when is_binary(User), is_binary(Server) -> + when is_binary(User), is_binary(Server) -> JID = exmpp_jid:make_jid(User, Server), US = {exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID)}, case mnesia:dirty_index_read(roster, US, #roster.us) of @@ -681,7 +826,16 @@ get_in_pending_subscriptions(Ls, User, Server) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -get_jid_info(_, User, Server, JID) when is_binary(User), is_binary(Server) -> +%% @spec (Ignored, User, Server, JID) -> {Subscription, Groups} +%% Ignored = term() +%% User = binary() +%% Server = binary() +%% JID = exmpp_jid:jid() +%% Subscription = none | to | from | both +%% Groups = [binary()] + +get_jid_info(_, User, Server, JID) + when is_binary(User), is_binary(Server), ?IS_JID(JID) -> try LJID = jlib:short_prepd_jid(JID), case catch mnesia:dirty_read(roster, {User, Server, LJID}) of @@ -710,6 +864,7 @@ get_jid_info(_, User, Server, JID) when is_binary(User), is_binary(Server) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% @hidden update_table() -> Fields = record_info(fields, roster), @@ -725,6 +880,7 @@ update_table() -> mnesia:transform_table(roster, ignore, Fields) end. +%% @hidden %% Convert roster table to support virtual host convert_table1(Fields) -> @@ -769,6 +925,7 @@ convert_table1(Fields) -> mnesia:transaction(F2), mnesia:delete_table(mod_roster_tmp_table). +%% @hidden %% Convert roster table: xattrs fields become convert_table2(Fields) -> @@ -777,58 +934,83 @@ convert_table2(Fields) -> mnesia:transform_table(roster, ignore, Fields), convert_to_exmpp(). +%% @hidden convert_to_exmpp() -> Fun = fun() -> case mnesia:first(roster) of - '$end_of_table' -> + {_User, Server, _JID} when is_binary(Server) -> none; - Key -> - case mnesia:read({roster, Key}) of - [#roster{jid = {_, _, undefined}}] -> - none; - [#roster{jid = {_, _, ""}}] -> - mnesia:foldl(fun convert_to_exmpp2/2, - done, roster, write) - end + {_User, Server, _JID} when is_list(Server) -> + mnesia:foldl(fun convert_to_exmpp2/2, + done, roster, write); + '$end_of_table' -> + none end end, mnesia:transaction(Fun). +%% @hidden + convert_to_exmpp2(#roster{ usj = {USJ_U, USJ_S, {USJ_JU, USJ_JS, USJ_JR}} = Key, us = {US_U, US_S}, jid = {JID_U, JID_S, JID_R}, - xs = XS, askmessage = AM} = R, Acc) -> + name = N, xs = XS, groups = G, askmessage = AM} = R, Acc) -> % Remove old entry. mnesia:delete({roster, Key}), - % Convert "" to undefined in JIDs. + % Convert "" to undefined in JIDs and string() to binary(). USJ_U1 = convert_jid_to_exmpp(USJ_U), + USJ_S1 = convert_jid_to_exmpp(USJ_S), USJ_JU1 = convert_jid_to_exmpp(USJ_JU), + USJ_JS1 = convert_jid_to_exmpp(USJ_JS), USJ_JR1 = convert_jid_to_exmpp(USJ_JR), US_U1 = convert_jid_to_exmpp(US_U), + US_S1 = convert_jid_to_exmpp(US_S), JID_U1 = convert_jid_to_exmpp(JID_U), + JID_S1 = convert_jid_to_exmpp(JID_S), JID_R1 = convert_jid_to_exmpp(JID_R), + % Convert name. + N1 = convert_name_to_exmpp(N), + % Convert groups. + G1 = convert_groups_to_exmpp(G, []), % Convert xs. XS1 = convert_xs_to_exmpp(XS), % Convert askmessage. AM1 = convert_askmessage_to_exmpp(AM), % Prepare the new record. New_R = R#roster{ - usj = {USJ_U1, USJ_S, {USJ_JU1, USJ_JS, USJ_JR1}}, - us = {US_U1, US_S}, - jid = {JID_U1, JID_S, JID_R1}, - xs = XS1, askmessage = AM1}, + usj = {USJ_U1, USJ_S1, {USJ_JU1, USJ_JS1, USJ_JR1}}, + us = {US_U1, US_S1}, + jid = {JID_U1, JID_S1, JID_R1}, + name = N1, groups = G1, xs = XS1, askmessage = AM1}, % Write the new record. mnesia:write(New_R), Acc. -convert_jid_to_exmpp("") -> undefined; -convert_jid_to_exmpp(V) -> V. +%% @hidden + +convert_jid_to_exmpp("") -> undefined; +convert_jid_to_exmpp(V) when is_list(V) -> list_to_binary(V). + +%% @hidden + +convert_name_to_exmpp(N) when is_list(N) -> list_to_binary(N). + +%% @hidden + +convert_groups_to_exmpp([G | Rest], New_G) -> + convert_groups_to_exmpp(Rest, [list_to_binary(G) | New_G]); +convert_groups_to_exmpp([], New_G) -> + lists:reverse(New_G). + +%% @hidden convert_xs_to_exmpp(Els) -> convert_xs_to_exmpp(Els, []). +%% @hidden + convert_xs_to_exmpp([El | Rest], Result) -> New_El = exmpp_xml:xmlelement_to_xmlel(El, [?NS_JABBER_CLIENT], [{?NS_XMPP, ?NS_XMPP_pfx}]), @@ -836,21 +1018,37 @@ convert_xs_to_exmpp([El | Rest], Result) -> convert_xs_to_exmpp([], Result) -> lists:reverse(Result). +%% @hidden + convert_askmessage_to_exmpp(AM) when is_binary(AM) -> AM; convert_askmessage_to_exmpp(AM) -> list_to_binary(AM). +%% @spec (Acc, Host, Request) -> {stop, Result} | Acc +%% Acc = term() +%% Host = string() +%% Request = ejabberd_http:request() +%% Result = [ejabberd_web:html()] + webadmin_page(_, Host, #request{us = _US, path = ["user", U, "roster"], q = Query, - lang = Lang} = _Request) -> - Res = user_roster(U, Host, Query, Lang), + lang = Lang} = _Request) + when is_list(Host), is_list(U) -> + Res = user_roster(list_to_binary(U), list_to_binary(Host), Query, Lang), {stop, Res}; webadmin_page(Acc, _, _) -> Acc. +%% @spec (User, Server, Query, Lang) -> Result +%% User = binary() +%% Server = binary() +%% Query = ejabberd_http:query() +%% Lang = string() +%% Result = [ejabberd_web:html()] + user_roster(User, Server, Query, Lang) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -933,6 +1131,10 @@ user_roster(User, Server, Query, Lang) -> ])] end. +%% @spec (JID) -> Result +%% JID = jlib:shortjid() +%% Result = ejabberd_web:html() + build_contact_jid_td({U, S, R}) -> %% Convert {U, S, R} into {jid, U, S, R, U, S, R}: ContactJID = exmpp_jid:make_jid(U, S, R), @@ -953,6 +1155,12 @@ build_contact_jid_td({U, S, R}) -> ?XAE('td', [?XMLATTR('class', <<"valign">>)], [?AC(JIDURI, exmpp_jid:jid_to_list(ContactJID))]) end. +%% @spec (User, Server, Items, Query) -> ok | nothing | error +%% User = binary() +%% Server = binary() +%% Items = [rosteritem()] +%% Query = ejabberd_http:query() + user_roster_parse_query(User, Server, Items, Query) -> case lists:keysearch("addjid", 1, Query) of {value, _} -> @@ -983,6 +1191,10 @@ user_roster_parse_query(User, Server, Items, Query) -> end end. +%% @spec (User, Server, JID) -> term() +%% User = binary() +%% Server = binary() +%% JID = exmpp_jid:jid() user_roster_subscribe_jid(User, Server, JID) -> out_subscription(User, Server, JID, subscribe), @@ -990,10 +1202,16 @@ user_roster_subscribe_jid(User, Server, JID) -> ejabberd_router:route( UJID, JID, exmpp_presence:subscribe()). +%% @spec (User, Server, Items, Query) -> term() +%% User = binary() +%% Server = binary() +%% Items = [rosteritem()] +%% Query = ejabberd_http:query() + user_roster_item_parse_query(User, Server, Items, Query) -> lists:foreach( - fun(R) -> - JID = R#roster.jid, + fun(Roster) -> + JID = Roster#roster.jid, case lists:keysearch( "validate" ++ ejabberd_web_admin:term_to_id(JID), 1, Query) of {value, _} -> @@ -1009,9 +1227,10 @@ user_roster_item_parse_query(User, Server, Items, Query) -> case lists:keysearch( "remove" ++ ejabberd_web_admin:term_to_id(JID), 1, Query) of {value, _} -> + {U, S, R} = JID, UJID = exmpp_jid:make_jid(User, Server), Attrs1 = exmpp_xml:set_attribute_in_list([], - 'jid', exmpp_jid:jid_to_list(JID)), + 'jid', exmpp_jid:jid_to_list(U, S, R)), Attrs2 = exmpp_xml:set_attribute_in_list(Attrs1, 'subscription', "remove"), Item = #xmlel{ns = ?NS_ROSTER, name = 'item', @@ -1032,9 +1251,21 @@ user_roster_item_parse_query(User, Server, Items, Query) -> end, Items), nothing. +%% @spec ({User, Server}) -> string() +%% User = binary() +%% Server = binary() + us_to_list({User, Server}) -> exmpp_jid:bare_jid_to_list(User, Server). +%% @spec (Acc, User, Server, Lang) -> New_Acc +%% Acc = [ejabberd_web:html()] +%% User = string() +%% Server = string() +%% Lang = string() +%% New_Acc = [ejabberd_web:html()] + webadmin_user(Acc, _User, _Server, Lang) -> + % `Lang' is used by the `T' macro, called from the `ACT' macro. Acc ++ [?XE("h3", [?ACT("roster/", "Roster")])]. From e977d099e2937deafc8ed4cfd45d52b055d75c24 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 13 Feb 2009 15:01:55 +0000 Subject: [PATCH 195/582] prevent from calling get_vh_registered_users/2 when not available SVN Revision: 1871 --- ChangeLog | 5 +++++ src/ejabberd_auth.erl | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index d8bb35775..c9a7a1db0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-02-13 Christophe Romain + + * src/ejabberd_auth.erl: prevent from calling + get_vh_registered_users/2 when not available + 2009-02-06 Jean-Sébastien Pédron * src/web/ejabberd_web.erl, src/web/ejabberd_http.erl: Add diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 6156b13bc..8e267ec37 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -242,7 +242,13 @@ get_vh_registered_users(Server) when is_list(Server) -> get_vh_registered_users(Server, Opts) when is_list(Server) -> lists:flatmap( fun(M) -> - M:get_vh_registered_users(Server, Opts) + case erlang:function_exported( + M, get_vh_registered_users_number, 2) of + true -> + M:get_vh_registered_users_number(Server, Opts); + false -> + M:get_vh_registered_users_number(Server) + end end, auth_modules(Server)). %% @spec (Server) -> Users_Number From ea62092d6e8264beb31c656f6ccc0c1556f26cfc Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Wed, 18 Feb 2009 13:48:06 +0000 Subject: [PATCH 196/582] src/ejabberd_auth.erl: Fix: for legacy authentication, the Digest parameters could be 'undefined'. src/mod_muc/mod_muc_room.erl: Typo. src/ejabberd_c2s.erl: Remove comment for an already done TODO. SVN Revision: 1885 --- ChangeLog | 9 +++++++++ src/ejabberd_auth.erl | 2 +- src/ejabberd_c2s.erl | 1 - src/mod_muc/mod_muc_room.erl | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index c9a7a1db0..b0f23021e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2009-02-18 Pablo Polvorin + + * src/ejabberd_auth.erl: Fix: for legacy authentication, the Digest + parameters could be 'undefined'. + + * src/mod_muc/mod_muc_room.erl: Typo. + + * src/ejabberd_c2s.erl: Remove comment for an already done TODO. + 2009-02-13 Christophe Romain * src/ejabberd_auth.erl: prevent from calling diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 8e267ec37..3e5152be5 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -145,7 +145,7 @@ check_password_with_authmodule(User, Server, Password) check_password_with_authmodule(User, Server, Password, StreamID, Digest) when is_list(User), is_list(Server), is_list(Password), - is_list(StreamID), is_list(Digest) -> + is_list(StreamID), (is_list(Digest) orelse Digest == 'undefined')-> Res = lists:dropwhile( fun(M) -> not apply(M, check_password, diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index e1d70770d..5377028ea 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -826,7 +826,6 @@ session_established2(El, StateData) -> User = StateData#state.user, Server = StateData#state.server, - % TODO: check 'from' attribute in stanza FromJID = StateData#state.jid, To = exmpp_stanza:get_recipient(El), ToJID = case To of diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 95400ed78..bac145b9b 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -1323,7 +1323,7 @@ prepare_room_queue(StateData) -> {{value, {message, From}}, _RoomQueue} -> Activity = get_user_activity(From, StateData), Packet = Activity#activity.message, - Size = erlang:iolist_size(exmpp_xml:documenent_to_iolist(Packet)), + Size = erlang:iolist_size(exmpp_xml:document_to_iolist(Packet)), {RoomShaper, RoomShaperInterval} = shaper:update(StateData#state.room_shaper, Size), erlang:send_after( From 7c10f3422a779ebf20ac756258e17a4cf42de07d Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Wed, 18 Feb 2009 18:03:11 +0000 Subject: [PATCH 197/582] src/web/ejabberd_web_admin.erl, src/web/ejabberd_web_admin.hrl: Many exmpp related fixes. Fix a bug when displaying users lists, if we can't access the 'offline_msg' mnesia table (using mod_offline_odbc). This fix should be temporal, we should find a better way to manage this situation. src/web/ejabberd_http.erl: Language must be in binary() format. src/translate.erl: Remove a debug call to io:format/2. src/ejabberd_sm.erl, src/mod_configure.erl, src/mod_disco.erl: ejabberd_sm:get_user_resources/2 returns resources as binary(). src/ejabberd_sm.erl: Bugfix in get_user_info/3. SVN Revision: 1886 --- ChangeLog | 15 ++++++++++ src/ejabberd_sm.erl | 8 +++--- src/mod_configure.erl | 2 +- src/mod_disco.erl | 2 +- src/translate.erl | 1 - src/web/ejabberd_http.erl | 6 ++-- src/web/ejabberd_web_admin.erl | 51 ++++++++++++++++++++-------------- src/web/ejabberd_web_admin.hrl | 30 ++++++++++---------- 8 files changed, 69 insertions(+), 46 deletions(-) diff --git a/ChangeLog b/ChangeLog index b0f23021e..274171a67 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,21 @@ * src/ejabberd_c2s.erl: Remove comment for an already done TODO. + * src/web/ejabberd_web_admin.erl, src/web/ejabberd_web_admin.hrl: + Many exmpp related fixes. Fix a bug when displaying users lists, + if we can't access the 'offline_msg' mnesia table (using mod_offline_odbc). + This fix should be temporal, we should find a better way to manage this + situation. The webadmin is usable again. + + * src/web/ejabberd_http.erl: Language must be in binary() format. + + * src/translate.erl: Remove a debug call to io:format/2. + + * src/ejabberd_sm.erl, src/mod_configure.erl, src/mod_disco.erl: + ejabberd_sm:get_user_resources/2 returns resources as binary(). + + * src/ejabberd_sm.erl: Bugfix in get_user_info/3. + 2009-02-13 Christophe Romain * src/ejabberd_auth.erl: prevent from calling diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 9f22b2ba4..ff857fc5c 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -154,7 +154,7 @@ get_user_resources(User, Server) {'EXIT', _Reason} -> []; Ss -> - [binary_to_list(element(3, S#session.usr)) || S <- clean_session_list(Ss)] + [element(3, S#session.usr) || S <- clean_session_list(Ss)] end. get_user_ip(JID) when ?IS_JID(JID) -> @@ -176,9 +176,9 @@ get_user_info(User, Server, Resource) LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), LResource = exmpp_stringprep:resourceprep(Resource), - USR = {list_to_binary(LUser), - list_to_binary(LServer), - list_to_binary(LResource)}, + USR = {LUser, + LServer, + LResource}, case mnesia:dirty_index_read(session, USR, #session.usr) of [] -> offline; diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 490e60858..ed5f7bdf9 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -287,7 +287,7 @@ get_sm_items(Acc, From, To, Node, Lang) -> {allow, ""} -> Nodes = [?NODEJID(To, "Configuration", <<"config">>), ?NODEJID(To, "User Management", <<"user">>)], - {result, Items ++ Nodes ++ get_user_resources(To)}; + {result, Items ++ Nodes ++ [binary_to_list(R) || R <- get_user_resources(To)]}; {allow, "config"} -> {result, []}; {_, "config"} -> diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 345a56ff7..b548464eb 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -324,7 +324,7 @@ get_sm_items(Acc, From, To, <<>>, _Lang) -> empty -> [] end, Items1 = case {LFrom, LSFrom} of - {LTo, LSTo} -> get_user_resources(To); + {LTo, LSTo} -> [binary_to_list(R) || R <- get_user_resources(To)]; _ -> [] end, {result, Items ++ Items1}; diff --git a/src/translate.erl b/src/translate.erl index 8929ccd06..9a823c5cd 100644 --- a/src/translate.erl +++ b/src/translate.erl @@ -105,7 +105,6 @@ load_file(Lang, File) -> end. translate(Lang, Msg) -> - io:format("translate(~p, ~p) ~n",[Lang, Msg]), LLang = ascii_tolower(Lang), case ets:lookup(translations, {LLang, Msg}) of [{_, Trans}] -> diff --git a/src/web/ejabberd_http.erl b/src/web/ejabberd_http.erl index 1a1546bfd..14fa5054f 100644 --- a/src/web/ejabberd_http.erl +++ b/src/web/ejabberd_http.erl @@ -51,7 +51,7 @@ request_auth, request_keepalive, request_content_length, - request_lang = "en", + request_lang = <<"en">>, %% XXX bard: request handlers are configured in %% ejabberd.cfg under the HTTP service. For example, %% to have the module test_web handle requests with @@ -548,9 +548,9 @@ make_text_output(State, Status, Headers, Data) when is_binary(Data) -> parse_lang(Langs) -> case string:tokens(Langs, ",; ") of [First | _] -> - First; + list_to_binary(First); [] -> - "en" + <<"en">> end. % Code below is taken (with some modifications) from the yaws webserver, which diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index ef68160d5..c870cef56 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -975,7 +975,7 @@ process_admin(Host, #request{lang = Lang} = Request) -> global -> {webadmin_page_main, [Request]}; Host -> {webadmin_page_host, [Host, Request]} end, - case ejabberd_hooks:run_fold(Hook, Host, [], Opts) of + case ejabberd_hooks:run_fold(Hook, list_to_binary(Host), [], Opts) of [] -> setelement(1, make_xhtml([?XC('h1', "Not Found")], Host, Lang), 404); Res -> make_xhtml(Res, Host, Lang) end. @@ -1291,7 +1291,7 @@ list_vhosts(Lang) -> lists:map( fun(Host) -> OnlineUsers = - length(ejabberd_sm:get_vh_session_list(Host)), + length(ejabberd_sm:get_vh_session_list(list_to_binary(Host))), RegisteredUsers = ejabberd_auth:get_vh_registered_users_number(Host), ?XE('tr', @@ -1400,13 +1400,20 @@ list_given_users(Users, Prefix, Lang, URLFunc) -> ?XE('tbody', lists:map( fun(_SU = {Server, User}) -> - US = {User, Server}, - QueueLen = length(mnesia:dirty_read({offline_msg, US})), - FQueueLen = [?AC(URLFunc({users_queue, Prefix, - User, Server}), - integer_to_list(QueueLen))], + ServerB = list_to_binary(Server), + UserB = list_to_binary(User), + US = {UserB, ServerB}, + FQueueLen = try + QueueLen = length(mnesia:dirty_read({offline_msg, US})), + [?AC(URLFunc({users_queue, Prefix, + User, Server}), + integer_to_list(QueueLen))] + catch + _:_ -> [#xmlcdata{cdata = <<"Can't access the offline messages storage.">>}] + end, + FLast = - case ejabberd_sm:get_user_resources(User, Server) of + case ejabberd_sm:get_user_resources(UserB, ServerB) of [] -> case mnesia:dirty_read({last_activity, US}) of [] -> @@ -1464,7 +1471,7 @@ get_stats(global, Lang) -> ])]; get_stats(Host, Lang) -> - OnlineUsers = length(ejabberd_sm:get_vh_session_list(Host)), + OnlineUsers = length(ejabberd_sm:get_vh_session_list(list_to_binary(Host))), RegisteredUsers = ejabberd_auth:get_vh_registered_users_number(Host), [?XAE('table', [], [?XE('tbody', @@ -1477,20 +1484,22 @@ get_stats(Host, Lang) -> list_online_users(Host, _Lang) -> - Users = [{S, U} || {U, S, _R} <- ejabberd_sm:get_vh_session_list(Host)], + Users = [{S, U} || {U, S, _R} <- ejabberd_sm:get_vh_session_list(list_to_binary(Host))], SUsers = lists:usort(Users), lists:flatmap( fun({_S, U} = SU) -> - [?AC("../user/" ++ ejabberd_http:url_encode(U) ++ "/", + [?AC("../user/" ++ ejabberd_http:url_encode(binary_to_list(U)) ++ "/", su_to_list(SU)), ?BR] end, SUsers). user_info(User, Server, Query, Lang) -> + UserB = list_to_binary(User), + ServerB = list_to_binary(Server), LServer = exmpp_stringprep:nameprep(Server), US = {exmpp_stringprep:nodeprep(User), LServer}, Res = user_parse_query(User, Server, Query), - Resources = ejabberd_sm:get_user_resources(User, Server), + Resources = ejabberd_sm:get_user_resources(UserB, ServerB), FResources = case Resources of [] -> @@ -1499,7 +1508,7 @@ user_info(User, Server, Query, Lang) -> [?XE('ul', lists:map(fun(R) -> FIP = case ejabberd_sm:get_user_info( - User, Server, R) of + UserB, ServerB, R) of offline -> ""; [{node, Node}, {conn, Conn}, {ip, {IP, Port}}] -> @@ -1518,13 +1527,13 @@ user_info(User, Server, Query, Lang) -> ++ "#" ++ atom_to_list(Node) ++ ")" end, - ?LI([?C(R ++ FIP)]) + ?LI([?C(binary_to_list(R) ++ FIP)]) end, lists:sort(Resources)))] end, Password = ejabberd_auth:get_password_s(User, Server), FPassword = [?INPUT("password", "password", Password), ?C(" "), ?INPUTT("submit", "chpassword", "Change Password")], - UserItems = ejabberd_hooks:run_fold(webadmin_user, LServer, [], + UserItems = ejabberd_hooks:run_fold(webadmin_user, list_to_binary(LServer), [], [User, Server, Lang]), [?XC('h1', ?T("User ") ++ us_to_list(US))] ++ case Res of @@ -1562,7 +1571,7 @@ user_parse_query1("removeuser", User, Server, _Query) -> ejabberd_auth:remove_user(User, Server), ok; user_parse_query1(Action, User, Server, Query) -> - case ejabberd_hooks:run_fold(webadmin_user_parse_query, Server, [], [Action, User, Server, Query]) of + case ejabberd_hooks:run_fold(webadmin_user_parse_query, list_to_binary(Server), [], [Action, User, Server, Query]) of [] -> nothing; Res -> Res end. @@ -1972,7 +1981,7 @@ get_node(Host, Node, NPath, Query, Lang) -> global -> {webadmin_page_node, [Node, NPath, Query, Lang]}; Host -> {webadmin_page_hostnode, [Host, Node, NPath, Query, Lang]} end, - case ejabberd_hooks:run_fold(Hook, Host, [], Opts) of + case ejabberd_hooks:run_fold(Hook, list_to_binary(Host), [], Opts) of [] -> [?XC('h1', "Not Found")]; Res -> Res end. @@ -2135,7 +2144,7 @@ node_ports_to_xhtml(Ports, Lang) -> ?XE('td', [?INPUTS("text", "ipnew", "0.0.0.0", "15")]), ?XE('td', [?INPUTS("text", "modulenew", "", "15")]), ?XE('td', [?TEXTAREA("optsnew", "2", "35", "[]")]), - ?XAE('td', [{"colspan", "2"}], + ?XAE('td', [?XMLATTR("colspan", "2")], [?INPUTT("submit", "addnew", "Add New")]) ] )] @@ -2237,7 +2246,7 @@ node_modules_to_xhtml(Modules, Lang) -> [?XE('tr', [?XE('td', [?INPUT("text", "modulenew", "")]), ?XE('td', [?TEXTAREA("optsnew", "2", "40", "[]")]), - ?XAE('td', [{"colspan", "2"}], + ?XAE('td', [?XMLATTR("colspan", "2")], [?INPUTT("submit", "start", "Start")]) ] )] @@ -2399,9 +2408,9 @@ make_server_menu(HostMenu, NodeMenu, Lang) -> get_menu_items_hook({hostnode, Host}, Lang) -> - ejabberd_hooks:run_fold(webadmin_menu_hostnode, Host, [], [Host, Lang]); + ejabberd_hooks:run_fold(webadmin_menu_hostnode, list_to_binary(Host), [], [Host, Lang]); get_menu_items_hook({host, Host}, Lang) -> - ejabberd_hooks:run_fold(webadmin_menu_host, Host, [], [Host, Lang]); + ejabberd_hooks:run_fold(webadmin_menu_host, list_to_binary(Host), [], [Host, Lang]); get_menu_items_hook(node, Lang) -> ejabberd_hooks:run_fold(webadmin_menu_node, [], [Lang]); get_menu_items_hook(server, Lang) -> diff --git a/src/web/ejabberd_web_admin.hrl b/src/web/ejabberd_web_admin.hrl index b896e693e..6f822f2f6 100644 --- a/src/web/ejabberd_web_admin.hrl +++ b/src/web/ejabberd_web_admin.hrl @@ -34,42 +34,42 @@ -define(XACT(Name, Attrs, Text), ?XAC(Name, Attrs, ?T(Text))). -define(LI(Els), ?XE('li', Els)). --define(A(URL, Els), ?XAE('a', [#xmlattr{name = 'href', value = URL}], Els)). +-define(A(URL, Els), ?XAE('a', [exmpp_xml:attribute('href', URL)], Els)). -define(AC(URL, Text), ?A(URL, [?C(Text)])). -define(ACT(URL, Text), ?AC(URL, ?T(Text))). -define(P, ?X('p')). -define(BR, ?X('br')). -define(INPUT(Type, Name, Value), - ?XA('input', [#xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'name', value = Name}, - #xmlattr{name = 'value', value = Value}])). + ?XA('input', [exmpp_xml:attribute('type', Type), + exmpp_xml:attribute('name', Name), + exmpp_xml:attribute('value', Value)])). -define(INPUTT(Type, Name, Value), ?INPUT(Type, Name, ?T(Value))). -define(INPUTS(Type, Name, Value, Size), - ?XA('input', [#xmlattr{name = 'type', value = Type}, - #xmlattr{name = 'name', value = Name}, - #xmlattr{name = 'value', value = Value}, - #xmlattr{name = 'size', value = Size}])). + ?XA('input', [exmpp_xml:attribute('type', Type), + exmpp_xml:attribute('name', Name), + exmpp_xml:attribute('value', Value), + exmpp_xml:attribute('size', Size)])). -define(INPUTST(Type, Name, Value, Size), ?INPUT(Type, Name, ?T(Value), Size)). -define(ACLINPUT(Text), ?XE('td', [?INPUT("text", "value" ++ ID, Text)])). -define(TEXTAREA(Name, Rows, Cols, Value), - ?XAC('textarea', [#xmlattr{name = 'name', value = list_to_binary(Name)}, - #xmlattr{name = 'rows', value = list_to_binary(Rows)}, - #xmlattr{name = 'cols', value = list_to_binary(Cols)}], + ?XAC('textarea', [exmpp_xml:attribute('name', list_to_binary(Name)), + exmpp_xml:attribute('rows', list_to_binary(Rows)), + exmpp_xml:attribute('cols', list_to_binary(Cols))], Value)). %% Build an xmlelement for result --define(XRES(Text), ?XAC('p', [#xmlattr{name = 'class', value = <<"result">>}], Text)). +-define(XRES(Text), ?XAC('p', [exmpp_xml:attribute('class', <<"result">>)], Text)). -define(XREST(Text), ?XRES(?T(Text))). %% Guide Link -define(GL(Ref, Title), ?XAE('div', - [#xmlattr{name = 'class', value = <<"guidelink">>}], + [exmpp_xml:attribute('class', <<"guidelink">>)], [?XAE('a', - [#xmlattr{name = 'href', value = list_to_binary("/admin/doc/guide.html#"++ Ref)}, - #xmlattr{name = 'target', value = <<"_blank">>}], + [exmpp_xml:attribute('href', list_to_binary("/admin/doc/guide.html#"++ Ref)), + exmpp_xml:attribute('target', <<"_blank">>)], [?C("[Guide: " ++ Title ++ "]")]) ])). From 5334a2d965bfcc6b2e9cb38c936b07aea3af16c7 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Wed, 18 Feb 2009 18:14:06 +0000 Subject: [PATCH 198/582] Bugfix: mod_announce.erl:get_title/2 now accepts node argument in binary() or list() format. SVN Revision: 1887 --- ChangeLog | 3 +++ src/mod_announce.erl | 25 +++++++++++++------------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 274171a67..d8b7ab8c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,9 @@ * src/ejabberd_sm.erl: Bugfix in get_user_info/3. + * src/mod_announce.erl: get_title/2 accepts node argument in binary() + or list() format. + 2009-02-13 Christophe Romain * src/ejabberd_auth.erl: prevent from calling diff --git a/src/mod_announce.erl b/src/mod_announce.erl index 5a419fef2..b6a2ea188 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -636,28 +636,29 @@ handle_adhoc_form(From, To, %% command nodes. {error, 'internal-server-error'} end. - -get_title(Lang, "announce") -> +get_title(Lang, Node) when is_list(Node) -> + get_title(Lang, list_to_binary(Node)); +get_title(Lang, <<"announce">>) -> translate:translate(Lang, "Announcements"); -get_title(Lang, ?NS_ADMIN_s ++ "#announce-all") -> +get_title(Lang, <>) -> translate:translate(Lang, "Send announcement to all users"); -get_title(Lang, ?NS_ADMIN_s ++ "#announce-all-allhosts") -> +get_title(Lang, <>) -> translate:translate(Lang, "Send announcement to all users on all hosts"); -get_title(Lang, ?NS_ADMIN_s ++ "#announce") -> +get_title(Lang, <>) -> translate:translate(Lang, "Send announcement to all online users"); -get_title(Lang, ?NS_ADMIN_s ++ "#announce-allhosts") -> +get_title(Lang, <>) -> translate:translate(Lang, "Send announcement to all online users on all hosts"); -get_title(Lang, ?NS_ADMIN_s ++ "#set-motd") -> +get_title(Lang, <>) -> translate:translate(Lang, "Set message of the day and send to online users"); -get_title(Lang, ?NS_ADMIN_s ++ "#set-motd-allhosts") -> +get_title(Lang, <>) -> translate:translate(Lang, "Set message of the day on all hosts and send to online users"); -get_title(Lang, ?NS_ADMIN_s ++ "#edit-motd") -> +get_title(Lang, <>) -> translate:translate(Lang, "Update message of the day (don't send)"); -get_title(Lang, ?NS_ADMIN_s ++ "#edit-motd-allhosts") -> +get_title(Lang, <>) -> translate:translate(Lang, "Update message of the day on all hosts (don't send)"); -get_title(Lang, ?NS_ADMIN_s ++ "#delete-motd") -> +get_title(Lang, <>) -> translate:translate(Lang, "Delete message of the day"); -get_title(Lang, ?NS_ADMIN_s ++ "#delete-motd-allhosts") -> +get_title(Lang, <>) -> translate:translate(Lang, "Delete message of the day on all hosts"). %%------------------------------------------------------------------------- From edc0a9ac87908aaeaedff03b20905a68f4fea75a Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 19 Feb 2009 11:29:01 +0000 Subject: [PATCH 199/582] fix nodetree plugin resolver, and backport last changes from trunk SVN Revision: 1890 --- ChangeLog | 13 +++++++++++++ src/mod_pubsub/mod_pubsub.erl | 25 +++++++++++++------------ src/mod_pubsub/node_buddy.erl | 2 +- src/mod_pubsub/node_club.erl | 2 +- src/mod_pubsub/node_default.erl | 2 +- src/mod_pubsub/node_mb.erl | 2 +- src/mod_pubsub/node_pep.erl | 2 +- src/mod_pubsub/node_private.erl | 2 +- src/mod_pubsub/node_public.erl | 2 +- 9 files changed, 33 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index d8b7ab8c7..c8356f29e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2009-02-19 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: fix nodetree plugin resolver + + * src/mod_pubsub/mod_pubsub.erl: backport last changes from trunk + * src/mod_pubsub/node_mb.erl: Likewise + * src/mod_pubsub/node_buddy.erl: Likewise + * src/mod_pubsub/node_private.erl: Likewise + * src/mod_pubsub/node_public.erl: Likewise + * src/mod_pubsub/node_default.erl: Likewise + * src/mod_pubsub/node_pep.erl: Likewise + * src/mod_pubsub/node_club.erl: Likewise + 2009-02-18 Pablo Polvorin * src/ejabberd_auth.erl: Fix: for legacy authentication, the Digest diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 622fc6b6d..08b17df85 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -33,14 +33,13 @@ %%% This module uses version 1.12 of the specification as a base. %%% Most of the specification is implemented. %%% Functions concerning configuration should be rewritten. -%%% Code is derivated from the original pubsub v1.7, by Alexey Shchepin %%% TODO %%% plugin: generate Reply (do not use broadcast atom anymore) -module(mod_pubsub). -author('christophe.romain@process-one.net'). --version('1.12-01'). +-version('1.12-02'). -behaviour(gen_server). -behaviour(gen_mod). @@ -185,7 +184,7 @@ init([ServerHost, Opts]) -> ets:new(gen_mod:get_module_proc(ServerHost, pubsub_state), [set, named_table]), ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {nodetree, NodeTree}), ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {plugins, Plugins}), - ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {pep_mapping, PepMapping}), + ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {pep_mapping, PepMapping}), init_nodes(Host, ServerHost), {ok, #state{host = Host, server_host = ServerHost, @@ -237,6 +236,8 @@ init_nodes(Host, ServerHost) -> ok. update_database(Host) -> + mnesia:del_table_index(pubsub_node, type), + mnesia:del_table_index(pubsub_node, parentid), case catch mnesia:table_info(pubsub_node, attributes) of [host_node, host_parent, info] -> ?INFO_MSG("upgrade pubsub tables",[]), @@ -761,10 +762,10 @@ iq_disco_info(Host, SNode, From, Lang) -> [?XMLATTR('category', "pubsub"), ?XMLATTR('type', "service"), ?XMLATTR('name', translate:translate(Lang, "Publish-Subscribe"))]}, - #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_DISCO_INFO_s)]}, - #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_DISCO_ITEMS_s)]}, - #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]}, - #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_VCARD_s)]}] ++ + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_DISCO_INFO_s)]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_DISCO_ITEMS_s)]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_VCARD_s)]}] ++ lists:map(fun(Feature) -> #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s++"#"++Feature)]} end, features(Host, SNode))}; @@ -1581,7 +1582,7 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> Action = fun(#pubsub_node{type = Type}) -> Features = features(Type), PersistentFeature = lists:member("persistent-items", Features), - DeleteFeature = lists:member("delete-any", Features), + DeleteFeature = lists:member("delete-items", Features), if %%-> iq_pubsub just does that matchs %% %% Request does not specify an item @@ -1591,7 +1592,7 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> {error, extended_error('feature-not-implemented', unsupported, "persistent-items")}; not DeleteFeature -> %% Service does not support item deletion - {error, extended_error('feature-not-implemented', unsupported, "delete-any")}; + {error, extended_error('feature-not-implemented', unsupported, "delete-items")}; true -> node_call(Type, delete_item, [Host, Node, Publisher, ItemId]) end @@ -1984,7 +1985,7 @@ get_subscriptions(Host, Node, JID) -> if not RetrieveFeature -> %% Service does not support manage subscriptions - {error, extended_error('feature-not-implemented', unsupported, "manage-affiliations")}; + {error, extended_error('feature-not-implemented', unsupported, "manage-subscriptions")}; Affiliation /= {result, owner} -> %% Entity is not an owner {error, 'forbidden'}; @@ -2695,7 +2696,7 @@ features() -> "config-node", % RECOMMENDED "create-and-configure", % RECOMMENDED % see plugin "create-nodes", % RECOMMENDED - % see plugin "delete-any", % RECOMMENDED + % see plugin "delete-items", % RECOMMENDED % see plugin "delete-nodes", % RECOMMENDED % see plugin "filtered-notifications", % RECOMMENDED %TODO "get-pending", % OPTIONAL @@ -2747,7 +2748,7 @@ tree_call({_User, Server, _Resource}, Function, Args) -> tree_call(Host, Function, Args) -> Module = case ets:lookup(gen_mod:get_module_proc(Host, pubsub_state), nodetree) of [{nodetree, N}] -> N; - _ -> list_to_atom(?TREE_PREFIX ++ ?STDNODE) + _ -> list_to_atom(?TREE_PREFIX ++ ?STDTREE) end, catch apply(Module, Function, Args). tree_action(Host, Function, Args) -> diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl index 91834e708..6d9e1b549 100644 --- a/src/mod_pubsub/node_buddy.erl +++ b/src/mod_pubsub/node_buddy.erl @@ -98,7 +98,7 @@ options() -> features() -> ["create-nodes", "delete-nodes", - "delete-any", + "delete-items", "instant-nodes", "item-ids", "outcast-affiliation", diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl index d62da7201..b5a04beda 100644 --- a/src/mod_pubsub/node_club.erl +++ b/src/mod_pubsub/node_club.erl @@ -98,7 +98,7 @@ options() -> features() -> ["create-nodes", "delete-nodes", - "delete-any", + "delete-items", "instant-nodes", "outcast-affiliation", "persistent-items", diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 7087ef11a..56e0d6d2b 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -160,7 +160,7 @@ features() -> ["create-nodes", "auto-create", "delete-nodes", - "delete-any", + "delete-items", "instant-nodes", "manage-subscriptions", "modify-affiliations", diff --git a/src/mod_pubsub/node_mb.erl b/src/mod_pubsub/node_mb.erl index d1071d863..90a5cdad2 100644 --- a/src/mod_pubsub/node_mb.erl +++ b/src/mod_pubsub/node_mb.erl @@ -103,7 +103,7 @@ features() -> "auto-create", %* "auto-subscribe", %* "delete-nodes", %* - "delete-any", %* + "delete-items", %* "filtered-notifications", %* "modify-affiliations", "outcast-affiliation", diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index 47041b83d..ebb2e5c35 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -98,7 +98,7 @@ features() -> "auto-create", %* "auto-subscribe", %* "delete-nodes", %* - "delete-any", %* + "delete-items", %* "filtered-notifications", %* "modify-affiliations", "outcast-affiliation", diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl index a1fe4783b..32f86fbb8 100644 --- a/src/mod_pubsub/node_private.erl +++ b/src/mod_pubsub/node_private.erl @@ -98,7 +98,7 @@ options() -> features() -> ["create-nodes", "delete-nodes", - "delete-any", + "delete-items", "instant-nodes", "outcast-affiliation", "persistent-items", diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl index 0a3d9d7cb..c8fa085ab 100644 --- a/src/mod_pubsub/node_public.erl +++ b/src/mod_pubsub/node_public.erl @@ -98,7 +98,7 @@ options() -> features() -> ["create-nodes", "delete-nodes", - "delete-any", + "delete-items", "instant-nodes", "outcast-affiliation", "persistent-items", From e989d41d500de22f7e6a2f8acc49c7d4133ef896 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Fri, 20 Feb 2009 15:30:16 +0000 Subject: [PATCH 200/582] "remove_user" hook actualized to expect binary arguments. Fix webadmin code that performs addition / removal of users. SVN Revision: 1892 --- ChangeLog | 10 ++++++++++ src/ejabberd_auth.erl | 8 +++++--- src/mod_offline_odbc.erl | 4 ++-- src/mod_privacy_odbc.erl | 2 +- src/mod_private_odbc.erl | 4 ++-- src/mod_roster_odbc.erl | 4 ++-- src/mod_vcard_odbc.erl | 6 +++--- src/web/ejabberd_web_admin.erl | 4 ++-- 8 files changed, 27 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index c8356f29e..7dcc3d4c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2009-02-20 Pablo Polvorin + + * src/mod_offline_odbc.erl, src/mod_privacy_odbc.erl, + src/ejabberd_auth.erl, src/mod_vcard_odbc.erl, + src/mod_private_odbc.erl, src/mod_roster_odbc.erl: remove_user hook + actualized to expect binary arguments. + + * src/web/ejabberd_web_admin.erl: Fix add / remove users. + + 2009-02-19 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: fix nodetree plugin resolver diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 3e5152be5..623fb7fd5 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -198,7 +198,7 @@ try_register(User, Server, Password) end, {error, not_allowed}, auth_modules(Server)), case Res of {atomic, ok} -> - ejabberd_hooks:run(register_user, Server, + ejabberd_hooks:run(register_user, list_to_binary(Server), [User, Server]), {atomic, ok}; _ -> Res @@ -370,7 +370,8 @@ remove_user(User, Server) when is_list(User), is_list(Server) -> M:remove_user(User, Server) end, auth_modules(Server)), case R of - ok -> ejabberd_hooks:run(remove_user, jlib:nameprep(Server), [User, Server]); + ok -> ejabberd_hooks:run(remove_user, list_to_binary(exmpp_stringprep:nameprep(Server)), + [list_to_binary(User), list_to_binary(Server)]); _ -> none end, R. @@ -393,7 +394,8 @@ remove_user(User, Server, Password) M:remove_user(User, Server, Password) end, error, auth_modules(Server)), case R of - ok -> ejabberd_hooks:run(remove_user, jlib:nameprep(Server), [User, Server]); + ok -> ejabberd_hooks:run(remove_user, list_to_binary(exmpp_stringprep:nameprep(Server)), + [list_to_binary(User), list_to_binary(Server)]); _ -> none end, R. diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index 77d4d806f..047388e57 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -279,8 +279,8 @@ pop_offline_messages(Ls, User, Server) remove_user(User, Server) when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), + LUser = binary_to_list(exmpp_stringprep:nodeprep(User)), + LServer = binary_to_list(exmpp_stringprep:nameprep(Server)), Username = ejabberd_odbc:escape(LUser), odbc_queries:del_spool_msg(LServer, Username) catch diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 5aded06af..67c7190ef 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -679,7 +679,7 @@ is_type_match(Type, Value, JID, Subscription, Groups) -> remove_user(User, Server) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), - sql_del_privacy_lists(LUser, LServer). + sql_del_privacy_lists(binary_to_list(LUser), binary_to_list(LServer)). updated_list(_, diff --git a/src/mod_private_odbc.erl b/src/mod_private_odbc.erl index a52bb3399..84deae535 100644 --- a/src/mod_private_odbc.erl +++ b/src/mod_private_odbc.erl @@ -171,8 +171,8 @@ end. remove_user(User, Server) when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), + LUser = binary_to_list(exmpp_stringprep:nodeprep(User)), + LServer = binary_to_list(exmpp_stringprep:nameprep(Server)), Username = ejabberd_odbc:escape(LUser), odbc_queries:del_user_private_storage(LServer, Username) catch diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index e56b70a77..a4abb072c 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -627,8 +627,8 @@ in_auto_reply(_, _, _) -> none. remove_user(User, Server) when is_binary(User), is_binary(Server) -> try - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), + LUser = binary_to_list(exmpp_stringprep:nodeprep(User)), + LServer = binary_to_list(exmpp_stringprep:nameprep(Server)), Username = ejabberd_odbc:escape(LUser), odbc_queries:del_user_roster_t(LServer, Username), ok diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl index d2db1f9e0..45531bd95 100644 --- a/src/mod_vcard_odbc.erl +++ b/src/mod_vcard_odbc.erl @@ -612,9 +612,9 @@ make_val(Match, Field, Val) -> % mnesia:transaction(F). -remove_user(User, Server) when is_binary(User), is_binary(server) -> - LUser = exmpp_stringprep:nodeprep(User), - LServer = exmpp_stringprep:nameprep(Server), +remove_user(User, Server) when is_binary(User), is_binary(Server) -> + LUser = binary_to_list(exmpp_stringprep:nodeprep(User)), + LServer = binary_to_list(exmpp_stringprep:nameprep(Server)), Username = ejabberd_odbc:escape(LUser), ejabberd_odbc:sql_transaction( LServer, diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index c870cef56..fe5ea042c 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -1364,8 +1364,8 @@ list_users_parse_query(Query, Host) -> lists:keysearch("newuserpassword", 1, Query), try JID = exmpp_jid:parse_jid(Username++"@"++Host), - User = exmpp_jid:node(JID), - Server = exmpp_jid:domain(JID), + User = exmpp_jid:node_as_list(JID), + Server = exmpp_jid:domain_as_list(JID), case ejabberd_auth:try_register(User, Server, Password) of {error, _Reason} -> error; From 2df100213bf73c1bcfbf95cf0a1f01084e6ab5aa Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Fri, 20 Feb 2009 16:34:56 +0000 Subject: [PATCH 201/582] mod_configure: Fix bug in form generation SVN Revision: 1893 --- ChangeLog | 2 ++ src/mod_configure.erl | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7dcc3d4c7..2613ee046 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,8 @@ actualized to expect binary arguments. * src/web/ejabberd_web_admin.erl: Fix add / remove users. + + * src/mod_configure.erl: Fix bug in form generation. 2009-02-19 Christophe Romain diff --git a/src/mod_configure.erl b/src/mod_configure.erl index ed5f7bdf9..ce6062310 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -51,7 +51,7 @@ -include("ejabberd.hrl"). -include("adhoc.hrl"). --define(T(Lang, Text), list_to_binary(translate:translate(Lang, Text))). +-define(T(Lang, Text), translate:translate(Lang, Text)). %% Copied from ejabberd_sm.erl -record(session, {sid, usr, us, priority, info}). @@ -711,7 +711,7 @@ get_running_nodes(Server, _Lang) -> S = list_to_binary(atom_to_list(N)), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Server), - ?XMLATTR('node', <<"running nodes/", (list_to_binary(S))/binary>>), + ?XMLATTR('node', <<"running nodes/", S/binary>>), ?XMLATTR('name', S)]} end, lists:sort(DBNodes)) end. From a5f70e15a2b4de9e4df9527791b1ee2664e480ee Mon Sep 17 00:00:00 2001 From: Badlop Date: Sat, 21 Feb 2009 14:41:29 +0000 Subject: [PATCH 202/582] * src/ejabberd_auth.erl: Password is undefined when using digest SVN Revision: 1908 --- ChangeLog | 4 ++++ src/ejabberd_auth.erl | 9 ++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2613ee046..3f2bd450a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-02-21 Badlop + + * src/ejabberd_auth.erl: Password is undefined when using digest + 2009-02-20 Pablo Polvorin * src/mod_offline_odbc.erl, src/mod_privacy_odbc.erl, diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 623fb7fd5..a90a2ad61 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -138,13 +138,16 @@ check_password_with_authmodule(User, Server, Password) %% @spec (User, Server, Password, StreamID, Digest) -> {true, AuthModule} | false %% User = string() %% Server = string() -%% Password = string() +%% Password = string() | undefined %% StreamID = string() -%% Digest = string() +%% Digest = string() | undefined %% AuthModule = authmodule() +%% The password is 'undefined' if the client +%% authenticates using the digest method as defined in +%% XEP-0078: Non-SASL Authentication check_password_with_authmodule(User, Server, Password, StreamID, Digest) - when is_list(User), is_list(Server), is_list(Password), + when is_list(User), is_list(Server), (is_list(Password) orelse Password == 'undefined'), is_list(StreamID), (is_list(Digest) orelse Digest == 'undefined')-> Res = lists:dropwhile( fun(M) -> From 49562591242448596ab3757118dfb684a1e0027a Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Sat, 21 Feb 2009 18:07:37 +0000 Subject: [PATCH 203/582] src/mod_roster.erl: Bugfix in remove_user/2, values already in binary() format. SVN Revision: 1909 --- ChangeLog | 5 +++++ src/mod_roster.erl | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3f2bd450a..52e4c80b8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-02-21 Pablo Polvorin + + * src/mod_roster.erl: Bugfix in remove_user/2: values already + in binary() format. + 2009-02-21 Badlop * src/ejabberd_auth.erl: Password is undefined when using digest diff --git a/src/mod_roster.erl b/src/mod_roster.erl index c4d6237e0..65cf56ef2 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -685,8 +685,8 @@ in_auto_reply(_, _, _) -> none. remove_user(User, Server) when is_binary(User), is_binary(Server) -> try - LUser = list_to_binary(exmpp_stringprep:nodeprep(User)), - LServer = list_to_binary(exmpp_stringprep:nameprep(Server)), + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, F = fun() -> lists:foreach(fun(R) -> From 7a17baccac6c759a2fb88d760108251c0b0b61f4 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Mon, 23 Feb 2009 15:58:21 +0000 Subject: [PATCH 204/582] Do not call mod_caps:clear_caps as it breaks PubSub/PEP (EJAB-854) SVN Revision: 1913 --- ChangeLog | 6 ++++++ src/ejabberd_c2s.erl | 10 ++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 52e4c80b8..9bea42ed9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-02-23 Christophe Romain + + * src/ejabberd_c2s.erl: Do not call mod_caps:clear_caps, this previous + optimization is too agressive and breaks PubSub/PEP standard behavior + (EJAB-854) + 2009-02-21 Pablo Polvorin * src/mod_roster.erl: Bugfix in remove_user/2: values already diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 5377028ea..6dbb5de4b 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1062,11 +1062,13 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> Els = Packet#xmlel.children, case exmpp_presence:get_type(Packet) of 'unavailable' -> - mod_caps:clear_caps(From); + %mod_caps:clear_caps(From); + % caps clear disabled cause it breaks things + ok; _ -> - ServerString = binary_to_list(StateData#state.server), - Caps = mod_caps:read_caps(Els), - mod_caps:note_caps(ServerString, From, Caps) + ServerString = binary_to_list(StateData#state.server), + Caps = mod_caps:read_caps(Els), + mod_caps:note_caps(ServerString, From, Caps) end, case ?SETS:is_element( LFrom, StateData#state.pres_a) orelse From acae6e20de1b4d8d91c3ea1b9e32a205278caf7b Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Mon, 23 Feb 2009 19:45:55 +0000 Subject: [PATCH 205/582] * Use exmpp_jid:to_binary/1 when possible. * ejabberd_odbc:escape/1 now can escape binaries too. This avoid the need to convert a binary value to list() just to sql-escape it. The escaped value returned is allways a list() (ejabberd's odbc drivers only works on lists()) SVN Revision: 1914 --- ChangeLog | 10 +++++ src/ejabberd_c2s.erl | 14 +++---- src/mod_echo.erl | 2 +- src/mod_roster.erl | 10 ++--- src/mod_roster_odbc.erl | 82 +++++++++++++++++++------------------- src/odbc/ejabberd_odbc.erl | 5 ++- 6 files changed, 67 insertions(+), 56 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9bea42ed9..c1688ad4e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2009-02-23 Pablo Polvorin + * src/ejabberd_c2s.erl, src/mod_echo.erl, src/mod_roster.erl, + src/mod_roster_odbc.erl: Use exmpp_jid:to_binary/1 when possible. + + * src/mod_roster_odbc.erl, src/odbc/ejabberd_odbc.erl: + ejabberd_odbc:escape/1 now can escape binaries too. This + avoid the need to convert a binary value to list() just to + sql-escape it. The escaped value returned is allways a list() + (ejabberd's odbc drivers only works on lists()) + 2009-02-23 Christophe Romain * src/ejabberd_c2s.erl: Do not call mod_caps:clear_caps, this previous diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 6dbb5de4b..50cac7292 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -409,7 +409,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> ?INFO_MSG( "(~w) Accepted legacy authentication for ~s", [StateData#state.socket, - exmpp_jid:jid_to_list(JID)]), + exmpp_jid:jid_to_binary(JID)]), SID = {now(), self()}, Conn = get_conn_type(StateData), Info = [{ip, StateData#state.ip}, {conn, Conn}, @@ -448,7 +448,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> ?INFO_MSG( "(~w) Failed legacy authentication for ~s", [StateData#state.socket, - exmpp_jid:jid_to_list(JID)]), + exmpp_jid:jid_to_binary(JID)]), Res = exmpp_iq:error_without_original(El, 'not-authorized'), send_element(StateData, Res), @@ -458,7 +458,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> ?INFO_MSG( "(~w) Forbidden legacy authentication for ~s", [StateData#state.socket, - exmpp_jid:jid_to_list(JID)]), + exmpp_jid:jid_to_binary(JID)]), Res = exmpp_iq:error_without_original(El, 'not-allowed'), send_element(StateData, Res), @@ -725,7 +725,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> allow -> ?INFO_MSG("(~w) Opened session for ~s", [StateData#state.socket, - exmpp_jid:jid_to_list(JID)]), + exmpp_jid:jid_to_binary(JID)]), SID = {now(), self()}, Conn = get_conn_type(StateData), Info = [{ip, StateData#state.ip}, {conn, Conn}, @@ -762,7 +762,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> StateData#state.server, [JID]), ?INFO_MSG("(~w) Forbidden session for ~s", [StateData#state.socket, - exmpp_jid:jid_to_list(JID)]), + exmpp_jid:jid_to_binary(JID)]), Err = exmpp_server_session:error(El, 'not-allowed'), send_element(StateData, Err), fsm_next_state(wait_for_session, StateData) @@ -1222,7 +1222,7 @@ terminate(_Reason, StateName, StateData) -> replaced -> ?INFO_MSG("(~w) Replaced session for ~s", [StateData#state.socket, - exmpp_jid:jid_to_list(StateData#state.jid)]), + exmpp_jid:jid_to_binary(StateData#state.jid)]), From = StateData#state.jid, Packet = exmpp_presence:unavailable(), Packet1 = exmpp_presence:set_status(Packet, @@ -1238,7 +1238,7 @@ terminate(_Reason, StateName, StateData) -> _ -> ?INFO_MSG("(~w) Close session for ~s", [StateData#state.socket, - exmpp_jid:jid_to_list(StateData#state.jid)]), + exmpp_jid:jid_to_binary(StateData#state.jid)]), EmptySet = ?SETS:new(), case StateData of diff --git a/src/mod_echo.erl b/src/mod_echo.erl index 0c0f86009..c4d5133b1 100644 --- a/src/mod_echo.erl +++ b/src/mod_echo.erl @@ -199,5 +199,5 @@ do_client_version(enabled, From, To) -> %% Print in log Values_string1 = [io_lib:format("~n~s: ~p", [N, V]) || {N, V} <- Values], Values_string2 = lists:concat(Values_string1), - ?INFO_MSG("Information of the client: ~s~s", [exmpp_jid:jid_to_list(To), Values_string2]). + ?INFO_MSG("Information of the client: ~s~s", [exmpp_jid:jid_to_binary(To), Values_string2]). diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 65cf56ef2..cb1b195e7 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -200,7 +200,7 @@ get_user_roster(Acc, {U, S} = US) when is_binary(U), is_binary(S) -> item_to_xml(Item) -> {U, S, R} = Item#roster.jid, Attrs1 = exmpp_xml:set_attribute_in_list([], - 'jid', exmpp_jid:jid_to_list(U, S, R)), + 'jid', exmpp_jid:jid_to_binary(U, S, R)), Attrs2 = case Item#roster.name of <<>> -> Attrs1; @@ -212,10 +212,10 @@ item_to_xml(Item) -> Attrs4 = case ask_to_pending(Item#roster.ask) of out -> exmpp_xml:set_attribute_in_list(Attrs3, - 'ask', "subscribe"); + 'ask', <<"subscribe">>); both -> exmpp_xml:set_attribute_in_list(Attrs3, - 'ask', "subscribe"); + 'ask', <<"subscribe">>); _ -> Attrs3 end, @@ -806,8 +806,8 @@ get_in_pending_subscriptions(Ls, User, Server) {U0, S0, R0} = R#roster.jid, Pres1 = exmpp_presence:subscribe(), Pres2 = exmpp_stanza:set_jids(Pres1, - exmpp_jid:jid_to_list(U0, S0, R0), - exmpp_jid:jid_to_list(JID)), + exmpp_jid:jid_to_binary(U0, S0, R0), + exmpp_jid:jid_to_binary(JID)), exmpp_presence:set_status(Pres2, Message) end, lists:filter( diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index a4abb072c..b408f7664 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -139,7 +139,7 @@ get_user_roster(Acc, {LUser, LServer}) -> end, Items) ++ Acc. get_roster(LUser, LServer) when is_binary(LUser), is_binary(LServer)-> - Username = ejabberd_odbc:escape(binary_to_list(LUser)), + Username = ejabberd_odbc:escape(LUser), DomainString = binary_to_list(LServer), case catch odbc_queries:get_roster(DomainString, Username) of {selected, ["username", "jid", "nick", "subscription", "ask", @@ -148,7 +148,7 @@ get_roster(LUser, LServer) when is_binary(LUser), is_binary(LServer)-> JIDGroups = case catch odbc_queries:get_roster_jid_groups(DomainString, Username) of {selected, ["jid","grp"], JGrps} when is_list(JGrps) -> - JGrps; + [{list_to_binary(S), list_to_binary(G)} || {S, G} <- JGrps]; _ -> [] end, @@ -160,7 +160,7 @@ get_roster(LUser, LServer) when is_binary(LUser), is_binary(LServer)-> []; R -> {U2, S2, R2} = R#roster.jid, - SJID = exmpp_jid:jid_to_list(U2, S2, R2), + SJID = exmpp_jid:jid_to_binary(U2, S2, R2), Groups = lists:flatmap( fun({S, G}) when S == SJID -> [G]; @@ -179,7 +179,7 @@ get_roster(LUser, LServer) when is_binary(LUser), is_binary(LServer)-> item_to_xml(Item) -> {U, S, R} = Item#roster.jid, Attrs1 = exmpp_xml:set_attribute_in_list([], - 'jid', exmpp_jid:jid_to_list(U, S, R)), + 'jid', exmpp_jid:jid_to_binary(U, S, R)), Attrs2 = case Item#roster.name of <<>> -> Attrs1; @@ -191,10 +191,10 @@ item_to_xml(Item) -> Attrs = case ask_to_pending(Item#roster.ask) of out -> exmpp_xml:set_attribute_in_list(Attrs3, - 'ask', "subscribe"); + 'ask', <<"subscribe">>); both -> exmpp_xml:set_attribute_in_list(Attrs3, - 'ask', "subscribe"); + 'ask', <<"subscribe">>); _ -> Attrs3 end, @@ -217,11 +217,12 @@ process_iq_set(From, To, #iq{payload = Request} = IQ_Rec) -> process_item_set(From, To, #xmlel{} = El) -> try JID1 = exmpp_jid:parse_jid(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), - LUser = exmpp_jid:lnode_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), + User = exmpp_jid:lnode(From), + Server = exmpp_jid:ldomain(From), + LServer = binary_to_list(Server), {U0, S0, R0} = LJID = jlib:short_prepd_jid(JID1), - Username = ejabberd_odbc:escape(LUser), - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(U0, S0, R0)), + Username = ejabberd_odbc:escape(User), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_binary(U0, S0, R0)), F = fun() -> {selected, ["username", "jid", "nick", "subscription", @@ -229,21 +230,21 @@ process_item_set(From, To, #xmlel{} = El) -> Res} = odbc_queries:get_roster_by_jid(LServer, Username, SJID), Item = case Res of [] -> - #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, + #roster{usj = {User, Server, LJID}, + us = {User, Server}, jid = LJID}; [I] -> R = raw_to_record(exmpp_jid:ldomain(From), I), case R of %% Bad JID in database: error -> - #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, + #roster{usj = {User, Server, LJID}, + us = {User, Server}, jid = LJID}; _ -> R#roster{ - usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, + usj = {User, Server, LJID}, + us = {User, Server}, jid = LJID, name = <<>>} end @@ -369,9 +370,8 @@ push_item(User, Server, Resource, From, Item) -> get_subscription_lists(_, User, Server) when is_binary(User), is_binary(Server) -> try - LUser = binary_to_list(User), LServer = binary_to_list(Server), - Username = ejabberd_odbc:escape(LUser), + Username = ejabberd_odbc:escape(User), case catch odbc_queries:get_roster(LServer, Username) of {selected, ["username", "jid", "nick", "subscription", "ask", "askmessage", "server", "subscribe", "type"], @@ -422,11 +422,10 @@ out_subscription(User, Server, JID, Type) -> process_subscription(Direction, User, Server, JID1, Type, Reason) when is_binary(User), is_binary(Server) -> try - LUser = binary_to_list(User), LServer = binary_to_list(Server), {N0,D0,R0} = LJID = jlib:short_prepd_jid(JID1), - Username = ejabberd_odbc:escape(LUser), - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(N0,D0,R0)), + Username = ejabberd_odbc:escape(User), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_binary(N0,D0,R0)), F = fun() -> Item = case odbc_queries:get_roster_by_jid(LServer, Username, SJID) of @@ -440,7 +439,7 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) Groups = case odbc_queries:get_roster_groups(LServer, Username, SJID) of {selected, ["grp"], JGrps} when is_list(JGrps) -> - [JGrp || {JGrp} <- JGrps]; + [list_to_binary(JGrp) || {JGrp} <- JGrps]; _ -> [] end, @@ -449,8 +448,8 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) ["username", "jid", "nick", "subscription", "ask", "askmessage", "server", "subscribe", "type"], []} -> - #roster{usj = {list_to_binary(LUser), list_to_binary(LServer), LJID}, - us = {list_to_binary(LUser), list_to_binary(LServer)}, + #roster{usj = {User, Server, LJID}, + us = {User, Server}, jid = LJID} end, NewState = case Direction of @@ -627,7 +626,7 @@ in_auto_reply(_, _, _) -> none. remove_user(User, Server) when is_binary(User), is_binary(Server) -> try - LUser = binary_to_list(exmpp_stringprep:nodeprep(User)), + LUser = exmpp_stringprep:nodeprep(User), LServer = binary_to_list(exmpp_stringprep:nameprep(Server)), Username = ejabberd_odbc:escape(LUser), odbc_queries:del_user_roster_t(LServer, Username), @@ -639,7 +638,7 @@ remove_user(User, Server) when is_binary(User), is_binary(Server) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -set_items(User, Server, #xmlel{children = Els}) -> +set_items(User, Server, #xmlel{children = Els}) when is_binary(User), is_binary(Server) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), catch odbc_queries:sql_transaction( @@ -653,7 +652,7 @@ process_item_set_t(LUser, LServer, #xmlel{} = El) -> JID1 = exmpp_jid:parse_jid(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), {U0, S0, R0} = LJID = jlib:short_prepd_jid(JID1), Username = ejabberd_odbc:escape(LUser), - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(U0, S0, R0)), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_binary(U0, S0, R0)), Item = #roster{usj = {LUser, LServer, LJID}, us = {LUser, LServer}, jid = LJID}, @@ -709,7 +708,7 @@ process_item_attrs_ws(Item, []) -> get_in_pending_subscriptions(Ls, User, Server) when is_binary(User), is_binary(Server) -> JID = exmpp_jid:make_jid(User, Server), - LUser = exmpp_jid:lnode_as_list(JID), + LUser = exmpp_jid:lnode(JID), LServer = exmpp_jid:ldomain_as_list(JID), Username = ejabberd_odbc:escape(LUser), case catch odbc_queries:get_roster(LServer, Username) of @@ -722,8 +721,8 @@ get_in_pending_subscriptions(Ls, User, Server) {U0, S0, R0} = R#roster.jid, Pres1 = exmpp_presence:subscribe(), Pres2 = exmpp_stanza:set_jids(Pres1, - exmpp_jid:jid_to_list(U0, S0, R0), - exmpp_jid:jid_to_list(JID)), + exmpp_jid:jid_to_binary(U0, S0, R0), + exmpp_jid:jid_to_binary(JID)), exmpp_presence:set_status(Pres2, Message) end, lists:flatmap( @@ -751,11 +750,10 @@ get_in_pending_subscriptions(Ls, User, Server) %% and short_prepd_bare_jid get_jid_info(_, User, Server, JID) when is_binary(User), is_binary(Server) -> try - LUser = binary_to_list(User), LServer = binary_to_list(Server), LJID = {N, D, R} = jlib:short_prepd_jid(JID), - Username = ejabberd_odbc:escape(LUser), - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(N, D, R)), + Username = ejabberd_odbc:escape(User), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_binary(N, D, R)), case catch odbc_queries:get_subscription(LServer, Username, SJID) of {selected, ["subscription"], [{SSubscription}]} -> Subscription = case SSubscription of @@ -766,7 +764,7 @@ get_jid_info(_, User, Server, JID) when is_binary(User), is_binary(Server) -> end, Groups = case catch odbc_queries:get_rostergroup_by_jid(LServer, Username, SJID) of {selected, ["grp"], JGrps} when is_list(JGrps) -> - [JGrp || {JGrp} <- JGrps]; + [list_to_binary(JGrp) || {JGrp} <- JGrps]; _ -> [] end, @@ -778,7 +776,7 @@ get_jid_info(_, User, Server, JID) when is_binary(User), is_binary(Server) -> {none, []}; true -> {LR_N, LR_D, LR_R} = LRJID, - SRJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(LR_N, LR_D, LR_R)), + SRJID = ejabberd_odbc:escape(exmpp_jid:jid_to_binary(LR_N, LR_D, LR_R)), case catch odbc_queries:get_subscription(LServer, Username, SRJID) of {selected, ["subscription"], [{SSubscription}]} -> Subscription = case SSubscription of @@ -789,7 +787,7 @@ get_jid_info(_, User, Server, JID) when is_binary(User), is_binary(Server) -> end, Groups = case catch odbc_queries:get_rostergroup_by_jid(LServer, Username, SRJID) of {selected, ["grp"], JGrps} when is_list(JGrps) -> - [JGrp || {JGrp} <- JGrps]; + [list_to_binary(JGrp) || {JGrp} <- JGrps]; _ -> [] end, @@ -844,10 +842,10 @@ record_to_string(#roster{us = {User, _Server}, subscription = Subscription, ask = Ask, askmessage = AskMessage}) -> - Username = ejabberd_odbc:escape(binary_to_list(User)), + Username = ejabberd_odbc:escape(User), {U, S, R} = JID, - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(U, S, R)), - Nick = ejabberd_odbc:escape(binary_to_list(Name)), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_binary(U, S, R)), + Nick = ejabberd_odbc:escape(Name), SSubscription = case Subscription of both -> "B"; to -> "T"; @@ -862,7 +860,7 @@ record_to_string(#roster{us = {User, _Server}, in -> "I"; none -> "N" end, - SAskMessage = ejabberd_odbc:escape(binary_to_list(AskMessage)), + SAskMessage = ejabberd_odbc:escape(AskMessage), [Username, SJID, Nick, SSubscription, SAsk, SAskMessage, "N", "", "item"]. groups_to_string(#roster{us = {User, _Server}, @@ -870,14 +868,14 @@ groups_to_string(#roster{us = {User, _Server}, groups = Groups}) -> Username = ejabberd_odbc:escape(User), {U, S, R} = JID, - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(U, S, R)), + SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_binary(U, S, R)), %% Empty groups do not need to be converted to string to be inserted in %% the database lists:foldl( fun([], Acc) -> Acc; (Group, Acc) -> - G = ejabberd_odbc:escape(binary_to_list(Group)), + G = ejabberd_odbc:escape(Group), [[Username, SJID, G]|Acc] end, [], Groups). webadmin_page(_, Host, diff --git a/src/odbc/ejabberd_odbc.erl b/src/odbc/ejabberd_odbc.erl index d40cb7588..aac4b2178 100644 --- a/src/odbc/ejabberd_odbc.erl +++ b/src/odbc/ejabberd_odbc.erl @@ -110,7 +110,10 @@ sql_query_t(Query) -> %% Escape character that will confuse an SQL engine escape(S) when is_list(S) -> - [odbc_queries:escape(C) || C <- S]. + [odbc_queries:escape(C) || C <- S]; + +escape(S) when is_binary(S) -> + [odbc_queries:escape(C) || <> <= S]. %% Escape character that will confuse an SQL engine %% Percent and underscore only need to be escaped for pattern matching like From 3119badb2b879e7695f9518592f4edd71a44a5df Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Tue, 24 Feb 2009 03:04:58 +0000 Subject: [PATCH 206/582] Removed a couple of expensive function calls used as arguments for ?DEBUG macros. All arguments used in the ?DEBUG macro are strictly evaluated (even if the loglevel is higher). The same is true for all log macros defined in ejabberd.hrl. We might need to use lazy evaluation for the arguments, when they are expensive to generate (wrap the arguments lists in a fun). SVN Revision: 1915 --- ChangeLog | 8 ++++++++ src/ejabberd_c2s.erl | 2 +- src/ejabberd_receiver.erl | 2 +- src/mod_caps.erl | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index c1688ad4e..75bb8adc1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,14 @@ sql-escape it. The escaped value returned is allways a list() (ejabberd's odbc drivers only works on lists()) + * src/ejabberd_c2s.erl, src/mod_caps.erl, src/ejabberd_receiver.erl: + Removed a couple of expensive function calls used as arguments for + ?DEBUG macros. All arguments used in the ?DEBUG macro are strictly + evaluated (even if the loglevel is higher). The same is true for + all log macros defined in ejabberd.hrl. We might need to use lazy + evaluation for the arguments, when they are expensive to generate + (wrap the arguments lists in a fun). + 2009-02-23 Christophe Romain * src/ejabberd_c2s.erl: Do not call mod_caps:clear_caps, this previous diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 50cac7292..614a4e4e4 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1277,7 +1277,7 @@ change_shaper(StateData, JID) -> (StateData#state.sockmod):change_shaper(StateData#state.socket, Shaper). send_text(StateData, Text) -> - ?DEBUG("Send XML on stream = ~p", [lists:flatten(Text)]), + ?DEBUG("Send XML on stream = ~s", [Text]), (StateData#state.sockmod):send(StateData#state.socket, Text). send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> diff --git a/src/ejabberd_receiver.erl b/src/ejabberd_receiver.erl index 05f8ddfb6..95e153554 100644 --- a/src/ejabberd_receiver.erl +++ b/src/ejabberd_receiver.erl @@ -302,7 +302,7 @@ process_data(Data, #state{xml_stream_state = XMLStreamState, shaper_state = ShaperState, c2s_pid = C2SPid} = State) -> - ?DEBUG("Received XML on stream = ~p", [binary_to_list(Data)]), + ?DEBUG("Received XML on stream = ~p", [Data]), {ok, XMLStreamState1} = exmpp_xmlstream:parse(XMLStreamState, Data), {NewShaperState, Pause} = shaper:update(ShaperState, size(Data)), HibTimeout = diff --git a/src/mod_caps.erl b/src/mod_caps.erl index c7483a121..df327eadf 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -311,7 +311,7 @@ handle_cast({disco_response, From, _To, #iq{id = ID, type = Type, payload = Payl %gen_server:cast(self(), visit_feature_queries), %?DEBUG("Error IQ reponse from ~s:~n~p", [exmpp_jid:jid_to_list(From), SubEls]); {result, Payload} -> - ?DEBUG("Invalid IQ contents from ~s:~n~p", [exmpp_jid:jid_to_list(From), Payload]); + ?DEBUG("Invalid IQ contents from ~s:~n~p", [exmpp_jid:jid_to_binary(From), Payload]); _ -> %% Can't do anything about errors ok From 31ef821e465437dd45f9f131ae1be2ab6737bded Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Tue, 24 Feb 2009 18:52:37 +0000 Subject: [PATCH 207/582] Exmpp related fixed to the external components service. SVN Revision: 1917 --- ChangeLog | 5 +++++ src/ejabberd_service.erl | 38 +++++++++++++++++--------------------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index 75bb8adc1..637e5414f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-02-24 Pablo Polvorin + + * src/ejabberd_service.erl: Exmpp related fixed to the external + components service. + 2009-02-23 Pablo Polvorin * src/ejabberd_c2s.erl, src/mod_echo.erl, src/mod_roster.erl, src/mod_roster_odbc.erl: Use exmpp_jid:to_binary/1 when possible. diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 41a78e0a7..72f7a03bb 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -134,7 +134,7 @@ init([{SockMod, Socket}, Opts]) -> {ok, wait_for_stream, #state{socket = Socket, sockmod = SockMod, streamid = new_id(), - hosts = Hosts, + hosts = [list_to_binary(H) || H <- Hosts], password = Password, access = Access, check_from = CheckFrom @@ -147,20 +147,20 @@ init([{SockMod, Socket}, Opts]) -> %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- -wait_for_stream({xmlstreamstart, #xmlel{ns = NS, attrs = Attrs}}, StateData) -> - case NS of - ?NS_COMPONENT_ACCEPT -> +wait_for_stream({xmlstreamstart, El = #xmlel{ns = NS, attrs = Attrs}}, StateData) -> + case exmpp_xml:is_ns_declared_here(El, ?NS_COMPONENT_ACCEPT) of + true -> %% Note: XEP-0114 requires to check that destination is a Jabber %% component served by this Jabber server. %% However several transports don't respect that, %% so ejabberd doesn't check 'to' attribute (EJAB-717) - To = binary_to_list(exmpp_stanza:get_recipient_from_attrs(Attrs)), - Opening_Reply = exmpp_stream:opening_reply(exmpp_xml:escape_using_entities(To), + To = exmpp_stanza:get_recipient_from_attrs(Attrs), + Opening_Reply = exmpp_stream:opening_reply(To, ?NS_COMPONENT_ACCEPT, {0, 0}, StateData#state.streamid), send_element(StateData, Opening_Reply), {next_state, wait_for_handshake, StateData}; - _ -> + false -> Error = #xmlel{ns = ?NS_XMPP, name = 'stream', children = [ #xmlel{ns = ?NS_XMPP, name = 'error', children = [ #xmlcdata{cdata = <<"Invalid Stream Header">>} @@ -184,7 +184,7 @@ wait_for_stream(closed, StateData) -> wait_for_handshake({xmlstreamelement, El}, StateData) -> - case {El#xmlel.name, exmpp_xml:get_cdata(El)} of + case {El#xmlel.name, exmpp_xml:get_cdata_as_list(El)} of {'handshake', Digest} -> case sha:sha(StateData#state.streamid ++ StateData#state.password) of @@ -193,11 +193,11 @@ wait_for_handshake({xmlstreamelement, El}, StateData) -> #xmlel{ns = ?NS_COMPONENT_ACCEPT, name = 'handshake'}), lists:foreach( fun(H) -> - ejabberd_router:register_route(H), + ejabberd_router:register_route(binary_to_list(H)), ?INFO_MSG("Route registered for service ~p~n", [H]) end, StateData#state.hosts), {next_state, stream_established, StateData}; - _ -> + _ -> send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'error', children = [ #xmlcdata{cdata = <<"Invalid Handshake">>}]}), @@ -231,7 +231,7 @@ stream_established({xmlstreamelement, El}, StateData) -> %% The default is the standard behaviour in XEP-0114 _ -> FromJID1 = exmpp_jid:parse_jid(From), - Server = exmpp_jid:ldomain_as_list(FromJID1), + Server = exmpp_jid:ldomain(FromJID1), case lists:member(Server, StateData#state.hosts) of true -> FromJID1; false -> error @@ -240,7 +240,7 @@ stream_established({xmlstreamelement, El}, StateData) -> To = exmpp_stanza:get_recipient(El), ToJID = case To of undefined -> error; - _ -> exmpp_jib:binary_to_jid(To) + _ -> exmpp_jid:parse_jid(To) end, if ((El#xmlel.name == 'iq') or (El#xmlel.name == 'message') or @@ -318,14 +318,10 @@ handle_info({send_text, Text}, StateName, StateData) -> send_text(StateData, Text), {next_state, StateName, StateData}; handle_info({send_element, El}, StateName, StateData) -> + io:format("ejabberd_service send_element ~p~n",[ El]), send_element(StateData, El), {next_state, StateName, StateData}; -handle_info({route, FromOld, ToOld, PacketOld}, StateName, StateData) -> - %% XXX OLD FORMAT: From, To and Packet are in the old format. - Packet = exmpp_xml:xmlelement_to_xmlel(PacketOld, - [?NS_JABBER_CLIENT], ?PREFIXED_NS), - From = jlib:from_old_jid(FromOld), - To = jlib:from_old_jid(ToOld), +handle_info({route, From, To, Packet}, StateName, StateData) -> case acl:match_rule(global, StateData#state.access, From) of allow -> El1 = exmpp_stanza:set_sender(Packet, From), @@ -349,7 +345,7 @@ terminate(Reason, StateName, StateData) -> stream_established -> lists:foreach( fun(H) -> - ejabberd_router:unregister_route(H) + ejabberd_router:unregister_route(binary_to_list(H)) end, StateData#state.hosts); _ -> ok @@ -365,9 +361,9 @@ send_text(StateData, Text) -> (StateData#state.sockmod):send(StateData#state.socket, Text). send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> - send_text(StateData, exmpp_stream:to_list(El)); + send_text(StateData, exmpp_stream:to_iolist(El)); send_element(StateData, El) -> - send_text(StateData, exmpp_stanza:to_list(El)). + send_text(StateData, exmpp_stanza:to_iolist(El)). new_id() -> randoms:get_string(). From 9b1e5928bd1c5357e683c144139b259bfee9e3c1 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Tue, 24 Feb 2009 20:07:32 +0000 Subject: [PATCH 208/582] Remove unused var SVN Revision: 1918 --- src/ejabberd_service.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 72f7a03bb..0f2472467 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -147,7 +147,7 @@ init([{SockMod, Socket}, Opts]) -> %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- -wait_for_stream({xmlstreamstart, El = #xmlel{ns = NS, attrs = Attrs}}, StateData) -> +wait_for_stream({xmlstreamstart, El = #xmlel{ns = _NS, attrs = Attrs}}, StateData) -> case exmpp_xml:is_ns_declared_here(El, ?NS_COMPONENT_ACCEPT) of true -> %% Note: XEP-0114 requires to check that destination is a Jabber @@ -358,6 +358,7 @@ terminate(Reason, StateName, StateData) -> %%%---------------------------------------------------------------------- send_text(StateData, Text) -> + io:format(">>~n ~s ~n", [Text]), (StateData#state.sockmod):send(StateData#state.socket, Text). send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> From 0f53fea9030adf6f569cdb4a0ad1d6bf1462b701 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Tue, 24 Feb 2009 20:25:57 +0000 Subject: [PATCH 209/582] src/mod_echo.erl: Fix call to exmpp_xml:get_cdata_as_list/1. SVN Revision: 1919 --- ChangeLog | 2 ++ src/mod_echo.erl | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 637e5414f..6c09ce86f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,8 @@ * src/ejabberd_service.erl: Exmpp related fixed to the external components service. + * src/mod_echo.erl: Fix call to exmpp_xml:get_cdata_as_list/1. + 2009-02-23 Pablo Polvorin * src/ejabberd_c2s.erl, src/mod_echo.erl, src/mod_roster.erl, src/mod_roster_odbc.erl: Use exmpp_jid:to_binary/1 when possible. diff --git a/src/mod_echo.erl b/src/mod_echo.erl index c4d5133b1..a1df48723 100644 --- a/src/mod_echo.erl +++ b/src/mod_echo.erl @@ -194,7 +194,7 @@ do_client_version(enabled, From, To) -> after 5000 -> % Timeout in miliseconds: 5 seconds [] end, - Values = [{Name, exmpp_xml:get_cdata_as_list(Children)} || #xmlel{name = Name, children = Children} <- Els], + Values = [{Name, exmpp_xml:get_cdata_as_list(El)} || #xmlel{name = Name} = El <- Els], %% Print in log Values_string1 = [io_lib:format("~n~s: ~p", [N, V]) || {N, V} <- Values], From 2678342c4a9a1eb3a418a8a8e36de5b3a8a04e13 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Tue, 24 Feb 2009 20:50:28 +0000 Subject: [PATCH 210/582] mod_muc/mod_muc_log.erl: The logging code expect nicknames to be in list() format. SVN Revision: 1920 --- ChangeLog | 3 +++ src/mod_muc/mod_muc_log.erl | 16 ++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6c09ce86f..79df3eb5a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,9 @@ * src/mod_echo.erl: Fix call to exmpp_xml:get_cdata_as_list/1. + * src/mod_muc/mod_muc_log.erl: The logging code expect nicknames + to be in list() format. + 2009-02-23 Pablo Polvorin * src/ejabberd_c2s.erl, src/mod_echo.erl, src/mod_roster.erl, src/mod_roster_odbc.erl: Use exmpp_jid:to_binary/1 when possible. diff --git a/src/mod_muc/mod_muc_log.erl b/src/mod_muc/mod_muc_log.erl index ae8c89645..7f5c18718 100644 --- a/src/mod_muc/mod_muc_log.erl +++ b/src/mod_muc/mod_muc_log.erl @@ -138,7 +138,7 @@ init([Host, Opts]) -> file_format = FileFormat, css_file = CSSFile, access = AccessLog, - lang = Lang, + lang = list_to_binary(Lang), timezone = Timezone, spam_prevention = NoFollow, top_link = Top_link}}. @@ -211,29 +211,29 @@ add_to_log2(text, {Nick, Packet}, Room, Opts, State) -> ok; {'undefined', SubEl} -> Message = {body, exmpp_xml:get_cdata_as_list(SubEl)}, - add_message_to_log(Nick, Message, Room, Opts, State); + add_message_to_log(binary_to_list(Nick), Message, Room, Opts, State); {SubEl, _} -> Message = {subject, exmpp_xml:get_cdata_as_list(SubEl)}, - add_message_to_log(Nick, Message, Room, Opts, State) + add_message_to_log(binary_to_list(Nick), Message, Room, Opts, State) end; add_to_log2(roomconfig_change, _, Room, Opts, State) -> add_message_to_log("", roomconfig_change, Room, Opts, State); add_to_log2(nickchange, {OldNick, NewNick}, Room, Opts, State) -> - add_message_to_log(NewNick, {nickchange, OldNick}, Room, Opts, State); + add_message_to_log(binary_to_list(NewNick), {nickchange, binary_to_list(OldNick)}, Room, Opts, State); add_to_log2(join, Nick, Room, Opts, State) -> - add_message_to_log(Nick, join, Room, Opts, State); + add_message_to_log(binary_to_list(Nick), join, Room, Opts, State); add_to_log2(leave, {Nick, Reason}, Room, Opts, State) -> case binary_to_list(Reason) of - "" -> add_message_to_log(Nick, leave, Room, Opts, State); - R -> add_message_to_log(Nick, {leave, R}, Room, Opts, State) + "" -> add_message_to_log(binary_to_list(Nick), leave, Room, Opts, State); + R -> add_message_to_log(binary_to_list(Nick), {leave, R}, Room, Opts, State) end; add_to_log2(kickban, {Nick, Reason, Code}, Room, Opts, State) -> - add_message_to_log(Nick, {kickban, Code, binary_to_list(Reason)}, Room, Opts, State). + add_message_to_log(binary_to_list(Nick), {kickban, Code, binary_to_list(Reason)}, Room, Opts, State). %%---------------------------------------------------------------------- From 34f6de0c84c1815b6a6a1d18211b41bfe2be8bc5 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 25 Feb 2009 21:17:14 +0000 Subject: [PATCH 211/582] * src/mod_pubsub/mod_pubsub.erl: Fix incorrect implementation of Pubsub payload requirements (thanks to Andy Skelton)(EJAB-823) SVN Revision: 1921 --- ChangeLog | 7 ++++++- src/mod_pubsub/mod_pubsub.erl | 10 ++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 79df3eb5a..a62b7c11a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-02-25 Badlop + + * src/mod_pubsub/mod_pubsub.erl: Fix incorrect implementation of + Pubsub payload requirements (thanks to Andy Skelton)(EJAB-823) + 2009-02-24 Pablo Polvorin * src/ejabberd_service.erl: Exmpp related fixed to the external @@ -9,6 +14,7 @@ to be in list() format. 2009-02-23 Pablo Polvorin + * src/ejabberd_c2s.erl, src/mod_echo.erl, src/mod_roster.erl, src/mod_roster_odbc.erl: Use exmpp_jid:to_binary/1 when possible. @@ -51,7 +57,6 @@ * src/web/ejabberd_web_admin.erl: Fix add / remove users. * src/mod_configure.erl: Fix bug in form generation. - 2009-02-19 Christophe Romain diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 08b17df85..2bdf8e1d0 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -1491,6 +1491,8 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> PublishFeature = lists:member("publish", Features), PublishModel = get_option(Options, publish_model), MaxItems = max_items(Options), + DeliverPayloads = get_option(Options, deliver_payloads), + PersistItems = get_option(Options, persist_items), PayloadCount = payload_xmlelements(Payload), PayloadSize = size(term_to_binary(Payload)), PayloadMaxSize = get_option(Options, max_payload_size), @@ -1509,11 +1511,11 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> Payload == "" -> %% Publisher attempts to publish to payload node with no payload {error, extended_error('bad-request', "payload-required")}; - (MaxItems == 0) and (PayloadSize > 0) -> - % Publisher attempts to publish to transient notification node with item + (DeliverPayloads == 0) and (PersistItems == 0) and (PayloadSize > 0) -> + %% Publisher attempts to publish to transient notification node with item {error, extended_error('bad-request', "item-forbidden")}; - (MaxItems > 0) and (PayloadSize == 0) -> - % Publisher attempts to publish to persistent node with no item + ((DeliverPayloads == 1) or (PersistItems == 1)) and (PayloadSize == 0) -> + %% Publisher attempts to publish to persistent node with no item {error, extended_error('bad-request', "item-required")}; true -> node_call(Type, publish_item, [Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload]) From dd5a7bcd540ad7c589c1826e9c72a1d65ee19b78 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 26 Feb 2009 23:10:28 +0000 Subject: [PATCH 212/582] * doc/guide.tex: No mention to the release date in ejabberd Guide or release notes. The date of an ejabberd release is determined by the date of the corresponding release announcement. SVN Revision: 1922 --- ChangeLog | 6 ++++++ doc/guide.tex | 3 --- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index a62b7c11a..9aca027f7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-02-27 Badlop + + * doc/guide.tex: No mention to the release date in ejabberd Guide + or release notes. The date of an ejabberd release is determined by + the date of the corresponding release announcement. + 2009-02-25 Badlop * src/mod_pubsub/mod_pubsub.erl: Fix incorrect implementation of diff --git a/doc/guide.tex b/doc/guide.tex index 9ee7be777..2e4c60531 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -126,9 +126,6 @@ the processing discipline for #1 IQ queries (see section~\ref{modiqdiscoption}). {\rule{\larg}{1mm}} \begin{latexonly} \vspace{2mm} \\ -\begin{tabular}{r} - {\large \bf \today} -\end{tabular}\\ \vspace{5.5cm} \end{latexonly} } From f4a952032a95bed7703c9c2edf5ffa0493aec275 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 27 Feb 2009 03:19:53 +0000 Subject: [PATCH 213/582] cosmetic changes SVN Revision: 1924 --- src/mod_pubsub/node_default.erl | 25 ++++++++++++------------- src/mod_pubsub/node_pep.erl | 12 ++++++------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 56e0d6d2b..adf3f1cf3 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -226,7 +226,6 @@ create_node(Host, Node, Owner) -> set_state(#pubsub_state{stateid = {OwnerKey, {Host, Node}}, affiliation = owner}), {result, {default, broadcast}}. - %% @spec (Host, Removed) -> ok %% Host = mod_pubsub:host() %% Removed = [mod_pubsub:pubsubNode()] @@ -559,8 +558,7 @@ get_entity_affiliations(Host, Owner) -> {result, lists:map(Tr, States)}. get_node_affiliations(Host, Node) -> - States = mnesia:match_object( - #pubsub_state{stateid = {'_', {Host, Node}}, _ = '_'}), + {result, States} = get_states(Host, Node), Tr = fun(#pubsub_state{stateid = {J, {_, _}}, affiliation = A}) -> {J, A} end, @@ -594,13 +592,15 @@ set_affiliation(Host, Node, Owner, Affiliation) -> %% that will be added to the affiliation stored in the main %% pubsub_state table.

      get_entity_subscriptions(Host, Owner) -> - States = case jlib:short_prepd_bare_jid(Owner) of - {U, D, ""} -> mnesia:match_object( - #pubsub_state{stateid = {{U, D, '_'}, {Host, '_'}}, _ = '_'}); - {U, D, R} -> mnesia:match_object( - #pubsub_state{stateid = {{U, D, ""}, {Host, '_'}}, _ = '_'}) - ++ mnesia:match_object( - #pubsub_state{stateid = {{U, D, R}, {Host, '_'}}, _ = '_'}) + SubKey = jlib:short_prepd_jid(Owner), + GenKey = jlib:short_prepd_bare_jid(SubKey), + States = case SubKey of + GenKey -> mnesia:match_object( + #pubsub_state{stateid = {{U, D, '_'}, {Host, '_'}}, _ = '_'}); + _ -> mnesia:match_object( + #pubsub_state{stateid = {GenKey, {Host, '_'}}, _ = '_'}) + ++ mnesia:match_object( + #pubsub_state{stateid = {SubKey, {Host, '_'}}, _ = '_'}) end, Tr = fun(#pubsub_state{stateid = {J, {_, N}}, subscription = S}) -> {N, S, J} @@ -608,8 +608,7 @@ get_entity_subscriptions(Host, Owner) -> {result, lists:map(Tr, States)}. get_node_subscriptions(Host, Node) -> - States = mnesia:match_object( - #pubsub_state{stateid = {'_', {Host, Node}}, _ = '_'}), + {result, States} = get_states(Host, Node), Tr = fun(#pubsub_state{stateid = {J, {_, _}}, subscription = S}) -> {J, S} end, @@ -778,7 +777,7 @@ get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup %% @spec (Item) -> ok | {error, Reason::stanzaError()} %% Item = mod_pubsub:pubsubItems() -%% @doc

      Write a state into database.

      +%% @doc

      Write an item into database.

      set_item(Item) when is_record(Item, pubsub_item) -> mnesia:write(Item); set_item(_) -> diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index ebb2e5c35..bf13d3520 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -114,25 +114,25 @@ features() -> create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> LOwner = jlib:short_prepd_jid(Owner), - {User, Server, _Resource} = LOwner, + {User, Server, Resource} = LOwner, Allowed = case LOwner of {undefined, Host, undefined} -> true; % pubsub service always allowed _ -> - {LU, LS, LR} = LOwner, - case acl:match_rule(ServerHost, Access, exmpp_jid:make_jid(LU, LS, LR)) of + JID = exmpp_jid:make_jid(User, Server, Resource), + case acl:match_rule(ServerHost, Access, JID) of allow -> case Host of {User, Server, _} -> true; _ -> false end; E -> - ?DEBUG("Create not allowed : ~p~n", [E]), - false + ?DEBUG("Create not allowed : ~p~n", [E]), + false end end, {result, Allowed}. - + create_node(Host, Node, Owner) -> case node_default:create_node(Host, Node, Owner) of {result, _} -> {result, []}; From 6482c11f92da0a00537cdc15e5a0e9142d976323 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 27 Feb 2009 15:42:27 +0000 Subject: [PATCH 214/582] * src/tls/tls_drv.c: S2S connection with STARTTLS fails to Gtalk and recent Openfire (thanks to Philipp Hancke)(EJAB-877) SVN Revision: 1926 --- ChangeLog | 3 +++ src/tls/tls_drv.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 9aca027f7..aaa915b62 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2009-02-27 Badlop + * src/tls/tls_drv.c: S2S connection with STARTTLS fails to Gtalk + and recent Openfire (thanks to Philipp Hancke)(EJAB-877) + * doc/guide.tex: No mention to the release date in ejabberd Guide or release notes. The date of an ejabberd release is determined by the date of the corresponding release announcement. diff --git a/src/tls/tls_drv.c b/src/tls/tls_drv.c index 3ca8ba777..e7b07028b 100644 --- a/src/tls/tls_drv.c +++ b/src/tls/tls_drv.c @@ -367,7 +367,7 @@ static int tls_drv_control(ErlDrvData handle, if (command == SET_CERTIFICATE_FILE_ACCEPT) SSL_set_accept_state(d->ssl); else { - SSL_set_options(d->ssl, SSL_OP_NO_SSLv2); + SSL_set_options(d->ssl, SSL_OP_NO_SSLv2|SSL_OP_NO_TICKET); SSL_set_connect_state(d->ssl); } break; From c73e87e9c88ec08752d73e3182609447da710804 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 27 Feb 2009 16:19:19 +0000 Subject: [PATCH 215/582] Merge fix from trunk r1910 * src/web/ejabberd_http.erl: Added a workaround for inet:peername returning 'ebadf' SVN Revision: 1928 --- ChangeLog | 3 +++ src/web/ejabberd_http.erl | 14 +++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index aaa915b62..1a04d8a30 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2009-02-27 Badlop + * src/web/ejabberd_http.erl: Added a workaround for inet:peername + returning 'ebadf' + * src/tls/tls_drv.c: S2S connection with STARTTLS fails to Gtalk and recent Openfire (thanks to Philipp Hancke)(EJAB-877) diff --git a/src/web/ejabberd_http.erl b/src/web/ejabberd_http.erl index 14fa5054f..71895bf3f 100644 --- a/src/web/ejabberd_http.erl +++ b/src/web/ejabberd_http.erl @@ -384,6 +384,13 @@ process_request(#state{request_method = Method, request_headers = RequestHeaders, request_handlers = RequestHandlers} = State) when (Method=:='POST' orelse Method=:='PUT') andalso is_integer(Len) -> + {ok, IP} = + case SockMod of + gen_tcp -> + inet:peername(Socket); + _ -> + SockMod:peername(Socket) + end, case SockMod of gen_tcp -> inet:setopts(Socket, [{packet, 0}]); @@ -403,13 +410,6 @@ process_request(#state{request_method = Method, LQ -> LQ end, - {ok, IP} = - case SockMod of - gen_tcp -> - inet:peername(Socket); - _ -> - SockMod:peername(Socket) - end, Request = #request{method = Method, path = LPath, q = LQuery, From 58e4b98d6112a177f7e44bab89250effa5d7a61f Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Fri, 27 Feb 2009 21:09:44 +0000 Subject: [PATCH 216/582] Fix small bug introduced in revision 1924. SVN Revision: 1929 --- src/mod_pubsub/node_default.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index adf3f1cf3..a326cbf78 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -592,7 +592,7 @@ set_affiliation(Host, Node, Owner, Affiliation) -> %% that will be added to the affiliation stored in the main %% pubsub_state table.

      get_entity_subscriptions(Host, Owner) -> - SubKey = jlib:short_prepd_jid(Owner), + {U, D, _} = SubKey = jlib:short_prepd_jid(Owner), GenKey = jlib:short_prepd_bare_jid(SubKey), States = case SubKey of GenKey -> mnesia:match_object( From 19d27258d92a9d7c396c5a66880288ae7ae816dc Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 27 Feb 2009 23:56:46 +0000 Subject: [PATCH 217/582] * src/mod_pubsub/node_default.erl: Fix that non-subscriber could fetch items from Authorize node (thanks to Brian Cully)(EJAB-873) SVN Revision: 1930 --- ChangeLog | 5 +++++ src/mod_pubsub/node_default.erl | 21 ++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1a04d8a30..183f49bce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-02-28 Badlop + + * src/mod_pubsub/node_default.erl: Fix that non-subscriber could + fetch items from Authorize node (thanks to Brian Cully)(EJAB-873) + 2009-02-27 Badlop * src/web/ejabberd_http.erl: Added a workaround for inet:peername diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index a326cbf78..116160658 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -307,7 +307,7 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel, (AccessModel == whitelist) and (not Whitelisted) -> %% Node has whitelist access model and entity lacks required affiliation {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; - (AccessModel == authorize) -> % TODO: to be done + (AccessModel == authorize) and (not Whitelisted) -> %% Node has authorize access model {error, 'forbidden'}; %%MustPay -> @@ -698,7 +698,8 @@ get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubI GenKey = jlib:short_prepd_bare_jid(JID), GenState = get_state(Host, Node, GenKey), Affiliation = GenState#pubsub_state.affiliation, - Whitelisted = lists:member(Affiliation, [member, publisher, owner]), + Subscription = GenState#pubsub_state.subscription, + Whitelisted = can_fetch_item(Affiliation, Subscription), if %%SubID == "", ?? -> %% Entity has multiple subscriptions to the node but does not specify a subscription ID @@ -745,7 +746,8 @@ get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup GenKey = jlib:short_prepd_bare_jid(JID), GenState = get_state(Host, Node, GenKey), Affiliation = GenState#pubsub_state.affiliation, - Whitelisted = lists:member(Affiliation, [member, publisher, owner]), + Subscription = GenState#pubsub_state.subscription, + Whitelisted = can_fetch_item(Affiliation, Subscription), if %%SubID == "", ?? -> %% Entity has multiple subscriptions to the node but does not specify a subscription ID @@ -799,3 +801,16 @@ del_items(Host, Node, ItemIds) -> %% node id.

      get_item_name(_Host, _Node, Id) -> Id. + +%% @spec (Affiliation, Subscription) -> true | false +%% Affiliation = owner | member | publisher | outcast | none +%% Subscription = subscribed | none +%% @doc Determines if the combination of Affiliation and Subscribed +%% are allowed to get items from a node. +can_fetch_item(owner, _) -> true; +can_fetch_item(member, _) -> true; +can_fetch_item(publisher, _) -> true; +can_fetch_item(outcast, _) -> false; +can_fetch_item(none, subscribed) -> true; +can_fetch_item(none, none) -> false; +can_fetch_item(_Affiliation, _Subscription) -> false. From 3336d66fc459dc325d8b0024ac06c82ed5fd7b45 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Sun, 1 Mar 2009 19:03:35 +0000 Subject: [PATCH 218/582] Host argument for ejabberd_hooks's functions must be in binary() format. SVN Revision: 1932 --- ChangeLog | 5 +++++ src/ejabberd_auth_anonymous.erl | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 183f49bce..73d3abb4f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-03-01 Pablo Polvorin + + * src/ejabberd_auth_anonymous.erl: Host argument for ejabberd_hooks's + functions must be in binary() format. + 2009-02-28 Badlop * src/mod_pubsub/node_default.erl: Fix that non-subscriber could diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index 419398fc2..f625dfd7f 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -65,14 +65,15 @@ %% Register to login / logout events. start(Host) when is_list(Host) -> + HostB = list_to_binary(Host), %% TODO: Check cluster mode mnesia:create_table(anonymous, [{ram_copies, [node()]}, {type, bag}, {attributes, record_info(fields, anonymous)}]), %% The hooks are needed to add / remove users from the anonymous tables - ejabberd_hooks:add(sm_register_connection_hook, Host, + ejabberd_hooks:add(sm_register_connection_hook, HostB, ?MODULE, register_connection, 100), - ejabberd_hooks:add(sm_remove_connection_hook, Host, + ejabberd_hooks:add(sm_remove_connection_hook, HostB, ?MODULE, unregister_connection, 100), ok. From f0d55c9a3faf9d9796fca560065ddbd433c02e02 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Sun, 1 Mar 2009 20:18:42 +0000 Subject: [PATCH 219/582] Fix bug when clients connect using legacy ssl (ejabberd_receiver:process_data/2 was called before initializing the xmlstream). SVN Revision: 1933 --- ChangeLog | 4 ++++ src/ejabberd_receiver.erl | 38 +++++++++++++++++++++----------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 73d3abb4f..724a6ead9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,10 @@ * src/ejabberd_auth_anonymous.erl: Host argument for ejabberd_hooks's functions must be in binary() format. + * src/ejabberd_receiver.erl: Fix bug when clients connect using legacy + ssl (ejabberd_receiver:process_data/2 was called before initializing + the xmlstream). + 2009-02-28 Badlop * src/mod_pubsub/node_default.erl: Fix that non-subscriber could diff --git a/src/ejabberd_receiver.erl b/src/ejabberd_receiver.erl index 95e153554..8d13eb497 100644 --- a/src/ejabberd_receiver.erl +++ b/src/ejabberd_receiver.erl @@ -132,9 +132,8 @@ init([Socket, SockMod, Shaper, MaxStanzaSize]) -> %% {stop, Reason, State} %% Description: Handling call messages %%-------------------------------------------------------------------- -handle_call({starttls, TLSSocket}, _From, - #state{xml_stream_state = XMLStreamState} = State) -> - NewXMLStreamState = do_reset_stream(XMLStreamState), +handle_call({starttls, TLSSocket}, _From, State) -> + NewXMLStreamState = do_reset_stream(State), NewState = State#state{socket = TLSSocket, sock_mod = tls, xml_stream_state = NewXMLStreamState}, @@ -165,17 +164,8 @@ handle_call(reset_stream, _From, {reply, Reply, State#state{xml_stream_state = NewXMLStreamState}, ?HIBERNATE_TIMEOUT}; handle_call({become_controller, C2SPid}, _From, State) -> - Parser = exmpp_xml:start_parser([ - {names_as_atom, true}, - {check_nss, xmpp}, - {check_elems, xmpp}, - {check_attrs, xmpp}, - {max_size, State#state.max_stanza_size} - ]), - XMLStreamState = exmpp_xmlstream:start( - {gen_fsm, C2SPid}, Parser, - [{xmlstreamstart, new}] - ), + close_stream(State#state.xml_stream_state), + XMLStreamState = new_xmlstream(C2SPid, State#state.max_stanza_size), NewState = State#state{c2s_pid = C2SPid, xml_stream_state = XMLStreamState}, activate_socket(NewState), @@ -327,8 +317,22 @@ close_stream(XMLStreamState) -> exmpp_xmlstream:stop(XMLStreamState). -do_reset_stream(undefined) -> - undefined; +do_reset_stream(#state{xml_stream_state = undefined, c2s_pid = C2SPid, max_stanza_size = MaxStanzaSize}) -> + new_xmlstream(C2SPid, MaxStanzaSize); -do_reset_stream(XMLStreamState) -> +do_reset_stream(#state{xml_stream_state = XMLStreamState}) -> exmpp_xmlstream:reset(XMLStreamState). + + +new_xmlstream(C2SPid, MaxStanzaSize) -> + Parser = exmpp_xml:start_parser([ + {names_as_atom, true}, + {check_nss, xmpp}, + {check_elems, xmpp}, + {check_attrs, xmpp}, + {max_size, MaxStanzaSize} + ]), + exmpp_xmlstream:start( + {gen_fsm, C2SPid}, Parser, + [{xmlstreamstart, new}] + ). From 7fea7b30b20dbb2611b93f446cb124f8e3cb0aa4 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Sun, 1 Mar 2009 20:48:43 +0000 Subject: [PATCH 220/582] Elements and namespace for (XEP-0039) aren't know by exmpp ("http://jabber.org/protocol/stats" is represented as a list()) SVN Revision: 1934 --- ChangeLog | 3 +++ src/mod_stats.erl | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 724a6ead9..18b9b53a6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,9 @@ ssl (ejabberd_receiver:process_data/2 was called before initializing the xmlstream). + * src/mod_stats.erl: Elements and namespace for (XEP-0039) aren't know + by exmpp ("http://jabber.org/protocol/stats" is represented as a list()) + 2009-02-28 Badlop * src/mod_pubsub/node_default.erl: Fix that non-subscriber could diff --git a/src/mod_stats.erl b/src/mod_stats.erl index f20e1580f..928b8de47 100644 --- a/src/mod_stats.erl +++ b/src/mod_stats.erl @@ -37,11 +37,11 @@ start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - gen_iq_handler:add_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_STATS, + gen_iq_handler:add_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_STATS_s, ?MODULE, process_local_iq, IQDisc). stop(Host) -> - gen_iq_handler:remove_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_STATS). + gen_iq_handler:remove_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_STATS_s). process_local_iq(_From, To, #iq{type = get, @@ -49,7 +49,7 @@ process_local_iq(_From, To, #iq{type = get, Node = string:tokens(exmpp_xml:get_attribute_as_list(SubEl, 'node', ""), "/"), Names = get_names(exmpp_xml:get_child_elements(SubEl), []), - case get_local_stats(exmpp_jid:domain_as_list(To), Node, Names) of + case get_local_stats(exmpp_jid:domain(To), Node, Names) of {result, Res} -> Result = #xmlel{ns = XMLNS, name = 'query', children = Res}, exmpp_iq:result(IQ_Rec, Result); @@ -62,7 +62,7 @@ process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> get_names([], Res) -> Res; -get_names([#xmlel{name = 'stat', attrs = Attrs} | Els], Res) -> +get_names([#xmlel{name = "stat", attrs = Attrs} | Els], Res) -> Name = exmpp_xml:get_attribute_from_list_as_binary(Attrs, 'name', <<>>), case Name of <<>> -> @@ -74,7 +74,7 @@ get_names([_ | Els], Res) -> get_names(Els, Res). --define(STAT(Name), #xmlel{ns = ?NS_STATS, name = 'stat', attrs = [?XMLATTR('name', Name)]}). +-define(STAT(Name), #xmlel{ns = ?NS_STATS_s, name = 'stat', attrs = [?XMLATTR('name', Name)]}). get_local_stats(_Server, [], []) -> {result, @@ -115,22 +115,22 @@ get_local_stats(_Server, _, _) -> -define(STATVAL(Val, Unit), - #xmlel{ns = ?NS_STATS, name = 'stat', attrs = + #xmlel{ns = ?NS_STATS_s, name = 'stat', attrs = [?XMLATTR('name', Name), ?XMLATTR('units', Unit), ?XMLATTR('value', Val) ]}). -define(STATERR(Code, Desc), - #xmlel{ns = ?NS_STATS, name = 'stat', attrs= + #xmlel{ns = ?NS_STATS_s, name = 'stat', attrs= [?XMLATTR('name', Name)], children = - [#xmlel{ns = ?NS_STATS, name = 'error', attrs = + [#xmlel{ns = ?NS_STATS_s, name = 'error', attrs = [?XMLATTR('code', Code)], children = [#xmlcdata{cdata = Desc}]}]}). get_local_stat(Server, [], Name) when Name == <<"users/online">> -> - case catch ejabberd_sm:get_vh_session_list(list_to_binary(Server)) of + case catch ejabberd_sm:get_vh_session_list(Server) of {'EXIT', _Reason} -> ?STATERR(<<"500">>, <<"Internal Server Error">>); Users -> @@ -139,7 +139,7 @@ get_local_stat(Server, [], Name) when Name == <<"users/online">> -> get_local_stat(Server, [], Name) when Name == <<"users/total">> -> %%LServer = jlib:nameprep(Server), - case catch ejabberd_auth:get_vh_registered_users_number(Server) of + case catch ejabberd_auth:get_vh_registered_users_number(binary_to_list(Server)) of {'EXIT', _Reason} -> ?STATERR(<<"500">>, <<"Internal Server Error">>); NUsers -> From 2c35514537066b3970b449f0fa266a1232ffd508 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Mon, 2 Mar 2009 13:27:35 +0000 Subject: [PATCH 221/582] Correct include declaration (thanks to badlop). Bug was introduced in r1863 SVN Revision: 1935 --- ChangeLog | 5 +++++ src/ejabberd_auth_anonymous.erl | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 18b9b53a6..f814d6116 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-03-02 Pablo Polvorin + + * src/ejabberd_auth_anonymous.erl: Correct include declaration (thanks + to badlop). Bug was introduced in r1863. + 2009-03-01 Pablo Polvorin * src/ejabberd_auth_anonymous.erl: Host argument for ejabberd_hooks's diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index f625dfd7f..195b16570 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -53,7 +53,7 @@ remove_user/3, plain_password_required/0]). --include_lib("exmpp/include/exmpp_xmpp.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). -include("ejabberd.hrl"). -record(anonymous, {us, sid}). From 54a6992ae0b0319edb1b006c6ccec5762e7cf695 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Mon, 2 Mar 2009 15:48:01 +0000 Subject: [PATCH 222/582] Serialize s2s stanzas to iolist() rather than list() SVN Revision: 1936 --- ChangeLog | 3 +++ src/ejabberd_s2s_in.erl | 4 ++-- src/ejabberd_s2s_out.erl | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index f814d6116..a96dc6dad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,9 @@ * src/ejabberd_auth_anonymous.erl: Correct include declaration (thanks to badlop). Bug was introduced in r1863. + * src/ejabberd_s2s_in.erl, src/ejabberd_s2s_out.erl: Serialize stanzas + to iolist(). + 2009-03-01 Pablo Polvorin * src/ejabberd_auth_anonymous.erl: Host argument for ejabberd_hooks's diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index b2bd7fd8e..ea1f3e597 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -554,9 +554,9 @@ send_text(StateData, Text) -> send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> - send_text(StateData, exmpp_stream:to_list(El)); + send_text(StateData, exmpp_stream:to_iolist(El)); send_element(StateData, El) -> - send_text(StateData, exmpp_stanza:to_list(El)). + send_text(StateData, exmpp_stanza:to_iolist(El)). change_shaper(StateData, Host, JID) -> diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 8833309e5..029e3e631 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -799,9 +799,9 @@ send_text(StateData, Text) -> ejabberd_socket:send(StateData#state.socket, Text). send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> - send_text(StateData, exmpp_stream:to_list(El)); + send_text(StateData, exmpp_stream:to_iolist(El)); send_element(StateData, El) -> - send_text(StateData, exmpp_stanza:to_list(El)). + send_text(StateData, exmpp_stanza:to_iolist(El)). send_queue(StateData, Q) -> case queue:out(Q) of From 85412f0a41e60cb03d8b7e01c00eccb233b69d0f Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 18:11:23 +0000 Subject: [PATCH 223/582] Merge from trunk: 1835, 1836, 1842, 1843, 1854, 1858, 1860, 1861, and 1862. * doc/Makefile: In Clean do not remove html. In new Distclean, remove also html. * doc/Makefile: When cleaning, remove contributed_modules.tex * src/Makefile.in: Fix arguments to Install program * doc/guide.tex: Provide only an example of language option * doc/guide.html: Likewise * doc/guide.tex: mod_muc can run in several nodes of cluster * doc/guide.html: Likewise * doc/api/process-one.css: Add some style to HTML elements * src/ejabberd_listener.erl: Fix EDoc errors * src/web/ejabberd_web_admin.erl: Likewise * src/ejabberd_hooks.erl: Explanation in EDoc of some functions * doc/guide.tex: Explain that account creation is only supported by internal and odbc authentication methods * doc/guide.html: Likewise * src/Makefile.in: The path to the installed copy of ejabberd Guide is set in the environment variable EJABBERD_DOC_PATH (EJAB-837). * src/web/ejabberd_web_admin.erl: Likewise * src/ejabberdctl.template: Likewise * doc/guide.tex: Likewise * doc/guide.html: Likewise SVN Revision: 1937 --- ChangeLog | 36 +++++++++++++++++++++++++++++++- doc/Makefile | 5 ++++- doc/api/process-one.css | 14 ++++++++++++- doc/guide.html | 38 +++++++++++++++------------------- doc/guide.tex | 31 ++++++++++++--------------- src/Makefile.in | 3 ++- src/ejabberd_hooks.erl | 18 +++++++++++++--- src/ejabberdctl.template | 4 ++++ src/web/ejabberd_web_admin.erl | 16 +++++++------- 9 files changed, 111 insertions(+), 54 deletions(-) diff --git a/ChangeLog b/ChangeLog index a96dc6dad..688f4deba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,41 @@ +2009-03-03 Badlop + + * doc/Makefile: In Clean do not remove html. In new Distclean, + remove also html. + + * doc/Makefile: When cleaning, remove contributed_modules.tex + + * src/Makefile.in: Fix arguments to Install program + + * doc/guide.tex: Provide only an example of language option + * doc/guide.html: Likewise + + * doc/guide.tex: mod_muc can run in several nodes of cluster + * doc/guide.html: Likewise + + * doc/api/process-one.css: Add some style to HTML elements + + * src/ejabberd_listener.erl: Fix EDoc errors + * src/web/ejabberd_web_admin.erl: Likewise + + * src/ejabberd_hooks.erl: Explanation in EDoc of some functions + + * doc/guide.tex: Explain that account creation is only supported + by internal and odbc authentication methods + * doc/guide.html: Likewise + + * src/Makefile.in: The path to the installed copy of ejabberd + Guide is set in the environment variable + EJABBERD_DOC_PATH (EJAB-837). + * src/web/ejabberd_web_admin.erl: Likewise + * src/ejabberdctl.template: Likewise + * doc/guide.tex: Likewise + * doc/guide.html: Likewise + 2009-03-02 Pablo Polvorin * src/ejabberd_auth_anonymous.erl: Correct include declaration (thanks - to badlop). Bug was introduced in r1863. + to Badlop). Bug was introduced in r1863. * src/ejabberd_s2s_in.erl, src/ejabberd_s2s_out.erl: Serialize stanzas to iolist(). diff --git a/doc/Makefile b/doc/Makefile index 2fda395a0..3cc89b059 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -32,7 +32,6 @@ pdf: guide.pdf features.pdf clean: rm -f *.aux rm -f *.haux - rm -f *.html rm -f *.htoc rm -f *.idx rm -f *.ilg @@ -41,6 +40,10 @@ clean: rm -f *.out rm -f *.pdf rm -f *.toc + [ ! -f contributed_modules.tex ] || rm contributed_modules.tex + +distclean: clean + rm -f *.html guide.html: guide.tex hevea -fix -pedantic guide.tex diff --git a/doc/api/process-one.css b/doc/api/process-one.css index 793d717aa..5cd371e10 100644 --- a/doc/api/process-one.css +++ b/doc/api/process-one.css @@ -71,10 +71,22 @@ pre, tt, code { } pre { - margin-left: 1em; + margin:1ex 2ex; + border:1px dashed lightgrey; + background-color:#f9f9f9; + padding:0.5ex; } pre em { font-style: normal; font-weight: bold; } + +dt { + margin:0ex 2ex; + font-weight:bold; +} + +dd { + margin:0ex 0ex 1ex 4ex; +} diff --git a/doc/guide.html b/doc/guide.html index 3282fc3d8..645ae6d5c 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -476,7 +476,7 @@ variable.

    • Install OpenSSL in C:\sdk\OpenSSL and add C:\sdk\OpenSSL\lib\VC to your path or copy the binaries to your system directory.
    • Install ZLib in C:\sdk\gnuWin32. Copy C:\sdk\GnuWin32\bin\zlib1.dll to your system directory. If you change your path it should already be set after libiconv install. -
    • Make sure the you can access Erlang binaries from your path. For example: set PATH=%PATH%;"C:\sdk\erl5.5.5\bin" +
    • Make sure the you can access Erlang binaries from your path. For example: set PATH=%PATH%;"C:\sdk\erl5.6.5\bin"
    • Depending on how you end up actually installing the library you might need to check and tweak the paths in the file configure.erl.
    • While in the directory ejabberd\src run:
      configure.bat
      @@ -914,8 +914,8 @@ connected to port 5237 with password ‘ggsecret’.
       {s2s_default_policy, deny}.
       {{s2s_host,"jabber.example.org"}, allow}.
       {{s2s_host,"example.com"}, allow}.
      -

      Note, that for jabberd 1.4- or WPJabber-based -services you have to make the transports log and do XDB by themselves: +

      Note, that for services based in jabberd14 or WPJabber +you have to make the transports log and do XDB by themselves:

        <!--
            You have to add elogger and rlogger entries here when using ejabberd.
            In this case the transport will do the logging.
      @@ -937,7 +937,7 @@ services you have to make the transports log and do XDB by themselves:
         <xdb id="xdb">
           <host/>
           <load>
      -      <!-- this is a lib of wpjabber or jabberd -->
      +      <!-- this is a lib of wpjabber or jabberd14 -->
             <xdb_file>/usr/lib/jabber/xdb_file.so</xdb_file>
             </load>
           <xdb_file xmlns="jabber:config:xdb_file">
      @@ -959,7 +959,7 @@ example authentication scripts.
       3.2.2 and 3.2.4.
       
    • anonymous — See section 3.1.4.
    • pam — See section 3.1.4. -
    • +

      Account creation is only supported by internal and odbc methods.

      Internal

      ejabberd uses its internal Mnesia database as the default authentication method.

      • auth_method: The value internal will enable the internal @@ -1193,13 +1193,9 @@ To define a shaper named ‘normal’ with traffic speed limi can be seen by Jabber clients. If a Jabber client does not support xml:lang, the specified language is used. The default value is en. In order to take effect there must be a translation file -<language>.msg in ejabberd’s msgs directory.

        Examples: -

        • -To set Russian as default language: -
          {language, "ru"}.
          -
        • To set Spanish as default language: -
          {language, "es"}.
          -

        Appendix A provides more details about internationalization and localization.

        +<language>.msg in ejabberd’s msgs directory.

        For example, to set Russian as default language: +

        {language, "ru"}.
        +

        Appendix A provides more details about internationalization and localization.

        3.1.8  Include Additional Configuration Files

        The option include_config_file in a configuration file instructs ejabberd to include other configuration files immediately.

        The basic usage is:

        {include_config_file, <filename>}.
        @@ -3019,6 +3015,8 @@ all the environment variables and command line parameters.

        The environment Path to the ejabberd service log file.

        EJABBERD_SO_PATH
        Path to the directory with binary system libraries. +
        EJABBERD_DOC_PATH
        + Path to the directory with ejabberd documentation.
        HOME
        Path to the directory that is considered ejabberd’s home. This path is used to read the file .erlang.cookie. @@ -3140,10 +3138,8 @@ be installed in the system. The file is searched by default in "/share/doc/ejabberd/guide.html". The directory of the documentation can be specified in -ejabberd.cfg with the option doc_path. -For example: -

        {doc_path, "/usr/local/share/doc/ejabberd/"}.
        -

        +the environment variable EJABBERD_DOC_PATH. +See section 4.1.2.

        4.3  Ad-hoc Commands

        If you enable mod_configure and mod_adhoc, you can perform several administrative tasks in ejabberd with a Jabber client. @@ -3315,11 +3311,11 @@ Writing, on the other hand, will be slower. And of course if machine with one of the replicas is down, other replicas will be used.

        Also section 5.3 (Table Fragmentation) of Mnesia User’s Guide can be helpful.

        (alt) Same as in previous item, but for other tables.

      • Run ‘init:stop().’ or just ‘q().’ to exit from the Erlang shell. This probably can take some time if Mnesia has not yet -transfered and processed all data it needed from first.
      • Now run ejabberd on second with almost the same config as -on first (you probably do not need to duplicate ‘acl’ -and ‘access’ options — they will be taken from -first, and mod_muc and mod_irc should be -enabled only on one machine in the cluster). +transfered and processed all data it needed from first.
      • Now run ejabberd on second with a configuration similar as +on first: you probably do not need to duplicate ‘acl’ +and ‘access’ options because they will be taken from +first; and mod_irc should be +enabled only on one machine in the cluster.
      • You can repeat these steps for other machines supposed to serve this domain.

        6.3  Service Load-Balancing

        diff --git a/doc/guide.tex b/doc/guide.tex index 2e4c60531..a84f24954 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -1118,6 +1118,8 @@ The following authentication methods are supported by \ejabberd{}: \item pam --- See section~\ref{pam}. \end{itemize} +Account creation is only supported by internal and odbc methods. + \makesubsubsection{internalauth}{Internal} \ind{internal authentication}\ind{Mnesia} @@ -1481,17 +1483,10 @@ can be seen by \Jabber{} clients. If a \Jabber{} client does not support \term{en}. In order to take effect there must be a translation file \term{.msg} in \ejabberd{}'s \term{msgs} directory. -Examples: -\begin{itemize} -\item To set Russian as default language: +For example, to set Russian as default language: \begin{verbatim} {language, "ru"}. \end{verbatim} -\item To set Spanish as default language: -\begin{verbatim} -{language, "es"}. -\end{verbatim} -\end{itemize} Appendix \ref{i18ni10n} provides more details about internationalization and localization. @@ -3891,6 +3886,8 @@ The environment variables: Path to the ejabberd service log file. \titem{EJABBERD\_SO\_PATH} Path to the directory with binary system libraries. + \titem{EJABBERD\_DOC\_PATH} + Path to the directory with ejabberd documentation. \titem{HOME} Path to the directory that is considered \ejabberd{}'s home. This path is used to read the file \term{.erlang.cookie}. @@ -4027,11 +4024,9 @@ be installed in the system. The file is searched by default in \term{"/share/doc/ejabberd/guide.html"}. The directory of the documentation can be specified in -\term{ejabberd.cfg} with the option \term{doc\_path}. -For example: -\begin{verbatim} -{doc_path, "/usr/local/share/doc/ejabberd/"}. -\end{verbatim} +the environment variable \term{EJABBERD\_DOC\_PATH}. +See section \ref{erlangconfiguration}. + \makesection{adhoccommands}{Ad-hoc Commands} @@ -4320,11 +4315,11 @@ mnesia:change_table_copy_type(schema, node(), disc_copies). transfered and processed all data it needed from \term{first}. -\item Now run \ejabberd{} on \term{second} with almost the same config as - on \term{first} (you probably do not need to duplicate `\verb|acl|' - and `\verb|access|' options --- they will be taken from - \term{first}, and \verb|mod_muc| and \verb|mod_irc| should be - enabled only on one machine in the cluster). +\item Now run \ejabberd{} on \term{second} with a configuration similar as + on \term{first}: you probably do not need to duplicate `\verb|acl|' + and `\verb|access|' options because they will be taken from + \term{first}; and \verb|mod_irc| should be + enabled only on one machine in the cluster. \end{enumerate} You can repeat these steps for other machines supposed to serve this diff --git a/src/Makefile.in b/src/Makefile.in index 8917df636..ac9412a17 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -172,6 +172,7 @@ install: all -e "s*@LIBDIR@*@libdir@*" \ -e "s*@SYSCONFDIR@*@sysconfdir@*" \ -e "s*@LOCALSTATEDIR@*@localstatedir@*" \ + -e "s*@DOCDIR@*@docdir@*" \ -e "s*@erl@*@ERL@*" ejabberdctl.template \ > ejabberdctl.example [ -f $(ETCDIR)/ejabberdctl.cfg ] \ @@ -180,7 +181,7 @@ install: all install -b -m 644 $(G_USER) inetrc $(ETCDIR)/inetrc # # Administration script - [ -d $(SBINDIR) ] || install -d 750 $(SBINDIR) + [ -d $(SBINDIR) ] || install -d -m 750 $(SBINDIR) install -m 550 $(G_USER) ejabberdctl.example $(SBINDIR)/ejabberdctl # # Binary Erlang files diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl index e506aea89..22dc49eba 100644 --- a/src/ejabberd_hooks.erl +++ b/src/ejabberd_hooks.erl @@ -58,6 +58,9 @@ start_link() -> gen_server:start_link({local, ejabberd_hooks}, ejabberd_hooks, [], []). +%% @spec (Hook::atom(), Module::atom(), Function::atom(), Seq::integer()) -> ok +%% @doc Add a module and function to this hook. +%% The integer sequence is used to sort the calls: low number is called before high number. add(Hook, Module, Function, Seq) -> add(Hook, global, Module, Function, Seq). @@ -65,6 +68,9 @@ add(Hook, Host, Module, Function, Seq) when is_binary(Host) orelse is_atom(Host) -> gen_server:call(ejabberd_hooks, {add, Hook, Host, Module, Function, Seq}). +%% @spec (Hook::atom(), Module::atom(), Function::atom(), Seq::integer()) -> ok +%% @doc Delete a module and function from this hook. +%% It is important to indicate exactly the same information than when the call was added. delete(Hook, Module, Function, Seq) -> delete(Hook, global, Module, Function, Seq). @@ -72,6 +78,9 @@ delete(Hook, Host, Module, Function, Seq) when is_binary(Host) orelse is_atom(Host) -> gen_server:call(ejabberd_hooks, {delete, Hook, Host, Module, Function, Seq}). +%% @spec (Hook::atom(), Args) -> ok +%% @doc Run the calls of this hook in order, don't care about function results. +%% If a call returns stop, no more calls are performed. run(Hook, Args) -> run(Hook, global, Args). @@ -83,6 +92,12 @@ run(Hook, Host, Args) when is_binary(Host) orelse is_atom(Host) -> ok end. +%% @spec (Hook::atom(), Val, Args) -> Val | stopped | NewVal +%% @doc Run the calls of this hook in order. +%% The arguments passed to the function are: [Val | Args]. +%% The result of a call is used as Val for the next call. +%% If a call returns 'stop', no more calls are performed and 'stopped' is returned. +%% If a call returns {stopped, NewVal}, no more calls are performed and NewVal is returned. run_fold(Hook, Val, Args) -> run_fold(Hook, global, Val, Args). @@ -214,6 +229,3 @@ run_fold1([{_Seq, Module, Function} | Ls], Hook, Val, Args) -> NewVal -> run_fold1(Ls, Hook, NewVal, Args) end. - - - diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template index b71531c19..32a31d105 100644 --- a/src/ejabberdctl.template +++ b/src/ejabberdctl.template @@ -48,6 +48,9 @@ fi if [ "$SPOOLDIR" = "" ] ; then SPOOLDIR=@LOCALSTATEDIR@/lib/ejabberd fi +if [ "$EJABBERD_DOC_PATH" = "" ] ; then + EJABBERD_DOC_PATH=@DOCDIR@ +fi # check the proper system user is used ID=`id -g` @@ -99,6 +102,7 @@ export EJABBERD_MSGS_PATH export EJABBERD_LOG_PATH export EJABBERD_SO_PATH export EJABBERD_BIN_PATH +export EJABBERD_DOC_PATH export ERL_CRASH_DUMP export ERL_INETRC export ERL_MAX_PORTS diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index fe5ea042c..1182c2a9f 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -41,9 +41,9 @@ process(["doc", LocalFile], _Request) -> - DocPath = case ejabberd_config:get_global_option(doc_path) of + DocPath = case os:getenv("EJABBERD_DOC_PATH") of P when is_list(P) -> P; - _ -> "/share/doc/ejabberd/" + false -> "/share/doc/ejabberd/" end, %% Code based in mod_http_fileserver FileName = filename:join(DocPath, LocalFile), @@ -55,8 +55,8 @@ process(["doc", LocalFile], _Request) -> FileContents}; {error, Error} -> ?DEBUG("Delivering error: ~p", [Error]), - Help = " " ++ FileName ++ " - Try to specify the path to ejabberd guide.html " - "with the option doc_path. Check the ejabberd Guide for more information", + Help = " " ++ FileName ++ " - Try to specify the path to ejabberd documentation " + "with the environment variable EJABBERD_DOC_PATH. Check the ejabberd Guide for more information.", case Error of eacces -> {403, [], "Forbidden"++Help}; enoent -> {404, [], "Not found"++Help}; @@ -1071,10 +1071,10 @@ term_to_string(T) -> %% @spec (T::any(), Cols::integer()) -> {NumLines::integer(), Paragraph::string()} term_to_paragraph(T, Cols) -> - Paragraph = erl_prettypr:format(erl_syntax:abstract(T), [{paper, Cols}]), - {ok, FieldList} = regexp:split(Paragraph, "\n"), - NumLines = length(FieldList), - {NumLines, Paragraph}. + Paragraph = erl_prettypr:format(erl_syntax:abstract(T), [{paper, Cols}]), + {ok, FieldList} = regexp:split(Paragraph, "\n"), + NumLines = length(FieldList), + {NumLines, Paragraph}. term_to_id(T) -> jlib:encode_base64(binary_to_list(term_to_binary(T))). From 77ff6573514664769bdd4abff2557d3d5cefa23a Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 18:24:42 +0000 Subject: [PATCH 224/582] Merge 1859 from trunk. * src/web/ejabberd_web_admin.erl: Calls to the hook webadmin_menu_node provide the node as first argument, and calls to webadmin_menu_hostnode provide both the host and the node. Fix call to make_menu_items, because webadmin_menu_node was called in cases where webadmin_menu_hostnode should be called. Align to right some table elements. SVN Revision: 1938 --- ChangeLog | 19 +++++++++++++------ src/web/ejabberd_web_admin.erl | 23 ++++++++++++----------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 688f4deba..2395362a5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2009-03-03 Badlop + * src/web/ejabberd_web_admin.erl: Calls to the hook + webadmin_menu_node provide the node as first argument, and calls + to webadmin_menu_hostnode provide both the host and the node. Fix + call to make_menu_items, because webadmin_menu_node was called in + cases where webadmin_menu_hostnode should be called. Align to + right some table elements. + * doc/Makefile: In Clean do not remove html. In new Distclean, remove also html. @@ -8,21 +15,21 @@ * src/Makefile.in: Fix arguments to Install program * doc/guide.tex: Provide only an example of language option - * doc/guide.html: Likewise + * doc/guide.html: Likewise * doc/guide.tex: mod_muc can run in several nodes of cluster - * doc/guide.html: Likewise + * doc/guide.html: Likewise * doc/api/process-one.css: Add some style to HTML elements - * src/ejabberd_listener.erl: Fix EDoc errors - * src/web/ejabberd_web_admin.erl: Likewise + * src/ejabberd_listener.erl: Fix EDoc errors + * src/web/ejabberd_web_admin.erl: Likewise * src/ejabberd_hooks.erl: Explanation in EDoc of some functions * doc/guide.tex: Explain that account creation is only supported - by internal and odbc authentication methods - * doc/guide.html: Likewise + by internal and odbc authentication methods + * doc/guide.html: Likewise * src/Makefile.in: The path to the installed copy of ejabberd Guide is set in the environment variable diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 1182c2a9f..7092697a4 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -556,6 +556,7 @@ p.result { *.alignright { font-size: 10pt; + text-align: right; } ". @@ -1724,7 +1725,7 @@ get_node(global, Node, [], Query, Lang) -> get_node(Host, Node, [], _Query, Lang) -> Base = get_base_path(Host, Node), - MenuItems2 = make_menu_items(global, Node, Base, Lang), + MenuItems2 = make_menu_items(Host, Node, Base, Lang), [?XC('h1', ?T("Node ") ++ atom_to_list(Node)), ?XE('ul', [?LI([?ACT(Base ++ "modules/", "Modules")])] ++ MenuItems2) @@ -2345,16 +2346,16 @@ make_menu_items(global, cluster, Base, Lang) -> HookItems = get_menu_items_hook(server, Lang), make_menu_items(Lang, {Base, "", HookItems}); -make_menu_items(global, _Node, Base, Lang) -> - HookItems = get_menu_items_hook(node, Lang), +make_menu_items(global, Node, Base, Lang) -> + HookItems = get_menu_items_hook({node, Node}, Lang), make_menu_items(Lang, {Base, "", HookItems}); make_menu_items(Host, cluster, Base, Lang) -> HookItems = get_menu_items_hook({host, Host}, Lang), make_menu_items(Lang, {Base, "", HookItems}); -make_menu_items(Host, _Node, Base, Lang) -> - HookItems = get_menu_items_hook({hostnode, Host}, Lang), +make_menu_items(Host, Node, Base, Lang) -> + HookItems = get_menu_items_hook({hostnode, Host, Node}, Lang), make_menu_items(Lang, {Base, "", HookItems}). @@ -2365,7 +2366,7 @@ make_host_node_menu(_, cluster, _Lang) -> make_host_node_menu(Host, Node, Lang) -> HostNodeBase = get_base_path(Host, Node), HostNodeFixed = [{"modules/", "Modules"}], - HostNodeHook = get_menu_items_hook({hostnode, Host}, Lang), + HostNodeHook = get_menu_items_hook({hostnode, Host, Node}, Lang), {HostNodeBase, atom_to_list(Node), HostNodeFixed ++ HostNodeHook}. make_host_menu(global, _HostNodeMenu, _Lang) -> @@ -2391,7 +2392,7 @@ make_node_menu(global, Node, Lang) -> {"ports/", "Listened Ports"}, {"stats/", "Statistics"}, {"update/", "Update"}], - NodeHook = get_menu_items_hook(node, Lang), + NodeHook = get_menu_items_hook({node, Node}, Lang), {NodeBase, atom_to_list(Node), NodeFixed ++ NodeHook}; make_node_menu(_Host, _Node, _Lang) -> {"", "", []}. @@ -2407,12 +2408,12 @@ make_server_menu(HostMenu, NodeMenu, Lang) -> {Base, "ejabberd", Fixed ++ Hook}. -get_menu_items_hook({hostnode, Host}, Lang) -> - ejabberd_hooks:run_fold(webadmin_menu_hostnode, list_to_binary(Host), [], [Host, Lang]); +get_menu_items_hook({hostnode, Host, Node}, Lang) -> + ejabberd_hooks:run_fold(webadmin_menu_hostnode, list_to_binary(Host), [], [Host, Node, Lang]); get_menu_items_hook({host, Host}, Lang) -> ejabberd_hooks:run_fold(webadmin_menu_host, list_to_binary(Host), [], [Host, Lang]); -get_menu_items_hook(node, Lang) -> - ejabberd_hooks:run_fold(webadmin_menu_node, [], [Lang]); +get_menu_items_hook({node, Node}, Lang) -> + ejabberd_hooks:run_fold(webadmin_menu_node, [], [Node, Lang]); get_menu_items_hook(server, Lang) -> ejabberd_hooks:run_fold(webadmin_menu_main, [], [Lang]). From 79463d7f7d7ecaf35197bcc26ca8b42c1bf06c6c Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 18:29:53 +0000 Subject: [PATCH 225/582] Merge 1873 from trunk. * src/web/ejabberd_web_admin.erl: Show big integers with comma separators for easy reading SVN Revision: 1939 --- ChangeLog | 3 +++ src/web/ejabberd_web_admin.erl | 49 +++++++++++++++++++++------------- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2395362a5..e489f3d61 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2009-03-03 Badlop + * src/web/ejabberd_web_admin.erl: Show big integers with comma + separators for easy reading + * src/web/ejabberd_web_admin.erl: Calls to the hook webadmin_menu_node provide the node as first argument, and calls to webadmin_menu_hostnode provide both the host and the node. Fix diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 7092697a4..61664d2ce 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -1297,8 +1297,8 @@ list_vhosts(Lang) -> ejabberd_auth:get_vh_registered_users_number(Host), ?XE('tr', [?XE('td', [?AC("../server/" ++ Host ++ "/", Host)]), - ?XC('td', integer_to_list(RegisteredUsers)), - ?XC('td', integer_to_list(OnlineUsers)) + ?XC('td', pretty_string_int(RegisteredUsers)), + ?XC('td', pretty_string_int(OnlineUsers)) ]) end, SHosts) )])]. @@ -1408,11 +1408,10 @@ list_given_users(Users, Prefix, Lang, URLFunc) -> QueueLen = length(mnesia:dirty_read({offline_msg, US})), [?AC(URLFunc({users_queue, Prefix, User, Server}), - integer_to_list(QueueLen))] + pretty_string_int(QueueLen))] catch _:_ -> [#xmlcdata{cdata = <<"Can't access the offline messages storage.">>}] end, - FLast = case ejabberd_sm:get_user_resources(UserB, ServerB) of [] -> @@ -1461,13 +1460,13 @@ get_stats(global, Lang) -> [?XAE('table', [], [?XE('tbody', [?XE('tr', [?XCT('td', "Registered Users:"), - ?XC('td', integer_to_list(RegisteredUsers))]), + ?XC('td', pretty_string_int(RegisteredUsers))]), ?XE('tr', [?XCT('td', "Online Users:"), - ?XC('td', integer_to_list(OnlineUsers))]), + ?XC('td', pretty_string_int(OnlineUsers))]), ?XE('tr', [?XCT('td', "Outgoing s2s Connections:"), - ?XC('td', integer_to_list(S2SConnections))]), + ?XC('td', pretty_string_int(S2SConnections))]), ?XE('tr', [?XCT('td', "Outgoing s2s Servers:"), - ?XC('td', integer_to_list(S2SServers))]) + ?XC('td', pretty_string_int(S2SServers))]) ]) ])]; @@ -1477,9 +1476,9 @@ get_stats(Host, Lang) -> [?XAE('table', [], [?XE('tbody', [?XE('tr', [?XCT('td', "Registered Users:"), - ?XC('td', integer_to_list(RegisteredUsers))]), + ?XC('td', pretty_string_int(RegisteredUsers))]), ?XE('tr', [?XCT('td', "Online Users:"), - ?XC('td', integer_to_list(OnlineUsers))]) + ?XC('td', pretty_string_int(OnlineUsers))]) ]) ])]. @@ -1626,7 +1625,7 @@ list_last_activity(Host, Lang, Integral, Period) -> [?XMLATTR('style', "width:" ++ integer_to_list( trunc(90 * V / Max)) ++ "%;")], - [#xmlcdata{cdata = list_to_binary(integer_to_list(V))}]) + [#xmlcdata{cdata = list_to_binary(pretty_string_int(V))}]) || V <- Hist ++ Tail])] end end. @@ -1770,9 +1769,9 @@ get_node(global, Node, ["db"], Query, Lang) -> ?XE('td', [db_storage_select( STable, Type, Lang)]), ?XAC('td', [?XMLATTR('class', <<"alignright">>)], - integer_to_list(Size)), + pretty_string_int(Size)), ?XAC('td', [?XMLATTR('class', <<"alignright">>)], - integer_to_list(Memory)) + pretty_string_int(Memory)) ]) end, STables), [?XC('h1', ?T("Database Tables at ") ++ atom_to_list(Node))] ++ @@ -1927,19 +1926,19 @@ get_node(global, Node, ["stats"], _Query, Lang) -> CPUTimeS)]), ?XE('tr', [?XCT('td', "Online Users:"), ?XAC('td', [?XMLATTR('class', <<"alignright">>)], - integer_to_list(OnlineUsers))]), + pretty_string_int(OnlineUsers))]), ?XE('tr', [?XCT('td', "Transactions Committed:"), ?XAC('td', [?XMLATTR('class', <<"alignright">>)], - integer_to_list(TransactionsCommitted))]), + pretty_string_int(TransactionsCommitted))]), ?XE('tr', [?XCT('td', "Transactions Aborted:"), ?XAC('td', [?XMLATTR('class', <<"alignright">>)], - integer_to_list(TransactionsAborted))]), + pretty_string_int(TransactionsAborted))]), ?XE('tr', [?XCT('td', "Transactions Restarted:"), ?XAC('td', [?XMLATTR('class', <<"alignright">>)], - integer_to_list(TransactionsRestarted))]), + pretty_string_int(TransactionsRestarted))]), ?XE('tr', [?XCT('td', "Transactions Logged:"), ?XAC('td', [?XMLATTR('class', <<"alignright">>)], - integer_to_list(TransactionsLogged))]) + pretty_string_int(TransactionsLogged))]) ]) ])]; @@ -2328,6 +2327,20 @@ last_modified() -> cache_control_public() -> {"Cache-Control", "public"}. +%% Transform 1234567890 into "1,234,567,890" +pretty_string_int(Integer) when is_integer(Integer) -> + pretty_string_int(integer_to_list(Integer)); +pretty_string_int(String) when is_list(String) -> + {_, Result} = lists:foldl( + fun(NewNumber, {3, Result}) -> + {1, [NewNumber, $, | Result]}; + (NewNumber, {CountAcc, Result}) -> + {CountAcc+1, [NewNumber | Result]} + end, + {0, ""}, + lists:reverse(String)), + Result. + %%% %%% Navigation Menu From c13ed8c6252f44255e494e511aab7ea881b71e89 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 18:45:26 +0000 Subject: [PATCH 226/582] Merge 1872 from trunk. * src/ejabberd_system_monitor.erl: Allow parametrizable watchdog threshold: option watchdog_large_heap or chatting with the watchdog bot (EJAB-545) * src/ejabberd_config.erl: Likewise * doc/guide.tex: Likewise * doc/guide.html: Likewise SVN Revision: 1940 --- ChangeLog | 7 +++++ doc/guide.html | 12 +++++---- doc/guide.tex | 14 +++++++--- src/ejabberd_config.erl | 2 ++ src/ejabberd_system_monitor.erl | 47 +++++++++++++++++++++++++++++---- 5 files changed, 68 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index e489f3d61..b6e5084c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2009-03-03 Badlop + * src/ejabberd_system_monitor.erl: Allow parametrizable watchdog + threshold: option watchdog_large_heap or chatting with the + watchdog bot (EJAB-545) + * src/ejabberd_config.erl: Likewise + * doc/guide.tex: Likewise + * doc/guide.html: Likewise + * src/web/ejabberd_web_admin.erl: Show big integers with comma separators for easy reading diff --git a/doc/guide.html b/doc/guide.html index 645ae6d5c..55ce1dc69 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -3366,14 +3366,16 @@ There are some simple and safe examples in the article

        7.3  Watchdog Alerts

        ejabberd includes a watchdog mechanism that may be useful to developers when troubleshooting a problem related to memory usage. -If a process in the ejabberd server consumes a lot of memory, +If a process in the ejabberd server consumes more memory than the configured threshold, a message is sent to the Jabber accounts defined with the option watchdog_admins - in the ejabberd configuration file. -Note that the threshold to define what is too much memory usage -is only configurable editing the source code. -Example configuration: + in the ejabberd configuration file.

        The memory consumed is measured in words: +a word on 32-bit architecture is 4 bytes, and a word on 64-bit architecture 8 bytes. +The threshold by default is 1000000 words. +This value can be configured with the option watchdog_large_heap, +or in a conversation with the watchdog alert bot.

        Example configuration:

        {watchdog_admins, ["admin2@localhost", "admin2@example.org"]}.
        +{watchdog_large_heap, 30000000}.
         

        To remove watchdog admins, remove them in the option. To remove all watchdog admins, set the option with an empty list:

        {watchdog_admins, []}.
        diff --git a/doc/guide.tex b/doc/guide.tex
        index a84f24954..ac054dab6 100644
        --- a/doc/guide.tex
        +++ b/doc/guide.tex
        @@ -4425,15 +4425,22 @@ To exit the shell, close the window or press the keys: control+c control+c.
         
         \ejabberd{} includes a watchdog mechanism that may be useful to developers
         when troubleshooting a problem related to memory usage.
        -If a process in the \ejabberd{} server consumes a lot of memory,
        +If a process in the \ejabberd{} server consumes more memory than the configured threshold,
         a message is sent to the Jabber accounts defined with the option
         \term{watchdog\_admins}
         \ind{options!watchdog\_admins} in the \ejabberd{} configuration file.
        -Note that the threshold to define what is too much memory usage 
        -is only configurable editing the source code.
        +
        +The memory consumed is measured in \term{words}:
        +a word on 32-bit architecture is 4 bytes,
        +and a word on 64-bit architecture is 8 bytes.
        +The threshold by default is 1000000 words.
        +This value can be configured with the option \term{watchdog\_large\_heap},
        +or in a conversation with the watchdog alert bot.
        +
         Example configuration:
         \begin{verbatim}
         {watchdog_admins, ["admin2@localhost", "admin2@example.org"]}.
        +{watchdog_large_heap, 30000000}.
         \end{verbatim}
         
         To remove watchdog admins, remove them in the option.
        @@ -4442,7 +4449,6 @@ To remove all watchdog admins, set the option with an empty list:
         {watchdog_admins, []}.
         \end{verbatim}
         
        -
         \appendix{}
         
         \makechapter{i18ni10n}{Internationalization and Localization}
        diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl
        index 9b9af443f..6f804be21 100644
        --- a/src/ejabberd_config.erl
        +++ b/src/ejabberd_config.erl
        @@ -357,6 +357,8 @@ process_term(Term, State) ->
         	    add_option({domain_balancing_component_number, Domain}, N, State);
         	{watchdog_admins, Admins} ->
         	    add_option(watchdog_admins, Admins, State);
        +	{watchdog_large_heap, LH} ->
        +	    add_option(watchdog_large_heap, LH, State);
         	{registration_timeout, Timeout} ->
         	    add_option(registration_timeout, Timeout, State);
         	{loglevel, Loglevel} ->
        diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl
        index f4e8c3774..6d5a03b81 100644
        --- a/src/ejabberd_system_monitor.erl
        +++ b/src/ejabberd_system_monitor.erl
        @@ -52,7 +52,12 @@
         %% Description: Starts the server
         %%--------------------------------------------------------------------
         start_link() ->
        -    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
        +    LH = case ejabberd_config:get_local_option(watchdog_large_heap) of
        +	I when is_integer(I) -> I;
        +	_ -> 1000000
        +end,
        +    Opts = [{large_heap, LH}],
        +    gen_server:start_link({local, ?MODULE}, ?MODULE, Opts, []).
         
         process_command(From, To, Packet) ->
             case {exmpp_jid:lnode(To), exmpp_jid:lresource(To) } of
        @@ -91,9 +96,10 @@ process_command(From, To, Packet) ->
         %%                         {stop, Reason}
         %% Description: Initiates the server
         %%--------------------------------------------------------------------
        -init([]) ->
        +init(Opts) ->
        +    LH = proplists:get_value(large_heap, Opts),
             process_flag(priority, high),
        -    erlang:system_monitor(self(), [{large_heap, 1000000}]),
        +    erlang:system_monitor(self(), [{large_heap, LH}]),
             lists:foreach(
               fun(Host) ->
         	      ejabberd_hooks:add(local_send_to_resource_hook, 
        @@ -111,10 +117,24 @@ init([]) ->
         %%                                      {stop, Reason, State}
         %% Description: Handling call messages
         %%--------------------------------------------------------------------
        +handle_call({get, large_heap}, _From, State) ->
        +    {reply, get_large_heap(), State};
        +handle_call({set, large_heap, NewValue}, _From, State) ->
        +    MonSettings = erlang:system_monitor(self(), [{large_heap, NewValue}]),
        +    OldLH = get_large_heap(MonSettings),
        +    NewLH = get_large_heap(),
        +    {reply, {lh_changed, OldLH, NewLH}, State};
         handle_call(_Request, _From, State) ->
             Reply = ok,
             {reply, Reply, State}.
         
        +get_large_heap() ->
        +    MonSettings = erlang:system_monitor(),
        +    get_large_heap(MonSettings).
        +get_large_heap(MonSettings) ->
        +    {_MonitorPid, Options} = MonSettings,
        +    proplists:get_value(large_heap, Options).
        +
         %%--------------------------------------------------------------------
         %% Function: handle_cast(Msg, State) -> {noreply, State} |
         %%                                      {noreply, State, Timeout} |
        @@ -167,7 +187,7 @@ process_large_heap(Pid, Info) ->
         		  JIDs /= [] ->
         	    DetailedInfo = detailed_info(Pid),
         	    Body = io_lib:format(
        -		     "(~w) The process ~w is consuming too much memory: ~w.~n"
        +		     "(~w) The process ~w is consuming too much memory:~n~p~n"
         		     "~s",
         		     [node(), Pid, Info, DetailedInfo]),
         	    From = exmpp_jid:make_jid(undefined, Host, <<"watchdog">>),
        @@ -310,14 +330,25 @@ process_command1(From, To, Body) ->
         process_command2(["kill", SNode, SPid], From, To) ->
             Node = list_to_atom(SNode),
             remote_command(Node, [kill, SPid], From, To);
        +process_command2(["showlh", SNode], From, To) ->
        +    Node = list_to_atom(SNode),
        +    remote_command(Node, [showlh], From, To);
        +process_command2(["setlh", SNode, NewValueString], From, To) ->
        +    Node = list_to_atom(SNode),
        +    NewValue = list_to_integer(NewValueString),
        +    remote_command(Node, [setlh, NewValue], From, To);
         process_command2(["help"], From, To) ->
             send_message(To, From, help());
         process_command2(_, From, To) ->
             send_message(To, From, help()).
         
        +
         help() ->
             "Commands:\n"
        -	"  kill  ".
        +	"  kill  \n"
        +	"  showlh \n"
        +	"  setlh  ".
        +
         
         remote_command(Node, Args, From, To) ->
             Message =
        @@ -332,6 +363,12 @@ remote_command(Node, Args, From, To) ->
         process_remote_command([kill, SPid]) ->
             exit(list_to_pid(SPid), kill),
             "ok";
        +process_remote_command([showlh]) ->
        +    Res = gen_server:call(ejabberd_system_monitor, {get, large_heap}),
        +    io_lib:format("Current large heap: ~p", [Res]);
        +process_remote_command([setlh, NewValue]) ->
        +    {lh_changed, OldLH, NewLH} = gen_server:call(ejabberd_system_monitor, {set, large_heap, NewValue}),
        +    io_lib:format("Result of set large heap: ~p --> ~p", [OldLH, NewLH]);
         process_remote_command(_) ->
             throw(unknown_command).
         
        
        From b0f29b20db5b690c62a6c30a3cf75b7fe6f3e033 Mon Sep 17 00:00:00 2001
        From: Badlop 
        Date: Tue, 3 Mar 2009 18:49:02 +0000
        Subject: [PATCH 227/582] Merge 1876 from trunk.
        
        * src/web/ejabberd_http_poll.erl: Allow configuration of session
        timeout, using new global option http_poll_timeout (EJAB-135)
        * doc/guide.tex: Document new option
        * doc/guide.html: Likewise
        
        SVN Revision: 1941
        ---
         ChangeLog                      |  5 +++++
         doc/guide.html                 | 10 +++++++---
         doc/guide.tex                  |  7 +++++++
         src/web/ejabberd_http_poll.erl | 13 +++++++++++--
         4 files changed, 30 insertions(+), 5 deletions(-)
        
        diff --git a/ChangeLog b/ChangeLog
        index b6e5084c5..4abaee92c 100644
        --- a/ChangeLog
        +++ b/ChangeLog
        @@ -1,5 +1,10 @@
         2009-03-03  Badlop  
         
        +	* src/web/ejabberd_http_poll.erl: Allow configuration of session
        +        timeout, using new global option http_poll_timeout (EJAB-135)
        +        * doc/guide.tex: Document new option
        +        * doc/guide.html: Likewise
        +
         	* src/ejabberd_system_monitor.erl: Allow parametrizable watchdog
         	threshold: option watchdog_large_heap or chatting with the
         	watchdog bot (EJAB-545)
        diff --git a/doc/guide.html b/doc/guide.html
        index 55ce1dc69..452131d97 100644
        --- a/doc/guide.html
        +++ b/doc/guide.html
        @@ -712,8 +712,11 @@ do not allow outgoing sockets on port 5222.

        If HTTP Polling is enabled, it wil http://server:port/http-poll/. Be aware that support for HTTP Polling is also needed in the Jabber client. Remark also that HTTP Polling can be interesting to host a web-based Jabber client such as -JWChat. -

        {max_stanza_size, Size}
        +JWChat.

        The maximum period of time to keep a client session active without +an incoming POST request can be configured with the global option +http_poll_timeout. The default value is five minutes. +The option can be defined in ejabberd.cfg, expressing the time +in seconds: {http_poll_timeout, 300}.

        {max_stanza_size, Size}
        This option specifies an approximate maximum size in bytes of XML stanzas. Approximate, because it is calculated with the precision of one block of readed @@ -3370,7 +3373,8 @@ If a process in the ejabberd server consumes more memory than the confi a message is sent to the Jabber accounts defined with the option watchdog_admins in the ejabberd configuration file.

        The memory consumed is measured in words: -a word on 32-bit architecture is 4 bytes, and a word on 64-bit architecture 8 bytes. +a word on 32-bit architecture is 4 bytes, +and a word on 64-bit architecture is 8 bytes. The threshold by default is 1000000 words. This value can be configured with the option watchdog_large_heap, or in a conversation with the watchdog alert bot.

        Example configuration: diff --git a/doc/guide.tex b/doc/guide.tex index ac054dab6..983e219b2 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -851,6 +851,13 @@ This is a detailed description of each option allowed by the listening modules: is also needed in the \Jabber{} client. Remark also that HTTP Polling can be interesting to host a web-based \Jabber{} client such as \footahref{http://jwchat.sourceforge.net/}{JWChat}. + + The maximum period of time to keep a client session active without + an incoming POST request can be configured with the global option + \term{http\_poll\_timeout}. The default value is five minutes. + The option can be defined in \term{ejabberd.cfg}, expressing the time + in seconds: \verb|{http_poll_timeout, 300}.| + \titem{\{max\_stanza\_size, Size\}} \ind{options!max\_stanza\_size}This option specifies an approximate maximum size in bytes of XML stanzas. Approximate, diff --git a/src/web/ejabberd_http_poll.erl b/src/web/ejabberd_http_poll.erl index 257a6f821..d4ecaf549 100644 --- a/src/web/ejabberd_http_poll.erl +++ b/src/web/ejabberd_http_poll.erl @@ -58,6 +58,7 @@ input = "", waiting_input = false, %% {ReceiverPid, Tag} last_receiver, + http_poll_timeout, timer}). %-define(DBGFSM, true). @@ -187,12 +188,20 @@ init([ID, Key, IP]) -> %% connector. Opts = ejabberd_c2s_config:get_c2s_limits(), + HTTPPollTimeout = case ejabberd_config:get_local_option({http_poll_timeout, + ?MYNAME}) of + %% convert seconds of option into milliseconds + Int when is_integer(Int) -> Int*1000; + undefined -> ?HTTP_POLL_TIMEOUT + end, + Socket = {http_poll, self(), IP}, ejabberd_socket:start(ejabberd_c2s, ?MODULE, Socket, Opts), - Timer = erlang:start_timer(?HTTP_POLL_TIMEOUT, self(), []), + Timer = erlang:start_timer(HTTPPollTimeout, self(), []), {ok, loop, #state{id = ID, key = Key, socket = Socket, + http_poll_timeout = HTTPPollTimeout, timer = Timer}}. %%---------------------------------------------------------------------- @@ -284,7 +293,7 @@ handle_sync_event({http_put, Key, NewKey, Packet}, Receiver ! {tcp, StateData#state.socket, list_to_binary(Packet)}, cancel_timer(StateData#state.timer), - Timer = erlang:start_timer(?HTTP_POLL_TIMEOUT, self(), []), + Timer = erlang:start_timer(StateData#state.http_poll_timeout, self(), []), Reply = ok, {reply, Reply, StateName, StateData#state{waiting_input = false, From 54da31e8059a93aa8d4d1e33b8da1dc42594db75 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 18:53:28 +0000 Subject: [PATCH 228/582] Merge 1874 from trunk. * src/mod_shared_roster.erl: Fix bug: a pending subscription request, and later the requester added to the roster due to a shared roster group, that request could neither be accepted or rejected (thanks to Brian Cully)(EJAB-869) SVN Revision: 1942 --- ChangeLog | 11 +++++++--- src/mod_shared_roster.erl | 43 ++++++++++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4abaee92c..04eef9ce3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,14 @@ 2009-03-03 Badlop + * src/mod_shared_roster.erl: Fix bug: a pending subscription + request, and later the requester added to the roster due to a + shared roster group, that request could neither be accepted or + rejected (thanks to Brian Cully)(EJAB-869) + * src/web/ejabberd_http_poll.erl: Allow configuration of session - timeout, using new global option http_poll_timeout (EJAB-135) - * doc/guide.tex: Document new option - * doc/guide.html: Likewise + timeout, using new global option http_poll_timeout (EJAB-135) + * doc/guide.tex: Document new option + * doc/guide.html: Likewise * src/ejabberd_system_monitor.erl: Allow parametrizable watchdog threshold: option watchdog_large_heap or chatting with the diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index bac6cf5c9..8de3e11f4 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -190,7 +190,24 @@ process_item(RosterItem, Host) -> %% Check if the list of groups of the new roster item %% include at least a new one case lists:subtract(RosterItem#roster.groups, CommonGroups) of + %% If it doesn't, then remove this user from any + %% existing roster groups. [] -> + %% Remove pending subscription by setting it + %% unsubscribed. + Mod = get_roster_mod(ServerFrom), + + %% Remove pending out subscription + Mod:out_subscription(UserTo, ServerTo, + jlib:make_jid(UserFrom, ServerFrom, ""), + unsubscribe), + + %% Remove pending in subscription + Mod:in_subscription(aaaa, UserFrom, ServerFrom, + jlib:make_jid(UserTo, ServerTo, ""), + unsubscribe, ""), + + %% But we're still subscribed, so respond as such. RosterItem#roster{subscription = both, ask = none}; %% If so, it means the user wants to add that contact %% to his personal roster @@ -215,11 +232,7 @@ build_roster_record(User1, Server1, User2, Server2, Name2, Groups) -> set_new_rosteritems(UserFrom, ServerFrom, UserTo, ServerTo, ResourceTo, NameTo, GroupsFrom) -> - Mod = case lists:member(mod_roster_odbc, - gen_mod:loaded_modules(ServerFrom)) of - true -> mod_roster_odbc; - false -> mod_roster - end, + Mod = get_roster_mod(ServerFrom), RIFrom = build_roster_record(UserFrom, ServerFrom, UserTo, ServerTo, NameTo, GroupsFrom), @@ -316,6 +329,18 @@ get_jid_info({Subscription, Groups}, User, Server, JID) in_subscription(Acc, User, Server, JID, Type, _Reason) -> process_subscription(in, User, Server, JID, Type, Acc). +out_subscription(UserFrom, ServerFrom, JIDTo, unsubscribed) -> + Mod = get_roster_mod(ServerFrom), + + %% Remove pending out subscription + {UserTo, ServerTo, _} = jlib:short_prepd_bare_jid(JIDTo), + JIDFrom = jlib:make_jid(UserFrom, UserTo, ""), + Mod:out_subscription(UserTo, ServerTo, JIDFrom, unsubscribe), + + %% Remove pending in subscription + Mod:in_subscription(aaaa, UserFrom, ServerFrom, JIDTo, unsubscribe, ""), + + process_subscription(out, UserFrom, ServerFrom, JIDTo, unsubscribed, false); out_subscription(User, Server, JID, Type) -> process_subscription(out, User, Server, JID, Type, false). @@ -929,6 +954,14 @@ shared_roster_group_parse_query(Host, Group, Query) -> nothing end. +%% Get the roster module for Server. +get_roster_mod(Server) -> + case lists:member(mod_roster_odbc, + gen_mod:loaded_modules(Server)) of + true -> mod_roster_odbc; + false -> mod_roster + end. + get_opt(Opts, Opt, Default) -> case lists:keysearch(Opt, 1, Opts) of {value, {_, Val}} -> From 23ec55975e7f378da6827ef3ce8b3f3499794f25 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 18:57:47 +0000 Subject: [PATCH 229/582] Merge 1877 from trunk. * src/mod_roster.erl: When account is deleted, cancel presence subscription for all roster items (EJAB-790) * src/mod_roster_odbc.erl: Likewise SVN Revision: 1943 --- ChangeLog | 4 ++++ src/mod_roster.erl | 49 ++++++++++++++++++++++++++++++++++++++++- src/mod_roster_odbc.erl | 49 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 100 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 04eef9ce3..3747dc12b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2009-03-03 Badlop + * src/mod_roster.erl: When account is deleted, cancel presence + subscription for all roster items (EJAB-790) + * src/mod_roster_odbc.erl: Likewise + * src/mod_shared_roster.erl: Fix bug: a pending subscription request, and later the requester added to the roster due to a shared roster group, that request could neither be accepted or diff --git a/src/mod_roster.erl b/src/mod_roster.erl index cb1b195e7..be4afd098 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -271,7 +271,8 @@ process_item_set(From, To, #xmlel{} = El) -> Item2 = process_item_els(Item1, El#xmlel.children), case Item2#roster.subscription of remove -> - mnesia:delete({roster, {LUser, LServer, LJID}}); + send_unsubscribing_presence(From, Item), + ok; _ -> mnesia:write(Item2) end, @@ -688,6 +689,7 @@ remove_user(User, Server) LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, + send_unsubscription_to_rosteritems(LUser, LServer), F = fun() -> lists:foreach(fun(R) -> mnesia:delete_object(R) @@ -700,6 +702,51 @@ remove_user(User, Server) ok end. +%% For each contact with Subscription: +%% Both or From, send a "unsubscribed" presence stanza; +%% Both or To, send a "unsubscribe" presence stanza. +send_unsubscription_to_rosteritems(LUser, LServer) -> + RosterItems = get_user_roster([], {LUser, LServer}), + From = jlib:make_jid({LUser, LServer, ""}), + lists:foreach(fun(RosterItem) -> + send_unsubscribing_presence(From, RosterItem) + end, + RosterItems). + +%% @spec (From::jid(), Item::roster()) -> ok +send_unsubscribing_presence(From, Item) -> + IsTo = case Item#roster.subscription of + both -> true; + to -> true; + _ -> false + end, + IsFrom = case Item#roster.subscription of + both -> true; + from -> true; + _ -> false + end, + if IsTo -> + send_presence_type( + jlib:jid_remove_resource(From), + jlib:make_jid(Item#roster.jid), "unsubscribe"); + true -> ok + end, + if IsFrom -> + send_presence_type( + jlib:jid_remove_resource(From), + jlib:make_jid(Item#roster.jid), "unsubscribed"); + true -> ok + end, + ok. + +send_presence_type(From, To, Type) -> + ejabberd_router:route( + From, To, + {xmlelement, "presence", + [{"type", Type}], + []}). + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% @spec (User, Server, El) -> term() diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index b408f7664..8f5a8405b 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -253,7 +253,8 @@ process_item_set(From, To, #xmlel{} = El) -> Item2 = process_item_els(Item1, El#xmlel.children), case Item2#roster.subscription of remove -> - odbc_queries:del_roster(LServer, Username, SJID); + send_unsubscribing_presence(From, Item), + ok; _ -> ItemVals = record_to_string(Item2), ItemGroups = groups_to_string(Item2), @@ -629,6 +630,7 @@ remove_user(User, Server) when is_binary(User), is_binary(Server) -> LUser = exmpp_stringprep:nodeprep(User), LServer = binary_to_list(exmpp_stringprep:nameprep(Server)), Username = ejabberd_odbc:escape(LUser), + send_unsubscription_to_rosteritems(LUser, LServer), odbc_queries:del_user_roster_t(LServer, Username), ok catch @@ -636,6 +638,51 @@ remove_user(User, Server) when is_binary(User), is_binary(Server) -> ok end. +%% For each contact with Subscription: +%% Both or From, send a "unsubscribed" presence stanza; +%% Both or To, send a "unsubscribe" presence stanza. +send_unsubscription_to_rosteritems(LUser, LServer) -> + RosterItems = get_user_roster([], {LUser, LServer}), + From = jlib:make_jid({LUser, LServer, ""}), + lists:foreach(fun(RosterItem) -> + send_unsubscribing_presence(From, RosterItem) + end, + RosterItems). + +%% @spec (From::jid(), Item::roster()) -> ok +send_unsubscribing_presence(From, Item) -> + IsTo = case Item#roster.subscription of + both -> true; + to -> true; + _ -> false + end, + IsFrom = case Item#roster.subscription of + both -> true; + from -> true; + _ -> false + end, + if IsTo -> + send_presence_type( + jlib:jid_remove_resource(From), + jlib:make_jid(Item#roster.jid), "unsubscribe"); + true -> ok + end, + if IsFrom -> + send_presence_type( + jlib:jid_remove_resource(From), + jlib:make_jid(Item#roster.jid), "unsubscribed"); + true -> ok + end, + ok. + +send_presence_type(From, To, Type) -> + ejabberd_router:route( + From, To, + {xmlelement, "presence", + [{"type", Type}], + []}). + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% set_items(User, Server, #xmlel{children = Els}) when is_binary(User), is_binary(Server) -> From f0c0b2230a6d566bde5f4ea0d95f583ab771ca38 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 19:01:24 +0000 Subject: [PATCH 230/582] Merge 1878 from trunk. * src/mod_muc/mod_muc.erl: Export function to create MUC room (thanks to Eric Cestari) (EJAB-729) SVN Revision: 1944 --- ChangeLog | 3 +++ src/mod_muc/mod_muc.erl | 31 ++++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 3747dc12b..840ac58af 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2009-03-03 Badlop + * src/mod_muc/mod_muc.erl: Export function to create MUC + room (thanks to Eric Cestari) (EJAB-729) + * src/mod_roster.erl: When account is deleted, cancel presence subscription for all roster items (EJAB-790) * src/mod_roster_odbc.erl: Likewise diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index 62c292d52..bb1502b81 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -38,6 +38,7 @@ store_room/3, restore_room/2, forget_room/2, + create_room/5, process_iq_disco_items/4, can_use_nick/3]). @@ -105,6 +106,13 @@ room_destroyed(Host, Room, Pid, ServerHost) when is_binary(Host), {room_destroyed, {Room, Host}, Pid}, ok. +%% @doc Create a room. +%% If Opts = default, the default room options are used. +%% Else use the passed options as defined in mod_muc_room. +create_room(Host, Name, From, Nick, Opts) -> + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + gen_server:call(Proc, {create, Name, From, Nick, Opts}). + store_room(Host, Name, Opts) when is_binary(Host), is_binary(Name) -> F = fun() -> mnesia:write(#muc_room{name_host = {Name, Host}, @@ -212,7 +220,28 @@ init([Host, Opts]) -> %% Description: Handling call messages %%-------------------------------------------------------------------- handle_call(stop, _From, State) -> - {stop, normal, ok, State}. + {stop, normal, ok, State}; + +handle_call({create, Room, From, Nick, Opts}, + _From, + #state{host = Host, + server_host = ServerHost, + access = Access, + default_room_opts = DefOpts, + history_size = HistorySize, + room_shaper = RoomShaper} = State) -> + ?DEBUG("MUC: create new room '~s'~n", [Room]), + NewOpts = case Opts of + default -> DefOpts; + _ -> Opts + end, + {ok, Pid} = mod_muc_room:start( + Host, ServerHost, Access, + Room, HistorySize, + RoomShaper, From, + Nick, NewOpts), + register_room(Host, Room, Pid), + {reply, ok, State}. %%-------------------------------------------------------------------- %% Function: handle_cast(Msg, State) -> {noreply, State} | From fe297e1deaba19809286ebb9b3ad724fffef9047 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 19:03:56 +0000 Subject: [PATCH 231/582] Merge 1879 from trunk. * src/mod_muc/mod_muc_log.erl: Prevent XSS in MUC logs by linkifying only a few known protocols (EJAB-850) SVN Revision: 1945 --- ChangeLog | 3 +++ src/mod_muc/mod_muc_log.erl | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 840ac58af..4dde5bf93 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2009-03-03 Badlop + * src/mod_muc/mod_muc_log.erl: Prevent XSS in MUC logs by + linkifying only a few known protocols (EJAB-850) + * src/mod_muc/mod_muc.erl: Export function to create MUC room (thanks to Eric Cestari) (EJAB-729) diff --git a/src/mod_muc/mod_muc_log.erl b/src/mod_muc/mod_muc_log.erl index 7f5c18718..01b3cda01 100644 --- a/src/mod_muc/mod_muc_log.erl +++ b/src/mod_muc/mod_muc_log.erl @@ -767,7 +767,8 @@ htmlize2(S1, NoFollow) -> S2 = element(2, regexp:gsub(S1, "\\&", "\\&")), S3 = element(2, regexp:gsub(S2, "<", "\\<")), S4 = element(2, regexp:gsub(S3, ">", "\\>")), - S5 = element(2, regexp:gsub(S4, "[-+.a-zA-Z0-9]+://[^] )\'\"}]+", link_regexp(NoFollow))), + S5 = element(2, regexp:gsub(S4, "(http|https|ftp|mailto|xmpp)://[^] )\'\"}]+", + link_regexp(NoFollow))), %% Remove 'right-to-left override' unicode character 0x202e element(2, regexp:gsub(S5, [226,128,174], "[RLO]")). From 4046ecc99e37786c0947687db68315fe5f3278f0 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 19:07:24 +0000 Subject: [PATCH 232/582] Merge 1880 from trunk. * src/mod_muc/mod_muc_room.erl: Owner of a password protected room must provide the password, like other participants (EJAB-867) SVN Revision: 1946 --- ChangeLog | 3 +++ src/mod_muc/mod_muc_room.erl | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4dde5bf93..a390e5b18 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2009-03-03 Badlop + * src/mod_muc/mod_muc_room.erl: Owner of a password protected room + must provide the password, like other participants (EJAB-867) + * src/mod_muc/mod_muc_log.erl: Prevent XSS in MUC logs by linkifying only a few known protocols (EJAB-850) diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index bac145b9b..941066647 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -1512,7 +1512,7 @@ add_new_user(From, Nick, Packet, StateData) -> From, Err), StateData; {_, _, _, Role} -> - case check_password(Affiliation, + case check_password(ServiceAffiliation, exmpp_xml:get_child_elements(Packet), StateData) of true -> @@ -1574,8 +1574,9 @@ add_new_user(From, Nick, Packet, StateData) -> end. check_password(owner, _Els, _StateData) -> + %% Don't check pass if user is owner in MUC service (access_admin option) true; -check_password(_Affiliation, Els, StateData) -> +check_password(_ServiceAffiliation, Els, StateData) -> case (StateData#state.config)#config.password_protected of false -> true; From 890b1c4f600515cb9f78aa818dad815e9fd8c5e3 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 19:26:24 +0000 Subject: [PATCH 233/582] Merge 1834 from trunk. * src/mod_privacy.erl: Only run roster_get_jid_info if privacy list has subscription or group (thanks to George Hazan)(EJAB-851). Sort items in privacy list by order before storing (EJAB-848) * src/mod_privacy.hrl: Likewise * src/mod_privacy_odbc.erl: Likewise SVN Revision: 1947 --- ChangeLog | 6 +++++ src/mod_privacy.erl | 53 ++++++++++++++++++++----------------- src/mod_privacy.hrl | 2 +- src/mod_privacy_odbc.erl | 56 ++++++++++++++++++++++------------------ 4 files changed, 68 insertions(+), 49 deletions(-) diff --git a/ChangeLog b/ChangeLog index a390e5b18..8948d28a6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2009-03-03 Badlop + * src/mod_privacy.erl: Only run roster_get_jid_info if privacy + list has subscription or group (thanks to George Hazan)(EJAB-851). + Sort items in privacy list by order before storing (EJAB-848) + * src/mod_privacy.hrl: Likewise + * src/mod_privacy_odbc.erl: Likewise + * src/mod_muc/mod_muc_room.erl: Owner of a password protected room must provide the password, like other participants (EJAB-867) diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 5bc30db0c..acd2fb380 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -322,7 +322,8 @@ process_active_set(LUser, LServer, Name) -> [#privacy{lists = Lists}] -> case lists:keysearch(Name, 1, Lists) of {value, {_, List}} -> - {result, [], #userlist{name = Name, list = List}}; + NeedDb = is_list_needdb(List), + {result, [], #userlist{name = Name, list = List, needdb = NeedDb}}; false -> {error, 'item-not-found'} end @@ -414,11 +415,7 @@ parse_items(Els) -> parse_items([], Res) -> %% Sort the items by their 'order' attribute - %% 5 is the position of 'order' attribute in a #listitem tuple - %% This integer can be calculated at runtime with: - %% 2 + length(lists:takewhile(fun(E) -> E =/= order end, - %% record_info(fields, listitem))), - lists:keysort(5, Res); + lists:keysort(#listitem.order, Res); parse_items([El = #xmlel{name = item} | Els], Res) -> Type = exmpp_xml:get_attribute_as_list(El, type, false), Value = exmpp_xml:get_attribute_as_list(El, value, false), @@ -524,6 +521,16 @@ parse_matches1(_Item, [#xmlel{} | _Els]) -> +is_list_needdb(Items) -> + lists:any( + fun(X) -> + case X#listitem.type of + subscription -> true; + group -> true; + _ -> false + end + end, Items). + get_user_list(_, User, Server) when is_binary(User), is_binary(Server) -> try @@ -555,7 +562,7 @@ get_user_list(_, User, Server) check_packet(_, User, Server, - #userlist{list = List}, + #userlist{list = List, needdb = NeedDb}, {From, To, #xmlel{name = PName}}, Dir) when PName =:= message ; @@ -569,37 +576,37 @@ check_packet(_, User, Server, {message, in} -> LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = - ejabberd_hooks:run_fold( - roster_get_jid_info, - Server, - {none, []}, [User, Server, From]), + case NeedDb of + true -> ejabberd_hooks:run_fold(roster_get_jid_info, Server, {none, []}, [User, Server, From]); + false -> {[], []} + end, check_packet_aux(List, message, LJID, Subscription, Groups); {iq, in} -> LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = - ejabberd_hooks:run_fold( - roster_get_jid_info, - Server, - {none, []}, [User, Server, From]), + case NeedDb of + true -> ejabberd_hooks:run_fold(roster_get_jid_info, Server, {none, []}, [User, Server, From]); + false -> {[], []} + end, check_packet_aux(List, iq, LJID, Subscription, Groups); {presence, in} -> LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = - ejabberd_hooks:run_fold( - roster_get_jid_info, - Server, - {none, []}, [User, Server, From]), + case NeedDb of + true -> ejabberd_hooks:run_fold(roster_get_jid_info, Server, {none, []}, [User, Server, From]); + false -> {[], []} + end, check_packet_aux(List, presence_in, LJID, Subscription, Groups); {presence, out} -> LJID = jlib:short_prepd_jid(To), {Subscription, Groups} = - ejabberd_hooks:run_fold( - roster_get_jid_info, - Server, - {none, []}, [User, Server, To]), + case NeedDb of + true -> ejabberd_hooks:run_fold(roster_get_jid_info, Server, {none, []}, [User, Server, From]); + false -> {[], []} + end, check_packet_aux(List, presence_out, LJID, Subscription, Groups); _ -> diff --git a/src/mod_privacy.hrl b/src/mod_privacy.hrl index 24e097cda..c14e6ec4d 100644 --- a/src/mod_privacy.hrl +++ b/src/mod_privacy.hrl @@ -34,4 +34,4 @@ match_presence_out = false }). --record(userlist, {name = none, list = []}). +-record(userlist, {name = none, list = [], needdb = false }). diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 67c7190ef..90fb41e62 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -322,7 +322,8 @@ process_active_set(LUser, LServer, Name) -> "match_presence_in", "match_presence_out"], RItems} -> Items = lists:map(fun raw_to_item/1, RItems), - {result, [], #userlist{name = Name, list = Items}}; + NeedDb = is_list_needdb(Items), + {result, [], #userlist{name = Name, list = Items, needdb = NeedDb}}; _ -> {error, 'internal-server-error'} end; @@ -415,11 +416,7 @@ parse_items(Els) -> parse_items([], Res) -> %% Sort the items by their 'order' attribute - %% 5 is the position of 'order' attribute in a #listitem tuple - %% This integer can be calculated at runtime with: - %% 2 + length(lists:takewhile(fun(E) -> E =/= order end, - %% record_info(fields, listitem))), - lists:keysort(5, Res); + lists:keysort(#listitem.order, Res); parse_items([El = #xmlel{name = item} | Els], Res) -> Type = exmpp_xml:get_attribute_as_list(El, type, false), Value = exmpp_xml:get_attribute_as_list(El, value, false), @@ -523,7 +520,15 @@ parse_matches1(_Item, [#xmlel{} | _Els]) -> - +is_list_needdb(Items) -> + lists:any( + fun(X) -> + case X#listitem.type of + subscription -> true; + group -> true; + _ -> false + end + end, Items). get_user_list(_, User, Server) when is_binary(User), is_binary(Server) -> @@ -540,7 +545,8 @@ get_user_list(_, User, Server) "match_presence_in", "match_presence_out"], RItems} -> Items = lists:map(fun raw_to_item/1, RItems), - #userlist{name = Default, list = Items}; + NeedDb = is_list_needdb(Items), + #userlist{name = Default, list = Items, needdb = NeedDb}; _ -> #userlist{} end; @@ -554,7 +560,7 @@ get_user_list(_, User, Server) check_packet(_, User, Server, - #userlist{list = List}, + #userlist{list = List, needdb = NeedDb}, {From, To, #xmlel{name = PName}}, Dir) when PName =:= message ; @@ -568,37 +574,37 @@ check_packet(_, User, Server, {message, in} -> LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = - ejabberd_hooks:run_fold( - roster_get_jid_info, - Server, - {none, []}, [User, Server, From]), + case NeedDb of + true -> ejabberd_hooks:run_fold(roster_get_jid_info, Server, {none, []}, [User, Server, LJID]); + false -> {[], []} + end, check_packet_aux(List, message, LJID, Subscription, Groups); {iq, in} -> LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = - ejabberd_hooks:run_fold( - roster_get_jid_info, - Server, - {none, []}, [User, Server, From]), + case NeedDb of + true -> ejabberd_hooks:run_fold(roster_get_jid_info, Server, {none, []}, [User, Server, LJID]); + false -> {[], []} + end, check_packet_aux(List, iq, LJID, Subscription, Groups); {presence, in} -> LJID = jlib:short_prepd_jid(From), {Subscription, Groups} = - ejabberd_hooks:run_fold( - roster_get_jid_info, - Server, - {none, []}, [User, Server, From]), + case NeedDb of + true -> ejabberd_hooks:run_fold(roster_get_jid_info, Server, {none, []}, [User, Server, LJID]); + false -> {[], []} + end, check_packet_aux(List, presence_in, LJID, Subscription, Groups); {presence, out} -> LJID = jlib:short_prepd_jid(To), {Subscription, Groups} = - ejabberd_hooks:run_fold( - roster_get_jid_info, - Server, - {none, []}, [User, Server, To]), + case NeedDb of + true -> ejabberd_hooks:run_fold(roster_get_jid_info, jlib:nameprep(Server), {none, []}, [User, Server, LJID]); + false -> {[], []} + end, check_packet_aux(List, presence_out, LJID, Subscription, Groups); _ -> From 5bfdb71b4c850abafa8bececefc4d8987827373c Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 19:32:48 +0000 Subject: [PATCH 234/582] Merge 1881 from trunk. * src/mod_privacy.erl: Privacy List: deny presence-out all + send presence to: presence is sent (EJAB-255) * src/ejabberd_c2s.erl: Likewise SVN Revision: 1948 --- ChangeLog | 4 +++ src/ejabberd_c2s.erl | 53 ++++++++++++++++------------ src/mod_privacy.erl | 83 ++++++++++++++++++++++---------------------- 3 files changed, 75 insertions(+), 65 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8948d28a6..6131a6b25 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2009-03-03 Badlop + * src/mod_privacy.erl: Privacy List: deny presence-out all + send + presence to: presence is sent (EJAB-255) + * src/ejabberd_c2s.erl: Likewise + * src/mod_privacy.erl: Only run roster_get_jid_info if privacy list has subscription or group (thanks to George Hazan)(EJAB-851). Sort items in privacy list by order before storing (EJAB-848) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 614a4e4e4..6fd3254a4 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -877,8 +877,8 @@ session_established2(El, StateData) -> user_send_packet, Server, [FromJID, ToJID, NewEl]), - ejabberd_router:route( - FromJID, ToJID, NewEl), + check_privacy_route(FromJID, StateData, FromJID, + ToJID, NewEl), StateData end; #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message'} -> @@ -1500,16 +1500,16 @@ presence_update(From, Packet, StateData) -> %% User sends a directed presence packet presence_track(From, To, Packet, StateData) -> LTo = jlib:short_prepd_jid(To), - BFrom = exmpp_jid:jid_to_bare_jid(From), case exmpp_presence:get_type(Packet) of 'unavailable' -> - ejabberd_router:route(From, To, Packet), + check_privacy_route(From, StateData, From, To, Packet), I = remove_element(LTo, StateData#state.pres_i), A = remove_element(LTo, StateData#state.pres_a), StateData#state{pres_i = I, pres_a = A}; 'invisible' -> ejabberd_router:route(From, To, Packet), + check_privacy_route(From, StateData, From, To, Packet), I = ?SETS:add_element(LTo, StateData#state.pres_i), A = remove_element(LTo, StateData#state.pres_a), StateData#state{pres_i = I, @@ -1518,52 +1518,59 @@ presence_track(From, To, Packet, StateData) -> ejabberd_hooks:run(roster_out_subscription, StateData#state.server, [StateData#state.user, StateData#state.server, To, subscribe]), - ejabberd_router:route(BFrom, To, Packet), + check_privacy_route(From, StateData, exmpp_jid:jid_to_bare_jid(From), + To, Packet), StateData; 'subscribed' -> ejabberd_hooks:run(roster_out_subscription, StateData#state.server, [StateData#state.user, StateData#state.server, To, subscribed]), - ejabberd_router:route(BFrom, To, Packet), + check_privacy_route(From, StateData, exmpp_jid:jid_to_bare_jid(From), + To, Packet), StateData; 'unsubscribe' -> ejabberd_hooks:run(roster_out_subscription, StateData#state.server, [StateData#state.user, StateData#state.server, To, unsubscribe]), - ejabberd_router:route(BFrom, To, Packet), + check_privacy_route(From, StateData, exmpp_jid:jid_to_bare_jid(From), + To, Packet), StateData; 'unsubscribed' -> ejabberd_hooks:run(roster_out_subscription, StateData#state.server, [StateData#state.user, StateData#state.server, To, unsubscribed]), - ejabberd_router:route(BFrom, To, Packet), + check_privacy_route(From, StateData, exmpp_jid:jid_to_bare_jid(From), + To, Packet), StateData; 'error' -> - ejabberd_router:route(From, To, Packet), + check_privacy_route(From, StateData, From, To, Packet), StateData; 'probe' -> - ejabberd_router:route(From, To, Packet), + check_privacy_route(From, StateData, From, To, Packet), StateData; _ -> - case ejabberd_hooks:run_fold( - privacy_check_packet, StateData#state.server, - allow, - [StateData#state.user, - StateData#state.server, - StateData#state.privacy_list, - {From, To, Packet}, - out]) of - deny -> - ok; - allow -> - ejabberd_router:route(From, To, Packet) - end, + check_privacy_route(From, StateData, From, To, Packet), I = remove_element(LTo, StateData#state.pres_i), A = ?SETS:add_element(LTo, StateData#state.pres_a), StateData#state{pres_i = I, pres_a = A} end. +check_privacy_route(From, StateData, FromRoute, To, Packet) -> + case ejabberd_hooks:run_fold( + privacy_check_packet, StateData#state.server, + allow, + [StateData#state.user, + StateData#state.server, + StateData#state.privacy_list, + {From, To, Packet}, + out]) of + deny -> + ok; + allow -> + ejabberd_router:route(FromRoute, To, Packet) + end. + presence_broadcast(StateData, From, JIDSet, Packet) -> lists:foreach(fun({U, S, R}) -> FJID = exmpp_jid:make_jid(U, S, R), diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index acd2fb380..2ef8e7a49 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -561,9 +561,12 @@ get_user_list(_, User, Server) end. +%% From is the sender, To is the destination. +%% If Dir = out, User@Server is the sender account (From). +%% If Dir = in, User@Server is the destination account (To). check_packet(_, User, Server, #userlist{list = List, needdb = NeedDb}, - {From, To, #xmlel{name = PName}}, + {From, To, #xmlel{name = PName, attrs = Attrs}}, Dir) when PName =:= message ; PName =:= iq ; @@ -572,48 +575,42 @@ check_packet(_, User, Server, [] -> allow; _ -> - case {PName, Dir} of - {message, in} -> - LJID = jlib:short_prepd_jid(From), - {Subscription, Groups} = - case NeedDb of - true -> ejabberd_hooks:run_fold(roster_get_jid_info, Server, {none, []}, [User, Server, From]); - false -> {[], []} - end, - check_packet_aux(List, message, - LJID, Subscription, Groups); - {iq, in} -> - LJID = jlib:short_prepd_jid(From), - {Subscription, Groups} = - case NeedDb of - true -> ejabberd_hooks:run_fold(roster_get_jid_info, Server, {none, []}, [User, Server, From]); - false -> {[], []} - end, - check_packet_aux(List, iq, - LJID, Subscription, Groups); - {presence, in} -> - LJID = jlib:short_prepd_jid(From), - {Subscription, Groups} = - case NeedDb of - true -> ejabberd_hooks:run_fold(roster_get_jid_info, Server, {none, []}, [User, Server, From]); - false -> {[], []} - end, - check_packet_aux(List, presence_in, - LJID, Subscription, Groups); - {presence, out} -> - LJID = jlib:short_prepd_jid(To), - {Subscription, Groups} = - case NeedDb of - true -> ejabberd_hooks:run_fold(roster_get_jid_info, Server, {none, []}, [User, Server, From]); - false -> {[], []} - end, - check_packet_aux(List, presence_out, - LJID, Subscription, Groups); - _ -> - allow - end + PType = case PName of + 'message' -> message; + 'iq' -> iq; + 'presence' -> + case xml:get_attr_s("type", Attrs) of + %% notification + '' -> presence; + 'unavailable' -> presence; + %% subscribe, subscribed, unsubscribe, + %% unsubscribed, error, probe, or other + _ -> other + end + end, + PType2 = case {PType, Dir} of + {message, in} -> message; + {iq, in} -> iq; + {presence, in} -> presence_in; + {presence, out} -> presence_out; + {_, _} -> other + end, + LJID = case Dir of + in -> From; + out -> To + end, + {Subscription, Groups} = + case NeedDb of + true -> ejabberd_hooks:run_fold(roster_get_jid_info, + exmpp_stringprep:nameprep(Server), + {none, []}, + [User, Server, LJID]); + false -> {[], []} + end, + check_packet_aux(List, PType2, LJID, Subscription, Groups) end. +%% Ptype = mesage | iq | presence_in | presence_out | other check_packet_aux([], _PType, _JID, _Subscription, _Groups) -> allow; check_packet_aux([Item | List], PType, JID, Subscription, Groups) -> @@ -651,7 +648,9 @@ is_ptype_match(Item, PType) -> presence_in -> Item#listitem.match_presence_in; presence_out -> - Item#listitem.match_presence_out + Item#listitem.match_presence_out; + other -> + false end end. From 25ef60a2c19c9da05e295b27b35f95ff66480927 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 19:35:32 +0000 Subject: [PATCH 235/582] Merge 1875 from trunk. * src/ejabberd_listener.erl: Report error at startup if a listener module isn't available or is not an ejabberd listener (EJAB-868) SVN Revision: 1949 --- ChangeLog | 3 +++ src/ejabberd_listener.erl | 23 +++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6131a6b25..305076282 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2009-03-03 Badlop + * src/ejabberd_listener.erl: Report error at startup if a listener + module isn't available or is not an ejabberd listener (EJAB-868) + * src/mod_privacy.erl: Privacy List: deny presence-out all + send presence to: presence is sent (EJAB-255) * src/ejabberd_c2s.erl: Likewise diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 03948120f..5ca3bdeb0 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -56,8 +56,13 @@ start_listeners() -> Ls -> Ls2 = lists:map( fun({Port, Module, Opts}) -> - start_listener(Port, Module, Opts) - end, Ls), + case start_listener(Port, Module, Opts) of + {ok, _Pid} = R -> R; + {error, Error} -> + ?ERROR_MSG(Error, []), + throw(Error) + end + end, Ls), report_duplicated_portips(Ls), {ok, {{one_for_one, 10, 1}, Ls2}} end. @@ -225,6 +230,20 @@ accept(ListenSocket, Module, Opts) -> %% @spec (Port, Module, Opts) -> {ok, Pid} | {error, Error} start_listener(Port, Module, Opts) -> + case start_listener2(Port, Module, Opts) of + {ok, _Pid} = R -> R; + {error, {{'EXIT', {undef, _}}, _} = Error} -> + EStr = io_lib:format( + "Error starting the ejabberd listener: ~p.~n" + "It could not be loaded or is not an ejabberd listener.~n" + "Error: ~p~n", [Module, Error]), + {error, lists:flatten(EStr)}; + {error, Error} -> + {error, Error} + end. + +%% @spec (Port, Module, Opts) -> {ok, Pid} | {error, Error} +start_listener2(Port, Module, Opts) -> %% It is only required to start the supervisor in some cases. %% But it doesn't hurt to attempt to start it for any listener. %% So, it's normal (and harmless) that in most cases this call returns: {error, {already_started, pid()}} From f80758f0dec2f109ca9181133be536a652efe1a1 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 19:38:13 +0000 Subject: [PATCH 236/582] Merge 1882 from trunk. * src/ejabberd_config.erl: Check certfiles are readable on server start and listener start (EJAB-753) * src/ejabberd_listener.erl: Likewise SVN Revision: 1950 --- ChangeLog | 6 +++- src/ejabberd_config.erl | 32 +++++++++++++++-- src/ejabberd_listener.erl | 74 ++++++++++++++++++++++++++++----------- 3 files changed, 88 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index 305076282..aa94ff25d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,11 @@ 2009-03-03 Badlop + * src/ejabberd_config.erl: Check certfiles are readable on server + start and listener start (EJAB-753) + * src/ejabberd_listener.erl: Likewise + * src/ejabberd_listener.erl: Report error at startup if a listener - module isn't available or is not an ejabberd listener (EJAB-868) + module isn't available or is not an ejabberd listener (EJAB-868) * src/mod_privacy.erl: Privacy List: deny presence-out all + send presence to: presence is sent (EJAB-255) diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 6f804be21..4da6fa5e4 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -31,9 +31,11 @@ add_global_option/2, add_local_option/2, get_global_option/1, get_local_option/1]). -export([get_vh_by_auth_method/1]). +-export([is_file_readable/1]). -include("ejabberd.hrl"). -include("ejabberd_config.hrl"). +-include_lib("kernel/include/file.hrl"). %% @type macro() = {macro_key(), macro_value()} @@ -79,6 +81,7 @@ get_ejabberd_config_path() -> %% @doc Load the ejabberd configuration file. %% It also includes additional configuration files and replaces macros. +%% This function will crash if finds some error in the configuration file. %% @spec (File::string()) -> ok load_file(File) -> Terms = get_plain_terms_file(File), @@ -344,9 +347,21 @@ process_term(Term, State) -> {s2s_use_starttls, Port} -> add_option(s2s_use_starttls, Port, State); {s2s_certfile, CertFile} -> - add_option(s2s_certfile, CertFile, State); + case ejabberd_config:is_file_readable(CertFile) of + true -> add_option(s2s_certfile, CertFile, State); + false -> + ErrorText = "There is a problem in the configuration: " + "the specified file is not readable: ", + throw({error, ErrorText ++ CertFile}) + end; {domain_certfile, Domain, CertFile} -> - add_option({domain_certfile, Domain}, CertFile, State); + case ejabberd_config:is_file_readable(CertFile) of + true -> add_option({domain_certfile, Domain}, CertFile, State); + false -> + ErrorText = "There is a problem in the configuration: " + "the specified file is not readable: ", + throw({error, ErrorText ++ CertFile}) + end; {node_type, NodeType} -> add_option(node_type, NodeType, State); {cluster_nodes, Nodes} -> @@ -518,3 +533,16 @@ get_vh_by_auth_method(AuthMethod) -> mnesia:dirty_select(local_config, [{#local_config{key = {auth_method, '$1'}, value=AuthMethod},[],['$1']}]). + +%% @spec (Path::string()) -> true | false +is_file_readable(Path) -> + case file:read_file_info(Path) of + {ok, FileInfo} -> + case {FileInfo#file_info.type, FileInfo#file_info.access} of + {regular, read} -> true; + {regular, read_write} -> true; + _ -> false + end; + {error, _Reason} -> + false + end. diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 5ca3bdeb0..df3e343d8 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -86,28 +86,15 @@ start(Port, Module, Opts) -> _ -> start_dependent(Port, Module, Opts) end. -%% -> {ok, Pid} | {error, ErrorMessage} +%% @spec(Port, Module, Opts) -> {ok, Pid} | {error, ErrorMessage} start_dependent(Port, Module, Opts) -> - case includes_deprecated_ssl_option(Opts) of - false -> - proc_lib:start_link(?MODULE, init, [Port, Module, Opts]); - true -> - SSLErr="There is a problem with your ejabberd configuration file: " - "the option 'ssl' for listening sockets is no longer available." - "To get SSL encryption use the option 'tls'.", - ?ERROR_MSG(SSLErr, []), - {error, SSLErr} - end. - -%% Parse the options of the socket, -%% and return if the deprecated option 'ssl' is included -%% @spec(Opts::[opt()]) -> true | false -includes_deprecated_ssl_option(Opts) -> - case lists:keysearch(ssl, 1, Opts) of - {value, {ssl, _SSLOpts}} -> - true; - _ -> - lists:member(ssl, Opts) + try check_listener_options(Opts) of + ok -> + proc_lib:start_link(?MODULE, init, [Port, Module, Opts]) + catch + throw:{error, Error} -> + ?ERROR_MSG(Error, []), + {error, Error} end. init(PortIP, Module, Opts1) -> @@ -331,3 +318,48 @@ is_frontend(_) -> false. %% where FrontMod = atom() | {frontend, atom()} strip_frontend({frontend, Module}) -> Module; strip_frontend(Module) when is_atom(Module) -> Module. + + +%%% +%%% Check options +%%% + +check_listener_options(Opts) -> + case includes_deprecated_ssl_option(Opts) of + false -> ok; + true -> + Error = "There is a problem with your ejabberd configuration file: " + "the option 'ssl' for listening sockets is no longer available." + " To get SSL encryption use the option 'tls'.", + throw({error, Error}) + end, + case certfile_readable(Opts) of + true -> ok; + {false, Path} -> + ErrorText = "There is a problem in the configuration: " + "the specified file is not readable: ", + throw({error, ErrorText ++ Path}) + end, + ok. + +%% Parse the options of the socket, +%% and return if the deprecated option 'ssl' is included +%% @spec (Opts) -> true | false +includes_deprecated_ssl_option(Opts) -> + case lists:keysearch(ssl, 1, Opts) of + {value, {ssl, _SSLOpts}} -> + true; + _ -> + lists:member(ssl, Opts) + end. + +%% @spec (Opts) -> true | {false, Path::string()} +certfile_readable(Opts) -> + case proplists:lookup(certfile, Opts) of + none -> true; + {certfile, Path} -> + case ejabberd_config:is_file_readable(Path) of + true -> true; + false -> {false, Path} + end + end. From 36fc43c3647f5987a0591879126eb5a3c03be57e Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 19:39:36 +0000 Subject: [PATCH 237/582] Merge 1883 from trunk. * src/ejabberd_listener.erl: More error detections SVN Revision: 1951 --- ChangeLog | 2 ++ src/ejabberd_listener.erl | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/ChangeLog b/ChangeLog index aa94ff25d..0a23343da 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2009-03-03 Badlop + * src/ejabberd_listener.erl: More error detections + * src/ejabberd_config.erl: Check certfiles are readable on server start and listener start (EJAB-753) * src/ejabberd_listener.erl: Likewise diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index df3e343d8..56df6d4cd 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -124,6 +124,7 @@ init(PortIP, Module, Opts1) -> {error, Reason} -> ReasonT = case Reason of eaddrnotavail -> "IP address not available: " ++ IPS; + eaddrinuse -> "IP address and port number already used: "++IPS++" "++integer_to_list(Port); _ -> atom_to_list(Reason) end, ?ERROR_MSG("Failed to open socket:~n ~p~nReason: ~s", @@ -225,6 +226,12 @@ start_listener(Port, Module, Opts) -> "It could not be loaded or is not an ejabberd listener.~n" "Error: ~p~n", [Module, Error]), {error, lists:flatten(EStr)}; + {error, {already_started, _Pid} = Error} -> + EStr = io_lib:format( + "Error starting the ejabberd listener: ~p.~n" + "A listener is already started in that port number and IP address:~n~p~n" + "Error: ~p~n", [Module, Port, Error]), + {error, lists:flatten(EStr)}; {error, Error} -> {error, Error} end. From 9a7c6b8be15d779083686cf6c5d4138287298732 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 19:40:55 +0000 Subject: [PATCH 238/582] Merge 1884 from trunk. * src/ejabberd_listener.erl: More error detections SVN Revision: 1952 --- src/ejabberd_listener.erl | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 56df6d4cd..337267726 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -59,7 +59,6 @@ start_listeners() -> case start_listener(Port, Module, Opts) of {ok, _Pid} = R -> R; {error, Error} -> - ?ERROR_MSG(Error, []), throw(Error) end end, Ls), @@ -129,7 +128,7 @@ init(PortIP, Module, Opts1) -> end, ?ERROR_MSG("Failed to open socket:~n ~p~nReason: ~s", [{Port, Module, SockOpts}, ReasonT]), - throw(ReasonT) + throw({Reason, PortIP}) end. %% @spec (PortIP, Opts) -> {Port, IPT, IPS, IPV, OptsClean} @@ -221,17 +220,12 @@ start_listener(Port, Module, Opts) -> case start_listener2(Port, Module, Opts) of {ok, _Pid} = R -> R; {error, {{'EXIT', {undef, _}}, _} = Error} -> - EStr = io_lib:format( - "Error starting the ejabberd listener: ~p.~n" - "It could not be loaded or is not an ejabberd listener.~n" - "Error: ~p~n", [Module, Error]), - {error, lists:flatten(EStr)}; - {error, {already_started, _Pid} = Error} -> - EStr = io_lib:format( - "Error starting the ejabberd listener: ~p.~n" - "A listener is already started in that port number and IP address:~n~p~n" - "Error: ~p~n", [Module, Port, Error]), - {error, lists:flatten(EStr)}; + ?ERROR_MSG("Error starting the ejabberd listener: ~p.~n" + "It could not be loaded or is not an ejabberd listener.~n" + "Error: ~p~n", [Module, Error]), + {error, {module_not_available, Module}}; + {error, {already_started, Pid}} -> + {ok, Pid}; {error, Error} -> {error, Error} end. From dbf0bb209d1b6bf7a007b6ad59bbe8885bd20311 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 19:43:55 +0000 Subject: [PATCH 239/582] Merge 1891 from trunk. * src/ejabberd_listener.erl: When stopping a listener, don't stop the listener supervisor (EJAB-874) SVN Revision: 1953 --- ChangeLog | 3 +++ src/ejabberd_listener.erl | 5 +---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0a23343da..1218515a5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2009-03-03 Badlop + * src/ejabberd_listener.erl: When stopping a listener, don't stop + the listener supervisor (EJAB-874) + * src/ejabberd_listener.erl: More error detections * src/ejabberd_config.erl: Check certfiles are readable on server diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 337267726..4a75a7cb4 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -260,10 +260,7 @@ start_listener_sup(Port, Module, Opts) -> stop_listener(Port, Module) -> supervisor:terminate_child(ejabberd_listeners, Port), - supervisor:delete_child(ejabberd_listeners, Port), - Proc1 = gen_mod:get_module_proc("sup", Module), - supervisor:terminate_child(ejabberd_sup, Proc1), - supervisor:delete_child(ejabberd_sup, Proc1). + supervisor:delete_child(ejabberd_listeners, Port). %% @spec (PortIP, Module, Opts) -> {ok, Pid} | {error, Error} %% where From 4df4527e775599283a7be6c0beecd282862773b4 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 19:46:08 +0000 Subject: [PATCH 240/582] Merge 1907 from trunk. * src/ejabberd_listener.erl: Fix a minor compilation warning and add EDoc comment SVN Revision: 1954 --- ChangeLog | 3 +++ src/ejabberd_listener.erl | 13 ++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1218515a5..7ab310ee8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2009-03-03 Badlop + * src/ejabberd_listener.erl: Fix a minor compilation warning and + add EDoc comment + * src/ejabberd_listener.erl: When stopping a listener, don't stop the listener supervisor (EJAB-874) diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 4a75a7cb4..3c3221257 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -258,9 +258,16 @@ start_listener_sup(Port, Module, Opts) -> [?MODULE]}, supervisor:start_child(ejabberd_listeners, ChildSpec). -stop_listener(Port, Module) -> - supervisor:terminate_child(ejabberd_listeners, Port), - supervisor:delete_child(ejabberd_listeners, Port). +%% @spec (PortIP, Module) -> ok +%% where +%% PortIP = {Port, IPT | IPS} +%% Port = integer() +%% IPT = tuple() +%% IPS = string() +%% Module = atom() +stop_listener(PortIP, _Module) -> + supervisor:terminate_child(ejabberd_listeners, PortIP), + supervisor:delete_child(ejabberd_listeners, PortIP). %% @spec (PortIP, Module, Opts) -> {ok, Pid} | {error, Error} %% where From 1db9642e4c3fbc30b5ccbaec8121bd264dc24310 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 3 Mar 2009 19:48:20 +0000 Subject: [PATCH 241/582] Merge 1916 from trunk. * src/ejabberd_listener.erl: Fix report message of 'undef' error SVN Revision: 1955 --- ChangeLog | 2 ++ src/ejabberd_listener.erl | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7ab310ee8..936477697 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2009-03-03 Badlop + * src/ejabberd_listener.erl: Fix report message of 'undef' error + * src/ejabberd_listener.erl: Fix a minor compilation warning and add EDoc comment diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 3c3221257..adffe6680 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -219,11 +219,11 @@ accept(ListenSocket, Module, Opts) -> start_listener(Port, Module, Opts) -> case start_listener2(Port, Module, Opts) of {ok, _Pid} = R -> R; - {error, {{'EXIT', {undef, _}}, _} = Error} -> + {error, {{'EXIT', {undef, [{M, _F, _A}|_]}}, _} = Error} -> ?ERROR_MSG("Error starting the ejabberd listener: ~p.~n" "It could not be loaded or is not an ejabberd listener.~n" "Error: ~p~n", [Module, Error]), - {error, {module_not_available, Module}}; + {error, {module_not_available, M}}; {error, {already_started, Pid}} -> {ok, Pid}; {error, Error} -> From facf17e689dc0bd09c194447440ab00a36169d81 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 3 Mar 2009 23:26:07 +0000 Subject: [PATCH 242/582] Add roster subscriptions handling and make PEP events sent to all resources SVN Revision: 1958 --- ChangeLog | 9 ++++ src/mod_caps.erl | 38 ++++++++-------- src/mod_pubsub/mod_pubsub.erl | 86 +++++++++++++++++++++++++++-------- 3 files changed, 95 insertions(+), 38 deletions(-) diff --git a/ChangeLog b/ChangeLog index 936477697..db60fe04d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2009-03-04 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: Add roster subscriptions handling + so on_sub_and_presence if fully supported. + + * src/mod_pubsub/mod_pubsub.erl: Allow to send PEP events to all + connected ressources, even via s2s. + * src/mod_caps.erl: Likewise + 2009-03-03 Badlop * src/ejabberd_listener.erl: Fix report message of 'undef' error diff --git a/src/mod_caps.erl b/src/mod_caps.erl index df327eadf..5aeb43475 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -35,7 +35,7 @@ note_caps/3, clear_caps/1, get_features/2, - get_user_resource/2, + get_user_resources/2, handle_disco_response/3]). %% gen_mod callbacks @@ -62,7 +62,7 @@ -record(caps, {node, version, exts}). -record(caps_features, {node_pair, features}). -record(user_caps, {jid, caps}). --record(user_caps_default, {uid, resource}). +-record(user_caps_resources, {uid, resource}). -record(state, {host, disco_requests = ?DICT:new(), feature_queries = []}). @@ -100,21 +100,17 @@ clear_caps(JID) -> BJID = exmpp_jid:jid_to_binary(JID), BUID = exmpp_jid:bare_jid_to_binary(JID), catch mnesia:dirty_delete({user_caps, BJID}), - case catch mnesia:dirty_read({user_caps_default, BUID}) of - [#user_caps_default{resource=_R}] -> - catch mnesia:dirty_delete({user_caps_default, BUID}); - _ -> - ok - end. + catch mnesia:dirty_delete_object(#user_caps_resources{uid = BUID, resource = list_to_binary(R)}), + ok. %% give default user resource -get_user_resource(U, S) -> +get_user_resources(U, S) -> BUID = exmpp_jid:bare_jid_to_binary(U, S), - case catch mnesia:dirty_read({user_caps_default, BUID}) of - [#user_caps_default{resource=R}] -> - R; - _ -> - [] + case catch mnesia:dirty_read({user_caps_resources, BUID}) of + {'EXIT', _} -> + []; + Resources -> + lists:map(fun(#user_caps_resources{resource=R}) -> binary_to_list(R) end, Resources) end. %% note_caps should be called to make the module request disco @@ -171,9 +167,11 @@ init([Host, _Opts]) -> mnesia:create_table(user_caps, [{disc_copies, [node()]}, {attributes, record_info(fields, user_caps)}]), - mnesia:create_table(user_caps_default, + mnesia:create_table(user_caps_resources, [{disc_copies, [node()]}, - {attributes, record_info(fields, user_caps_default)}]), + {type, bag}, + {attributes, record_info(fields, user_caps_resources)}]), + mnesia:delete_table(user_caps_default), {ok, #state{host = Host}}. maybe_get_features(#caps{node = Node, version = Version, exts = Exts}) -> @@ -233,11 +231,11 @@ handle_cast({note_caps, From, mnesia:dirty_write(#user_caps{jid = BJID, caps = Caps}), case ejabberd_sm:get_user_resources(U, S) of [] -> - ok; - _ -> - % only store default resource of external contacts + % only store resource of caps aware external contacts BUID = exmpp_jid:bare_jid_to_binary(From), - mnesia:dirty_write(#user_caps_default{uid = BUID, resource = R}) + mnesia:dirty_write(#user_caps_resources{uid = BUID, resource = list_to_binary(R)}) + _ -> + ok end, SubNodes = [Version | Exts], %% Now, find which of these are not already in the database. diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 2bdf8e1d0..7e47dbdb7 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -55,6 +55,7 @@ %% exports for hooks -export([presence_probe/3, + in_subscription/6, remove_user/2, disco_local_identity/5, disco_local_features/5, @@ -164,6 +165,7 @@ init([ServerHost, Opts]) -> ejabberd_hooks:add(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), ejabberd_hooks:add(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75), ejabberd_hooks:add(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50), + ejabberd_hooks:add(roster_in_subscription, ServerHostB, ?MODULE, in_subscription, 50), ejabberd_hooks:add(remove_user, ServerHostB, ?MODULE, remove_user, 50), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), lists:foreach( @@ -418,6 +420,16 @@ presence_probe(JID, JID, Pid) -> presence_probe(_, _, _) -> ok. +%% ------- +%% subscription hooks handling functions +%% +in_subscription(Acc, User, Server, JID, subscribed, _) -> + Proc = gen_mod:get_module_proc(Server, ?PROCNAME), + gen_server:cast(Proc, {subscribed, User, Server, JID}), + Acc; +in_subscription(Acc, _, _, _, _, _) -> + Acc. + %% ------- %% user remove hook handling function %% @@ -521,6 +533,42 @@ handle_cast({presence, JID, Pid}, State) -> end, {noreply, State}; +handle_cast({subscribed, User, Server, JID}, State) -> + %% and send last PEP events published by JID + Owner = jlib:short_prepd_bare_jid(JID), + Host = State#state.host, + ServerHost = State#state.server_host, + lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) -> + case get_option(Options, send_last_published_item) of + on_sub_and_presence -> + lists:foreach(fun(Resource) -> + LJID = jlib:short_prepd_jid(exmpp_jid:make_jid(User, Server, Resource)), + case is_caps_notify(ServerHost, Node, LJID) of + true -> + Subscribed = case get_option(Options, access_model) of + open -> true; + presence -> true; + whitelist -> false; % subscribers are added manually + authorize -> false; % likewise + roster -> + Grps = get_option(Options, roster_groups_allowed, []), + element(2, get_roster_info(User, Server, LJID, Grps)) + end, + if Subscribed -> + send_last_item(Owner, Node, LJID); + true -> + ok + end; + false -> + ok + end + end, user_resources(User, Server)); + _ -> + ok + end + end, tree_action(Host, get_nodes, [Owner])), + {noreply, State}; + handle_cast({remove_user, LUser, LServer}, State) -> Host = State#state.host, Owner = exmpp_jid:make_jid(LUser, LServer), @@ -586,6 +634,7 @@ terminate(_Reason, #state{host = Host, ejabberd_hooks:delete(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), ejabberd_hooks:delete(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75), ejabberd_hooks:delete(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50), + ejabberd_hooks:delete(roster_in_subscription, ServerHostB, ?MODULE, in_subscription, 50), ejabberd_hooks:delete(remove_user, ServerHostB, ?MODULE, remove_user, 50), lists:foreach(fun({NS,Mod}) -> gen_iq_handler:remove_iq_handler(Mod, ServerHostB, NS) @@ -2342,7 +2391,10 @@ broadcast_stanza(Host, NodeOpts, States, Stanza) -> %% broadcast Stanza to all contacts of the user that are advertising %% interest in this kind of Node. broadcast_by_caps({LUser, LServer, LResource}, Node, _Type, Stanza) -> - SenderResource = user_resource(LUser, LServer, LResource), + SenderResource = case LResource of + [] -> hd(user_resources(LUser, LServer)); + _ -> LResource + end, case ejabberd_sm:get_session_pid(LUser, LServer, SenderResource) of C2SPid when is_pid(C2SPid) -> %% set the from address on the notification to the bare JID of the account owner @@ -2352,14 +2404,16 @@ broadcast_by_caps({LUser, LServer, LResource}, Node, _Type, Stanza) -> %%ReplyTo = jlib:make_jid(LUser, LServer, SenderResource), % This has to be used case catch ejabberd_c2s:get_subscribed(C2SPid) of Contacts when is_list(Contacts) -> - lists:foreach(fun({U, S, R}) -> - OR = user_resource(U, S, R), - case is_caps_notify(LServer, Node, {U, S, OR}) of - true -> - ejabberd_router ! {route, Sender, exmpp_jid:make_jid(U, S, OR), Stanza}; - false -> - ok - end + lists:foreach(fun({U, S, _}) -> + Resources = lists:foldl(fun(R, Acc) -> + case is_caps_notify(LServer, Node, {U, S, R}) of + true -> [R | Acc]; + false -> Acc + end + end, [], user_resources(U, S)), + lists:foreach(fun(R) -> + ejabberd_router ! {route, Sender, exmpp_jid:make_jid(U, S, R), Stanza} + end, Resources) end, Contacts); _ -> ok @@ -2374,15 +2428,11 @@ broadcast_by_caps(_, _, _, _) -> %% If we don't know the resource, just pick first if any %% If no resource available, check if caps anyway (remote online) -user_resource(LUser, LServer, []) -> - case ejabberd_sm:get_user_resources(LUser, LServer) of - [R|_] -> - R; - [] -> - mod_caps:get_user_resource(LUser, LServer) - end; -user_resource(_, _, LResource) -> - LResource. +user_resources(User, Server) -> + case ejabberd_sm:get_user_resources(User, Server) of + [] -> mod_caps:get_user_resources(User, Server); + Rs -> Rs + end. is_caps_notify(Host, Node, LJID) -> case mod_caps:get_caps(LJID) of From 592c98fd7a5781c9ad01f389be00ee59320eb708 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Wed, 4 Mar 2009 01:04:51 +0000 Subject: [PATCH 243/582] update pubsub version SVN Revision: 1961 --- src/mod_pubsub/mod_pubsub.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 7e47dbdb7..f66a2fbf3 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -39,7 +39,7 @@ -module(mod_pubsub). -author('christophe.romain@process-one.net'). --version('1.12-02'). +-version('1.12-03'). -behaviour(gen_server). -behaviour(gen_mod). From ab2dc5877f706b8b7b90c3eb03d5905f6f5dab0d Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Wed, 4 Mar 2009 01:14:13 +0000 Subject: [PATCH 244/582] Allow node creation without configure item SVN Revision: 1964 --- src/mod_pubsub/mod_pubsub.erl | 43 ++++++++++++++++------------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index f66a2fbf3..d56a8b810 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -929,30 +929,25 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) -> end, case {IQType, Name} of {set, 'create'} -> - case Configuration of - [#xmlel{name = 'configure', children = Config}] -> - %% Get the type of the node - Type = case exmpp_xml:get_attribute_from_list_as_list(Attrs, 'type', "") of - [] -> hd(Plugins); - T -> T - end, - %% we use Plugins list matching because we do not want to allocate - %% atoms for non existing type, this prevent atom allocation overflow - case lists:member(Type, Plugins) of - false -> - {error, extended_error( - 'feature-not-implemented', - unsupported, "create-nodes")}; - true -> - create_node(Host, ServerHost, Node, From, - Type, Access, Config) - end; - _ -> - %% this breaks backward compatibility! - %% can not create node without - %% but this is the new spec anyway - ?INFO_MSG("Node ~p ; invalid configuration: ~p", [Node, Configuration]), - {error, 'bad-request'} + Config = case Configuration of + [#xmlel{name = 'configure', children = C}] -> C; + _ -> [] + end, + %% Get the type of the node + Type = case exmpp_xml:get_attribute_from_list_as_list(Attrs, 'type', "") of + [] -> hd(Plugins); + T -> T + end, + %% we use Plugins list matching because we do not want to allocate + %% atoms for non existing type, this prevent atom allocation overflow + case lists:member(Type, Plugins) of + false -> + {error, extended_error( + 'feature-not-implemented', + unsupported, "create-nodes")}; + true -> + create_node(Host, ServerHost, Node, From, + Type, Access, Config) end; {set, 'publish'} -> case exmpp_xml:remove_cdata_from_list(Els) of From 7af7afc30e5ed0f5f480ad0321fc8732dcdfcb10 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 4 Mar 2009 09:55:20 +0000 Subject: [PATCH 245/582] * src/mod_caps.erl: Fix two small compilation errors SVN Revision: 1965 --- ChangeLog | 4 ++++ src/mod_caps.erl | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index db60fe04d..0ec0b6fc9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-03-04 Badlop + + * src/mod_caps.erl: Fix two small compilation errors + 2009-03-04 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: Add roster subscriptions handling diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 5aeb43475..902145625 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -97,6 +97,7 @@ get_caps({U, S, R}) -> %% clear_caps removes user caps from database clear_caps(JID) -> + R = exmpp_jid:lresource(JID), BJID = exmpp_jid:jid_to_binary(JID), BUID = exmpp_jid:bare_jid_to_binary(JID), catch mnesia:dirty_delete({user_caps, BJID}), @@ -233,7 +234,7 @@ handle_cast({note_caps, From, [] -> % only store resource of caps aware external contacts BUID = exmpp_jid:bare_jid_to_binary(From), - mnesia:dirty_write(#user_caps_resources{uid = BUID, resource = list_to_binary(R)}) + mnesia:dirty_write(#user_caps_resources{uid = BUID, resource = list_to_binary(R)}); _ -> ok end, From 7982492f50d84bda9516478c38d6d6ec147ac8d8 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 4 Mar 2009 18:34:02 +0000 Subject: [PATCH 246/582] * src/ejabberd_auth.erl: If anonymous auth is enabled, when checking if the account already exists in other auth methods, take into account if the auth method failed (EJAB-882) * src/ejabberd_auth_anonymous.erl: Likewise * src/ejabberd_auth_external.erl: Likewise * src/ejabberd_auth_internal.erl: Likewise * src/ejabberd_auth_ldap.erl: Likewise * src/ejabberd_auth_odbc.erl: Likewise * src/ejabberd_auth_pam.erl: Likewise SVN Revision: 1966 --- ChangeLog | 10 +++++ src/ejabberd_auth.erl | 70 +++++++++++++++++++-------------- src/ejabberd_auth_anonymous.erl | 3 ++ src/ejabberd_auth_external.erl | 7 +++- src/ejabberd_auth_internal.erl | 5 ++- src/ejabberd_auth_ldap.erl | 5 ++- src/ejabberd_auth_odbc.erl | 41 +++++++++++++------ src/ejabberd_auth_pam.erl | 4 +- 8 files changed, 98 insertions(+), 47 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0ec0b6fc9..5db904314 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,15 @@ 2009-03-04 Badlop + * src/ejabberd_auth.erl: If anonymous auth is enabled, when + checking if the account already exists in other auth methods, take + into account if the auth method failed (EJAB-882) + * src/ejabberd_auth_anonymous.erl: Likewise + * src/ejabberd_auth_external.erl: Likewise + * src/ejabberd_auth_internal.erl: Likewise + * src/ejabberd_auth_ldap.erl: Likewise + * src/ejabberd_auth_odbc.erl: Likewise + * src/ejabberd_auth_pam.erl: Likewise + * src/mod_caps.erl: Fix two small compilation errors 2009-03-04 Christophe Romain diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index a90a2ad61..357e5cfae 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -92,10 +92,10 @@ plain_password_required(Server) when is_list(Server) -> check_password(User, Server, Password) when is_list(User), is_list(Server), is_list(Password) -> - lists:any( - fun(M) -> - M:check_password(User, Server, Password) - end, auth_modules(Server)). + case check_password_with_authmodule(User, Server, Password) of + {true, _AuthModule} -> true; + false -> false + end. %% @spec (User, Server, Password, StreamID, Digest) -> bool() %% User = string() @@ -108,10 +108,11 @@ check_password(User, Server, Password) check_password(User, Server, Password, StreamID, Digest) when is_list(User), is_list(Server), is_list(Password), is_list(StreamID), is_list(Digest) -> - lists:any( - fun(M) -> - M:check_password(User, Server, Password, StreamID, Digest) - end, auth_modules(Server)). + case check_password_with_authmodule(User, Server, Password, + StreamID, Digest) of + {true, _AuthModule} -> true; + false -> false + end. %% @spec (User, Server, Password) -> {true, AuthModule} | false %% User = string() @@ -125,15 +126,7 @@ check_password(User, Server, Password, StreamID, Digest) check_password_with_authmodule(User, Server, Password) when is_list(User), is_list(Server), is_list(Password) -> - Res = lists:dropwhile( - fun(M) -> - not apply(M, check_password, - [User, Server, Password]) - end, auth_modules(Server)), - case Res of - [] -> false; - [AuthMod | _] -> {true, AuthMod} - end. + check_password_loop(auth_modules(Server), [User, Server, Password]). %% @spec (User, Server, Password, StreamID, Digest) -> {true, AuthModule} | false %% User = string() @@ -149,14 +142,17 @@ check_password_with_authmodule(User, Server, Password) check_password_with_authmodule(User, Server, Password, StreamID, Digest) when is_list(User), is_list(Server), (is_list(Password) orelse Password == 'undefined'), is_list(StreamID), (is_list(Digest) orelse Digest == 'undefined')-> - Res = lists:dropwhile( - fun(M) -> - not apply(M, check_password, - [User, Server, Password, StreamID, Digest]) - end, auth_modules(Server)), - case Res of - [] -> false; - [AuthMod | _] -> {true, AuthMod} + check_password_loop(auth_modules(Server), [User, Server, Password, + StreamID, Digest]). + +check_password_loop([], _Args) -> + false; +check_password_loop([AuthModule | AuthModules], Args) -> + case apply(AuthModule, check_password, Args) of + true -> + {true, AuthModule}; + false -> + check_password_loop(AuthModules, Args) end. %% @spec (User, Server, Password) -> ok | {error, ErrorType} @@ -347,7 +343,7 @@ is_user_exists(User, Server) when is_list(User), is_list(Server) -> M:is_user_exists(User, Server) end, auth_modules(Server)). -%% @spec (Module, User, Server) -> bool +%% @spec (Module, User, Server) -> true | false | maybe %% Module = authmodule() %% User = string() %% Server = string() @@ -356,10 +352,24 @@ is_user_exists(User, Server) when is_list(User), is_list(Server) -> is_user_exists_in_other_modules(Module, User, Server) when is_list(User), is_list(Server) -> - lists:any( - fun(M) -> - M:is_user_exists(User, Server) - end, auth_modules(Server)--[Module]). + is_user_exists_in_other_modules_loop( + auth_modules(Server)--[Module], + User, Server). +is_user_exists_in_other_modules_loop([], _User, _Server) -> + false; +is_user_exists_in_other_modules_loop([AuthModule|AuthModules], User, Server) -> + case AuthModule:is_user_exists(User, Server) of + true -> + true; + false -> + is_user_exists_in_other_modules_loop(AuthModules, User, Server); + {error, Error} -> + ?DEBUG("The authentication module ~p returned an error~nwhen " + "checking user ~p in server ~p~nError message: ~p", + [AuthModule, User, Server, Error]), + maybe + end. + %% @spec (User, Server) -> ok | error | {error, not_allowed} %% User = string() diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index 195b16570..440fa16ca 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -234,7 +234,10 @@ check_password(User, Server, _Password, _StreamID, _Digest) -> %% they however are "reserved") case ejabberd_auth:is_user_exists_in_other_modules(?MODULE, User, Server) of + %% If user exists in other module, reject anonnymous authentication true -> false; + %% If we are not sure whether the user exists in other module, reject anon auth + maybe -> false; false -> login(User, Server) end. diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl index 9c6dec870..bcdce272a 100644 --- a/src/ejabberd_auth_external.erl +++ b/src/ejabberd_auth_external.erl @@ -128,8 +128,13 @@ get_password_s(_User, _Server) -> %% User = string() %% Server = string() +%% @spec (User, Server) -> true | false | {error, Error} is_user_exists(User, Server) -> - extauth:is_user_exists(User, Server). + try extauth:is_user_exists(User, Server) of + Res -> Res + catch + _:Error -> {error, Error} + end. %% @spec (User, Server) -> {error, not_allowed} %% User = string() diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index 2df3cab39..003b24edf 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -310,6 +310,7 @@ get_password_s(User, Server) -> %% User = string() %% Server = string() +%% @spec (User, Server) -> true | false | {error, Error} is_user_exists(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), @@ -320,8 +321,8 @@ is_user_exists(User, Server) -> false; [_] -> true; - _ -> - false + Other -> + {error, Other} end catch _ -> diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl index c73ad0a55..c083cc141 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -242,10 +242,11 @@ get_password_s(_User, _Server) -> %% User = string() %% Server = string() +%% @spec (User, Server) -> true | false | {error, Error} is_user_exists(User, Server) -> case catch is_user_exists_ldap(User, Server) of - {'EXIT', _} -> - false; + {'EXIT', Error} -> + {error, Error}; Result -> Result end. diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index bee6d9013..4b390eb06 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -73,11 +73,18 @@ check_password(User, Server, Password) -> LUser = exmpp_stringprep:nodeprep(User), Username = ejabberd_odbc:escape(LUser), LServer = exmpp_stringprep:nameprep(Server), - case catch odbc_queries:get_password(LServer, Username) of + try odbc_queries:get_password(LServer, Username) of {selected, ["password"], [{Password}]} -> - Password /= ""; - _ -> - false + Password /= ""; %% Password is correct, and not empty + {selected, ["password"], [{_Password2}]} -> + false; %% Password is not correct + {selected, ["password"], []} -> + false; %% Account does not exist + {error, _Error} -> + false %% Typical error is that table doesn't exist + catch + _:_ -> + false %% Typical error is database not accessible end catch _ -> @@ -96,7 +103,8 @@ check_password(User, Server, Password, StreamID, Digest) -> LUser = exmpp_stringprep:nodeprep(User), Username = ejabberd_odbc:escape(LUser), LServer = exmpp_stringprep:nameprep(Server), - case catch odbc_queries:get_password(LServer, Username) of + try odbc_queries:get_password(LServer, Username) of + %% Account exists, check if password is valid {selected, ["password"], [{Passwd}]} -> DigRes = if Digest /= "" -> @@ -109,8 +117,13 @@ check_password(User, Server, Password, StreamID, Digest) -> true -> (Passwd == Password) and (Password /= "") end; - _ -> - false + {selected, ["password"], []} -> + false; %% Account does not exist + {error, _Error} -> + false %% Typical error is that table doesn't exist + catch + _:_ -> + false %% Typical error is database not accessible end catch _ -> @@ -277,16 +290,22 @@ get_password_s(User, Server) -> %% User = string() %% Server = string() +%% @spec (User, Server) -> true | false | {error, Error} is_user_exists(User, Server) -> try LUser = exmpp_stringprep:nodeprep(User), Username = ejabberd_odbc:escape(LUser), LServer = exmpp_stringprep:nameprep(Server), - case catch odbc_queries:get_password(LServer, Username) of + try odbc_queries:get_password(LServer, Username) of {selected, ["password"], [{_Password}]} -> - true; - _ -> - false + true; %% Account exists + {selected, ["password"], []} -> + false; %% Account does not exist + {error, Error} -> + {error, Error} %% Typical error is that table doesn't exist + catch + _:B -> + {error, B} %% Typical error is database not accessible end catch _ -> diff --git a/src/ejabberd_auth_pam.erl b/src/ejabberd_auth_pam.erl index a09bbac65..e147e1cc0 100644 --- a/src/ejabberd_auth_pam.erl +++ b/src/ejabberd_auth_pam.erl @@ -125,9 +125,11 @@ get_password(_User, _Server) -> get_password_s(_User, _Server) -> "". -%% @spec (User, Server) -> bool() +%% @spec (User, Server) -> true | false | {error, Error} %% User = string() %% Server = string() +%% TODO: Improve this function to return an error instead of 'false' when +%% connection to PAM failed is_user_exists(User, Server) -> Service = get_pam_service(Server), From 982f61774d06c91cd23973fe5d1d460df1dabc54 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 5 Mar 2009 19:48:24 +0000 Subject: [PATCH 247/582] * doc/guide.tex: Require OpenSSL 0.9.8f or higher (EJAB-877) * doc/guide.html: Likewise SVN Revision: 1967 --- ChangeLog | 5 +++++ doc/guide.html | 4 ++-- doc/guide.tex | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5db904314..e23272baa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-03-05 Badlop + + * doc/guide.tex: Require OpenSSL 0.9.8f or higher (EJAB-877) + * doc/guide.html: Likewise + 2009-03-04 Badlop * src/ejabberd_auth.erl: If anonymous auth is enabled, when diff --git a/doc/guide.html b/doc/guide.html index 452131d97..377dbbdb3 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -331,7 +331,7 @@ GNU Make

      • GCC
      • Libexpat 1.95 or higher
      • Erlang/OTP R10B-9 or higher. -
      • OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended. +
      • OpenSSL 0.9.8f or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended.
      • Zlib 1.2.3 or higher, for Stream Compression support (XEP-0138). Optional.
      • Erlang mysql library. Optional. For MySQL authentication or storage. See section 3.2.1.
      • Erlang pgsql library. Optional. For PostgreSQL authentication or storage. See section 3.2.3. @@ -455,7 +455,7 @@ MS Visual C++ 6.0 Compiler
      • Expat 2.0.0 or higher
      • GNU Iconv 1.9.2 (optional) -
      • Shining Light OpenSSL 0.9.8d or higher +
      • Shining Light OpenSSL 0.9.8f or higher (to enable SSL connections)
      • Zlib 1.2.3 or higher

      diff --git a/doc/guide.tex b/doc/guide.tex index 983e219b2..57e37a794 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -299,7 +299,7 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need: \item GCC \item Libexpat 1.95 or higher \item Erlang/OTP R10B-9 or higher. -\item OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended. +\item OpenSSL 0.9.8f or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended. \item Zlib 1.2.3 or higher, for Stream Compression support (\xepref{0138}). Optional. \item Erlang mysql library. Optional. For MySQL authentication or storage. See section \ref{compilemysql}. \item Erlang pgsql library. Optional. For PostgreSQL authentication or storage. See section \ref{compilepgsql}. @@ -488,7 +488,7 @@ To compile \ejabberd{} on a Microsoft Windows system, you need: \item \footahref{http://www.gnu.org/software/libiconv/}{GNU Iconv 1.9.2} (optional) -\item \footahref{http://www.slproweb.com/products/Win32OpenSSL.html}{Shining Light OpenSSL 0.9.8d or higher} +\item \footahref{http://www.slproweb.com/products/Win32OpenSSL.html}{Shining Light OpenSSL 0.9.8f or higher} (to enable SSL connections) \item \footahref{http://www.zlib.net/}{Zlib 1.2.3 or higher} \end{itemize} From 19b803bb03e6f0ac8f94ba479198d5435bca25bb Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 5 Mar 2009 20:03:18 +0000 Subject: [PATCH 248/582] * src/ejabberd_app.erl: In a Windows machine, explicitly add the nameservers, as it seems Erlang does not do itself (EJAB-860) * src/win32_dns.erl: Get name servers from Windows registy (thanks to Geoff Cant) SVN Revision: 1968 --- ChangeLog | 5 ++ src/ejabberd_app.erl | 14 +++++ src/win32_dns.erl | 122 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 src/win32_dns.erl diff --git a/ChangeLog b/ChangeLog index e23272baa..4a07966d0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2009-03-05 Badlop + * src/ejabberd_app.erl: In a Windows machine, explicitly add the + nameservers, as it seems Erlang does not do itself (EJAB-860) + * src/win32_dns.erl: Get name servers from Windows registy (thanks + to Geoff Cant) + * doc/guide.tex: Require OpenSSL 0.9.8f or higher (EJAB-877) * doc/guide.html: Likewise diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index 41e7444d8..d109a2082 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -63,6 +63,7 @@ start(normal, _Args) -> %eprof:start(), %eprof:profile([self()]), %fprof:trace(start, "/tmp/fprof"), + maybe_add_nameservers(), start_modules(), ejabberd_listener:start_listeners(), ?INFO_MSG("ejabberd ~s is started in the node ~p", [?VERSION, node()]), @@ -180,3 +181,16 @@ get_log_path() -> Path end end. + + +%% If ejabberd is running on some Windows machine, get nameservers and add to Erlang +maybe_add_nameservers() -> + case os:type() of + {win32, _} -> add_windows_nameservers(); + _ -> ok + end. + +add_windows_nameservers() -> + IPTs = win32_dns_test:get_nameservers(), + ?INFO_MSG("Adding machine's DNS IPs to Erlang system:~n~p", [IPTs]), + lists:foreach(fun(IPT) -> inet_db:add_ns(IPT) end, IPTs). diff --git a/src/win32_dns.erl b/src/win32_dns.erl new file mode 100644 index 000000000..79725cbab --- /dev/null +++ b/src/win32_dns.erl @@ -0,0 +1,122 @@ +%%%---------------------------------------------------------------------- +%%% File : win32_dns.erl +%%% Author : Geoff Cant +%%% Purpose : Get name servers in a Windows machine +%%% Created : 5 Mar 2009 by Geoff Cant +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%%---------------------------------------------------------------------- + +-module(win32_dns). +-export([get_nameservers/0]). + +-define(IF_KEY, "\\hklm\\system\\CurrentControlSet\\Services\\TcpIp\\Parameters\\Interfaces"). +-define(TOP_KEY, "\\hklm\\system\\CurrentControlSet\\Services\\TcpIp\\Parameters"). + +get_nameservers() -> + {_, Config} = pick_config(), + IPTs = get_value(["NameServer"], Config), + lists:filter(fun(IPTuple) -> is_good_ns(IPTuple) end, IPTs). + +is_good_ns(Addr) -> + element(1, + inet_res:nnslookup("a.root-servers.net", in, any, [{Addr,53}], + timer:seconds(5) + ) + ) =:= ok. + +reg() -> + {ok, R} = win32reg:open([read]), + R. + +interfaces(R) -> + ok = win32reg:change_key(R, ?IF_KEY), + {ok, I} = win32reg:sub_keys(R), + I. +config_keys(R, Key) -> + ok = win32reg:change_key(R, Key), + [ {K, + case win32reg:value(R, K) of + {ok, V} -> translate(K, V); + _ -> undefined + end + } || K <- ["Domain", "DhcpDomain", + "NameServer", "DhcpNameServer", "SearchList"]]. + +translate(NS, V) when NS =:= "NameServer"; NS =:= "DhcpNameServer" -> + IPsStrings = [string:tokens(IP, ".") || IP <- string:tokens(V, ",")], + [ list_to_tuple([list_to_integer(String) || String <- IpStrings]) + || IpStrings <- IPsStrings]; +translate(_, V) -> V. + +interface_configs(R) -> + [{If, config_keys(R, ?IF_KEY ++ "\\" ++ If)} + || If <- interfaces(R)]. + +sort_configs(Configs) -> + lists:sort(fun ({_, A}, {_, B}) -> + ANS = proplists:get_value("NameServer", A), + BNS = proplists:get_value("NameServer", B), + if ANS =/= undefined, BNS =:= undefined -> false; + true -> count_undef(A) < count_undef(B) + end + end, + Configs). + +count_undef(L) when is_list(L) -> + lists:foldl(fun ({_K, undefined}, Acc) -> Acc +1; + ({_K, []}, Acc) -> Acc +1; + (_, Acc) -> Acc + end, 0, L). + +all_configs() -> + R = reg(), + TopConfig = config_keys(R, ?TOP_KEY), + Configs = [{top, TopConfig} + | interface_configs(R)], + win32reg:close(R), + {TopConfig, Configs}. + +pick_config() -> + {TopConfig, Configs} = all_configs(), + NSConfigs = [{If, C} || {If, C} <- Configs, + get_value(["DhcpNameServer","NameServer"], C) + =/= undefined], + case get_value(["DhcpNameServer","NameServer"], + TopConfig) of + %% No top level nameserver to pick interface with + undefined -> + hd(sort_configs(NSConfigs)); + %% Top level has a nameserver - use this to select an interface. + NS -> + Cs = [ {If, C} + || {If, C} <- Configs, + lists:member(NS, + [get_value(["NameServer"], C), + get_value(["DhcpNameServer"], C)])], + hd(sort_configs(Cs)) + end. + +get_value([], _Config) -> undefined; +get_value([K|Keys], Config) -> + case proplists:get_value(K, Config) of + undefined -> get_value(Keys, Config); + V -> V + end. From 66c60c4e6d0f8a790585137508deddd1792f5c3c Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 6 Mar 2009 11:39:12 +0000 Subject: [PATCH 249/582] Merge 1851 from trunk. * src/eldap/eldap.erl: Close a connection on tcp_error (thanks to Evgeniy Khramtsov) SVN Revision: 1972 --- ChangeLog | 5 +++++ src/eldap/eldap.erl | 25 +++++++++++++------------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4a07966d0..3cb8672d2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-03-06 Badlop + + * src/eldap/eldap.erl: Close a connection on tcp_error (thanks to + Evgeniy Khramtsov) + 2009-03-05 Badlop * src/ejabberd_app.erl: In a Windows machine, explicitly add the diff --git a/src/eldap/eldap.erl b/src/eldap/eldap.erl index 6384c87b7..799012fc5 100644 --- a/src/eldap/eldap.erl +++ b/src/eldap/eldap.erl @@ -517,22 +517,13 @@ handle_info({tcp, _Socket, Data}, StateName, S) handle_info({tcp_closed, _Socket}, Fsm_state, S) -> ?WARNING_MSG("LDAP server closed the connection: ~s:~p~nIn State: ~p", [S#eldap.host, S#eldap.port ,Fsm_state]), - F = fun(_Id, [{Timer, From, _Name}|_]) -> - gen_fsm:reply(From, {error, tcp_closed}), - cancel_timer(Timer) - end, - dict:map(F, S#eldap.dict), - {ok, NextState, NewS} = connect_bind(S#eldap{fd = null, - dict = dict:new(), - bind_q=queue:new()}), + {ok, NextState, NewS} = close_and_rebind(S, tcp_closed), {next_state, NextState, NewS}; handle_info({tcp_error, _Socket, Reason}, Fsm_state, S) -> ?DEBUG("eldap received tcp_error: ~p~nIn State: ~p", [Reason, Fsm_state]), - %% XXX wouldn't it be safer to try reconnect ? - %% if we were waiting a result, we may mait forever - %% cause request is probably lost.... - {next_state, Fsm_state, S}; + {ok, NextState, NewS} = close_and_rebind(S, tcp_error), + {next_state, NextState, NewS}; %% %% Timers @@ -1006,3 +997,13 @@ bump_id(#eldap{id = Id}) when Id > ?MAX_TRANSACTION_ID -> ?MIN_TRANSACTION_ID; bump_id(#eldap{id = Id}) -> Id + 1. + +close_and_rebind(State, Err) -> + F = fun(_Id, [{Timer, From, _Name}|_]) -> + gen_fsm:reply(From, {error, Err}), + cancel_timer(Timer) + end, + dict:map(F, State#eldap.dict), + connect_bind(State#eldap{fd = null, + dict = dict:new(), + bind_q=queue:new()}). From d23ebd354bf1eb83d43e11b7d27b8dae2be9641b Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 6 Mar 2009 11:42:56 +0000 Subject: [PATCH 250/582] Merge 1855 from trunk. * src/eldap/eldap.erl: implemented queue for pending queries (thanks to Evgeniy Khramtsov) SVN Revision: 1973 --- ChangeLog | 3 + src/eldap/eldap.erl | 208 ++++++++++++++++++++++---------------------- 2 files changed, 109 insertions(+), 102 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3cb8672d2..451eb19cc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2009-03-06 Badlop + * src/eldap/eldap.erl: implemented queue for pending + queries (thanks to Evgeniy Khramtsov) + * src/eldap/eldap.erl: Close a connection on tcp_error (thanks to Evgeniy Khramtsov) diff --git a/src/eldap/eldap.erl b/src/eldap/eldap.erl index 799012fc5..24e234cf7 100644 --- a/src/eldap/eldap.erl +++ b/src/eldap/eldap.erl @@ -85,6 +85,10 @@ -define(RETRY_TIMEOUT, 500). -define(BIND_TIMEOUT, 10000). -define(CMD_TIMEOUT, 100000). +%% Used in gen_fsm sync calls. +-define(CALL_TIMEOUT, ?CMD_TIMEOUT + ?BIND_TIMEOUT + ?RETRY_TIMEOUT). +%% Used as a timeout for gen_tcp:send/2 +-define(SEND_TIMEOUT, 30000). -define(MAX_TRANSACTION_ID, 65535). -define(MIN_TRANSACTION_ID, 0). @@ -98,7 +102,7 @@ id = 0, % LDAP Request ID bind_timer, % Ref to bind timeout dict, % dict holding operation params and results - bind_q % Queue for bind() requests + req_q % Queue for requests }). %%%---------------------------------------------------------------------- @@ -141,7 +145,8 @@ close(Handle) -> %%% -------------------------------------------------------------------- add(Handle, Entry, Attributes) when list(Entry),list(Attributes) -> Handle1 = get_handle(Handle), - gen_fsm:sync_send_event(Handle1, {add, Entry, add_attrs(Attributes)}). + gen_fsm:sync_send_event(Handle1, {add, Entry, add_attrs(Attributes)}, + ?CALL_TIMEOUT). %%% Do sanity check ! add_attrs(Attrs) -> @@ -166,7 +171,7 @@ add_attrs(Attrs) -> %%% -------------------------------------------------------------------- delete(Handle, Entry) when list(Entry) -> Handle1 = get_handle(Handle), - gen_fsm:sync_send_event(Handle1, {delete, Entry}). + gen_fsm:sync_send_event(Handle1, {delete, Entry}, ?CALL_TIMEOUT). %%% -------------------------------------------------------------------- %%% Modify an entry. Given an entry a number of modification @@ -181,7 +186,7 @@ delete(Handle, Entry) when list(Entry) -> %%% -------------------------------------------------------------------- modify(Handle, Object, Mods) when list(Object), list(Mods) -> Handle1 = get_handle(Handle), - gen_fsm:sync_send_event(Handle1, {modify, Object, Mods}). + gen_fsm:sync_send_event(Handle1, {modify, Object, Mods}, ?CALL_TIMEOUT). %%% %%% Modification operations. @@ -214,7 +219,10 @@ m(Operation, Type, Values) -> modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup) when list(Entry),list(NewRDN),atom(DelOldRDN),list(NewSup) -> Handle1 = get_handle(Handle), - gen_fsm:sync_send_event(Handle1, {modify_dn, Entry, NewRDN, bool_p(DelOldRDN), optional(NewSup)}). + gen_fsm:sync_send_event( + Handle1, + {modify_dn, Entry, NewRDN, bool_p(DelOldRDN), optional(NewSup)}, + ?CALL_TIMEOUT). %%% -------------------------------------------------------------------- @@ -228,7 +236,7 @@ modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup) bind(Handle, RootDN, Passwd) when list(RootDN),list(Passwd) -> Handle1 = get_handle(Handle), - gen_fsm:sync_send_event(Handle1, {bind, RootDN, Passwd}, infinity). + gen_fsm:sync_send_event(Handle1, {bind, RootDN, Passwd}, ?CALL_TIMEOUT). %%% Sanity checks ! @@ -273,7 +281,7 @@ search(Handle, L) when list(L) -> call_search(Handle, A) -> Handle1 = get_handle(Handle), - gen_fsm:sync_send_event(Handle1, {search, A}, infinity). + gen_fsm:sync_send_event(Handle1, {search, A}, ?CALL_TIMEOUT). parse_search_args(Args) -> parse_search_args(Args, #eldap_search{scope = wholeSubtree}). @@ -382,7 +390,7 @@ init({Hosts, Port, Rootdn, Passwd}) -> passwd = Passwd, id = 0, dict = dict:new(), - bind_q = queue:new()}, 0}. + req_q = queue:new()}, 0}. %%---------------------------------------------------------------------- %% Func: StateName/2 @@ -405,38 +413,20 @@ connecting(timeout, S) -> %% {stop, Reason, NewStateData} | %% {stop, Reason, Reply, NewStateData} %%---------------------------------------------------------------------- -connecting(_Event, _From, S) -> - Reply = {error, connecting}, - {reply, Reply, connecting, S}. +connecting(Event, From, S) -> + Q = queue:in({Event, From}, S#eldap.req_q), + {next_state, connecting, S#eldap{req_q=Q}}. -wait_bind_response(_Event, _From, S) -> - Reply = {error, wait_bind_response}, - {reply, Reply, wait_bind_response, S}. +wait_bind_response(Event, From, S) -> + Q = queue:in({Event, From}, S#eldap.req_q), + {next_state, wait_bind_response, S#eldap{req_q=Q}}. + +active_bind(Event, From, S) -> + Q = queue:in({Event, From}, S#eldap.req_q), + {next_state, active_bind, S#eldap{req_q=Q}}. active(Event, From, S) -> - case catch send_command(Event, From, S) of - {ok, NewS} -> - case Event of - {bind, _, _} -> - {next_state, active_bind, NewS}; - _ -> - {next_state, active, NewS} - end; - {error, Reason} -> - {reply, {error, Reason}, active, S}; - {'EXIT', Reason} -> - {reply, {error, Reason}, active, S} - end. - -active_bind({bind, RootDN, Passwd}, From, #eldap{bind_q=Q} = S) -> - NewQ = queue:in({{bind, RootDN, Passwd}, From}, Q), - {next_state, active_bind, S#eldap{bind_q=NewQ}}; -active_bind(Event, From, S) -> - case catch send_command(Event, From, S) of - {ok, NewS} -> {next_state, active_bind, NewS}; - {error, Reason} -> {reply, {error, Reason}, active_bind, S}; - {'EXIT', Reason} -> {reply, {error, Reason}, active_bind, S} - end. + process_command(S, Event, From). %%---------------------------------------------------------------------- %% Func: handle_event/3 @@ -446,21 +436,8 @@ active_bind(Event, From, S) -> %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- handle_event(close, _StateName, S) -> - gen_tcp:close(S#eldap.fd), - {stop, closed, S}; - -handle_event(process_bind_q, active_bind, #eldap{bind_q=Q} = S) -> - case queue:out(Q) of - {{value, {BindEvent, To}}, NewQ} -> - NewStateData = case catch send_command(BindEvent, To, S) of - {ok, NewS} -> NewS; - {error, Reason} -> gen_fsm:reply(To, {error, Reason}), S; - {'EXIT', Reason} -> gen_fsm:reply(To, {error, Reason}), S - end, - {next_state, active_bind, NewStateData#eldap{bind_q=NewQ}}; - {empty, Q} -> - {next_state, active, S} - end; + catch gen_tcp:close(S#eldap.fd), + {stop, normal, S}; handle_event(_Event, StateName, S) -> {next_state, StateName, S}. @@ -489,50 +466,61 @@ handle_sync_event(_Event, _From, StateName, S) -> %% Packets arriving in various states %% handle_info({tcp, _Socket, Data}, connecting, S) -> - ?DEBUG("eldap. tcp packet received when disconnected!~n~p", [Data]), + ?DEBUG("tcp packet received when disconnected!~n~p", [Data]), {next_state, connecting, S}; handle_info({tcp, _Socket, Data}, wait_bind_response, S) -> cancel_timer(S#eldap.bind_timer), case catch recvd_wait_bind_response(Data, S) of - bound -> {next_state, active, S}; - {fail_bind, _Reason} -> close_and_retry(S), - {next_state, connecting, S#eldap{fd = null}}; - {'EXIT', _Reason} -> close_and_retry(S), - {next_state, connecting, S#eldap{fd = null}}; - {error, _Reason} -> close_and_retry(S), - {next_state, connecting, S#eldap{fd = null}} + bound -> + dequeue_commands(S); + {fail_bind, _Reason} -> + {next_state, connecting, close_and_retry(S)}; + {'EXIT', _Reason} -> + {next_state, connecting, close_and_retry(S)}; + {error, _Reason} -> + {next_state, connecting, close_and_retry(S)} end; handle_info({tcp, _Socket, Data}, StateName, S) - when StateName==active; StateName==active_bind -> + when StateName == active orelse StateName == active_bind -> case catch recvd_packet(Data, S) of - {reply, Reply, To, NewS} -> gen_fsm:reply(To, Reply), - {next_state, StateName, NewS}; - {ok, NewS} -> {next_state, StateName, NewS}; - {'EXIT', _Reason} -> {next_state, StateName, S}; - {error, _Reason} -> {next_state, StateName, S} + {response, Response, RequestType} -> + NewS = case Response of + {reply, Reply, To, S1} -> + gen_fsm:reply(To, Reply), + S1; + {ok, S1} -> + S1 + end, + if (StateName == active_bind andalso + RequestType == bindRequest) orelse + (StateName == active) -> + dequeue_commands(NewS); + true -> + {next_state, StateName, NewS} + end; + _ -> + {next_state, StateName, S} end; handle_info({tcp_closed, _Socket}, Fsm_state, S) -> ?WARNING_MSG("LDAP server closed the connection: ~s:~p~nIn State: ~p", [S#eldap.host, S#eldap.port ,Fsm_state]), - {ok, NextState, NewS} = close_and_rebind(S, tcp_closed), - {next_state, NextState, NewS}; + {next_state, connecting, close_and_retry(S)}; handle_info({tcp_error, _Socket, Reason}, Fsm_state, S) -> ?DEBUG("eldap received tcp_error: ~p~nIn State: ~p", [Reason, Fsm_state]), - {ok, NextState, NewS} = close_and_rebind(S, tcp_error), - {next_state, NextState, NewS}; + {next_state, connecting, close_and_retry(S)}; %% %% Timers %% -handle_info({timeout, Timer, {cmd_timeout, Id}}, active, S) -> +handle_info({timeout, Timer, {cmd_timeout, Id}}, StateName, S) -> case cmd_timeout(Timer, Id, S) of {reply, To, Reason, NewS} -> gen_fsm:reply(To, Reason), - {next_state, active, NewS}; - {error, _Reason} -> {next_state, active, S} + {next_state, StateName, NewS}; + {error, _Reason} -> {next_state, StateName, S} end; handle_info({timeout, retry_connect}, connecting, S) -> @@ -540,8 +528,7 @@ handle_info({timeout, retry_connect}, connecting, S) -> {next_state, NextState, NewS}; handle_info({timeout, _Timer, bind_timeout}, wait_bind_response, S) -> - close_and_retry(S), - {next_state, connecting, S#eldap{fd = null}}; + {next_state, connecting, close_and_retry(S)}; %% %% Make sure we don't fill the message queue with rubbish @@ -570,6 +557,34 @@ code_change(_OldVsn, StateName, S, _Extra) -> %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- +dequeue_commands(S) -> + case queue:out(S#eldap.req_q) of + {{value, {Event, From}}, Q} -> + case process_command(S#eldap{req_q=Q}, Event, From) of + {_, active, NewS} -> + dequeue_commands(NewS); + Res -> + Res + end; + {empty, _} -> + {next_state, active, S} + end. + +process_command(S, Event, From) -> + case send_command(Event, From, S) of + {ok, NewS} -> + case Event of + {bind, _, _} -> + {next_state, active_bind, NewS}; + _ -> + {next_state, active, NewS} + end; + {error, _Reason} -> + Q = queue:in_r({Event, From}, S#eldap.req_q), + NewS = close_and_retry(S#eldap{req_q=Q}), + {next_state, connecting, NewS} + end. + send_command(Command, From, S) -> Id = bump_id(S), {Name, Request} = gen_req(Command), @@ -640,6 +655,7 @@ recvd_packet(Pkt, S) -> Dict = S#eldap.dict, Id = Msg#'LDAPMessage'.messageID, {Timer, From, Name, Result_so_far} = get_op_rec(Id, Dict), + Answer = case {Name, Op} of {searchRequest, {searchResEntry, R}} when record(R,'SearchResultEntry') -> @@ -687,14 +703,14 @@ recvd_packet(Pkt, S) -> New_dict = dict:erase(Id, Dict), cancel_timer(Timer), Reply = check_bind_reply(Result, From), - gen_fsm:send_all_state_event(self(), process_bind_q), {reply, Reply, From, S#eldap{dict = New_dict}}; {OtherName, OtherResult} -> New_dict = dict:erase(Id, Dict), cancel_timer(Timer), {reply, {error, {invalid_result, OtherName, OtherResult}}, From, S#eldap{dict = New_dict}} - end; + end, + {response, Answer, Name}; Error -> Error end. @@ -775,13 +791,9 @@ check_tag(Data) -> end. close_and_retry(S) -> - gen_tcp:close(S#eldap.fd), - retry_connect(). - -retry_connect() -> - erlang:send_after(?RETRY_TIMEOUT, self(), - {timeout, retry_connect}). - + catch gen_tcp:close(S#eldap.fd), + erlang:send_after(?RETRY_TIMEOUT, self(), {timeout, retry_connect}), + S#eldap{fd = null}. %%----------------------------------------------------------------------- %% Sort out timed out commands @@ -832,7 +844,8 @@ polish([], Res, Ref) -> %%----------------------------------------------------------------------- connect_bind(S) -> Host = next_host(S#eldap.host, S#eldap.hosts), - TcpOpts = [{packet, asn1}, {active, true}, {keepalive, true}, binary], + TcpOpts = [{packet, asn1}, {active, true}, {keepalive, true}, + {send_timeout, ?SEND_TIMEOUT}, binary], ?INFO_MSG("LDAP connection on ~s:~p", [Host, S#eldap.port]), case gen_tcp:connect(Host, S#eldap.port, TcpOpts) of {ok, Socket} -> @@ -844,15 +857,16 @@ connect_bind(S) -> host = Host, bind_timer = Timer}}; {error, Reason} -> - ?ERROR_MSG("LDAP bind failed on ~s:~p~nReason: ~p", [Host, S#eldap.port, Reason]), - gen_tcp:close(Socket), - retry_connect(), - {ok, connecting, S#eldap{host = Host}} + ?ERROR_MSG("LDAP bind failed on ~s:~p~nReason: ~p", + [Host, S#eldap.port, Reason]), + NewS = close_and_retry(S), + {ok, connecting, NewS#eldap{host = Host}} end; {error, Reason} -> - ?ERROR_MSG("LDAP connection failed on ~s:~p~nReason: ~p", [Host, S#eldap.port, Reason]), - retry_connect(), - {ok, connecting, S#eldap{host = Host}} + ?ERROR_MSG("LDAP connection failed on ~s:~p~nReason: ~p", + [Host, S#eldap.port, Reason]), + NewS = close_and_retry(S), + {ok, connecting, NewS#eldap{host = Host}} end. bind_request(Socket, S) -> @@ -997,13 +1011,3 @@ bump_id(#eldap{id = Id}) when Id > ?MAX_TRANSACTION_ID -> ?MIN_TRANSACTION_ID; bump_id(#eldap{id = Id}) -> Id + 1. - -close_and_rebind(State, Err) -> - F = fun(_Id, [{Timer, From, _Name}|_]) -> - gen_fsm:reply(From, {error, Err}), - cancel_timer(Timer) - end, - dict:map(F, State#eldap.dict), - connect_bind(State#eldap{fd = null, - dict = dict:new(), - bind_q=queue:new()}). From cf4b7b36ee09f44457b747f32771248c159e7add Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 6 Mar 2009 11:50:23 +0000 Subject: [PATCH 251/582] Merge 1856 from trunk. * src/eldap/eldap.erl: moves waiting for response queries to pending queue on an LDAP connection failure (thanks to Evgeniy Khramtsov) SVN Revision: 1974 --- ChangeLog | 4 ++++ src/eldap/eldap.erl | 15 +++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 451eb19cc..224aa8ec4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2009-03-06 Badlop + * src/eldap/eldap.erl: moves waiting for response queries to + pending queue on an LDAP connection failure (thanks to Evgeniy + Khramtsov) + * src/eldap/eldap.erl: implemented queue for pending queries (thanks to Evgeniy Khramtsov) diff --git a/src/eldap/eldap.erl b/src/eldap/eldap.erl index 24e234cf7..412a66862 100644 --- a/src/eldap/eldap.erl +++ b/src/eldap/eldap.erl @@ -595,7 +595,7 @@ send_command(Command, From, S) -> case gen_tcp:send(S#eldap.fd, Bytes) of ok -> Timer = erlang:start_timer(?CMD_TIMEOUT, self(), {cmd_timeout, Id}), - New_dict = dict:store(Id, [{Timer, From, Name}], S#eldap.dict), + New_dict = dict:store(Id, [{Timer, Command, From, Name}], S#eldap.dict), {ok, S#eldap{id = Id, dict = New_dict}}; Error -> Error @@ -730,7 +730,7 @@ check_bind_reply(Other, _From) -> get_op_rec(Id, Dict) -> case dict:find(Id, Dict) of - {ok, [{Timer, From, Name}|Res]} -> + {ok, [{Timer, _Command, From, Name}|Res]} -> {Timer, From, Name, Res}; error -> throw({error, unkown_id}) @@ -792,8 +792,15 @@ check_tag(Data) -> close_and_retry(S) -> catch gen_tcp:close(S#eldap.fd), + Queue = dict:fold( + fun(_Id, [{Timer, Command, From, _Name}|_], Q) -> + cancel_timer(Timer), + queue:in_r({Command, From}, Q); + (_, _, Q) -> + Q + end, S#eldap.req_q, S#eldap.dict), erlang:send_after(?RETRY_TIMEOUT, self(), {timeout, retry_connect}), - S#eldap{fd = null}. + S#eldap{fd=null, req_q=Queue, dict=dict:new()}. %%----------------------------------------------------------------------- %% Sort out timed out commands @@ -801,7 +808,7 @@ close_and_retry(S) -> cmd_timeout(Timer, Id, S) -> Dict = S#eldap.dict, case dict:find(Id, Dict) of - {ok, [{Timer, From, Name}|Res]} -> + {ok, [{Timer, _Command, From, Name}|Res]} -> case Name of searchRequest -> {Res1, Ref1} = polish(Res), From d6820f2c2dd1132c53530cf8402b05a63446a8a0 Mon Sep 17 00:00:00 2001 From: Badlop Date: Sat, 7 Mar 2009 08:53:34 +0000 Subject: [PATCH 252/582] * src/mod_privacy.erl: Temporary workaround to inconsistency * src/mod_privacy_odbc.erl: Likewise SVN Revision: 1975 --- ChangeLog | 5 +++++ src/mod_privacy.erl | 23 +++++------------------ src/mod_privacy_odbc.erl | 23 +++++------------------ 3 files changed, 15 insertions(+), 36 deletions(-) diff --git a/ChangeLog b/ChangeLog index 224aa8ec4..fb795ab15 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-03-07 Badlop + + * src/mod_privacy.erl: Temporary workaround to inconsistency + * src/mod_privacy_odbc.erl: Likewise + 2009-03-06 Badlop * src/eldap/eldap.erl: moves waiting for response queries to diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 2ef8e7a49..03f042aa3 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -655,27 +655,14 @@ is_ptype_match(Item, PType) -> end. +%% TODO: Investigate this: sometimes Value has binaries, other times has strings is_type_match(Type, Value, JID, Subscription, Groups) -> case Type of jid -> - case Value of - {undefined, Server, undefined} -> - case JID of - {_, Server, _} -> - true; - _ -> - false - end; - {User, Server, undefined} -> - case JID of - {User, Server, _} -> - true; - _ -> - false - end; - _ -> - Value == JID - end; + {User, Server, Resource} = Value, + ((User == undefined) orelse (User == []) orelse (User == exmpp_jid:lnode(JID))) + andalso ((Server == undefined) orelse (Server == []) orelse (Server == exmpp_jid:ldomain(JID))) + andalso ((Resource == undefined) orelse (Resource == []) orelse (Resource == exmpp_jid:lresource(JID))); subscription -> Value == Subscription; group -> diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 90fb41e62..42e84e520 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -654,27 +654,14 @@ is_ptype_match(Item, PType) -> end. +%% TODO: Investigate this: sometimes Value has binaries, other times has strings is_type_match(Type, Value, JID, Subscription, Groups) -> case Type of jid -> - case Value of - {undefined, Server, undefined} -> - case JID of - {_, Server, _} -> - true; - _ -> - false - end; - {User, Server, undefined} -> - case JID of - {User, Server, _} -> - true; - _ -> - false - end; - _ -> - Value == JID - end; + {User, Server, Resource} = Value, + ((User == undefined) orelse (User == []) orelse (User == exmpp_jid:lnode(JID))) + andalso ((Server == undefined) orelse (Server == []) orelse (Server == exmpp_jid:ldomain(JID))) + andalso ((Resource == undefined) orelse (Resource == []) orelse (Resource == exmpp_jid:lresource(JID))); subscription -> Value == Subscription; group -> From 56c33e994d3d18803365aed342e4bcaa92d9a84d Mon Sep 17 00:00:00 2001 From: Badlop Date: Sat, 7 Mar 2009 08:59:26 +0000 Subject: [PATCH 253/582] * src/ejabberd_c2s.erl: Enforce privacy rules also for subscription requests (EJAB-300) * src/ejabberd_sm.erl: Likewise SVN Revision: 1976 --- ChangeLog | 4 ++++ src/ejabberd_c2s.erl | 47 ++++++++++++++++++++++++++++++++++++++++---- src/ejabberd_sm.erl | 29 ++++----------------------- 3 files changed, 51 insertions(+), 29 deletions(-) diff --git a/ChangeLog b/ChangeLog index fb795ab15..b7ce1d28b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2009-03-07 Badlop + * src/ejabberd_c2s.erl: Enforce privacy rules also for + subscription requests (EJAB-300) + * src/ejabberd_sm.erl: Likewise + * src/mod_privacy.erl: Temporary workaround to inconsistency * src/mod_privacy_odbc.erl: Likewise diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 6fd3254a4..d7aca754b 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1039,13 +1039,22 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> 'unavailable'), {true, Attrs1, StateData}; 'subscribe' -> - {true, Attrs, StateData}; + Reason = exmpp_presence:get_status(Packet), + SRes = check_privacy_subs(in, subscribe, From, To, + Packet, Reason, StateData), + {SRes, Attrs, StateData}; 'subscribed' -> - {true, Attrs, StateData}; + SRes = check_privacy_subs(in, subscribed, From, To, + Packet, <<>>, StateData), + {SRes, Attrs, StateData}; 'unsubscribe' -> - {true, Attrs, StateData}; + SRes = check_privacy_subs(in, unsubscribe, From, To, + Packet, <<>>, StateData), + {SRes, Attrs, StateData}; 'unsubscribed' -> - {true, Attrs, StateData}; + SRes = check_privacy_subs(in, unsubscribed, From, To, + Packet, <<>>, StateData), + {SRes, Attrs, StateData}; _ -> case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, @@ -1571,6 +1580,36 @@ check_privacy_route(From, StateData, FromRoute, To, Packet) -> ejabberd_router:route(FromRoute, To, Packet) end. +%% Check privacy rules for subscription requests and call the roster storage +check_privacy_subs(Dir, Type, From, To, Packet, Reason, StateData) -> + case is_privacy_allow(From, To, Dir, Packet, StateData) of + true -> + ejabberd_hooks:run_fold( + roster_in_subscription, + exmpp_jid:ldomain(To), + false, + [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, Type, Reason]), + true; + false -> + false + end. + +%% Check if privacy rules allow this delivery, then push to roster +is_privacy_allow(From, To, Dir, Packet, StateData) -> + case ejabberd_hooks:run_fold( + privacy_check_packet, StateData#state.server, + allow, + [StateData#state.user, + StateData#state.server, + StateData#state.privacy_list, + {From, To, Packet}, + Dir]) of + deny -> + false; + allow -> + true + end. + presence_broadcast(StateData, From, JIDSet, Packet) -> lists:foreach(fun({U, S, R}) -> FJID = exmpp_jid:make_jid(U, S, R), diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index ff857fc5c..8d2dbeb33 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -422,34 +422,13 @@ do_route(From, To, Packet) -> {Pass, _Subsc} = case exmpp_presence:get_type(Packet) of 'subscribe' -> - Reason = exmpp_presence:get_status(Packet), - {ejabberd_hooks:run_fold( - roster_in_subscription, - exmpp_jid:ldomain(To), - false, - [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, subscribe, Reason]), - true}; + {true, true}; 'subscribed' -> - {ejabberd_hooks:run_fold( - roster_in_subscription, - exmpp_jid:ldomain(To), - false, - [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, subscribed, <<>>]), - true}; + {true, true}; 'unsubscribe' -> - {ejabberd_hooks:run_fold( - roster_in_subscription, - exmpp_jid:ldomain(To), - false, - [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, unsubscribe, <<>>]), - true}; + {true, true}; 'unsubscribed' -> - {ejabberd_hooks:run_fold( - roster_in_subscription, - exmpp_jid:ldomain(To), - false, - [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, unsubscribed, <<>>]), - true}; + {true, true}; _ -> {true, false} end, From ed3cae6f11726c78a42bad548ae9be8d8b72c0fb Mon Sep 17 00:00:00 2001 From: Badlop Date: Sat, 7 Mar 2009 09:52:26 +0000 Subject: [PATCH 254/582] * src/Makefile.in: In SunOS, use different C flags (thanks to Thomas)(EJAB-438) * src/ejabberd_zlib/Makefile.in: Likewise * src/mod_irc/Makefile.in: Likewise * src/stringprep/Makefile.in: Likewise * src/tls/Makefile.in: Likewise SVN Revision: 1977 --- ChangeLog | 7 +++++++ src/Makefile.in | 8 +++++--- src/ejabberd_zlib/Makefile.in | 10 ++++++---- src/mod_irc/Makefile.in | 11 +++++++---- src/stringprep/Makefile.in | 11 +++++++---- src/tls/Makefile.in | 10 ++++++---- 6 files changed, 38 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index b7ce1d28b..c833cd6eb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2009-03-07 Badlop + * src/Makefile.in: In SunOS, use different C flags (thanks to + Thomas)(EJAB-438) + * src/ejabberd_zlib/Makefile.in: Likewise + * src/mod_irc/Makefile.in: Likewise + * src/stringprep/Makefile.in: Likewise + * src/tls/Makefile.in: Likewise + * src/ejabberd_c2s.erl: Enforce privacy rules also for subscription requests (EJAB-300) * src/ejabberd_sm.erl: Likewise diff --git a/src/Makefile.in b/src/Makefile.in index ac9412a17..1728e12f3 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -114,11 +114,13 @@ COOKIEFILE = $(SPOOLDIR)/.erlang.cookie # /var/log/ejabberd/ LOGDIR = $(DESTDIR)@localstatedir@/log/ejabberd -ifeq ($(shell uname),Darwin) -DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress -else # Assume Linux-style dynamic library flags DYNAMIC_LIB_CFLAGS = -fpic -shared +ifeq ($(shell uname),Darwin) + DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress +endif +ifeq ($(shell uname),SunOs) + DYNAMIC_LIB_CFLAGS = -KPIC -G -z text endif all: $(ERLSHLIBS) compile-beam all-recursive diff --git a/src/ejabberd_zlib/Makefile.in b/src/ejabberd_zlib/Makefile.in index dd781d0ae..b572c1169 100644 --- a/src/ejabberd_zlib/Makefile.in +++ b/src/ejabberd_zlib/Makefile.in @@ -12,11 +12,13 @@ ZLIB_LIBS = @ZLIB_LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ +# Assume Linux-style dynamic library flags +DYNAMIC_LIB_CFLAGS = -fpic -shared ifeq ($(shell uname),Darwin) - DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress -else - # Assume Linux-style dynamic library flags - DYNAMIC_LIB_CFLAGS = -fpic -shared + DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress +endif +ifeq ($(shell uname),SunOs) + DYNAMIC_LIB_CFLAGS = -KPIC -G -z text endif EFLAGS += -I .. diff --git a/src/mod_irc/Makefile.in b/src/mod_irc/Makefile.in index 76a2d57f6..9dcf9f182 100644 --- a/src/mod_irc/Makefile.in +++ b/src/mod_irc/Makefile.in @@ -9,12 +9,15 @@ LIBS = @LIBS@ @LIBICONV@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ +# Assume Linux-style dynamic library flags +DYNAMIC_LIB_CFLAGS = -fpic -shared ifeq ($(shell uname),Darwin) - DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress -else - # Assume Linux-style dynamic library flags - DYNAMIC_LIB_CFLAGS = -fpic -shared + DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress endif +ifeq ($(shell uname),SunOs) + DYNAMIC_LIB_CFLAGS = -KPIC -G -z text +endif + EFLAGS += -I .. EFLAGS += -pz .. diff --git a/src/stringprep/Makefile.in b/src/stringprep/Makefile.in index 3ac6c24db..7c4997d26 100644 --- a/src/stringprep/Makefile.in +++ b/src/stringprep/Makefile.in @@ -9,12 +9,15 @@ LIBS = @LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ +# Assume Linux-style dynamic library flags +DYNAMIC_LIB_CFLAGS = -fpic -shared ifeq ($(shell uname),Darwin) - DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress -else - # Assume Linux-style dynamic library flags - DYNAMIC_LIB_CFLAGS = -fpic -shared + DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress endif +ifeq ($(shell uname),SunOs) + DYNAMIC_LIB_CFLAGS = -KPIC -G -z text +endif + EFLAGS += -I .. EFLAGS += -pz .. diff --git a/src/tls/Makefile.in b/src/tls/Makefile.in index b6f10efc2..44142fa7e 100644 --- a/src/tls/Makefile.in +++ b/src/tls/Makefile.in @@ -12,11 +12,13 @@ SSL_LIBS = @SSL_LIBS@ ERLANG_CFLAGS = @ERLANG_CFLAGS@ ERLANG_LIBS = @ERLANG_LIBS@ +# Assume Linux-style dynamic library flags +DYNAMIC_LIB_CFLAGS = -fpic -shared ifeq ($(shell uname),Darwin) - DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress -else - # Assume Linux-style dynamic library flags - DYNAMIC_LIB_CFLAGS = -fpic -shared + DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress +endif +ifeq ($(shell uname),SunOs) + DYNAMIC_LIB_CFLAGS = -KPIC -G -z text endif EFLAGS += -I .. From 4dde341c9d67c9d9fbdf2027f5fdda8c7e27ca74 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 9 Mar 2009 14:44:46 +0000 Subject: [PATCH 255/582] Merge 1925 from trunk. * src/mod_proxy65/mod_proxy65_service.erl: if an ip option is not defined, the module takes an IP address of a local hostname (thanks to Evgeniy Khramtsov) SVN Revision: 1978 --- ChangeLog | 6 +++++ src/mod_proxy65/mod_proxy65_service.erl | 30 +++++++++++-------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index c833cd6eb..d2baefebb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-03-09 Badlop + + * src/mod_proxy65/mod_proxy65_service.erl: if an ip option is not + defined, the module takes an IP address of a local + hostname (thanks to Evgeniy Khramtsov) + 2009-03-07 Badlop * src/Makefile.in: In SunOS, use different C flags (thanks to diff --git a/src/mod_proxy65/mod_proxy65_service.erl b/src/mod_proxy65/mod_proxy65_service.erl index 3f9ba61c8..372e2d7a9 100644 --- a/src/mod_proxy65/mod_proxy65_service.erl +++ b/src/mod_proxy65/mod_proxy65_service.erl @@ -223,26 +223,22 @@ parse_options(ServerHost, Opts) -> ACL = gen_mod:get_opt(access, Opts, all), Name = gen_mod:get_opt(name, Opts, "SOCKS5 Bytestreams"), IP = case gen_mod:get_opt(ip, Opts, none) of - none -> get_proxy_or_domainip(ServerHost, MyHost); - Addr -> Addr - end, + none -> get_my_ip(); + Addr -> Addr + end, StrIP = inet_parse:ntoa(IP), StreamAddr = [?XMLATTR('jid', MyHost), ?XMLATTR('host', StrIP), ?XMLATTR('port', Port)], #state{myhost = MyHost, - serverhost = ServerHost, - name = Name, - port = Port, - ip = IP, - stream_addr = StreamAddr, - acl = ACL}. + serverhost = ServerHost, + name = Name, + port = Port, + ip = IP, + stream_addr = StreamAddr, + acl = ACL}. -%% Return the IP of the proxy host, or if not found, the ip of the xmpp domain -get_proxy_or_domainip(ServerHost, MyHost) -> - case inet:getaddr(MyHost, inet) of +get_my_ip() -> + {ok, MyHostName} = inet:gethostname(), + case inet:getaddr(MyHostName, inet) of {ok, Addr} -> Addr; - {error, _} -> - case inet:getaddr(ServerHost, inet) of - {ok, Addr} -> Addr; - {error, _} -> {127,0,0,1} - end + {error, _} -> {127,0,0,1} end. From 4c08e65fabe9c641855b86481b4675c28d039b75 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 9 Mar 2009 19:17:53 +0000 Subject: [PATCH 256/582] * src/tls/tls_drv.c: Fix to support OpenSSL older than 0.9.8f (EJAB-877)(thanks to Jonathan Schleifer) * doc/guide.tex: It is again supported OpenSSL older than 0.9.8f * doc/guide.html: Likewise SVN Revision: 1979 --- ChangeLog | 5 +++++ doc/guide.html | 14 +++++++------- doc/guide.tex | 14 +++++++------- src/tls/tls_drv.c | 4 ++++ 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index d2baefebb..af9a88f5c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2009-03-09 Badlop + * src/tls/tls_drv.c: Fix to support OpenSSL older than + 0.9.8f (EJAB-877)(thanks to Jonathan Schleifer) + * doc/guide.tex: It is again supported OpenSSL older than 0.9.8f + * doc/guide.html: Likewise + * src/mod_proxy65/mod_proxy65_service.erl: if an ip option is not defined, the module takes an IP address of a local hostname (thanks to Evgeniy Khramtsov) diff --git a/doc/guide.html b/doc/guide.html index 377dbbdb3..631ae306d 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -331,7 +331,7 @@ GNU Make
    • GCC
    • Libexpat 1.95 or higher
    • Erlang/OTP R10B-9 or higher. -
    • OpenSSL 0.9.8f or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended. +
    • OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended.
    • Zlib 1.2.3 or higher, for Stream Compression support (XEP-0138). Optional.
    • Erlang mysql library. Optional. For MySQL authentication or storage. See section 3.2.1.
    • Erlang pgsql library. Optional. For PostgreSQL authentication or storage. See section 3.2.3. @@ -455,7 +455,7 @@ MS Visual C++ 6.0 Compiler
    • Expat 2.0.0 or higher
    • GNU Iconv 1.9.2 (optional) -
    • Shining Light OpenSSL 0.9.8f or higher +
    • Shining Light OpenSSL 0.9.8d or higher (to enable SSL connections)
    • Zlib 1.2.3 or higher
    • @@ -1305,7 +1305,7 @@ if you define several domains in ejabberd.cfg (see section you probably want that each virtual host uses a different configuration of database, authentication and storage, so that usernames do not conflict and mix between different virtual hosts. For that purpose, the options described in the next sections -must be set inside a host_cofig for each vhost (see section 3.1.2). +must be set inside a host_config for each vhost (see section 3.1.2). For example:

      {host_config, "public.example.org", [
         {odbc_server, {pgsql, "localhost", "database-public-example-org", "ejabberd", "password"}},
      @@ -2510,7 +2510,7 @@ In the body you can set a newline with the characters: \n
       list of JIDs which will be notified each time a new account is registered.
       
      iqdisc
      This specifies the processing discipline for In-Band Registration (jabber:iq:register) IQ queries (see section 3.3.2). -

      This module reads also another option defined globably for the server: +

      This module reads also another option defined globally for the server: {registration_timeout, Timeout}. This option limits the frequency of registration from a given IP or username. So, a user can’t register a new account from the same IP address or JID during @@ -2976,7 +2976,7 @@ they are automatically renamed to "*-old.log". See section restore ejabberd.backup

      Restore immediately from a binary backup file the internal Mnesia database. -This will comsume quite some memory for big servers. +This will consume quite some memory for big servers.
      install-fallback ejabberd.backup
      The binary backup file is installed as fallback: it will be used to restore the database at the next ejabberd start. @@ -2998,9 +2998,9 @@ This allows to administer a remote node.

      The ejabberdctl script c This file includes detailed information about each configurable option.

      The ejabberdctl script returns a numerical status code. Success is represented by 0, error is represented by 1, -and other codes may be used for specifical results. +and other codes may be used for specific results. This can be used by other scripts to determine automatically -if a command succedded or failed, +if a command succeeded or failed, for example using: echo $?

      4.1.2  Erlang Runtime System

      ejabberd is an Erlang/OTP application that runs inside an Erlang runtime system. This system is configured using environment variables and command line parameters. diff --git a/doc/guide.tex b/doc/guide.tex index 57e37a794..1c3df924e 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -299,7 +299,7 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need: \item GCC \item Libexpat 1.95 or higher \item Erlang/OTP R10B-9 or higher. -\item OpenSSL 0.9.8f or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended. +\item OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended. \item Zlib 1.2.3 or higher, for Stream Compression support (\xepref{0138}). Optional. \item Erlang mysql library. Optional. For MySQL authentication or storage. See section \ref{compilemysql}. \item Erlang pgsql library. Optional. For PostgreSQL authentication or storage. See section \ref{compilepgsql}. @@ -488,7 +488,7 @@ To compile \ejabberd{} on a Microsoft Windows system, you need: \item \footahref{http://www.gnu.org/software/libiconv/}{GNU Iconv 1.9.2} (optional) -\item \footahref{http://www.slproweb.com/products/Win32OpenSSL.html}{Shining Light OpenSSL 0.9.8f or higher} +\item \footahref{http://www.slproweb.com/products/Win32OpenSSL.html}{Shining Light OpenSSL 0.9.8d or higher} (to enable SSL connections) \item \footahref{http://www.zlib.net/}{Zlib 1.2.3 or higher} \end{itemize} @@ -1672,7 +1672,7 @@ if you define several domains in ejabberd.cfg (see section \ref{hostnames}), you probably want that each virtual host uses a different configuration of database, authentication and storage, so that usernames do not conflict and mix between different virtual hosts. For that purpose, the options described in the next sections -must be set inside a \term{host\_cofig} for each vhost (see section \ref{virtualhost}). +must be set inside a \term{host\_config} for each vhost (see section \ref{virtualhost}). For example: \begin{verbatim} {host_config, "public.example.org", [ @@ -3246,7 +3246,7 @@ Options: \iqdiscitem{In-Band Registration (\ns{jabber:iq:register})} \end{description} -This module reads also another option defined globably for the server: +This module reads also another option defined globally for the server: \term{\{registration\_timeout, Timeout\}}. \ind{options!registratimeout} This option limits the frequency of registration from a given IP or username. So, a user can't register a new account from the same IP address or JID during @@ -3837,7 +3837,7 @@ The more interesting ones are: Store internal Mnesia database to a binary backup file. \titem {restore ejabberd.backup} Restore immediately from a binary backup file the internal Mnesia database. - This will comsume quite some memory for big servers. + This will consume quite some memory for big servers. \titem {install-fallback ejabberd.backup} The binary backup file is installed as fallback: it will be used to restore the database at the next ejabberd start. @@ -3867,9 +3867,9 @@ This file includes detailed information about each configurable option. The \term{ejabberdctl} script returns a numerical status code. Success is represented by \term{0}, error is represented by \term{1}, -and other codes may be used for specifical results. +and other codes may be used for specific results. This can be used by other scripts to determine automatically -if a command succedded or failed, +if a command succeeded or failed, for example using: \term{echo \$?} diff --git a/src/tls/tls_drv.c b/src/tls/tls_drv.c index e7b07028b..257262607 100644 --- a/src/tls/tls_drv.c +++ b/src/tls/tls_drv.c @@ -40,6 +40,10 @@ typedef struct { typedef unsigned __int32 uint32_t; #endif +#ifndef SSL_OP_NO_TICKET +#define SSL_OP_NO_TICKET 0 +#endif + /* * str_hash is based on the public domain code from * http://www.burtleburtle.net/bob/hash/doobs.html From 5ed381fc58d5ee6e94f66ce947d118d26d4d4c86 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 10 Mar 2009 11:13:46 +0000 Subject: [PATCH 257/582] Fix PEP with other domains and s2s (EJAB-825) SVN Revision: 1982 --- ChangeLog | 7 +++ src/mod_pubsub/mod_pubsub.erl | 89 ++++++++++++--------------------- src/mod_pubsub/node_default.erl | 4 +- 3 files changed, 40 insertions(+), 60 deletions(-) diff --git a/ChangeLog b/ChangeLog index af9a88f5c..b2a67f1c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-03-10 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: Fix PEP with other domains and s2s + (EJAB-825). Also fixes send last published items in subscription. + + * src/mod_pubsub/node_default.erl: minor typo fix + 2009-03-09 Badlop * src/tls/tls_drv.c: Fix to support OpenSSL older than diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index d56a8b810..ee09e6a84 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -55,7 +55,7 @@ %% exports for hooks -export([presence_probe/3, - in_subscription/6, + out_subscription/4, remove_user/2, disco_local_identity/5, disco_local_features/5, @@ -165,7 +165,7 @@ init([ServerHost, Opts]) -> ejabberd_hooks:add(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), ejabberd_hooks:add(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75), ejabberd_hooks:add(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50), - ejabberd_hooks:add(roster_in_subscription, ServerHostB, ?MODULE, in_subscription, 50), + ejabberd_hooks:add(roster_out_subscription, ServerHostB, ?MODULE, out_subscription, 50), ejabberd_hooks:add(remove_user, ServerHostB, ?MODULE, remove_user, 50), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), lists:foreach( @@ -414,21 +414,33 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) -> %% presence hooks handling functions %% -presence_probe(JID, JID, Pid) -> - Proc = gen_mod:get_module_proc(exmpp_jid:ldomain_as_list(JID), ?PROCNAME), - gen_server:cast(Proc, {presence, JID, Pid}); -presence_probe(_, _, _) -> - ok. +presence_probe(JID, JID, _Pid) -> + {U, S, R} = jlib:short_prepd_jid(JID), + Host = S, % exmpp_jid:ldomain_as_list(JID), + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + gen_server:cast(Proc, {presence, JID}), + gen_server:cast(Proc, {presence, U, S, [R], JID}); +presence_probe(Peer, JID, _Pid) -> + {U, S, R} = jlib:short_prepd_jid(Peer), + Host = exmpp_jid:ldomain_as_list(JID), + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + gen_server:cast(Proc, {presence, U, S, [R], JID}). %% ------- %% subscription hooks handling functions %% -in_subscription(Acc, User, Server, JID, subscribed, _) -> + +out_subscription(User, Server, JID, subscribed) -> + Owner = exmpp_jid:make_jid(User, Server, ""), + {U, S, R} = jlib:short_prepd_jid(JID), + Rs = case R of + [] -> user_resources(U, S); + _ -> [R] + end, Proc = gen_mod:get_module_proc(Server, ?PROCNAME), - gen_server:cast(Proc, {subscribed, User, Server, JID}), - Acc; -in_subscription(Acc, _, _, _, _, _) -> - Acc. + gen_server:cast(Proc, {presence, U, S, Rs, Owner}); +out_subscription(_, _, _, _) -> + ok. %% ------- %% user remove hook handling function @@ -469,11 +481,9 @@ handle_call(stop, _From, State) -> %% Description: Handling cast messages %%-------------------------------------------------------------------- %% @private -handle_cast({presence, JID, Pid}, State) -> +handle_cast({presence, JID}, State) -> %% A new resource is available. send last published items - LJID = jlib:short_prepd_jid(JID), Host = State#state.host, - ServerHost = State#state.server_host, %% for each node From is subscribed to %% and if the node is so configured, send the last published item to From lists:foreach(fun(Type) -> @@ -495,54 +505,17 @@ handle_cast({presence, JID, Pid}, State) -> ok end, Subscriptions) end, State#state.plugins), - %% and send to From last PEP events published by its contacts - case catch ejabberd_c2s:get_subscribed(Pid) of - Contacts when is_list(Contacts) -> - lists:foreach( - fun({User, Server, _}) -> - Owner = {User, Server, undefined}, - lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) -> - case get_option(Options, send_last_published_item) of - on_sub_and_presence -> - case is_caps_notify(ServerHost, Node, LJID) of - true -> - Subscribed = case get_option(Options, access_model) of - open -> true; - presence -> true; - whitelist -> false; % subscribers are added manually - authorize -> false; % likewise - roster -> - Grps = get_option(Options, roster_groups_allowed, []), - element(2, get_roster_info(User, Server, LJID, Grps)) - end, - if Subscribed -> - send_last_item(Owner, Node, LJID); - true -> - ok - end; - false -> - ok - end; - _ -> - ok - end - end, tree_action(Host, get_nodes, [Owner, JID])) - end, Contacts); - _ -> - ok - end, {noreply, State}; -handle_cast({subscribed, User, Server, JID}, State) -> - %% and send last PEP events published by JID +handle_cast({presence, User, Server, Resources, JID}, State) -> + %% A new resource is available. send last published PEP items Owner = jlib:short_prepd_bare_jid(JID), - Host = State#state.host, ServerHost = State#state.server_host, lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) -> case get_option(Options, send_last_published_item) of on_sub_and_presence -> lists:foreach(fun(Resource) -> - LJID = jlib:short_prepd_jid(exmpp_jid:make_jid(User, Server, Resource)), + LJID = {User, Server, Resource}, case is_caps_notify(ServerHost, Node, LJID) of true -> Subscribed = case get_option(Options, access_model) of @@ -562,11 +535,11 @@ handle_cast({subscribed, User, Server, JID}, State) -> false -> ok end - end, user_resources(User, Server)); + end, Resources); _ -> ok end - end, tree_action(Host, get_nodes, [Owner])), + end, tree_action(Host, get_nodes, [Owner, JID])) {noreply, State}; handle_cast({remove_user, LUser, LServer}, State) -> @@ -634,7 +607,7 @@ terminate(_Reason, #state{host = Host, ejabberd_hooks:delete(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), ejabberd_hooks:delete(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75), ejabberd_hooks:delete(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50), - ejabberd_hooks:delete(roster_in_subscription, ServerHostB, ?MODULE, in_subscription, 50), + ejabberd_hooks:delete(roster_out_subscription, ServerHostB, ?MODULE, out_subscription, 50), ejabberd_hooks:delete(remove_user, ServerHostB, ?MODULE, remove_user, 50), lists:foreach(fun({NS,Mod}) -> gen_iq_handler:remove_iq_handler(Mod, ServerHostB, NS) diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 116160658..ae0707fcb 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -307,7 +307,7 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel, (AccessModel == whitelist) and (not Whitelisted) -> %% Node has whitelist access model and entity lacks required affiliation {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; - (AccessModel == authorize) and (not Whitelisted) -> + (AccessModel == authorize) -> % TODO: to be done %% Node has authorize access model {error, 'forbidden'}; %%MustPay -> @@ -437,7 +437,7 @@ publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) -> {error, 'forbidden'}; true -> PubId = {SubKey, now()}, %% TODO, uses {now(),PublisherKey} for sorting (EJAB-824) - %% TODO: check creation, presence, roster (EJAB-663) + %% TODO: check creation, presence, roster Item = case get_item(Host, Node, ItemId) of {result, OldItem} -> OldItem#pubsub_item{modification = PubId, From 2c4effe6ce163bb350b95408302b99f71ce68deb Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 10 Mar 2009 12:09:31 +0000 Subject: [PATCH 258/582] typo fix on roster access_model SVN Revision: 1985 --- src/mod_pubsub/mod_pubsub.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index ee09e6a84..863f2c494 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -525,7 +525,8 @@ handle_cast({presence, User, Server, Resources, JID}, State) -> authorize -> false; % likewise roster -> Grps = get_option(Options, roster_groups_allowed, []), - element(2, get_roster_info(User, Server, LJID, Grps)) + {OU, OS, _} = Owner, + element(2, get_roster_info(OU, OS, LJID, Grps)) end, if Subscribed -> send_last_item(Owner, Node, LJID); From b245d68568a8b85eb5e4e7187006d660c5cef5e6 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 10 Mar 2009 15:21:36 +0000 Subject: [PATCH 259/582] * src/tls/tls_drv.c: Fix encryption problem for ejabberd_http after timeout (thanks to Alexey Shchepin)(EJAB-880) SVN Revision: 1986 --- ChangeLog | 5 +++++ src/tls/tls_drv.c | 1 + 2 files changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index b2a67f1c7..f5d1eb8e0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-03-10 Badlop + + * src/tls/tls_drv.c: Fix encryption problem for ejabberd_http + after timeout (thanks to Alexey Shchepin)(EJAB-880) + 2009-03-10 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: Fix PEP with other domains and s2s diff --git a/src/tls/tls_drv.c b/src/tls/tls_drv.c index 257262607..8380ea751 100644 --- a/src/tls/tls_drv.c +++ b/src/tls/tls_drv.c @@ -344,6 +344,7 @@ static int tls_drv_control(ErlDrvData handle, res = SSL_CTX_check_private_key(ctx); die_unless(res > 0, "SSL_CTX_check_private_key failed"); + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); SSL_CTX_set_default_verify_paths(ctx); if (command == SET_CERTIFICATE_FILE_ACCEPT) From d0a6ae7855ddb7527edbf08465e5603d16c1c54e Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 10 Mar 2009 16:25:20 +0000 Subject: [PATCH 260/582] * doc/release_notes_2.0.4.txt: Added file for new release SVN Revision: 1987 --- ChangeLog | 2 ++ doc/release_notes_2.0.4.txt | 44 +++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 doc/release_notes_2.0.4.txt diff --git a/ChangeLog b/ChangeLog index f5d1eb8e0..cabba90f6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2009-03-10 Badlop + * doc/release_notes_2.0.4.txt: Added file for new release + * src/tls/tls_drv.c: Fix encryption problem for ejabberd_http after timeout (thanks to Alexey Shchepin)(EJAB-880) diff --git a/doc/release_notes_2.0.4.txt b/doc/release_notes_2.0.4.txt new file mode 100644 index 000000000..24f943779 --- /dev/null +++ b/doc/release_notes_2.0.4.txt @@ -0,0 +1,44 @@ + + Release Notes + ejabberd 2.0.4 + + ejabberd 2.0.4 is the fourth bugfix release for ejabberd 2.0.x branch. + + ejabberd 2.0.4 includes several bugfixes. + A detailed list of changes can be retrieved from: + http://redir.process-one.net/ejabberd-2.0.4 + + The new code can be downloaded from ejabberd download page: + http://www.process-one.net/en/ejabberd/ + + + The changes are: + +- Ensure ID attribute in roster push is unique +- Authentication: Fix Anonymous auth when enabled with broken ODBC +- Authentication: Unquote correctly backslash in DIGEST-MD5 SASL responses +- Authentication: Cancel presence subscriptions on account deletion +- LDAP: Close a connection on tcp_error +- LDAP: Implemented queue for pending queries +- LDAP: On failure of LDAP connection, waiting is done on pending queue +- MUC: Owner of a password protected room must also provide the password +- MUC: Prevent XSS in MUC logs by linkifying only a few known protocols +- Privacy rules: Items are now processed in the specified order +- Privacy rules: Fix to correctly block subscription requests +- Proxy65: If ip option is not defined, take an IP address of a local hostname +- PubSub: Add roster subscription handling; send PEP events to all resources +- PubSub: Allow node creation without configure item +- PubSub: Requesting items on a node which exists, but empty returns an error +- PEP: Fix sending notifications to other domains and s2s +- S2S: Fix problem with encrypted connection to Gtalk and recent Openfire +- S2S: Workaround to get DNS SRV lookup to work on Windows machine +- Shared Roster Groups: Fix to not resend authorization request +- WebAdmin: Fix encryption problem for ejabberd_http after timeout + + + Bug reports + + You can officially report bugs on ProcessOne support site: + http://support.process-one.net/ + +END From cd3556f195de4e0b308397b0c2f766bb128702c9 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 11 Mar 2009 18:36:27 +0000 Subject: [PATCH 261/582] Fix mistake when calling win32_dns. SVN Revision: 1990 --- src/ejabberd_app.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index d109a2082..5cf16068d 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -191,6 +191,6 @@ maybe_add_nameservers() -> end. add_windows_nameservers() -> - IPTs = win32_dns_test:get_nameservers(), + IPTs = win32_dns:get_nameservers(), ?INFO_MSG("Adding machine's DNS IPs to Erlang system:~n~p", [IPTs]), lists:foreach(fun(IPT) -> inet_db:add_ns(IPT) end, IPTs). From 026c4a27116fb31e5aebc0194b2c28512d4d1740 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 19 Mar 2009 21:30:10 +0000 Subject: [PATCH 262/582] Allow more environment variable overrides in ejabberdctl (EJAB-891) SVN Revision: 1996 --- ChangeLog | 5 +++++ src/ejabberdctl.template | 24 ++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index cabba90f6..546576bf5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-03-19 Christophe Romain + + * src/ejabberdctl.template: Allow more environment variable overrides + in ejabberdctl (thanks to Brian Cully)(EJAB-891) + 2009-03-10 Badlop * doc/release_notes_2.0.4.txt: Added file for new release diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template index 32a31d105..5054d89b3 100644 --- a/src/ejabberdctl.template +++ b/src/ejabberdctl.template @@ -79,12 +79,24 @@ fi ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $KERNEL_OPTS" # define additional environment variables -EJABBERDDIR=@LIBDIR@/ejabberd -EJABBERD_EBIN_PATH=$EJABBERDDIR/ebin -EJABBERD_PRIV_PATH=$EJABBERDDIR/priv -EJABBERD_BIN_PATH=$EJABBERD_PRIV_PATH/bin -EJABBERD_SO_PATH=$EJABBERD_PRIV_PATH/lib -EJABBERD_MSGS_PATH=$EJABBERD_PRIV_PATH/msgs +if [ "$EJABBERDDIR" = "" ]; then + EJABBERDDIR=@LIBDIR@/ejabberd +fi +if [ "$EJABBERD_EBIN_PATH" = "" ]; then + EJABBERD_EBIN_PATH=$EJABBERDDIR/ebin +fi +if [ "$EJABBERD_PRIV_PATH" = "" ]; then + EJABBERD_PRIV_PATH=$EJABBERDDIR/priv +fi +if [ "$EJABBRD_BIN_PATH" = "" ]; then + EJABBERD_BIN_PATH=$EJABBERD_PRIV_PATH/bin +fi +if [ "$EJABBERD_SO_PATH" = "" ]; then + EJABBERD_SO_PATH=$EJABBERD_PRIV_PATH/lib +fi +if [ "$EJABBERD_MSGS_PATH" = "" ]; then + EJABBERD_MSGS_PATH=$EJABBERD_PRIV_PATH/msgs +fi EJABBERD_LOG_PATH=$LOGS_DIR/ejabberd.log SASL_LOG_PATH=$LOGS_DIR/sasl.log From 3e756f5d1cc50c0b189d45a419f5df76571b849c Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 20 Mar 2009 00:08:38 +0000 Subject: [PATCH 263/582] implement roster acces model (EJAB-780) SVN Revision: 1997 --- ChangeLog | 5 +++ src/mod_pubsub/mod_pubsub.erl | 58 +++++++++++++++++++++++------------ 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 546576bf5..87d50c776 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-03-20 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: implement roster acces model (thanks + to Andy Skelton)(EJAB-780) + 2009-03-19 Christophe Romain * src/ejabberdctl.template: Allow more environment variable overrides diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 863f2c494..613f3cb91 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -76,7 +76,7 @@ unsubscribe_node/5, publish_item/6, delete_item/4, - get_configure/4, + get_configure/5, set_configure/5, get_items/3, tree_action/3, @@ -682,7 +682,7 @@ do_route(ServerHost, Access, Plugins, Host, From, To, Packet) -> #iq{type = IQType, ns = ?NS_PUBSUB_OWNER, lang = Lang, payload = SubEl} -> Res = - case iq_pubsub_owner(Host, From, IQType, SubEl, Lang) of + case iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) of {result, IQRes} -> exmpp_iq:result(Packet, IQRes); {error, Error} -> @@ -855,7 +855,7 @@ iq_local(From, To, #iq{type = Type, LOwner = jlib:short_prepd_bare_jid(From), Res = case XMLNS of ?NS_PUBSUB -> iq_pubsub(LOwner, ServerHost, From, Type, SubEl, Lang); - ?NS_PUBSUB_OWNER -> iq_pubsub_owner(LOwner, From, Type, SubEl, Lang) + ?NS_PUBSUB_OWNER -> iq_pubsub_owner(LOwner, ServerHost, From, Type, SubEl, Lang) end, case Res of {result, []} -> exmpp_iq:result(IQ_Rec); @@ -869,7 +869,7 @@ iq_sm(From, To, #iq{type = Type, payload = SubEl, ns = XMLNS, lang = Lang} = IQ_ LOwner = jlib:short_prepd_bare_jid(To), Res = case XMLNS of ?NS_PUBSUB -> iq_pubsub(LOwner, ServerHost, From, Type, SubEl, Lang); - ?NS_PUBSUB_OWNER -> iq_pubsub_owner(LOwner, From, Type, SubEl, Lang) + ?NS_PUBSUB_OWNER -> iq_pubsub_owner(LOwner, ServerHost, From, Type, SubEl, Lang) end, case Res of {result, []} -> exmpp_iq:result(IQ_Rec); @@ -988,7 +988,7 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) -> {error, 'bad-request'} end. -iq_pubsub_owner(Host, From, IQType, SubEl, Lang) -> +iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> SubEls = SubEl#xmlel.children, Action = exmpp_xml:remove_cdata_from_list(SubEls), case Action of @@ -999,7 +999,7 @@ iq_pubsub_owner(Host, From, IQType, SubEl, Lang) -> end, case {IQType, Name} of {get, 'configure'} -> - get_configure(Host, Node, From, Lang); + get_configure(Host, ServerHost, Node, From, Lang); {set, 'configure'} -> set_configure(Host, Node, From, Els, Lang); {get, 'default'} -> @@ -1188,6 +1188,21 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> -define(LISTXFIELD(Label, Var, Val, Opts), ?XFIELDOPT("list-single", Label, Var, Val, Opts)). +-define(LISTMXFIELD(Label, Var, Vals, Opts), + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', Type), + ?XMLATTR('label', translate:translate(Lang, Label)), + ?XMLATTR('var', Var)], children = + lists:map(fun(Opt) -> + #xmlel{ns = ?NS_DATA_FORMS, name = 'option', children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = + [#xmlcdata{cdata = list_to_binary(Opt)}]}]} + end, Opts) ++ + lists:map(fun(Val) -> + #xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = + [#xmlcdata{cdata = list_to_binary(Val)}]} + end, Vals) + }). + %% @spec (Host::host(), ServerHost::host(), Node::pubsubNode(), Owner::jid(), NodeType::nodeType()) -> %% {error, Reason::stanzaError()} | %% {result, []} @@ -1400,7 +1415,11 @@ subscribe_node(Host, Node, From, JID) -> get_roster_info(OUser, OServer, Subscriber, AllowedGroups); _ -> - {true, true} + case Subscriber of + {"", "", ""} -> {false, false}; + {U, S, _} -> get_roster_info(U, S, Subscriber, + AllowedGroups) + end end, if not SubscribeFeature -> @@ -2318,7 +2337,7 @@ broadcast_config_notification(Host, Node, Lang) -> Content = case get_option(Options, deliver_payloads) of true -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = - get_configure_xfields(Type, Options, Lang, Owners)}]; + get_configure_xfields(Type, Options, Lang, Owners, [])}]; false -> [] end, @@ -2421,18 +2440,19 @@ is_caps_notify(Host, Node, LJID) -> %%

    • The service does not support node configuration.
    • %%
    • The service does not support retrieval of default node configuration.
    • %% -get_configure(Host, Node, From, Lang) -> +get_configure(Host, ServerHost, Node, From, Lang) -> Action = fun(#pubsub_node{options = Options, owners = Owners, type = Type}) -> case node_call(Type, get_affiliation, [Host, Node, From]) of {result, owner} -> + Groups = ejabberd_hooks:run_fold(roster_groups, ServerHost, [], [ServerHost]), {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'configure', attrs = [?XMLATTR('node', node_to_string(Node))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = - get_configure_xfields(Type, Options, Lang, Owners) + get_configure_xfields(Type, Options, Lang, Owners, Groups) }]}]}]}; _ -> {error, 'forbidden'} @@ -2446,7 +2466,7 @@ get_default(Host, Node, _From, Lang) -> {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'default', children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = - get_configure_xfields(Type, Options, Lang, []) + get_configure_xfields(Type, Options, Lang, [], []) }]}]}]}. %% Get node option @@ -2518,7 +2538,11 @@ max_items(Options) -> atom_to_list(get_option(Options, Var)), [atom_to_list(O) || O <- Opts])). -get_configure_xfields(_Type, Options, Lang, _Owners) -> +-define(LISTM_CONFIG_FIELD(Label, Var, Opts), + ?LISTMXFIELD(Label, "pubsub#" ++ atom_to_list(Var), + get_option(Options, Var), Opts)). + +get_configure_xfields(_Type, Options, Lang, _Owners, Groups) -> [?XFIELD("hidden", "", "FORM_TYPE", ?NS_PUBSUB_NODE_CONFIG_s), ?BOOL_CONFIG_FIELD("Deliver payloads with event notifications", deliver_payloads), ?BOOL_CONFIG_FIELD("Deliver event notifications", deliver_notifications), @@ -2532,11 +2556,7 @@ get_configure_xfields(_Type, Options, Lang, _Owners) -> ?ALIST_CONFIG_FIELD("Specify the access model", access_model, [open, authorize, presence, roster, whitelist]), %% XXX: change to list-multi, include current roster groups as options - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', <<"text-multi">>), - ?XMLATTR('label', translate:translate(Lang, "Roster groups allowed to subscribe")), - ?XMLATTR('var', <<"pubsub#roster_groups_allowed">>)], children = - [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Value)}]} || - Value <- get_option(Options, roster_groups_allowed, [])]}, + ?LISTM_CONFIG_FIELD("Roster groups allowed to subscribe", roster_groups_allowed, Groups), ?ALIST_CONFIG_FIELD("Specify the publisher model", publish_model, [publishers, subscribers, open]), ?INTEGER_CONFIG_FIELD("Max payload size in bytes", max_payload_size), @@ -2643,8 +2663,8 @@ set_xoption([], NewOpts) -> NewOpts; set_xoption([{"FORM_TYPE", _} | Opts], NewOpts) -> set_xoption(Opts, NewOpts); -set_xoption([{"pubsub#roster_groups_allowed", _Value} | Opts], NewOpts) -> - ?SET_LIST_XOPT(roster_groups_allowed, []); % XXX: waiting for EJAB-659 to be solved +set_xoption([{"pubsub#roster_groups_allowed", Value} | Opts], NewOpts) -> + ?SET_LIST_XOPT(roster_groups_allowed, Value); set_xoption([{"pubsub#deliver_payloads", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(deliver_payloads, Val); set_xoption([{"pubsub#deliver_notifications", [Val]} | Opts], NewOpts) -> From 61691ac47d04cc3d9c4a599c512acd2fb6d92864 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 24 Mar 2009 18:02:13 +0000 Subject: [PATCH 264/582] Merge 1998 from trunk. * src/ejabberd_sm.erl: Partially retract SVN r1976 EJAB-300 (EJAB-890). Check default privacy list when account, not a specific session, receives a presence subscription stanza (EJAB-300). * src/ejabberd_c2s.erl: Likewise SVN Revision: 1999 --- ChangeLog | 8 ++++++ src/ejabberd_c2s.erl | 54 ++++++++++++---------------------------- src/ejabberd_sm.erl | 59 +++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 79 insertions(+), 42 deletions(-) diff --git a/ChangeLog b/ChangeLog index 87d50c776..100091d6e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2009-03-24 Badlop + + * src/ejabberd_sm.erl: Partially retract SVN r1976 + EJAB-300 (EJAB-890). Check default privacy list when account, not + a specific session, receives a presence subscription + stanza (EJAB-300). + * src/ejabberd_c2s.erl: Likewise + 2009-03-20 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: implement roster acces model (thanks diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index d7aca754b..91c257a7c 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1039,21 +1039,16 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> 'unavailable'), {true, Attrs1, StateData}; 'subscribe' -> - Reason = exmpp_presence:get_status(Packet), - SRes = check_privacy_subs(in, subscribe, From, To, - Packet, Reason, StateData), + SRes = is_privacy_allow(From, To, Packet, StateData#state.privacy_list), {SRes, Attrs, StateData}; 'subscribed' -> - SRes = check_privacy_subs(in, subscribed, From, To, - Packet, <<>>, StateData), + SRes = is_privacy_allow(From, To, Packet, StateData#state.privacy_list), {SRes, Attrs, StateData}; 'unsubscribe' -> - SRes = check_privacy_subs(in, unsubscribe, From, To, - Packet, <<>>, StateData), + SRes = is_privacy_allow(From, To, Packet, StateData#state.privacy_list), {SRes, Attrs, StateData}; 'unsubscribed' -> - SRes = check_privacy_subs(in, unsubscribed, From, To, - Packet, <<>>, StateData), + SRes = is_privacy_allow(From, To, Packet, StateData#state.privacy_list), {SRes, Attrs, StateData}; _ -> case ejabberd_hooks:run_fold( @@ -1580,35 +1575,18 @@ check_privacy_route(From, StateData, FromRoute, To, Packet) -> ejabberd_router:route(FromRoute, To, Packet) end. -%% Check privacy rules for subscription requests and call the roster storage -check_privacy_subs(Dir, Type, From, To, Packet, Reason, StateData) -> - case is_privacy_allow(From, To, Dir, Packet, StateData) of - true -> - ejabberd_hooks:run_fold( - roster_in_subscription, - exmpp_jid:ldomain(To), - false, - [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, Type, Reason]), - true; - false -> - false - end. - -%% Check if privacy rules allow this delivery, then push to roster -is_privacy_allow(From, To, Dir, Packet, StateData) -> - case ejabberd_hooks:run_fold( - privacy_check_packet, StateData#state.server, - allow, - [StateData#state.user, - StateData#state.server, - StateData#state.privacy_list, - {From, To, Packet}, - Dir]) of - deny -> - false; - allow -> - true - end. +%% Check if privacy rules allow this delivery +is_privacy_allow(From, To, Packet, PrivacyList) -> + User = exmpp_jid:lnode(To), + Server = exmpp_jid:ldomain(To), + allow == ejabberd_hooks:run_fold( + privacy_check_packet, Server, + allow, + [User, + Server, + PrivacyList, + {From, To, Packet}, + in]). presence_broadcast(StateData, From, JIDSet, Packet) -> lists:foreach(fun({U, S, R}) -> diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 8d2dbeb33..d2f415d66 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -62,6 +62,7 @@ -include("ejabberd.hrl"). -include("ejabberd_commands.hrl"). +-include("mod_privacy.hrl"). -record(session, {sid, usr, us, priority, info}). -record(state, {}). @@ -422,13 +423,38 @@ do_route(From, To, Packet) -> {Pass, _Subsc} = case exmpp_presence:get_type(Packet) of 'subscribe' -> - {true, true}; + Reason = exmpp_presence:get_status(Packet), + {is_privacy_allow(From, To, Packet) andalso + ejabberd_hooks:run_fold( + roster_in_subscription, + exmpp_jid:ldomain(To), + false, + [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, subscribe, Reason]), + true}; 'subscribed' -> - {true, true}; + {is_privacy_allow(From, To, Packet) andalso + ejabberd_hooks:run_fold( + roster_in_subscription, + exmpp_jid:ldomain(To), + false, + [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, subscribed, <<>>]), + true}; 'unsubscribe' -> - {true, true}; + {is_privacy_allow(From, To, Packet) andalso + ejabberd_hooks:run_fold( + roster_in_subscription, + exmpp_jid:ldomain(To), + false, + [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, unsubscribe, <<>>]), + true}; 'unsubscribed' -> - {true, true}; + {is_privacy_allow(From, To, Packet) andalso + ejabberd_hooks:run_fold( + roster_in_subscription, + exmpp_jid:ldomain(To), + false, + [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, unsubscribed, <<>>]), + true}; _ -> {true, false} end, @@ -490,6 +516,31 @@ do_route(From, To, Packet) -> end end. +%% The default list applies to the user as a whole, +%% and is processed if there is no active list set +%% for the target session/resource to which a stanza is addressed, +%% or if there are no current sessions for the user. +is_privacy_allow(From, To, Packet) -> + User = exmpp_jid:lnode(To), + Server = exmpp_jid:ldomain(To), + PrivacyList = ejabberd_hooks:run_fold(privacy_get_user_list, Server, + #userlist{}, [User, Server]), + is_privacy_allow(From, To, Packet, PrivacyList). + +%% Check if privacy rules allow this delivery +%% Function copied from ejabberd_c2s.erl +is_privacy_allow(From, To, Packet, PrivacyList) -> + User = exmpp_jid:lnode(To), + Server = exmpp_jid:ldomain(To), + allow == ejabberd_hooks:run_fold( + privacy_check_packet, Server, + allow, + [User, + Server, + PrivacyList, + {From, To, Packet}, + in]). + route_message(From, To, Packet) -> LUser = exmpp_jid:lnode(To), LServer = exmpp_jid:ldomain(To), From 79247dad41a8741b1c6907ca49fdc4e10d9a131a Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 1 Apr 2009 10:37:18 +0000 Subject: [PATCH 265/582] * doc/release_notes_2.0.5.txt: Added file for new release SVN Revision: 2002 --- ChangeLog | 4 ++++ doc/release_notes_2.0.5.txt | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 doc/release_notes_2.0.5.txt diff --git a/ChangeLog b/ChangeLog index 100091d6e..a03b14e34 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-04-01 Badlop + + * doc/release_notes_2.0.5.txt: Added file for new release + 2009-03-24 Badlop * src/ejabberd_sm.erl: Partially retract SVN r1976 diff --git a/doc/release_notes_2.0.5.txt b/doc/release_notes_2.0.5.txt new file mode 100644 index 000000000..cf652ccfe --- /dev/null +++ b/doc/release_notes_2.0.5.txt @@ -0,0 +1,33 @@ + + Release Notes + ejabberd 2.0.5 + + ejabberd 2.0.5 is the fifth bugfix release in ejabberd 2.0.x branch. + + ejabberd 2.0.5 includes three bugfixes. + More details of those fixes can be retrieved from: + http://redir.process-one.net/ejabberd-2.0.5 + + The new code can be downloaded from ejabberd download page: + http://www.process-one.net/en/ejabberd/ + + + The changes are: + +- Fix two problems introduced in ejabberd 2.0.4: subscription request + produced many authorization requests with some clients and + transports; and subscription requests were not stored for later + delivery when receiver was offline. + +- Fix warning in expat_erl.c about implicit declaration of x_fix_buff + +- HTTP-Bind (BOSH): Fix a missing stream:error in the returned + remote-stream-error stanza + + + Bug reports + + You can officially report bugs on ProcessOne support site: + http://support.process-one.net/ + +END From e34d6e3678d20df791d631e562265404a06e4323 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 8 Apr 2009 18:52:52 +0000 Subject: [PATCH 266/582] * src/mod_irc/mod_irc_connection.erl: Fix compilation warnings. SVN Revision: 2006 --- ChangeLog | 4 ++++ src/mod_irc/mod_irc_connection.erl | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index a03b14e34..1af05bac4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-04-08 Badlop + + * src/mod_irc/mod_irc_connection.erl: Fix compilation warnings. + 2009-04-01 Badlop * doc/release_notes_2.0.5.txt: Added file for new release diff --git a/src/mod_irc/mod_irc_connection.erl b/src/mod_irc/mod_irc_connection.erl index c7d07113e..03f3fae64 100644 --- a/src/mod_irc/mod_irc_connection.erl +++ b/src/mod_irc/mod_irc_connection.erl @@ -371,25 +371,25 @@ handle_info({route_chan, Channel, Resource, From = StateData#state.user, To = exmpp_jid:make_jid(lists:concat([Channel, "%", StateData#state.server]), StateData#state.host, StateData#state.nick), - case exmpp_iq:xmlel_to_iq(El) of + _ = case exmpp_iq:xmlel_to_iq(El) of #iq{kind = request, ns = ?NS_MUC_ADMIN} = IQ_Rec -> iq_admin(StateData, Channel, From, To, IQ_Rec); #iq{kind = request, ns = ?NS_SOFT_VERSION} -> Res = io_lib:format("PRIVMSG ~s :\001VERSION\001\r\n", [Resource]), - ?SEND(Res), + _ = ?SEND(Res), Err = exmpp_iq:error(El, 'feature-not-implemented'), ejabberd_router:route(To, From, Err); #iq{kind = request, ns = ?NS_TIME_OLD} -> Res = io_lib:format("PRIVMSG ~s :\001TIME\001\r\n", [Resource]), - ?SEND(Res), + _ = ?SEND(Res), Err = exmpp_iq:error(El, 'feature-not-implemented'), ejabberd_router:route(To, From, Err); #iq{kind = request, ns = ?NS_VCARD} -> Res = io_lib:format("WHOIS ~s \r\n", [Resource]), - ?SEND(Res), + _ = ?SEND(Res), Err = exmpp_iq:error(El, 'feature-not-implemented'), ejabberd_router:route(To, From, Err); #iq{} -> From d13be09524a5ee5539255c0422d9b3181add6b6c Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 8 Apr 2009 18:58:11 +0000 Subject: [PATCH 267/582] * src/mod_pubsub/mod_pubsub.erl: Quickfix compilation errors. SVN Revision: 2008 --- ChangeLog | 2 ++ src/mod_pubsub/mod_pubsub.erl | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1af05bac4..40ae11a56 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2009-04-08 Badlop + * src/mod_pubsub/mod_pubsub.erl: Quickfix compilation errors. + * src/mod_irc/mod_irc_connection.erl: Fix compilation warnings. 2009-04-01 Badlop diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 613f3cb91..7e44cdfaf 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -540,7 +540,7 @@ handle_cast({presence, User, Server, Resources, JID}, State) -> _ -> ok end - end, tree_action(Host, get_nodes, [Owner, JID])) + end, tree_action(ServerHost, get_nodes, [Owner, JID])), {noreply, State}; handle_cast({remove_user, LUser, LServer}, State) -> @@ -2542,7 +2542,7 @@ max_items(Options) -> ?LISTMXFIELD(Label, "pubsub#" ++ atom_to_list(Var), get_option(Options, Var), Opts)). -get_configure_xfields(_Type, Options, Lang, _Owners, Groups) -> +get_configure_xfields(Type, Options, Lang, _Owners, Groups) -> [?XFIELD("hidden", "", "FORM_TYPE", ?NS_PUBSUB_NODE_CONFIG_s), ?BOOL_CONFIG_FIELD("Deliver payloads with event notifications", deliver_payloads), ?BOOL_CONFIG_FIELD("Deliver event notifications", deliver_notifications), From 2195e433dc6f8349a4d1bab558b3d3c93b89c825 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 8 Apr 2009 19:04:13 +0000 Subject: [PATCH 268/582] * src/mod_muc/mod_muc.erl: English fixes (thanks to Glenn Sieb) * src/mod_muc/mod_muc_log.erl: Likewise * src/mod_muc/mod_muc_room.erl: Likewise * src/mod_register.erl: Likewise * src/web/ejabberd_web_admin.erl: Likewise SVN Revision: 2009 --- ChangeLog | 6 ++++++ src/mod_muc/mod_muc.erl | 2 +- src/mod_muc/mod_muc_log.erl | 2 +- src/mod_muc/mod_muc_room.erl | 18 +++++++++--------- src/mod_register.erl | 2 +- src/web/ejabberd_web_admin.erl | 2 +- 6 files changed, 19 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index 40ae11a56..fce26e5ca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2009-04-08 Badlop + * src/mod_muc/mod_muc.erl: English fixes (thanks to Glenn Sieb) + * src/mod_muc/mod_muc_log.erl: Likewise + * src/mod_muc/mod_muc_room.erl: Likewise + * src/mod_register.erl: Likewise + * src/web/ejabberd_web_admin.erl: Likewise + * src/mod_pubsub/mod_pubsub.erl: Quickfix compilation errors. * src/mod_irc/mod_irc_connection.erl: Fix compilation warnings. diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index bb1502b81..bd87b7e7a 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -719,7 +719,7 @@ iq_set_register_info(Host, From, Nick, Lang) when is_binary(Host), is_binary(Nic {atomic, ok} -> ok; {atomic, false} -> - ErrText = "Specified nickname is already registered", + ErrText = "That nickname is registered by another person", %%TODO: Always in the jabber:client namespace? {error,exmpp_stanza:error(?NS_JABBER_CLIENT, 'conflict', diff --git a/src/mod_muc/mod_muc_log.erl b/src/mod_muc/mod_muc_log.erl index 01b3cda01..f1fcbc18f 100644 --- a/src/mod_muc/mod_muc_log.erl +++ b/src/mod_muc/mod_muc_log.erl @@ -852,7 +852,7 @@ get_roomconfig_text(anonymous) -> "Make room semianonymous"; get_roomconfig_text(members_only) -> "Make room members-only"; get_roomconfig_text(moderated) -> "Make room moderated"; get_roomconfig_text(members_by_default) -> "Default users as participants"; -get_roomconfig_text(allow_change_subj) -> "Allow users to change subject"; +get_roomconfig_text(allow_change_subj) -> "Allow users to change the subject"; get_roomconfig_text(allow_private_messages) -> "Allow users to send private messages"; get_roomconfig_text(allow_query_users) -> "Allow users to query other users"; get_roomconfig_text(allow_user_invites) -> "Allow users to send invites"; diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 941066647..3d0608a95 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -793,13 +793,13 @@ process_groupchat_message(From, #xmlel{name = 'message'} = Packet, exmpp_stanza:error(Packet#xmlel.ns, 'forbidden', {Lang, translate:translate(Lang, "Only moderators and participants " - "are allowed to change subject in this room")})); + "are allowed to change the subject in this room")})); _ -> exmpp_stanza:reply_with_error(Packet, exmpp_stanza:error(Packet#xmlel.ns, 'forbidden', {Lang, translate:translate(Lang, "Only moderators " - "are allowed to change subject in this room")})) + "are allowed to change the subject in this room")})) end, ejabberd_router:route( StateData#state.jid, @@ -909,7 +909,7 @@ process_presence(From, Nick, #xmlel{name = 'presence'} = Packet, StateData; {true, _, _} -> Lang = exmpp_stanza:get_lang(Packet), - ErrText = "Nickname is already in use by another occupant", + ErrText = "That nickname is already in use by another occupant", Err = exmpp_stanza:reply_with_error(Packet, exmpp_stanza:error(Packet#xmlel.ns, 'conflict', {Lang, translate:translate(Lang, ErrText)})), @@ -920,7 +920,7 @@ process_presence(From, Nick, #xmlel{name = 'presence'} = Packet, From, Err), StateData; {_, false, _} -> - ErrText = "Nickname is registered by another person", + ErrText = "That nickname is registered by another person", Err = exmpp_stanza:reply_with_error(Packet, exmpp_stanza:error(Packet#xmlel.ns, 'conflict', {Lang, translate:translate(Lang, ErrText)})), @@ -1482,7 +1482,7 @@ add_new_user(From, Nick, Packet, StateData) -> 'forbidden', {Lang, translate:translate(Lang, ErrText)}); _ -> - ErrText = "Membership required to enter this room", + ErrText = "Membership is required to enter this room", exmpp_stanza:error(Packet#xmlel.ns, 'registration-required', {Lang, translate:translate(Lang, ErrText)}) @@ -1492,7 +1492,7 @@ add_new_user(From, Nick, Packet, StateData) -> From, Err), StateData; {_, true, _, _} -> - ErrText = "Nickname is already in use by another occupant", + ErrText = "That nickname is already in use by another occupant", Err = exmpp_stanza:reply_with_error(Packet, exmpp_stanza:error(Packet#xmlel.ns, 'conflict', @@ -1503,7 +1503,7 @@ add_new_user(From, Nick, Packet, StateData) -> From, Err), StateData; {_, _, false, _} -> - ErrText = "Nickname is registered by another person", + ErrText = "That nickname is registered by another person", Err = exmpp_stanza:reply_with_error(Packet, ?ERR(Packet, 'conflict', Lang, ErrText)), ejabberd_router:route( @@ -1553,7 +1553,7 @@ add_new_user(From, Nick, Packet, StateData) -> NewState end; nopass -> - ErrText = "Password required to enter this room", + ErrText = "The password is required to enter this room", Err = exmpp_stanza:reply_with_error( Packet, ?ERR(Packet, 'not-authorized', Lang, ErrText)), ejabberd_router:route( % TODO: s/Nick/""/ @@ -2817,7 +2817,7 @@ get_config(Lang, StateData, From) -> ?BOOLXFIELD("Default users as participants", "members_by_default", Config#config.members_by_default), - ?BOOLXFIELD("Allow users to change subject", + ?BOOLXFIELD("Allow users to change the subject", "muc#roomconfig_changesubject", Config#config.allow_change_subj), ?BOOLXFIELD("Allow users to send private messages", diff --git a/src/mod_register.erl b/src/mod_register.erl index f7800e0b2..5e895d6f2 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -233,7 +233,7 @@ try_register(User, Server, Password, Source, Lang) -> end; false -> ErrText = "Users are not allowed to register " - "accounts so fast", + "accounts so quickly", {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'resource-constraint', {Lang, ErrText})} end end diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 61664d2ce..484c9b393 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -1804,7 +1804,7 @@ get_node(global, Node, ["backup"], Query, Lang) -> end, [?XC('h1', ?T("Backup of ") ++ atom_to_list(Node))] ++ ResS ++ - [?XCT('p', "Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately."), + [?XCT('p', "Please note that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately."), ?XAE('form', [?XMLATTR('action', <<>>), ?XMLATTR('method', <<"post">>)], [?XAE('table', [], [?XE('tbody', From 854b448536e5e1cd64ad9c2d2e6c0ce8ff6426c8 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 8 Apr 2009 19:30:24 +0000 Subject: [PATCH 269/582] * src/mod_pubsub/mod_pubsub.erl: Announce PubSub features in the server JID only if PEP is enabled (EJAB-905) SVN Revision: 2010 --- ChangeLog | 3 +++ src/mod_pubsub/mod_pubsub.erl | 22 ++++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index fce26e5ca..1bc6c4bde 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2009-04-08 Badlop + * src/mod_pubsub/mod_pubsub.erl: Announce PubSub features in the + server JID only if PEP is enabled (EJAB-905) + * src/mod_muc/mod_muc.erl: English fixes (thanks to Glenn Sieb) * src/mod_muc/mod_muc_log.erl: Likewise * src/mod_muc/mod_muc_room.erl: Likewise diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 7e44cdfaf..952f546fe 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -158,9 +158,6 @@ init([ServerHost, Opts]) -> Access = gen_mod:get_opt(access_createnode, Opts, all), ServerHostB = list_to_binary(ServerHost), mod_disco:register_feature(ServerHost, ?NS_PUBSUB_s), - ejabberd_hooks:add(disco_local_identity, ServerHostB, ?MODULE, disco_local_identity, 75), - ejabberd_hooks:add(disco_local_features, ServerHostB, ?MODULE, disco_local_features, 75), - ejabberd_hooks:add(disco_local_items, ServerHostB, ?MODULE, disco_local_items, 75), ejabberd_hooks:add(disco_sm_identity, ServerHostB, ?MODULE, disco_sm_identity, 75), ejabberd_hooks:add(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), ejabberd_hooks:add(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75), @@ -173,12 +170,25 @@ init([ServerHost, Opts]) -> gen_iq_handler:add_iq_handler( Mod, ServerHostB, NS, ?MODULE, Fun, IQDisc) end, - [{?NS_PUBSUB, ejabberd_local, iq_local}, - {?NS_PUBSUB_OWNER, ejabberd_local, iq_local}, - {?NS_PUBSUB, ejabberd_sm, iq_sm}, + [{?NS_PUBSUB, ejabberd_sm, iq_sm}, {?NS_PUBSUB_OWNER, ejabberd_sm, iq_sm}]), ejabberd_router:register_route(Host), {Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts), + case lists:member("pep", Plugins) of + true -> + ejabberd_hooks:add(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75), + ejabberd_hooks:add(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75), + ejabberd_hooks:add(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75), + lists:foreach( + fun({NS,Mod,Fun}) -> + gen_iq_handler:add_iq_handler( + Mod, ServerHost, NS, ?MODULE, Fun, IQDisc) + end, + [{?NS_PUBSUB, ejabberd_local, iq_local}, + {?NS_PUBSUB_OWNER, ejabberd_local, iq_local}]); + false -> + ok + end, update_database(Host), ets:new(gen_mod:get_module_proc(Host, pubsub_state), [set, named_table]), ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {nodetree, NodeTree}), From 6b2a838e244153f49d68332c0881e9ebb66c3170 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 9 Apr 2009 11:18:06 +0000 Subject: [PATCH 270/582] * src/msgs/pl.po: Fix some translations (thanks to Andrzej Smyk) SVN Revision: 2011 --- ChangeLog | 4 ++++ src/msgs/pl.po | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1bc6c4bde..7675acfa7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-04-09 Badlop + + * src/msgs/pl.po: Fix some translations (thanks to Andrzej Smyk) + 2009-04-08 Badlop * src/mod_pubsub/mod_pubsub.erl: Announce PubSub features in the diff --git a/src/msgs/pl.po b/src/msgs/pl.po index b92561c9e..4f1e2c19a 100644 --- a/src/msgs/pl.po +++ b/src/msgs/pl.po @@ -921,7 +921,7 @@ msgstr "Wiadomości offline" #: mod_proxy65/mod_proxy65_service.erl:192 msgid "ejabberd SOCKS5 Bytestreams module" -msgstr "Mudł SOCKS5 Bytestreams" +msgstr "Moduł SOCKS5 Bytestreams" #: mod_pubsub/mod_pubsub.erl:753 msgid "Publish-Subscribe" @@ -1447,7 +1447,7 @@ msgstr "Transakcje uruchomione ponownie" #: web/ejabberd_web_admin.erl:1883 msgid "Transactions Logged:" -msgstr "Transakcje logowane" +msgstr "Transakcje zalogowane" #: web/ejabberd_web_admin.erl:1906 msgid "Update " From 08cbaf8ccf310d562e9fa1af37ce2130b2e17b29 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 10 Apr 2009 13:21:37 +0000 Subject: [PATCH 271/582] Better handling of presence hook and caps clean SVN Revision: 2015 --- ChangeLog | 9 + src/ejabberd_c2s.erl | 12 -- src/mod_caps.erl | 42 +++- src/mod_pubsub/mod_pubsub.erl | 359 +++++++++++++++++----------------- src/mod_pubsub/node_flat.erl | 6 +- 5 files changed, 236 insertions(+), 192 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7675acfa7..5514b3153 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2009-03-20 Christophe Romain + + * src/mod_caps.erl: Better handling of presence hook and caps clean + * src/ejabberd_c2s.erl: Likewise + * src/mod_pubsub/mod_pubsub.erl: Likewise + + * src/mod_pubsub/mod_pubsub.erl: Improve invalid-payload check, send + last published item to new resource only, thread message sending. + 2009-04-09 Badlop * src/msgs/pl.po: Fix some translations (thanks to Andrzej Smyk) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 91c257a7c..67a55757d 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1062,18 +1062,6 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> allow -> LFrom = jlib:short_prepd_jid(From), LBFrom = jlib:short_prepd_bare_jid(From), - %% Note contact availability - Els = Packet#xmlel.children, - case exmpp_presence:get_type(Packet) of - 'unavailable' -> - %mod_caps:clear_caps(From); - % caps clear disabled cause it breaks things - ok; - _ -> - ServerString = binary_to_list(StateData#state.server), - Caps = mod_caps:read_caps(Els), - mod_caps:note_caps(ServerString, From, Caps) - end, case ?SETS:is_element( LFrom, StateData#state.pres_a) orelse ?SETS:is_element( diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 902145625..875483807 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -53,6 +53,10 @@ -include_lib("exmpp/include/exmpp.hrl"). +%% hook handlers +-export([receive_packet/3, + receive_packet/4]). + -include("ejabberd.hrl"). -define(PROCNAME, ejabberd_mod_caps). @@ -157,6 +161,35 @@ stop(Host) -> Proc = gen_mod:get_module_proc(Host, ?PROCNAME), gen_server:call(Proc, stop). +receive_packet(From, To, Packet) when ?IS_PRESENCE(Packet) -> + case exmpp_presence:get_type(Packet) of + 'probe' -> + ok; + 'error' -> + ok; + 'invisible' -> + ok; + 'subscribe' -> + ok; + 'subscribed' -> + ok; + 'unsubscribe' -> + ok; + 'unsubscribed' -> + ok; + 'unavailable' -> + clear_caps(From); + _ -> + ServerString = binary_to_list(StateData#state.server), + Els = Packet#xmlel.children, + note_caps(ServerString, From, read_caps(Els)) + end; +receive_packet(_, _, _) -> + ok. + +receive_packet(_JID, From, To, Packet) -> + receive_packet(From, To, Packet). + %%==================================================================== %% gen_server callbacks %%==================================================================== @@ -173,6 +206,10 @@ init([Host, _Opts]) -> {type, bag}, {attributes, record_info(fields, user_caps_resources)}]), mnesia:delete_table(user_caps_default), + mnesia:clear_table(user_caps), + mnesia:clear_table(user_caps_resources), + ejabberd_hooks:add(user_receive_packet, Host, ?MODULE, receive_packet, 30), + ejabberd_hooks:add(s2s_receive_packet, Host, ?MODULE, receive_packet, 30), {ok, #state{host = Host}}. maybe_get_features(#caps{node = Node, version = Version, exts = Exts}) -> @@ -349,7 +386,10 @@ handle_disco_response(From, To, IQ_Rec) -> handle_info(_Info, State) -> {noreply, State}. -terminate(_Reason, _State) -> +terminate(_Reason, State) -> + Host = State#state.host, + ejabberd_hooks:delete(user_receive_packet, Host, ?MODULE, receive_packet, 30), + ejabberd_hooks:delete(s2s_receive_packet, Host, ?MODULE, receive_packet, 30), ok. code_change(_OldVsn, State, _Extra) -> diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 952f546fe..56ff84714 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -76,6 +76,8 @@ unsubscribe_node/5, publish_item/6, delete_item/4, + send_items/4, + broadcast_stanza/6, get_configure/5, set_configure/5, get_items/3, @@ -156,6 +158,7 @@ init([ServerHost, Opts]) -> ?DEBUG("pubsub init ~p ~p",[ServerHost,Opts]), Host = gen_mod:get_opt_host(ServerHost, Opts, "pubsub.@HOST@"), Access = gen_mod:get_opt(access_createnode, Opts, all), + IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), ServerHostB = list_to_binary(ServerHost), mod_disco:register_feature(ServerHost, ?NS_PUBSUB_s), ejabberd_hooks:add(disco_sm_identity, ServerHostB, ?MODULE, disco_sm_identity, 75), @@ -164,28 +167,17 @@ init([ServerHost, Opts]) -> ejabberd_hooks:add(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50), ejabberd_hooks:add(roster_out_subscription, ServerHostB, ?MODULE, out_subscription, 50), ejabberd_hooks:add(remove_user, ServerHostB, ?MODULE, remove_user, 50), - IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), - lists:foreach( - fun({NS,Mod,Fun}) -> - gen_iq_handler:add_iq_handler( - Mod, ServerHostB, NS, ?MODULE, Fun, IQDisc) - end, - [{?NS_PUBSUB, ejabberd_sm, iq_sm}, - {?NS_PUBSUB_OWNER, ejabberd_sm, iq_sm}]), + gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB, ?MODULE, iq_sm, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB_OWNER, ?MODULE, iq_sm, IQDisc), ejabberd_router:register_route(Host), {Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts), - case lists:member("pep", Plugins) of + case lists:member(?PEPNODE, Plugins) of true -> - ejabberd_hooks:add(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75), - ejabberd_hooks:add(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75), - ejabberd_hooks:add(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75), - lists:foreach( - fun({NS,Mod,Fun}) -> - gen_iq_handler:add_iq_handler( - Mod, ServerHost, NS, ?MODULE, Fun, IQDisc) - end, - [{?NS_PUBSUB, ejabberd_local, iq_local}, - {?NS_PUBSUB_OWNER, ejabberd_local, iq_local}]); + ejabberd_hooks:add(disco_local_identity, ServerHostB, ?MODULE, disco_local_identity, 75), + ejabberd_hooks:add(disco_local_features, ServerHostB, ?MODULE, disco_local_features, 75), + ejabberd_hooks:add(disco_local_items, ServerHostB, ?MODULE, disco_local_items, 75), + gen_iq_handler:add_iq_handler(ejabberd_local, ServerHostB, ?NS_PUBSUB, ?MODULE, iq_local, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_local, ServerHostB, ?NS_PUBSUB_OWNER, ?MODULE, iq_local, IQDisc); false -> ok end, @@ -494,63 +486,69 @@ handle_call(stop, _From, State) -> handle_cast({presence, JID}, State) -> %% A new resource is available. send last published items Host = State#state.host, + LJID = jlib:short_prepd_jid(JID), %% for each node From is subscribed to %% and if the node is so configured, send the last published item to From - lists:foreach(fun(Type) -> - {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, JID]), - lists:foreach( - fun({Node, subscribed, SubJID}) -> - case tree_action(Host, get_node, [Host, Node, JID]) of - #pubsub_node{options = Options} -> - case get_option(Options, send_last_published_item) of - on_sub_and_presence -> - send_last_item(Host, Node, SubJID); - _ -> - ok - end; - _ -> - ok - end; + spawn(fun() -> + lists:foreach(fun(Type) -> + {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, JID]), + lists:foreach( + fun({Node, subscribed, _SubJID}) -> + case tree_action(Host, get_node, [Host, Node, JID]) of + #pubsub_node{options = Options} -> + case get_option(Options, send_last_published_item) of + on_sub_and_presence -> + send_items(Host, Node, LJID, last); + _ -> + ok + end; + _ -> + ok + end; (_) -> - ok - end, Subscriptions) - end, State#state.plugins), + ok + end, Subscriptions) + end, State#state.plugins) + end), {noreply, State}; handle_cast({presence, User, Server, Resources, JID}, State) -> %% A new resource is available. send last published PEP items Owner = jlib:short_prepd_bare_jid(JID), + Host = State#state.host, ServerHost = State#state.server_host, - lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) -> - case get_option(Options, send_last_published_item) of - on_sub_and_presence -> - lists:foreach(fun(Resource) -> - LJID = {User, Server, Resource}, - case is_caps_notify(ServerHost, Node, LJID) of - true -> - Subscribed = case get_option(Options, access_model) of - open -> true; - presence -> true; - whitelist -> false; % subscribers are added manually - authorize -> false; % likewise - roster -> - Grps = get_option(Options, roster_groups_allowed, []), - {OU, OS, _} = Owner, - element(2, get_roster_info(OU, OS, LJID, Grps)) - end, - if Subscribed -> - send_last_item(Owner, Node, LJID); + spawn(fun() -> + lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) -> + case get_option(Options, send_last_published_item) of + on_sub_and_presence -> + lists:foreach(fun(Resource) -> + LJID = {User, Server, Resource}, + case is_caps_notify(ServerHost, Node, LJID) of true -> + Subscribed = case get_option(Options, access_model) of + open -> true; + presence -> true; + whitelist -> false; % subscribers are added manually + authorize -> false; % likewise + roster -> + Grps = get_option(Options, roster_groups_allowed, []), + {OU, OS, _} = Owner, + element(2, get_roster_info(OU, OS, LJID, Grps)) + end, + if Subscribed -> + send_items(Owner, Node, LJID, last); + true -> + ok + end; + false -> ok - end; - false -> - ok - end - end, Resources); - _ -> - ok - end - end, tree_action(ServerHost, get_nodes, [Owner, JID])), + end + end, Resources); + _ -> + ok + end + end, tree_action(ServerHost, get_nodes, [Owner, JID])) + end), {noreply, State}; handle_cast({remove_user, LUser, LServer}, State) -> @@ -611,6 +609,16 @@ terminate(_Reason, #state{host = Host, terminate_plugins(Host, ServerHost, Plugins, TreePlugin), ejabberd_router:unregister_route(Host), ServerHostB = list_to_binary(ServerHost), + case lists:member(?PEPNODE, Plugins) of + true -> + ejabberd_hooks:delete(disco_local_identity, ServerHostB, ?MODULE, disco_local_identity, 75), + ejabberd_hooks:delete(disco_local_features, ServerHostB, ?MODULE, disco_local_features, 75), + ejabberd_hooks:delete(disco_local_items, ServerHostB, ?MODULE, disco_local_items, 75), + gen_iq_handler:remove_iq_handler(ejabberd_local, ServerHostB, ?NS_PUBSUB), + gen_iq_handler:remove_iq_handler(ejabberd_local, ServerHostB, ?NS_PUBSUB_OWNER); + false -> + ok + end, ejabberd_hooks:delete(disco_local_identity, ServerHostB, ?MODULE, disco_local_identity, 75), ejabberd_hooks:delete(disco_local_features, ServerHostB, ?MODULE, disco_local_features, 75), ejabberd_hooks:delete(disco_local_items, ServerHostB, ?MODULE, disco_local_items, 75), @@ -620,12 +628,8 @@ terminate(_Reason, #state{host = Host, ejabberd_hooks:delete(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50), ejabberd_hooks:delete(roster_out_subscription, ServerHostB, ?MODULE, out_subscription, 50), ejabberd_hooks:delete(remove_user, ServerHostB, ?MODULE, remove_user, 50), - lists:foreach(fun({NS,Mod}) -> - gen_iq_handler:remove_iq_handler(Mod, ServerHostB, NS) - end, [{?NS_PUBSUB, ejabberd_local}, - {?NS_PUBSUB_OWNER, ejabberd_local}, - {?NS_PUBSUB, ejabberd_sm}, - {?NS_PUBSUB_OWNER, ejabberd_sm}]), + gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB), + gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB_OWNER), mod_disco:unregister_feature(ServerHost, ?NS_PUBSUB_s), ok. @@ -851,10 +855,7 @@ iq_disco_items(Host, Item, From) -> transaction(Host, Node, Action, sync_dirty) end. -iq_local(From, To, #iq{type = Type, - payload = SubEl, - ns = XMLNS, - lang = Lang} = IQ_Rec) -> +iq_local(From, To, #iq{type = Type, payload = SubEl, ns = XMLNS, lang = Lang} = IQ_Rec) -> ServerHost = exmpp_jid:ldomain_as_list(To), FromHost = exmpp_jid:ldomain_as_list(To), %% Accept IQs to server only from our own users. @@ -1102,14 +1103,14 @@ find_authorization_response(Packet) -> %% @spec (Host, JID, Node, Subscription) -> void %% Host = mod_pubsub:host() %% JID = jlib:jid() -%% Node = string() +%% SNode = string() %% Subscription = atom() %% Plugins = [Plugin::string()] %% @doc Send a message to JID with the supplied Subscription -send_authorization_approval(Host, JID, Node, Subscription) -> +send_authorization_approval(Host, JID, SNode, Subscription) -> Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'subscription', attrs = - [?XMLATTR('node', Node), + [?XMLATTR('node', SNode), ?XMLATTR('jid', exmpp_jid:jid_to_binary(JID)), ?XMLATTR('subscription', subscription_to_string(Subscription))]}]), ejabberd_router ! {route, service_jid(Host), JID, Stanza}. @@ -1462,7 +1463,7 @@ subscribe_node(Host, Node, From, JID) -> {error, Error} -> {error, Error}; {result, {Result, subscribed, send_last}} -> - send_last_item(Host, Node, Subscriber), + send_items(Host, Node, Subscriber, last), case Result of default -> {result, Reply(subscribed)}; _ -> {result, Result} @@ -1552,12 +1553,12 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> PayloadSize > PayloadMaxSize -> %% Entity attempts to publish very large payload {error, extended_error('not-acceptable', "payload-too-big")}; + PayloadCount == 0 -> + %% Publisher attempts to publish to payload node with no payload + {error, extended_error('bad-request', "payload-required")}; PayloadCount > 1 -> %% Entity attempts to publish item with multiple payload elements {error, extended_error('bad-request', "invalid-payload")}; - Payload == "" -> - %% Publisher attempts to publish to payload node with no payload - {error, extended_error('bad-request', "payload-required")}; (DeliverPayloads == 0) and (PersistItems == 0) and (PayloadSize > 0) -> %% Publisher attempts to publish to transient notification node with item {error, extended_error('bad-request', "item-forbidden")}; @@ -1773,18 +1774,9 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> end, %% Generate the XML response (Item list), limiting the %% number of items sent to MaxItems: - ItemsEls = lists:map( - fun(#pubsub_item{itemid = {ItemId, _}, - payload = Payload}) -> - ItemAttrs = case ItemId of - "" -> []; - _ -> [?XMLATTR('id', ItemId)] - end, - #xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = ItemAttrs, children = Payload} - end, lists:sublist(SendItems, MaxItems)), {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = - ItemsEls}]}]} + itemsEls(lists:sublist(SendItems, MaxItems))}]}]} end end. @@ -1794,14 +1786,6 @@ get_items(Host, Node, From) -> _ -> [] end. -%% @spec (Host, Node, LJID) -> any() -%% Host = host() -%% Node = pubsubNode() -%% LJID = {U, S, []} -%% @doc

      Resend the last item of a node to the user.

      -send_last_item(Host, Node, LJID) -> - send_items(Host, Node, LJID, last). - %% @spec (Host, Node, LJID, Number) -> any() %% Host = host() %% Node = pubsubNode() @@ -1834,17 +1818,9 @@ send_items(Host, Node, {LU, LS, LR} = LJID, Number) -> Items end end, - ItemsEls = lists:map( - fun(#pubsub_item{itemid = {ItemId, _}, payload = Payload}) -> - ItemAttrs = case ItemId of - "" -> []; - _ -> [?XMLATTR('id', ItemId)] - end, - #xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = ItemAttrs, children = Payload} - end, ToSend), Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = - ItemsEls}]), + itemsEls(ToSend)}]), ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(LU, LS, LR), Stanza}. %% @spec (Host, JID, Plugins) -> {error, Reason} | {result, Response} @@ -2229,6 +2205,7 @@ event_stanza(Els) -> %%%%%% broadcast functions broadcast_publish_item(Host, Node, ItemId, _From, Payload) -> + %broadcast(Host, Node, none, true, 'items', ItemEls) Action = fun(#pubsub_node{options = Options, type = Type}) -> case node_call(Type, get_states, [Host, Node]) of @@ -2239,15 +2216,10 @@ broadcast_publish_item(Host, Node, ItemId, _From, Payload) -> true -> Payload; false -> [] end, - ItemAttrs = case ItemId of - "" -> []; - _ -> [?XMLATTR('id', ItemId)] - end, Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = ItemAttrs, children = Content}]}]), - broadcast_stanza(Host, Options, States, Stanza), - broadcast_by_caps(Host, Node, Type, Stanza), + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = itemAttr(ItemId), children = Content}]}]), + broadcast_stanza(Host, Node, Type, Options, States, Stanza), {result, true}; _ -> {result, false} @@ -2258,6 +2230,7 @@ broadcast_publish_item(Host, Node, ItemId, _From, Payload) -> broadcast_retract_items(Host, Node, ItemIds) -> broadcast_retract_items(Host, Node, ItemIds, false). broadcast_retract_items(Host, Node, ItemIds, ForceNotify) -> + %broadcast(Host, Node, notify_retract, ForceNotify, 'retract', RetractEls) Action = fun(#pubsub_node{options = Options, type = Type}) -> case (get_option(Options, notify_retract) or ForceNotify) of @@ -2266,19 +2239,11 @@ broadcast_retract_items(Host, Node, ItemIds, ForceNotify) -> {result, []} -> {result, false}; {result, States} -> - RetractEls = lists:map( - fun(ItemId) -> - ItemAttrs = case ItemId of - "" -> []; - _ -> [?XMLATTR('id', ItemId)] - end, - #xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = ItemAttrs} - end, ItemIds), + RetractEls = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = itemAttr(ItemId)} || ItemId <- ItemIds], Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = RetractEls}]), - broadcast_stanza(Host, Options, States, Stanza), - broadcast_by_caps(Host, Node, Type, Stanza), + broadcast_stanza(Host, Node, Type, Options, States, Stanza), {result, true}; _ -> {result, false} @@ -2290,6 +2255,7 @@ broadcast_retract_items(Host, Node, ItemIds, ForceNotify) -> transaction(Host, Node, Action, sync_dirty). broadcast_purge_node(Host, Node) -> + %broadcast(Host, Node, notify_retract, false, 'purge', []) Action = fun(#pubsub_node{options = Options, type = Type}) -> case get_option(Options, notify_retract) of @@ -2300,8 +2266,7 @@ broadcast_purge_node(Host, Node) -> {result, States} -> Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'purge', attrs = [?XMLATTR('node', node_to_string(Node))]}]), - broadcast_stanza(Host, Options, States, Stanza), - broadcast_by_caps(Host, Node, Type, Stanza), + broadcast_stanza(Host, Node, Type, Options, States, Stanza), {result, true}; _ -> {result, false} @@ -2313,6 +2278,7 @@ broadcast_purge_node(Host, Node) -> transaction(Host, Node, Action, sync_dirty). broadcast_removed_node(Host, Node) -> + %broadcast(Host, Node, notify_delete, false, 'delete', []) Action = fun(#pubsub_node{options = Options, type = Type}) -> case get_option(Options, notify_delete) of @@ -2323,8 +2289,7 @@ broadcast_removed_node(Host, Node) -> {result, States} -> Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'delete', attrs = [?XMLATTR('node', node_to_string(Node))]}]), - broadcast_stanza(Host, Options, States, Stanza), - broadcast_by_caps(Host, Node, Type, Stanza), + broadcast_stanza(Host, Node, Type, Options, States, Stanza), {result, true}; _ -> {result, false} @@ -2336,6 +2301,7 @@ broadcast_removed_node(Host, Node) -> transaction(Host, Node, Action, sync_dirty). broadcast_config_notification(Host, Node, Lang) -> + %broadcast(Host, Node, notify_config, false, 'items', ConfigEls) Action = fun(#pubsub_node{options = Options, owners = Owners, type = Type}) -> case get_option(Options, notify_config) of @@ -2355,8 +2321,7 @@ broadcast_config_notification(Host, Node, Lang) -> [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = [?XMLATTR('id', <<"configuration">>)], children = Content}]}]), - broadcast_stanza(Host, Options, States, Stanza), - broadcast_by_caps(Host, Node, Type, Stanza), + broadcast_stanza(Host, Node, Type, Options, States, Stanza), {result, true}; _ -> {result, false} @@ -2367,62 +2332,91 @@ broadcast_config_notification(Host, Node, Lang) -> end, transaction(Host, Node, Action, sync_dirty). -broadcast_stanza(Host, NodeOpts, States, Stanza) -> - PresenceDelivery = get_option(NodeOpts, presence_based_delivery), - BroadcastAll = get_option(NodeOpts, broadcast_all_resources), %% XXX this is not standard +% TODO: merge broadcast code that way +%broadcast(Host, Node, Feature, Force, ElName, SubEls) -> +% Action = +% fun(#pubsub_node{options = Options, type = Type}) -> +% case (get_option(Options, Feature) or Force) of +% true -> +% case node_call(Type, get_states, [Host, Node]) of +% {result, []} -> +% {result, false}; +% {result, States} -> +% Stanza = event_stanza([{xmlelement, ElName, [{"node", node_to_string(Node)}], SubEls}]), +% broadcast_stanza(Host, Node, Type, Options, States, Stanza), +% {result, true}; +% _ -> +% {result, false} +% end; +% _ -> +% {result, false} +% end +% end, +% transaction(Host, Node, Action, sync_dirty). + +broadcast_stanza(Host, Node, _Type, Options, States, Stanza) -> + AccessModel = get_option(Options, access_model), + PresenceDelivery = get_option(Options, presence_based_delivery), + BroadcastAll = get_option(Options, broadcast_all_resources), %% XXX this is not standard, but usefull From = service_jid(Host), + %% Handles explicit subscriptions lists:foreach(fun(#pubsub_state{stateid = {LJID, _}, subscription = Subs}) -> case is_to_deliver(LJID, Subs, PresenceDelivery) of true -> - JIDs = case BroadcastAll of - true -> ejabberd_sm:get_user_resources(element(1, LJID), element(2, LJID)); - false -> [LJID] + {U, S, R} = case BroadcastAll of + true -> jlib:short_prepd_bare_jid(LJID); + false -> LJID end, - lists:foreach(fun({U, S, R}) -> - ejabberd_router ! {route, From, exmpp_jlib:make_jid(U, S, R), Stanza} - end, JIDs); + ejabberd_router ! {route, From, exmpp_jlib:make_jid(U, S, R), Stanza}; false -> ok end - end, States). - -%% broadcast Stanza to all contacts of the user that are advertising -%% interest in this kind of Node. -broadcast_by_caps({LUser, LServer, LResource}, Node, _Type, Stanza) -> - SenderResource = case LResource of - [] -> hd(user_resources(LUser, LServer)); - _ -> LResource - end, - case ejabberd_sm:get_session_pid(LUser, LServer, SenderResource) of - C2SPid when is_pid(C2SPid) -> - %% set the from address on the notification to the bare JID of the account owner - %% Also, add "replyto" if entity has presence subscription to the account owner - %% See XEP-0163 1.1 section 4.3.1 - Sender = exmpp_jid:make_jid(LUser, LServer), - %%ReplyTo = jlib:make_jid(LUser, LServer, SenderResource), % This has to be used - case catch ejabberd_c2s:get_subscribed(C2SPid) of - Contacts when is_list(Contacts) -> - lists:foreach(fun({U, S, _}) -> - Resources = lists:foldl(fun(R, Acc) -> - case is_caps_notify(LServer, Node, {U, S, R}) of - true -> [R | Acc]; - false -> Acc - end - end, [], user_resources(U, S)), - lists:foreach(fun(R) -> - ejabberd_router ! {route, Sender, exmpp_jid:make_jid(U, S, R), Stanza} - end, Resources) - end, Contacts); + end, States), + %% Handles implicit presence subscriptions + case Host of + {LUser, LServer, LResource} -> + SenderResource = case LResource of + [] -> + case user_resources(LUser, LServer) of + [Resource|_] -> Resource; + _ -> "" + end; _ -> - ok + LResource end, - ok; + case ejabberd_sm:get_session_pid(LUser, LServer, SenderResource) of + C2SPid when is_pid(C2SPid) -> + %% set the from address on the notification to the bare JID of the account owner + %% Also, add "replyto" if entity has presence subscription to the account owner + %% See XEP-0163 1.1 section 4.3.1 + Sender = exmpp_jid:make_jid(LUser, LServer), + %%ReplyTo = jlib:make_jid(LUser, LServer, SenderResource), % This has to be used + case catch ejabberd_c2s:get_subscribed(C2SPid) of + Contacts when is_list(Contacts) -> + lists:foreach(fun({U, S, _}) -> + spawn(fun() -> + Rs = lists:foldl(fun(R, Acc) -> + case is_caps_notify(LServer, Node, {U, S, R}) of + true -> [R | Acc]; + false -> Acc + end + end, [], user_resources(U, S)), + lists:foreach(fun(R) -> + ejabberd_router ! {route, Sender, exmpp_jid:make_jid(U, S, R), Stanza} + end, Rs) + end) + end, Contacts); + _ -> + ok + end, + ok; + _ -> + ?DEBUG("~p@~p has no session; can't deliver ~p to contacts", [LUser, LServer, Stanza]), + ok + end; _ -> - ?DEBUG("~p@~p has no session; can't deliver ~p to contacts", [LUser, LServer, Stanza]), ok - end; -broadcast_by_caps(_, _, _, _) -> - ok. + end. %% If we don't know the resource, just pick first if any %% If no resource available, check if caps anyway (remote online) @@ -2877,3 +2871,16 @@ uniqid() -> {T1, T2, T3} = now(), lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])). +% node attributes +nodeAttr(Node) -> %% TODO: to be used + [?XMLATTR('node', node_to_string(Node))]. + +% item attributes +itemAttr([]) -> []; +itemAttr(ItemId) -> [?XMLATTR('id', ItemId)]. + +% build item elements from item list +itemsEls(Items) -> + lists:map(fun(#pubsub_item{itemid = {ItemId, _}, payload = Payload}) -> + #xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = itemAttr(ItemId), children = Payload} + end, Items). diff --git a/src/mod_pubsub/node_flat.erl b/src/mod_pubsub/node_flat.erl index 2d1f8b234..e9e983aa8 100644 --- a/src/mod_pubsub/node_flat.erl +++ b/src/mod_pubsub/node_flat.erl @@ -16,7 +16,7 @@ %%% This software is copyright 2006-2009, ProcessOne. %%% %%% @copyright 2006-2009 ProcessOne -%%% @author Christophe romain +%%% @author Christophe Romain %%% [http://www.process-one.net/] %%% @version {@vsn}, {@date} {@time} %%% @end @@ -82,7 +82,7 @@ options() -> {roster_groups_allowed, []}, {publish_model, publishers}, {max_payload_size, ?MAX_PAYLOAD_SIZE}, - {send_last_published_item, never}, + {send_last_published_item, on_sub_and_presence}, {deliver_notifications, true}, {presence_based_delivery, false}]. @@ -168,7 +168,7 @@ get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId get_item(Host, Node, ItemId) -> node_default:get_item(Host, Node, ItemId). - + get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). From b519fdd3cb104f4cd92a4a17f5eb7445109437be Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 14 Apr 2009 10:13:05 +0000 Subject: [PATCH 272/582] back to original caps patch which may be safer SVN Revision: 2018 --- src/mod_caps.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 875483807..4e31e6e38 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -171,8 +171,8 @@ receive_packet(From, To, Packet) when ?IS_PRESENCE(Packet) -> ok; 'subscribe' -> ok; - 'subscribed' -> - ok; +% 'subscribed' -> % this my be useless, to be checked +% ok; 'unsubscribe' -> ok; 'unsubscribed' -> From ab4750ec1e1a00ae16ed07b32547ca4504b1574a Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 14 Apr 2009 12:46:55 +0000 Subject: [PATCH 273/582] after check, last commit was useless SVN Revision: 2019 --- src/mod_caps.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 4e31e6e38..875483807 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -171,8 +171,8 @@ receive_packet(From, To, Packet) when ?IS_PRESENCE(Packet) -> ok; 'subscribe' -> ok; -% 'subscribed' -> % this my be useless, to be checked -% ok; + 'subscribed' -> + ok; 'unsubscribe' -> ok; 'unsubscribed' -> From 8782597c1a6733ba78afa5e0cf92841b0c343a9e Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 14 Apr 2009 18:25:58 +0000 Subject: [PATCH 274/582] * src/mod_muc/mod_muc_log.erl: Linkify also xmpp:..., as it was done previously (thanks to Konstantin Khomoutov)(EJAB-850) SVN Revision: 2020 --- ChangeLog | 5 +++++ src/mod_muc/mod_muc_log.erl | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 5514b3153..250dc4fd5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-04-14 Badlop + + * src/mod_muc/mod_muc_log.erl: Linkify also xmpp:..., as it was + done previously (thanks to Konstantin Khomoutov)(EJAB-850) + 2009-03-20 Christophe Romain * src/mod_caps.erl: Better handling of presence hook and caps clean diff --git a/src/mod_muc/mod_muc_log.erl b/src/mod_muc/mod_muc_log.erl index f1fcbc18f..e531de96e 100644 --- a/src/mod_muc/mod_muc_log.erl +++ b/src/mod_muc/mod_muc_log.erl @@ -767,7 +767,7 @@ htmlize2(S1, NoFollow) -> S2 = element(2, regexp:gsub(S1, "\\&", "\\&")), S3 = element(2, regexp:gsub(S2, "<", "\\<")), S4 = element(2, regexp:gsub(S3, ">", "\\>")), - S5 = element(2, regexp:gsub(S4, "(http|https|ftp|mailto|xmpp)://[^] )\'\"}]+", + S5 = element(2, regexp:gsub(S4, "((http|https|ftp)://|(mailto|xmpp):)[^] )\'\"}]+", link_regexp(NoFollow))), %% Remove 'right-to-left override' unicode character 0x202e element(2, regexp:gsub(S5, [226,128,174], "[RLO]")). From 13fcbd6413a830f99c0ac667aa84081effe7f5ec Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 14 Apr 2009 18:31:29 +0000 Subject: [PATCH 275/582] * doc/guide.tex: Explain that the recommended Erlang/OTP version is R12B-5, and R13 is not supported yet. * doc/guide.html: Likewise * README: Likewise SVN Revision: 2021 --- ChangeLog | 5 +++++ README | 7 +++++-- doc/guide.html | 2 +- doc/guide.tex | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 250dc4fd5..d7c9d8eb1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2009-04-14 Badlop + * doc/guide.tex: Explain that the recommended Erlang/OTP version + is R12B-5, and R13 is not supported yet. + * doc/guide.html: Likewise + * README: Likewise + * src/mod_muc/mod_muc_log.erl: Linkify also xmpp:..., as it was done previously (thanks to Konstantin Khomoutov)(EJAB-850) diff --git a/README b/README index bbc9511ab..09a4ef40f 100644 --- a/README +++ b/README @@ -8,12 +8,15 @@ Quickstart guide To compile ejabberd you need: - GNU Make - GCC - - libexpat 1.95 or higher - - Erlang/OTP R10B-9 or higher + - Libexpat 1.95 or higher + - Erlang/OTP R12B-5. R13 is not supported yet. - OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended. - Zlib 1.2.3 or higher, for Stream Compression support (XEP-0138). Optional. + - Erlang mysql library. Optional. MySQL authentication/storage. + - Erlang pgsql library. Optional. PostgreSQL authentication/storage. + - PAM library. Optional. For Pluggable Authentication Modules (PAM). - GNU Iconv 1.8 or higher, for the IRC Transport (mod_irc). Optional. Not needed on systems with GNU Libc. diff --git a/doc/guide.html b/doc/guide.html index 631ae306d..4723b9f0e 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -330,7 +330,7 @@ as long as your system have all the dependencies.

    • GCC
    • Libexpat 1.95 or higher -
    • Erlang/OTP R10B-9 or higher. +
    • Erlang/OTP R12B-5. R13 is not supported yet.
    • OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended.
    • Zlib 1.2.3 or higher, for Stream Compression support (XEP-0138). Optional.
    • Erlang mysql library. Optional. For MySQL authentication or storage. See section 3.2.1. diff --git a/doc/guide.tex b/doc/guide.tex index 1c3df924e..31481c1ef 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -298,7 +298,7 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need: \item GNU Make \item GCC \item Libexpat 1.95 or higher -\item Erlang/OTP R10B-9 or higher. +\item Erlang/OTP R12B-5. R13 is not supported yet. \item OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended. \item Zlib 1.2.3 or higher, for Stream Compression support (\xepref{0138}). Optional. \item Erlang mysql library. Optional. For MySQL authentication or storage. See section \ref{compilemysql}. From 5ca560d0bdea7281c66e4bdcbd10c38bdb528353 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 17 Apr 2009 13:40:57 +0000 Subject: [PATCH 276/582] * src/mod_caps.erl: Fix unbound variable SVN Revision: 2022 --- ChangeLog | 4 ++++ src/mod_caps.erl | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index d7c9d8eb1..d4e16fdeb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-04-17 Badlop + + * src/mod_caps.erl: Fix unbound variable + 2009-04-14 Badlop * doc/guide.tex: Explain that the recommended Erlang/OTP version diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 875483807..536e103a2 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -180,7 +180,7 @@ receive_packet(From, To, Packet) when ?IS_PRESENCE(Packet) -> 'unavailable' -> clear_caps(From); _ -> - ServerString = binary_to_list(StateData#state.server), + ServerString = exmpp_jid:ldomain_as_list(To), Els = Packet#xmlel.children, note_caps(ServerString, From, read_caps(Els)) end; From b451f078014d05c951c22ab97633622d5abff945 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 17 Apr 2009 13:43:15 +0000 Subject: [PATCH 277/582] * src/ejabberd_commands.erl: API to restrict who can execute what commands and arguments (EJAB-910) SVN Revision: 2023 --- ChangeLog | 3 + src/ejabberd_commands.erl | 119 ++++++++++++++++++++++++++++++++++---- 2 files changed, 111 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index d4e16fdeb..a7d1f7074 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2009-04-17 Badlop + * src/ejabberd_commands.erl: API to restrict who can execute what + commands and arguments (EJAB-910) + * src/mod_caps.erl: Fix unbound variable 2009-04-14 Badlop diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl index e4e7d4bb1..19b5e5967 100644 --- a/src/ejabberd_commands.erl +++ b/src/ejabberd_commands.erl @@ -216,7 +216,8 @@ get_tags_commands/0, register_commands/1, unregister_commands/1, - execute_command/2 + execute_command/2, + execute_command/4 ]). -include("ejabberd_commands.hrl"). @@ -225,7 +226,7 @@ init() -> ets:new(ejabberd_commands, [named_table, set, public, - {keypos, #ejabberd_commands.name}]). + {keypos, #ejabberd_commands.name}]). %% @spec ([ejabberd_commands()]) -> ok %% @doc Register ejabberd commands. @@ -256,9 +257,9 @@ unregister_commands(Commands) -> list_commands() -> Commands = ets:match(ejabberd_commands, #ejabberd_commands{name = '$1', - args = '$2', - desc = '$3', - _ = '_'}), + args = '$2', + desc = '$3', + _ = '_'}), [{A, B, C} || [A, B, C] <- Commands]. %% @spec (Name::atom()) -> {Args::[aterm()], Result::rterm()} | {error, command_unknown} @@ -266,9 +267,9 @@ list_commands() -> get_command_format(Name) -> Matched = ets:match(ejabberd_commands, #ejabberd_commands{name = Name, - args = '$1', - result = '$2', - _ = '_'}), + args = '$1', + result = '$2', + _ = '_'}), case Matched of [] -> {error, command_unknown}; @@ -287,11 +288,24 @@ get_command_definition(Name) -> %% @spec (Name::atom(), Arguments) -> ResultTerm | {error, command_unknown} %% @doc Execute a command. execute_command(Name, Arguments) -> + execute_command([], noauth, Name, Arguments). + +%% @spec (AccessCommands, AuthList, Name::atom(), Arguments) -> ResultTerm | {error, Error} +%% where +%% AccessCommands = [{Access, CommandNames, Arguments}] +%% Auth = {user, string()}, {server, string()}, {password, string()} | noauth +%% Method = atom() +%% Arguments = [...] +%% Error = command_unknown | account_unprivileged | invalid_account_data | no_auth_provided +execute_command(AccessCommands, Auth, Name, Arguments) -> case ets:lookup(ejabberd_commands, Name) of [Command] -> - execute_command2(Command, Arguments); - [] -> - {error, command_unknown} + try check_access_commands(AccessCommands, Auth, Name, Command, Arguments) of + ok -> execute_command2(Command, Arguments) + catch + {error, Error} -> {error, Error} + end; + [] -> {error, command_unknown} end. execute_command2(Command, Arguments) -> @@ -326,3 +340,86 @@ get_tags_commands() -> orddict:new(), CommandTags), orddict:to_list(Dict). + + +%% ----------------------------- +%% Access verification +%% ----------------------------- + +%% At least one AccessCommand must be satisfied +%% @spec (AccessCommands, Auth, Method, Command, Arguments) -> ok +%% where +%% AccessCommands = [ {Access, CommandNames, Arguments} ] +%% Auth = {User::string(), Server::string(), Password::string()} +%% Method = atom() +%% Arguments = [...] +%% It may throw {error, Error} where +%% Error = account_unprivileged | invalid_account_data | no_auth_provided +check_access_commands([], _Auth, _Method, _Command, _Arguments) -> + ok; +check_access_commands(AccessCommands, Auth, Method, Command, Arguments) -> + {ok, User, Server} = check_auth(Auth), + AccessCommandsAllowed = + lists:filter( + fun({Access, Commands, ArgumentRestrictions}) -> + case check_access(Access, User, Server) of + true -> + check_access_command(Commands, Command, ArgumentRestrictions, + Method, Arguments); + false -> + false + end + end, + AccessCommands), + case AccessCommandsAllowed of + [] -> throw({error, account_unprivileged}); + L when is_list(L) -> ok + end. + +check_auth(noauth) -> + throw({error, no_auth_provided}); +check_auth({User, Server, Password}) -> + %% Check the account exists and password is valid + AccountPass = ejabberd_auth:get_password_s(User, Server), + AccountPassMD5 = get_md5(AccountPass), + case Password of + AccountPass -> {ok, User, Server}; + AccountPassMD5 -> {ok, User, Server}; + _ -> throw({error, invalid_account_data}) + end. + +get_md5(AccountPass) -> + lists:flatten([io_lib:format("~.16B", [X]) + || X <- binary_to_list(crypto:md5(AccountPass))]). + +check_access(Access, User, Server) -> + %% Check this user has access permission + case acl:match_rule(global, Access, jlib:make_jid(User, Server, "")) of + allow -> true; + deny -> false + end. + +check_access_command(Commands, Command, ArgumentRestrictions, Method, Arguments) -> + case Commands==all orelse lists:member(Method, Commands) of + true -> check_access_arguments(Command, ArgumentRestrictions, Arguments); + false -> false + end. + +check_access_arguments(Command, ArgumentRestrictions, Arguments) -> + ArgumentsTagged = tag_arguments(Command#ejabberd_commands.args, Arguments), + lists:all( + fun({ArgName, ArgAllowedValue}) -> + %% If the call uses the argument, check the value is acceptable + case lists:keysearch(ArgName, 1, ArgumentsTagged) of + {value, {ArgName, ArgValue}} -> ArgValue == ArgAllowedValue; + false -> true + end + end, ArgumentRestrictions). + +tag_arguments(ArgsDefs, Args) -> + lists:zipwith( + fun({ArgName, _ArgType}, ArgValue) -> + {ArgName, ArgValue} + end, + ArgsDefs, + Args). From fd967d697672a09da9c06a0715a825b6c054163a Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 17 Apr 2009 13:48:59 +0000 Subject: [PATCH 278/582] * src/ejabberd_ctl.erl: New option to require auth in ejabberdctl and restrict what commands and arguments can execute (EJAB-910) * src/ejabberd_config.erl: Likewise SVN Revision: 2024 --- ChangeLog | 4 ++++ src/ejabberd_config.erl | 2 ++ src/ejabberd_ctl.erl | 47 ++++++++++++++++++++++++++++------------- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index a7d1f7074..58c038417 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2009-04-17 Badlop + * src/ejabberd_ctl.erl: New option to require auth in ejabberdctl + and restrict what commands and arguments can execute (EJAB-910) + * src/ejabberd_config.erl: Likewise + * src/ejabberd_commands.erl: API to restrict who can execute what commands and arguments (EJAB-910) diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 4da6fa5e4..a5b47ed94 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -376,6 +376,8 @@ process_term(Term, State) -> add_option(watchdog_large_heap, LH, State); {registration_timeout, Timeout} -> add_option(registration_timeout, Timeout, State); + {ejabberdctl_access_commands, ACs} -> + add_option(ejabberdctl_access_commands, ACs, State); {loglevel, Loglevel} -> ejabberd_loglevel:set(Loglevel), State; diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl index 62d208e37..32b1ea9d2 100644 --- a/src/ejabberd_ctl.erl +++ b/src/ejabberd_ctl.erl @@ -50,7 +50,7 @@ -export([start/0, init/0, process/1, - process2/1, + process2/2, register_commands/3, unregister_commands/3]). @@ -194,14 +194,20 @@ process(["help" | Mode]) -> end; process(Args) -> - {String, Code} = process2(Args), + AccessCommands = get_accesscommands(), + {String, Code} = process2(Args, AccessCommands), io:format(String), io:format("\n"), Code. -%% @spec (Args::[string()]) -> {String::string(), Code::integer()} -process2(Args) -> - case try_run_ctp(Args) of +%% @spec (Args::[string()], AccessCommands) -> {String::string(), Code::integer()} +process2(["--auth", User, Server, Pass | Args], AccessCommands) -> + process2(Args, {User, Server, Pass}, AccessCommands); +process2(Args, AccessCommands) -> + process2(Args, noauth, AccessCommands). + +process2(Args, Auth, AccessCommands) -> + case try_run_ctp(Args, Auth, AccessCommands) of {String, wrong_command_arguments} when is_list(String) -> io:format(lists:flatten(["\n" | String]++["\n"])), @@ -221,16 +227,22 @@ process2(Args) -> {"Erroneous result: " ++ io_lib:format("~p", [Other]), ?STATUS_ERROR} end. +get_accesscommands() -> + case ejabberd_config:get_local_option(ejabberdctl_access_commands) of + ACs when is_list(ACs) -> ACs; + _ -> [] + end. + %%----------------------------- %% Command calling %%----------------------------- -%% @spec (Args::[string()]) -> string() | integer() | {string(), integer()} -try_run_ctp(Args) -> +%% @spec (Args::[string()], Auth, AccessCommands) -> string() | integer() | {string(), integer()} +try_run_ctp(Args, Auth, AccessCommands) -> try ejabberd_hooks:run_fold(ejabberd_ctl_process, false, [Args]) of false when Args /= [] -> - try_call_command(Args); + try_call_command(Args, Auth, AccessCommands); false -> print_usage(), {"", ?STATUS_USAGE}; @@ -247,9 +259,9 @@ try_run_ctp(Args) -> {io_lib:format("Error in ejabberd ctl process: '~p' ~p", [Error, Why]), ?STATUS_USAGE} end. -%% @spec (Args::[string()]) -> string() | integer() | {string(), integer()} -try_call_command(Args) -> - try call_command(Args) of +%% @spec (Args::[string()], Auth, AccessCommands) -> string() | integer() | {string(), integer()} +try_call_command(Args, Auth, AccessCommands) -> + try call_command(Args, Auth, AccessCommands) of {error, command_unknown} -> {io_lib:format("Error: command ~p not known.", [hd(Args)]), ?STATUS_ERROR}; {error, wrong_number_parameters} -> @@ -262,8 +274,8 @@ try_call_command(Args) -> {io_lib:format("Problem '~p ~p' occurred executing the command.~nStacktrace: ~p", [A, Why, Stack]), ?STATUS_ERROR} end. -%% @spec (Args::[string()]) -> string() | integer() | {string(), integer()} | {error, ErrorType} -call_command([CmdString | Args]) -> +%% @spec (Args::[string()], Auth) -> string() | integer() | {string(), integer()} | {error, ErrorType} +call_command([CmdString | Args], Auth, AccessCommands) -> {ok, CmdStringU, _} = regexp:gsub(CmdString, "-", "_"), Command = list_to_atom(CmdStringU), case ejabberd_commands:get_command_format(Command) of @@ -272,7 +284,7 @@ call_command([CmdString | Args]) -> {ArgsFormat, ResultFormat} -> case (catch format_args(Args, ArgsFormat)) of ArgsFormatted when is_list(ArgsFormatted) -> - Result = ejabberd_commands:execute_command(Command, + Result = ejabberd_commands:execute_command(AccessCommands, Auth, Command, ArgsFormatted), format_result(Result, ResultFormat); {'EXIT', {function_clause,[{lists,zip,[A1, A2]} | _]}} -> @@ -317,6 +329,9 @@ format_arg(Arg, Format) -> %% Format result %%----------------------------- +format_result({error, ErrorAtom}, _) -> + {io_lib:format("Error: ~p", [ErrorAtom]), make_status(error)}; + format_result(Atom, {_Name, atom}) -> io_lib:format("~p", [Atom]); @@ -430,7 +445,9 @@ print_usage(HelpMode, MaxC, ShCode) -> get_list_ctls(), ?PRINT( - ["Usage: ", ?B("ejabberdctl"), " [--node ", ?U("nodename"), "] ", ?U("command"), " [options]\n" + ["Usage: ", ?B("ejabberdctl"), " [--node ", ?U("nodename"), "] [--auth ", + ?U("user"), " ", ?U("host"), " ", ?U("password"), "] ", + ?U("command"), " [", ?U("options"), "]\n" "\n" "Available commands in this ejabberd node:\n"], []), print_usage_commands(HelpMode, MaxC, ShCode, AllCommands), From 554a9a72f10c629c6bd0fa7a253cebf1dbcfcd09 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 17 Apr 2009 13:53:20 +0000 Subject: [PATCH 279/582] * doc/guide.tex: Document new ejabberdctl option. New section that documents AccessCommands. (EJAB-910) * doc/guide.html: Likewise SVN Revision: 2025 --- ChangeLog | 4 + doc/guide.html | 306 ++++++++++++++++++++++++++++++++----------------- doc/guide.tex | 222 +++++++++++++++++++++++++++-------- 3 files changed, 382 insertions(+), 150 deletions(-) diff --git a/ChangeLog b/ChangeLog index 58c038417..d91136760 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2009-04-17 Badlop + * doc/guide.tex: Document new ejabberdctl option. New section that + documents AccessCommands. (EJAB-910) + * doc/guide.html: Likewise + * src/ejabberd_ctl.erl: New option to require auth in ejabberdctl and restrict what commands and arguments can execute (EJAB-910) * src/ejabberd_config.erl: Likewise diff --git a/doc/guide.html b/doc/guide.html index 4723b9f0e..9b5d2596d 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -165,48 +165,53 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;} -
    • Chapter 5  Securing ejabberd +
    • 4.2  ejabberd Commands -
    • Chapter 6  Clustering +
    • 4.3  Web Admin +
    • 4.4  Ad-hoc Commands +
    • 4.5  Change Computer Hostname +
    • +
    • Chapter 5  Securing ejabberd +
    • Chapter 6  Clustering -
    • 6.2  Clustering Setup -
    • 6.3  Service Load-Balancing +6.1  How it Works -
    • -
    • Chapter 7  Debugging +
    • 6.2  Clustering Setup +
    • 6.3  Service Load-Balancing -
    • Appendix A  Internationalization and Localization -
    • Appendix B  Release Notes -
    • Appendix C  Acknowledgements -
    • Appendix D  Copyright Information +
    • +
    • Chapter 7  Debugging + +
    • Appendix A  Internationalization and Localization +
    • Appendix B  Release Notes +
    • Appendix C  Acknowledgements +
    • Appendix D  Copyright Information
    • Chapter 1  Introduction

      ejabberd is a free and open source instant messaging server written in Erlang.

      ejabberd is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.

      ejabberd is designed to be a rock-solid and feature rich XMPP server.

      ejabberd is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.

      @@ -795,7 +800,7 @@ and also allows plain connections for old clients.
    • Port 5269 listens for s2s connections with STARTTLS. The socket is set for IPv6 instead of IPv4.
    • Port 5280 listens for HTTP requests, and serves the HTTP Poll service.
    • Port 5281 listens for HTTP requests, and serves the Web Admin using HTTPS as explained in -section 4.2. The socket only listens connections to the IP address 127.0.0.1. +section 4.3. The socket only listens connections to the IP address 127.0.0.1.
    • {hosts, ["example.com", "example.org", "example.net"]}.
       {listen,
        [
      @@ -839,7 +844,7 @@ only two servers can connect: "jabber.example.org" and "example.com".
       
    • Port 5280 is serving the Web Admin and the HTTP Polling service in all the IPv4 addresses. Note that it is also possible to serve them on different ports. The second -example in section 4.2 shows how exactly this can be done. +example in section 4.3 shows how exactly this can be done.
    • All users except for the administrators have a traffic of limit 1,000 Bytes/second
    • The @@ -2953,9 +2958,19 @@ The default value is true. the processing discipline for Software Version (jabber:iq:version) IQ queries (see section 3.3.2).
    • Chapter 4  Managing an ejabberd Server

      -

      4.1  ejabberdctl

      -

      4.1.1  Commands

      The ejabberdctl command line administration script allows to start, stop and perform -many other administrative tasks in a local or remote ejabberd server.

      When ejabberdctl is executed without any parameter, +

      4.1  ejabberdctl

      With the ejabberdctl command line administration script +you can execute ejabberdctl commands (described in the next section, 4.1.1) +and also many general ejabberd commands (described in section 4.2). +This means you can start, stop and perform many other administrative tasks +in a local or remote ejabberd server (by providing the argument --node NODENAME).

      The ejabberdctl script can be configured in the file ejabberdctl.cfg. +This file includes detailed information about each configurable option. See section 4.1.2.

      The ejabberdctl script returns a numerical status code. +Success is represented by 0, +error is represented by 1, +and other codes may be used for specific results. +This can be used by other scripts to determine automatically +if a command succeeded or failed, +for example using: echo $?

      +

      4.1.1  ejabberdctl Commands

      When ejabberdctl is executed without any parameter, it displays the available options. If there isn’t an ejabberd server running, the available parameters are:

      @@ -2963,45 +2978,34 @@ the available parameters are:
      debug
      Attach an Erlang shell to an already existing ejabberd server. This allows to execute commands interactively in the ejabberd server.
      live
      Start ejabberd in live mode: the shell keeps attached to the started server, showing log messages and allowing to execute interactive commands.

      If there is an ejabberd server running in the system, -ejabberdctl shows all the available commands in that server. -The more interesting ones are: +ejabberdctl shows the ejabberdctl commands described bellow +and all the ejabberd commands available in that server (see 4.2.1).

      The ejabberdctl commands are:

      help
      Get help about ejabberdctl or any available command. Try ejabberdctl help help.
      status
      Check the status of the ejabberd server. -
      stop
      Stop the ejabberd server which is running in the machine. -
      reopen-log
      Reopen the log files after they were renamed. -If the old files were not renamed before calling this command, -they are automatically renamed to "*-old.log". See section 7.1. -
      backup ejabberd.backup
      -Store internal Mnesia database to a binary backup file. -
      restore ejabberd.backup
      -Restore immediately from a binary backup file the internal Mnesia database. -This will consume quite some memory for big servers. -
      install-fallback ejabberd.backup
      -The binary backup file is installed as fallback: -it will be used to restore the database at the next ejabberd start. -Similar to restore, but requires less memory. -
      dump ejabberd.dump
      -Dump internal Mnesia database to a text file dump. -
      load ejabberd.dump
      -Restore immediately from a text file dump. -This is not recommended for big databases, as it will consume much time, -memory and processor. In that case it’s preferable to use backup and install-fallback. -
      import-file, import-dir
      -These options can be used to migrate from other Jabber/XMPP servers. There -exist tutorials to migrate from other software to ejabberd. -
      delete-expired-messages
      This option can be used to delete old messages -in offline storage. This might be useful when the number of offline messages -is very high. -

      The ejabberdctl script also allows the argument --node NODENAME. -This allows to administer a remote node.

      The ejabberdctl script can be configured in the file ejabberdctl.cfg. -This file includes detailed information about each configurable option.

      The ejabberdctl script returns a numerical status code. -Success is represented by 0, -error is represented by 1, -and other codes may be used for specific results. -This can be used by other scripts to determine automatically -if a command succeeded or failed, -for example using: echo $?

      +
      stop
      Stop the ejabberd server. +
      restart
      Restart the ejabberd server. +
      mnesia
      Get information about the Mnesia database. +

      The ejabberdctl script can be restricted to require authentication +and execute some ejabberd commands; see 4.2.2. +Add the option to the file ejabberd.cfg. +In this example there is no restriction: +

      {ejabberdctl_access_commands, []}.
      +

      If account robot1@example.org is registered in ejabberd with password abcdef +(which MD5 is E8B501798950FC58AAD83C8C14978E), +and ejabberd.cfg contains this setting: +

      {hosts, ["example.org"]}.
      +{acl, bots, {user, "robot1", "example.org"}}.
      +{access, ctlaccess, [{allow, bots}]}.
      +{ejabberdctl_access_commands, [ {ctlaccess, [registered_users, register], []} ]}.
      +

      then you can do this in the shell: +

      $ ejabberdctl registered_users example.org
      +Error: no_auth_provided
      +$ ejabberdctl --auth robot1 example.org E8B501798950FC58AAD83C8C14978E registered_users example.org
      +robot1
      +testuser1
      +testuser2
      +

      4.1.2  Erlang Runtime System

      ejabberd is an Erlang/OTP application that runs inside an Erlang runtime system. This system is configured using environment variables and command line parameters. The ejabberdctl administration script uses many of those possibilities. @@ -3070,8 +3074,102 @@ Starts the Erlang system detached from the system console. Open an Erlang shell in a remote Erlang node.

      Note that some characters need to be escaped when used in shell scripts, for instance " and {}. -You can find other options in the Erlang manual page (erl -man erl).

      -

      4.2  Web Admin

      +You can find other options in the Erlang manual page (erl -man erl).

      +

      4.2  ejabberd Commands

      An ejabberd command is an abstract function identified by a name, +with a defined number and type of calling arguments and type of result +that is registered in the ejabberd_commands service. +Those commands can be defined in any Erlang module and executed using any valid frontend.

      ejabberd includes a frontend to execute ejabberd commands: the script ejabberdctl. +Other known frontends that can be installed to execute ejabberd commands in different ways are: +ejabberd_xmlrpc (XML-RPC service), +mod_rest (HTTP POST service), +mod_shcommands (ejabberd WebAdmin page).

      +

      4.2.1  List of ejabberd Commands

      ejabberd includes a few ejabberd Commands by default. +When more modules are installed, new commands may be available in the frontends.

      The easiest way to get a list of the available commands, and get help for them is to use +the ejabberdctl script: +

      $ ejabberdctl help
      +Usage: ejabberdctl [--node nodename] [--auth user host password] command [options]
      +
      +Available commands in this ejabberd node:
      +  backup file                  Store the database to backup file
      +  connected_users              List all established sessions
      +  connected_users_number       Get the number of established sessions
      +  delete_expired_messages      Delete expired offline messages from database
      +  delete_old_messages days     Delete offline messages older than DAYS
      +  ...
      +

      The more interesting ones are: +

      +reopen-log
      Reopen the log files after they were renamed. +If the old files were not renamed before calling this command, +they are automatically renamed to "*-old.log". See section 7.1. +
      backup ejabberd.backup
      +Store internal Mnesia database to a binary backup file. +
      restore ejabberd.backup
      +Restore immediately from a binary backup file the internal Mnesia database. +This will consume quite some memory for big servers. +
      install-fallback ejabberd.backup
      +The binary backup file is installed as fallback: +it will be used to restore the database at the next ejabberd start. +Similar to restore, but requires less memory. +
      dump ejabberd.dump
      +Dump internal Mnesia database to a text file dump. +
      load ejabberd.dump
      +Restore immediately from a text file dump. +This is not recommended for big databases, as it will consume much time, +memory and processor. In that case it’s preferable to use backup and install-fallback. +
      import-file, import-dir
      +These options can be used to migrate from other Jabber/XMPP servers. There +exist tutorials to migrate from other software to ejabberd. +
      delete-expired-messages
      This option can be used to delete old messages +in offline storage. This might be useful when the number of offline messages +is very high. +

      +

      4.2.2  Restrict Execution with AccessCommands

      The frontends can be configured to restrict access to certain commands. +In that case, authentication information must be provided. +In each frontend the AccessCommands option is defined +in a different place. But in all cases the option syntax is the same: +

      AccessCommands = [ {Access, CommandNames, Arguments} ]
      +Access = atom()
      +CommandNames = all | [CommandName]
      +CommandName = atom()
      +Arguments = [{ArgumentName, ArgumentValue}]
      +ArgumentName = atom()
      +ArgumentValue = any()
      +

      The default value is to not define any restriction: []. +If at least one restriction is defined, then the frontend expects +that authentication information is provided when executing a command. +The authentication information is Username, Hostname and Password of a local Jabber account +that has permission to execute the corresponding command. +This means that the account must be registered in the local ejabberd, +because the information will be verified. +It is possible to provide the plaintext password or its MD5 sum.

      When one or several access restrictions are defined and the +authentication information is provided, +each restriction is verified until one matches completely: +the account matches the Access rule, +the command name is listed in CommandNames, +and the provided arguments do not contradict Arguments.

      As an example to understand the syntax, let’s suppose those options: +

      {hosts, ["example.org"]}.
      +{acl, bots, {user, "robot1", "example.org"}}.
      +{access, commaccess, [{allow, bots}]}.
      +

      This list of access restrictions allows only robot1@example.org to execute all commands: +

      [{commaccess, all, []}]
      +

      See another list of restrictions (the corresponding ACL and ACCESS are not shown): +

      [
      + %% This bot can execute all commands:
      + {bot, all, []},
      + %% This bot can only execute the command 'dump'. No argument restriction:
      + {bot_backups, [dump], []}
      + %% This bot can execute all commands,
      + %% but if a 'host' argument is provided, it must be "example.org":
      + {bot_all_example, all, [{host, "example.org"}]},
      + %% This bot can only execute the command 'register',
      + %% and if argument 'host' is provided, it must be "example.org":
      + {bot_reg_example, [register], [{host, "example.org"}]},
      + %% This bot can execute the commands 'register' and 'unregister',
      + %% if argument host is provided, it must be "test.org":
      + {_bot_reg_test, [register, unregister], [{host, "test.org"}]}
      +]
      +

      +

      4.3  Web Admin

      The ejabberd Web Admin allows to administer most of ejabberd using a web browser.

      This feature is enabled by default: a ejabberd_http listener with the option web_admin (see section 3.1.3) is included in the listening ports. Then you can open @@ -3143,13 +3241,13 @@ The file is searched by default in The directory of the documentation can be specified in the environment variable EJABBERD_DOC_PATH. See section 4.1.2.

      -

      4.3  Ad-hoc Commands

      If you enable mod_configure and mod_adhoc, +

      4.4  Ad-hoc Commands

      If you enable mod_configure and mod_adhoc, you can perform several administrative tasks in ejabberd with a Jabber client. The client must support Ad-Hoc Commands (XEP-0050), and you must login in the Jabber server with an account with proper privileges.

      -

      4.4  Change Computer Hostname

      ejabberd uses the distributed Mnesia database. +

      4.5  Change Computer Hostname

      ejabberd uses the distributed Mnesia database. Being distributed, Mnesia enforces consistency of its file, so it stores the name of the Erlang node in it (see section 5.4). The name of an Erlang node includes the hostname of the computer. @@ -3165,8 +3263,8 @@ you must follow these instructions: For example:

      ejabberdctl restore /tmp/ejabberd-oldhost.backup
       

      -

      Chapter 5  Securing ejabberd

      -

      5.1  Firewall Settings

      +

      Chapter 5  Securing ejabberd

      +

      5.1  Firewall Settings

      You need to take the following TCP ports in mind when configuring your firewall:


      @@ -3177,7 +3275,7 @@ you must follow these instructions:
      PortDescription
      port rangeUsed for connections between Erlang nodes. This range is configurable (see section 5.2).

      -

      5.2  epmd

      epmd (Erlang Port Mapper Daemon) +

      5.2  epmd

      epmd (Erlang Port Mapper Daemon) is a small name server included in Erlang/OTP and used by Erlang programs when establishing distributed Erlang communications. ejabberd needs epmd to use ejabberdctl and also when clustering ejabberd nodes. @@ -3202,7 +3300,7 @@ but can be configured in the file ejabberdctl.cfg. The Erlang command-line parameter used internally is, for example:

      erl ... -kernel inet_dist_listen_min 4370 inet_dist_listen_max 4375
       

      -

      5.3  Erlang Cookie

      The Erlang cookie is a string with numbers and letters. +

      5.3  Erlang Cookie

      The Erlang cookie is a string with numbers and letters. An Erlang node reads the cookie at startup from the command-line parameter -setcookie. If not indicated, the cookie is read from the cookie file $HOME/.erlang.cookie. If this file does not exist, it is created immediately with a random cookie. @@ -3216,7 +3314,7 @@ to prevent unauthorized access or intrusion to an Erlang node. The communication between Erlang nodes are not encrypted, so the cookie could be read sniffing the traffic on the network. The recommended way to secure the Erlang node is to block the port 4369.

      -

      5.4  Erlang Node Name

      An Erlang node may have a node name. +

      5.4  Erlang Node Name

      An Erlang node may have a node name. The name can be short (if indicated with the command-line parameter -sname) or long (if indicated with the parameter -name). Starting an Erlang node with -sname limits the communication between Erlang nodes to the LAN.

      Using the option -sname instead of -name is a simple method @@ -3225,7 +3323,7 @@ However, it is not ultimately effective to prevent access to the Erlang node, because it may be possible to fake the fact that you are on another network using a modified version of Erlang epmd. The recommended way to secure the Erlang node is to block the port 4369.

      -

      5.5  Securing Sensible Files

      ejabberd stores sensible data in the file system either in plain text or binary files. +

      5.5  Securing Sensible Files

      ejabberd stores sensible data in the file system either in plain text or binary files. The file system permissions should be set to only allow the proper user to read, write and execute those files and directories.

      ejabberd configuration file: /etc/ejabberd/ejabberd.cfg
      @@ -3245,9 +3343,9 @@ so it is preferable to secure the whole /var/lib/ejabberd/ directory.
      Erlang cookie file: /var/lib/ejabberd/.erlang.cookie
      See section 5.3.

      -

      Chapter 6  Clustering

      +

      Chapter 6  Clustering

      -

      6.1  How it Works

      +

      6.1  How it Works

      A Jabber domain is served by one or more ejabberd nodes. These nodes can be run on different machines that are connected via a network. They all must have the ability to connect to port 4369 of all another nodes, and must @@ -3261,29 +3359,29 @@ router,

    • session manager,
    • s2s manager.
    • -

      6.1.1  Router

      +

      6.1.1  Router

      This module is the main router of Jabber packets on each node. It routes them based on their destination’s domains. It uses a global routing table. The domain of the packet’s destination is searched in the routing table, and if it is found, the packet is routed to the appropriate process. If not, it is sent to the s2s manager.

      -

      6.1.2  Local Router

      +

      6.1.2  Local Router

      This module routes packets which have a destination domain equal to one of this server’s host names. If the destination JID has a non-empty user part, it is routed to the session manager, otherwise it is processed depending on its content.

      -

      6.1.3  Session Manager

      +

      6.1.3  Session Manager

      This module routes packets to local users. It looks up to which user resource a packet must be sent via a presence table. Then the packet is either routed to the appropriate c2s process, or stored in offline storage, or bounced back.

      -

      6.1.4  s2s Manager

      +

      6.1.4  s2s Manager

      This module routes packets to other Jabber servers. First, it checks if an opened s2s connection from the domain of the packet’s source to the domain of the packet’s destination exists. If that is the case, the s2s manager routes the packet to the process serving this connection, otherwise a new connection is opened.

      -

      6.2  Clustering Setup

      +

      6.2  Clustering Setup

      Suppose you already configured ejabberd on one machine named (first), and you need to setup another one to make an ejabberd cluster. Then do following steps:

      1. @@ -3321,10 +3419,10 @@ and ‘access’ options because they will be taken from enabled only on one machine in the cluster.

      You can repeat these steps for other machines supposed to serve this domain.

      -

      6.3  Service Load-Balancing

      +

      6.3  Service Load-Balancing

      -

      6.3.1  Components Load-Balancing

      -

      6.3.2  Domain Load-Balancing Algorithm

      +

      6.3.1  Components Load-Balancing

      +

      6.3.2  Domain Load-Balancing Algorithm

      ejabberd includes an algorithm to load balance the components that are plugged on an ejabberd cluster. It means that you can plug one or several instances of the same component on each ejabberd cluster and that the traffic will be automatically distributed.

      The default distribution algorithm try to deliver to a local instance of a component. If several local instances are available, one instance is chosen randomly. If no instance is available locally, one instance is chosen randomly among the remote component instances.

      If you need a different behaviour, you can change the load balancing behaviour with the option domain_balancing. The syntax of the option is the following:

      {domain_balancing, "component.example.com", <balancing_criterium>}.
       

      Several balancing criteria are available:

      • @@ -3333,13 +3431,13 @@ domain.

        -

        6.3.3  Load-Balancing Buckets

        +

        6.3.3  Load-Balancing Buckets

        When there is a risk of failure for a given component, domain balancing can cause service trouble. If one component is failing the service will not work correctly unless the sessions are rebalanced.

        In this case, it is best to limit the problem to the sessions handled by the failing component. This is what the domain_balancing_component_number option does, making the load balancing algorithm not dynamic, but sticky on a fix number of component instances.

        The syntax is the following:

        {domain_balancing_component_number, "component.example.com", N}
         

        -

        Chapter 7  Debugging

        +

        Chapter 7  Debugging

        -

        7.1  Log Files

        An ejabberd node writes two log files: +

        7.1  Log Files

        An ejabberd node writes two log files:

        ejabberd.log
        is the ejabberd service log, with the messages reported by ejabberd code
        sasl.log
        is the Erlang/OTP system log, with the messages reported by Erlang/OTP using SASL (System Architecture Support Libraries) @@ -3357,16 +3455,16 @@ For example, the default configuration is:

        {loglevel, 4}.
         

        The log files grow continually, so it is recommended to rotate them periodically. To rotate the log files, rename the files and then reopen them. -The ejabberd command reopen-log -(please refer to section 4.1.1) +The ejabberdctl command reopen-log +(please refer to section 4.1.1) reopens the log files, and also renames the old ones if you didn’t rename them.

        -

        7.2  Debug Console

        The Debug Console is an Erlang shell attached to an already running ejabberd server. +

        7.2  Debug Console

        The Debug Console is an Erlang shell attached to an already running ejabberd server. With this Erlang shell, an experienced administrator can perform complex tasks.

        This shell gives complete control over the ejabberd server, so it is important to use it with extremely care. There are some simple and safe examples in the article Interconnecting Erlang Nodes

        To exit the shell, close the window or press the keys: control+c control+c.

        -

        7.3  Watchdog Alerts

        +

        7.3  Watchdog Alerts

        ejabberd includes a watchdog mechanism that may be useful to developers when troubleshooting a problem related to memory usage. If a process in the ejabberd server consumes more memory than the configured threshold, @@ -3384,7 +3482,7 @@ or in a conversation with the watchdog alert bot.

        Example configuration: To remove all watchdog admins, set the option with an empty list:

        {watchdog_admins, []}.
         

        -

        Appendix A  Internationalization and Localization

        +

        Appendix A  Internationalization and Localization

        The source code of ejabberd supports localization. The translators can edit the gettext .po files @@ -3419,9 +3517,9 @@ HTTP header ‘Accept-Language: ru’


  • -

    Appendix B  Release Notes

    +

    Appendix B  Release Notes

    Release notes are available from ejabberd Home Page

    -

    Appendix C  Acknowledgements

    Thanks to all people who contributed to this guide: +

    Appendix C  Acknowledgements

    Thanks to all people who contributed to this guide:

    -

    Appendix D  Copyright Information

    Ejabberd Installation and Operation Guide.
    +

    Appendix D  Copyright Information

    Ejabberd Installation and Operation Guide.
    Copyright © 2003 — 2009 ProcessOne

    This document 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 diff --git a/doc/guide.tex b/doc/guide.tex index 31481c1ef..0f691af9a 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -3809,10 +3809,24 @@ Options: \makesection{ejabberdctl}{\term{ejabberdctl}} -\makesubsection{commands}{Commands} +With the \term{ejabberdctl} command line administration script +you can execute \term{ejabberdctl commands} (described in the next section, \ref{ectl-commands}) +and also many general \term{ejabberd commands} (described in section \ref{eja-commands}). +This means you can start, stop and perform many other administrative tasks +in a local or remote \ejabberd{} server (by providing the argument \term{--node NODENAME}). -The \term{ejabberdctl} command line administration script allows to start, stop and perform -many other administrative tasks in a local or remote \ejabberd{} server. +The \term{ejabberdctl} script can be configured in the file \term{ejabberdctl.cfg}. +This file includes detailed information about each configurable option. See section \ref{erlangconfiguration}. + +The \term{ejabberdctl} script returns a numerical status code. +Success is represented by \term{0}, +error is represented by \term{1}, +and other codes may be used for specific results. +This can be used by other scripts to determine automatically +if a command succeeded or failed, +for example using: \term{echo \$?} + +\makesubsection{ectl-commands}{ejabberdctl Commands} When \term{ejabberdctl} is executed without any parameter, it displays the available options. If there isn't an \ejabberd{} server running, @@ -3824,53 +3838,44 @@ the available parameters are: \end{description} If there is an \ejabberd{} server running in the system, -\term{ejabberdctl} shows all the available commands in that server. -The more interesting ones are: +\term{ejabberdctl} shows the \term{ejabberdctl commands} described bellow +and all the \term{ejabberd commands} available in that server (see \ref{list-eja-commands}). + +The \term{ejabberdctl commands} are: \begin{description} \titem{help} Get help about ejabberdctl or any available command. Try \term{ejabberdctl help help}. \titem{status} Check the status of the \ejabberd{} server. -\titem{stop} Stop the \ejabberd{} server which is running in the machine. -\titem{reopen-log} Reopen the log files after they were renamed. - If the old files were not renamed before calling this command, - they are automatically renamed to \term{"*-old.log"}. See section \ref{logfiles}. -\titem {backup ejabberd.backup} - Store internal Mnesia database to a binary backup file. -\titem {restore ejabberd.backup} - Restore immediately from a binary backup file the internal Mnesia database. - This will consume quite some memory for big servers. -\titem {install-fallback ejabberd.backup} - The binary backup file is installed as fallback: - it will be used to restore the database at the next ejabberd start. - Similar to \term{restore}, but requires less memory. -\titem {dump ejabberd.dump} - Dump internal Mnesia database to a text file dump. -\titem {load ejabberd.dump} - Restore immediately from a text file dump. - This is not recommended for big databases, as it will consume much time, - memory and processor. In that case it's preferable to use \term{backup} and \term{install-fallback}. -%%More information about backuping can -%% be found in section~\ref{backup}. -\titem{import-file, import-dir} \ind{migration from other software} - These options can be used to migrate from other \Jabber{}/XMPP servers. There - exist tutorials to \footahref{http://www.ejabberd.im/migrate-to-ejabberd}{migrate from other software to ejabberd}. -\titem{delete-expired-messages} This option can be used to delete old messages - in offline storage. This might be useful when the number of offline messages - is very high. +\titem{stop} Stop the \ejabberd{} server. +\titem{restart} Restart the \ejabberd{} server. +\titem{mnesia} Get information about the Mnesia database. \end{description} -The \term{ejabberdctl} script also allows the argument \term{--node NODENAME}. -This allows to administer a remote node. +The \term{ejabberdctl} script can be restricted to require authentication +and execute some \term{ejabberd commands}; see \ref{accesscommands}. +Add the option to the file \term{ejabberd.cfg}. +In this example there is no restriction: +\begin{verbatim} +{ejabberdctl_access_commands, []}. +\end{verbatim} -The \term{ejabberdctl} script can be configured in the file \term{ejabberdctl.cfg}. -This file includes detailed information about each configurable option. - -The \term{ejabberdctl} script returns a numerical status code. -Success is represented by \term{0}, -error is represented by \term{1}, -and other codes may be used for specific results. -This can be used by other scripts to determine automatically -if a command succeeded or failed, -for example using: \term{echo \$?} +If account \term{robot1@example.org} is registered in \ejabberd{} with password \term{abcdef} +(which MD5 is E8B501798950FC58AAD83C8C14978E), +and \term{ejabberd.cfg} contains this setting: +\begin{verbatim} +{hosts, ["example.org"]}. +{acl, bots, {user, "robot1", "example.org"}}. +{access, ctlaccess, [{allow, bots}]}. +{ejabberdctl_access_commands, [ {ctlaccess, [registered_users, register], []} ]}. +\end{verbatim} +then you can do this in the shell: +\begin{verbatim} +$ ejabberdctl registered_users example.org +Error: no_auth_provided +$ ejabberdctl --auth robot1 example.org E8B501798950FC58AAD83C8C14978E registered_users example.org +robot1 +testuser1 +testuser2 +\end{verbatim} \makesubsection{erlangconfiguration}{Erlang Runtime System} @@ -3949,6 +3954,131 @@ The command line parameters: Note that some characters need to be escaped when used in shell scripts, for instance \verb|"| and \verb|{}|. You can find other options in the Erlang manual page (\shell{erl -man erl}). +\makesection{eja-commands}{\ejabberd{} Commands} + +An \term{ejabberd command} is an abstract function identified by a name, +with a defined number and type of calling arguments and type of result +that is registered in the \term{ejabberd\_commands} service. +Those commands can be defined in any Erlang module and executed using any valid frontend. + +\ejabberd{} includes a frontend to execute \term{ejabberd commands}: the script \term{ejabberdctl}. +Other known frontends that can be installed to execute ejabberd commands in different ways are: +\term{ejabberd\_xmlrpc} (XML-RPC service), +\term{mod\_rest} (HTTP POST service), +\term{mod\_shcommands} (ejabberd WebAdmin page). + +\makesubsection{list-eja-commands}{List of ejabberd Commands} + +\ejabberd{} includes a few ejabberd Commands by default. +When more modules are installed, new commands may be available in the frontends. + +The easiest way to get a list of the available commands, and get help for them is to use +the ejabberdctl script: +\begin{verbatim} +$ ejabberdctl help +Usage: ejabberdctl [--node nodename] [--auth user host password] command [options] + +Available commands in this ejabberd node: + backup file Store the database to backup file + connected_users List all established sessions + connected_users_number Get the number of established sessions + delete_expired_messages Delete expired offline messages from database + delete_old_messages days Delete offline messages older than DAYS + ... +\end{verbatim} + +The more interesting ones are: +\begin{description} +\titem{reopen-log} Reopen the log files after they were renamed. + If the old files were not renamed before calling this command, + they are automatically renamed to \term{"*-old.log"}. See section \ref{logfiles}. +\titem {backup ejabberd.backup} + Store internal Mnesia database to a binary backup file. +\titem {restore ejabberd.backup} + Restore immediately from a binary backup file the internal Mnesia database. + This will consume quite some memory for big servers. +\titem {install-fallback ejabberd.backup} + The binary backup file is installed as fallback: + it will be used to restore the database at the next ejabberd start. + Similar to \term{restore}, but requires less memory. +\titem {dump ejabberd.dump} + Dump internal Mnesia database to a text file dump. +\titem {load ejabberd.dump} + Restore immediately from a text file dump. + This is not recommended for big databases, as it will consume much time, + memory and processor. In that case it's preferable to use \term{backup} and \term{install-fallback}. +%%More information about backuping can +%% be found in section~\ref{backup}. +\titem{import-file, import-dir} \ind{migration from other software} + These options can be used to migrate from other \Jabber{}/XMPP servers. There + exist tutorials to \footahref{http://www.ejabberd.im/migrate-to-ejabberd}{migrate from other software to ejabberd}. +\titem{delete-expired-messages} This option can be used to delete old messages + in offline storage. This might be useful when the number of offline messages + is very high. +\end{description} + +\makesubsection{accesscommands}{Restrict Execution with AccessCommands} + +The frontends can be configured to restrict access to certain commands. +In that case, authentication information must be provided. +In each frontend the \term{AccessCommands} option is defined +in a different place. But in all cases the option syntax is the same: +\begin{verbatim} +AccessCommands = [ {Access, CommandNames, Arguments} ] +Access = atom() +CommandNames = all | [CommandName] +CommandName = atom() +Arguments = [{ArgumentName, ArgumentValue}] +ArgumentName = atom() +ArgumentValue = any() +\end{verbatim} + +The default value is to not define any restriction: \term{[]}. +If at least one restriction is defined, then the frontend expects +that authentication information is provided when executing a command. +The authentication information is Username, Hostname and Password of a local Jabber account +that has permission to execute the corresponding command. +This means that the account must be registered in the local ejabberd, +because the information will be verified. +It is possible to provide the plaintext password or its MD5 sum. + +When one or several access restrictions are defined and the +authentication information is provided, +each restriction is verified until one matches completely: +the account matches the Access rule, +the command name is listed in CommandNames, +and the provided arguments do not contradict Arguments. + +As an example to understand the syntax, let's suppose those options: +\begin{verbatim} +{hosts, ["example.org"]}. +{acl, bots, {user, "robot1", "example.org"}}. +{access, commaccess, [{allow, bots}]}. +\end{verbatim} + +This list of access restrictions allows only \term{robot1@example.org} to execute all commands: +\begin{verbatim} +[{commaccess, all, []}] +\end{verbatim} + +See another list of restrictions (the corresponding ACL and ACCESS are not shown): +\begin{verbatim} +[ + %% This bot can execute all commands: + {bot, all, []}, + %% This bot can only execute the command 'dump'. No argument restriction: + {bot_backups, [dump], []} + %% This bot can execute all commands, + %% but if a 'host' argument is provided, it must be "example.org": + {bot_all_example, all, [{host, "example.org"}]}, + %% This bot can only execute the command 'register', + %% and if argument 'host' is provided, it must be "example.org": + {bot_reg_example, [register], [{host, "example.org"}]}, + %% This bot can execute the commands 'register' and 'unregister', + %% if argument host is provided, it must be "test.org": + {_bot_reg_test, [register, unregister], [{host, "test.org"}]} +] +\end{verbatim} \makesection{webadmin}{Web Admin} \ind{web admin} @@ -4408,8 +4538,8 @@ For example, the default configuration is: The log files grow continually, so it is recommended to rotate them periodically. To rotate the log files, rename the files and then reopen them. -The ejabberd command \term{reopen-log} -(please refer to section \ref{commands}) +The ejabberdctl command \term{reopen-log} +(please refer to section \ref{ectl-commands}) reopens the log files, and also renames the old ones if you didn't rename them. From 6e37389145a39f2c19223968b724c0d3d54b1857 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 17 Apr 2009 20:43:12 +0000 Subject: [PATCH 280/582] fix missing greetings SVN Revision: 2026 --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index d91136760..1bb2d734d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -26,6 +26,7 @@ 2009-03-20 Christophe Romain * src/mod_caps.erl: Better handling of presence hook and caps clean + (thanks to Jonathan Schleifer)(EJAB-707) * src/ejabberd_c2s.erl: Likewise * src/mod_pubsub/mod_pubsub.erl: Likewise From 39f71ab2abe43e97d13d551bace9acde6a68db36 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 22 Apr 2009 10:40:11 +0000 Subject: [PATCH 281/582] * src/mod_shared_roster.erl: Support in API to add 'all' as member of a group (thanks to Martin Langhoff)(EJAB-916) SVN Revision: 2031 --- ChangeLog | 5 ++++ src/mod_shared_roster.erl | 63 +++++++++++++++++++++++++++------------ 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1bb2d734d..e99c92731 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-04-22 Badlop + + * src/mod_shared_roster.erl: Support in API to add 'all' as member + of a group (thanks to Martin Langhoff)(EJAB-916) + 2009-04-17 Badlop * doc/guide.tex: Document new ejabberdctl option. New section that diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 8de3e11f4..81adde1d8 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -561,15 +561,28 @@ is_user_in_group({_U, S} = US, Group, Host) -> %% @spec (Host::string(), {User::string(), Server::string()}, Group::string()) -> {atomic, ok} add_user_to_group(Host, US, Group) -> {LUser, LServer} = US, - %% Push this new user to members of groups where this group is displayed - push_user_to_displayed(LUser, LServer, Group, both), - %% Push members of groups that are displayed to this group - push_displayed_to_user(LUser, LServer, Group, Host, both), - R = #sr_user{us = US, group_host = {Group, Host}}, - F = fun() -> - mnesia:write(R) - end, - mnesia:transaction(F). + case regexp:match(LUser, "^@.+@$") of + {match,_,_} -> + GroupOpts = mod_shared_roster:get_group_opts(Host, Group), + AllUsersOpt = + case LUser == "@all@" of + true -> [{all_users, true}]; + false -> [] + end, + mod_shared_roster:set_group_opts( + Host, Group, + GroupOpts ++ AllUsersOpt); + nomatch -> + %% Push this new user to members of groups where this group is displayed + push_user_to_displayed(LUser, LServer, Group, both), + %% Push members of groups that are displayed to this group + push_displayed_to_user(LUser, LServer, Group, Host, both), + R = #sr_user{us = US, group_host = {Group, Host}}, + F = fun() -> + mnesia:write(R) + end, + mnesia:transaction(F) + end. push_displayed_to_user(LUser, LServer, Group, Host, Subscription) -> GroupsOpts = groups_with_opts(LServer), @@ -579,17 +592,29 @@ push_displayed_to_user(LUser, LServer, Group, Host, Subscription) -> remove_user_from_group(Host, US, Group) -> GroupHost = {Group, Host}, - R = #sr_user{us = US, group_host = GroupHost}, - F = fun() -> - mnesia:delete_object(R) - end, - Result = mnesia:transaction(F), {LUser, LServer} = US, - %% Push removal of the old user to members of groups where the group that this user was members was displayed - push_user_to_displayed(LUser, LServer, Group, remove), - %% Push removal of members of groups that where displayed to the group which this user has left - push_displayed_to_user(LUser, LServer, Group, Host, remove), - Result. + case regexp:match(LUser, "^@.+@$") of + {match,_,_} -> + GroupOpts = mod_shared_roster:get_group_opts(Host, Group), + NewGroupOpts = + case LUser of + "@all@" -> + lists:filter(fun(X) -> X/={all_users,true} end, GroupOpts) + end, + mod_shared_roster:set_group_opts(Host, Group, NewGroupOpts); + nomatch -> + R = #sr_user{us = US, group_host = GroupHost}, + F = fun() -> + mnesia:delete_object(R) + end, + Result = mnesia:transaction(F), + %% Push removal of the old user to members of groups where the group that this user was members was displayed + push_user_to_displayed(LUser, LServer, Group, remove), + %% Push removal of members of groups that where displayed to the group which this user has left + push_displayed_to_user(LUser, LServer, Group, Host, remove), + Result + end. + push_members_to_user(LUser, LServer, Group, Host, Subscription) -> GroupsOpts = groups_with_opts(LServer), From 240e37c38762a6abc0cb3a966b034951534c3af7 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 22 Apr 2009 11:02:03 +0000 Subject: [PATCH 282/582] * src/ejabberd_c2s.erl: Fix for SASL Anonymous connections not stored or purged (thanks to Andy Skelton)(EJAB-912) SVN Revision: 2032 --- ChangeLog | 3 +++ src/ejabberd_c2s.erl | 14 ++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index e99c92731..4d6264c0a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2009-04-22 Badlop + * src/ejabberd_c2s.erl: Fix for SASL Anonymous connections not + stored or purged (thanks to Andy Skelton)(EJAB-912) + * src/mod_shared_roster.erl: Support in API to add 'all' as member of a group (thanks to Martin Langhoff)(EJAB-916) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 67a55757d..762961a95 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -407,9 +407,9 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> StateData#state.streamid, D) of {true, AuthModule} -> ?INFO_MSG( - "(~w) Accepted legacy authentication for ~s", + "(~w) Accepted legacy authentication for ~s by ~s", [StateData#state.socket, - exmpp_jid:jid_to_binary(JID)]), + exmpp_jid:jid_to_binary(JID), AuthModule]), SID = {now(), self()}, Conn = get_conn_type(StateData), Info = [{ip, StateData#state.ip}, {conn, Conn}, @@ -513,12 +513,14 @@ wait_for_feature_request({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, StateData#state.socket), send_element(StateData, exmpp_server_sasl:success()), U = proplists:get_value(username, Props), - ?INFO_MSG("(~w) Accepted authentication for ~s", - [StateData#state.socket, U]), + AuthModule = proplists:get_value(auth_module, Props), + ?INFO_MSG("(~w) Accepted authentication for ~s by ~s", + [StateData#state.socket, U, AuthModule]), fsm_next_state(wait_for_stream, StateData#state{ streamid = new_id(), authenticated = true, + auth_module = AuthModule, user = list_to_binary(U) }); {continue, ServerOut, NewSASLState} -> send_element(StateData, @@ -628,8 +630,8 @@ wait_for_sasl_response({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, send_element(StateData, exmpp_server_sasl:success()), U = proplists:get_value(username, Props), AuthModule = proplists:get_value(auth_module, Props), - ?INFO_MSG("(~w) Accepted authentication for ~s", - [StateData#state.socket, U]), + ?INFO_MSG("(~w) Accepted authentication for ~s by ~s", + [StateData#state.socket, U, AuthModule]), fsm_next_state(wait_for_stream, StateData#state{ streamid = new_id(), From 43b59911e2f4473ce87fc067057771cf2f0b3765 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 22 Apr 2009 11:44:03 +0000 Subject: [PATCH 283/582] * src/cyrsasl.erl: Change API of check_password: pass a function to generate the digest (thanks to Graham Whitted)(EJAB-863) * src/cyrsasl_anonymous.erl: Likewise * src/cyrsasl_digest.erl: Likewise * src/cyrsasl_plain.erl: Likewise * src/ejabberd_auth.erl: Likewise * src/ejabberd_auth_anonymous.erl: Likewise * src/ejabberd_auth_external.erl: Likewise * src/ejabberd_auth_internal.erl: Likewise * src/ejabberd_auth_ldap.erl: Likewise * src/ejabberd_auth_odbc.erl: Likewise * src/ejabberd_auth_pam.erl: Likewise * src/ejabberd_c2s.erl: Likewise SVN Revision: 2033 --- ChangeLog | 17 +++++++++++++++++ src/cyrsasl.erl | 14 ++++++++------ src/cyrsasl_anonymous.erl | 6 +++--- src/cyrsasl_digest.erl | 24 +++++++++++++----------- src/cyrsasl_plain.erl | 6 +++--- src/ejabberd_auth.erl | 20 ++++++++++---------- src/ejabberd_auth_anonymous.erl | 4 ++-- src/ejabberd_auth_external.erl | 6 +++--- src/ejabberd_auth_internal.erl | 8 ++++---- src/ejabberd_auth_ldap.erl | 6 +++--- src/ejabberd_auth_odbc.erl | 8 ++++---- src/ejabberd_auth_pam.erl | 4 ++-- src/ejabberd_c2s.erl | 8 +++++++- 13 files changed, 79 insertions(+), 52 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4d6264c0a..fbe370c96 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,22 @@ 2009-04-22 Badlop + * src/cyrsasl.erl: Change API of check_password: pass a function + to generate the digest (thanks to Graham Whitted)(EJAB-863) + * src/cyrsasl_anonymous.erl: Likewise + * src/cyrsasl_digest.erl: Likewise + * src/cyrsasl_plain.erl: Likewise + * src/ejabberd_auth.erl: Likewise + * src/ejabberd_auth_anonymous.erl: Likewise + * src/ejabberd_auth_external.erl: Likewise + * src/ejabberd_auth_internal.erl: Likewise + * src/ejabberd_auth_ldap.erl: Likewise + * src/ejabberd_auth_odbc.erl: Likewise + * src/ejabberd_auth_pam.erl: Likewise + * src/ejabberd_c2s.erl: Likewise + + * src/ejabberd_c2s.erl: Fix for SASL Anonymous connections not + stored or purged (thanks to Andy Skelton)(EJAB-912) + * src/ejabberd_c2s.erl: Fix for SASL Anonymous connections not stored or purged (thanks to Andy Skelton)(EJAB-912) diff --git a/src/cyrsasl.erl b/src/cyrsasl.erl index 1f99f63ee..c1287e080 100644 --- a/src/cyrsasl.erl +++ b/src/cyrsasl.erl @@ -30,7 +30,7 @@ -export([start/0, register_mechanism/3, listmech/1, - server_new/6, + server_new/7, server_start/3, server_step/2]). @@ -53,7 +53,7 @@ %% State of this process. -record(sasl_state, {service, myname, realm, - get_password, check_password, + get_password, check_password, check_password_digest, mech_mod, mech_state}). -export([behaviour_info/1]). @@ -61,7 +61,7 @@ %% @hidden behaviour_info(callbacks) -> - [{mech_new, 3}, {mech_step, 2}]; + [{mech_new, 4}, {mech_step, 2}]; behaviour_info(_Other) -> undefined. @@ -157,12 +157,13 @@ listmech(Host) -> %% CheckPassword = function() server_new(Service, ServerFQDN, UserRealm, _SecFlags, - GetPassword, CheckPassword) -> + GetPassword, CheckPassword, CheckPasswordDigest) -> #sasl_state{service = Service, myname = ServerFQDN, realm = UserRealm, get_password = GetPassword, - check_password = CheckPassword}. + check_password = CheckPassword, + check_password_digest= CheckPasswordDigest}. %% @spec (State, Mech, ClientIn) -> Ok | Continue | Error %% State = saslstate() @@ -188,7 +189,8 @@ server_start(State, Mech, ClientIn) -> {ok, MechState} = Module:mech_new( State#sasl_state.myname, State#sasl_state.get_password, - State#sasl_state.check_password), + State#sasl_state.check_password, + State#sasl_state.check_password_digest), server_step(State#sasl_state{mech_mod = Module, mech_state = MechState}, ClientIn); diff --git a/src/cyrsasl_anonymous.erl b/src/cyrsasl_anonymous.erl index 84dc24831..d90838918 100644 --- a/src/cyrsasl_anonymous.erl +++ b/src/cyrsasl_anonymous.erl @@ -27,7 +27,7 @@ -module(cyrsasl_anonymous). --export([start/1, stop/0, mech_new/3, mech_step/2]). +-export([start/1, stop/0, mech_new/4, mech_step/2]). -behaviour(cyrsasl). @@ -48,13 +48,13 @@ start(_Opts) -> stop() -> ok. -%% @spec (Host, GetPassword, CheckPassword) -> {ok, State} +%% @spec (Host, GetPassword, CheckPassword, CheckPasswordDigest) -> {ok, State} %% Host = string() %% GetPassword = function() %% CheckPassword = function() %% State = mechstate() -mech_new(Host, _GetPassword, _CheckPassword) -> +mech_new(Host, _GetPassword, _CheckPassword, _CheckPasswordDigest) -> {ok, #state{server = Host}}. %% @spec (State, ClientIn) -> Ok | Error diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl index 1f07e407f..4c2a2a103 100644 --- a/src/cyrsasl_digest.erl +++ b/src/cyrsasl_digest.erl @@ -11,14 +11,14 @@ -export([start/1, stop/0, - mech_new/3, + mech_new/4, mech_step/2]). -include("ejabberd.hrl"). -behaviour(cyrsasl). -%% @type mechstate() = {state, Step, Nonce, Username, AuthzId, GetPassword, AuthModule, Host} +%% @type mechstate() = {state, Step, Nonce, Username, AuthzId, GetPassword, CheckPassword, AuthModule, Host} %% Step = 1 | 3 | 5 %% Nonce = string() %% Username = string() @@ -27,7 +27,7 @@ %% AuthModule = atom() %% Host = string(). --record(state, {step, nonce, username, authzid, get_password, auth_module, +-record(state, {step, nonce, username, authzid, get_password, check_password, auth_module, host}). %% @spec (Opts) -> true @@ -41,17 +41,18 @@ start(_Opts) -> stop() -> ok. -%% @spec (Host, GetPassword, CheckPassword) -> {ok, State} +%% @spec (Host, GetPassword, CheckPassword, CheckPasswordDigest) -> {ok, State} %% Host = string() %% GetPassword = function() %% CheckPassword = function() %% State = mechstate() -mech_new(Host, GetPassword, _CheckPassword) -> +mech_new(Host, GetPassword, _CheckPassword, CheckPasswordDigest) -> {ok, #state{step = 1, nonce = randoms:get_string(), host = Host, - get_password = GetPassword}}. + get_password = GetPassword, + check_password = CheckPasswordDigest}}. %% @spec (State, ClientIn) -> Ok | Continue | Error %% State = mechstate() @@ -91,10 +92,11 @@ mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) -> {false, _} -> {error, 'not-authorized', UserName}; {Passwd, AuthModule} -> - Response = response(KeyVals, UserName, Passwd, - Nonce, AuthzId, "AUTHENTICATE"), - case proplists:get_value("response", KeyVals, "") of - Response -> + case (State#state.check_password)(UserName, Passwd, + proplists:get_value("response", KeyVals, ""), + fun(PW) -> response(KeyVals, UserName, PW, Nonce, AuthzId, + "AUTHENTICATE") end) of + {true, _} -> RspAuth = response(KeyVals, UserName, Passwd, Nonce, AuthzId, ""), @@ -104,7 +106,7 @@ mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) -> auth_module = AuthModule, username = UserName, authzid = AuthzId}}; - _ -> + {false, _} -> {error, 'not-authorized', UserName} end end diff --git a/src/cyrsasl_plain.erl b/src/cyrsasl_plain.erl index ffcf4b104..12576c77a 100644 --- a/src/cyrsasl_plain.erl +++ b/src/cyrsasl_plain.erl @@ -27,7 +27,7 @@ -module(cyrsasl_plain). -author('alexey@process-one.net'). --export([start/1, stop/0, mech_new/3, mech_step/2, parse/1]). +-export([start/1, stop/0, mech_new/4, mech_step/2, parse/1]). -behaviour(cyrsasl). @@ -48,13 +48,13 @@ start(_Opts) -> stop() -> ok. -%% @spec (Host, GetPassword, CheckPassword) -> {ok, State} +%% @spec (Host, GetPassword, CheckPassword, CheckPasswordDigest) -> {ok, State} %% Host = string() %% GetPassword = function() %% CheckPassword = function() %% State = mechstate() -mech_new(_Host, _GetPassword, CheckPassword) -> +mech_new(_Host, _GetPassword, CheckPassword, _CheckPasswordDigest) -> {ok, #state{check_password = CheckPassword}}. %% @spec (State, ClientIn) -> Ok | Error diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 357e5cfae..bce8bd3cf 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -97,19 +97,19 @@ check_password(User, Server, Password) false -> false end. -%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% @spec (User, Server, Password, Digest, DigestGen) -> bool() %% User = string() %% Server = string() %% Password = string() -%% StreamID = string() %% Digest = string() +%% DigestGen = function() %% @doc Check if the user and password can login in server. -check_password(User, Server, Password, StreamID, Digest) +check_password(User, Server, Password, Digest, DigestGen) when is_list(User), is_list(Server), is_list(Password), - is_list(StreamID), is_list(Digest) -> + is_list(Digest), is_function(DigestGen) -> case check_password_with_authmodule(User, Server, Password, - StreamID, Digest) of + Digest, DigestGen) of {true, _AuthModule} -> true; false -> false end. @@ -128,22 +128,22 @@ check_password_with_authmodule(User, Server, Password) when is_list(User), is_list(Server), is_list(Password) -> check_password_loop(auth_modules(Server), [User, Server, Password]). -%% @spec (User, Server, Password, StreamID, Digest) -> {true, AuthModule} | false +%% @spec (User, Server, Password, Digest, DigestGen) -> {true, AuthModule} | false %% User = string() %% Server = string() %% Password = string() | undefined -%% StreamID = string() %% Digest = string() | undefined +%% DigestGen = function() %% AuthModule = authmodule() %% The password is 'undefined' if the client %% authenticates using the digest method as defined in %% XEP-0078: Non-SASL Authentication -check_password_with_authmodule(User, Server, Password, StreamID, Digest) +check_password_with_authmodule(User, Server, Password, Digest, DigestGen) when is_list(User), is_list(Server), (is_list(Password) orelse Password == 'undefined'), - is_list(StreamID), (is_list(Digest) orelse Digest == 'undefined')-> + is_function(DigestGen), (is_list(Digest) orelse Digest == 'undefined')-> check_password_loop(auth_modules(Server), [User, Server, Password, - StreamID, Digest]). + Digest, DigestGen]). check_password_loop([], _Args) -> false; diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index 440fa16ca..0a9361180 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -229,7 +229,7 @@ purge_hook(true, LUser, LServer) when is_list(LUser), is_list(LServer) -> check_password(User, Server, Password) -> check_password(User, Server, Password, undefined, undefined). -check_password(User, Server, _Password, _StreamID, _Digest) -> +check_password(User, Server, _Password, _Digest, _DigestGen) -> %% We refuse login for registered accounts (They cannot logged but %% they however are "reserved") case ejabberd_auth:is_user_exists_in_other_modules(?MODULE, @@ -310,7 +310,7 @@ get_password(User, Server) -> %% DefaultValue = string() get_password(User, Server, DefaultValue) -> - case anonymous_user_exist(User, Server) of + case anonymous_user_exist(User, Server) or login(User, Server) of %% We return the default value if the user is anonymous true -> DefaultValue; diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl index bcdce272a..d9a32dd20 100644 --- a/src/ejabberd_auth_external.erl +++ b/src/ejabberd_auth_external.erl @@ -68,14 +68,14 @@ plain_password_required() -> check_password(User, Server, Password) -> extauth:check_password(User, Server, Password) andalso Password /= "". -%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% @spec (User, Server, Password, Digest, DigestGen) -> bool() %% User = string() %% Server = string() %% Password = string() -%% StreamID = string() %% Digest = string() +%% DigestGen = function() -check_password(User, Server, Password, _StreamID, _Digest) -> +check_password(User, Server, Password, _Digest, _DigestGen) -> check_password(User, Server, Password). %% @spec (User, Server, Password) -> ok | {error, unknown_problem} diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index 003b24edf..74aa82c7c 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -84,14 +84,14 @@ check_password(User, Server, Password) -> false end. -%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% @spec (User, Server, Password, Digest, DigestGen) -> bool() %% User = string() %% Server = string() %% Password = string() -%% StreamID = string() %% Digest = string() +%% DigestGen = function() -check_password(User, Server, Password, StreamID, Digest) -> +check_password(User, Server, Password, Digest, DigestGen) -> LUser = exmpp_stringprep:nodeprep(User), LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, @@ -99,7 +99,7 @@ check_password(User, Server, Password, StreamID, Digest) -> [#passwd{password = Passwd}] -> DigRes = if Digest /= "" -> - Digest == sha:sha(StreamID ++ Passwd); + Digest == DigestGen(Passwd); true -> false end, diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl index c083cc141..7a31d6bae 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -169,14 +169,14 @@ check_password(User, Server, Password) -> end end. -%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% @spec (User, Server, Password, Digest, DigestGen) -> bool() %% User = string() %% Server = string() %% Password = string() -%% StreamID = string() %% Digest = string() +%% DigestGen = function() -check_password(User, Server, Password, _StreamID, _Digest) -> +check_password(User, Server, Password, _Digest, _DigestGen) -> check_password(User, Server, Password). %% @spec (User, Server, Password) -> {error, not_allowed} diff --git a/src/ejabberd_auth_odbc.erl b/src/ejabberd_auth_odbc.erl index 4b390eb06..0943488f4 100644 --- a/src/ejabberd_auth_odbc.erl +++ b/src/ejabberd_auth_odbc.erl @@ -91,14 +91,14 @@ check_password(User, Server, Password) -> false end. -%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% @spec (User, Server, Password, Digest, DigestGen) -> bool() %% User = string() %% Server = string() %% Password = string() -%% StreamID = string() %% Digest = string() +%% DigestGen = function() -check_password(User, Server, Password, StreamID, Digest) -> +check_password(User, Server, Password, Digest, DigestGen) -> try LUser = exmpp_stringprep:nodeprep(User), Username = ejabberd_odbc:escape(LUser), @@ -108,7 +108,7 @@ check_password(User, Server, Password, StreamID, Digest) -> {selected, ["password"], [{Passwd}]} -> DigRes = if Digest /= "" -> - Digest == sha:sha(StreamID ++ Passwd); + Digest == DigestGen(Passwd); true -> false end, diff --git a/src/ejabberd_auth_pam.erl b/src/ejabberd_auth_pam.erl index e147e1cc0..a5ff59c47 100644 --- a/src/ejabberd_auth_pam.erl +++ b/src/ejabberd_auth_pam.erl @@ -64,12 +64,12 @@ start(_Host) -> set_password(_User, _Server, _Password) -> {error, not_allowed}. -%% @spec (User, Server, Password, StreamID, Digest) -> bool() +%% @spec (User, Server, Password, Digest, DigestGen) -> bool() %% User = string() %% Server = string() %% Password = string() -%% StreamID = string() %% Digest = string() +%% DigestGen = function() check_password(User, Server, Password, _StreamID, _Digest) -> check_password(User, Server, Password). diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 762961a95..b15ebdc1b 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -257,6 +257,10 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> fun(U, P) -> ejabberd_auth:check_password_with_authmodule( U, Server, P) + end, + fun(U, P, D, DG) -> + ejabberd_auth:check_password_with_authmodule( + U, Server, P, D, DG) end), SASL_Mechs = [exmpp_server_sasl:feature( cyrsasl:listmech(Server))], @@ -402,9 +406,11 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> case acl:match_rule(ServerString, StateData#state.access, JID) of allow -> + DGen = fun(PW) -> + sha:sha(StateData#state.streamid ++ PW) end, case ejabberd_auth:check_password_with_authmodule( U, ServerString, P, - StateData#state.streamid, D) of + D, DGen) of {true, AuthModule} -> ?INFO_MSG( "(~w) Accepted legacy authentication for ~s by ~s", From 92b1e9d9acad0b8eeb05ce334cf6d19ef2f08220 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 22 Apr 2009 12:05:10 +0000 Subject: [PATCH 284/582] * src/mod_muc/mod_muc.erl: Limit number of characters in Room ID, Name and Description (EJAB-899) * src/mod_muc/mod_muc_room.erl: Likewise * doc/guide.tex: Likewise * doc/guide.html: Likewise SVN Revision: 2034 --- ChangeLog | 6 +++++ doc/guide.html | 21 +++++++++++++-- doc/guide.tex | 21 +++++++++++++-- src/mod_muc/mod_muc.erl | 21 ++++++++++----- src/mod_muc/mod_muc_room.erl | 52 ++++++++++++++++++++++++++++-------- 5 files changed, 100 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index fbe370c96..f80f522fd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2009-04-22 Badlop + * src/mod_muc/mod_muc.erl: Limit number of characters in Room ID, + Name and Description (EJAB-899) + * src/mod_muc/mod_muc_room.erl: Likewise + * doc/guide.tex: Likewise + * doc/guide.html: Likewise + * src/cyrsasl.erl: Change API of check_password: pass a function to generate the digest (thanks to Graham Whitted)(EJAB-863) * src/cyrsasl_anonymous.erl: Likewise diff --git a/doc/guide.html b/doc/guide.html index 9b5d2596d..39740f51e 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -2098,6 +2098,18 @@ number of rooms that any given user can join. The default value is 10. This option is used to prevent possible abuses. Note that this is a soft limit: some users can sometimes join more conferences in cluster configurations. +

    max_room_id
    +This option defines the maximum number of characters that Room ID +can have when creating a new room. +The default value is to not limit: infinite. +
    max_room_name
    +This option defines the maximum number of characters that Room Name +can have when configuring the room. +The default value is to not limit: infinite. +
    max_room_desc
    +This option defines the maximum number of characters that Room Description +can have when configuring the room. +The default value is to not limit: infinite.
    min_message_interval
    This option defines the minimum interval between two messages send by an occupant in seconds. This option is global and valid for all @@ -2209,12 +2221,17 @@ and the default value of 20 history messages will be send to the users. ]}.
  • In the following example, MUC anti abuse options are used. An occupant cannot send more than one message every 0.4 seconds and cannot -change its presence more than once every 4 seconds. No ACLs are +change its presence more than once every 4 seconds. +The length of Room IDs and Room Names are limited to 20 characters, +and Room Description to 300 characters. No ACLs are defined, but some user restriction could be added as well:
    {modules,
      [
       ...
       {mod_muc, [{min_message_interval, 0.4},
    -             {min_presence_interval, 4}]},
    +             {min_presence_interval, 4},
    +             {max_room_id, 20},
    +             {max_room_name, 20},
    +             {max_room_desc, 300}]},
       ...
      ]}.
     
  • This example shows how to use default_room_options to make sure diff --git a/doc/guide.tex b/doc/guide.tex index 0f691af9a..1c81860c1 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -2763,6 +2763,18 @@ Module options: is 10. This option is used to prevent possible abuses. Note that this is a soft limit: some users can sometimes join more conferences in cluster configurations. +\titem{max\_room\_id} \ind{options!max\_room\_id} + This option defines the maximum number of characters that Room ID + can have when creating a new room. + The default value is to not limit: infinite. +\titem{max\_room\_name} \ind{options!max\_room\_name} + This option defines the maximum number of characters that Room Name + can have when configuring the room. + The default value is to not limit: infinite. +\titem{max\_room\_desc} \ind{options!max\_room\_desc} + This option defines the maximum number of characters that Room Description + can have when configuring the room. + The default value is to not limit: infinite. \titem{min\_message\_interval} \ind{options!min\_message\_interval} This option defines the minimum interval between two messages send by an occupant in seconds. This option is global and valid for all @@ -2881,7 +2893,9 @@ Examples: \item In the following example, MUC anti abuse options are used. An occupant cannot send more than one message every 0.4 seconds and cannot -change its presence more than once every 4 seconds. No ACLs are +change its presence more than once every 4 seconds. +The length of Room IDs and Room Names are limited to 20 characters, +and Room Description to 300 characters. No ACLs are defined, but some user restriction could be added as well: \begin{verbatim} @@ -2889,7 +2903,10 @@ defined, but some user restriction could be added as well: [ ... {mod_muc, [{min_message_interval, 0.4}, - {min_presence_interval, 4}]}, + {min_presence_interval, 4}, + {max_room_id, 20}, + {max_room_name, 20}, + {max_room_desc, 300}]}, ... ]}. \end{verbatim} diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index bd87b7e7a..69d6fce1a 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -447,8 +447,10 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, Type = exmpp_stanza:get_type(Packet), case {Name, Type} of {'presence', 'undefined'} -> - case acl:match_rule(ServerHost, AccessCreate, From) of - allow -> + case check_user_can_create_room(ServerHost, + AccessCreate, From, + Room) of + true -> ?DEBUG("MUC: open new room '~s'~n", [Room]), {ok, Pid} = mod_muc_room:start( Host, ServerHost, Access, @@ -458,10 +460,10 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, register_room(Host, Room, Pid), mod_muc_room:route(Pid, From, Nick, Packet), ok; - _ -> - Lang = exmpp_stanza:get_lang(Packet), + false -> + Lang = exmpp_stanza:get_lang(Packet), ErrText = "Room creation is denied by service policy", - Err = exmpp_stanza:reply_with_error(Packet,exmpp_stanza:error(Packet#xmlel.ns, + Err = exmpp_stanza:reply_with_error(Packet,exmpp_stanza:error(Packet#xmlel.ns, 'forbidden', {Lang,ErrText})), ejabberd_router:route(To, From, Err) @@ -483,7 +485,14 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, end end. - +check_user_can_create_room(ServerHost, AccessCreate, From, RoomID) -> + case acl:match_rule(ServerHost, AccessCreate, From) of + allow -> + (size(RoomID) =< gen_mod:get_module_opt(ServerHost, mod_muc, + max_room_id, infinite)); + _ -> + false + end. load_permanent_rooms(Host, ServerHost, Access, HistorySize, RoomShaper) -> diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 3d0608a95..199597d8f 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -2612,11 +2612,16 @@ process_iq_owner(From, set, Lang, SubEl, StateData) -> {?NS_DATA_FORMS, <<"cancel">>} -> {result, [], StateData}; {?NS_DATA_FORMS, <<"submit">>} -> - case {check_allowed_log_change(XEl, StateData, From), - check_allowed_persistent_change(XEl, StateData, From)} of - {allow, allow} -> set_config(XEl, StateData); - _ -> {error, 'bad-request'} - end; + case is_allowed_log_change(XEl, StateData, From) + andalso + is_allowed_persistent_change(XEl, StateData, + From) + andalso + is_allowed_room_name_desc_limits(XEl, + StateData) of + true -> set_config(XEl, StateData); + false -> {error, 'bad-request'} + end; _ -> {error, 'bad-request'} end; @@ -2667,26 +2672,51 @@ process_iq_owner(From, get, Lang, SubEl, StateData) -> {error, ?ERR(SubEl, 'forbidden', Lang, ErrText)} end. -check_allowed_log_change(XEl, StateData, From) -> +is_allowed_log_change(XEl, StateData, From) -> case lists:keymember("muc#roomconfig_enablelogging", 1, jlib:parse_xdata_submit(XEl)) of false -> - allow; + true; true -> - mod_muc_log:check_access_log( - StateData#state.server_host, From) + (allow == mod_muc_log:check_access_log( + StateData#state.server_host, From)) end. -check_allowed_persistent_change(XEl, StateData, From) -> +is_allowed_persistent_change(XEl, StateData, From) -> case lists:keymember("muc#roomconfig_persistentroom", 1, jlib:parse_xdata_submit(XEl)) of false -> - allow; + true; true -> {_AccessRoute, _AccessCreate, _AccessAdmin, AccessPersistent} = StateData#state.access, acl:match_rule(StateData#state.server_host, AccessPersistent, From) end. +%% Check if the Room Name and Room Description defined in the Data Form +%% are conformant to the configured limits +is_allowed_room_name_desc_limits(XEl, StateData) -> + IsNameAccepted = + case lists:keysearch("muc#roomconfig_roomname", 1, + jlib:parse_xdata_submit(XEl)) of + {value, {_, [N]}} -> + length(N) =< gen_mod:get_module_opt(StateData#state.server_host, + mod_muc, max_room_name, + infinite); + _ -> + true + end, + IsDescAccepted = + case lists:keysearch("muc#roomconfig_roomdesc", 1, + jlib:parse_xdata_submit(XEl)) of + {value, {_, [D]}} -> + length(D) =< gen_mod:get_module_opt(StateData#state.server_host, + mod_muc, max_room_desc, + infinite); + _ -> + true + end, + IsNameAccepted and IsDescAccepted. + -define(XFIELD(Type, Label, Var, Val), #xmlel{name = 'field', attrs = [?XMLATTR('type', Type), From 0141779b9c6c9750bb45ec38bd10c2cac88439ad Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 22 Apr 2009 13:45:57 +0000 Subject: [PATCH 285/582] * src/ejabberd.cfg.example: Fix English typos. Fix line length: max 80 characters per line. Remove trailing blankspaces. Added markers for Vim fold, you may want to add to $HOME/.vimrc this line: set modeline * src/ejabberdctl.cfg.example: Likewise SVN Revision: 2035 --- ChangeLog | 6 +++ src/ejabberd.cfg.example | 89 ++++++++++++++++++++----------------- src/ejabberdctl.cfg.example | 37 +++++++++------ 3 files changed, 76 insertions(+), 56 deletions(-) diff --git a/ChangeLog b/ChangeLog index f80f522fd..2c8bfa982 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2009-04-22 Badlop + * src/ejabberd.cfg.example: Fix English typos. Fix line length: + max 80 characters per line. Remove trailing blankspaces. Added + markers for Vim fold, you may want to add to $HOME/.vimrc this + line: set modeline + * src/ejabberdctl.cfg.example: Likewise + * src/mod_muc/mod_muc.erl: Limit number of characters in Room ID, Name and Description (EJAB-899) * src/mod_muc/mod_muc_room.erl: Likewise diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index 046db942b..9f8c34b24 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -1,10 +1,11 @@ %%% %%% ejabberd configuration file %%% +%%%' %%% The parameters used in this configuration file are explained in more detail %%% in the ejabberd Installation and Operation Guide. -%%% Please consult the Guide in case of doubts, it is included in +%%% Please consult the Guide in case of doubts, it is included in %%% your copy of ejabberd, and is also available online at %%% http://www.process-one.net/en/ejabberd/docs/ @@ -16,26 +17,26 @@ %%% - Each term ends in a dot, for example: %%% override_global. %%% -%%% - A tuple has a fixed definition, its elements are +%%% - A tuple has a fixed definition, its elements are %%% enclosed in {}, and separated with commas: %%% {loglevel, 4}. %%% -%%% - A list can have as many elements as you want, +%%% - A list can have as many elements as you want, %%% and is enclosed in [], for example: %%% [http_poll, web_admin, tls] %%% -%%% - A keyword of ejabberd is a word in lowercase. +%%% - A keyword of ejabberd is a word in lowercase. %%% The strings are enclosed in "" and can have spaces, dots... %%% {language, "en"}. -%%% {ldap_rootdn, "dc=example,dc=com"}. +%%% {ldap_rootdn, "dc=example,dc=com"}. %%% %%% - This term includes a tuple, a keyword, a list and two strings: %%% {hosts, ["jabber.example.net", "im.example.com"]}. %%% -%%% ======================= -%%% OVERRIDE STORED OPTIONS +%%%. ======================= +%%%' OVERRIDE STORED OPTIONS %% %% Override the old values stored in the database. @@ -57,8 +58,8 @@ %%override_acls. -%%% ========= -%%% DEBUGGING +%%%. ========= +%%%' DEBUGGING %% %% loglevel: Verbosity of log files generated by ejabberd. @@ -79,8 +80,8 @@ %%{watchdog_admins, ["bob@example.com"]}. -%%% ================ -%%% SERVED HOSTNAMES +%%%. ================ +%%%' SERVED HOSTNAMES %% %% hosts: Domains served by ejabberd. @@ -97,8 +98,8 @@ %%{route_subdomains, s2s}. -%%% =============== -%%% LISTENING PORTS +%%%. =============== +%%%' LISTENING PORTS %% %% listen: Which ports will ejabberd listen, which service handles it @@ -111,7 +112,7 @@ %% %% If TLS is compiled and you installed a SSL - %% certificate, put the correct path to the + %% certificate, put the correct path to the %% file and uncomment this line: %% %%{certfile, "/path/to/ssl.pem"}, starttls, @@ -140,7 +141,7 @@ %% ejabberd_service: Interact with external components (transports...) %% %%{8888, ejabberd_service, [ - %% {access, all}, + %% {access, all}, %% {shaper_rule, fast}, %% {ip, {127, 0, 0, 1}}, %% {hosts, ["icq.example.org", "sms.example.org"], @@ -149,7 +150,7 @@ %% ]}, {5280, ejabberd_http, [ - http_poll, + http_poll, web_admin ]} @@ -194,13 +195,14 @@ %% %%{outgoing_s2s_options, [ipv4, ipv6], 10000}. -%%% ============== -%%% AUTHENTICATION + +%%%. ============== +%%%' AUTHENTICATION %% %% auth_method: Method used to authenticate the users. %% The default method is the internal. -%% If you want to use a different method, +%% If you want to use a different method, %% comment this line and enable the correct ones. %% {auth_method, internal}. @@ -230,19 +232,19 @@ %%{auth_method, ldap}. %% %% List of LDAP servers: -%%{ldap_servers, ["localhost"]}. +%%{ldap_servers, ["localhost"]}. %% %% LDAP attribute that holds user ID: -%%{ldap_uids, [{"mail", "%u@mail.example.org"}]}. +%%{ldap_uids, [{"mail", "%u@mail.example.org"}]}. %% %% Search base of LDAP directory: -%%{ldap_base, "dc=example,dc=com"}. +%%{ldap_base, "dc=example,dc=com"}. %% %% LDAP manager: -%%{ldap_rootdn, "dc=example,dc=com"}. +%%{ldap_rootdn, "dc=example,dc=com"}. %% %% Password to LDAP manager: -%%{ldap_password, "******"}. +%%{ldap_password, "******"}. %% %% Anonymous login support: @@ -259,8 +261,8 @@ %%{host_config, "public.example.org", [{auth_method, [internal, anonymous]}]}. -%%% ============== -%%% DATABASE SETUP +%%%. ============== +%%%' DATABASE SETUP %% ejabberd uses by default the internal Mnesia database, %% so you can avoid this section. @@ -306,8 +308,8 @@ %%{odbc_keepalive_interval, undefined}. -%%% =============== -%%% TRAFFIC SHAPERS +%%%. =============== +%%%' TRAFFIC SHAPERS %% %% The "normal" shaper limits traffic speed to 1.000 B/s @@ -320,8 +322,8 @@ {shaper, fast, {maxrate, 50000}}. -%%% ==================== -%%% ACCESS CONTROL LISTS +%%%. ==================== +%%%' ACCESS CONTROL LISTS %% %% The 'admin' ACL grants administrative privileges to Jabber accounts. @@ -359,8 +361,8 @@ %%}. -%%% ============ -%%% ACCESS RULES +%%%. ============ +%%%' ACCESS RULES %% Maximum number of simultaneous sessions allowed for a single user: {access, max_user_sessions, [{10, all}]}. @@ -398,7 +400,7 @@ %% To disable in-band registration, replace 'allow' with 'deny'. {access, register, [{allow, all}]}. -%% By default frequency of account registrations from a the same IP +%% By default frequency of account registrations from the same IP %% is limited to 1 account every 10 minutes. To disable put: infinity %%{registration_timeout, 600}. @@ -413,8 +415,8 @@ %%}. -%%% ================ -%%% DEFAULT LANGUAGE +%%%. ================ +%%%' DEFAULT LANGUAGE %% %% language: Default language used for server messages. @@ -429,8 +431,8 @@ %%}. -%%% ======= -%%% MODULES +%%%. ======= +%%%' MODULES %% %% Modules enabled in all ejabberd virtual hosts. @@ -439,7 +441,7 @@ [ {mod_adhoc, []}, {mod_announce, [{access, announce}]}, % recommends mod_adhoc - {mod_caps, []}, + {mod_caps, []}, {mod_configure,[]}, % requires mod_adhoc {mod_disco, []}, %%{mod_echo, [{host, "echo.localhost"}]}, @@ -463,14 +465,14 @@ ]}, {mod_register, [ %% - %% After successful registration, the user receives + %% After successful registration, the user receives %% a message with this subject and body. %% - {welcome_message, {"Welcome!", + {welcome_message, {"Welcome!", "Hi.\nWelcome to this Jabber server."}}, %% - %% When a user registers, send a notification to + %% When a user registers, send a notification to %% these Jabber accounts. %% %%{registration_watchers, ["admin1@example.org"]}, @@ -498,9 +500,12 @@ %% ]}. +%%%. +%%%' + %%% $Id$ %%% Local Variables: %%% mode: erlang %%% End: -%%% vim: set filetype=erlang tabstop=8: +%%% vim: set filetype=erlang tabstop=8 foldmarker=%%%',%%%. foldmethod=marker: diff --git a/src/ejabberdctl.cfg.example b/src/ejabberdctl.cfg.example index 661d8ce77..d6bb80e16 100644 --- a/src/ejabberdctl.cfg.example +++ b/src/ejabberdctl.cfg.example @@ -1,21 +1,22 @@ # -# In this file you can configure options that are passed by ejabberdctl +# In this file you can configure options that are passed by ejabberdctl # to the erlang runtime system when starting ejabberd # -# POLL: Kernel polling ([true|false]) +#' POLL: Kernel polling ([true|false]) # # The kernel polling option requires support in the kernel. -# Additionaly, you need to enable this feature while compiling Erlang. +# Additionally, you need to enable this feature while compiling Erlang. # # Default: true # #POLL=true -# SMP: SMP support ([enable|auto|disable]) +#. +#' SMP: SMP support ([enable|auto|disable]) # # Explanation in Erlang/OTP documentation: -# enable: starts the Erlang runtime system with SMP support enabled. +# enable: starts the Erlang runtime system with SMP support enabled. # This may fail if no runtime system with SMP support is available. # auto: starts the Erlang runtime system with SMP support enabled if it # is available and more than one logical processor are detected. @@ -25,9 +26,10 @@ # #SMP=auto -# ERL_MAX_PORTS: Maximum number of simultaneously open Erlang ports +#. +#' ERL_MAX_PORTS: Maximum number of simultaneously open Erlang ports # -# ejabberd consumes two or three ports for every connection, either +# ejabberd consumes two or three ports for every connection, either # from a client or from another Jabber server. So take this into # account when setting this limit. # @@ -36,21 +38,23 @@ # #ERL_MAX_PORTS=32000 -# FIREWALL_WINDOW: Range of allowed ports to pass through a firewall +#. +#' FIREWALL_WINDOW: Range of allowed ports to pass through a firewall # # If Ejabberd is configured to run in cluster, and a firewall is blocking ports, -# it's possible to make Erlang use a defined range of port (instead of dynamic ports) -# for node communication. +# it's possible to make Erlang use a defined range of port (instead of dynamic +# ports) for node communication. # # Default: not defined # Example: 4200-4210 # #FIREWALL_WINDOW= -# PROCESSES: Maximum number of Erlang processes +#. +#' PROCESSES: Maximum number of Erlang processes # # Erlang consumes a lot of lightweight processes. If there is a lot of activity -# on ejabberd so that the maximum number of proccesses is reached, people will +# on ejabberd so that the maximum number of processes is reached, people will # experiment greater latency times. As these processes are implemented in # Erlang, and therefore not related to the operating system processes, you do # not have to worry about allowing a huge number of them. @@ -60,7 +64,8 @@ # #PROCESSES=250000 -# ERL_MAX_ETS_TABLES: Maximum number of ETS and Mnesia tables +#. +#' ERL_MAX_ETS_TABLES: Maximum number of ETS and Mnesia tables # # The number of concurrent ETS and Mnesia tables is limited. When the limit is # reached, errors will appear in the logs: @@ -72,6 +77,8 @@ # #ERL_MAX_ETS_TABLES=1400 +#. +#' ERLANG_NODE # The next variable allows to explicitly specify erlang node for ejabberd # It can be given in different formats: # ERLANG_NODE=ejabberd @@ -80,9 +87,11 @@ # Erlang uses node name as is (so make sure that hostname is a real # machine hostname or you'll not be able to control ejabberd) # ERLANG_NODE=ejabberd@hostname.domainname -# The same as previous, but erlang will use long hostname +# The same as previous, but erlang will use long hostname # (see erl (1) manual for details) # # Default: ejabberd # #ERLANG_NODE=ejabberd + +# vim: foldmarker=#',#. foldmethod=marker: From 1d44abfc8ae7afac1d1ad1ed93410858480fe5ca Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Wed, 22 Apr 2009 23:01:51 +0000 Subject: [PATCH 286/582] improve send last published items spawning SVN Revision: 2037 --- ChangeLog | 7 ++ src/mod_pubsub/mod_pubsub.erl | 199 ++++++++++++++++++++++------------ 2 files changed, 137 insertions(+), 69 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2c8bfa982..86ff1f1be 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ + +2009-04-23 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: improve send last published items + (not spawned as much) and allow to send last PEP items of our offline + contacts if configured for (fix discussion issue on standars ML) + 2009-04-22 Badlop * src/ejabberd.cfg.example: Fix English typos. Fix line length: diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 56ff84714..acaa3f90f 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -109,6 +109,10 @@ code_change/3 ]). +%% calls for parallel sending of last items +-export([send_loop/1 + ]). + -define(PROCNAME, ejabberd_mod_pubsub). -define(PLUGIN_PREFIX, "node_"). -define(TREE_PREFIX, "nodetree_"). @@ -117,8 +121,10 @@ host, access, pep_mapping = [], + pep_sendlast_offline, nodetree = ?STDTREE, - plugins = [?STDNODE]}). + plugins = [?STDNODE], + send_loop}). %%==================================================================== %% API @@ -158,6 +164,7 @@ init([ServerHost, Opts]) -> ?DEBUG("pubsub init ~p ~p",[ServerHost,Opts]), Host = gen_mod:get_opt_host(ServerHost, Opts, "pubsub.@HOST@"), Access = gen_mod:get_opt(access_createnode, Opts, all), + PepOffline = gen_mod:get_opt(pep_sendlast_offline, Opts, false), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), ServerHostB = list_to_binary(ServerHost), mod_disco:register_feature(ServerHost, ?NS_PUBSUB_s), @@ -190,12 +197,15 @@ init([ServerHost, Opts]) -> ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {plugins, Plugins}), ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {pep_mapping, PepMapping}), init_nodes(Host, ServerHost), - {ok, #state{host = Host, + State = #state{host = Host, server_host = ServerHost, access = Access, pep_mapping = PepMapping, + pep_sendlast_offline = PepOffline, nodetree = NodeTree, - plugins = Plugins}}. + plugins = Plugins}, + SendLoop = spawn(?MODULE, send_loop, [State]), %% TODO supervise that process + {ok, State#state{send_loop = SendLoop}}. %% @spec (Host, ServerHost, Opts) -> Plugins %% Host = mod_pubsub:host() Opts = [{Key,Value}] @@ -310,6 +320,113 @@ update_database(Host) -> ok end. +send_loop(State) -> + receive + {presence, JID, Pid} -> + Host = State#state.host, + ServerHost = State#state.server_host, + LJID = jlib:short_prepd_jid(JID), + BJID = jlib:short_prepd_bare_jid(JID), + %% for each node From is subscribed to + %% and if the node is so configured, send the last published item to From + lists:foreach(fun(Type) -> + {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, JID]), + lists:foreach( + fun({Node, subscribed, SubJID}) -> + if (SubJID == LJID) or (SubJID == BJID) -> + case tree_action(Host, get_node, [Host, Node, JID]) of + #pubsub_node{options = Options} -> + case get_option(Options, send_last_published_item) of + on_sub_and_presence -> + send_items(Host, Node, SubJID, last); + _ -> + ok + end; + _ -> + ok + end; + true -> + % resource not concerned about that subscription + ok + end; + (_) -> + ok + end, Subscriptions) + end, State#state.plugins), + %% and force send the last PEP events published by its offline and local contacts + %% only if pubsub is explicitely configured for that. + %% this is a hack in a sense that PEP should only be based on presence + %% and is not able to "store" events of remote users (via s2s) + %% this makes that hack only work for local domain by now + if State#state.pep_sendlast_offline -> + case catch ejabberd_c2s:get_subscribed(Pid) of + Contacts when is_list(Contacts) -> + {User, Server, Resource} = LJID, + lists:foreach( + fun({U, S, R}) -> %% local contacts + case ejabberd_sm:get_user_resources(U, S) of + [] -> %% offline + case S of + ServerHost -> %% local contact, so we may have pep items + PeerJID = exmpp_jlib:make_jid(U, S, R), + handle_cast({presence, User, Server, [Resource], PeerJID}, State); + _ -> %% remote contact, no items available + ok + end; + _ -> %% online + % this is already handled by presence probe + ok + end; + (_) -> %% remote contacts + % we can not do anything in any cases + ok + end, Contacts); + _ -> + ok + end; + true -> + ok + end, + send_loop(State); + {presence, User, Server, Resources, JID} -> + Owner = jlib:short_prepd_bare_jid(JID), + Host = State#state.host, + ServerHost = State#state.server_host, + lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) -> + case get_option(Options, send_last_published_item) of + on_sub_and_presence -> + lists:foreach(fun(Resource) -> + LJID = {User, Server, Resource}, + case is_caps_notify(ServerHost, Node, LJID) of + true -> + Subscribed = case get_option(Options, access_model) of + open -> true; + presence -> true; + whitelist -> false; % subscribers are added manually + authorize -> false; % likewise + roster -> + Grps = get_option(Options, roster_groups_allowed, []), + {OU, OS, _} = Owner, + element(2, get_roster_info(OU, OS, LJID, Grps)) + end, + if Subscribed -> + send_items(Owner, Node, LJID, last); + true -> + ok + end; + false -> + ok + end + end, Resources); + _ -> + ok + end + end, tree_action(Host, get_nodes, [Owner, JID])), + send_loop(State); + stop -> + ok + end. + %% ------- %% disco hooks handling functions %% @@ -416,11 +533,11 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) -> %% presence hooks handling functions %% -presence_probe(JID, JID, _Pid) -> +presence_probe(JID, JID, Pid) -> {U, S, R} = jlib:short_prepd_jid(JID), Host = S, % exmpp_jid:ldomain_as_list(JID), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), - gen_server:cast(Proc, {presence, JID}), + gen_server:cast(Proc, {presence, JID, Pid}), gen_server:cast(Proc, {presence, U, S, [R], JID}); presence_probe(Peer, JID, _Pid) -> {U, S, R} = jlib:short_prepd_jid(Peer), @@ -483,72 +600,14 @@ handle_call(stop, _From, State) -> %% Description: Handling cast messages %%-------------------------------------------------------------------- %% @private -handle_cast({presence, JID}, State) -> +handle_cast({presence, JID, Pid}, State) -> %% A new resource is available. send last published items - Host = State#state.host, - LJID = jlib:short_prepd_jid(JID), - %% for each node From is subscribed to - %% and if the node is so configured, send the last published item to From - spawn(fun() -> - lists:foreach(fun(Type) -> - {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, JID]), - lists:foreach( - fun({Node, subscribed, _SubJID}) -> - case tree_action(Host, get_node, [Host, Node, JID]) of - #pubsub_node{options = Options} -> - case get_option(Options, send_last_published_item) of - on_sub_and_presence -> - send_items(Host, Node, LJID, last); - _ -> - ok - end; - _ -> - ok - end; - (_) -> - ok - end, Subscriptions) - end, State#state.plugins) - end), + State#state.send_loop ! {presence, JID, Pid}, {noreply, State}; handle_cast({presence, User, Server, Resources, JID}, State) -> %% A new resource is available. send last published PEP items - Owner = jlib:short_prepd_bare_jid(JID), - Host = State#state.host, - ServerHost = State#state.server_host, - spawn(fun() -> - lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) -> - case get_option(Options, send_last_published_item) of - on_sub_and_presence -> - lists:foreach(fun(Resource) -> - LJID = {User, Server, Resource}, - case is_caps_notify(ServerHost, Node, LJID) of - true -> - Subscribed = case get_option(Options, access_model) of - open -> true; - presence -> true; - whitelist -> false; % subscribers are added manually - authorize -> false; % likewise - roster -> - Grps = get_option(Options, roster_groups_allowed, []), - {OU, OS, _} = Owner, - element(2, get_roster_info(OU, OS, LJID, Grps)) - end, - if Subscribed -> - send_items(Owner, Node, LJID, last); - true -> - ok - end; - false -> - ok - end - end, Resources); - _ -> - ok - end - end, tree_action(ServerHost, get_nodes, [Owner, JID])) - end), + State#state.send_loop ! {presence, User, Server, Resources, JID}, {noreply, State}; handle_cast({remove_user, LUser, LServer}, State) -> @@ -605,7 +664,8 @@ handle_info(_Info, State) -> terminate(_Reason, #state{host = Host, server_host = ServerHost, nodetree = TreePlugin, - plugins = Plugins}) -> + plugins = Plugins, + send_loop = SendLoop}) -> terminate_plugins(Host, ServerHost, Plugins, TreePlugin), ejabberd_router:unregister_route(Host), ServerHostB = list_to_binary(ServerHost), @@ -631,6 +691,7 @@ terminate(_Reason, #state{host = Host, gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB), gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB_OWNER), mod_disco:unregister_feature(ServerHost, ?NS_PUBSUB_s), + SendLoop ! stop, ok. %%-------------------------------------------------------------------- @@ -829,7 +890,7 @@ iq_disco_items(Host, Item, From) -> %% Note: Multiple Node Discovery not supported (mask on pubsub#type) %% TODO this code is also back-compatible with pubsub v1.8 (for client issue) %% TODO make it pubsub v1.12 compliant (breaks client compatibility ?) - %% TODO That is, remove name attribute + %% TODO That is, remove name attribute (or node?, please check) Action = fun(#pubsub_node{type = Type}) -> NodeItems = case node_call(Type, get_items, [Host, Node, From]) of @@ -1570,7 +1631,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> end end, ejabberd_hooks:run(pubsub_publish_item, ServerHost, [ServerHost, Node, Publisher, service_jid(Host), ItemId, Payload]), - Reply = [], + Reply = [], %% TODO EJAB-909 case transaction(Host, Node, Action, sync_dirty) of {error, 'item-not-found'} -> %% handles auto-create feature From 6710d66a58050ee194295688733cc099c7f2e9ee Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 24 Apr 2009 10:32:41 +0000 Subject: [PATCH 287/582] fix minor pubsub init glitch, and allow ejabberd_odbc to execute bloc of queries without transaction SVN Revision: 2039 --- ChangeLog | 7 +++++++ src/mod_pubsub/mod_pubsub.erl | 18 +++++++++--------- src/odbc/ejabberd_odbc.erl | 28 ++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 86ff1f1be..af8bd71e3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-04-24 Christophe Romain + + * src/odbc/ejabberd_odbc.erl: allow to run query bloc as erlang + function without transaction + + * src/mod_pubsub/mod_pubsub.erl: do not register handlers and hooks + while plugins and ets tables are not initialized. 2009-04-23 Christophe Romain diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index acaa3f90f..cf2881c7a 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -39,7 +39,7 @@ -module(mod_pubsub). -author('christophe.romain@process-one.net'). --version('1.12-03'). +-version('1.12-04'). -behaviour(gen_server). -behaviour(gen_mod). @@ -168,6 +168,14 @@ init([ServerHost, Opts]) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), ServerHostB = list_to_binary(ServerHost), mod_disco:register_feature(ServerHost, ?NS_PUBSUB_s), + {Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts), + ets:new(gen_mod:get_module_proc(Host, pubsub_state), [set, named_table]), + ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {nodetree, NodeTree}), + ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {plugins, Plugins}), + ets:new(gen_mod:get_module_proc(ServerHost, pubsub_state), [set, named_table]), + ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {nodetree, NodeTree}), + ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {plugins, Plugins}), + ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {pep_mapping, PepMapping}), ejabberd_hooks:add(disco_sm_identity, ServerHostB, ?MODULE, disco_sm_identity, 75), ejabberd_hooks:add(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), ejabberd_hooks:add(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75), @@ -177,7 +185,6 @@ init([ServerHost, Opts]) -> gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB, ?MODULE, iq_sm, IQDisc), gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB_OWNER, ?MODULE, iq_sm, IQDisc), ejabberd_router:register_route(Host), - {Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts), case lists:member(?PEPNODE, Plugins) of true -> ejabberd_hooks:add(disco_local_identity, ServerHostB, ?MODULE, disco_local_identity, 75), @@ -189,13 +196,6 @@ init([ServerHost, Opts]) -> ok end, update_database(Host), - ets:new(gen_mod:get_module_proc(Host, pubsub_state), [set, named_table]), - ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {nodetree, NodeTree}), - ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {plugins, Plugins}), - ets:new(gen_mod:get_module_proc(ServerHost, pubsub_state), [set, named_table]), - ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {nodetree, NodeTree}), - ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {plugins, Plugins}), - ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {pep_mapping, PepMapping}), init_nodes(Host, ServerHost), State = #state{host = Host, server_host = ServerHost, diff --git a/src/odbc/ejabberd_odbc.erl b/src/odbc/ejabberd_odbc.erl index aac4b2178..be1c315a8 100644 --- a/src/odbc/ejabberd_odbc.erl +++ b/src/odbc/ejabberd_odbc.erl @@ -34,6 +34,7 @@ sql_query/2, sql_query_t/1, sql_transaction/2, + sql_bloc/2, escape/1, escape_like/1, keep_alive/1]). @@ -87,6 +88,11 @@ sql_transaction(Host, F) -> gen_server:call(ejabberd_odbc_sup:get_random_pid(Host), {sql_transaction, F}, ?TRANSACTION_TIMEOUT). +%% SQL bloc, based on a erlang anonymous function (F = fun) +sql_bloc(Host, F) -> + gen_server:call(ejabberd_odbc_sup:get_random_pid(Host), + {sql_bloc, F}, ?TRANSACTION_TIMEOUT). + %% This function is intended to be used from inside an sql_transaction: sql_query_t(Query) -> State = get(?STATE_KEY), @@ -192,6 +198,17 @@ handle_call({sql_transaction, F}, _From, State) -> Reply -> {reply, Reply, State} end; +handle_call({sql_bloc, F}, _From, State) -> + case execute_bloc(State, F) of + % error returned by MySQL driver + {error, "query timed out"} -> + {stop, timeout, State}; + % error returned by MySQL driver + {error, "Failed sending data on socket"++_} = Reply -> + {stop, closed, Reply, State}; + Reply -> + {reply, Reply, State} + end; handle_call(_Request, _From, State) -> Reply = ok, {reply, Reply, State}. @@ -276,6 +293,17 @@ execute_transaction(State, F, NRestarts, _Reason) -> {atomic, Res} end. +execute_bloc(State, F) -> + put(?STATE_KEY, State), + case catch F() of + {aborted, Reason} -> + {aborted, Reason}; + {'EXIT', Reason} -> + {aborted, Reason}; + Res -> + {atomic, Res} + end. + %% == pure ODBC code %% part of init/1 From fd5e312ed933dba092b37eb777755083aa2eecfe Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 24 Apr 2009 21:34:59 +0000 Subject: [PATCH 288/582] minor cosmetic fix SVN Revision: 2040 --- src/mod_pubsub/mod_pubsub.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index cf2881c7a..21042fcfe 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -369,7 +369,7 @@ send_loop(State) -> case S of ServerHost -> %% local contact, so we may have pep items PeerJID = exmpp_jlib:make_jid(U, S, R), - handle_cast({presence, User, Server, [Resource], PeerJID}, State); + self() ! {presence, User, Server, [Resource], PeerJID}; _ -> %% remote contact, no items available ok end; From 028509c3a9058a12c211ea6dda1a7ca7277817f2 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 27 Apr 2009 19:17:17 +0000 Subject: [PATCH 289/582] * src/jlib.erl: Fix recursive call to speedup base64 decoding (thanks to Jeffrey Rogiers)(EJAB-333) SVN Revision: 2041 --- ChangeLog | 5 +++++ src/jlib.erl | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index af8bd71e3..60c50a037 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-04-27 Badlop + + * src/jlib.erl: Fix recursive call to speedup base64 + decoding (thanks to Jeffrey Rogiers)(EJAB-333) + 2009-04-24 Christophe Romain * src/odbc/ejabberd_odbc.erl: allow to run query bloc as erlang diff --git a/src/jlib.erl b/src/jlib.erl index f19dd052e..898e20a8b 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -297,7 +297,7 @@ decode1_base64([Sextet1,Sextet2,$=,$=|Rest]) -> (d(Sextet1) bsl 18) bor (d(Sextet2) bsl 12), Octet1=Bits2x6 bsr 16, - [Octet1|decode_base64(Rest)]; + [Octet1|decode1_base64(Rest)]; decode1_base64([Sextet1,Sextet2,Sextet3,$=|Rest]) -> Bits3x6= (d(Sextet1) bsl 18) bor @@ -305,7 +305,7 @@ decode1_base64([Sextet1,Sextet2,Sextet3,$=|Rest]) -> (d(Sextet3) bsl 6), Octet1=Bits3x6 bsr 16, Octet2=(Bits3x6 bsr 8) band 16#ff, - [Octet1,Octet2|decode_base64(Rest)]; + [Octet1,Octet2|decode1_base64(Rest)]; decode1_base64([Sextet1,Sextet2,Sextet3,Sextet4|Rest]) -> Bits4x6= (d(Sextet1) bsl 18) bor @@ -315,7 +315,7 @@ decode1_base64([Sextet1,Sextet2,Sextet3,Sextet4|Rest]) -> Octet1=Bits4x6 bsr 16, Octet2=(Bits4x6 bsr 8) band 16#ff, Octet3=Bits4x6 band 16#ff, - [Octet1,Octet2,Octet3|decode_base64(Rest)]; + [Octet1,Octet2,Octet3|decode1_base64(Rest)]; decode1_base64(_CatchAll) -> "". From ec779c001cbad42fe13fb5b661f6418ffeb72b2d Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 27 Apr 2009 20:24:21 +0000 Subject: [PATCH 290/582] * src/cyrsasl_digest.erl: Fix auth verification (EJAB-863) SVN Revision: 2042 --- ChangeLog | 2 ++ src/cyrsasl_digest.erl | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 60c50a037..a13d0265a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2009-04-27 Badlop + * src/cyrsasl_digest.erl: Fix auth verification (EJAB-863) + * src/jlib.erl: Fix recursive call to speedup base64 decoding (thanks to Jeffrey Rogiers)(EJAB-333) diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl index 4c2a2a103..0eb8f8df1 100644 --- a/src/cyrsasl_digest.erl +++ b/src/cyrsasl_digest.erl @@ -92,7 +92,7 @@ mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) -> {false, _} -> {error, 'not-authorized', UserName}; {Passwd, AuthModule} -> - case (State#state.check_password)(UserName, Passwd, + case (State#state.check_password)(UserName, "", proplists:get_value("response", KeyVals, ""), fun(PW) -> response(KeyVals, UserName, PW, Nonce, AuthzId, "AUTHENTICATE") end) of @@ -106,6 +106,8 @@ mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) -> auth_module = AuthModule, username = UserName, authzid = AuthzId}}; + false -> + {error, 'not-authorized', UserName}; {false, _} -> {error, 'not-authorized', UserName} end From d7829a76ce10ff6c5520f15d7ab23d5fe0623a25 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 27 Apr 2009 20:36:19 +0000 Subject: [PATCH 291/582] * src/win32_dns.erl: Fix problem parsing some win32 dns (EJAB-927) SVN Revision: 2043 --- ChangeLog | 2 ++ src/win32_dns.erl | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index a13d0265a..f5c8adc2e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2009-04-27 Badlop + * src/win32_dns.erl: Fix problem parsing some win32 dns (EJAB-927) + * src/cyrsasl_digest.erl: Fix auth verification (EJAB-863) * src/jlib.erl: Fix recursive call to speedup base64 diff --git a/src/win32_dns.erl b/src/win32_dns.erl index 79725cbab..6d1bbca00 100644 --- a/src/win32_dns.erl +++ b/src/win32_dns.erl @@ -27,6 +27,8 @@ -module(win32_dns). -export([get_nameservers/0]). +-include("ejabberd.hrl"). + -define(IF_KEY, "\\hklm\\system\\CurrentControlSet\\Services\\TcpIp\\Parameters\\Interfaces"). -define(TOP_KEY, "\\hklm\\system\\CurrentControlSet\\Services\\TcpIp\\Parameters"). @@ -54,14 +56,27 @@ config_keys(R, Key) -> ok = win32reg:change_key(R, Key), [ {K, case win32reg:value(R, K) of - {ok, V} -> translate(K, V); + {ok, V} -> try_translate(K, V); _ -> undefined end } || K <- ["Domain", "DhcpDomain", "NameServer", "DhcpNameServer", "SearchList"]]. +try_translate(K, V) -> + try translate(K, V) of + Res -> + Res + catch + A:B -> + ?ERROR_MSG("Error '~p' translating Win32 registry~n" + "K: ~p~nV: ~p~nError: ~p", [A, K, V, B]), + undefined + end. + translate(NS, V) when NS =:= "NameServer"; NS =:= "DhcpNameServer" -> - IPsStrings = [string:tokens(IP, ".") || IP <- string:tokens(V, ",")], + %% The IPs may be separated by commas ',' or by spaces " " + %% The parts of an IP are separated by dots '.' + IPsStrings = [string:tokens(IP, ".") || IP <- string:tokens(V, " ,")], [ list_to_tuple([list_to_integer(String) || String <- IpStrings]) || IpStrings <- IPsStrings]; translate(_, V) -> V. From 5afe7cfafb8f13e8569600bc3644972a2ea73fe8 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 27 Apr 2009 20:55:35 +0000 Subject: [PATCH 292/582] * src/translate.erl: Support additional files (EJAB-925) * contrib/extract_translations/extract_translations.erl: Likewise * contrib/extract_translations/prepare-translation.sh: Likewise SVN Revision: 2044 --- ChangeLog | 4 + .../extract_translations.erl | 4 +- .../prepare-translation.sh | 92 ++++++++++++++----- src/translate.erl | 11 ++- 4 files changed, 81 insertions(+), 30 deletions(-) diff --git a/ChangeLog b/ChangeLog index f5c8adc2e..1d39dc7eb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2009-04-27 Badlop + * src/translate.erl: Support additional files (EJAB-925) + * contrib/extract_translations/extract_translations.erl: Likewise + * contrib/extract_translations/prepare-translation.sh: Likewise + * src/win32_dns.erl: Fix problem parsing some win32 dns (EJAB-927) * src/cyrsasl_digest.erl: Fix auth verification (EJAB-863) diff --git a/contrib/extract_translations/extract_translations.erl b/contrib/extract_translations/extract_translations.erl index 1f38cd08e..488357ba6 100644 --- a/contrib/extract_translations/extract_translations.erl +++ b/contrib/extract_translations/extract_translations.erl @@ -68,7 +68,7 @@ process(Dir, File, Used) -> parse_file(Dir, File, Used) -> ets:delete_all_objects(vars), - case epp:parse_file(File, [Dir, filename:dirname(File)], []) of + case epp:parse_file(File, [Dir, filename:dirname(File) | code:get_path()], []) of {ok, Forms} -> lists:foreach( fun(F) -> @@ -80,6 +80,8 @@ parse_file(Dir, File, Used) -> parse_form(Dir, File, Form, Used) -> case Form of + %%{undefined, Something} -> + %% io:format("Undefined: ~p~n", [Something]); {call, _, {remote, _, {atom, _, translate}, {atom, _, translate}}, diff --git a/contrib/extract_translations/prepare-translation.sh b/contrib/extract_translations/prepare-translation.sh index d1c435fbe..0ecb61139 100755 --- a/contrib/extract_translations/prepare-translation.sh +++ b/contrib/extract_translations/prepare-translation.sh @@ -3,16 +3,24 @@ # Frontend for ejabberd's extract_translations.erl # by Badlop +# How to create template files for a new language: +# NEWLANG=zh +# cp msgs/ejabberd.pot msgs/$NEWLANG.po +# echo \{\"\",\"\"\}. > msgs/$NEWLANG.msg +# ../../extract_translations/prepare-translation.sh -updateall + prepare_dirs () { # Where is Erlang binary ERL=`which erl` - EJA_DIR=`pwd`/.. + EJA_SRC_DIR=$EJA_DIR/src/ + EJA_MSGS_DIR=$EJA_SRC_DIR/msgs/ EXTRACT_DIR=$EJA_DIR/contrib/extract_translations/ EXTRACT_ERL=$EXTRACT_DIR/extract_translations.erl EXTRACT_BEAM=$EXTRACT_DIR/extract_translations.beam - SRC_DIR=$EJA_DIR/src + + SRC_DIR=$RUN_DIR/src MSGS_DIR=$SRC_DIR/msgs if !([[ -n $EJA_DIR ]]) @@ -74,14 +82,14 @@ extract_lang () extract_lang_all () { cd $MSGS_DIR - for i in *.msg; do + for i in $( ls *.msg ) ; do extract_lang $i; done echo -e "File\tMissing\tLanguage\t\tLast translator" echo -e "----\t-------\t--------\t\t---------------" cd $MSGS_DIR - for i in *.msg; do + for i in $( ls *.msg ) ; do MISSING=`cat $i.translate | grep "\", \"\"}." | wc -l` LANGUAGE=`grep "Language:" $i.translate | sed 's/% Language: //g'` LASTAUTH=`grep "Author:" $i.translate | head -n 1 | sed 's/% Author: //g'` @@ -140,11 +148,14 @@ find_unused_full () extract_lang_srcmsg2po () { - LANG_CODE=$1 + LANG=$1 + LANG_CODE=$LANG.$PROJECT MSGS_PATH=$MSGS_DIR/$LANG_CODE.msg PO_PATH=$MSGS_DIR/$LANG_CODE.po - $ERL -pa $EXTRACT_DIR -pa $SRC_DIR -noinput -noshell -s extract_translations -s init stop -extra -srcmsg2po . $MSGS_PATH >$PO_PATH.1 + echo $MSGS_PATH + + $ERL -pa $EXTRACT_DIR -pa $SRC_DIR -pa $EJA_SRC_DIR -pa /lib/ejabberd/include -noinput -noshell -s extract_translations -s init stop -extra -srcmsg2po . $MSGS_PATH >$PO_PATH.1 sed -e 's/ \[\]$/ \"\"/g;' $PO_PATH.1 > $PO_PATH.2 msguniq --sort-by-file $PO_PATH.2 --output-file=$PO_PATH @@ -153,7 +164,7 @@ extract_lang_srcmsg2po () extract_lang_src2pot () { - LANG_CODE=ejabberd + LANG_CODE=$PROJECT MSGS_PATH=$MSGS_DIR/$LANG_CODE.msg POT_PATH=$MSGS_DIR/$LANG_CODE.pot @@ -163,19 +174,30 @@ extract_lang_src2pot () echo "" >>$MSGS_PATH cd $SRC_DIR - $ERL -pa $EXTRACT_DIR -pa $SRC_DIR -noinput -noshell -s extract_translations -s init stop -extra -srcmsg2po . $MSGS_PATH >$POT_PATH.1 + $ERL -pa $EXTRACT_DIR -pa $SRC_DIR -pa $EJA_SRC_DIR -pa /lib/ejabberd/include -noinput -noshell -s extract_translations -s init stop -extra -srcmsg2po . $MSGS_PATH >$POT_PATH.1 sed -e 's/ \[\]$/ \"\"/g;' $POT_PATH.1 > $POT_PATH.2 + + #msguniq --sort-by-file $POT_PATH.2 $EJA_MSGS_DIR --output-file=$POT_PATH msguniq --sort-by-file $POT_PATH.2 --output-file=$POT_PATH rm $POT_PATH.* rm $MSGS_PATH + + # If the project is a specific module, not the main ejabberd + if [[ $PROJECT != ejabberd ]] ; then + # Remove from project.pot the strings that are already present in the general ejabberd + EJABBERD_MSG_FILE=$EJA_MSGS_DIR/es.po # This is just some file with translated strings + POT_PATH_TEMP=$POT_PATH.temp + msgattrib --set-obsolete --only-file=$EJABBERD_MSG_FILE -o $POT_PATH_TEMP $POT_PATH + mv $POT_PATH_TEMP $POT_PATH + fi } extract_lang_popot2po () { LANG_CODE=$1 PO_PATH=$MSGS_DIR/$LANG_CODE.po - POT_PATH=$MSGS_DIR/ejabberd.pot + POT_PATH=$MSGS_DIR/$PROJECT.pot msgmerge $PO_PATH $POT_PATH >$PO_PATH.translate 2>/dev/null mv $PO_PATH.translate $PO_PATH @@ -222,7 +244,7 @@ extract_lang_updateall () echo "" echo -e "File Missing Language Last translator" echo -e "---- ------- -------- ---------------" - for i in *.msg; do + for i in $( ls *.msg ) ; do LANG_CODE=${i%.msg} echo -n $LANG_CODE | awk '{printf "%-6s", $1 }' @@ -266,43 +288,62 @@ translation_instructions () echo " $MSGS_PATH" } -prepare_dirs -case "$1" in - -lang) - LANGU=$2 - extract_lang $LANGU +EJA_DIR=`pwd`/.. +RUN_DIR=`pwd`/.. +PROJECT=ejabberd + +while [ $# -ne 0 ] ; do + PARAM=$1 + shift + case $PARAM in + --) break ;; + -project) + PROJECT=$1 shift + ;; + -ejadir) + EJA_DIR=$1 + shift + ;; + -rundir) + RUN_DIR=$1 + shift + ;; + -lang) + LANGU=$1 + prepare_dirs + extract_lang $LANGU shift ;; -langall) + prepare_dirs extract_lang_all - shift ;; -srcmsg2po) - LANG_CODE=$2 + LANG_CODE=$1 + prepare_dirs extract_lang_srcmsg2po $LANG_CODE shift - shift ;; -popot2po) - LANG_CODE=$2 + LANG_CODE=$1 + prepare_dirs extract_lang_popot2po $LANG_CODE shift - shift ;; -src2pot) + prepare_dirs extract_lang_src2pot - shift ;; -po2msg) - LANG_CODE=$2 + LANG_CODE=$1 + prepare_dirs extract_lang_po2msg $LANG_CODE shift - shift ;; -updateall) + prepare_dirs extract_lang_updateall - shift ;; *) echo "Options:" @@ -318,4 +359,5 @@ case "$1" in echo " ./prepare-translation.sh -lang es.msg" exit 0 ;; -esac + esac +done diff --git a/src/translate.erl b/src/translate.erl index 9a823c5cd..391d22574 100644 --- a/src/translate.erl +++ b/src/translate.erl @@ -69,10 +69,13 @@ load_dir(Dir) -> end, Files), lists:foreach( fun(FN) -> - L = ascii_tolower( - list_to_binary( - string:substr(FN, 1, string:len(FN) - 4))), - load_file(L, Dir ++ "/" ++ FN) + LP = string:substr(FN, 1, string:len(FN) - 4), + L1 = case string:tokens(LP, ".") of + [Language] -> Language; + [Language, _Project] -> Language + end, + L2 = ascii_tolower(list_to_binary(L1)), + load_file(L2, Dir ++ "/" ++ FN) end, MsgFiles), ok; {error, Reason} -> From 2908e5da194d8afd4d465b670d047e11ebd4da50 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 28 Apr 2009 14:46:12 +0000 Subject: [PATCH 293/582] Merge 1969 and 1970 from trunk. * src/ejabberd_hooks.erl: anonymous functions support. SVN Revision: 2046 --- ChangeLog | 4 ++++ src/ejabberd_hooks.erl | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1d39dc7eb..4e6bb6c03 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-04-28 Badlop + + * src/ejabberd_hooks.erl: anonymous functions support. + 2009-04-27 Badlop * src/translate.erl: Support additional files (EJAB-925) diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl index 22dc49eba..fcdfde389 100644 --- a/src/ejabberd_hooks.erl +++ b/src/ejabberd_hooks.erl @@ -31,7 +31,9 @@ %% External exports -export([start_link/0, + add/3, add/4, + delete/3, delete/4, run/2, run_fold/3, @@ -58,6 +60,14 @@ start_link() -> gen_server:start_link({local, ejabberd_hooks}, ejabberd_hooks, [], []). +%% @spec (Hook::atom(), Function::function(), Seq::integer()) -> ok +%% @doc See add/4. +add(Hook, Function, Seq) when is_function(Function) -> + add(Hook, global, undefined, Function, Seq). + +add(Hook, Host, Function, Seq) when is_function(Function) -> + add(Hook, Host, undefined, Function, Seq); + %% @spec (Hook::atom(), Module::atom(), Function::atom(), Seq::integer()) -> ok %% @doc Add a module and function to this hook. %% The integer sequence is used to sort the calls: low number is called before high number. @@ -68,6 +78,14 @@ add(Hook, Host, Module, Function, Seq) when is_binary(Host) orelse is_atom(Host) -> gen_server:call(ejabberd_hooks, {add, Hook, Host, Module, Function, Seq}). +%% @spec (Hook::atom(), Function::function(), Seq::integer()) -> ok +%% @doc See del/4. +delete(Hook, Function, Seq) when is_function(Function) -> + delete(Hook, global, undefined, Function, Seq). + +delete(Hook, Host, Function, Seq) when is_function(Function) -> + delete(Hook, Host, undefined, Function, Seq); + %% @spec (Hook::atom(), Module::atom(), Function::atom(), Seq::integer()) -> ok %% @doc Delete a module and function from this hook. %% It is important to indicate exactly the same information than when the call was added. @@ -202,7 +220,12 @@ code_change(_OldVsn, State, _Extra) -> run1([], _Hook, _Args) -> ok; run1([{_Seq, Module, Function} | Ls], Hook, Args) -> - case catch apply(Module, Function, Args) of + Res = if is_function(Function) -> + catch apply(Function, Args); + true -> + catch apply(Module, Function, Args) + end, + case Res of {'EXIT', Reason} -> ?ERROR_MSG("~p~nrunning hook: ~p", [Reason, {Hook, Args}]), @@ -217,7 +240,12 @@ run1([{_Seq, Module, Function} | Ls], Hook, Args) -> run_fold1([], _Hook, Val, _Args) -> Val; run_fold1([{_Seq, Module, Function} | Ls], Hook, Val, Args) -> - case catch apply(Module, Function, [Val | Args]) of + Res = if is_function(Function) -> + catch apply(Function, [Val | Args]); + true -> + catch apply(Module, Function, [Val | Args]) + end, + case Res of {'EXIT', Reason} -> ?ERROR_MSG("~p~nrunning hook: ~p", [Reason, {Hook, Args}]), From 3debaf99d864dd3cba575d57f8ea8c2239f4afa1 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 28 Apr 2009 14:57:16 +0000 Subject: [PATCH 294/582] * src/ejabberd_hooks.erl: Support distributed hooks (EJAB-829) SVN Revision: 2047 --- ChangeLog | 2 + src/ejabberd_hooks.erl | 87 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/ChangeLog b/ChangeLog index 4e6bb6c03..47f9e6eec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2009-04-28 Badlop + * src/ejabberd_hooks.erl: Support distributed hooks (EJAB-829) + * src/ejabberd_hooks.erl: anonymous functions support. 2009-04-27 Badlop diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl index fcdfde389..0f3782f52 100644 --- a/src/ejabberd_hooks.erl +++ b/src/ejabberd_hooks.erl @@ -33,12 +33,16 @@ -export([start_link/0, add/3, add/4, + add_dist/5, delete/3, delete/4, + delete_dist/5, run/2, run_fold/3, add/5, + add_dist/6, delete/5, + delete_dist/6, run/3, run_fold/4]). @@ -52,6 +56,9 @@ -include("ejabberd.hrl"). +%% Timeout of 5 seconds in calls to distributed hooks +-define(TIMEOUT_DISTRIBUTED_HOOK, 5000). + -record(state, {}). %%%---------------------------------------------------------------------- @@ -78,6 +85,12 @@ add(Hook, Host, Module, Function, Seq) when is_binary(Host) orelse is_atom(Host) -> gen_server:call(ejabberd_hooks, {add, Hook, Host, Module, Function, Seq}). +add_dist(Hook, Node, Module, Function, Seq) -> + gen_server:call(ejabberd_hooks, {add, Hook, global, Node, Module, Function, Seq}). + +add_dist(Hook, Host, Node, Module, Function, Seq) -> + gen_server:call(ejabberd_hooks, {add, Hook, Host, Node, Module, Function, Seq}). + %% @spec (Hook::atom(), Function::function(), Seq::integer()) -> ok %% @doc See del/4. delete(Hook, Function, Seq) when is_function(Function) -> @@ -96,6 +109,12 @@ delete(Hook, Host, Module, Function, Seq) when is_binary(Host) orelse is_atom(Host) -> gen_server:call(ejabberd_hooks, {delete, Hook, Host, Module, Function, Seq}). +delete_dist(Hook, Node, Module, Function, Seq) -> + delete_dist(Hook, global, Node, Module, Function, Seq). + +delete_dist(Hook, Host, Node, Module, Function, Seq) -> + gen_server:call(ejabberd_hooks, {delete, Hook, Host, Node, Module, Function, Seq}). + %% @spec (Hook::atom(), Args) -> ok %% @doc Run the calls of this hook in order, don't care about function results. %% If a call returns stop, no more calls are performed. @@ -169,6 +188,24 @@ handle_call({add, Hook, Host, Module, Function, Seq}, _From, State) -> ok end, {reply, Reply, State}; +handle_call({add, Hook, Host, Node, Module, Function, Seq}, _From, State) -> + Reply = case ets:lookup(hooks, {Hook, Host}) of + [{_, Ls}] -> + El = {Seq, Node, Module, Function}, + case lists:member(El, Ls) of + true -> + ok; + false -> + NewLs = lists:merge(Ls, [El]), + ets:insert(hooks, {{Hook, Host}, NewLs}), + ok + end; + [] -> + NewLs = [{Seq, Node, Module, Function}], + ets:insert(hooks, {{Hook, Host}, NewLs}), + ok + end, + {reply, Reply, State}; handle_call({delete, Hook, Host, Module, Function, Seq}, _From, State) -> Reply = case ets:lookup(hooks, {Hook, Host}) of [{_, Ls}] -> @@ -179,6 +216,16 @@ handle_call({delete, Hook, Host, Module, Function, Seq}, _From, State) -> ok end, {reply, Reply, State}; +handle_call({delete, Hook, Host, Node, Module, Function, Seq}, _From, State) -> + Reply = case ets:lookup(hooks, {Hook, Host}) of + [{_, Ls}] -> + NewLs = lists:delete({Seq, Node, Module, Function}, Ls), + ets:insert(hooks, {{Hook, Host}, NewLs}), + ok; + [] -> + ok + end, + {reply, Reply, State}; handle_call(_Request, _From, State) -> Reply = ok, {reply, Reply, State}. @@ -219,6 +266,25 @@ code_change(_OldVsn, State, _Extra) -> run1([], _Hook, _Args) -> ok; +run1([{_Seq, Node, Module, Function} | Ls], Hook, Args) -> + case rpc:call(Node, Module, Function, Args, ?TIMEOUT_DISTRIBUTED_HOOK) of + timeout -> + ?ERROR_MSG("Timeout on RPC to ~p~nrunning hook: ~p", + [Node, {Hook, Args}]), + run1(Ls, Hook, Args); + {badrpc, Reason} -> + ?ERROR_MSG("Bad RPC error to ~p: ~p~nrunning hook: ~p", + [Node, Reason, {Hook, Args}]), + run1(Ls, Hook, Args); + stop -> + ?INFO_MSG("~nThe process ~p in node ~p ran a hook in node ~p.~n" + "Stop.", [self(), node(), Node]), % debug code + ok; + Res -> + ?INFO_MSG("~nThe process ~p in node ~p ran a hook in node ~p.~n" + "The response is:~n~s", [self(), node(), Node, Res]), % debug code + run1(Ls, Hook, Args) + end; run1([{_Seq, Module, Function} | Ls], Hook, Args) -> Res = if is_function(Function) -> catch apply(Function, Args); @@ -239,6 +305,27 @@ run1([{_Seq, Module, Function} | Ls], Hook, Args) -> run_fold1([], _Hook, Val, _Args) -> Val; +run_fold1([{_Seq, Node, Module, Function} | Ls], Hook, Val, Args) -> + case rpc:call(Node, Module, Function, [Val | Args], ?TIMEOUT_DISTRIBUTED_HOOK) of + {badrpc, Reason} -> + ?ERROR_MSG("Bad RPC error to ~p: ~p~nrunning hook: ~p", + [Node, Reason, {Hook, Args}]), + run_fold1(Ls, Hook, Val, Args); + timeout -> + ?ERROR_MSG("Timeout on RPC to ~p~nrunning hook: ~p", + [Node, {Hook, Args}]), + run_fold1(Ls, Hook, Val, Args); + stop -> + stopped; + {stop, NewVal} -> + ?INFO_MSG("~nThe process ~p in node ~p ran a hook in node ~p.~n" + "Stop, and the NewVal is:~n~p", [self(), node(), Node, NewVal]), % debug code + NewVal; + NewVal -> + ?INFO_MSG("~nThe process ~p in node ~p ran a hook in node ~p.~n" + "The NewVal is:~n~p", [self(), node(), Node, NewVal]), % debug code + run_fold1(Ls, Hook, NewVal, Args) + end; run_fold1([{_Seq, Module, Function} | Ls], Hook, Val, Args) -> Res = if is_function(Function) -> catch apply(Function, [Val | Args]); From ced30acb20a36983a45b80f3408857c4ca5a530d Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 30 Apr 2009 23:17:38 +0000 Subject: [PATCH 295/582] backport pubsub/pep/caps optimizations from trunk SVN Revision: 2052 --- ChangeLog | 21 + src/mod_caps.erl | 111 ++-- src/mod_pubsub/gen_pubsub_node.erl | 40 +- src/mod_pubsub/gen_pubsub_nodetree.erl | 2 +- src/mod_pubsub/mod_pubsub.erl | 821 ++++++++++++++----------- src/mod_pubsub/node.template | 122 ++-- src/mod_pubsub/node_buddy.erl | 120 ++-- src/mod_pubsub/node_club.erl | 120 ++-- src/mod_pubsub/node_default.erl | 315 +++++----- src/mod_pubsub/node_dispatch.erl | 110 ++-- src/mod_pubsub/node_flat.erl | 120 ++-- src/mod_pubsub/node_mb.erl | 122 ++-- src/mod_pubsub/node_pep.erl | 126 ++-- src/mod_pubsub/node_private.erl | 120 ++-- src/mod_pubsub/node_public.erl | 120 ++-- src/mod_pubsub/nodetree_default.erl | 78 +-- src/mod_pubsub/nodetree_virtual.erl | 25 +- src/mod_pubsub/pubsub.hrl | 24 +- src/mod_pubsub/pubsub_index.erl | 65 ++ 19 files changed, 1374 insertions(+), 1208 deletions(-) create mode 100644 src/mod_pubsub/pubsub_index.erl diff --git a/ChangeLog b/ChangeLog index 47f9e6eec..964d5a689 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2009-04-30 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: API change for major optimization + * src/mod_pubsub/pubsub.hrl: Likewise + * src/mod_pubsub/nodetree_default.erl: Likewise + * src/mod_pubsub/nodetree_virtual.erl: Likewise + * src/mod_pubsub/node_mb.erl: Likewise + * src/mod_pubsub/node_dispatch.erl: Likewise + * src/mod_pubsub/node_buddy.erl: Likewise + * src/mod_pubsub/node_private.erl: Likewise + * src/mod_pubsub/node_public.erl: Likewise + * src/mod_pubsub/node_default.erl: Likewise + * src/mod_pubsub/node_pep.erl: Likewise + * src/mod_pubsub/node_club.erl: Likewise + * src/mod_pubsub/node_flat.erl: Likewise + * src/mod_pubsub/node.template: Likewise + * src/mod_pubsub/gen_pubsub_node.erl: Likewise + * src/mod_pubsub/gen_pubsub_nodetree.erl: Likewise + + * src/mod_caps.erl: Reduce memory consumption and remove mnesia table + 2009-04-28 Badlop * src/ejabberd_hooks.erl: Support distributed hooks (EJAB-829) diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 536e103a2..3b95cfd22 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -22,6 +22,8 @@ %%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA %%% 02111-1307 USA %%% +%%% 2009, improvements from Process-One to support correct PEP handling +%%% through s2s, use less memory, and speedup global caps handling %%%---------------------------------------------------------------------- -module(mod_caps). @@ -64,7 +66,7 @@ -define(CAPS_QUERY_TIMEOUT, 60000). % 1mn without answer, consider client never answer -record(caps, {node, version, exts}). --record(caps_features, {node_pair, features}). +-record(caps_features, {node_pair, features = []}). -record(user_caps, {jid, caps}). -record(user_caps_resources, {uid, resource}). -record(state, {host, @@ -190,19 +192,32 @@ receive_packet(_, _, _) -> receive_packet(_JID, From, To, Packet) -> receive_packet(From, To, Packet). +jid_to_binary(JID) -> + list_to_binary(jlib:jid_to_string(JID)). + +caps_to_binary(#caps{node = Node, version = Version, exts = Exts}) -> + BExts = [list_to_binary(Ext) || Ext <- Exts], + #caps{node = list_to_binary(Node), version = list_to_binary(Version), exts = BExts}. + +node_to_binary(Node, SubNode) -> + {list_to_binary(Node), list_to_binary(SubNode)}. + +features_to_binary(L) -> [list_to_binary(I) || I <- L]. +binary_to_features(L) -> [binary_to_list(I) || I <- L]. + %%==================================================================== %% gen_server callbacks %%==================================================================== init([Host, _Opts]) -> mnesia:create_table(caps_features, - [{ram_copies, [node()]}, + [{disc_copies, [node()]}, {attributes, record_info(fields, caps_features)}]), mnesia:create_table(user_caps, - [{disc_copies, [node()]}, + [{ram_copies, [node()]}, {attributes, record_info(fields, user_caps)}]), mnesia:create_table(user_caps_resources, - [{disc_copies, [node()]}, + [{ram_copies, [node()]}, {type, bag}, {attributes, record_info(fields, user_caps_resources)}]), mnesia:delete_table(user_caps_default), @@ -214,26 +229,21 @@ init([Host, _Opts]) -> maybe_get_features(#caps{node = Node, version = Version, exts = Exts}) -> SubNodes = [Version | Exts], - F = fun() -> - %% Make sure that we have all nodes we need to know. - %% If a single one is missing, we wait for more disco - %% responses. - lists:foldl(fun(SubNode, Acc) -> - case Acc of - fail -> fail; - _ -> - case mnesia:read({caps_features, {Node, SubNode}}) of - [] -> fail; - [#caps_features{features = Features}] -> Features ++ Acc - end - end - end, [], SubNodes) - end, - case mnesia:transaction(F) of - {atomic, fail} -> - wait; - {atomic, Features} -> - {ok, Features} + %% Make sure that we have all nodes we need to know. + %% If a single one is missing, we wait for more disco + %% responses. + case lists:foldl(fun(SubNode, Acc) -> + case Acc of + fail -> fail; + _ -> + case mnesia:dirty_read({caps_features, {Node, SubNode}}) of + [] -> fail; + [#caps_features{features = Features}] -> Features ++ Acc %% TODO binary + end + end + end, [], SubNodes) of + fail -> wait; + Features -> {ok, Features} end. timestamp() -> @@ -243,7 +253,7 @@ timestamp() -> handle_call({get_features, Caps}, From, State) -> case maybe_get_features(Caps) of {ok, Features} -> - {reply, Features, State}; + {reply, binary_to_features(Features), State}; wait -> gen_server:cast(self(), visit_feature_queries), Timeout = timestamp() + 10, @@ -266,7 +276,7 @@ handle_cast({note_caps, From, S = exmpp_jid:ldomain(From), R = exmpp_jid:resource(From), BJID = exmpp_jid:jid_to_binary(From), - mnesia:dirty_write(#user_caps{jid = BJID, caps = Caps}), + mnesia:dirty_write(#user_caps{jid = BJID, caps = caps_to_binary(Caps)}), case ejabberd_sm:get_user_resources(U, S) of [] -> % only store resource of caps aware external contacts @@ -275,20 +285,19 @@ handle_cast({note_caps, From, _ -> ok end, - SubNodes = [Version | Exts], %% Now, find which of these are not already in the database. - Fun = fun() -> - lists:foldl(fun(SubNode, Acc) -> - case mnesia:read({caps_features, {Node, SubNode}}) of - [] -> - [SubNode | Acc]; - _ -> - Acc - end - end, [], SubNodes) - end, - case mnesia:transaction(Fun) of - {atomic, Missing} -> + SubNodes = [Version | Exts], + case lists:foldl(fun(SubNode, Acc) -> + case mnesia:dirty_read({caps_features, {Node, SubNode}}) of + [] -> + [SubNode | Acc]; + _ -> + Acc + end + end, [], SubNodes) of + [] -> + {noreply, State}; + Missing -> %% For each unknown caps "subnode", we send a disco request. NewRequests = lists:foldl( fun(SubNode, Dict) -> @@ -302,30 +311,23 @@ handle_cast({note_caps, From, ejabberd_router:route(exmpp_jid:make_jid(Host), From, Stanza), timer:send_after(?CAPS_QUERY_TIMEOUT, self(), {disco_timeout, ID}), - ?DICT:store(ID, {Node, SubNode}, Dict) + ?DICT:store(ID, node_to_binary(Node, SubNode), Dict) end, Requests, Missing), - {noreply, State#state{disco_requests = NewRequests}}; - Error -> - ?ERROR_MSG("Transaction failed: ~p", [Error]), - {noreply, State} + {noreply, State#state{disco_requests = NewRequests}} end; handle_cast({disco_response, From, _To, #iq{id = ID, type = Type, payload = Payload}}, #state{disco_requests = Requests} = State) -> case {Type, Payload} of {result, #xmlel{name = 'query', children = Els}} -> case ?DICT:find(ID, Requests) of - {ok, {Node, SubNode}} -> + {ok, BinaryNode} -> Features = lists:flatmap(fun(#xmlel{name = 'feature'} = F) -> [exmpp_xml:get_attribute_as_list(F, 'var', "")]; (_) -> [] end, Els), - mnesia:transaction( - fun() -> - mnesia:write(#caps_features{node_pair = {Node, SubNode}, - features = Features}) - end), + mnesia:dirty_write(#caps_features{node_pair = BinaryNode, features = features_to_binary(Features)}), gen_server:cast(self(), visit_feature_queries); error -> ?ERROR_MSG("ID '~s' matches no query", [ID]) @@ -333,13 +335,8 @@ handle_cast({disco_response, From, _To, #iq{id = ID, type = Type, payload = Payl {error, _} -> %% XXX: if we get error, we cache empty feature not to probe the client continuously case ?DICT:find(ID, Requests) of - {ok, {Node, SubNode}} -> - Features = [], - mnesia:transaction( - fun() -> - mnesia:write(#caps_features{node_pair = {Node, SubNode}, - features = Features}) - end), + {ok, BinaryNode} -> + mnesia:dirty_write(#caps_features{node_pair = BinaryNode}), gen_server:cast(self(), visit_feature_queries); error -> ?ERROR_MSG("ID '~s' matches no query", [ID]) diff --git a/src/mod_pubsub/gen_pubsub_node.erl b/src/mod_pubsub/gen_pubsub_node.erl index 91b8163bc..b4264f809 100644 --- a/src/mod_pubsub/gen_pubsub_node.erl +++ b/src/mod_pubsub/gen_pubsub_node.erl @@ -43,29 +43,29 @@ behaviour_info(callbacks) -> {options, 0}, {features, 0}, {create_node_permission, 6}, - {create_node, 3}, - {delete_node, 2}, - {purge_node, 3}, - {subscribe_node, 8}, - {unsubscribe_node, 5}, - {publish_item, 7}, - {delete_item, 4}, - {remove_extra_items, 4}, - {get_node_affiliations, 2}, + {create_node, 2}, + {delete_node, 1}, + {purge_node, 2}, + {subscribe_node, 7}, + {unsubscribe_node, 4}, + {publish_item, 6}, + {delete_item, 3}, + {remove_extra_items, 3}, + {get_node_affiliations, 1}, {get_entity_affiliations, 2}, - {get_affiliation, 3}, - {set_affiliation, 4}, - {get_node_subscriptions, 2}, + {get_affiliation, 2}, + {set_affiliation, 3}, + {get_node_subscriptions, 1}, {get_entity_subscriptions, 2}, - {get_subscription, 3}, - {set_subscription, 4}, - {get_states, 2}, - {get_state, 3}, + {get_subscription, 2}, + {set_subscription, 3}, + {get_states, 1}, + {get_state, 2}, {set_state, 1}, - {get_items, 7}, - {get_items, 3}, - {get_item, 8}, - {get_item, 3}, + {get_items, 6}, + {get_items, 2}, + {get_item, 7}, + {get_item, 2}, {set_item, 1}, {get_item_name, 3} ]; diff --git a/src/mod_pubsub/gen_pubsub_nodetree.erl b/src/mod_pubsub/gen_pubsub_nodetree.erl index 8bd35f51d..941748e68 100644 --- a/src/mod_pubsub/gen_pubsub_nodetree.erl +++ b/src/mod_pubsub/gen_pubsub_nodetree.erl @@ -47,7 +47,7 @@ behaviour_info(callbacks) -> {get_nodes, 2}, {get_nodes, 1}, {get_subnodes, 3}, - {get_subnodes_tree, 2}, + {get_subnodes_tree, 3}, {create_node, 5}, {delete_node, 2} ]; diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 21042fcfe..45c8212a6 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -39,7 +39,7 @@ -module(mod_pubsub). -author('christophe.romain@process-one.net'). --version('1.12-04'). +-version('1.12-05'). -behaviour(gen_server). -behaviour(gen_mod). @@ -76,13 +76,11 @@ unsubscribe_node/5, publish_item/6, delete_item/4, - send_items/4, - broadcast_stanza/6, + send_items/6, + broadcast_stanza/7, get_configure/5, set_configure/5, - get_items/3, tree_action/3, - node_action/3, node_action/4 ]). @@ -167,8 +165,9 @@ init([ServerHost, Opts]) -> PepOffline = gen_mod:get_opt(pep_sendlast_offline, Opts, false), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), ServerHostB = list_to_binary(ServerHost), - mod_disco:register_feature(ServerHost, ?NS_PUBSUB_s), + pubsub_index:init(Host, ServerHost, Opts), {Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts), + mod_disco:register_feature(ServerHost, ?NS_PUBSUB_s), ets:new(gen_mod:get_module_proc(Host, pubsub_state), [set, named_table]), ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {nodetree, NodeTree}), ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {plugins, Plugins}), @@ -195,7 +194,7 @@ init([ServerHost, Opts]) -> false -> ok end, - update_database(Host), + update_database(Host, ServerHost), init_nodes(Host, ServerHost), State = #state{host = Host, server_host = ServerHost, @@ -204,7 +203,7 @@ init([ServerHost, Opts]) -> pep_sendlast_offline = PepOffline, nodetree = NodeTree, plugins = Plugins}, - SendLoop = spawn(?MODULE, send_loop, [State]), %% TODO supervise that process + SendLoop = spawn(?MODULE, send_loop, [State]), {ok, State#state{send_loop = SendLoop}}. %% @spec (Host, ServerHost, Opts) -> Plugins @@ -249,7 +248,7 @@ init_nodes(Host, ServerHost) -> create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), ?STDNODE), ok. -update_database(Host) -> +update_database(Host, ServerHost) -> mnesia:del_table_index(pubsub_node, type), mnesia:del_table_index(pubsub_node, parentid), case catch mnesia:table_info(pubsub_node, attributes) of @@ -257,14 +256,14 @@ update_database(Host) -> ?INFO_MSG("upgrade pubsub tables",[]), F = fun() -> lists:foldl( - fun({pubsub_node, NodeId, ParentId, {nodeinfo, Items, Options, Entities}}, RecList) -> + fun({pubsub_node, NodeId, ParentId, {nodeinfo, Items, Options, Entities}}, {RecList, NodeIdx}) -> ItemsList = lists:foldl( fun({item, IID, Publisher, Payload}, Acc) -> - C = {Publisher, unknown}, - M = {Publisher, now()}, + C = {unknown, Publisher}, + M = {now(), Publisher}, mnesia:write( - #pubsub_item{itemid = {IID, NodeId}, + #pubsub_item{itemid = {IID, NodeIdx}, creation = C, modification = M, payload = Payload}), @@ -282,7 +281,7 @@ update_database(Host) -> end end, [], ItemsList), mnesia:write( - #pubsub_state{stateid = {JID, NodeId}, + #pubsub_state{stateid = {JID, NodeIdx}, items = UsrItems, affiliation = Aff, subscription = Sub}), @@ -292,12 +291,13 @@ update_database(Host) -> end end, [], Entities), mnesia:delete({pubsub_node, NodeId}), - [#pubsub_node{nodeid = NodeId, - parentid = ParentId, + {[#pubsub_node{nodeid = NodeId, + id = NodeIdx, + parent = element(2, ParentId), owners = Owners, options = Options} | - RecList] - end, [], + RecList], NodeIdx + 1} + end, {[], 1}, mnesia:match_object( {pubsub_node, {Host, '_'}, '_', '_'})) end, @@ -316,10 +316,62 @@ update_database(Host) -> {aborted, Reason} -> ?ERROR_MSG("Problem updating Pubsub tables:~n~p", [Reason]) end; + [nodeid, parentid, type, owners, options] -> + F = fun({pubsub_node, NodeId, {_, Parent}, Type, Owners, Options}) -> + #pubsub_node{ + nodeid = NodeId, + id = 0, + parent = Parent, + type = Type, + owners = Owners, + options = Options} + end, + mnesia:transform_table(pubsub_node, F, [nodeid, id, parent, type, owners, options]), + FNew = fun() -> + lists:foldl(fun(#pubsub_node{nodeid = NodeId} = PubsubNode, NodeIdx) -> + mnesia:write(PubsubNode#pubsub_node{id = NodeIdx}), + lists:foreach(fun(#pubsub_state{stateid = StateId} = State) -> + {JID, _} = StateId, + mnesia:delete({pubsub_state, StateId}), + mnesia:write(State#pubsub_state{stateid = {JID, NodeIdx}}) + end, mnesia:match_object(#pubsub_state{stateid = {'_', NodeId}, _ = '_'})), + lists:foreach(fun(#pubsub_item{itemid = ItemId} = Item) -> + {IID, _} = ItemId, + {M1, M2} = Item#pubsub_item.modification, + {C1, C2} = Item#pubsub_item.creation, + mnesia:delete({pubsub_item, ItemId}), + mnesia:write(Item#pubsub_item{itemid = {IID, NodeIdx}, + modification = {M2, M1}, + creation = {C2, C1}}) + end, mnesia:match_object(#pubsub_item{itemid = {'_', NodeId}, _ = '_'})), + NodeIdx + 1 + end, 1, mnesia:match_object( + {pubsub_node, {Host, '_'}, '_', '_', '_', '_', '_'}) + ++ mnesia:match_object( + {pubsub_node, {{'_', ServerHost, '_'}, '_'}, '_', '_', '_', '_', '_'})) + end, + case mnesia:transaction(FNew) of + {atomic, Result} -> + ?INFO_MSG("Pubsub tables updated correctly: ~p", [Result]); + {aborted, Reason} -> + ?ERROR_MSG("Problem updating Pubsub tables:~n~p", [Reason]) + end; _ -> ok end. +send_queue(State, Msg) -> + Pid = State#state.send_loop, + case is_process_alive(Pid) of + true -> + Pid ! Msg, + State; + false -> + SendLoop = spawn(?MODULE, send_loop, [State]), + SendLoop ! Msg, + State#state{send_loop = SendLoop} + end. + send_loop(State) -> receive {presence, JID, Pid} -> @@ -329,16 +381,16 @@ send_loop(State) -> BJID = jlib:short_prepd_bare_jid(JID), %% for each node From is subscribed to %% and if the node is so configured, send the last published item to From - lists:foreach(fun(Type) -> - {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, JID]), + lists:foreach(fun(PType) -> + {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, JID]), lists:foreach( fun({Node, subscribed, SubJID}) -> if (SubJID == LJID) or (SubJID == BJID) -> case tree_action(Host, get_node, [Host, Node, JID]) of - #pubsub_node{options = Options} -> + #pubsub_node{options = Options, type = Type, id = NodeId} -> case get_option(Options, send_last_published_item) of on_sub_and_presence -> - send_items(Host, Node, SubJID, last); + send_items(Host, Node, NodeId, Type, SubJID, last); _ -> ok end; @@ -392,7 +444,7 @@ send_loop(State) -> Owner = jlib:short_prepd_bare_jid(JID), Host = State#state.host, ServerHost = State#state.server_host, - lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) -> + lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = NodeId, options = Options}) -> case get_option(Options, send_last_published_item) of on_sub_and_presence -> lists:foreach(fun(Resource) -> @@ -410,7 +462,7 @@ send_loop(State) -> element(2, get_roster_info(OU, OS, LJID, Grps)) end, if Subscribed -> - send_items(Owner, Node, LJID, last); + send_items(Owner, Node, NodeId, Type, LJID, last); true -> ok end; @@ -496,7 +548,7 @@ disco_sm_items(Acc, From, To, <<>>, _Lang) -> _ -> [] end, NodeItems = lists:map( - fun(Node) -> + fun(#pubsub_node{nodeid = {_, Node}}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', exmpp_jid:jid_to_binary(LJID)), ?XMLATTR('node', node_to_string(Node))]} @@ -509,24 +561,32 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) -> %% TODO, use iq_disco_items(Host, Node, From) Host = exmpp_jid:ldomain_as_list(To), LJID = jlib:short_prepd_bare_jid(To), - case get_items(Host, Node, From) of - [] -> - Acc; - AllItems -> - Items = case Acc of + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + case node_call(Type, get_items, [NodeId, From]) of + {result, []} -> + none; + {result, AllItems} -> + Items = case Acc of {result, I} -> I; _ -> [] end, - NodeItems = lists:map( - fun(#pubsub_item{itemid = Id}) -> + NodeItems = lists:map( + fun(#pubsub_item{itemid = {Id, _}}) -> %% "jid" is required by XEP-0030, and %% "node" is forbidden by XEP-0060. - {result, Name} = node_action(Host, Node, get_item_name, [Host, Node, Id]), + {result, Name} = node_action(Host, Node, get_item_name, [NodeId, Id]), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', exmpp_jid:jid_to_binary(LJID)), ?XMLATTR('name', Name)]} end, AllItems), - {result, NodeItems ++ Items} + {result, NodeItems ++ Items}; + _ -> + none + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Items}} -> {result, Items}; + _ -> Acc end. %% ------- @@ -602,20 +662,18 @@ handle_call(stop, _From, State) -> %% @private handle_cast({presence, JID, Pid}, State) -> %% A new resource is available. send last published items - State#state.send_loop ! {presence, JID, Pid}, - {noreply, State}; + {noreply, send_queue(State, {presence, JID, Pid})}; handle_cast({presence, User, Server, Resources, JID}, State) -> %% A new resource is available. send last published PEP items - State#state.send_loop ! {presence, User, Server, Resources, JID}, - {noreply, State}; + {noreply, send_queue(State, {presence, User, Server, Resources, JID})}; handle_cast({remove_user, LUser, LServer}, State) -> Host = State#state.host, Owner = exmpp_jid:make_jid(LUser, LServer), %% remove user's subscriptions - lists:foreach(fun(Type) -> - {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, Owner]), + lists:foreach(fun(PType) -> + {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Owner]), lists:foreach(fun ({Node, subscribed, JID}) -> unsubscribe_node(Host, Node, Owner, JID, all); @@ -816,17 +874,17 @@ node_disco_features(Host, Node, From) -> node_disco_info(Host, Node, From, false, true). node_disco_info(Host, Node, From, Identity, Features) -> Action = - fun(#pubsub_node{type = Type}) -> + fun(#pubsub_node{type = Type, id = NodeId}) -> I = case Identity of false -> []; true -> Types = - case tree_call(Host, get_subnodes, [Host, Node, From]) of + case tree_call(Host, get_subnodes, [NodeId, From]) of [] -> ["leaf"]; %% No sub-nodes: it's a leaf node _ -> - case node_call(Type, get_items, [Host, Node, From]) of + case node_call(Type, get_items, [NodeId, From]) of {result, []} -> ["collection"]; {result, _} -> ["leaf", "collection"]; _ -> [] @@ -849,10 +907,17 @@ node_disco_info(Host, Node, From, Identity, Features) -> %% TODO: add meta-data info (spec section 5.4) {result, I ++ F} end, - transaction(Host, Node, Action, sync_dirty). + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Result}} -> {result, Result}; + Other -> Other + end. iq_disco_info(Host, SNode, From, Lang) -> - Node = string_to_node(SNode), + [RealSNode|_] = case SNode of + [] -> [[]]; + _ -> string:tokens(SNode, "!") + end, + Node = string_to_node(RealSNode), case Node of [] -> {result, @@ -866,7 +931,7 @@ iq_disco_info(Host, SNode, From, Lang) -> #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_VCARD_s)]}] ++ lists:map(fun(Feature) -> #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s++"#"++Feature)]} - end, features(Host, SNode))}; + end, features(Host, Node))}; _ -> node_disco_info(Host, Node, From) end. @@ -890,10 +955,10 @@ iq_disco_items(Host, Item, From) -> %% Note: Multiple Node Discovery not supported (mask on pubsub#type) %% TODO this code is also back-compatible with pubsub v1.8 (for client issue) %% TODO make it pubsub v1.12 compliant (breaks client compatibility ?) - %% TODO That is, remove name attribute (or node?, please check) + %% TODO That is, remove name attribute (or node?, please check for 2.1) Action = - fun(#pubsub_node{type = Type}) -> - NodeItems = case node_call(Type, get_items, [Host, Node, From]) of + fun(#pubsub_node{type = Type, id = NodeId}) -> + NodeItems = case node_call(Type, get_items, [NodeId, From]) of {result, I} -> I; _ -> [] end, @@ -903,17 +968,20 @@ iq_disco_items(Host, Item, From) -> RN = lists:last(SubNode), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), ?XMLATTR('name', RN)]} - end, tree_call(Host, get_subnodes, [Host, Node, From])), + end, tree_call(Host, get_subnodes, [NodeId, From])), Items = lists:map( fun(#pubsub_item{itemid = {RN, _}}) -> SN = node_to_string(Node) ++ "!" ++ RN, - {result, Name} = node_call(Type, get_item_name, [Host, Node, RN]), + {result, Name} = node_call(Type, get_item_name, [NodeId, RN]), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), ?XMLATTR('name', Name)]} end, NodeItems), {result, Nodes ++ Items} end, - transaction(Host, Node, Action, sync_dirty) + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Result}} -> {result, Result}; + Other -> Other + end end. iq_local(From, To, #iq{type = Type, payload = SubEl, ns = XMLNS, lang = Lang} = IQ_Rec) -> @@ -1098,7 +1166,7 @@ iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> %%% authorization handling -send_authorization_request(Host, Node, Subscriber) -> +send_authorization_request(#pubsub_node{owners = Owners, nodeid = {Host, Node}}, Subscriber) -> Lang = "en", %% TODO fix {U, S, R} = Subscriber, Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = @@ -1125,16 +1193,9 @@ send_authorization_request(Host, Node, Subscriber) -> ?XMLATTR('type', <<"boolean">>), ?XMLATTR('label', translate:translate(Lang, "Allow this Jabber ID to subscribe to this pubsub node?"))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"false">>}]}]}]}]}, - case tree_action(Host, get_node, [Host, Node, Subscriber]) of - #pubsub_node{owners = Owners} -> - lists:foreach( - fun({U1, S1, R1}) -> - ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(U1, S1, R1), Stanza} - end, Owners), - ok; - _ -> - ok - end. + lists:foreach(fun(Owner) -> + ejabberd_router ! {route, service_jid(Host), jlib:make_jid(Owner), Stanza} + end, Owners). find_authorization_response(Packet) -> Els = Packet#xmlel.children, @@ -1192,11 +1253,9 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> "true" -> true; _ -> false end, - Action = fun(#pubsub_node{type = Type, - %%options = Options, - owners = Owners}) -> + Action = fun(#pubsub_node{type = Type, id = NodeId, owners = Owners}) -> IsApprover = lists:member(jlib:short_prepd_bare_jid(From), Owners), - {result, Subscription} = node_call(Type, get_subscription, [Host, Node, Subscriber]), + {result, Subscription} = node_call(Type, get_subscription, [NodeId, Subscriber]), if not IsApprover -> {error, 'forbidden'}; @@ -1208,7 +1267,7 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> false -> none end, send_authorization_approval(Host, Subscriber, SNode, NewSubscription), - node_call(Type, set_subscription, [Host, Node, Subscriber, NewSubscription]) + node_call(Type, set_subscription, [NodeId, Subscriber, NewSubscription]) end end, case transaction(Host, Node, Action, sync_dirty) of @@ -1216,7 +1275,7 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> ejabberd_router:route( To, From, exmpp_stanza:reply_with_error(Packet, Error)); - {result, _NewSubscription} -> + {result, _} -> %% XXX: notify about subscription state change, section 12.11 ok; _ -> @@ -1297,7 +1356,6 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> %% create_node(Host, ServerHost, Node, Owner, Type) -> create_node(Host, ServerHost, Node, Owner, Type, all, []). - create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) -> case lists:member("instant-nodes", features(Type)) of true -> @@ -1348,13 +1406,10 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> case node_call(Type, create_node_permission, [Host, ServerHost, Node, Parent, Owner, Access]) of {result, true} -> case tree_call(Host, create_node, [Host, Node, Type, Owner, NodeOptions]) of - ok -> - node_call(Type, create_node, [Host, Node, Owner]); - {error, 'conflict'} -> - case proplists:get_value(virtual_tree, tree_call(Host, options, [])) of - true -> node_call(Type, create_node, [Host, Node, Owner]); - _ -> {error, 'conflict'} - end; + {ok, NodeId} -> + node_call(Type, create_node, [NodeId, Owner]); + {error, {virtual, NodeId}} -> + node_call(Type, create_node, [NodeId, Owner]); Error -> Error end; @@ -1365,12 +1420,6 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> Reply = [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = [?XMLATTR('node', node_to_string(Node))]}]}], case transaction(CreateNode, transaction) of - {error, Error} -> - %% in case we change transaction to sync_dirty... - %%node_action: - %% node_call(Type, delete_node, [Host, Node]), - %% tree_call(Host, delete_node, [Host, Node]), - {error, Error}; {result, {Result, broadcast}} -> %%Lang = "en", %% TODO: fix %%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), @@ -1385,7 +1434,12 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> {result, default} -> {result, Reply}; {result, Result} -> - {result, Result} + {result, Result}; + Error -> + %% in case we change transaction to sync_dirty... + %% node_call(Type, delete_node, [NodeId]), + %% tree_call(Host, delete_node, [NodeId]), + Error end; Error -> Error @@ -1408,11 +1462,11 @@ delete_node(_Host, [], _Owner) -> %% Node is the root {error, 'not-allowed'}; delete_node(Host, Node, Owner) -> - Action = fun(#pubsub_node{type = Type}) -> - case node_call(Type, get_affiliation, [Host, Node, Owner]) of + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + case node_call(Type, get_affiliation, [NodeId, Owner]) of {result, owner} -> - Removed = tree_call(Host, delete_node, [Host, Node]), - node_call(Type, delete_node, [Host, Removed]); + Removed = tree_call(Host, delete_node, [NodeId]), + node_call(Type, delete_node, [Removed]); _ -> %% Entity is not an owner {error, 'forbidden'} @@ -1420,28 +1474,29 @@ delete_node(Host, Node, Owner) -> end, Reply = [], case transaction(Host, Node, Action, transaction) of - {error, Error} -> - {error, Error}; - {result, {Result, broadcast, Removed}} -> - lists:foreach(fun(RNode) -> - broadcast_removed_node(Host, RNode) + {result, {_, {Result, broadcast, Removed}}} -> + lists:foreach(fun({RNode, RSubscriptions}) -> + {RH, RN} = RNode#pubsub_node.nodeid, + NodeId = RNode#pubsub_node.id, + Type = RNode#pubsub_node.type, + Options = RNode#pubsub_node.options, + broadcast_removed_node(RH, RN, NodeId, Type, Options, RSubscriptions) end, Removed), case Result of default -> {result, Reply}; _ -> {result, Result} end; - {result, {Result, Removed}} -> - lists:foreach(fun(RNode) -> - broadcast_removed_node(Host, RNode) - end, Removed), + {result, {_, {Result, _Removed}}} -> case Result of default -> {result, Reply}; _ -> {result, Result} end; - {result, default} -> + {result, {_, default}} -> {result, Reply}; - {result, Result} -> - {result, Result} + {result, {_, Result}} -> + {result, Result}; + Error -> + Error end. %% @spec (Host, Node, From, JID) -> @@ -1474,7 +1529,7 @@ subscribe_node(Host, Node, From, JID) -> {undefined, undefined, undefined} end, SubId = uniqid(), - Action = fun(#pubsub_node{options = Options, type = Type}) -> + Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> Features = features(Type), SubscribeFeature = lists:member("subscribe", Features), SubscribeConfig = get_option(Options, subscribe), @@ -1502,7 +1557,7 @@ subscribe_node(Host, Node, From, JID) -> {error, extended_error('feature-not-implemented', unsupported, "subscribe")}; true -> node_call(Type, subscribe_node, - [Host, Node, From, Subscriber, + [NodeId, From, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup]) end @@ -1521,26 +1576,28 @@ subscribe_node(Host, Node, From, JID) -> end}]}] end, case transaction(Host, Node, Action, sync_dirty) of - {error, Error} -> - {error, Error}; - {result, {Result, subscribed, send_last}} -> - send_items(Host, Node, Subscriber, last), + {result, {TNode, {Result, subscribed, send_last}}} -> + NodeId = TNode#pubsub_node.id, + Type = TNode#pubsub_node.type, + send_items(Host, Node, NodeId, Type, Subscriber, last), case Result of default -> {result, Reply(subscribed)}; _ -> {result, Result} end; - {result, {Result, Subscription}} -> + {result, {TNode, {Result, Subscription}}} -> case Subscription of - pending -> send_authorization_request(Host, Node, Subscriber); + pending -> send_authorization_request(TNode, Subscriber); _ -> ok end, case Result of default -> {result, Reply(Subscription)}; _ -> {result, Result} end; - {result, Result} -> + {result, {_, Result}} -> %% this case should never occure anyway - {result, Result} + {result, Result}; + Error -> + Error end. %% @spec (Host, Noce, From, JID, SubId) -> {error, Reason} | {result, []} @@ -1567,14 +1624,16 @@ unsubscribe_node(Host, Node, From, JID, SubId) when is_list(JID) -> end, unsubscribe_node(Host, Node, From, Subscriber, SubId); unsubscribe_node(Host, Node, From, Subscriber, SubId) -> - case node_action(Host, Node, unsubscribe_node, - [Host, Node, From, Subscriber, SubId]) of - {error, Error} -> - {error, Error}; - {result, default} -> + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + node_call(Type, unsubscribe_node, [NodeId, From, Subscriber, SubId]) + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, default}} -> {result, []}; - {result, Result} -> - {result, Result} + {result, {_, Result}} -> + {result, Result}; + Error -> + Error end. %% @spec (Host::host(), ServerHost::host(), JID::jid(), Node::pubsubNode(), ItemId::string(), Payload::term()) -> @@ -1595,7 +1654,7 @@ publish_item(Host, ServerHost, Node, Publisher, "", Payload) -> %% if publisher does not specify an ItemId, the service MUST generate the ItemId publish_item(Host, ServerHost, Node, Publisher, uniqid(), Payload); publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> - Action = fun(#pubsub_node{options = Options, type = Type}) -> + Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> Features = features(Type), PublishFeature = lists:member("publish", Features), PublishModel = get_option(Options, publish_model), @@ -1627,12 +1686,37 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> %% Publisher attempts to publish to persistent node with no item {error, extended_error('bad-request', "item-required")}; true -> - node_call(Type, publish_item, [Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload]) + node_call(Type, publish_item, [NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload]) end end, ejabberd_hooks:run(pubsub_publish_item, ServerHost, [ServerHost, Node, Publisher, service_jid(Host), ItemId, Payload]), Reply = [], %% TODO EJAB-909 case transaction(Host, Node, Action, sync_dirty) of + {result, {TNode, {Result, broadcast, Removed}}} -> + NodeId = TNode#pubsub_node.id, + Type = TNode#pubsub_node.type, + Options = TNode#pubsub_node.options, + broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, jlib:short_prepd_jid(Publisher), Payload), + case Result of + default -> {result, Reply}; + _ -> {result, Result} + end; + {result, {TNode, {default, Removed}}} -> + NodeId = TNode#pubsub_node.id, + Type = TNode#pubsub_node.type, + Options = TNode#pubsub_node.options, + broadcast_retract_items(Host, Node, NodeId, Type, Options, Removed), + {result, Reply}; + {result, {TNode, {Result, Removed}}} -> + NodeId = TNode#pubsub_node.id, + Type = TNode#pubsub_node.type, + Options = TNode#pubsub_node.options, + broadcast_retract_items(Host, Node, NodeId, Type, Options, Removed), + {result, Result}; + {result, {_, default}} -> + {result, Reply}; + {result, {_, Result}} -> + {result, Result}; {error, 'item-not-found'} -> %% handles auto-create feature %% for automatic node creation. we'll take the default node type: @@ -1649,25 +1733,8 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> false -> {error, 'item-not-found'} end; - {error, Reason} -> - {error, Reason}; - {result, {Result, broadcast, Removed}} -> - broadcast_retract_items(Host, Node, Removed), - broadcast_publish_item(Host, Node, ItemId, jlib:short_prepd_jid(Publisher), Payload), - case Result of - default -> {result, Reply}; - _ -> {result, Result} - end; - {result, default, Removed} -> - broadcast_retract_items(Host, Node, Removed), - {result, Reply}; - {result, Result, Removed} -> - broadcast_retract_items(Host, Node, Removed), - {result, Result}; - {result, default} -> - {result, Reply}; - {result, Result} -> - {result, Result} + Error -> + Error end. %% @spec (Host::host(), JID::jid(), Node::pubsubNode(), ItemId::string()) -> @@ -1690,7 +1757,7 @@ delete_item(_, "", _, _, _) -> %% Request does not specify a node {error, extended_error('bad-request', "node-required")}; delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> - Action = fun(#pubsub_node{type = Type}) -> + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> Features = features(Type), PersistentFeature = lists:member("persistent-items", Features), DeleteFeature = lists:member("delete-items", Features), @@ -1705,23 +1772,26 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> %% Service does not support item deletion {error, extended_error('feature-not-implemented', unsupported, "delete-items")}; true -> - node_call(Type, delete_item, [Host, Node, Publisher, ItemId]) + node_call(Type, delete_item, [NodeId, Publisher, ItemId]) end end, Reply = [], case transaction(Host, Node, Action, sync_dirty) of - {error, Reason} -> - {error, Reason}; - {result, {Result, broadcast}} -> - broadcast_retract_items(Host, Node, [ItemId], ForceNotify), + {result, {TNode, {Result, broadcast}}} -> + NodeId = TNode#pubsub_node.id, + Type = TNode#pubsub_node.type, + Options = TNode#pubsub_node.options, + broadcast_retract_items(Host, Node, NodeId, Type, Options, [ItemId], ForceNotify), case Result of default -> {result, Reply}; _ -> {result, Result} end; - {result, default} -> + {result, {_, default}} -> {result, Reply}; - {result, Result} -> - {result, Result} + {result, {_, Result}} -> + {result, Result}; + Error -> + Error end. %% @spec (Host, JID, Node) -> @@ -1739,7 +1809,7 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> %%
  • The specified node does not exist.
  • %% purge_node(Host, Node, Owner) -> - Action = fun(#pubsub_node{type = Type, options = Options}) -> + Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> Features = features(Type), PurgeFeature = lists:member("purge-nodes", Features), PersistentFeature = lists:member("persistent-items", Features), @@ -1755,23 +1825,26 @@ purge_node(Host, Node, Owner) -> %% Node is not configured for persistent items {error, extended_error('feature-not-implemented', unsupported, "persistent-items")}; true -> - node_call(Type, purge_node, [Host, Node, Owner]) + node_call(Type, purge_node, [NodeId, Owner]) end end, Reply = [], case transaction(Host, Node, Action, sync_dirty) of - {error, Reason} -> - {error, Reason}; - {result, {Result, broadcast}} -> - broadcast_purge_node(Host, Node), + {result, {TNode, {Result, broadcast}}} -> + NodeId = TNode#pubsub_node.id, + Type = TNode#pubsub_node.type, + Options = TNode#pubsub_node.options, + broadcast_purge_node(Host, Node, NodeId, Type, Options), case Result of default -> {result, Reply}; _ -> {result, Result} end; - {result, default} -> + {result, {_, default}} -> {result, Reply}; - {result, Result} -> - {result, Result} + {result, {_, Result}} -> + {result, Result}; + Error -> + Error end. %% @doc

    Return the items of a given node.

    @@ -1793,7 +1866,7 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> {error, Error} -> {error, Error}; _ -> - Action = fun(#pubsub_node{options = Options, type = Type}) -> + Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> Features = features(Type), RetreiveFeature = lists:member("retrieve-items", Features), PersistentFeature = lists:member("persistent-items", Features), @@ -1816,15 +1889,13 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> {error, extended_error('feature-not-implemented', unsupported, "persistent-items")}; true -> node_call(Type, get_items, - [Host, Node, From, + [NodeId, From, AccessModel, PresenceSubscription, RosterGroup, SubId]) end end, case transaction(Host, Node, Action, sync_dirty) of - {error, Reason} -> - {error, Reason}; - {result, Items} -> + {result, {_, Items}} -> SendItems = case ItemIDs of [] -> Items; @@ -1837,47 +1908,46 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> %% number of items sent to MaxItems: {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = - itemsEls(lists:sublist(SendItems, MaxItems))}]}]} + itemsEls(lists:sublist(SendItems, MaxItems))}]}]}; + Error -> + Error end end. -get_items(Host, Node, From) -> - case node_action(Host, Node, get_items, [Host, Node, From]) of - {result, Items} -> Items; - _ -> [] - end. - -%% @spec (Host, Node, LJID, Number) -> any() +%% @spec (Host, Node, NodeId, Type, LJID, Number) -> any() %% Host = host() -%% Node = pubsubNode() +%% NodeId = pubsubNodeId() +%% Type = pubsubNodeType() %% LJID = {U, S, []} %% Number = last | integer() %% @doc

    Resend the items of a node to the user.

    %% @todo use cache-last-item feature -send_items(Host, Node, {LU, LS, LR} = LJID, Number) -> - ToSend = case get_items(Host, Node, LJID) of - [] -> +send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> + ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of + {result, []} -> []; - Items -> + {result, Items} -> case Number of last -> %%% [lists:last(Items)] does not work on clustered table [First|Tail] = Items, [lists:foldl( fun(CurItem, LastItem) -> - {_, LTimeStamp} = LastItem#pubsub_item.creation, - {_, CTimeStamp} = CurItem#pubsub_item.creation, + {LTimeStamp, _} = LastItem#pubsub_item.creation, + {CTimeStamp, _} = CurItem#pubsub_item.creation, if CTimeStamp > LTimeStamp -> CurItem; true -> LastItem end end, First, Tail)]; N when N > 0 -> - %%% This case is buggy on clustered table due to lake of order + %%% This case is buggy on clustered table due to lack of order lists:nthtail(length(Items)-N, Items); _ -> Items - end + end; + _ -> + [] end, Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = @@ -1901,7 +1971,7 @@ get_affiliations(Host, JID, Plugins) when is_list(Plugins) -> %% Service does not support retreive affiliatons {{error, extended_error('feature-not-implemented', unsupported, "retrieve-affiliations")}, Acc}; true -> - {result, Affiliations} = node_action(Type, get_entity_affiliations, [Host, JID]), + {result, Affiliations} = node_action(Host, Type, get_entity_affiliations, [Host, JID]), {Status, [Affiliations|Acc]} end end, {ok, []}, Plugins), @@ -1921,10 +1991,10 @@ get_affiliations(Host, JID, Plugins) when is_list(Plugins) -> Error end; get_affiliations(Host, Node, JID) -> - Action = fun(#pubsub_node{type = Type}) -> + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> Features = features(Type), RetrieveFeature = lists:member("modify-affiliations", Features), - Affiliation = node_call(Type, get_affiliation, [Host, Node, JID]), + Affiliation = node_call(Type, get_affiliation, [NodeId, JID]), if not RetrieveFeature -> %% Service does not support modify affiliations @@ -1933,15 +2003,13 @@ get_affiliations(Host, Node, JID) -> %% Entity is not an owner {error, 'forbidden'}; true -> - node_call(Type, get_node_affiliations, [Host, Node]) + node_call(Type, get_node_affiliations, [NodeId]) end end, case transaction(Host, Node, Action, sync_dirty) of - {error, Reason} -> - {error, Reason}; - {result, []} -> + {result, {_, []}} -> {error, 'item-not-found'}; - {result, Affiliations} -> + {result, {_, Affiliations}} -> Entities = lists:flatmap( fun({_, none}) -> []; ({{AU, AS, AR}, Affiliation}) -> @@ -1951,7 +2019,9 @@ get_affiliations(Host, Node, JID) -> end, Affiliations), {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'affiliations', attrs = [?XMLATTR('node', node_to_string(Node))], children = - Entities}]}]} + Entities}]}]}; + Error -> + Error end. set_affiliations(Host, Node, From, EntitiesEls) -> @@ -1987,12 +2057,12 @@ set_affiliations(Host, Node, From, EntitiesEls) -> error -> {error, 'bad-request'}; _ -> - Action = fun(#pubsub_node{type = Type, owners = Owners}=N) -> + Action = fun(#pubsub_node{owners = Owners, type = Type, id = NodeId}=N) -> case lists:member(Owner, Owners) of true -> lists:foreach( fun({JID, Affiliation}) -> - node_call(Type, set_affiliation, [Host, Node, JID, Affiliation]), + node_call(Type, set_affiliation, [NodeId, JID, Affiliation]), case Affiliation of owner -> NewOwner = jlib:short_prepd_bare_jid(JID), @@ -2016,7 +2086,10 @@ set_affiliations(Host, Node, From, EntitiesEls) -> {error, 'forbidden'} end end, - transaction(Host, Node, Action, sync_dirty) + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Result}} -> {result, Result}; + Other -> Other + end end. @@ -2038,7 +2111,7 @@ get_subscriptions(Host, JID, Plugins) when is_list(Plugins) -> {{error, extended_error('feature-not-implemented', unsupported, "retrieve-subscriptions")}, Acc}; true -> Subscriber = jlib:jid_remove_resource(JID), - {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, Subscriber]), + {result, Subscriptions} = node_action(Host, Type, get_entity_subscriptions, [Host, Subscriber]), {Status, [Subscriptions|Acc]} end end, {ok, []}, Plugins), @@ -2064,10 +2137,10 @@ get_subscriptions(Host, JID, Plugins) when is_list(Plugins) -> Error end; get_subscriptions(Host, Node, JID) -> - Action = fun(#pubsub_node{type = Type}) -> + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> Features = features(Type), RetrieveFeature = lists:member("manage-subscriptions", Features), - Affiliation = node_call(Type, get_affiliation, [Host, Node, JID]), + Affiliation = node_call(Type, get_affiliation, [NodeId, JID]), if not RetrieveFeature -> %% Service does not support manage subscriptions @@ -2076,15 +2149,13 @@ get_subscriptions(Host, Node, JID) -> %% Entity is not an owner {error, 'forbidden'}; true -> - node_call(Type, get_node_subscriptions, [Host, Node]) + node_call(Type, get_node_subscriptions, [NodeId]) end end, case transaction(Host, Node, Action, sync_dirty) of - {error, Reason} -> - {error, Reason}; - {result, []} -> + {result, {_, []}} -> {error, 'item-not-found'}; - {result, Subscriptions} -> + {result, {_, Subscriptions}} -> Entities = lists:flatmap( fun({_, none}) -> []; ({{AU, AS, AR}, Subscription}) -> @@ -2099,7 +2170,9 @@ get_subscriptions(Host, Node, JID) -> end, Subscriptions), {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscriptions', attrs = [?XMLATTR('node', node_to_string(Node))], children = - Entities}]}]} + Entities}]}]}; + Error -> + Error end. set_subscriptions(Host, Node, From, EntitiesEls) -> @@ -2136,21 +2209,22 @@ set_subscriptions(Host, Node, From, EntitiesEls) -> error -> {error, 'bad-request'}; _ -> - Action = fun(#pubsub_node{type = Type, owners = Owners}) -> + Action = fun(#pubsub_node{type = Type, id = NodeId, owners = Owners}) -> case lists:member(Owner, Owners) of true -> lists:foreach( fun({JID, Subscription}) -> - node_call( - Type, set_subscription, - [Host, Node, JID, Subscription]) + node_call(Type, set_subscription, [NodeId, JID, Subscription]) end, Entities), {result, []}; _ -> {error, 'forbidden'} end end, - transaction(Host, Node, Action, sync_dirty) + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Result}} -> {result, Result}; + Other -> Other + end end. @@ -2265,174 +2339,169 @@ event_stanza(Els) -> %%%%%% broadcast functions -broadcast_publish_item(Host, Node, ItemId, _From, Payload) -> - %broadcast(Host, Node, none, true, 'items', ItemEls) - Action = - fun(#pubsub_node{options = Options, type = Type}) -> - case node_call(Type, get_states, [Host, Node]) of +broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, _From, Payload) -> + %broadcast(Host, Node, NodeId, Options, none, true, 'items', ItemEls) + case node_action(Host, Type, get_node_subscriptions, [NodeId]) of + {result, []} -> + {result, false}; + {result, Subs} -> + Content = case get_option(Options, deliver_payloads) of + true -> Payload; + false -> [] + end, + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = itemAttr(ItemId), children = Content}]}]), + broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza), + case Removed of + [] -> + ok; + _ -> + case get_option(Options, notify_retract) of + true -> + RetractStanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = itemAttr(RId)} || RId <- Removed]}]), + broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, RetractStanza); + _ -> + ok + end + end, + {result, true}; + _ -> + {result, false} + end. + +broadcast_retract_items(Host, Node, NodeId, Type, Options, ItemIds) -> + broadcast_retract_items(Host, Node, NodeId, Type, Options, ItemIds, false). +broadcast_retract_items(_Host, _Node, _NodeId, _Type, _Options, [], _ForceNotify) -> + {result, false}; +broadcast_retract_items(Host, Node, NodeId, Type, Options, ItemIds, ForceNotify) -> + %broadcast(Host, Node, NodeId, Options, notify_retract, ForceNotify, 'retract', RetractEls) + case (get_option(Options, notify_retract) or ForceNotify) of + true -> + case node_action(Host, Type, get_node_subscriptions, [NodeId]) of {result, []} -> {result, false}; - {result, States} -> - Content = case get_option(Options, deliver_payloads) of - true -> Payload; - false -> [] - end, + {result, Subs} -> Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = itemAttr(ItemId), children = Content}]}]), - broadcast_stanza(Host, Node, Type, Options, States, Stanza), + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = itemAttr(ItemId)} || ItemId <- ItemIds]}]), + broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza), {result, true}; _ -> {result, false} - end - end, - transaction(Host, Node, Action, sync_dirty). + end; + _ -> + {result, false} + end. -broadcast_retract_items(Host, Node, ItemIds) -> - broadcast_retract_items(Host, Node, ItemIds, false). -broadcast_retract_items(Host, Node, ItemIds, ForceNotify) -> - %broadcast(Host, Node, notify_retract, ForceNotify, 'retract', RetractEls) - Action = - fun(#pubsub_node{options = Options, type = Type}) -> - case (get_option(Options, notify_retract) or ForceNotify) of - true -> - case node_call(Type, get_states, [Host, Node]) of - {result, []} -> - {result, false}; - {result, States} -> - RetractEls = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = itemAttr(ItemId)} || ItemId <- ItemIds], - Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], - children = RetractEls}]), - broadcast_stanza(Host, Node, Type, Options, States, Stanza), - {result, true}; - _ -> - {result, false} - end; - _ -> +broadcast_purge_node(Host, Node, NodeId, Type, Options) -> + %broadcast(Host, Node, NodeId, Options, notify_retract, false, 'purge', []) + case get_option(Options, notify_retract) of + true -> + case node_action(Host, Type, get_node_subscriptions, [NodeId]) of + {result, []} -> + {result, false}; + {result, Subs} -> + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'purge', attrs = [?XMLATTR('node', node_to_string(Node))]}]), + broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza), + {result, true}; + _ -> {result, false} - end - end, - transaction(Host, Node, Action, sync_dirty). + end; + _ -> + {result, false} + end. -broadcast_purge_node(Host, Node) -> - %broadcast(Host, Node, notify_retract, false, 'purge', []) - Action = - fun(#pubsub_node{options = Options, type = Type}) -> - case get_option(Options, notify_retract) of - true -> - case node_call(Type, get_states, [Host, Node]) of - {result, []} -> - {result, false}; - {result, States} -> - Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'purge', attrs = [?XMLATTR('node', node_to_string(Node))]}]), - broadcast_stanza(Host, Node, Type, Options, States, Stanza), - {result, true}; - _ -> - {result, false} - end; +broadcast_removed_node(Host, Node, NodeId, Type, Options, Subs) -> + %broadcast(Host, Node, NodeId, Options, notify_delete, false, 'delete', []) + case get_option(Options, notify_delete) of + true -> + case Subs of + [] -> + {result, false}; _ -> - {result, false} - end - end, - transaction(Host, Node, Action, sync_dirty). + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'delete', attrs = [?XMLATTR('node', node_to_string(Node))]}]), + broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza), + {result, true} + end; + _ -> + {result, false} + end. -broadcast_removed_node(Host, Node) -> - %broadcast(Host, Node, notify_delete, false, 'delete', []) - Action = - fun(#pubsub_node{options = Options, type = Type}) -> - case get_option(Options, notify_delete) of - true -> - case node_call(Type, get_states, [Host, Node]) of - {result, []} -> - {result, false}; - {result, States} -> - Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'delete', attrs = [?XMLATTR('node', node_to_string(Node))]}]), - broadcast_stanza(Host, Node, Type, Options, States, Stanza), - {result, true}; - _ -> - {result, false} - end; - _ -> +broadcast_config_notification(Host, Node, NodeId, Type, Options, Lang) -> + %broadcast(Host, Node, NodeId, Options, notify_config, false, 'items', ConfigEls) + case get_option(Options, notify_config) of + true -> + case node_action(Host, Type, get_node_subscriptions, [NodeId]) of + {result, []} -> + {result, false}; + {result, Subs} -> + Content = case get_option(Options, deliver_payloads) of + true -> + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = + get_configure_xfields(Type, Options, Lang, [])}]; + false -> + [] + end, + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = [?XMLATTR('id', <<"configuration">>)], children = + Content}]}]), + broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza), + {result, true}; + _ -> {result, false} - end - end, - transaction(Host, Node, Action, sync_dirty). + end; + _ -> + {result, false} + end. -broadcast_config_notification(Host, Node, Lang) -> - %broadcast(Host, Node, notify_config, false, 'items', ConfigEls) - Action = - fun(#pubsub_node{options = Options, owners = Owners, type = Type}) -> - case get_option(Options, notify_config) of - true -> - case node_call(Type, get_states, [Host, Node]) of - {result, []} -> - {result, false}; - {result, States} -> - Content = case get_option(Options, deliver_payloads) of - true -> - [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = - get_configure_xfields(Type, Options, Lang, Owners, [])}]; - false -> - [] - end, - Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = [?XMLATTR('id', <<"configuration">>)], children = - Content}]}]), - broadcast_stanza(Host, Node, Type, Options, States, Stanza), - {result, true}; - _ -> - {result, false} - end; - _ -> - {result, false} - end - end, - transaction(Host, Node, Action, sync_dirty). % TODO: merge broadcast code that way -%broadcast(Host, Node, Feature, Force, ElName, SubEls) -> -% Action = -% fun(#pubsub_node{options = Options, type = Type}) -> -% case (get_option(Options, Feature) or Force) of -% true -> -% case node_call(Type, get_states, [Host, Node]) of -% {result, []} -> -% {result, false}; -% {result, States} -> -% Stanza = event_stanza([{xmlelement, ElName, [{"node", node_to_string(Node)}], SubEls}]), -% broadcast_stanza(Host, Node, Type, Options, States, Stanza), -% {result, true}; -% _ -> -% {result, false} -% end; -% _ -> -% {result, false} -% end -% end, -% transaction(Host, Node, Action, sync_dirty). +%broadcast(Host, Node, NodeId, Type, Options, Feature, Force, ElName, SubEls) -> +% case (get_option(Options, Feature) or Force) of +% true -> +% case node_action(Host, Type, get_node_subscriptions, [NodeId]) of +% {result, []} -> +% {result, false}; +% {result, Subs} -> +% Stanza = event_stanza([{xmlelement, ElName, [{"node", node_to_string(Node)}], SubEls}]), +% broadcast_stanza(Host, Node, Type, Options, Subs, Stanza), +% {result, true}; +% _ -> +% {result, false} +% end; +% _ -> +% {result, false} +% end -broadcast_stanza(Host, Node, _Type, Options, States, Stanza) -> - AccessModel = get_option(Options, access_model), +broadcast_stanza(Host, Node, _NodeId, _Type, Options, Subscriptions, Stanza) -> + %AccessModel = get_option(Options, access_model), PresenceDelivery = get_option(Options, presence_based_delivery), BroadcastAll = get_option(Options, broadcast_all_resources), %% XXX this is not standard, but usefull From = service_jid(Host), %% Handles explicit subscriptions - lists:foreach(fun(#pubsub_state{stateid = {LJID, _}, subscription = Subs}) -> - case is_to_deliver(LJID, Subs, PresenceDelivery) of + lists:foreach(fun({LJID, Subscription}) -> + case is_to_deliver(LJID, Subscription, PresenceDelivery) of true -> - {U, S, R} = case BroadcastAll of - true -> jlib:short_prepd_bare_jid(LJID); - false -> LJID + LJIDs = case BroadcastAll of + true -> + {U, S, _} = LJID, + [{U, S, R} || R <- user_resources(U, S)]; + false -> + [LJID] end, - ejabberd_router ! {route, From, exmpp_jlib:make_jid(U, S, R), Stanza}; + lists:foreach(fun(To) -> + ejabberd_router ! {route, From, jlib:make_jid(To), Stanza} + end, LJIDs); false -> ok end - end, States), + end, Subscriptions), %% Handles implicit presence subscriptions case Host of {LUser, LServer, LResource} -> @@ -2507,8 +2576,8 @@ is_caps_notify(Host, Node, LJID) -> %% get_configure(Host, ServerHost, Node, From, Lang) -> Action = - fun(#pubsub_node{options = Options, owners = Owners, type = Type}) -> - case node_call(Type, get_affiliation, [Host, Node, From]) of + fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> + case node_call(Type, get_affiliation, [NodeId, From]) of {result, owner} -> Groups = ejabberd_hooks:run_fold(roster_groups, ServerHost, [], [ServerHost]), {result, @@ -2517,13 +2586,16 @@ get_configure(Host, ServerHost, Node, From, Lang) -> [?XMLATTR('node', node_to_string(Node))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = - get_configure_xfields(Type, Options, Lang, Owners, Groups) + get_configure_xfields(Type, Options, Lang, Groups) }]}]}]}; _ -> {error, 'forbidden'} end end, - transaction(Host, Node, Action, sync_dirty). + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Result}} -> {result, Result}; + Other -> Other + end. get_default(Host, Node, _From, Lang) -> Type = select_type(Host, Host, Node), @@ -2531,7 +2603,7 @@ get_default(Host, Node, _From, Lang) -> {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'default', children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = - get_configure_xfields(Type, Options, Lang, [], []) + get_configure_xfields(Type, Options, Lang, []) }]}]}]}. %% Get node option @@ -2607,7 +2679,7 @@ max_items(Options) -> ?LISTMXFIELD(Label, "pubsub#" ++ atom_to_list(Var), get_option(Options, Var), Opts)). -get_configure_xfields(Type, Options, Lang, _Owners, Groups) -> +get_configure_xfields(Type, Options, Lang, Groups) -> [?XFIELD("hidden", "", "FORM_TYPE", ?NS_PUBSUB_NODE_CONFIG_s), ?BOOL_CONFIG_FIELD("Deliver payloads with event notifications", deliver_payloads), ?BOOL_CONFIG_FIELD("Deliver event notifications", deliver_notifications), @@ -2646,9 +2718,8 @@ set_configure(Host, Node, From, Els, Lang) -> {result, []}; "submit" -> Action = - fun(#pubsub_node{options = Options, type = Type}=N) -> - case node_call(Type, get_affiliation, - [Host, Node, From]) of + fun(#pubsub_node{options = Options, type = Type, id = NodeId} = N) -> + case node_call(Type, get_affiliation, [NodeId, From]) of {result, owner} -> case jlib:parse_xdata_submit(XEl) of invalid -> @@ -2660,8 +2731,7 @@ set_configure(Host, Node, From, Els, Lang) -> end, case set_xoption(XData, OldOpts) of NewOpts when is_list(NewOpts) -> - tree_call(Host, set_node, - [N#pubsub_node{options = NewOpts}]), + tree_call(Host, set_node, [N#pubsub_node{options = NewOpts}]), {result, ok}; Err -> Err @@ -2672,8 +2742,11 @@ set_configure(Host, Node, From, Els, Lang) -> end end, case transaction(Host, Node, Action, transaction) of - {result, ok} -> - broadcast_config_notification(Host, Node, Lang), + {result, {TNode, ok}} -> + NodeId = TNode#pubsub_node.id, + Type = TNode#pubsub_node.type, + Options = TNode#pubsub_node.options, + broadcast_config_notification(Host, Node, NodeId, Type, Options, Lang), {result, []}; Other -> Other @@ -2845,13 +2918,17 @@ features(Host, []) -> Acc ++ features(Plugin) end, [], plugins(Host))); features(Host, Node) -> - {result, Features} = node_action(Host, Node, features, []), - lists:usort(features() ++ Features). + Action = fun(#pubsub_node{type = Type}) -> {result, features(Type)} end, + case transaction(Host, Node, Action, sync_dirty) of + {result, Features} -> lists:usort(features() ++ Features); + _ -> features() + end. %% @doc

    node tree plugin call.

    tree_call({_User, Server, _Resource}, Function, Args) -> tree_call(Server, Function, Args); tree_call(Host, Function, Args) -> + ?DEBUG("tree_call ~p ~p ~p",[Host, Function, Args]), Module = case ets:lookup(gen_mod:get_module_proc(Host, pubsub_state), nodetree) of [{nodetree, N}] -> N; _ -> list_to_atom(?TREE_PREFIX ++ ?STDTREE) @@ -2863,6 +2940,7 @@ tree_action(Host, Function, Args) -> %% @doc

    node plugin call.

    node_call(Type, Function, Args) -> + ?DEBUG("node_call ~p ~p ~p",[Type, Function, Args]), Module = list_to_atom(?PLUGIN_PREFIX++Type), case catch apply(Module, Function, Args) of {result, Result} -> {result, Result}; @@ -2876,24 +2954,23 @@ node_call(Type, Function, Args) -> Result -> {result, Result} %% any other return value is forced as result end. -node_action(Type, Function, Args) -> +node_action(_Host, Type, Function, Args) -> transaction(fun() -> node_call(Type, Function, Args) end, sync_dirty). -node_action(Host, Node, Function, Args) -> - transaction(fun() -> - case tree_call(Host, get_node, [Host, Node]) of - #pubsub_node{type=Type} -> node_call(Type, Function, Args); - Other -> Other - end - end, sync_dirty). %% @doc

    plugin transaction handling.

    transaction(Host, Node, Action, Trans) -> transaction(fun() -> case tree_call(Host, get_node, [Host, Node]) of - Record when is_record(Record, pubsub_node) -> Action(Record); - Other -> Other + N when is_record(N, pubsub_node) -> + case Action(N) of + {result, Result} -> {result, {N, Result}}; + {atomic, {result, Result}} -> {result, {N, Result}}; + Other -> Other + end; + Error -> + Error end end, Trans). diff --git a/src/mod_pubsub/node.template b/src/mod_pubsub/node.template index a9f45e1ef..d4fffc474 100644 --- a/src/mod_pubsub/node.template +++ b/src/mod_pubsub/node.template @@ -41,29 +41,29 @@ -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, - create_node/3, - delete_node/2, - purge_node/3, - subscribe_node/8, - unsubscribe_node/5, - publish_item/7, - delete_item/4, - remove_extra_items/4, + create_node/2, + delete_node/1, + purge_node/2, + subscribe_node/7, + unsubscribe_node/4, + publish_item/6, + delete_item/3, + remove_extra_items/3, get_entity_affiliations/2, - get_node_affiliations/2, - get_affiliation/3, - set_affiliation/4, + get_node_affiliations/1, + get_affiliation/2, + set_affiliation/3, get_entity_subscriptions/2, - get_node_subscriptions/2, - get_subscription/3, - set_subscription/4, - get_states/2, - get_state/3, + get_node_subscriptions/1, + get_subscription/2, + set_subscription/3, + get_states/1, + get_state/2, set_state/1, - get_items/7, - get_items/3, - get_item/8, - get_item/3, + get_items/6, + get_items/2, + get_item/7, + get_item/2, set_item/1 ]). @@ -87,7 +87,7 @@ options() -> {roster_groups_allowed, []}, {publish_model, publishers}, {max_payload_size, ?MAX_PAYLOAD_SIZE}, - {send_last_published_item, never}, + {send_last_published_item, on_sub_and_presence}, {deliver_notifications, true}, {presence_based_delivery, false}]. @@ -111,74 +111,74 @@ features() -> create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). -create_node(Host, Node, Owner) -> - node_default:create_node(Host, Node, Owner). +create_node(NodeId, Owner) -> + node_default:create_node(NodeId, Owner). -delete_node(Host, Removed) -> - node_default:delete_node(Host, Removed). +delete_node(Removed) -> + node_default:delete_node(Removed). -subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). +subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> + node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). -unsubscribe_node(Host, Node, Sender, Subscriber, SubID) -> - node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID). +unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> + node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID). -publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) -> - node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload). +publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> + node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). -remove_extra_items(Host, Node, MaxItems, ItemIds) -> - node_default:remove_extra_items(Host, Node, MaxItems, ItemIds). +remove_extra_items(NodeId, MaxItems, ItemIds) -> + node_default:remove_extra_items(NodeId, MaxItems, ItemIds). -delete_item(Host, Node, JID, ItemId) -> - node_default:delete_item(Host, Node, JID, ItemId). +delete_item(NodeId, JID, ItemId) -> + node_default:delete_item(NodeId, JID, ItemId). -purge_node(Host, Node, Owner) -> - node_default:purge_node(Host, Node, Owner). +purge_node(NodeId, Owner) -> + node_default:purge_node(NodeId, Owner). get_entity_affiliations(Host, Owner) -> node_default:get_entity_affiliations(Host, Owner). -get_node_affiliations(Host, Node) -> - node_default:get_node_affiliations(Host, Node). +get_node_affiliations(NodeId) -> + node_default:get_node_affiliations(NodeId). -get_affiliation(Host, Node, Owner) -> - node_default:get_affiliation(Host, Node, Owner). +get_affiliation(NodeId, Owner) -> + node_default:get_affiliation(NodeId, Owner). -set_affiliation(Host, Node, Owner, Affiliation) -> - node_default:set_affiliation(Host, Node, Owner, Affiliation). +set_affiliation(NodeId, Owner, Affiliation) -> + node_default:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(Host, Owner) -> node_default:get_entity_subscriptions(Host, Owner). -get_node_subscriptions(Host, Node) -> - node_default:get_node_subscriptions(Host, Node). +get_node_subscriptions(NodeId) -> + node_default:get_node_subscriptions(NodeId). -get_subscription(Host, Node, Owner) -> - node_default:get_subscription(Host, Node, Owner). +get_subscription(NodeId, Owner) -> + node_default:get_subscription(NodeId, Owner). -set_subscription(Host, Node, Owner, Subscription) -> - node_default:set_subscription(Host, Node, Owner, Subscription). +set_subscription(NodeId, Owner, Subscription) -> + node_default:set_subscription(NodeId, Owner, Subscription). -get_states(Host, Node) -> - node_default:get_states(Host, Node). +get_states(NodeId) -> + node_default:get_states(NodeId). -get_state(Host, Node, JID) -> - node_default:get_state(Host, Node, JID). +get_state(NodeId, JID) -> + node_default:get_state(NodeId, JID). set_state(State) -> node_default:set_state(State). -get_items(Host, Node, From) -> - node_default:get_items(Host, Node, From). +get_items(NodeId, From) -> + node_default:get_items(NodeId, From). -get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) - node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) + node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). -get_item(Host, Node, ItemId) -> - node_default:get_item(Host, Node, ItemId). +get_item(NodeId, ItemId) -> + node_default:get_item(NodeId, ItemId). -get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). set_item(Item) -> node_default:set_item(Item). diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl index 6d9e1b549..b963fba20 100644 --- a/src/mod_pubsub/node_buddy.erl +++ b/src/mod_pubsub/node_buddy.erl @@ -44,29 +44,29 @@ -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, - create_node/3, - delete_node/2, - purge_node/3, - subscribe_node/8, - unsubscribe_node/5, - publish_item/7, - delete_item/4, - remove_extra_items/4, + create_node/2, + delete_node/1, + purge_node/2, + subscribe_node/7, + unsubscribe_node/4, + publish_item/6, + delete_item/3, + remove_extra_items/3, get_entity_affiliations/2, - get_node_affiliations/2, - get_affiliation/3, - set_affiliation/4, + get_node_affiliations/1, + get_affiliation/2, + set_affiliation/3, get_entity_subscriptions/2, - get_node_subscriptions/2, - get_subscription/3, - set_subscription/4, - get_states/2, - get_state/3, + get_node_subscriptions/1, + get_subscription/2, + set_subscription/3, + get_states/1, + get_state/2, set_state/1, - get_items/7, - get_items/3, - get_item/8, - get_item/3, + get_items/6, + get_items/2, + get_item/7, + get_item/2, set_item/1, get_item_name/3 ]). @@ -116,74 +116,74 @@ features() -> create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). -create_node(Host, Node, Owner) -> - node_default:create_node(Host, Node, Owner). +create_node(NodeId, Owner) -> + node_default:create_node(NodeId, Owner). -delete_node(Host, Removed) -> - node_default:delete_node(Host, Removed). +delete_node(Removed) -> + node_default:delete_node(Removed). -subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). +subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> + node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). -unsubscribe_node(Host, Node, Sender, Subscriber, SubID) -> - node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID). +unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> + node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID). -publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) -> - node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload). +publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> + node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). -remove_extra_items(Host, Node, MaxItems, ItemIds) -> - node_default:remove_extra_items(Host, Node, MaxItems, ItemIds). +remove_extra_items(NodeId, MaxItems, ItemIds) -> + node_default:remove_extra_items(NodeId, MaxItems, ItemIds). -delete_item(Host, Node, JID, ItemId) -> - node_default:delete_item(Host, Node, JID, ItemId). +delete_item(NodeId, JID, ItemId) -> + node_default:delete_item(NodeId, JID, ItemId). -purge_node(Host, Node, Owner) -> - node_default:purge_node(Host, Node, Owner). +purge_node(NodeId, Owner) -> + node_default:purge_node(NodeId, Owner). get_entity_affiliations(Host, Owner) -> node_default:get_entity_affiliations(Host, Owner). -get_node_affiliations(Host, Node) -> - node_default:get_node_affiliations(Host, Node). +get_node_affiliations(NodeId) -> + node_default:get_node_affiliations(NodeId). -get_affiliation(Host, Node, Owner) -> - node_default:get_affiliation(Host, Node, Owner). +get_affiliation(NodeId, Owner) -> + node_default:get_affiliation(NodeId, Owner). -set_affiliation(Host, Node, Owner, Affiliation) -> - node_default:set_affiliation(Host, Node, Owner, Affiliation). +set_affiliation(NodeId, Owner, Affiliation) -> + node_default:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(Host, Owner) -> node_default:get_entity_subscriptions(Host, Owner). -get_node_subscriptions(Host, Node) -> - node_default:get_node_subscriptions(Host, Node). +get_node_subscriptions(NodeId) -> + node_default:get_node_subscriptions(NodeId). -get_subscription(Host, Node, Owner) -> - node_default:get_subscription(Host, Node, Owner). +get_subscription(NodeId, Owner) -> + node_default:get_subscription(NodeId, Owner). -set_subscription(Host, Node, Owner, Subscription) -> - node_default:set_subscription(Host, Node, Owner, Subscription). +set_subscription(NodeId, Owner, Subscription) -> + node_default:set_subscription(NodeId, Owner, Subscription). -get_states(Host, Node) -> - node_default:get_states(Host, Node). +get_states(NodeId) -> + node_default:get_states(NodeId). -get_state(Host, Node, JID) -> - node_default:get_state(Host, Node, JID). +get_state(NodeId, JID) -> + node_default:get_state(NodeId, JID). set_state(State) -> node_default:set_state(State). -get_items(Host, Node, From) -> - node_default:get_items(Host, Node, From). +get_items(NodeId, From) -> + node_default:get_items(NodeId, From). -get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). -get_item(Host, Node, ItemId) -> - node_default:get_item(Host, Node, ItemId). +get_item(NodeId, ItemId) -> + node_default:get_item(NodeId, ItemId). -get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). set_item(Item) -> node_default:set_item(Item). diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl index b5a04beda..1e3900cc0 100644 --- a/src/mod_pubsub/node_club.erl +++ b/src/mod_pubsub/node_club.erl @@ -44,29 +44,29 @@ -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, - create_node/3, - delete_node/2, - purge_node/3, - subscribe_node/8, - unsubscribe_node/5, - publish_item/7, - delete_item/4, - remove_extra_items/4, + create_node/2, + delete_node/1, + purge_node/2, + subscribe_node/7, + unsubscribe_node/4, + publish_item/6, + delete_item/3, + remove_extra_items/3, get_entity_affiliations/2, - get_node_affiliations/2, - get_affiliation/3, - set_affiliation/4, + get_node_affiliations/1, + get_affiliation/2, + set_affiliation/3, get_entity_subscriptions/2, - get_node_subscriptions/2, - get_subscription/3, - set_subscription/4, - get_states/2, - get_state/3, + get_node_subscriptions/1, + get_subscription/2, + set_subscription/3, + get_states/1, + get_state/2, set_state/1, - get_items/7, - get_items/3, - get_item/8, - get_item/3, + get_items/6, + get_items/2, + get_item/7, + get_item/2, set_item/1, get_item_name/3 ]). @@ -115,74 +115,74 @@ features() -> create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). -create_node(Host, Node, Owner) -> - node_default:create_node(Host, Node, Owner). +create_node(NodeId, Owner) -> + node_default:create_node(NodeId, Owner). -delete_node(Host, Removed) -> - node_default:delete_node(Host, Removed). +delete_node(Removed) -> + node_default:delete_node(Removed). -subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). +subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> + node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). -unsubscribe_node(Host, Node, Sender, Subscriber, SubID) -> - node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID). +unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> + node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID). -publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) -> - node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload). +publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> + node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). -remove_extra_items(Host, Node, MaxItems, ItemIds) -> - node_default:remove_extra_items(Host, Node, MaxItems, ItemIds). +remove_extra_items(NodeId, MaxItems, ItemIds) -> + node_default:remove_extra_items(NodeId, MaxItems, ItemIds). -delete_item(Host, Node, JID, ItemId) -> - node_default:delete_item(Host, Node, JID, ItemId). +delete_item(NodeId, JID, ItemId) -> + node_default:delete_item(NodeId, JID, ItemId). -purge_node(Host, Node, Owner) -> - node_default:purge_node(Host, Node, Owner). +purge_node(NodeId, Owner) -> + node_default:purge_node(NodeId, Owner). get_entity_affiliations(Host, Owner) -> node_default:get_entity_affiliations(Host, Owner). -get_node_affiliations(Host, Node) -> - node_default:get_node_affiliations(Host, Node). +get_node_affiliations(NodeId) -> + node_default:get_node_affiliations(NodeId). -get_affiliation(Host, Node, Owner) -> - node_default:get_affiliation(Host, Node, Owner). +get_affiliation(NodeId, Owner) -> + node_default:get_affiliation(NodeId, Owner). -set_affiliation(Host, Node, Owner, Affiliation) -> - node_default:set_affiliation(Host, Node, Owner, Affiliation). +set_affiliation(NodeId, Owner, Affiliation) -> + node_default:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(Host, Owner) -> node_default:get_entity_subscriptions(Host, Owner). -get_node_subscriptions(Host, Node) -> - node_default:get_node_subscriptions(Host, Node). +get_node_subscriptions(NodeId) -> + node_default:get_node_subscriptions(NodeId). -get_subscription(Host, Node, Owner) -> - node_default:get_subscription(Host, Node, Owner). +get_subscription(NodeId, Owner) -> + node_default:get_subscription(NodeId, Owner). -set_subscription(Host, Node, Owner, Subscription) -> - node_default:set_subscription(Host, Node, Owner, Subscription). +set_subscription(NodeId, Owner, Subscription) -> + node_default:set_subscription(NodeId, Owner, Subscription). -get_states(Host, Node) -> - node_default:get_states(Host, Node). +get_states(NodeId) -> + node_default:get_states(NodeId). -get_state(Host, Node, JID) -> - node_default:get_state(Host, Node, JID). +get_state(NodeId, JID) -> + node_default:get_state(NodeId, JID). set_state(State) -> node_default:set_state(State). -get_items(Host, Node, From) -> - node_default:get_items(Host, Node, From). +get_items(NodeId, From) -> + node_default:get_items(NodeId, From). -get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). -get_item(Host, Node, ItemId) -> - node_default:get_item(Host, Node, ItemId). +get_item(NodeId, ItemId) -> + node_default:get_item(NodeId, ItemId). -get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). set_item(Item) -> node_default:set_item(Item). diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index ae0707fcb..be4f3ebfa 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -51,29 +51,29 @@ -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, - create_node/3, - delete_node/2, - purge_node/3, - subscribe_node/8, - unsubscribe_node/5, - publish_item/7, - delete_item/4, - remove_extra_items/4, + create_node/2, + delete_node/1, + purge_node/2, + subscribe_node/7, + unsubscribe_node/4, + publish_item/6, + delete_item/3, + remove_extra_items/3, get_entity_affiliations/2, - get_node_affiliations/2, - get_affiliation/3, - set_affiliation/4, + get_node_affiliations/1, + get_affiliation/2, + set_affiliation/3, get_entity_subscriptions/2, - get_node_subscriptions/2, - get_subscription/3, - set_subscription/4, - get_states/2, - get_state/3, + get_node_subscriptions/1, + get_subscription/2, + set_subscription/3, + get_states/1, + get_state/2, set_state/1, - get_items/7, - get_items/3, - get_item/8, - get_item/3, + get_items/6, + get_items/2, + get_item/7, + get_item/2, set_item/1, get_item_name/3 ]). @@ -193,8 +193,8 @@ features() -> %%

    PubSub plugins can redefine the PubSub node creation rights as they %% which. They can simply delegate this check to the {@link node_default} %% module by implementing this function like this: -%% ```check_create_user_permission(Host, Node, Owner, Access) -> -%% node_default:check_create_user_permission(Host, Node, Owner, Access).'''

    +%% ```check_create_user_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> +%% node_default:check_create_user_permission(Host, ServerHost, Node, ParentNode, Owner, Access).'''

    create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) -> LOwner = jlib:short_prepd_jid(Owner), {User, Server, _Resource} = LOwner, @@ -215,35 +215,36 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) -> end, {result, Allowed}. -%% @spec (Host, Node, Owner) -> +%% @spec (NodeId, Owner) -> %% {result, Result} | exit -%% Host = mod_pubsub:host() -%% Node = mod_pubsub:pubsubNode() +%% NodeId = mod_pubsub:pubsubNodeId() %% Owner = mod_pubsub:jid() %% @doc

    -create_node(Host, Node, Owner) -> +create_node(NodeId, Owner) -> OwnerKey = jlib:short_prepd_bare_jid(Owner), - set_state(#pubsub_state{stateid = {OwnerKey, {Host, Node}}, affiliation = owner}), + set_state(#pubsub_state{stateid = {OwnerKey, NodeId}, affiliation = owner}), {result, {default, broadcast}}. -%% @spec (Host, Removed) -> ok -%% Host = mod_pubsub:host() +%% @spec (Removed) -> ok %% Removed = [mod_pubsub:pubsubNode()] %% @doc

    purge items of deleted nodes after effective deletion.

    -delete_node(Host, Removed) -> - lists:foreach( - fun(Node) -> - lists:foreach( - fun(#pubsub_state{stateid = StateId, items = Items}) -> - del_items(Host, Node, Items), - del_state(StateId) - end, - mnesia:match_object( - #pubsub_state{stateid = {'_', {Host, Node}}, _ = '_'})) - end, Removed), - {result, {default, broadcast, Removed}}. +delete_node(Removed) -> + Tr = fun(#pubsub_state{stateid = {J, _}, subscription = S}) -> + {J, S} + end, + Reply = lists:map( + fun(#pubsub_node{id = NodeId} = PubsubNode) -> + {result, States} = get_states(NodeId), + lists:foreach( + fun(#pubsub_state{stateid = {LJID, _}, items = Items}) -> + del_items(NodeId, Items), + del_state(NodeId, LJID) + end, States), + {PubsubNode, lists:map(Tr, States)} + end, Removed), + {result, {default, broadcast, Reply}}. -%% @spec (Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> +%% @spec (NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> %% {error, Reason} | {result, Result} %% @doc

    Accepts or rejects subcription requests on a PubSub node.

    %%

    The mechanism works as follow: @@ -276,17 +277,18 @@ delete_node(Host, Removed) -> %% to completly disable persistance. %%

    %%

    In the default plugin module, the record is unchanged.

    -subscribe_node(Host, Node, Sender, Subscriber, AccessModel, +subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> SubKey = jlib:short_prepd_jid(Subscriber), GenKey = jlib:short_prepd_bare_jid(SubKey), Authorized = (jlib:short_prepd_bare_jid(Sender) == GenKey), - GenState = get_state(Host, Node, GenKey), + GenState = get_state(NodeId, GenKey), SubState = case SubKey of GenKey -> GenState; - _ -> get_state(Host, Node, SubKey) + _ -> get_state(NodeId, SubKey) end, Affiliation = GenState#pubsub_state.affiliation, + Subscription = SubState#pubsub_state.subscription, Whitelisted = lists:member(Affiliation, [member, publisher, owner]), if not Authorized -> @@ -295,7 +297,7 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel, Affiliation == outcast -> %% Requesting entity is blocked {error, 'forbidden'}; - SubState#pubsub_state.subscription == pending -> + Subscription == pending -> %% Requesting entity has pending subscription {error, ?ERR_EXTENDED('not-authorized', "pending-subscription")}; (AccessModel == presence) and (not PresenceSubscription) -> @@ -338,23 +340,22 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel, end end. -%% @spec (Host, Node, Sender, Subscriber, SubID) -> +%% @spec (NodeId, Sender, Subscriber, SubID) -> %% {error, Reason} | {result, []} -%% Host = mod_pubsub:host() -%% Node = mod_pubsub:pubsubNode() +%% NodeId = mod_pubsub:pubsubNodeId() %% Sender = mod_pubsub:jid() %% Subscriber = mod_pubsub:jid() %% SubID = string() %% Reason = mod_pubsub:stanzaError() %% @doc

    Unsubscribe the Subscriber from the Node.

    -unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> +unsubscribe_node(NodeId, Sender, Subscriber, _SubId) -> SubKey = jlib:short_prepd_jid(Subscriber), GenKey = jlib:short_prepd_bare_jid(SubKey), Authorized = (jlib:short_prepd_bare_jid(Sender) == GenKey), - GenState = get_state(Host, Node, GenKey), + GenState = get_state(NodeId, GenKey), SubState = case SubKey of GenKey -> GenState; - _ -> get_state(Host, Node, SubKey) + _ -> get_state(NodeId, SubKey) end, if %% Requesting entity is prohibited from unsubscribing entity @@ -371,17 +372,16 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> {error, ?ERR_EXTENDED('unexpected-request', "not-subscribed")}; %% Was just subscriber, remove the record SubState#pubsub_state.affiliation == none -> - del_state(SubState#pubsub_state.stateid), + del_state(NodeId, SubKey), {result, default}; true -> set_state(SubState#pubsub_state{subscription = none}), {result, default} end. -%% @spec (Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) -> +%% @spec (NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload) -> %% {true, PubsubItem} | {result, Reply} -%% Host = mod_pubsub:host() -%% Node = mod_pubsub:pubsubNode() +%% NodeId = mod_pubsub:pubsubNodeId() %% Publisher = mod_pubsub:jid() %% PublishModel = atom() %% MaxItems = integer() @@ -417,13 +417,13 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> %% to completly disable persistance. %%

    %%

    In the default plugin module, the record is unchanged.

    -publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) -> +publish_item(NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload) -> SubKey = jlib:short_prepd_jid(Publisher), GenKey = jlib:short_prepd_bare_jid(SubKey), - GenState = get_state(Host, Node, GenKey), + GenState = get_state(NodeId, GenKey), SubState = case SubKey of GenKey -> GenState; - _ -> get_state(Host, Node, SubKey) + _ -> get_state(NodeId, SubKey) end, Affiliation = GenState#pubsub_state.affiliation, Subscription = SubState#pubsub_state.subscription, @@ -436,31 +436,31 @@ publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) -> %% Entity does not have sufficient privileges to publish to node {error, 'forbidden'}; true -> - PubId = {SubKey, now()}, %% TODO, uses {now(),PublisherKey} for sorting (EJAB-824) %% TODO: check creation, presence, roster - Item = case get_item(Host, Node, ItemId) of + if MaxItems > 0 -> + PubId = {now(), SubKey}, + Item = case get_item(NodeId, ItemId) of {result, OldItem} -> OldItem#pubsub_item{modification = PubId, payload = Payload}; _ -> - #pubsub_item{itemid = {ItemId, {Host, Node}}, - creation = {GenKey, now()}, + #pubsub_item{itemid = {ItemId, NodeId}, + creation = {now(), GenKey}, modification = PubId, payload = Payload} end, - Items = [ItemId | GenState#pubsub_state.items--[ItemId]], - {result, {NI, OI}} = remove_extra_items( - Host, Node, MaxItems, Items), - if MaxItems > 0 -> set_item(Item); - true -> ok - end, - set_state(GenState#pubsub_state{items = NI}), - {result, {default, broadcast, OI}} + Items = [ItemId | GenState#pubsub_state.items--[ItemId]], + {result, {NI, OI}} = remove_extra_items(NodeId, MaxItems, Items), + set_item(Item), + set_state(GenState#pubsub_state{items = NI}), + {result, {default, broadcast, OI}}; + true -> + {result, {default, broadcast, []}} + end end. -%% @spec (Host, Node, MaxItems, ItemIds) -> {NewItemIds,OldItemIds} -%% Host = mod_pubsub:host() -%% Node = mod_pubsub:pubsubNode() +%% @spec (NodeId, MaxItems, ItemIds) -> {NewItemIds,OldItemIds} +%% NodeId = mod_pubsub:pubsubNodeId() %% MaxItems = integer() | unlimited %% ItemIds = [ItemId::string()] %% NewItemIds = [ItemId::string()] @@ -472,34 +472,33 @@ publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) -> %% rules can be used.

    %%

    If another PubSub plugin wants to delegate the item removal (and if the %% plugin is using the default pubsub storage), it can implements this function like this: -%% ```remove_extra_items(Host, Node, MaxItems, ItemIds) -> -%% node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).'''

    -remove_extra_items(_Host, _Node, unlimited, ItemIds) -> +%% ```remove_extra_items(NodeId, MaxItems, ItemIds) -> +%% node_default:remove_extra_items(NodeId, MaxItems, ItemIds).'''

    +remove_extra_items(_NodeId, unlimited, ItemIds) -> {result, {ItemIds, []}}; -remove_extra_items(Host, Node, MaxItems, ItemIds) -> +remove_extra_items(NodeId, MaxItems, ItemIds) -> NewItems = lists:sublist(ItemIds, MaxItems), OldItems = lists:nthtail(length(NewItems), ItemIds), %% Remove extra items: - del_items(Host, Node, OldItems), + del_items(NodeId, OldItems), %% Return the new items list: {result, {NewItems, OldItems}}. -%% @spec (Host, Node, JID, ItemId) -> +%% @spec (NodeId, JID, ItemId) -> %% {error, Reason::stanzaError()} | %% {result, []} -%% Host = mod_pubsub:host() -%% Node = mod_pubsub:pubsubNode() +%% NodeId = mod_pubsub:pubsubNodeId() %% JID = mod_pubsub:jid() %% ItemId = string() %% @doc

    Triggers item deletion.

    %%

    Default plugin: The user performing the deletion must be the node owner %% or a publisher.

    -delete_item(Host, Node, Publisher, ItemId) -> +delete_item(NodeId, Publisher, ItemId) -> GenKey = jlib:short_prepd_bare_jid(Publisher), - GenState = get_state(Host, Node, GenKey), + GenState = get_state(NodeId, GenKey), #pubsub_state{affiliation = Affiliation, items = Items} = GenState, Allowed = (Affiliation == publisher) orelse (Affiliation == owner) - orelse case get_item(Host, Node, ItemId) of + orelse case get_item(NodeId, ItemId) of {result, #pubsub_item{creation = {GenKey, _}}} -> true; _ -> false end, @@ -508,30 +507,30 @@ delete_item(Host, Node, Publisher, ItemId) -> %% Requesting entity does not have sufficient privileges {error, 'forbidden'}; true -> - case get_item(Host, Node, ItemId) of - {result, _} -> - del_item(Host, Node, ItemId), + case lists:member(ItemId, Items) of + true -> + del_item(NodeId, ItemId), NewItems = lists:delete(ItemId, Items), set_state(GenState#pubsub_state{items = NewItems}), {result, {default, broadcast}}; - _ -> + false -> %% Non-existent node or item {error, 'item-not-found'} end end. -%% @spec (Host, Node, Owner) -> +%% @spec (NodeId, Owner) -> %% {error, Reason::stanzaError()} | %% {result, {default, broadcast}} -%% Host = mod_pubsub:host() -%% Node = mod_pubsub:pubsubNode() +%% NodeId = mod_pubsub:pubsubNodeId() %% Owner = mod_pubsub:jid() -purge_node(Host, Node, Owner) -> +purge_node(NodeId, Owner) -> GenKey = jlib:short_prepd_bare_jid(Owner), - GenState = get_state(Host, Node, GenKey), + GenState = get_state(NodeId, GenKey), case GenState of #pubsub_state{items = Items, affiliation = owner} -> - del_items(Host, Node, Items), + del_items(NodeId, Items), + set_state(GenState#pubsub_state{items = []}), {result, {default, broadcast}}; _ -> %% Entity is not owner @@ -548,42 +547,40 @@ purge_node(Host, Node, Owner) -> %% the default PubSub module. Otherwise, it should return its own affiliation, %% that will be added to the affiliation stored in the main %% pubsub_state table.

    -get_entity_affiliations(Host, Owner) -> +get_entity_affiliations(_Host, Owner) -> GenKey = jlib:short_prepd_bare_jid(Owner), States = mnesia:match_object( - #pubsub_state{stateid = {GenKey, {Host, '_'}}, _ = '_'}), - Tr = fun(#pubsub_state{stateid = {_, {_, N}}, affiliation = A}) -> + #pubsub_state{stateid = {GenKey, '_'}, _ = '_'}), + Tr = fun(#pubsub_state{stateid = {_, N}, affiliation = A}) -> {N, A} end, {result, lists:map(Tr, States)}. -get_node_affiliations(Host, Node) -> - {result, States} = get_states(Host, Node), +get_node_affiliations(NodeId) -> + {result, States} = get_states(NodeId), Tr = fun(#pubsub_state{stateid = {J, {_, _}}, affiliation = A}) -> {J, A} end, {result, lists:map(Tr, States)}. -get_affiliation(Host, Node, Owner) -> +get_affiliation(NodeId, Owner) -> GenKey = jlib:short_prepd_bare_jid(Owner), - GenState = get_state(Host, Node, GenKey), + GenState = get_state(NodeId, GenKey), {result, GenState#pubsub_state.affiliation}. -set_affiliation(Host, Node, Owner, Affiliation) -> +set_affiliation(NodeId, Owner, Affiliation) -> GenKey = jlib:short_prepd_bare_jid(Owner), - GenState = get_state(Host, Node, GenKey), + GenState = get_state(NodeId, GenKey), case {Affiliation, GenState#pubsub_state.subscription} of {none, none} -> - del_state(GenState#pubsub_state.stateid); + del_state(NodeId, GenKey); _ -> set_state(GenState#pubsub_state{affiliation = Affiliation}) - end, - ok. + end. %% @spec (Host, Owner) -> [{Node,Subscription}] %% Host = host() %% Owner = mod_pubsub:jid() -%% Node = mod_pubsub:pubsubNode() %% @doc

    Return the current subscriptions for the given user

    %%

    The default module reads subscriptions in the main Mnesia %% pubsub_state table. If a plugin stores its data in the same @@ -591,49 +588,47 @@ set_affiliation(Host, Node, Owner, Affiliation) -> %% the default PubSub module. Otherwise, it should return its own affiliation, %% that will be added to the affiliation stored in the main %% pubsub_state table.

    -get_entity_subscriptions(Host, Owner) -> +get_entity_subscriptions(_Host, Owner) -> {U, D, _} = SubKey = jlib:short_prepd_jid(Owner), GenKey = jlib:short_prepd_bare_jid(SubKey), States = case SubKey of GenKey -> mnesia:match_object( - #pubsub_state{stateid = {{U, D, '_'}, {Host, '_'}}, _ = '_'}); + #pubsub_state{stateid = {{U, D, '_'}, '_'}, _ = '_'}); _ -> mnesia:match_object( - #pubsub_state{stateid = {GenKey, {Host, '_'}}, _ = '_'}) + #pubsub_state{stateid = {GenKey, '_'}, _ = '_'}) ++ mnesia:match_object( - #pubsub_state{stateid = {SubKey, {Host, '_'}}, _ = '_'}) + #pubsub_state{stateid = {SubKey, '_'}, _ = '_'}) end, - Tr = fun(#pubsub_state{stateid = {J, {_, N}}, subscription = S}) -> + Tr = fun(#pubsub_state{stateid = {J, N}, subscription = S}) -> {N, S, J} end, {result, lists:map(Tr, States)}. -get_node_subscriptions(Host, Node) -> - {result, States} = get_states(Host, Node), - Tr = fun(#pubsub_state{stateid = {J, {_, _}}, subscription = S}) -> +get_node_subscriptions(NodeId) -> + {result, States} = get_states(NodeId), + Tr = fun(#pubsub_state{stateid = {J, _}, subscription = S}) -> {J, S} end, {result, lists:map(Tr, States)}. -get_subscription(Host, Node, Owner) -> +get_subscription(NodeId, Owner) -> SubKey = jlib:short_prepd_jid(Owner), - SubState = get_state(Host, Node, SubKey), + SubState = get_state(NodeId, SubKey), {result, SubState#pubsub_state.subscription}. -set_subscription(Host, Node, Owner, Subscription) -> +set_subscription(NodeId, Owner, Subscription) -> SubKey = jlib:short_prepd_jid(Owner), - SubState = get_state(Host, Node, SubKey), + SubState = get_state(NodeId, SubKey), case {Subscription, SubState#pubsub_state.affiliation} of {none, none} -> - del_state(SubState#pubsub_state.stateid); + del_state(NodeId, SubKey); _ -> set_state(SubState#pubsub_state{subscription = Subscription}) end, ok. -%% @spec (Host, Node) -> [States] | [] -%% Host = mod_pubsub:host() -%% Node = mod_pubsub:pubsubNode() -%% Item = mod_pubsub:pubsubItems() +%% @spec (NodeId) -> [States] | [] +%% NodeId = mod_pubsub:pubsubNodeId() %% @doc Returns the list of stored states for a given node. %%

    For the default PubSub module, states are stored in Mnesia database.

    %%

    We can consider that the pubsub_state table have been created by the main @@ -642,21 +637,20 @@ set_subscription(Host, Node, Owner, Subscription) -> %% relational database).

    %%

    If a PubSub plugin wants to delegate the states storage to the default node, %% they can implement this function like this: -%% ```get_states(Host, Node) -> -%% node_default:get_states(Host, Node).'''

    -get_states(Host, Node) -> +%% ```get_states(NodeId) -> +%% node_default:get_states(NodeId).'''

    +get_states(NodeId) -> States = mnesia:match_object( - #pubsub_state{stateid = {'_', {Host, Node}}, _ = '_'}), + #pubsub_state{stateid = {'_', NodeId}, _ = '_'}), {result, States}. -%% @spec (JID, Host, Node) -> [State] | [] -%% Host = mod_pubsub:host() -%% Node = mod_pubsub:pubsubNode() +%% @spec (NodeId, JID) -> [State] | [] +%% NodeId = mod_pubsub:pubsubNodeId() %% JID = mod_pubsub:jid() %% State = mod_pubsub:pubsubItems() %% @doc

    Returns a state (one state list), given its reference.

    -get_state(Host, Node, JID) -> - StateId = {JID, {Host, Node}}, +get_state(NodeId, JID) -> + StateId = {JID, NodeId}, case mnesia:read({pubsub_state, StateId}) of [State] when is_record(State, pubsub_state) -> State; _ -> #pubsub_state{stateid=StateId} @@ -673,12 +667,11 @@ set_state(_) -> %% @spec (StateId) -> ok | {error, Reason::stanzaError()} %% StateId = mod_pubsub:pubsubStateId() %% @doc

    Delete a state from database.

    -del_state(StateId) -> - mnesia:delete({pubsub_state, StateId}). +del_state(NodeId, JID) -> + mnesia:delete({pubsub_state, {JID, NodeId}}). -%% @spec (Host, Node, From) -> [Items] | [] -%% Host = mod_pubsub:host() -%% Node = mod_pubsub:pubsubNode() +%% @spec (NodeId, From) -> [Items] | [] +%% NodeId = mod_pubsub:pubsubNodeId() %% Items = mod_pubsub:pubsubItems() %% @doc Returns the list of stored items for a given node. %%

    For the default PubSub module, items are stored in Mnesia database.

    @@ -688,15 +681,15 @@ del_state(StateId) -> %% relational database), or they can even decide not to persist any items.

    %%

    If a PubSub plugin wants to delegate the item storage to the default node, %% they can implement this function like this: -%% ```get_items(Host, Node, From) -> -%% node_default:get_items(Host, Node, From).'''

    -get_items(Host, Node, _From) -> +%% ```get_items(NodeId, From) -> +%% node_default:get_items(NodeId, From).'''

    +get_items(NodeId, _From) -> Items = mnesia:match_object( - #pubsub_item{itemid = {'_', {Host, Node}}, _ = '_'}), + #pubsub_item{itemid = {'_', NodeId}, _ = '_'}), {result, Items}. -get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> +get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> GenKey = jlib:short_prepd_bare_jid(JID), - GenState = get_state(Host, Node, GenKey), + GenState = get_state(NodeId, GenKey), Affiliation = GenState#pubsub_state.affiliation, Subscription = GenState#pubsub_state.subscription, Whitelisted = can_fetch_item(Affiliation, Subscription), @@ -726,25 +719,24 @@ get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubI %% % Payment is required for a subscription %% {error, ?ERR_PAYMENT_REQUIRED}; true -> - get_items(Host, Node, JID) + get_items(NodeId, JID) end. -%% @spec (Host, Node, ItemId) -> [Item] | [] -%% Host = mod_pubsub:host() -%% Node = mod_pubsub:pubsubNode() +%% @spec (NodeId, ItemId) -> [Item] | [] +%% NodeId = mod_pubsub:pubsubNodeId() %% ItemId = string() %% Item = mod_pubsub:pubsubItems() %% @doc

    Returns an item (one item list), given its reference.

    -get_item(Host, Node, ItemId) -> - case mnesia:read({pubsub_item, {ItemId, {Host, Node}}}) of +get_item(NodeId, ItemId) -> + case mnesia:read({pubsub_item, {ItemId, NodeId}}) of [Item] when is_record(Item, pubsub_item) -> {result, Item}; _ -> {error, 'item-not-found'} end. -get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> +get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> GenKey = jlib:short_prepd_bare_jid(JID), - GenState = get_state(Host, Node, GenKey), + GenState = get_state(NodeId, GenKey), Affiliation = GenState#pubsub_state.affiliation, Subscription = GenState#pubsub_state.subscription, Whitelisted = can_fetch_item(Affiliation, Subscription), @@ -774,7 +766,7 @@ get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup %% % Payment is required for a subscription %% {error, ?ERR_PAYMENT_REQUIRED}; true -> - get_item(Host, Node, ItemId) + get_item(NodeId, ItemId) end. %% @spec (Item) -> ok | {error, Reason::stanzaError()} @@ -785,21 +777,20 @@ set_item(Item) when is_record(Item, pubsub_item) -> set_item(_) -> {error, 'internal-server-error'}. -%% @spec (Host, Node, ItemId) -> ok | {error, Reason::stanzaError()} -%% Host = mod_pubsub:host() -%% Node = mod_pubsub:pubsubNode() +%% @spec (NodeId, ItemId) -> ok | {error, Reason::stanzaError()} +%% NodeId = mod_pubsub:pubsubNodeId() %% ItemId = string() %% @doc

    Delete an item from database.

    -del_item(Host, Node, ItemId) -> - mnesia:delete({pubsub_item, {ItemId, {Host, Node}}}). -del_items(Host, Node, ItemIds) -> +del_item(NodeId, ItemId) -> + mnesia:delete({pubsub_item, {ItemId, NodeId}}). +del_items(NodeId, ItemIds) -> lists:foreach(fun(ItemId) -> - del_item(Host, Node, ItemId) + del_item(NodeId, ItemId) end, ItemIds). %% @doc

    Return the name of the node if known: Default is to return %% node id.

    -get_item_name(_Host, _Node, Id) -> +get_item_name(_host, _Node, Id) -> Id. %% @spec (Affiliation, Subscription) -> true | false diff --git a/src/mod_pubsub/node_dispatch.erl b/src/mod_pubsub/node_dispatch.erl index 2d9e245e9..d5b379844 100644 --- a/src/mod_pubsub/node_dispatch.erl +++ b/src/mod_pubsub/node_dispatch.erl @@ -42,29 +42,29 @@ -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, - create_node/3, - delete_node/2, - purge_node/3, - subscribe_node/8, - unsubscribe_node/5, - publish_item/7, - delete_item/4, - remove_extra_items/4, + create_node/2, + delete_node/1, + purge_node/2, + subscribe_node/7, + unsubscribe_node/4, + publish_item/6, + delete_item/3, + remove_extra_items/3, get_entity_affiliations/2, - get_node_affiliations/2, - get_affiliation/3, - set_affiliation/4, + get_node_affiliations/1, + get_affiliation/2, + set_affiliation/3, get_entity_subscriptions/2, - get_node_subscriptions/2, - get_subscription/3, - set_subscription/4, - get_states/2, - get_state/3, + get_node_subscriptions/1, + get_subscription/2, + set_subscription/3, + get_states/1, + get_state/2, set_state/1, - get_items/7, - get_items/3, - get_item/8, - get_item/3, + get_items/6, + get_items/2, + get_item/7, + get_item/2, set_item/1, get_item_name/3 ]). @@ -112,79 +112,81 @@ features() -> create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). -create_node(Host, Node, Owner) -> - node_default:create_node(Host, Node, Owner). +create_node(NodeId, Owner) -> + node_default:create_node(NodeId, Owner). -delete_node(Host, Removed) -> - node_default:delete_node(Host, Removed). +delete_node(Removed) -> + node_default:delete_node(Removed). -subscribe_node(_Host, _Node, _Sender, _Subscriber, _AccessModel, +subscribe_node(_NodeId, _Sender, _Subscriber, _AccessModel, _SendLast, _PresenceSubscription, _RosterGroup) -> {error, 'forbidden'}. -unsubscribe_node(_Host, _Node, _Sender, _Subscriber, _SubID) -> +unsubscribe_node(_NodeId, _Sender, _Subscriber, _SubID) -> {error, 'forbidden'}. -publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) -> +publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> lists:foreach(fun(SubNode) -> node_default:publish_item( - Host, SubNode, Publisher, Model, + SubNode#pubsub_node.id, Publisher, Model, MaxItems, ItemId, Payload) - end, nodetree_default:get_subnodes(Host, Node, Publisher)). + end, nodetree_default:get_subnodes(NodeId, Publisher)). -remove_extra_items(_Host, _Node, _MaxItems, ItemIds) -> +remove_extra_items(_NodeId, _MaxItems, ItemIds) -> {result, {ItemIds, []}}. -delete_item(_Host, _Node, _JID, _ItemId) -> +delete_item(_NodeId, _JID, _ItemId) -> {error, 'item-not-found'}. -purge_node(_Host, _Node, _Owner) -> +purge_node(_NodeId, _Owner) -> {error, 'forbidden'}. get_entity_affiliations(_Host, _Owner) -> {result, []}. -get_node_affiliations(_Host, _Node) -> +get_node_affiliations(_NodeId) -> {result, []}. -get_affiliation(_Host, _Node, _Owner) -> +get_affiliation(_NodeId, _Owner) -> {result, []}. -set_affiliation(Host, Node, Owner, Affiliation) -> - node_default:set_affiliation(Host, Node, Owner, Affiliation). +set_affiliation(NodeId, Owner, Affiliation) -> + node_default:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(_Host, _Owner) -> {result, []}. -get_node_subscriptions(_Host, _Node) -> +get_node_subscriptions(NodeId) -> + %% note: get_node_subscriptions is used for broadcasting + %% DO NOT REMOVE + node_default:get_node_subscriptions(NodeId). + +get_subscription(_NodeId, _Owner) -> {result, []}. -get_subscription(_Host, _Node, _Owner) -> - {result, []}. +set_subscription(NodeId, Owner, Subscription) -> + node_default:set_subscription(NodeId, Owner, Subscription). -set_subscription(Host, Node, Owner, Subscription) -> - node_default:set_subscription(Host, Node, Owner, Subscription). +get_states(NodeId) -> + node_default:get_states(NodeId). -get_states(Host, Node) -> - node_default:get_states(Host, Node). - -get_state(Host, Node, JID) -> - node_default:get_state(Host, Node, JID). +get_state(NodeId, JID) -> + node_default:get_state(NodeId, JID). set_state(State) -> node_default:set_state(State). -get_items(Host, Node, From) -> - node_default:get_items(Host, Node, From). +get_items(NodeId, From) -> + node_default:get_items(NodeId, From). -get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). -get_item(Host, Node, ItemId) -> - node_default:get_item(Host, Node, ItemId). +get_item(NodeId, ItemId) -> + node_default:get_item(NodeId, ItemId). -get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). set_item(Item) -> node_default:set_item(Item). diff --git a/src/mod_pubsub/node_flat.erl b/src/mod_pubsub/node_flat.erl index e9e983aa8..8fb33e447 100644 --- a/src/mod_pubsub/node_flat.erl +++ b/src/mod_pubsub/node_flat.erl @@ -35,29 +35,29 @@ -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, - create_node/3, - delete_node/2, - purge_node/3, - subscribe_node/8, - unsubscribe_node/5, - publish_item/7, - delete_item/4, - remove_extra_items/4, + create_node/2, + delete_node/1, + purge_node/2, + subscribe_node/7, + unsubscribe_node/4, + publish_item/6, + delete_item/3, + remove_extra_items/3, get_entity_affiliations/2, - get_node_affiliations/2, - get_affiliation/3, - set_affiliation/4, + get_node_affiliations/1, + get_affiliation/2, + set_affiliation/3, get_entity_subscriptions/2, - get_node_subscriptions/2, - get_subscription/3, - set_subscription/4, - get_states/2, - get_state/3, + get_node_subscriptions/1, + get_subscription/2, + set_subscription/3, + get_states/1, + get_state/2, set_state/1, - get_items/7, - get_items/3, - get_item/8, - get_item/3, + get_items/6, + get_items/2, + get_item/7, + get_item/2, set_item/1, get_item_name/3 ]). @@ -103,74 +103,74 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> end, {result, Allowed}. -create_node(Host, Node, Owner) -> - node_default:create_node(Host, Node, Owner). +create_node(NodeId, Owner) -> + node_default:create_node(NodeId, Owner). -delete_node(Host, Removed) -> - node_default:delete_node(Host, Removed). +delete_node(Removed) -> + node_default:delete_node(Removed). -subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). +subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> + node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). -unsubscribe_node(Host, Node, Sender, Subscriber, SubID) -> - node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID). +unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> + node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID). -publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) -> - node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload). +publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> + node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). -remove_extra_items(Host, Node, MaxItems, ItemIds) -> - node_default:remove_extra_items(Host, Node, MaxItems, ItemIds). +remove_extra_items(NodeId, MaxItems, ItemIds) -> + node_default:remove_extra_items(NodeId, MaxItems, ItemIds). -delete_item(Host, Node, JID, ItemId) -> - node_default:delete_item(Host, Node, JID, ItemId). +delete_item(NodeId, JID, ItemId) -> + node_default:delete_item(NodeId, JID, ItemId). -purge_node(Host, Node, Owner) -> - node_default:purge_node(Host, Node, Owner). +purge_node(NodeId, Owner) -> + node_default:purge_node(NodeId, Owner). get_entity_affiliations(Host, Owner) -> node_default:get_entity_affiliations(Host, Owner). -get_node_affiliations(Host, Node) -> - node_default:get_node_affiliations(Host, Node). +get_node_affiliations(NodeId) -> + node_default:get_node_affiliations(NodeId). -get_affiliation(Host, Node, Owner) -> - node_default:get_affiliation(Host, Node, Owner). +get_affiliation(NodeId, Owner) -> + node_default:get_affiliation(NodeId, Owner). -set_affiliation(Host, Node, Owner, Affiliation) -> - node_default:set_affiliation(Host, Node, Owner, Affiliation). +set_affiliation(NodeId, Owner, Affiliation) -> + node_default:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(Host, Owner) -> node_default:get_entity_subscriptions(Host, Owner). -get_node_subscriptions(Host, Node) -> - node_default:get_node_subscriptions(Host, Node). +get_node_subscriptions(NodeId) -> + node_default:get_node_subscriptions(NodeId). -get_subscription(Host, Node, Owner) -> - node_default:get_subscription(Host, Node, Owner). +get_subscription(NodeId, Owner) -> + node_default:get_subscription(NodeId, Owner). -set_subscription(Host, Node, Owner, Subscription) -> - node_default:set_subscription(Host, Node, Owner, Subscription). +set_subscription(NodeId, Owner, Subscription) -> + node_default:set_subscription(NodeId, Owner, Subscription). -get_states(Host, Node) -> - node_default:get_states(Host, Node). +get_states(NodeId) -> + node_default:get_states(NodeId). -get_state(Host, Node, JID) -> - node_default:get_state(Host, Node, JID). +get_state(NodeId, JID) -> + node_default:get_state(NodeId, JID). set_state(State) -> node_default:set_state(State). -get_items(Host, Node, From) -> - node_default:get_items(Host, Node, From). +get_items(NodeId, From) -> + node_default:get_items(NodeId, From). -get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). -get_item(Host, Node, ItemId) -> - node_default:get_item(Host, Node, ItemId). +get_item(NodeId, ItemId) -> + node_default:get_item(NodeId, ItemId). -get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). set_item(Item) -> node_default:set_item(Item). diff --git a/src/mod_pubsub/node_mb.erl b/src/mod_pubsub/node_mb.erl index 90a5cdad2..83413cd39 100644 --- a/src/mod_pubsub/node_mb.erl +++ b/src/mod_pubsub/node_mb.erl @@ -47,29 +47,29 @@ -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, - create_node/3, - delete_node/2, - purge_node/3, - subscribe_node/8, - unsubscribe_node/5, - publish_item/7, - delete_item/4, - remove_extra_items/4, + create_node/2, + delete_node/1, + purge_node/2, + subscribe_node/7, + unsubscribe_node/4, + publish_item/6, + delete_item/3, + remove_extra_items/3, get_entity_affiliations/2, - get_node_affiliations/2, - get_affiliation/3, - set_affiliation/4, + get_node_affiliations/1, + get_affiliation/2, + set_affiliation/3, get_entity_subscriptions/2, - get_node_subscriptions/2, - get_subscription/3, - set_subscription/4, - get_states/2, - get_state/3, + get_node_subscriptions/1, + get_subscription/2, + set_subscription/3, + get_states/1, + get_state/2, set_state/1, - get_items/7, - get_items/3, - get_item/8, - get_item/3, + get_items/6, + get_items/2, + get_item/7, + get_item/2, set_item/1, get_item_name/3 ]). @@ -120,77 +120,77 @@ features() -> create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> node_pep:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). -create_node(Host, Node, Owner) -> - node_pep:create_node(Host, Node, Owner). +create_node(NodeId, Owner) -> + node_pep:create_node(NodeId, Owner). -delete_node(Host, Removed) -> - node_pep:delete_node(Host, Removed). +delete_node(Removed) -> + node_pep:delete_node(Removed). -subscribe_node(Host, Node, Sender, Subscriber, AccessModel, +subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> node_pep:subscribe_node( - Host, Node, Sender, Subscriber, AccessModel, SendLast, + NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). -unsubscribe_node(Host, Node, Sender, Subscriber, SubID) -> - node_pep:unsubscribe_node(Host, Node, Sender, Subscriber, SubID). +unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> + node_pep:unsubscribe_node(NodeId, Sender, Subscriber, SubID). -publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) -> - node_pep:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload). +publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> + node_pep:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). -remove_extra_items(Host, Node, MaxItems, ItemIds) -> - node_pep:remove_extra_items(Host, Node, MaxItems, ItemIds). +remove_extra_items(NodeId, MaxItems, ItemIds) -> + node_pep:remove_extra_items(NodeId, MaxItems, ItemIds). -delete_item(Host, Node, JID, ItemId) -> - node_pep:delete_item(Host, Node, JID, ItemId). +delete_item(NodeId, JID, ItemId) -> + node_pep:delete_item(NodeId, JID, ItemId). -purge_node(Host, Node, Owner) -> - node_pep:purge_node(Host, Node, Owner). +purge_node(NodeId, Owner) -> + node_pep:purge_node(NodeId, Owner). get_entity_affiliations(Host, Owner) -> node_pep:get_entity_affiliations(Host, Owner). -get_node_affiliations(Host, Node) -> - node_pep:get_node_affiliations(Host, Node). +get_node_affiliations(NodeId) -> + node_pep:get_node_affiliations(NodeId). -get_affiliation(Host, Node, Owner) -> - node_pep:get_affiliation(Host, Node, Owner). +get_affiliation(NodeId, Owner) -> + node_pep:get_affiliation(NodeId, Owner). -set_affiliation(Host, Node, Owner, Affiliation) -> - node_pep:set_affiliation(Host, Node, Owner, Affiliation). +set_affiliation(NodeId, Owner, Affiliation) -> + node_pep:set_affiliation(NodeId, Owner, Affiliation). -get_entity_subscriptions(Host,Owner) -> +get_entity_subscriptions(Host, Owner) -> node_pep:get_entity_subscriptions(Host, Owner). -get_node_subscriptions(Host, Node) -> - node_pep:get_node_subscriptions(Host, Node). +get_node_subscriptions(NodeId) -> + node_pep:get_node_subscriptions(NodeId). -get_subscription(Host,Node,Owner) -> - node_pep:get_subscription(Host,Node,Owner). +get_subscription(NodeId, Owner) -> + node_pep:get_subscription(NodeId, Owner). -set_subscription(Host, Node, Owner, Subscription) -> - node_pep:set_subscription(Host, Node, Owner, Subscription). +set_subscription(NodeId, Owner, Subscription) -> + node_pep:set_subscription(NodeId, Owner, Subscription). -get_states(Host, Node) -> - node_pep:get_states(Host, Node). +get_states(NodeId) -> + node_pep:get_states(NodeId). -get_state(Host, Node, JID) -> - node_pep:get_state(Host, Node, JID). +get_state(NodeId, JID) -> + node_pep:get_state(NodeId, JID). set_state(State) -> node_pep:set_state(State). -get_items(Host, Node, From) -> - node_pep:get_items(Host, Node, From). +get_items(NodeId, From) -> + node_pep:get_items(NodeId, From). -get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_pep:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_pep:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). -get_item(Host, Node, ItemId) -> - node_pep:get_item(Host, Node, ItemId). +get_item(NodeId, ItemId) -> + node_pep:get_item(NodeId, ItemId). -get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_pep:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_pep:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). set_item(Item) -> node_pep:set_item(Item). diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index bf13d3520..6c3f83d21 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -40,29 +40,29 @@ -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, - create_node/3, - delete_node/2, - purge_node/3, - subscribe_node/8, - unsubscribe_node/5, - publish_item/7, - delete_item/4, - remove_extra_items/4, + create_node/2, + delete_node/1, + purge_node/2, + subscribe_node/7, + unsubscribe_node/4, + publish_item/6, + delete_item/3, + remove_extra_items/3, get_entity_affiliations/2, - get_node_affiliations/2, - get_affiliation/3, - set_affiliation/4, + get_node_affiliations/1, + get_affiliation/2, + set_affiliation/3, get_entity_subscriptions/2, - get_node_subscriptions/2, - get_subscription/3, - set_subscription/4, - get_states/2, - get_state/3, + get_node_subscriptions/1, + get_subscription/2, + set_subscription/3, + get_states/1, + get_state/2, set_state/1, - get_items/7, - get_items/3, - get_item/8, - get_item/3, + get_items/6, + get_items/2, + get_item/7, + get_item/2, set_item/1, get_item_name/3 ]). @@ -133,92 +133,92 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> end, {result, Allowed}. -create_node(Host, Node, Owner) -> - case node_default:create_node(Host, Node, Owner) of +create_node(NodeId, Owner) -> + case node_default:create_node(NodeId, Owner) of {result, _} -> {result, []}; Error -> Error end. -delete_node(Host, Removed) -> - case node_default:delete_node(Host, Removed) of +delete_node(Removed) -> + case node_default:delete_node(Removed) of {result, {_, _, Removed}} -> {result, {[], Removed}}; Error -> Error end. -subscribe_node(Host, Node, Sender, Subscriber, AccessModel, +subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> node_default:subscribe_node( - Host, Node, Sender, Subscriber, AccessModel, SendLast, + NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). -unsubscribe_node(Host, Node, Sender, Subscriber, SubID) -> - case node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID) of +unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> + case node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID) of {error, Error} -> {error, Error}; {result, _} -> {result, []} end. -publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) -> - node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload). +publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> + node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). -remove_extra_items(Host, Node, MaxItems, ItemIds) -> - node_default:remove_extra_items(Host, Node, MaxItems, ItemIds). +remove_extra_items(NodeId, MaxItems, ItemIds) -> + node_default:remove_extra_items(NodeId, MaxItems, ItemIds). -delete_item(Host, Node, JID, ItemId) -> - node_default:delete_item(Host, Node, JID, ItemId). +delete_item(NodeId, JID, ItemId) -> + node_default:delete_item(NodeId, JID, ItemId). -purge_node(Host, Node, Owner) -> - node_default:purge_node(Host, Node, Owner). +purge_node(NodeId, Owner) -> + node_default:purge_node(NodeId, Owner). get_entity_affiliations(_Host, Owner) -> OwnerKey = jlib:short_prepd_bare_jid(Owner), node_default:get_entity_affiliations(OwnerKey, Owner). -get_node_affiliations(Host, Node) -> - OwnerKey = jlib:short_bare_jid(Host), - node_default:get_node_affiliations(OwnerKey, Node). +get_node_affiliations(NodeId) -> + node_default:get_node_affiliations(NodeId). -get_affiliation(_Host, Node, Owner) -> - OwnerKey = jlib:short_prepd_bare_jid(Owner), - node_default:get_affiliation(OwnerKey, Node, Owner). +get_affiliation(NodeId, Owner) -> + node_default:get_affiliation(NodeId, Owner). -set_affiliation(_Host, Node, Owner, Affiliation) -> - OwnerKey = jlib:short_prepd_bare_jid(Owner), - State = get_state(OwnerKey, Node, OwnerKey), - set_state(State#pubsub_state{affiliation = Affiliation}), - ok. +set_affiliation(NodeId, Owner, Affiliation) -> + node_default:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(_Host, _Owner) -> {result, []}. -get_node_subscriptions(_Host, _Node) -> - {result, []}. +get_node_subscriptions(NodeId) -> + %% note: get_node_subscriptions is used for broadcasting + %% there should not have any subscriptions + %% but that call returns also all subscription to none + %% and this is required for broadcast to occurs + %% DO NOT REMOVE + node_default:get_node_subscriptions(NodeId). -get_subscription(_Host, _Node, _Owner) -> +get_subscription(_NodeId, _Owner) -> {result, none}. -set_subscription(_Host, _Node, _Owner, _Subscription) -> +set_subscription(_NodeId, _Owner, _Subscription) -> ok. -get_states(Host, Node) -> - node_default:get_states(Host, Node). +get_states(NodeId) -> + node_default:get_states(NodeId). -get_state(Host, Node, JID) -> - node_default:get_state(Host, Node, JID). +get_state(NodeId, JID) -> + node_default:get_state(NodeId, JID). set_state(State) -> node_default:set_state(State). -get_items(Host, Node, From) -> - node_default:get_items(Host, Node, From). +get_items(NodeId, From) -> + node_default:get_items(NodeId, From). -get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). -get_item(Host, Node, ItemId) -> - node_default:get_item(Host, Node, ItemId). +get_item(NodeId, ItemId) -> + node_default:get_item(NodeId, ItemId). -get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). set_item(Item) -> node_default:set_item(Item). diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl index 32f86fbb8..8458d50dc 100644 --- a/src/mod_pubsub/node_private.erl +++ b/src/mod_pubsub/node_private.erl @@ -44,29 +44,29 @@ -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, - create_node/3, - delete_node/2, - purge_node/3, - subscribe_node/8, - unsubscribe_node/5, - publish_item/7, - delete_item/4, - remove_extra_items/4, + create_node/2, + delete_node/1, + purge_node/2, + subscribe_node/7, + unsubscribe_node/4, + publish_item/6, + delete_item/3, + remove_extra_items/3, get_entity_affiliations/2, - get_node_affiliations/2, - get_affiliation/3, - set_affiliation/4, + get_node_affiliations/1, + get_affiliation/2, + set_affiliation/3, get_entity_subscriptions/2, - get_node_subscriptions/2, - get_subscription/3, - set_subscription/4, - get_states/2, - get_state/3, + get_node_subscriptions/1, + get_subscription/2, + set_subscription/3, + get_states/1, + get_state/2, set_state/1, - get_items/7, - get_items/3, - get_item/8, - get_item/3, + get_items/6, + get_items/2, + get_item/7, + get_item/2, set_item/1, get_item_name/3 ]). @@ -116,76 +116,76 @@ create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). -create_node(Host, Node, Owner) -> - node_default:create_node(Host, Node, Owner). +create_node(NodeId, Owner) -> + node_default:create_node(NodeId, Owner). -delete_node(Host, Removed) -> - node_default:delete_node(Host, Removed). +delete_node(Removed) -> + node_default:delete_node(Removed). -subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, +subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, + node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). -unsubscribe_node(Host, Node, Sender, Subscriber, SubID) -> - node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID). +unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> + node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID). -publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) -> - node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload). +publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> + node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). -remove_extra_items(Host, Node, MaxItems, ItemIds) -> - node_default:remove_extra_items(Host, Node, MaxItems, ItemIds). +remove_extra_items(NodeId, MaxItems, ItemIds) -> + node_default:remove_extra_items(NodeId, MaxItems, ItemIds). -delete_item(Host, Node, JID, ItemId) -> - node_default:delete_item(Host, Node, JID, ItemId). +delete_item(NodeId, JID, ItemId) -> + node_default:delete_item(NodeId, JID, ItemId). -purge_node(Host, Node, Owner) -> - node_default:purge_node(Host, Node, Owner). +purge_node(NodeId, Owner) -> + node_default:purge_node(NodeId, Owner). get_entity_affiliations(Host, Owner) -> node_default:get_entity_affiliations(Host, Owner). -get_node_affiliations(Host, Node) -> - node_default:get_node_affiliations(Host, Node). +get_node_affiliations(NodeId) -> + node_default:get_node_affiliations(NodeId). -get_affiliation(Host, Node, Owner) -> - node_default:get_affiliation(Host, Node, Owner). +get_affiliation(NodeId, Owner) -> + node_default:get_affiliation(NodeId, Owner). -set_affiliation(Host, Node, Owner, Affiliation) -> - node_default:set_affiliation(Host, Node, Owner, Affiliation). +set_affiliation(NodeId, Owner, Affiliation) -> + node_default:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(Host, Owner) -> node_default:get_entity_subscriptions(Host, Owner). -get_node_subscriptions(Host, Node) -> - node_default:get_node_subscriptions(Host, Node). +get_node_subscriptions(NodeId) -> + node_default:get_node_subscriptions(NodeId). -get_subscription(Host, Node, Owner) -> - node_default:get_subscription(Host, Node, Owner). +get_subscription(NodeId, Owner) -> + node_default:get_subscription(NodeId, Owner). -set_subscription(Host, Node, Owner, Subscription) -> - node_default:set_subscription(Host, Node, Owner, Subscription). +set_subscription(NodeId, Owner, Subscription) -> + node_default:set_subscription(NodeId, Owner, Subscription). -get_states(Host, Node) -> - node_default:get_states(Host, Node). +get_states(NodeId) -> + node_default:get_states(NodeId). -get_state(Host, Node, JID) -> - node_default:get_state(Host, Node, JID). +get_state(NodeId, JID) -> + node_default:get_state(NodeId, JID). set_state(State) -> node_default:set_state(State). -get_items(Host, Node, From) -> - node_default:get_items(Host, Node, From). +get_items(NodeId, From) -> + node_default:get_items(NodeId, From). -get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). -get_item(Host, Node, ItemId) -> - node_default:get_item(Host, Node, ItemId). +get_item(NodeId, ItemId) -> + node_default:get_item(NodeId, ItemId). -get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). set_item(Item) -> node_default:set_item(Item). diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl index c8fa085ab..2c8d702be 100644 --- a/src/mod_pubsub/node_public.erl +++ b/src/mod_pubsub/node_public.erl @@ -44,29 +44,29 @@ -export([init/3, terminate/2, options/0, features/0, create_node_permission/6, - create_node/3, - delete_node/2, - purge_node/3, - subscribe_node/8, - unsubscribe_node/5, - publish_item/7, - delete_item/4, - remove_extra_items/4, + create_node/2, + delete_node/1, + purge_node/2, + subscribe_node/7, + unsubscribe_node/4, + publish_item/6, + delete_item/3, + remove_extra_items/3, get_entity_affiliations/2, - get_node_affiliations/2, - get_affiliation/3, - set_affiliation/4, + get_node_affiliations/1, + get_affiliation/2, + set_affiliation/3, get_entity_subscriptions/2, - get_node_subscriptions/2, - get_subscription/3, - set_subscription/4, - get_states/2, - get_state/3, + get_node_subscriptions/1, + get_subscription/2, + set_subscription/3, + get_states/1, + get_state/2, set_state/1, - get_items/7, - get_items/3, - get_item/8, - get_item/3, + get_items/6, + get_items/2, + get_item/7, + get_item/2, set_item/1, get_item_name/3 ]). @@ -115,74 +115,74 @@ features() -> create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). -create_node(Host, Node, Owner) -> - node_default:create_node(Host, Node, Owner). +create_node(NodeId, Owner) -> + node_default:create_node(NodeId, Owner). -delete_node(Host, Removed) -> - node_default:delete_node(Host, Removed). +delete_node(Removed) -> + node_default:delete_node(Removed). -subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). +subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> + node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). -unsubscribe_node(Host, Node, Sender, Subscriber, SubID) -> - node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID). +unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> + node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID). -publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) -> - node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload). +publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> + node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). -remove_extra_items(Host, Node, MaxItems, ItemIds) -> - node_default:remove_extra_items(Host, Node, MaxItems, ItemIds). +remove_extra_items(NodeId, MaxItems, ItemIds) -> + node_default:remove_extra_items(NodeId, MaxItems, ItemIds). -delete_item(Host, Node, JID, ItemId) -> - node_default:delete_item(Host, Node, JID, ItemId). +delete_item(NodeId, JID, ItemId) -> + node_default:delete_item(NodeId, JID, ItemId). -purge_node(Host, Node, Owner) -> - node_default:purge_node(Host, Node, Owner). +purge_node(NodeId, Owner) -> + node_default:purge_node(NodeId, Owner). get_entity_affiliations(Host, Owner) -> node_default:get_entity_affiliations(Host, Owner). -get_node_affiliations(Host, Node) -> - node_default:get_node_affiliations(Host, Node). +get_node_affiliations(NodeId) -> + node_default:get_node_affiliations(NodeId). -get_affiliation(Host, Node, Owner) -> - node_default:get_affiliation(Host, Node, Owner). +get_affiliation(NodeId, Owner) -> + node_default:get_affiliation(NodeId, Owner). -set_affiliation(Host, Node, Owner, Affiliation) -> - node_default:set_affiliation(Host, Node, Owner, Affiliation). +set_affiliation(NodeId, Owner, Affiliation) -> + node_default:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(Host, Owner) -> node_default:get_entity_subscriptions(Host, Owner). -get_node_subscriptions(Host, Node) -> - node_default:get_node_subscriptions(Host, Node). +get_node_subscriptions(NodeId) -> + node_default:get_node_subscriptions(NodeId). -get_subscription(Host, Node, Owner) -> - node_default:get_subscription(Host, Node, Owner). +get_subscription(NodeId, Owner) -> + node_default:get_subscription(NodeId, Owner). -set_subscription(Host, Node, Owner, Subscription) -> - node_default:set_subscription(Host, Node, Owner, Subscription). +set_subscription(NodeId, Owner, Subscription) -> + node_default:set_subscription(NodeId, Owner, Subscription). -get_states(Host, Node) -> - node_default:get_states(Host, Node). +get_states(NodeId) -> + node_default:get_states(NodeId). -get_state(Host, Node, JID) -> - node_default:get_state(Host, Node, JID). +get_state(NodeId, JID) -> + node_default:get_state(NodeId, JID). set_state(State) -> node_default:set_state(State). -get_items(Host, Node, From) -> - node_default:get_items(Host, Node, From). +get_items(NodeId, From) -> + node_default:get_items(NodeId, From). -get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). -get_item(Host, Node, ItemId) -> - node_default:get_item(Host, Node, ItemId). +get_item(NodeId, ItemId) -> + node_default:get_item(NodeId, ItemId). -get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). +get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). set_item(Item) -> node_default:set_item(Item). diff --git a/src/mod_pubsub/nodetree_default.erl b/src/mod_pubsub/nodetree_default.erl index b8a6b6f26..d529849ff 100644 --- a/src/mod_pubsub/nodetree_default.erl +++ b/src/mod_pubsub/nodetree_default.erl @@ -51,7 +51,7 @@ get_nodes/2, get_nodes/1, get_subnodes/3, - get_subnodes_tree/2, + get_subnodes_tree/3, create_node/5, delete_node/2 ]). @@ -76,9 +76,10 @@ init(_Host, _ServerHost, _Opts) -> {attributes, record_info(fields, pubsub_node)}]), NodesFields = record_info(fields, pubsub_node), case mnesia:table_info(pubsub_node, attributes) of - [host_node, host_parent, info] -> ok; % old schema, updated later by pubsub NodesFields -> ok; - _ -> mnesia:transform_table(pubsub_node, ignore, NodesFields) + _ -> + ok + %% mnesia:transform_table(pubsub_state, ignore, StatesFields) end, ok. terminate(_Host, _ServerHost) -> @@ -97,12 +98,11 @@ set_node(Record) when is_record(Record, pubsub_node) -> set_node(_) -> {error, 'internal-server-error'}. -get_node(Host, Node, _From) -> - get_node(Host, Node). - %% @spec (Host, Node) -> pubsubNode() | {error, Reason} %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() +get_node(Host, Node, _From) -> + get_node(Host, Node). get_node(Host, Node) -> case catch mnesia:read({pubsub_node, {Host, Node}}) of [Record] when is_record(Record, pubsub_node) -> Record; @@ -110,44 +110,48 @@ get_node(Host, Node) -> Error -> Error end. -get_nodes(Key, _From) -> - get_nodes(Key). - -%% @spec (Key) -> [pubsubNode()] | {error, Reason} -%% Key = mod_pubsub:host() | mod_pubsub:jid() -get_nodes(Key) -> - mnesia:match_object(#pubsub_node{nodeid = {Key, '_'}, _ = '_'}). +%% @spec (Host) -> [pubsubNode()] | {error, Reason} +%% Host = mod_pubsub:host() | mod_pubsub:jid() +get_nodes(Host, _From) -> + get_nodes(Host). +get_nodes(Host) -> + mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, _ = '_'}). %% @spec (Host, Node, From) -> [pubsubNode()] | {error, Reason} %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() %% From = mod_pubsub:jid() get_subnodes(Host, Node, _From) -> - mnesia:match_object(#pubsub_node{parentid = {Host, Node}, _ = '_'}). + get_subnodes(Host, Node). +get_subnodes(Host, Node) -> + mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, parent = Node, _ = '_'}). %% @spec (Host, Index) -> [pubsubNode()] | {error, Reason} %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() +%% From = mod_pubsub:jid() +get_subnodes_tree(Host, Node, _From) -> + get_subnodes_tree(Host, Node). get_subnodes_tree(Host, Node) -> - mnesia:foldl(fun(#pubsub_node{nodeid = {H, N}}, Acc) -> + mnesia:foldl(fun(#pubsub_node{nodeid = {H, N} = R}, Acc) -> case lists:prefix(Node, N) and (H == Host) of - true -> [N | Acc]; + true -> [R | Acc]; _ -> Acc end end, [], pubsub_node). -%% @spec (Key, Node, Type, Owner, Options) -> ok | {error, Reason} -%% Key = mod_pubsub:host() | mod_pubsub:jid() +%% @spec (Host, Node, Type, Owner, Options) -> ok | {error, Reason} +%% Host = mod_pubsub:host() | mod_pubsub:jid() %% Node = mod_pubsub:pubsubNode() %% NodeType = mod_pubsub:nodeType() %% Owner = mod_pubsub:jid() %% Options = list() -create_node(Key, Node, Type, Owner, Options) -> - OwnerKey = jlib:short_prepd_bare_jid(Owner), - case mnesia:read({pubsub_node, {Key, Node}}) of +create_node(Host, Node, Type, Owner, Options) -> + BJID = jlib:short_prepd_bare_jid(Owner), + case mnesia:read({pubsub_node, {Host, Node}}) of [] -> {ParentNode, ParentExists} = - case Key of + case Host of {_U, _S, _R} -> %% This is special case for PEP handling %% PEP does not uses hierarchy @@ -158,7 +162,7 @@ create_node(Key, Node, Type, Owner, Options) -> [] -> {[], true}; _ -> - case mnesia:read({pubsub_node, {Key, Parent}}) of + case mnesia:read({pubsub_node, {Host, Parent}}) of [] -> {Parent, false}; _ -> {Parent, true} end @@ -166,13 +170,14 @@ create_node(Key, Node, Type, Owner, Options) -> end, case ParentExists of true -> - %% Service requires registration - %%{error, ?ERR_REGISTRATION_REQUIRED}; - mnesia:write(#pubsub_node{nodeid = {Key, Node}, - parentid = {Key, ParentNode}, + NodeId = pubsub_index:new(node), + mnesia:write(#pubsub_node{nodeid = {Host, Node}, + id = NodeId, + parent = ParentNode, type = Type, - owners = [OwnerKey], - options = Options}); + owners = [BJID], + options = Options}), + {ok, NodeId}; false -> %% Requesting entity is prohibited from creating nodes {error, 'forbidden'} @@ -182,12 +187,13 @@ create_node(Key, Node, Type, Owner, Options) -> {error, 'conflict'} end. -%% @spec (Key, Node) -> [mod_pubsub:node()] -%% Key = mod_pubsub:host() | mod_pubsub:jid() +%% @spec (Host, Node) -> [mod_pubsub:node()] +%% Host = mod_pubsub:host() | mod_pubsub:jid() %% Node = mod_pubsub:pubsubNode() -delete_node(Key, Node) -> - Removed = get_subnodes_tree(Key, Node), - lists:foreach(fun(N) -> - mnesia:delete({pubsub_node, {Key, N}}) - end, Removed), +delete_node(Host, Node) -> + Removed = get_subnodes_tree(Host, Node), + lists:foreach(fun(#pubsub_node{nodeid = {_, N}, id = I}) -> + pubsub_index:free(node, I), + mnesia:delete({pubsub_node, {Host, N}}) + end, Removed), Removed. diff --git a/src/mod_pubsub/nodetree_virtual.erl b/src/mod_pubsub/nodetree_virtual.erl index a850f26e6..5fb77e217 100644 --- a/src/mod_pubsub/nodetree_virtual.erl +++ b/src/mod_pubsub/nodetree_virtual.erl @@ -49,7 +49,7 @@ get_nodes/2, get_nodes/1, get_subnodes/3, - get_subnodes_tree/2, + get_subnodes_tree/3, create_node/5, delete_node/2 ]). @@ -95,14 +95,13 @@ get_node(Host, Node, _From) -> get_node(Host, Node) -> #pubsub_node{nodeid = {Host, Node}}. -get_nodes(Key, _From) -> - get_nodes(Key). - -%% @spec (Key) -> [pubsubNode()] +%% @spec (Host) -> [pubsubNode()] %% Host = mod_pubsub:host() | mod_pubsub:jid() %% @doc

    Virtual node tree does not handle a node database. Any node is considered %% as existing. Nodes list can not be determined.

    -get_nodes(_Key) -> +get_nodes(Host, _From) -> + get_nodes(Host). +get_nodes(_Host) -> []. %% @spec (Host, Node, From) -> [pubsubNode()] @@ -110,13 +109,17 @@ get_nodes(_Key) -> %% Node = mod_pubsub:pubsubNode() %% From = mod_pubsub:jid() %% @doc

    Virtual node tree does not handle parent/child. Child list is empty.

    -get_subnodes(_Host, _Node, _From) -> +get_subnodes(Host, Node, _From) -> + get_subnodes(Host, Node). +get_subnodes(_Host, _Node) -> []. %% @spec (Host, Index) -> [pubsubNode()] %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() %% @doc

    Virtual node tree does not handle parent/child. Child list is empty.

    +get_subnodes_tree(Host, Node, _From) -> + get_subnodes_tree(Host, Node). get_subnodes_tree(_Host, _Node) -> []. @@ -129,11 +132,11 @@ get_subnodes_tree(_Host, _Node) -> %% @doc

    No node record is stored on database. Any valid node %% is considered as already created.

    %%

    default allowed nodes: /home/host/user/any/node/name

    -create_node(_Host, Node, _Type, Owner, _Options) -> +create_node(Host, Node, _Type, Owner, _Options) -> UserName = exmpp_jid:lnode_as_list(Owner), UserHost = exmpp_jid:ldomain_as_list(Owner), case Node of - ["home", UserHost, UserName | _] -> {error, 'conflict'}; + ["home", UserHost, UserName | _] -> {error, {virtual, {Host, Node}}}; _ -> {error, 'not-allowed'} end. @@ -142,5 +145,5 @@ create_node(_Host, Node, _Type, Owner, _Options) -> %% Node = mod_pubsub:pubsubNode() %% @doc

    Virtual node tree does not handle parent/child. %% node deletion just affects the corresponding node.

    -delete_node(_Host, Node) -> - [Node]. +delete_node(Host, Node) -> + [get_node(Host, Node)]. diff --git a/src/mod_pubsub/pubsub.hrl b/src/mod_pubsub/pubsub.hrl index 46cbe9b95..87088eb6a 100644 --- a/src/mod_pubsub/pubsub.hrl +++ b/src/mod_pubsub/pubsub.hrl @@ -77,24 +77,28 @@ %%% @type affiliation() = none | owner | publisher | outcast. %%% @type subscription() = none | pending | unconfigured | subscribed. +%%% internal pubsub index table +-record(pubsub_index, {index, last, free}). + %%% @type pubsubNode() = #pubsub_node{ %%% nodeid = {Host::host(), Node::pubsubNode()}, %%% parentid = {Host::host(), Node::pubsubNode()}, +%%% nodeidx = int(). %%% type = nodeType(), -%%% owners = [ljid()], -%%% options = [nodeOption()]}. +%%% options = [nodeOption()]} %%%

    This is the format of the nodes table. The type of the table %%% is: set,ram/disc.

    %%%

    The parentid and type fields are indexed.

    -record(pubsub_node, {nodeid, - parentid = {}, - type = "", + id, + parent, + type = "default", owners = [], options = [] }). %%% @type pubsubState() = #pubsub_state{ -%%% stateid = {ljid(), {Host::host(), Node::pubsubNode()}}, +%%% stateid = {ljid(), pubsubNodeId()}}, %%% items = [ItemId::string()], %%% affiliation = affiliation(), %%% subscription = subscription()}. @@ -106,11 +110,11 @@ subscription = none }). -%% @type pubsubItem() = #pubsub_item{ -%% itemid = {ItemId::string(), {Host::host(),Node::pubsubNode()}}, -%% creation = {ljid(), now()}, -%% modification = {ljid(), now()}, -%% payload = XMLContent::string()}. +%%% @type pubsubItem() = #pubsub_item{ +%%% itemid = {ItemId::string(), pubsubNodeId()}}, +%%% creation = {ljid(), now()}, +%%% modification = {ljid(), now()}, +%%% payload = XMLContent::string()}. %%%

    This is the format of the published items table. The type of the %%% table is: set,disc,fragmented.

    -record(pubsub_item, {itemid, diff --git a/src/mod_pubsub/pubsub_index.erl b/src/mod_pubsub/pubsub_index.erl new file mode 100644 index 000000000..2ba5d4b20 --- /dev/null +++ b/src/mod_pubsub/pubsub_index.erl @@ -0,0 +1,65 @@ +%%% ==================================================================== +%%% ``The contents of this file are subject to the Erlang Public License, +%%% Version 1.1, (the "License"); you may not use this file except in +%%% compliance with the License. You should have received a copy of the +%%% Erlang Public License along with this software. If not, it can be +%%% retrieved via the world wide web at http://www.erlang.org/. +%%% +%%% Software distributed under the License is distributed on an "AS IS" +%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%%% the License for the specific language governing rights and limitations +%%% under the License. +%%% +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne +%%% All Rights Reserved.'' +%%% This software is copyright 2006-2009, ProcessOne. +%%% +%%% +%%% @copyright 2006-2009 ProcessOne +%%% @author Christophe Romain +%%% [http://www.process-one.net/] +%%% @version {@vsn}, {@date} {@time} +%%% @end +%%% ==================================================================== + +%% important note: +%% new/1 and free/2 MUST be called inside a transaction bloc + +-module(pubsub_index). +-author('christophe.romain@process-one.net'). + +-include("pubsub.hrl"). + +-export([init/3, new/1, free/2]). + +init(_Host, _ServerHost, _Opts) -> + mnesia:create_table(pubsub_index, + [{disc_copies, [node()]}, + {attributes, record_info(fields, pubsub_index)}]). + +new(Index) -> + case mnesia:read({pubsub_index, Index}) of + [I] -> + case I#pubsub_index.free of + [] -> + Id = I#pubsub_index.last + 1, + mnesia:write(I#pubsub_index{last = Id}), + Id; + [Id|Free] -> + mnesia:write(I#pubsub_index{free = Free}), + Id + end; + _ -> + mnesia:write(#pubsub_index{index = Index, last = 1, free = []}), + 1 + end. + +free(Index, Id) -> + case mnesia:read({pubsub_index, Index}) of + [I] -> + Free = I#pubsub_index.free, + mnesia:write(I#pubsub_index{free = [Id|Free]}); + _ -> + ok + end. From e202ec009e668c8dc44623f5909152bd2e8b7db1 Mon Sep 17 00:00:00 2001 From: Badlop Date: Sun, 3 May 2009 11:26:18 +0000 Subject: [PATCH 296/582] * src/mod_muc/mod_muc_room.erl: Fix badarg return (EJAB-899) SVN Revision: 2053 --- ChangeLog | 4 ++++ src/mod_muc/mod_muc_room.erl | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 964d5a689..cc010190d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-05-03 Badlop + + * src/mod_muc/mod_muc_room.erl: Fix badarg return (EJAB-899) + 2009-04-30 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: API change for major optimization diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 199597d8f..033c537a9 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -2689,7 +2689,7 @@ is_allowed_persistent_change(XEl, StateData, From) -> true; true -> {_AccessRoute, _AccessCreate, _AccessAdmin, AccessPersistent} = StateData#state.access, - acl:match_rule(StateData#state.server_host, AccessPersistent, From) + (allow == acl:match_rule(StateData#state.server_host, AccessPersistent, From)) end. %% Check if the Room Name and Room Description defined in the Data Form From 921c7ede0d746cde88479f70cb5c2ce0914b1886 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 6 May 2009 14:51:51 +0000 Subject: [PATCH 297/582] * src/ejabberd_loglevel.erl: Use dynamic_compile instead of ram_file_io_server. Support definition of loglevels with integer or atom. (thanks to Geoff Cant)(EJAB-919) * src/dynamic_compile.erl: Added erlang module that converts string to binary loadable code by Mats Cronqvist, Chris Newcombe, and Jacob Vorreuter. * src/ram_file_io_server.erl: Remove file not longer useful. * src/ejabberd.app: Likewise SVN Revision: 2054 --- ChangeLog | 11 + src/dynamic_compile.erl | 268 ++++++++++++++++++++++++ src/ejabberd.app | 1 - src/ejabberd_loglevel.erl | 61 ++---- src/ram_file_io_server.erl | 408 ------------------------------------- 5 files changed, 299 insertions(+), 450 deletions(-) create mode 100644 src/dynamic_compile.erl delete mode 100644 src/ram_file_io_server.erl diff --git a/ChangeLog b/ChangeLog index cc010190d..84d2197dc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2009-05-06 Badlop + + * src/ejabberd_loglevel.erl: Use dynamic_compile instead of + ram_file_io_server. Support definition of loglevels with integer + or atom. (thanks to Geoff Cant)(EJAB-919) + * src/dynamic_compile.erl: Added erlang module that converts + string to binary loadable code by Mats Cronqvist, Chris Newcombe, + and Jacob Vorreuter. + * src/ram_file_io_server.erl: Remove file not longer useful. + * src/ejabberd.app: Likewise + 2009-05-03 Badlop * src/mod_muc/mod_muc_room.erl: Fix badarg return (EJAB-899) diff --git a/src/dynamic_compile.erl b/src/dynamic_compile.erl new file mode 100644 index 000000000..1fe2dcaad --- /dev/null +++ b/src/dynamic_compile.erl @@ -0,0 +1,268 @@ +%% Copyright (c) 2007 +%% Mats Cronqvist +%% Chris Newcombe +%% Jacob Vorreuter +%% +%% Permission is hereby granted, free of charge, to any person +%% obtaining a copy of this software and associated documentation +%% files (the "Software"), to deal in the Software without +%% restriction, including without limitation the rights to use, +%% copy, modify, merge, publish, distribute, sublicense, and/or sell +%% copies of the Software, and to permit persons to whom the +%% Software is furnished to do so, subject to the following +%% conditions: +%% +%% The above copyright notice and this permission notice shall be +%% included in all copies or substantial portions of the Software. +%% +%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +%% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +%% OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +%% NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +%% HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +%% WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +%% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +%% OTHER DEALINGS IN THE SOFTWARE. + +%%%------------------------------------------------------------------- +%%% File : dynamic_compile.erl +%%% Description : +%%% Authors : Mats Cronqvist +%%% Chris Newcombe +%%% Jacob Vorreuter +%%% TODO : +%%% - add support for limit include-file depth (and prevent circular references) +%%% prevent circular macro expansion set FILE correctly when -module() is found +%%% -include_lib support $ENVVAR in include filenames +%%% substitute-stringize (??MACRO) +%%% -undef/-ifdef/-ifndef/-else/-endif +%%% -file(File, Line) +%%%------------------------------------------------------------------- +-module(dynamic_compile). + +%% API +-export([from_string/1, from_string/2]). + +-import(lists, [reverse/1, keyreplace/4]). + +%%==================================================================== +%% API +%%==================================================================== +%%-------------------------------------------------------------------- +%% Function: +%% Description: +%% Returns a binary that can be used with +%% code:load_binary(Module, ModuleFilenameForInternalRecords, Binary). +%%-------------------------------------------------------------------- +from_string(CodeStr) -> + from_string(CodeStr, []). + +% takes Options as for compile:forms/2 +from_string(CodeStr, CompileFormsOptions) -> + %% Initialise the macro dictionary with the default predefined macros, + %% (adapted from epp.erl:predef_macros/1 + Filename = "compiled_from_string", + %%Machine = list_to_atom(erlang:system_info(machine)), + Ms0 = dict:new(), + % Ms1 = dict:store('FILE', {[], "compiled_from_string"}, Ms0), + % Ms2 = dict:store('LINE', {[], 1}, Ms1), % actually we might add special code for this + % Ms3 = dict:store('MODULE', {[], undefined}, Ms2), + % Ms4 = dict:store('MODULE_STRING', {[], undefined}, Ms3), + % Ms5 = dict:store('MACHINE', {[], Machine}, Ms4), + % InitMD = dict:store(Machine, {[], true}, Ms5), + InitMD = Ms0, + + %% From the docs for compile:forms: + %% When encountering an -include or -include_dir directive, the compiler searches for header files in the following directories: + %% 1. ".", the current working directory of the file server; + %% 2. the base name of the compiled file; + %% 3. the directories specified using the i option. The directory specified last is searched first. + %% In this case, #2 is meaningless. + IncludeSearchPath = ["." | reverse([Dir || {i, Dir} <- CompileFormsOptions])], + {RevForms, _OutMacroDict} = scan_and_parse(CodeStr, Filename, 1, [], InitMD, IncludeSearchPath), + Forms = reverse(RevForms), + + %% note: 'binary' is forced as an implicit option, whether it is provided or not. + case compile:forms(Forms, CompileFormsOptions) of + {ok, ModuleName, CompiledCodeBinary} when is_binary(CompiledCodeBinary) -> + {ModuleName, CompiledCodeBinary}; + {ok, ModuleName, CompiledCodeBinary, []} when is_binary(CompiledCodeBinary) -> % empty warnings list + {ModuleName, CompiledCodeBinary}; + {ok, _ModuleName, _CompiledCodeBinary, Warnings} -> + throw({?MODULE, warnings, Warnings}); + Other -> + throw({?MODULE, compile_forms, Other}) + end. + +%%==================================================================== +%% Internal functions +%%==================================================================== +%%% Code from Mats Cronqvist +%%% See http://www.erlang.org/pipermail/erlang-questions/2007-March/025507.html +%%%## 'scan_and_parse' +%%% +%%% basically we call the OTP scanner and parser (erl_scan and +%%% erl_parse) line-by-line, but check each scanned line for (or +%%% definitions of) macros before parsing. +%% returns {ReverseForms, FinalMacroDict} +scan_and_parse([], _CurrFilename, _CurrLine, RevForms, MacroDict, _IncludeSearchPath) -> + {RevForms, MacroDict}; + +scan_and_parse(RemainingText, CurrFilename, CurrLine, RevForms, MacroDict, IncludeSearchPath) -> + case scanner(RemainingText, CurrLine, MacroDict) of + {tokens, NLine, NRemainingText, Toks} -> + {ok, Form} = erl_parse:parse_form(Toks), + scan_and_parse(NRemainingText, CurrFilename, NLine, [Form | RevForms], MacroDict, IncludeSearchPath); + {macro, NLine, NRemainingText, NMacroDict} -> + scan_and_parse(NRemainingText, CurrFilename, NLine, RevForms,NMacroDict, IncludeSearchPath); + {include, NLine, NRemainingText, IncludeFilename} -> + IncludeFileRemainingTextents = read_include_file(IncludeFilename, IncludeSearchPath), + %%io:format("include file ~p contents: ~n~p~nRemainingText = ~p~n", [IncludeFilename,IncludeFileRemainingTextents, RemainingText]), + %% Modify the FILE macro to reflect the filename + %%IncludeMacroDict = dict:store('FILE', {[],IncludeFilename}, MacroDict), + IncludeMacroDict = MacroDict, + + %% Process the header file (inc. any nested header files) + {RevIncludeForms, IncludedMacroDict} = scan_and_parse(IncludeFileRemainingTextents, IncludeFilename, 1, [], IncludeMacroDict, IncludeSearchPath), + %io:format("include file results = ~p~n", [R]), + %% Restore the FILE macro in the NEW MacroDict (so we keep any macros defined in the header file) + %%NMacroDict = dict:store('FILE', {[],CurrFilename}, IncludedMacroDict), + NMacroDict = IncludedMacroDict, + + %% Continue with the original file + scan_and_parse(NRemainingText, CurrFilename, NLine, RevIncludeForms ++ RevForms, NMacroDict, IncludeSearchPath); + done -> + scan_and_parse([], CurrFilename, CurrLine, RevForms, MacroDict, IncludeSearchPath) + end. + +scanner(Text, Line, MacroDict) -> + case erl_scan:tokens([],Text,Line) of + {done, {ok,Toks,NLine}, LeftOverChars} -> + case pre_proc(Toks, MacroDict) of + {tokens, NToks} -> {tokens, NLine, LeftOverChars, NToks}; + {macro, NMacroDict} -> {macro, NLine, LeftOverChars, NMacroDict}; + {include, Filename} -> {include, NLine, LeftOverChars, Filename} + end; + {more, _Continuation} -> + %% This is supposed to mean "term is not yet complete" (i.e. a '.' has + %% not been reached yet). + %% However, for some bizarre reason we also get this if there is a comment after the final '.' in a file. + %% So we check to see if Text only consists of comments. + case is_only_comments(Text) of + true -> + done; + false -> + throw({incomplete_term, Text, Line}) + end + end. + +is_only_comments(Text) -> is_only_comments(Text, not_in_comment). + +is_only_comments([], _) -> true; +is_only_comments([$ |T], not_in_comment) -> is_only_comments(T, not_in_comment); % skipping whitspace outside of comment +is_only_comments([$\t |T], not_in_comment) -> is_only_comments(T, not_in_comment); % skipping whitspace outside of comment +is_only_comments([$\n |T], not_in_comment) -> is_only_comments(T, not_in_comment); % skipping whitspace outside of comment +is_only_comments([$% |T], not_in_comment) -> is_only_comments(T, in_comment); % found start of a comment +is_only_comments(_, not_in_comment) -> false; +% found any significant char NOT in a comment +is_only_comments([$\n |T], in_comment) -> is_only_comments(T, not_in_comment); % found end of a comment +is_only_comments([_ |T], in_comment) -> is_only_comments(T, in_comment). % skipping over in-comment chars + +%%%## 'pre-proc' +%%% +%%% have to implement a subset of the pre-processor, since epp insists +%%% on running on a file. +%%% only handles 2 cases; +%% -define(MACRO, something). +%% -define(MACRO(VAR1,VARN),{stuff,VAR1,more,stuff,VARN,extra,stuff}). +pre_proc([{'-',_},{atom,_,define},{'(',_},{_,_,Name}|DefToks],MacroDict) -> + false = dict:is_key(Name, MacroDict), + case DefToks of + [{',',_} | Macro] -> + {macro, dict:store(Name, {[], macro_body_def(Macro, [])}, MacroDict)}; + [{'(',_} | Macro] -> + {macro, dict:store(Name, macro_params_body_def(Macro, []), MacroDict)} + end; + +pre_proc([{'-',_}, {atom,_,include}, {'(',_}, {string,_,Filename}, {')',_}, {dot,_}], _MacroDict) -> + {include, Filename}; + +pre_proc(Toks,MacroDict) -> + {tokens, subst_macros(Toks, MacroDict)}. + +macro_params_body_def([{')',_},{',',_} | Toks], RevParams) -> + {reverse(RevParams), macro_body_def(Toks, [])}; +macro_params_body_def([{var,_,Param} | Toks], RevParams) -> + macro_params_body_def(Toks, [Param | RevParams]); +macro_params_body_def([{',',_}, {var,_,Param} | Toks], RevParams) -> + macro_params_body_def(Toks, [Param | RevParams]). + +macro_body_def([{')',_}, {dot,_}], RevMacroBodyToks) -> + reverse(RevMacroBodyToks); +macro_body_def([Tok|Toks], RevMacroBodyToks) -> + macro_body_def(Toks, [Tok | RevMacroBodyToks]). + +subst_macros(Toks, MacroDict) -> + reverse(subst_macros_rev(Toks, MacroDict, [])). + +%% returns a reversed list of tokes +subst_macros_rev([{'?',_}, {_,LineNum,'LINE'} | Toks], MacroDict, RevOutToks) -> + %% special-case for ?LINE, to avoid creating a new MacroDict for every line in the source file + subst_macros_rev(Toks, MacroDict, [{integer,LineNum,LineNum}] ++ RevOutToks); + +subst_macros_rev([{'?',_}, {_,_,Name}, {'(',_} = Paren | Toks], MacroDict, RevOutToks) -> + case dict:fetch(Name, MacroDict) of + {[], MacroValue} -> + %% This macro does not have any vars, so ignore the fact that the invocation is followed by "(...stuff" + %% Recursively expand any macro calls inside this macro's value + %% TODO: avoid infinite expansion due to circular references (even indirect ones) + RevExpandedOtherMacrosToks = subst_macros_rev(MacroValue, MacroDict, []), + subst_macros_rev([Paren|Toks], MacroDict, RevExpandedOtherMacrosToks ++ RevOutToks); + ParamsAndBody -> + %% This macro does have vars. + %% Collect all of the passe arguments, in an ordered list + {NToks, Arguments} = subst_macros_get_args(Toks, []), + %% Expand the varibles + ExpandedParamsToks = subst_macros_subst_args_for_vars(ParamsAndBody, Arguments), + %% Recursively expand any macro calls inside this macro's value + %% TODO: avoid infinite expansion due to circular references (even indirect ones) + RevExpandedOtherMacrosToks = subst_macros_rev(ExpandedParamsToks, MacroDict, []), + subst_macros_rev(NToks, MacroDict, RevExpandedOtherMacrosToks ++ RevOutToks) + end; + +subst_macros_rev([{'?',_}, {_,_,Name} | Toks], MacroDict, RevOutToks) -> + %% This macro invocation does not have arguments. + %% Therefore the definition should not have parameters + {[], MacroValue} = dict:fetch(Name, MacroDict), + + %% Recursively expand any macro calls inside this macro's value + %% TODO: avoid infinite expansion due to circular references (even indirect ones) + RevExpandedOtherMacrosToks = subst_macros_rev(MacroValue, MacroDict, []), + subst_macros_rev(Toks, MacroDict, RevExpandedOtherMacrosToks ++ RevOutToks); + +subst_macros_rev([Tok|Toks], MacroDict, RevOutToks) -> +subst_macros_rev(Toks, MacroDict, [Tok|RevOutToks]); +subst_macros_rev([], _MacroDict, RevOutToks) -> RevOutToks. + +subst_macros_get_args([{')',_} | Toks], RevArgs) -> + {Toks, reverse(RevArgs)}; +subst_macros_get_args([{',',_}, {var,_,ArgName} | Toks], RevArgs) -> + subst_macros_get_args(Toks, [ArgName| RevArgs]); +subst_macros_get_args([{var,_,ArgName} | Toks], RevArgs) -> + subst_macros_get_args(Toks, [ArgName | RevArgs]). + +subst_macros_subst_args_for_vars({[], BodyToks}, []) -> + BodyToks; +subst_macros_subst_args_for_vars({[Param | Params], BodyToks}, [Arg|Args]) -> + NBodyToks = keyreplace(Param, 3, BodyToks, {var,1,Arg}), + subst_macros_subst_args_for_vars({Params, NBodyToks}, Args). + +read_include_file(Filename, IncludeSearchPath) -> + case file:path_open(IncludeSearchPath, Filename, [read, raw, binary]) of + {ok, IoDevice, FullName} -> + {ok, Data} = file:read(IoDevice, filelib:file_size(FullName)), + file:close(IoDevice), + binary_to_list(Data); + {error, Reason} -> + throw({failed_to_read_include_file, Reason, Filename, IncludeSearchPath}) + end. \ No newline at end of file diff --git a/src/ejabberd.app b/src/ejabberd.app index 1ff41ec46..7f0948f04 100644 --- a/src/ejabberd.app +++ b/src/ejabberd.app @@ -115,7 +115,6 @@ nodetree_virtual, p1_fsm, p1_mnesia, - ram_file_io_server, randoms, sha, shaper, diff --git a/src/ejabberd_loglevel.erl b/src/ejabberd_loglevel.erl index 3134d4d03..2a340606b 100644 --- a/src/ejabberd_loglevel.erl +++ b/src/ejabberd_loglevel.erl @@ -38,51 +38,30 @@ -define(LOGMODULE, "error_logger"). %% Error levels: -%% 0 -> No log -%% 1 -> Critical -%% 2 -> Error -%% 3 -> Warning -%% 4 -> Info -%% 5 -> Debug +-define(LOG_LEVELS,[ {0, no_log, "No log"} + ,{1, critical, "Critical"} + ,{2, error, "Error"} + ,{3, warning, "Warning"} + ,{4, info, "Info"} + ,{5, debug, "Debug"} + ]). + +set(LogLevel) when is_atom(LogLevel) -> + set(level_to_integer(LogLevel)); set(Loglevel) when is_integer(Loglevel) -> - Forms = compile_string(?LOGMODULE, ejabberd_logger_src(Loglevel)), - load_logger(Forms, ?LOGMODULE, Loglevel); + try + {Mod,Code} = dynamic_compile:from_string(ejabberd_logger_src(Loglevel)), + code:load_binary(Mod, ?LOGMODULE ++ ".erl", Code) + catch + Type:Error -> ?CRITICAL_MSG("Error compiling logger (~p): ~p~n", [Type, Error]) + end; set(_) -> exit("Loglevel must be an integer"). - -%% -------------------------------------------------------------- -%% Compile a string into a module and returns the binary -compile_string(Mod, Str) -> - Fname = Mod ++ ".erl", - {ok, Fd} = open_ram_file(Fname), - file:write(Fd, Str), - file:position(Fd, 0), - case epp_dodger:parse(Fd) of - {ok, Tree} -> - Forms = revert_tree(Tree), - close_ram_file(Fd), - Forms; - Error -> - close_ram_file(Fd), - Error - end. - -open_ram_file(Fname) -> - ram_file_io_server:start(self(), Fname, [read,write]). -close_ram_file(Fd) -> - file:close(Fd). - -revert_tree(Tree) -> - [erl_syntax:revert(T) || T <- Tree]. - -load_logger(Forms, Mod, Loglevel) -> - Fname = Mod ++ ".erl", - case compile:forms(Forms, [binary, {d,'LOGLEVEL',Loglevel}]) of - {ok, M, Bin} -> - code:load_binary(M, Fname, Bin); - Error -> - ?CRITICAL_MSG("Error ~p~n", [Error]) +level_to_integer(Level) -> + case lists:keyfind(Level, 2, ?LOG_LEVELS) of + {Int, Level, _Desc} -> Int; + _ -> erlang:error({no_such_loglevel, Level}) end. %% -------------------------------------------------------------- diff --git a/src/ram_file_io_server.erl b/src/ram_file_io_server.erl deleted file mode 100644 index 197cfa806..000000000 --- a/src/ram_file_io_server.erl +++ /dev/null @@ -1,408 +0,0 @@ -%% ``The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved via the world wide web at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. -%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings -%% AB. All Rights Reserved.'' -%% -%% $Id$ -%% -%% This file is mostly copied from Erlang file_io_server.erl -%% See: http://www.erlang.org/ml-archive/erlang-questions/200607/msg00080.html -%% for details on ram_file_io_server.erl (Erlang OTP R11B-2) --module(ram_file_io_server). - -%% A simple file server for io to one file instance per server instance. - --export([format_error/1]). --export([start/3, start_link/3]). - --record(state, {handle,owner,mref,buf,read_mode}). - --define(PRIM_FILE, ram_file). --define(READ_SIZE_LIST, 128). --define(READ_SIZE_BINARY, (8*1024)). - --define(eat_message(M, T), receive M -> M after T -> timeout end). - -%%%----------------------------------------------------------------- -%%% Exported functions - -format_error({_Line, ?MODULE, Reason}) -> - io_lib:format("~w", [Reason]); -format_error({_Line, Mod, Reason}) -> - Mod:format_error(Reason); -format_error(ErrorId) -> - erl_posix_msg:message(ErrorId). - -start(Owner, FileName, ModeList) - when pid(Owner), list(FileName), list(ModeList) -> - do_start(spawn, Owner, FileName, ModeList). - -start_link(Owner, FileName, ModeList) - when pid(Owner), list(FileName), list(ModeList) -> - do_start(spawn_link, Owner, FileName, ModeList). - -%%%----------------------------------------------------------------- -%%% Server starter, dispatcher and helpers - -do_start(Spawn, Owner, FileName, ModeList) -> - Self = self(), - Ref = make_ref(), - Pid = - erlang:Spawn( - fun() -> - %% process_flag(trap_exit, true), - {ReadMode,Opts} = - case lists:member(binary, ModeList) of - true -> - {binary,ModeList}; - false -> - {list,[binary|ModeList]} - end, - case ?PRIM_FILE:open(FileName, Opts) of - {error, Reason} = Error -> - Self ! {Ref, Error}, - exit(Reason); - {ok, Handle} -> - %% XXX must I handle R6 nodes here? - M = erlang:monitor(process, Owner), - Self ! {Ref, ok}, - server_loop( - #state{handle = Handle, - owner = Owner, - mref = M, - buf = <<>>, - read_mode = ReadMode}) - end - end), - Mref = erlang:monitor(process, Pid), - receive - {Ref, {error, _Reason} = Error} -> - erlang:demonitor(Mref), - receive {'DOWN', Mref, _, _, _} -> ok after 0 -> ok end, - Error; - {Ref, ok} -> - erlang:demonitor(Mref), - receive - {'DOWN', Mref, _, _, Reason} -> - {error, Reason} - after 0 -> - {ok, Pid} - end; - {'DOWN', Mref, _, _, Reason} -> - {error, Reason} - end. - -server_loop(#state{mref = Mref} = State) -> - receive - {file_request, From, ReplyAs, Request} when pid(From) -> - case file_request(Request, State) of - {reply, Reply, NewState} -> - file_reply(From, ReplyAs, Reply), - server_loop(NewState); - {error, Reply, NewState} -> - %% error is the same as reply, except that - %% it breaks the io_request_loop further down - file_reply(From, ReplyAs, Reply), - server_loop(NewState); - {stop, Reason, Reply, _NewState} -> - file_reply(From, ReplyAs, Reply), - exit(Reason) - end; - {io_request, From, ReplyAs, Request} when pid(From) -> - case io_request(Request, State) of - {reply, Reply, NewState} -> - io_reply(From, ReplyAs, Reply), - server_loop(NewState); - {error, Reply, NewState} -> - %% error is the same as reply, except that - %% it breaks the io_request_loop further down - io_reply(From, ReplyAs, Reply), - server_loop(NewState); - {stop, Reason, Reply, _NewState} -> - io_reply(From, ReplyAs, Reply), - exit(Reason) - end; - {'DOWN', Mref, _, _, Reason} -> - exit(Reason); - _ -> - server_loop(State) - end. - -file_reply(From, ReplyAs, Reply) -> - From ! {file_reply, ReplyAs, Reply}. - -io_reply(From, ReplyAs, Reply) -> - From ! {io_reply, ReplyAs, Reply}. - -%%%----------------------------------------------------------------- -%%% file requests - -file_request({pread,At,Sz}, - #state{handle=Handle,buf=Buf,read_mode=ReadMode}=State) -> - case position(Handle, At, Buf) of - {ok,_Offs} -> - case ?PRIM_FILE:read(Handle, Sz) of - {ok,Bin} when ReadMode==list -> - std_reply({ok,binary_to_list(Bin)}, State); - Reply -> - std_reply(Reply, State) - end; - Reply -> - std_reply(Reply, State) - end; -file_request({pwrite,At,Data}, - #state{handle=Handle,buf=Buf}=State) -> - case position(Handle, At, Buf) of - {ok,_Offs} -> - std_reply(?PRIM_FILE:write(Handle, Data), State); - Reply -> - std_reply(Reply, State) - end; -file_request(sync, - #state{handle=Handle}=State) -> - case ?PRIM_FILE:sync(Handle) of - {error,_}=Reply -> - {stop,normal,Reply,State}; - Reply -> - {reply,Reply,State} - end; -file_request(close, - #state{handle=Handle}=State) -> - {stop,normal,?PRIM_FILE:close(Handle),State#state{buf= <<>>}}; -file_request({position,At}, - #state{handle=Handle,buf=Buf}=State) -> - std_reply(position(Handle, At, Buf), State); -file_request(truncate, - #state{handle=Handle}=State) -> - case ?PRIM_FILE:truncate(Handle) of - {error,_Reason}=Reply -> - {stop,normal,Reply,State#state{buf= <<>>}}; - Reply -> - {reply,Reply,State} - end; -file_request(Unknown, - #state{}=State) -> - Reason = {request, Unknown}, - {error,{error,Reason},State}. - -std_reply({error,_}=Reply, State) -> - {error,Reply,State#state{buf= <<>>}}; -std_reply(Reply, State) -> - {reply,Reply,State#state{buf= <<>>}}. - -%%%----------------------------------------------------------------- -%%% I/O request - -io_request({put_chars,Chars}, % binary(Chars) new in R9C - #state{buf= <<>>}=State) -> - put_chars(Chars, State); -io_request({put_chars,Chars}, % binary(Chars) new in R9C - #state{handle=Handle,buf=Buf}=State) -> - case position(Handle, cur, Buf) of - {error,_}=Reply -> - {stop,normal,Reply,State#state{buf= <<>>}}; - _ -> - put_chars(Chars, State#state{buf= <<>>}) - end; -io_request({put_chars,Mod,Func,Args}, - #state{}=State) -> - case catch apply(Mod, Func, Args) of - Chars when list(Chars); binary(Chars) -> - io_request({put_chars,Chars}, State); - _ -> - {error,{error,Func},State} - end; -io_request({get_until,_Prompt,Mod,Func,XtraArgs}, - #state{}=State) -> - get_chars(io_lib, get_until, {Mod, Func, XtraArgs}, State); -io_request({get_chars,_Prompt,N}, % New in R9C - #state{}=State) -> - get_chars(N, State); -io_request({get_chars,_Prompt,Mod,Func,XtraArg}, % New in R9C - #state{}=State) -> - get_chars(Mod, Func, XtraArg, State); -io_request({get_line,_Prompt}, % New in R9C - #state{}=State) -> - get_chars(io_lib, collect_line, [], State); -io_request({setopts, Opts}, % New in R9C - #state{}=State) when list(Opts) -> - setopts(Opts, State); -io_request({requests,Requests}, - #state{}=State) when list(Requests) -> - io_request_loop(Requests, {reply,ok,State}); -io_request(Unknown, - #state{}=State) -> - Reason = {request,Unknown}, - {error,{error,Reason},State}. - - - -%% Process a list of requests as long as the results are ok. - -io_request_loop([], Result) -> - Result; -io_request_loop([_Request|_Tail], - {stop,_Reason,_Reply,_State}=Result) -> - Result; -io_request_loop([_Request|_Tail], - {error,_Reply,_State}=Result) -> - Result; -io_request_loop([Request|Tail], - {reply,_Reply,State}) -> - io_request_loop(Tail, io_request(Request, State)). - - - -%% I/O request put_chars -%% -put_chars(Chars, #state{handle=Handle}=State) -> - case ?PRIM_FILE:write(Handle, Chars) of - {error,_}=Reply -> - {stop,normal,Reply,State}; - Reply -> - {reply,Reply,State} - end. - - -%% Process the I/O request get_chars -%% -get_chars(0, #state{read_mode=ReadMode}=State) -> - {reply,cast(<<>>, ReadMode),State}; -get_chars(N, #state{buf=Buf,read_mode=ReadMode}=State) - when integer(N), N > 0, N =< size(Buf) -> - {B1,B2} = split_binary(Buf, N), - {reply,cast(B1, ReadMode),State#state{buf=B2}}; -get_chars(N, #state{handle=Handle,buf=Buf,read_mode=ReadMode}=State) - when integer(N), N > 0 -> - BufSize = size(Buf), - NeedSize = N-BufSize, - Size = max(NeedSize, ?READ_SIZE_BINARY), - case ?PRIM_FILE:read(Handle, Size) of - {ok, B} -> - if BufSize+size(B) < N -> - std_reply(cat(Buf, B, ReadMode), State); - true -> - {B1,B2} = split_binary(B, NeedSize), - {reply,cat(Buf, B1, ReadMode),State#state{buf=B2}} - end; - eof when BufSize==0 -> - {reply,eof,State}; - eof -> - std_reply(cast(Buf, ReadMode), State); - {error,Reason}=Error -> - {stop,Reason,Error,State#state{buf= <<>>}} - end; -get_chars(_N, #state{}=State) -> - {error,{error,get_chars},State}. - -get_chars(Mod, Func, XtraArg, #state{buf= <<>>}=State) -> - get_chars_empty(Mod, Func, XtraArg, start, State); -get_chars(Mod, Func, XtraArg, #state{buf=Buf}=State) -> - get_chars_apply(Mod, Func, XtraArg, start, State#state{buf= <<>>}, Buf). - -get_chars_empty(Mod, Func, XtraArg, S, - #state{handle=Handle,read_mode=ReadMode}=State) -> - case ?PRIM_FILE:read(Handle, read_size(ReadMode)) of - {ok,Bin} -> - get_chars_apply(Mod, Func, XtraArg, S, State, Bin); - eof -> - get_chars_apply(Mod, Func, XtraArg, S, State, eof); - {error,Reason}=Error -> - {stop,Reason,Error,State} - end. - -get_chars_apply(Mod, Func, XtraArg, S0, - #state{read_mode=ReadMode}=State, Data0) -> - Data1 = case ReadMode of - list when binary(Data0) -> binary_to_list(Data0); - _ -> Data0 - end, - case catch Mod:Func(S0, Data1, XtraArg) of - {stop,Result,Buf} -> - {reply,Result,State#state{buf=cast_binary(Buf)}}; - {'EXIT',Reason} -> - {stop,Reason,{error,err_func(Mod, Func, XtraArg)},State}; - S1 -> - get_chars_empty(Mod, Func, XtraArg, S1, State) - end. - -%% Convert error code to make it look as before -err_func(io_lib, get_until, {_,F,_}) -> - F; -err_func(_, F, _) -> - F. - - - -%% Process the I/O request setopts -%% -%% setopts -setopts(Opts0, State) -> - Opts = proplists:substitute_negations([{list,binary}], Opts0), - case proplists:get_value(binary, Opts) of - true -> - {ok,ok,State#state{read_mode=binary}}; - false -> - {ok,ok,State#state{read_mode=list}}; - _ -> - {error,{error,badarg},State} - end. - - - -%% Concatenate two binaries and convert the result to list or binary -cat(B1, B2, binary) -> - list_to_binary([B1,B2]); -cat(B1, B2, list) -> - binary_to_list(B1)++binary_to_list(B2). - -%% Cast binary to list or binary -cast(B, binary) -> - B; -cast(B, list) -> - binary_to_list(B). - -%% Convert buffer to binary -cast_binary(Binary) when binary(Binary) -> - Binary; -cast_binary(List) when list(List) -> - list_to_binary(List); -cast_binary(_EOF) -> - <<>>. - -%% Read size for different read modes -read_size(binary) -> - ?READ_SIZE_BINARY; -read_size(list) -> - ?READ_SIZE_LIST. - -max(A, B) when A >= B -> - A; -max(_, B) -> - B. - -%%%----------------------------------------------------------------- -%%% ?PRIM_FILE helpers - -%% Compensates ?PRIM_FILE:position/2 for the number of bytes -%% we have buffered - -position(Handle, cur, Buf) -> - position(Handle, {cur, 0}, Buf); -position(Handle, {cur, Offs}, Buf) when list(Buf) -> - ?PRIM_FILE:position(Handle, {cur, Offs-length(Buf)}); -position(Handle, {cur, Offs}, Buf) when binary(Buf) -> - ?PRIM_FILE:position(Handle, {cur, Offs-size(Buf)}); -position(Handle, At, _Buf) -> - ?PRIM_FILE:position(Handle, At). - From 69349925a3fc2fd76952ca779d5072eea661a433 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 6 May 2009 15:15:09 +0000 Subject: [PATCH 298/582] * src/Makefile.in: Prevent Erlang R13B compilation warning: behaviour X undefined (EJAB-920) SVN Revision: 2056 --- ChangeLog | 3 +++ src/Makefile.in | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 84d2197dc..f80e64f2f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2009-05-06 Badlop + * src/Makefile.in: Prevent Erlang R13B compilation warning: + behaviour X undefined (EJAB-920) + * src/ejabberd_loglevel.erl: Use dynamic_compile instead of ram_file_io_server. Support definition of loglevels with integer or atom. (thanks to Geoff Cant)(EJAB-919) diff --git a/src/Makefile.in b/src/Makefile.in index 1728e12f3..a64f81337 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -28,7 +28,7 @@ else CHOWN_OUTPUT=&1 endif -EFLAGS += @ERLANG_SSL39@ +EFLAGS += @ERLANG_SSL39@ -pa . # make debug=true to compile Erlang module with debug informations. ifdef debug From 1d3947c0da332b1feef0cf863ee566c42fbb211b Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 6 May 2009 16:54:43 +0000 Subject: [PATCH 299/582] Replace TYPE/1 with is_TYPE/1 (EJAB-922) SVN Revision: 2057 --- ChangeLog | 11 +++++++ src/ejabberd_c2s.erl | 2 +- src/ejabberd_logger_h.erl | 14 ++++----- src/ejabberd_s2s.erl | 2 +- src/eldap/eldap.erl | 66 +++++++++++++++++++-------------------- src/mod_offline.erl | 2 +- src/mod_offline_odbc.erl | 2 +- src/mod_roster.erl | 2 +- src/odbc/odbc_queries.erl | 2 +- src/p1_fsm.erl | 2 +- src/xml.erl | 2 +- 11 files changed, 59 insertions(+), 48 deletions(-) diff --git a/ChangeLog b/ChangeLog index f80e64f2f..bcc51d814 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 2009-05-06 Badlop + * src/ejabberd_c2s.erl: Replace TYPE/1 with is_TYPE/1 (EJAB-922) + * src/ejabberd_logger_h.erl: + * src/ejabberd_s2s.erl: + * src/eldap/eldap.erl: + * src/mod_offline.erl: + * src/mod_offline_odbc.erl: + * src/mod_roster.erl: + * src/odbc/odbc_queries.erl: + * src/p1_fsm.erl: + * src/xml.erl: + * src/Makefile.in: Prevent Erlang R13B compilation warning: behaviour X undefined (EJAB-920) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index b15ebdc1b..6183af374 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1809,7 +1809,7 @@ resend_offline_messages(#state{user = UserB, StateData#state.server, [], [UserB, ServerB]) of - Rs when list(Rs) -> + Rs when is_list(Rs) -> lists:foreach( fun({route, From, To, Packet}) -> diff --git a/src/ejabberd_logger_h.erl b/src/ejabberd_logger_h.erl index e356c649b..ce18c5e12 100644 --- a/src/ejabberd_logger_h.erl +++ b/src/ejabberd_logger_h.erl @@ -117,7 +117,7 @@ reopen_log() -> write_event(Fd, {Time, {error, _GL, {Pid, Format, Args}}}) -> T = write_time(Time), case catch io_lib:format(add_node(Format,Pid), Args) of - S when list(S) -> + S when is_list(S) -> file:write(Fd, io_lib:format(T ++ S, [])); _ -> F = add_node("ERROR: ~p - ~p~n", Pid), @@ -126,7 +126,7 @@ write_event(Fd, {Time, {error, _GL, {Pid, Format, Args}}}) -> write_event(Fd, {Time, {emulator, _GL, Chars}}) -> T = write_time(Time), case catch io_lib:format(Chars, []) of - S when list(S) -> + S when is_list(S) -> file:write(Fd, io_lib:format(T ++ S, [])); _ -> file:write(Fd, io_lib:format(T ++ "ERROR: ~p ~n", [Chars])) @@ -145,7 +145,7 @@ write_event(Fd, {Time, {info_report, _GL, {Pid, std_info, Rep}}}) -> write_event(Fd, {Time, {info_msg, _GL, {Pid, Format, Args}}}) -> T = write_time(Time, "INFO REPORT"), case catch io_lib:format(add_node(Format,Pid), Args) of - S when list(S) -> + S when is_list(S) -> file:write(Fd, io_lib:format(T ++ S, [])); _ -> F = add_node("ERROR: ~p - ~p~n", Pid), @@ -154,7 +154,7 @@ write_event(Fd, {Time, {info_msg, _GL, {Pid, Format, Args}}}) -> write_event(_, _) -> ok. -format_report(Rep) when list(Rep) -> +format_report(Rep) when is_list(Rep) -> case string_p(Rep) of true -> io_lib:format("~s~n",[Rep]); @@ -171,7 +171,7 @@ format_rep([Other|Rep]) -> format_rep(_) -> []. -add_node(X, Pid) when atom(X) -> +add_node(X, Pid) when is_atom(X) -> add_node(atom_to_list(X), Pid); add_node(X, Pid) when node(Pid) /= node() -> lists:concat([X,"** at node ",node(Pid)," **~n"]); @@ -183,7 +183,7 @@ string_p([]) -> string_p(Term) -> string_p1(Term). -string_p1([H|T]) when integer(H), H >= $\s, H < 255 -> +string_p1([H|T]) when is_integer(H), H >= $\s, H < 255 -> string_p1(T); string_p1([$\n|T]) -> string_p1(T); string_p1([$\r|T]) -> string_p1(T); @@ -192,7 +192,7 @@ string_p1([$\v|T]) -> string_p1(T); string_p1([$\b|T]) -> string_p1(T); string_p1([$\f|T]) -> string_p1(T); string_p1([$\e|T]) -> string_p1(T); -string_p1([H|T]) when list(H) -> +string_p1([H|T]) when is_list(H) -> case string_p1(H) of true -> string_p1(T); _ -> false diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index 139e0f8c9..e25566d75 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -277,7 +277,7 @@ do_route(From, To, Packet) -> ?DEBUG("s2s manager~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n", [From, To, Packet, 8]), case find_connection(From, To) of - {atomic, Pid} when pid(Pid) -> + {atomic, Pid} when is_pid(Pid) -> ?DEBUG("sending to process ~p~n", [Pid]), NewPacket1 = exmpp_stanza:set_sender(Packet, From), NewPacket = exmpp_stanza:set_recipient(NewPacket1, To), diff --git a/src/eldap/eldap.erl b/src/eldap/eldap.erl index 412a66862..5d7652fcc 100644 --- a/src/eldap/eldap.erl +++ b/src/eldap/eldap.erl @@ -143,14 +143,14 @@ close(Handle) -> %%% {"telephoneNumber", ["545 555 00"]}] %%% ) %%% -------------------------------------------------------------------- -add(Handle, Entry, Attributes) when list(Entry),list(Attributes) -> +add(Handle, Entry, Attributes) when is_list(Entry), is_list(Attributes) -> Handle1 = get_handle(Handle), gen_fsm:sync_send_event(Handle1, {add, Entry, add_attrs(Attributes)}, ?CALL_TIMEOUT). %%% Do sanity check ! add_attrs(Attrs) -> - F = fun({Type,Vals}) when list(Type),list(Vals) -> + F = fun({Type,Vals}) when is_list(Type), is_list(Vals) -> %% Confused ? Me too... :-/ {'AddRequest_attributes',Type, Vals} end, @@ -169,7 +169,7 @@ add_attrs(Attrs) -> %%% "cn=Bill Valentine, ou=people, o=Bluetail AB, dc=bluetail, dc=com" %%% ) %%% -------------------------------------------------------------------- -delete(Handle, Entry) when list(Entry) -> +delete(Handle, Entry) when is_list(Entry) -> Handle1 = get_handle(Handle), gen_fsm:sync_send_event(Handle1, {delete, Entry}, ?CALL_TIMEOUT). @@ -184,7 +184,7 @@ delete(Handle, Entry) when list(Entry) -> %%% add("description", ["LDAP hacker"])] %%% ) %%% -------------------------------------------------------------------- -modify(Handle, Object, Mods) when list(Object), list(Mods) -> +modify(Handle, Object, Mods) when is_list(Object), is_list(Mods) -> Handle1 = get_handle(Handle), gen_fsm:sync_send_event(Handle1, {modify, Object, Mods}, ?CALL_TIMEOUT). @@ -193,9 +193,9 @@ modify(Handle, Object, Mods) when list(Object), list(Mods) -> %%% Example: %%% replace("telephoneNumber", ["555 555 00"]) %%% -mod_add(Type, Values) when list(Type), list(Values) -> m(add, Type, Values). -mod_delete(Type, Values) when list(Type), list(Values) -> m(delete, Type, Values). -mod_replace(Type, Values) when list(Type), list(Values) -> m(replace, Type, Values). +mod_add(Type, Values) when is_list(Type), is_list(Values) -> m(add, Type, Values). +mod_delete(Type, Values) when is_list(Type), is_list(Values) -> m(delete, Type, Values). +mod_replace(Type, Values) when is_list(Type), is_list(Values) -> m(replace, Type, Values). m(Operation, Type, Values) -> #'ModifyRequest_modification_SEQOF'{ @@ -217,7 +217,7 @@ m(Operation, Type, Values) -> %%% ) %%% -------------------------------------------------------------------- modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup) - when list(Entry),list(NewRDN),atom(DelOldRDN),list(NewSup) -> + when is_list(Entry), is_list(NewRDN), is_atom(DelOldRDN), is_list(NewSup) -> Handle1 = get_handle(Handle), gen_fsm:sync_send_event( Handle1, @@ -234,7 +234,7 @@ modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup) %%% "secret") %%% -------------------------------------------------------------------- bind(Handle, RootDN, Passwd) - when list(RootDN),list(Passwd) -> + when is_list(RootDN), is_list(Passwd) -> Handle1 = get_handle(Handle), gen_fsm:sync_send_event(Handle1, {bind, RootDN, Passwd}, ?CALL_TIMEOUT). @@ -270,13 +270,13 @@ optional(Value) -> Value. %%% []}} %%% %%% -------------------------------------------------------------------- -search(Handle, A) when record(A, eldap_search) -> +search(Handle, A) when is_record(A, eldap_search) -> call_search(Handle, A); -search(Handle, L) when list(L) -> +search(Handle, L) when is_list(L) -> case catch parse_search_args(L) of {error, Emsg} -> {error, Emsg}; {'EXIT', Emsg} -> {error, Emsg}; - A when record(A, eldap_search) -> call_search(Handle, A) + A when is_record(A, eldap_search) -> call_search(Handle, A) end. call_search(Handle, A) -> @@ -296,7 +296,7 @@ parse_search_args([{attributes, Attrs}|T],A) -> parse_search_args(T,A#eldap_search{attributes = Attrs}); parse_search_args([{types_only, TypesOnly}|T],A) -> parse_search_args(T,A#eldap_search{types_only = TypesOnly}); -parse_search_args([{timeout, Timeout}|T],A) when integer(Timeout) -> +parse_search_args([{timeout, Timeout}|T],A) when is_integer(Timeout) -> parse_search_args(T,A#eldap_search{timeout = Timeout}); parse_search_args([{limit, Limit}|T],A) when is_integer(Limit) -> parse_search_args(T,A#eldap_search{limit = Limit}); @@ -315,9 +315,9 @@ wholeSubtree() -> wholeSubtree. %%% %%% Boolean filter operations %%% -'and'(ListOfFilters) when list(ListOfFilters) -> {'and',ListOfFilters}. -'or'(ListOfFilters) when list(ListOfFilters) -> {'or', ListOfFilters}. -'not'(Filter) when tuple(Filter) -> {'not',Filter}. +'and'(ListOfFilters) when is_list(ListOfFilters) -> {'and',ListOfFilters}. +'or'(ListOfFilters) when is_list(ListOfFilters) -> {'or', ListOfFilters}. +'not'(Filter) when is_tuple(Filter) -> {'not',Filter}. %%% %%% The following Filter parameters consist of an attribute @@ -335,7 +335,7 @@ av_assert(Desc, Value) -> %%% %%% Filter to check for the presence of an attribute %%% -present(Attribute) when list(Attribute) -> +present(Attribute) when is_list(Attribute) -> {present, Attribute}. @@ -354,15 +354,15 @@ present(Attribute) when list(Attribute) -> %%% Example: substrings("sn",[{initial,"To"},{any,"kv"},{final,"st"}]) %%% will match entries containing: 'sn: Tornkvist' %%% -substrings(Type, SubStr) when list(Type), list(SubStr) -> +substrings(Type, SubStr) when is_list(Type), is_list(SubStr) -> Ss = {'SubstringFilter_substrings',v_substr(SubStr)}, {substrings,#'SubstringFilter'{type = Type, substrings = Ss}}. -get_handle(Pid) when pid(Pid) -> Pid; -get_handle(Atom) when atom(Atom) -> Atom; -get_handle(Name) when list(Name) -> list_to_atom("eldap_" ++ Name). +get_handle(Pid) when is_pid(Pid) -> Pid; +get_handle(Atom) when is_atom(Atom) -> Atom; +get_handle(Name) when is_list(Name) -> list_to_atom("eldap_" ++ Name). %%%---------------------------------------------------------------------- %%% Callback functions from gen_fsm %%%---------------------------------------------------------------------- @@ -835,7 +835,7 @@ cmd_timeout(Timer, Id, S) -> polish(Entries) -> polish(Entries, [], []). -polish([H|T], Res, Ref) when record(H, 'SearchResultEntry') -> +polish([H|T], Res, Ref) when is_record(H, 'SearchResultEntry') -> ObjectName = H#'SearchResultEntry'.objectName, F = fun({_,A,V}) -> {A,V} end, Attrs = lists:map(F, H#'SearchResultEntry'.attributes), @@ -913,7 +913,7 @@ v_filter({greaterOrEqual,AV}) -> {greaterOrEqual,AV}; v_filter({lessOrEqual,AV}) -> {lessOrEqual,AV}; v_filter({approxMatch,AV}) -> {approxMatch,AV}; v_filter({present,A}) -> {present,A}; -v_filter({substrings,S}) when record(S,'SubstringFilter') -> {substrings,S}; +v_filter({substrings,S}) when is_record(S,'SubstringFilter') -> {substrings,S}; v_filter(_Filter) -> throw({error,concat(["unknown filter: ",_Filter])}). v_modifications(Mods) -> @@ -925,7 +925,7 @@ v_modifications(Mods) -> end, lists:foreach(F, Mods). -v_substr([{Key,Str}|T]) when list(Str),Key==initial;Key==any;Key==final -> +v_substr([{Key,Str}|T]) when is_list(Str),Key==initial;Key==any;Key==final -> [{Key,Str}|v_substr(T)]; v_substr([H|_]) -> throw({error,{substring_arg,H}}); @@ -940,11 +940,11 @@ v_bool(true) -> true; v_bool(false) -> false; v_bool(_Bool) -> throw({error,concat(["not Boolean: ",_Bool])}). -v_timeout(I) when integer(I), I>=0 -> I; +v_timeout(I) when is_integer(I), I>=0 -> I; v_timeout(_I) -> throw({error,concat(["timeout not positive integer: ",_I])}). v_attributes(Attrs) -> - F = fun(A) when list(A) -> A; + F = fun(A) when is_list(A) -> A; (A) -> throw({error,concat(["attribute not String: ",A])}) end, lists:map(F,Attrs). @@ -979,7 +979,7 @@ parse(Entries) -> get_integer(Key, List) -> case lists:keysearch(Key, 1, List) of - {value, {Key, Value}} when integer(Value) -> + {value, {Key, Value}} when is_integer(Value) -> Value; {value, {Key, _Value}} -> throw({error, "Bad Value in Config for " ++ atom_to_list(Key)}); @@ -989,7 +989,7 @@ get_integer(Key, List) -> get_list(Key, List) -> case lists:keysearch(Key, 1, List) of - {value, {Key, Value}} when list(Value) -> + {value, {Key, Value}} when is_list(Value) -> Value; {value, {Key, _Value}} -> throw({error, "Bad Value in Config for " ++ atom_to_list(Key)}); @@ -998,13 +998,13 @@ get_list(Key, List) -> end. get_hosts(Key, List) -> - lists:map(fun({Key1, {A,B,C,D}}) when integer(A), - integer(B), - integer(C), - integer(D), + lists:map(fun({Key1, {A,B,C,D}}) when is_integer(A), + is_integer(B), + is_integer(C), + is_integer(D), Key == Key1-> {A,B,C,D}; - ({Key1, Value}) when list(Value), + ({Key1, Value}) when is_list(Value), Key == Key1-> Value; ({_Else, _Value}) -> diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 80342c8e7..8ef6507a0 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -87,7 +87,7 @@ start(Host, Opts) -> init(infinity) -> loop(infinity); init(MaxOfflineMsgs) - when integer(MaxOfflineMsgs), MaxOfflineMsgs > 0 -> + when is_integer(MaxOfflineMsgs), MaxOfflineMsgs > 0 -> loop(MaxOfflineMsgs). loop(MaxOfflineMsgs) -> diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index 047388e57..e0a35b7dd 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -81,7 +81,7 @@ start(Host, Opts) -> init(Host, infinity) -> loop(Host, infinity); init(Host, MaxOfflineMsgs) - when integer(MaxOfflineMsgs), MaxOfflineMsgs > 0 -> + when is_integer(MaxOfflineMsgs), MaxOfflineMsgs > 0 -> loop(Host, MaxOfflineMsgs). loop(Host, MaxOfflineMsgs) -> diff --git a/src/mod_roster.erl b/src/mod_roster.erl index be4afd098..38c6ffb05 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -846,7 +846,7 @@ get_in_pending_subscriptions(Ls, User, Server) JID = exmpp_jid:make_jid(User, Server), US = {exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID)}, case mnesia:dirty_index_read(roster, US, #roster.us) of - Result when list(Result) -> + Result when is_list(Result) -> Ls ++ lists:map( fun(R) -> Message = R#roster.askmessage, diff --git a/src/odbc/odbc_queries.erl b/src/odbc/odbc_queries.erl index b878184a8..ef1f59218 100644 --- a/src/odbc/odbc_queries.erl +++ b/src/odbc/odbc_queries.erl @@ -652,7 +652,7 @@ get_and_del_spool_msg_t(LServer, Username) -> [Result] = case ejabberd_odbc:sql_query( LServer, ["EXECUTE dbo.get_and_del_spool_msg '", Username, "'"]) of - Rs when list(Rs) -> + Rs when is_list(Rs) -> lists:filter(fun({selected, _Header, _Row}) -> true; ({updated, _N}) -> diff --git a/src/p1_fsm.erl b/src/p1_fsm.erl index 40ae33465..c4de9faa4 100644 --- a/src/p1_fsm.erl +++ b/src/p1_fsm.erl @@ -663,7 +663,7 @@ limit_options([], Limits) -> Limits; %% Maximum number of messages allowed in the process message queue limit_options([{max_queue,N}|Options], Limits) - when integer(N) -> + when is_integer(N) -> NewLimits = Limits#limits{max_queue=N}, limit_options(Options, NewLimits); limit_options([_|Options], Limits) -> diff --git a/src/xml.erl b/src/xml.erl index c55ca0d6e..19813278a 100644 --- a/src/xml.erl +++ b/src/xml.erl @@ -58,7 +58,7 @@ element_to_string(El) -> [$<, Name, attrs_to_list(Attrs), $/, $>] end; %% We do not crypt CDATA binary, but we enclose it in XML CDATA - {xmlcdata, CData} when binary(CData) -> + {xmlcdata, CData} when is_binary(CData) -> ?ESCAPE_BINARY(CData); %% We crypt list and possibly binaries if full XML usage is %% disabled unsupported (implies a conversion to list). From e40e4298ca6bebdb8a64fd3e0efdbc0496c4a550 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 7 May 2009 00:54:44 +0000 Subject: [PATCH 300/582] several pubsub fixes and improvements. also fixes EJAB-913 and EJAB-871 SVN Revision: 2061 --- ChangeLog | 35 ++++++ src/mod_caps.erl | 7 +- src/mod_pubsub/gen_pubsub_node.erl | 2 +- src/mod_pubsub/mod_pubsub.erl | 177 ++++++++++++++++------------ src/mod_pubsub/node.template | 6 +- src/mod_pubsub/node_buddy.erl | 6 +- src/mod_pubsub/node_club.erl | 6 +- src/mod_pubsub/node_default.erl | 28 +++-- src/mod_pubsub/node_dispatch.erl | 4 +- src/mod_pubsub/node_flat.erl | 6 +- src/mod_pubsub/node_mb.erl | 6 +- src/mod_pubsub/node_pep.erl | 6 +- src/mod_pubsub/node_private.erl | 6 +- src/mod_pubsub/node_public.erl | 6 +- src/mod_pubsub/nodetree_default.erl | 1 + 15 files changed, 184 insertions(+), 118 deletions(-) diff --git a/ChangeLog b/ChangeLog index bcc51d814..cb153b056 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,38 @@ +2009-05-07 Christophe Romain + + * src/mod_caps.erl: Set debug message to DEBUG (from debian patch, + thanks to Sergei Golovan) + + * src/mod_pubsub/mod_pubsub.erl: Remove subscriptions when anonymous + user removed (EJAB-913) (thanks to Andy Skelton) + + * src/mod_pubsub/mod_pubsub.erl: Fix disco#items bug on root node, + and fix other minor typo from previous patch. + + * src/mod_pubsub/mod_pubsub.erl: Avoid calling get_user_resources + on non local domain when pep_sendlast_offline is enabled + + * src/mod_pubsub/mod_pubsub.erl: Reduce send_last_item load and number + of calls to get_caps + + * src/mod_pubsub/mod_pubsub.erl: Fix get_entity_* not returning node + * src/mod_pubsub/node_default.erl: Likewise + * src/mod_pubsub/nodetree_default.erl: Likewise + + * src/mod_pubsub/mod_pubsub.erl: Retract policy should obey + pubsub#publish_model (EJAB-871) (thanks to Matthew Baron) + * src/mod_pubsub/node_default.erl: Likewise + * src/mod_pubsub/node_mb.erl: Likewise + * src/mod_pubsub/node_dispatch.erl: Likewise + * src/mod_pubsub/node_buddy.erl: Likewise + * src/mod_pubsub/node_private.erl: Likewise + * src/mod_pubsub/node_public.erl: Likewise + * src/mod_pubsub/node_default.erl: Likewise + * src/mod_pubsub/node_pep.erl: Likewise + * src/mod_pubsub/node_club.erl: Likewise + * src/mod_pubsub/node_flat.erl: Likewise + * src/mod_pubsub/node.template: Likewise + 2009-05-06 Badlop * src/ejabberd_c2s.erl: Replace TYPE/1 with is_TYPE/1 (EJAB-922) diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 3b95cfd22..532cc8fa1 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -192,9 +192,6 @@ receive_packet(_, _, _) -> receive_packet(_JID, From, To, Packet) -> receive_packet(From, To, Packet). -jid_to_binary(JID) -> - list_to_binary(jlib:jid_to_string(JID)). - caps_to_binary(#caps{node = Node, version = Version, exts = Exts}) -> BExts = [list_to_binary(Ext) || Ext <- Exts], #caps{node = list_to_binary(Node), version = list_to_binary(Version), exts = BExts}. @@ -330,7 +327,7 @@ handle_cast({disco_response, From, _To, #iq{id = ID, type = Type, payload = Payl mnesia:dirty_write(#caps_features{node_pair = BinaryNode, features = features_to_binary(Features)}), gen_server:cast(self(), visit_feature_queries); error -> - ?ERROR_MSG("ID '~s' matches no query", [ID]) + ?DEBUG("ID '~s' matches no query", [ID]) end; {error, _} -> %% XXX: if we get error, we cache empty feature not to probe the client continuously @@ -339,7 +336,7 @@ handle_cast({disco_response, From, _To, #iq{id = ID, type = Type, payload = Payl mnesia:dirty_write(#caps_features{node_pair = BinaryNode}), gen_server:cast(self(), visit_feature_queries); error -> - ?ERROR_MSG("ID '~s' matches no query", [ID]) + ?DEBUG("ID '~s' matches no query", [ID]) end; %gen_server:cast(self(), visit_feature_queries), %?DEBUG("Error IQ reponse from ~s:~n~p", [exmpp_jid:jid_to_list(From), SubEls]); diff --git a/src/mod_pubsub/gen_pubsub_node.erl b/src/mod_pubsub/gen_pubsub_node.erl index b4264f809..78256cd56 100644 --- a/src/mod_pubsub/gen_pubsub_node.erl +++ b/src/mod_pubsub/gen_pubsub_node.erl @@ -49,7 +49,7 @@ behaviour_info(callbacks) -> {subscribe_node, 7}, {unsubscribe_node, 4}, {publish_item, 6}, - {delete_item, 3}, + {delete_item, 4}, {remove_extra_items, 3}, {get_node_affiliations, 1}, {get_entity_affiliations, 2}, diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 45c8212a6..02fc6b12d 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -181,6 +181,7 @@ init([ServerHost, Opts]) -> ejabberd_hooks:add(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50), ejabberd_hooks:add(roster_out_subscription, ServerHostB, ?MODULE, out_subscription, 50), ejabberd_hooks:add(remove_user, ServerHostB, ?MODULE, remove_user, 50), + ejabberd_hooks:add(anonymous_purge_hook, ServerHostB, ?MODULE, remove_user, 50), gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB, ?MODULE, iq_sm, IQDisc), gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB_OWNER, ?MODULE, iq_sm, IQDisc), ejabberd_router:register_route(Host), @@ -411,69 +412,89 @@ send_loop(State) -> %% and is not able to "store" events of remote users (via s2s) %% this makes that hack only work for local domain by now if State#state.pep_sendlast_offline -> - case catch ejabberd_c2s:get_subscribed(Pid) of - Contacts when is_list(Contacts) -> - {User, Server, Resource} = LJID, - lists:foreach( - fun({U, S, R}) -> %% local contacts - case ejabberd_sm:get_user_resources(U, S) of - [] -> %% offline - case S of - ServerHost -> %% local contact, so we may have pep items - PeerJID = exmpp_jlib:make_jid(U, S, R), - self() ! {presence, User, Server, [Resource], PeerJID}; - _ -> %% remote contact, no items available - ok - end; - _ -> %% online - % this is already handled by presence probe - ok - end; - (_) -> %% remote contacts - % we can not do anything in any cases - ok - end, Contacts); + {User, Server, Resource} = LJID, + case mod_caps:get_caps({User, Server, Resource}) of + nothing -> + %% we don't have caps, no need to handle PEP items + ok; _ -> - ok + case catch ejabberd_c2s:get_subscribed(Pid) of + Contacts when is_list(Contacts) -> + lists:foreach( + fun({U, S, R}) -> + case S of + ServerHost -> %% local contacts + case ejabberd_sm:get_user_resources(U, S) of + [] -> %% offline + PeerJID = exmpp_jlib:make_jid(U, S, R), + self() ! {presence, User, Server, [Resource], PeerJID}; + _ -> %% online + % this is already handled by presence probe + ok + end; + _ -> %% remote contacts + % we can not do anything in any cases + ok + end + end, Contacts); + _ -> + ok + end end; true -> ok end, send_loop(State); {presence, User, Server, Resources, JID} -> - Owner = jlib:short_prepd_bare_jid(JID), - Host = State#state.host, - ServerHost = State#state.server_host, - lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = NodeId, options = Options}) -> - case get_option(Options, send_last_published_item) of - on_sub_and_presence -> - lists:foreach(fun(Resource) -> - LJID = {User, Server, Resource}, - case is_caps_notify(ServerHost, Node, LJID) of - true -> - Subscribed = case get_option(Options, access_model) of - open -> true; - presence -> true; - whitelist -> false; % subscribers are added manually - authorize -> false; % likewise - roster -> - Grps = get_option(Options, roster_groups_allowed, []), - {OU, OS, _} = Owner, - element(2, get_roster_info(OU, OS, LJID, Grps)) - end, - if Subscribed -> - send_items(Owner, Node, NodeId, Type, LJID, last); - true -> - ok - end; - false -> - ok - end - end, Resources); - _ -> - ok - end - end, tree_action(Host, get_nodes, [Owner, JID])), + %% get resources caps and check if processing is needed + {HasCaps, ResourcesCaps} = lists:foldl(fun(Resource, {R, L}) -> + case mod_caps:get_caps({User, Server, Resource}) of + nothing -> {R, L}; + Caps -> {true, [{Resource, Caps} | L]} + end + end, {false, []}, Resources), + case HasCaps of + true -> + Host = State#state.host, + ServerHost = State#state.server_host, + Owner = jlib:short_prepd_bare_jid(JID), + lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = NodeId, options = Options}) -> + case get_option(Options, send_last_published_item) of + on_sub_and_presence -> + lists:foreach(fun({Resource, Caps}) -> + CapsNotify = case catch mod_caps:get_features(ServerHost, Caps) of + Features when is_list(Features) -> lists:member(Node ++ "+notify", Features); + _ -> false + end, + case CapsNotify of + true -> + LJID = {User, Server, Resource}, + Subscribed = case get_option(Options, access_model) of + open -> true; + presence -> true; + whitelist -> false; % subscribers are added manually + authorize -> false; % likewise + roster -> + Grps = get_option(Options, roster_groups_allowed, []), + {OU, OS, _} = Owner, + element(2, get_roster_info(OU, OS, LJID, Grps)) + end, + if Subscribed -> + send_items(Owner, Node, NodeId, Type, LJID, last); + true -> + ok + end; + false -> + ok + end + end, ResourcesCaps); + _ -> + ok + end + end, tree_action(Host, get_nodes, [Owner, JID])); + false -> + ok + end, send_loop(State); stop -> ok @@ -539,7 +560,7 @@ disco_sm_items(Acc, From, To, <<>>, _Lang) -> %% TODO, use iq_disco_items(Host, [], From) Host = exmpp_jid:ldomain_as_list(To), LJID = jlib:short_prepd_bare_jid(To), - case tree_action(Host, get_nodes, [Host, From]) of + case tree_action(Host, get_subnodes, [Host, [], From]) of [] -> Acc; Nodes -> @@ -684,7 +705,7 @@ handle_cast({remove_user, LUser, LServer}, State) -> %% remove user's PEP nodes lists:foreach(fun(#pubsub_node{nodeid={NodeKey, NodeName}}) -> delete_node(NodeKey, NodeName, Owner) - end, tree_action(Host, get_nodes, [jlib:short_prepd_bare_jid(Owner)])), + end, tree_action(Host, get_nodes, [jlib:short_prepd_bare_jid(Owner), Owner])), %% remove user's nodes delete_node(Host, ["home", LServer, LUser], Owner), {noreply, State}; @@ -724,7 +745,6 @@ terminate(_Reason, #state{host = Host, nodetree = TreePlugin, plugins = Plugins, send_loop = SendLoop}) -> - terminate_plugins(Host, ServerHost, Plugins, TreePlugin), ejabberd_router:unregister_route(Host), ServerHostB = list_to_binary(ServerHost), case lists:member(?PEPNODE, Plugins) of @@ -746,11 +766,12 @@ terminate(_Reason, #state{host = Host, ejabberd_hooks:delete(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50), ejabberd_hooks:delete(roster_out_subscription, ServerHostB, ?MODULE, out_subscription, 50), ejabberd_hooks:delete(remove_user, ServerHostB, ?MODULE, remove_user, 50), + ejabberd_hooks:delete(anonymous_purge_hook, ServerHostB, ?MODULE, remove_user, 50), gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB), gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB_OWNER), mod_disco:unregister_feature(ServerHost, ?NS_PUBSUB_s), SendLoop ! stop, - ok. + terminate_plugins(Host, ServerHost, Plugins, TreePlugin). %%-------------------------------------------------------------------- %% Func: code_change(OldVsn, State, Extra) -> {ok, NewState} @@ -1757,23 +1778,24 @@ delete_item(_, "", _, _, _) -> %% Request does not specify a node {error, extended_error('bad-request', "node-required")}; delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> - Action = fun(#pubsub_node{type = Type, id = NodeId}) -> - Features = features(Type), - PersistentFeature = lists:member("persistent-items", Features), - DeleteFeature = lists:member("delete-items", Features), - if - %%-> iq_pubsub just does that matchs - %% %% Request does not specify an item - %% {error, extended_error('bad-request', "item-required")}; - not PersistentFeature -> - %% Node does not support persistent items - {error, extended_error('feature-not-implemented', unsupported, "persistent-items")}; - not DeleteFeature -> - %% Service does not support item deletion - {error, extended_error('feature-not-implemented', unsupported, "delete-items")}; - true -> - node_call(Type, delete_item, [NodeId, Publisher, ItemId]) - end + Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> + Features = features(Type), + PersistentFeature = lists:member("persistent-items", Features), + DeleteFeature = lists:member("delete-items", Features), + PublishModel = get_option(Options, publish_model), + if + %%-> iq_pubsub just does that matchs + %% %% Request does not specify an item + %% {error, extended_error('bad-request', "item-required")}; + not PersistentFeature -> + %% Node does not support persistent items + {error, extended_error('feature-not-implemented', unsupported, "persistent-items")}; + not DeleteFeature -> + %% Service does not support item deletion + {error, extended_error('feature-not-implemented', unsupported, "delete-items")}; + true -> + node_call(Type, delete_item, [NodeId, Publisher, PublishModel, ItemId]) + end end, Reply = [], case transaction(Host, Node, Action, sync_dirty) of @@ -1916,6 +1938,7 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> %% @spec (Host, Node, NodeId, Type, LJID, Number) -> any() %% Host = host() +%% Node = pubsubNode() %% NodeId = pubsubNodeId() %% Type = pubsubNodeType() %% LJID = {U, S, []} diff --git a/src/mod_pubsub/node.template b/src/mod_pubsub/node.template index d4fffc474..3151877f5 100644 --- a/src/mod_pubsub/node.template +++ b/src/mod_pubsub/node.template @@ -47,7 +47,7 @@ subscribe_node/7, unsubscribe_node/4, publish_item/6, - delete_item/3, + delete_item/4, remove_extra_items/3, get_entity_affiliations/2, get_node_affiliations/1, @@ -129,8 +129,8 @@ publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> remove_extra_items(NodeId, MaxItems, ItemIds) -> node_default:remove_extra_items(NodeId, MaxItems, ItemIds). -delete_item(NodeId, JID, ItemId) -> - node_default:delete_item(NodeId, JID, ItemId). +delete_item(NodeId, Publisher, PublishModel, ItemId) -> + node_default:delete_item(NodeId, Publisher, PublishModel, ItemId). purge_node(NodeId, Owner) -> node_default:purge_node(NodeId, Owner). diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl index b963fba20..d52121c9c 100644 --- a/src/mod_pubsub/node_buddy.erl +++ b/src/mod_pubsub/node_buddy.erl @@ -50,7 +50,7 @@ subscribe_node/7, unsubscribe_node/4, publish_item/6, - delete_item/3, + delete_item/4, remove_extra_items/3, get_entity_affiliations/2, get_node_affiliations/1, @@ -134,8 +134,8 @@ publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> remove_extra_items(NodeId, MaxItems, ItemIds) -> node_default:remove_extra_items(NodeId, MaxItems, ItemIds). -delete_item(NodeId, JID, ItemId) -> - node_default:delete_item(NodeId, JID, ItemId). +delete_item(NodeId, Publisher, PublishModel, ItemId) -> + node_default:delete_item(NodeId, Publisher, PublishModel, ItemId). purge_node(NodeId, Owner) -> node_default:purge_node(NodeId, Owner). diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl index 1e3900cc0..49d7a99fd 100644 --- a/src/mod_pubsub/node_club.erl +++ b/src/mod_pubsub/node_club.erl @@ -50,7 +50,7 @@ subscribe_node/7, unsubscribe_node/4, publish_item/6, - delete_item/3, + delete_item/4, remove_extra_items/3, get_entity_affiliations/2, get_node_affiliations/1, @@ -133,8 +133,8 @@ publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> remove_extra_items(NodeId, MaxItems, ItemIds) -> node_default:remove_extra_items(NodeId, MaxItems, ItemIds). -delete_item(NodeId, JID, ItemId) -> - node_default:delete_item(NodeId, JID, ItemId). +delete_item(NodeId, Publisher, PublishModel, ItemId) -> + node_default:delete_item(NodeId, Publisher, PublishModel, ItemId). purge_node(NodeId, Owner) -> node_default:purge_node(NodeId, Owner). diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index be4f3ebfa..21c20770e 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -57,7 +57,7 @@ subscribe_node/7, unsubscribe_node/4, publish_item/6, - delete_item/3, + delete_item/4, remove_extra_items/3, get_entity_affiliations/2, get_node_affiliations/1, @@ -484,22 +484,24 @@ remove_extra_items(NodeId, MaxItems, ItemIds) -> %% Return the new items list: {result, {NewItems, OldItems}}. -%% @spec (NodeId, JID, ItemId) -> +%% @spec (NodeId, Publisher, PublishModel, ItemId) -> %% {error, Reason::stanzaError()} | %% {result, []} %% NodeId = mod_pubsub:pubsubNodeId() -%% JID = mod_pubsub:jid() +%% Publisher = mod_pubsub:jid() +%% PublishModel = atom() %% ItemId = string() %% @doc

    Triggers item deletion.

    %%

    Default plugin: The user performing the deletion must be the node owner %% or a publisher.

    -delete_item(NodeId, Publisher, ItemId) -> +delete_item(NodeId, Publisher, PublishModel, ItemId) -> GenKey = jlib:short_prepd_bare_jid(Publisher), GenState = get_state(NodeId, GenKey), #pubsub_state{affiliation = Affiliation, items = Items} = GenState, Allowed = (Affiliation == publisher) orelse (Affiliation == owner) + orelse (PublishModel == open) orelse case get_item(NodeId, ItemId) of - {result, #pubsub_item{creation = {GenKey, _}}} -> true; + {result, #pubsub_item{creation = {_, GenKey}}} -> true; _ -> false end, if @@ -552,14 +554,14 @@ get_entity_affiliations(_Host, Owner) -> States = mnesia:match_object( #pubsub_state{stateid = {GenKey, '_'}, _ = '_'}), Tr = fun(#pubsub_state{stateid = {_, N}, affiliation = A}) -> - {N, A} + {get_nodename(N), A} end, {result, lists:map(Tr, States)}. get_node_affiliations(NodeId) -> {result, States} = get_states(NodeId), Tr = fun(#pubsub_state{stateid = {J, {_, _}}, affiliation = A}) -> - {J, A} + {J, A} end, {result, lists:map(Tr, States)}. @@ -600,14 +602,14 @@ get_entity_subscriptions(_Host, Owner) -> #pubsub_state{stateid = {SubKey, '_'}, _ = '_'}) end, Tr = fun(#pubsub_state{stateid = {J, N}, subscription = S}) -> - {N, S, J} + {get_nodename(N), S, J} end, {result, lists:map(Tr, States)}. get_node_subscriptions(NodeId) -> {result, States} = get_states(NodeId), Tr = fun(#pubsub_state{stateid = {J, _}, subscription = S}) -> - {J, S} + {J, S} end, {result, lists:map(Tr, States)}. @@ -805,3 +807,11 @@ can_fetch_item(outcast, _) -> false; can_fetch_item(none, subscribed) -> true; can_fetch_item(none, none) -> false; can_fetch_item(_Affiliation, _Subscription) -> false. + +%% @spec (NodeId) -> Node +%% @doc retreive pubsubNode() representation giving a NodeId +get_nodename(NodeId) -> + case mnesia:index_read(pubsub_node, NodeId, #pubsub_node.id) of + [#pubsub_node{nodeid = {_, Node}}] -> Node; + _ -> [] + end. diff --git a/src/mod_pubsub/node_dispatch.erl b/src/mod_pubsub/node_dispatch.erl index d5b379844..f1d356fdd 100644 --- a/src/mod_pubsub/node_dispatch.erl +++ b/src/mod_pubsub/node_dispatch.erl @@ -48,7 +48,7 @@ subscribe_node/7, unsubscribe_node/4, publish_item/6, - delete_item/3, + delete_item/4, remove_extra_items/3, get_entity_affiliations/2, get_node_affiliations/1, @@ -135,7 +135,7 @@ publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> remove_extra_items(_NodeId, _MaxItems, ItemIds) -> {result, {ItemIds, []}}. -delete_item(_NodeId, _JID, _ItemId) -> +delete_item(_NodeId, _Publisher, _PublishModel, _ItemId) -> {error, 'item-not-found'}. purge_node(_NodeId, _Owner) -> diff --git a/src/mod_pubsub/node_flat.erl b/src/mod_pubsub/node_flat.erl index 8fb33e447..8120f3787 100644 --- a/src/mod_pubsub/node_flat.erl +++ b/src/mod_pubsub/node_flat.erl @@ -41,7 +41,7 @@ subscribe_node/7, unsubscribe_node/4, publish_item/6, - delete_item/3, + delete_item/4, remove_extra_items/3, get_entity_affiliations/2, get_node_affiliations/1, @@ -121,8 +121,8 @@ publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> remove_extra_items(NodeId, MaxItems, ItemIds) -> node_default:remove_extra_items(NodeId, MaxItems, ItemIds). -delete_item(NodeId, JID, ItemId) -> - node_default:delete_item(NodeId, JID, ItemId). +delete_item(NodeId, Publisher, PublishModel, ItemId) -> + node_default:delete_item(NodeId, Publisher, PublishModel, ItemId). purge_node(NodeId, Owner) -> node_default:purge_node(NodeId, Owner). diff --git a/src/mod_pubsub/node_mb.erl b/src/mod_pubsub/node_mb.erl index 83413cd39..fa0e93401 100644 --- a/src/mod_pubsub/node_mb.erl +++ b/src/mod_pubsub/node_mb.erl @@ -53,7 +53,7 @@ subscribe_node/7, unsubscribe_node/4, publish_item/6, - delete_item/3, + delete_item/4, remove_extra_items/3, get_entity_affiliations/2, get_node_affiliations/1, @@ -141,8 +141,8 @@ publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> remove_extra_items(NodeId, MaxItems, ItemIds) -> node_pep:remove_extra_items(NodeId, MaxItems, ItemIds). -delete_item(NodeId, JID, ItemId) -> - node_pep:delete_item(NodeId, JID, ItemId). +delete_item(NodeId, Publisher, PublishModel, ItemId) -> + node_pep:delete_item(NodeId, Publisher, PublishModel, ItemId). purge_node(NodeId, Owner) -> node_pep:purge_node(NodeId, Owner). diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index 6c3f83d21..1c1e0fc3d 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -46,7 +46,7 @@ subscribe_node/7, unsubscribe_node/4, publish_item/6, - delete_item/3, + delete_item/4, remove_extra_items/3, get_entity_affiliations/2, get_node_affiliations/1, @@ -163,8 +163,8 @@ publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> remove_extra_items(NodeId, MaxItems, ItemIds) -> node_default:remove_extra_items(NodeId, MaxItems, ItemIds). -delete_item(NodeId, JID, ItemId) -> - node_default:delete_item(NodeId, JID, ItemId). +delete_item(NodeId, Publisher, PublishModel, ItemId) -> + node_default:delete_item(NodeId, Publisher, PublishModel, ItemId). purge_node(NodeId, Owner) -> node_default:purge_node(NodeId, Owner). diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl index 8458d50dc..ba0a987fa 100644 --- a/src/mod_pubsub/node_private.erl +++ b/src/mod_pubsub/node_private.erl @@ -50,7 +50,7 @@ subscribe_node/7, unsubscribe_node/4, publish_item/6, - delete_item/3, + delete_item/4, remove_extra_items/3, get_entity_affiliations/2, get_node_affiliations/1, @@ -136,8 +136,8 @@ publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> remove_extra_items(NodeId, MaxItems, ItemIds) -> node_default:remove_extra_items(NodeId, MaxItems, ItemIds). -delete_item(NodeId, JID, ItemId) -> - node_default:delete_item(NodeId, JID, ItemId). +delete_item(NodeId, Publisher, PublishModel, ItemId) -> + node_default:delete_item(NodeId, Publisher, PublishModel, ItemId). purge_node(NodeId, Owner) -> node_default:purge_node(NodeId, Owner). diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl index 2c8d702be..a5a619fdc 100644 --- a/src/mod_pubsub/node_public.erl +++ b/src/mod_pubsub/node_public.erl @@ -50,7 +50,7 @@ subscribe_node/7, unsubscribe_node/4, publish_item/6, - delete_item/3, + delete_item/4, remove_extra_items/3, get_entity_affiliations/2, get_node_affiliations/1, @@ -133,8 +133,8 @@ publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> remove_extra_items(NodeId, MaxItems, ItemIds) -> node_default:remove_extra_items(NodeId, MaxItems, ItemIds). -delete_item(NodeId, JID, ItemId) -> - node_default:delete_item(NodeId, JID, ItemId). +delete_item(NodeId, Publisher, PublishModel, ItemId) -> + node_default:delete_item(NodeId, Publisher, PublishModel, ItemId). purge_node(NodeId, Owner) -> node_default:purge_node(NodeId, Owner). diff --git a/src/mod_pubsub/nodetree_default.erl b/src/mod_pubsub/nodetree_default.erl index d529849ff..dd5b3391f 100644 --- a/src/mod_pubsub/nodetree_default.erl +++ b/src/mod_pubsub/nodetree_default.erl @@ -74,6 +74,7 @@ init(_Host, _ServerHost, _Opts) -> mnesia:create_table(pubsub_node, [{disc_copies, [node()]}, {attributes, record_info(fields, pubsub_node)}]), + mnesia:add_table_index(pubsub_node, id), NodesFields = record_info(fields, pubsub_node), case mnesia:table_info(pubsub_node, attributes) of NodesFields -> ok; From ef94ad36cd76183809e59acc18bb8080deb7ecf5 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 7 May 2009 22:56:23 +0000 Subject: [PATCH 301/582] Merge 2063 from trunk. * src/ejabberd_app.erl: Better support for profiling. * src/ejabberd.erl: Likewise * src/ejabberd_ctl.erl: Likewise * src/ejabberd_debug.erl: Likewise SVN Revision: 2064 --- ChangeLog | 7 ++++ src/ejabberd.erl | 3 +- src/ejabberd_app.erl | 6 +-- src/ejabberd_ctl.erl | 1 + src/ejabberd_debug.erl | 93 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 src/ejabberd_debug.erl diff --git a/ChangeLog b/ChangeLog index cb153b056..b1c8c3d52 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-05-08 Mickael Remond + + * src/ejabberd_app.erl: Better support for profiling. + * src/ejabberd.erl: Likewise + * src/ejabberd_ctl.erl: Likewise + * src/ejabberd_debug.erl: Likewise + 2009-05-07 Christophe Romain * src/mod_caps.erl: Set debug message to DEBUG (from debian patch, diff --git a/src/ejabberd.erl b/src/ejabberd.erl index bc23dd80e..0c7c56a2a 100644 --- a/src/ejabberd.erl +++ b/src/ejabberd.erl @@ -31,11 +31,12 @@ get_so_path/0, get_bin_path/0]). start() -> + %%ejabberd_cover:start(), application:start(ejabberd). stop() -> application:stop(ejabberd). - + %%ejabberd_cover:stop(). get_so_path() -> case os:getenv("EJABBERD_SO_PATH") of diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index 5cf16068d..d20e6cd99 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -60,9 +60,8 @@ start(normal, _Args) -> ejabberd_auth:start(), cyrsasl:start(), % Profiling - %eprof:start(), - %eprof:profile([self()]), - %fprof:trace(start, "/tmp/fprof"), + %ejabberd_debug:eprof_start(), + %fprof:trace([start, {file, "/tmp/fprof"}, {procs, ejabberd_debug:pids()}]), maybe_add_nameservers(), start_modules(), ejabberd_listener:start_listeners(), @@ -82,6 +81,7 @@ prep_stop(State) -> %% All the processes were killed when this function is called stop(_State) -> ?INFO_MSG("ejabberd ~s is stopped in the node ~p", [?VERSION, node()]), + ejabberd_debug:stop(), ok. diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl index 32b1ea9d2..264bbaa53 100644 --- a/src/ejabberd_ctl.erl +++ b/src/ejabberd_ctl.erl @@ -143,6 +143,7 @@ process(["status"]) -> end; process(["stop"]) -> + %%ejabberd_cover:stop(), init:stop(), ?STATUS_SUCCESS; diff --git a/src/ejabberd_debug.erl b/src/ejabberd_debug.erl new file mode 100644 index 000000000..62641d6f5 --- /dev/null +++ b/src/ejabberd_debug.erl @@ -0,0 +1,93 @@ +%%%---------------------------------------------------------------------- +%%% File : ejabberd_debug.erl +%%% Author : Mickael Remond +%%% Purpose : ejabberd's application callback module +%%% Created : 6 may 2009 by Mickael Remond +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%%---------------------------------------------------------------------- + +-module(ejabberd_debug). + +-export([eprof_start/0, stop/0]). +-export([pids/0]). + +eprof_start() -> + eprof:start(), + eprof:profile(pids()). + +%% Stop all profilers +stop() -> + catch eprof:stop(), + ok. + +pids() -> + lists:zf( + fun(Pid) -> + case process_info(Pid) of + ProcessInfo when list(ProcessInfo) -> + CurrentFunction = current_function(ProcessInfo), + InitialCall = initial_call(ProcessInfo), + RegisteredName = registered_name(ProcessInfo), + Ancestor = ancestor(ProcessInfo), + filter_pid(Pid, CurrentFunction, InitialCall, RegisteredName, Ancestor); + _ -> + false + end + end, + processes()). + +current_function(ProcessInfo) -> + {value, {_, {CurrentFunction, _,_}}} = + lists:keysearch(current_function, 1, ProcessInfo), + atom_to_list(CurrentFunction). + +initial_call(ProcessInfo) -> + {value, {_, {InitialCall, _,_}}} = + lists:keysearch(initial_call, 1, ProcessInfo), + atom_to_list(InitialCall). + +registered_name(ProcessInfo) -> + case lists:keysearch(registered_name, 1, ProcessInfo) of + {value, {_, Name}} when is_atom(Name) -> atom_to_list(Name); + _ -> "" + end. + +ancestor(ProcessInfo) -> + {value, {_, Dictionary}} = lists:keysearch(dictionary, 1, ProcessInfo), + case lists:keysearch('$ancestors', 1, Dictionary) of + {value, {_, [Ancestor|_T]}} when is_atom(Ancestor) -> + atom_to_list(Ancestor); + _ -> + "" + end. + +filter_pid(Pid, "ejabberd" ++ _, _InitialCall, _RegisteredName, _Ancestor) -> + {true, Pid}; +filter_pid(Pid, _CurrentFunction, "ejabberd" ++ _, _RegisteredName, _Ancestor) -> + {true, Pid}; +filter_pid(Pid, _CurrentFunction, _InitialCall, "ejabberd"++_, _Ancestor) -> + {true, Pid}; +filter_pid(Pid, _CurrentFunction, _InitialCall, "stringprep"++_, _Ancestor) -> + {true, Pid}; +filter_pid(Pid, _CurrentFunction, _InitialCall, _RegisteredName, "ejabberd"++_) -> + {true, Pid}; +filter_pid(_Pid, _CurrentFunction, _InitialCall, _RegisteredName, _Ancestor) -> + false. From 38413dc2367b0cd3e689b77141eb2d88ecfd49f4 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 8 May 2009 00:02:08 +0000 Subject: [PATCH 302/582] Allow to get subscriptions on a given node (EJAB-712), and presence based fixes SVN Revision: 2067 --- ChangeLog | 8 ++ src/mod_pubsub/mod_pubsub.erl | 205 ++++++++++++++++++++++------------ 2 files changed, 141 insertions(+), 72 deletions(-) diff --git a/ChangeLog b/ChangeLog index b1c8c3d52..7743a49b5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2009-05-08 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: Allow to get subscriptions on a given + node (EJAB-712); Improve XML schema validation on publish item; + Remove subscriptions of users whose authorization has been removed on + nodes with presence access model; Do not allow unsubscribed user to + subscribe node with presence access model. + 2009-05-08 Mickael Remond * src/ejabberd_app.erl: Better support for profiling. diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 02fc6b12d..e0245fc3d 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -55,6 +55,7 @@ %% exports for hooks -export([presence_probe/3, + in_subscription/6, out_subscription/4, remove_user/2, disco_local_identity/5, @@ -179,6 +180,7 @@ init([ServerHost, Opts]) -> ejabberd_hooks:add(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), ejabberd_hooks:add(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75), ejabberd_hooks:add(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50), + ejabberd_hooks:add(roster_in_subscription, ServerHostB, ?MODULE, in_subscription, 50), ejabberd_hooks:add(roster_out_subscription, ServerHostB, ?MODULE, out_subscription, 50), ejabberd_hooks:add(remove_user, ServerHostB, ?MODULE, remove_user, 50), ejabberd_hooks:add(anonymous_purge_hook, ServerHostB, ?MODULE, remove_user, 50), @@ -446,6 +448,7 @@ send_loop(State) -> end, send_loop(State); {presence, User, Server, Resources, JID} -> +?INFO_MSG("got presence probe ~s@~s~p ~p",[User,Server,Resources,jlib:jid_tolower(JID)]), %% get resources caps and check if processing is needed {HasCaps, ResourcesCaps} = lists:foldl(fun(Resource, {R, L}) -> case mod_caps:get_caps({User, Server, Resource}) of @@ -466,6 +469,7 @@ send_loop(State) -> Features when is_list(Features) -> lists:member(Node ++ "+notify", Features); _ -> false end, +?INFO_MSG("notify ~s ~s",[Node, CapsNotify]), case CapsNotify of true -> LJID = {User, Server, Resource}, @@ -641,6 +645,12 @@ out_subscription(User, Server, JID, subscribed) -> gen_server:cast(Proc, {presence, U, S, Rs, Owner}); out_subscription(_, _, _, _) -> ok. +in_subscription(_, User, Server, Subscriber, unsubscribed, _) -> + Owner = exmpp_jid:make_jid(User, Server, ""), + Proc = gen_mod:get_module_proc(Server, ?PROCNAME), + gen_server:cast(Proc, {unsubscribe, Subscriber, Owner}); +in_subscription(_, _, _, _, _, _) -> + ok. %% ------- %% user remove hook handling function @@ -710,6 +720,33 @@ handle_cast({remove_user, LUser, LServer}, State) -> delete_node(Host, ["home", LServer, LUser], Owner), {noreply, State}; +handle_cast({unsubscribe, Subscriber, Owner}, State) -> + Host = State#state.host, + BJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + lists:foreach(fun(PType) -> + {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), + lists:foreach(fun + ({Node, subscribed, JID}) -> + Action = fun(#pubsub_node{options = Options, owners = Owners, type = Type, id = NodeId}) -> + case get_option(Options, access_model) of + presence -> + case lists:member(BJID, Owners) of + true -> + node_call(Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); + false -> + ok + end; + _ -> + ok + end + end, + transaction(Host, Node, Action, sync_dirty); + (_) -> + ok + end, Subscriptions) + end, State#state.plugins), + {noreply, State}; + handle_cast(_Msg, State) -> {noreply, State}. @@ -764,6 +801,7 @@ terminate(_Reason, #state{host = Host, ejabberd_hooks:delete(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), ejabberd_hooks:delete(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75), ejabberd_hooks:delete(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50), + ejabberd_hooks:delete(roster_in_subscription, ServerHostB, ?MODULE, in_subscription, 50), ejabberd_hooks:delete(roster_out_subscription, ServerHostB, ?MODULE, out_subscription, 50), ejabberd_hooks:delete(remove_user, ServerHostB, ?MODULE, remove_user, 50), ejabberd_hooks:delete(anonymous_purge_hook, ServerHostB, ?MODULE, remove_user, 50), @@ -1134,7 +1172,7 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) -> end, [], exmpp_xml:remove_cdata_from_list(Els)), get_items(Host, Node, From, SubId, MaxItems, ItemIDs); {get, 'subscriptions'} -> - get_subscriptions(Host, From, Plugins); + get_subscriptions(Host, Node, From, Plugins); {get, 'affiliations'} -> get_affiliations(Host, From, Plugins); {get, "options"} -> @@ -1550,39 +1588,42 @@ subscribe_node(Host, Node, From, JID) -> {undefined, undefined, undefined} end, SubId = uniqid(), - Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> - Features = features(Type), - SubscribeFeature = lists:member("subscribe", Features), - SubscribeConfig = get_option(Options, subscribe), - AccessModel = get_option(Options, access_model), - SendLast = get_option(Options, send_last_published_item), - AllowedGroups = get_option(Options, roster_groups_allowed, []), - {PresenceSubscription, RosterGroup} = - case Host of - {OUser, OServer, _} -> - get_roster_info(OUser, OServer, - Subscriber, AllowedGroups); - _ -> - case Subscriber of - {"", "", ""} -> {false, false}; - {U, S, _} -> get_roster_info(U, S, Subscriber, - AllowedGroups) - end - end, - if - not SubscribeFeature -> - %% Node does not support subscriptions - {error, extended_error('feature-not-implemented', unsupported, "subscribe")}; - not SubscribeConfig -> - %% Node does not support subscriptions - {error, extended_error('feature-not-implemented', unsupported, "subscribe")}; - true -> - node_call(Type, subscribe_node, - [NodeId, From, Subscriber, + Action = fun(#pubsub_node{options = Options, owners = [Owner|_], type = Type, id = NodeId}) -> + Features = features(Type), + SubscribeFeature = lists:member("subscribe", Features), + SubscribeConfig = get_option(Options, subscribe), + AccessModel = get_option(Options, access_model), + SendLast = get_option(Options, send_last_published_item), + AllowedGroups = get_option(Options, roster_groups_allowed, []), + {PresenceSubscription, RosterGroup} = + case Host of + {OUser, OServer, _} -> + get_roster_info(OUser, OServer, + Subscriber, AllowedGroups); + _ -> + case Subscriber of + {"", "", ""} -> + {false, false}; + _ -> + {OU, OS, _} = Owner, + get_roster_info(OU, OS, + Subscriber, AllowedGroups) + end + end, + if + not SubscribeFeature -> + %% Node does not support subscriptions + {error, extended_error('feature-not-implemented', unsupported, "subscribe")}; + not SubscribeConfig -> + %% Node does not support subscriptions + {error, extended_error('feature-not-implemented', unsupported, "subscribe")}; + true -> + node_call(Type, subscribe_node, + [NodeId, From, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup]) - end - end, + end + end, Reply = fun(Subscription) -> %% TODO, this is subscription-notification, should depends on node features Fields = @@ -1694,10 +1735,10 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> PayloadSize > PayloadMaxSize -> %% Entity attempts to publish very large payload {error, extended_error('not-acceptable', "payload-too-big")}; - PayloadCount == 0 -> + (PayloadCount == 0) and (Payload == []) -> %% Publisher attempts to publish to payload node with no payload {error, extended_error('bad-request', "payload-required")}; - PayloadCount > 1 -> + (PayloadCount > 1) or (PayloadCount == 0) -> %% Entity attempts to publish item with multiple payload elements {error, extended_error('bad-request', "invalid-payload")}; (DeliverPayloads == 0) and (PersistItems == 0) and (PayloadSize > 0) -> @@ -2015,20 +2056,20 @@ get_affiliations(Host, JID, Plugins) when is_list(Plugins) -> end; get_affiliations(Host, Node, JID) -> Action = fun(#pubsub_node{type = Type, id = NodeId}) -> - Features = features(Type), - RetrieveFeature = lists:member("modify-affiliations", Features), - Affiliation = node_call(Type, get_affiliation, [NodeId, JID]), - if - not RetrieveFeature -> - %% Service does not support modify affiliations - {error, extended_error('feature-not-implemented', unsupported, "modify-affiliations")}; - Affiliation /= {result, owner} -> - %% Entity is not an owner - {error, 'forbidden'}; - true -> - node_call(Type, get_node_affiliations, [NodeId]) - end - end, + Features = features(Type), + RetrieveFeature = lists:member("modify-affiliations", Features), + {result, Affiliation} = node_call(Type, get_affiliation, [NodeId, JID]), + if + not RetrieveFeature -> + %% Service does not support modify affiliations + {error, extended_error('feature-not-implemented', unsupported, "modify-affiliations")}; + Affiliation /= owner -> + %% Entity is not an owner + {error, 'forbidden'}; + true -> + node_call(Type, get_node_affiliations, [NodeId]) + end + end, case transaction(Host, Node, Action, sync_dirty) of {result, {_, []}} -> {error, 'item-not-found'}; @@ -2116,14 +2157,15 @@ set_affiliations(Host, Node, From, EntitiesEls) -> end. -%% @spec (Host, JID, Plugins) -> {error, Reason} | {result, Response} +%% @spec (Host, Node, JID, Plugins) -> {error, Reason} | {result, Response} %% Host = host() +%% Node = pubsubNode() %% JID = jid() %% Plugins = [Plugin::string()] %% Reason = stanzaError() %% Response = [pubsubIQResponse()] %% @doc

    Return the list of subscriptions as an XMPP response.

    -get_subscriptions(Host, JID, Plugins) when is_list(Plugins) -> +get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> Result = lists:foldl( fun(Type, {Status, Acc}) -> Features = features(Type), @@ -2141,40 +2183,59 @@ get_subscriptions(Host, JID, Plugins) when is_list(Plugins) -> case Result of {ok, Subscriptions} -> Entities = lists:flatmap( - fun({_, none}) -> []; - ({Node, Subscription}) -> + fun({_, none}) -> + []; + ({SubsNode, Subscription}) -> + case Node of + [] -> [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = - [?XMLATTR('node', node_to_string(Node)), + [?XMLATTR('node', node_to_string(SubsNode)), ?XMLATTR('subscription', subscription_to_string(Subscription))]}]; - ({_, none, _}) -> []; - ({Node, Subscription, SubJID}) -> + SubsNode -> [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = - [?XMLATTR('node', node_to_string(Node)), + [?XMLATTR('subscription', subscription_to_string(Subscription))]}]; + _ -> + [] + end; + ({_, none, _}) -> + []; + ({SubsNode, Subscription, SubJID}) -> + case Node of + [] -> + [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = + [?XMLATTR('node', node_to_string(SubsNode)), ?XMLATTR('jid', exmpp_jid:jid_to_binary(SubJID)), - ?XMLATTR('subscription', subscription_to_string(Subscription))]}] + ?XMLATTR('subscription', subscription_to_string(Subscription))]}]; + SubsNode -> + [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = + [?XMLATTR('jid', exmpp_jid:jid_to_binary(SubJID)), + ?XMLATTR('subscription', subscription_to_string(Subscription))]}]; + _ -> + [] + end end, lists:usort(lists:flatten(Subscriptions))), {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'subscriptions', children = Entities}]}]}; {Error, _} -> Error - end; + end. get_subscriptions(Host, Node, JID) -> Action = fun(#pubsub_node{type = Type, id = NodeId}) -> - Features = features(Type), - RetrieveFeature = lists:member("manage-subscriptions", Features), - Affiliation = node_call(Type, get_affiliation, [NodeId, JID]), - if - not RetrieveFeature -> - %% Service does not support manage subscriptions - {error, extended_error('feature-not-implemented', unsupported, "manage-subscriptions")}; - Affiliation /= {result, owner} -> - %% Entity is not an owner - {error, 'forbidden'}; - true -> - node_call(Type, get_node_subscriptions, [NodeId]) - end - end, + Features = features(Type), + RetrieveFeature = lists:member("manage-subscriptions", Features), + {result, Affiliation} = node_call(Type, get_affiliation, [NodeId, JID]), + if + not RetrieveFeature -> + %% Service does not support manage subscriptions + {error, extended_error('feature-not-implemented', unsupported, "manage-subscriptions")}; + Affiliation /= owner -> + %% Entity is not an owner + {error, 'forbidden'}; + true -> + node_call(Type, get_node_subscriptions, [NodeId]) + end + end, case transaction(Host, Node, Action, sync_dirty) of {result, {_, []}} -> {error, 'item-not-found'}; From 8dc1bb0659ff619291ffb2add412919159c547c1 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 8 May 2009 01:28:17 +0000 Subject: [PATCH 303/582] handle Example 90 of XEP-0060 (EJAB-909), and make use of nodeAttr SVN Revision: 2069 --- ChangeLog | 3 +++ src/mod_pubsub/mod_pubsub.erl | 32 +++++++++++++++++--------------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7743a49b5..12ae00993 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,9 @@ nodes with presence access model; Do not allow unsubscribed user to subscribe node with presence access model. + * src/mod_pubsub/mod_pubsub.erl: Handle Example 90 of XEP-0060 + (EJAB-909) + 2009-05-08 Mickael Remond * src/ejabberd_app.erl: Better support for profiling. diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index e0245fc3d..543768239 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -1428,7 +1428,7 @@ create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) -> {result, []} -> {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = - [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = [?XMLATTR('node', node_to_string(NewNode))]}]}]}; + [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(NewNode)}]}]}; Error -> Error end; false -> @@ -1477,7 +1477,7 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> end end, Reply = [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = - [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = [?XMLATTR('node', node_to_string(Node))]}]}], + [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(Node)}]}], case transaction(CreateNode, transaction) of {result, {Result, broadcast}} -> %%Lang = "en", %% TODO: fix @@ -1752,7 +1752,9 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> end end, ejabberd_hooks:run(pubsub_publish_item, ServerHost, [ServerHost, Node, Publisher, service_jid(Host), ItemId, Payload]), - Reply = [], %% TODO EJAB-909 + Reply = [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB, name = 'publish', attrs = nodeAttr(Node), children = + [#xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = itemAttr(ItemId)}]}]}], case transaction(Host, Node, Action, sync_dirty) of {result, {TNode, {Result, broadcast, Removed}}} -> NodeId = TNode#pubsub_node.id, @@ -1970,7 +1972,7 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> %% Generate the XML response (Item list), limiting the %% number of items sent to MaxItems: {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = - [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = + [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = nodeAttr(Node), children = itemsEls(lists:sublist(SendItems, MaxItems))}]}]}; Error -> Error @@ -2014,7 +2016,7 @@ send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> [] end, Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = itemsEls(ToSend)}]), ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(LU, LS, LR), Stanza}. @@ -2082,7 +2084,7 @@ get_affiliations(Host, Node, JID) -> ?XMLATTR('affiliation', affiliation_to_string(Affiliation))]}] end, Affiliations), {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = - [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'affiliations', attrs = [?XMLATTR('node', node_to_string(Node))], children = + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'affiliations', attrs = nodeAttr(Node), children = Entities}]}]}; Error -> Error @@ -2253,7 +2255,7 @@ get_subscriptions(Host, Node, JID) -> ?XMLATTR('subid', SubId)]}] end, Subscriptions), {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = - [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscriptions', attrs = [?XMLATTR('node', node_to_string(Node))], children = + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscriptions', attrs = nodeAttr(Node), children = Entities}]}]}; Error -> Error @@ -2434,7 +2436,7 @@ broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, _From false -> [] end, Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = itemAttr(ItemId), children = Content}]}]), broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza), case Removed of @@ -2444,7 +2446,7 @@ broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, _From case get_option(Options, notify_retract) of true -> RetractStanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = itemAttr(RId)} || RId <- Removed]}]), broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, RetractStanza); _ -> @@ -2469,7 +2471,7 @@ broadcast_retract_items(Host, Node, NodeId, Type, Options, ItemIds, ForceNotify) {result, false}; {result, Subs} -> Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = itemAttr(ItemId)} || ItemId <- ItemIds]}]), broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza), {result, true}; @@ -2489,7 +2491,7 @@ broadcast_purge_node(Host, Node, NodeId, Type, Options) -> {result, false}; {result, Subs} -> Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'purge', attrs = [?XMLATTR('node', node_to_string(Node))]}]), + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'purge', attrs = nodeAttr(Node)}]), broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza), {result, true}; _ -> @@ -2508,7 +2510,7 @@ broadcast_removed_node(Host, Node, NodeId, Type, Options, Subs) -> {result, false}; _ -> Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'delete', attrs = [?XMLATTR('node', node_to_string(Node))]}]), + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'delete', attrs = nodeAttr(Node)}]), broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza), {result, true} end; @@ -2532,7 +2534,7 @@ broadcast_config_notification(Host, Node, NodeId, Type, Options, Lang) -> [] end, Stanza = event_stanza( - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = [?XMLATTR('id', <<"configuration">>)], children = Content}]}]), broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza), @@ -2667,7 +2669,7 @@ get_configure(Host, ServerHost, Node, From, Lang) -> {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'configure', attrs = - [?XMLATTR('node', node_to_string(Node))], children = + nodeAttr(Node), children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = get_configure_xfields(Type, Options, Lang, Groups) @@ -3094,7 +3096,7 @@ uniqid() -> lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])). % node attributes -nodeAttr(Node) -> %% TODO: to be used +nodeAttr(Node) -> [?XMLATTR('node', node_to_string(Node))]. % item attributes From fd36726357bda81003fa0a76055db13ef6db2288 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Mon, 11 May 2009 17:27:55 +0000 Subject: [PATCH 304/582] Prevent race condition when calling get_caps while note_caps has not been handled yet (EJAB-934) SVN Revision: 2072 --- ChangeLog | 6 ++ src/mod_caps.erl | 64 +++++++++++++++++----- src/mod_pubsub/mod_pubsub.erl | 100 +++++++++++++++++----------------- 3 files changed, 106 insertions(+), 64 deletions(-) diff --git a/ChangeLog b/ChangeLog index 12ae00993..08bc3c68e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-05-11 Christophe Romain + + * src/mod_caps.erl: Prevent race condition when calling get_caps while + note_caps has not been handled yet (EJAB-934) + * src/mod_pubsub/mod_pubsub.erl: Likewise + 2009-05-08 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: Allow to get subscriptions on a given diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 532cc8fa1..1a6691cc0 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -35,6 +35,7 @@ -export([read_caps/1, get_caps/1, note_caps/3, + wait_caps/2, clear_caps/1, get_features/2, get_user_resources/2, @@ -57,7 +58,8 @@ %% hook handlers -export([receive_packet/3, - receive_packet/4]). + receive_packet/4, + presence_probe/3]). -include("ejabberd.hrl"). @@ -92,12 +94,25 @@ read_caps([], Result) -> Result. %% get_caps reads user caps from database -get_caps({U, S, R}) -> +%% here we handle a simple retry loop, to avoid race condition +%% when asking caps while we still did not called note_caps +%% timeout is set to 10s +%% this is to be improved, but without altering performances. +%% if we did not get user presence 10s after getting presence_probe +%% we assume it has no caps +get_caps(LJID) -> + get_caps(LJID, 5). +get_caps(_, 0) -> + nothing; +get_caps({U, S, R}, Retry) -> BJID = exmpp_jid:jid_to_binary(U, S, R), case catch mnesia:dirty_read({user_caps, BJID}) of - [#user_caps{caps=Caps}] -> + [#user_caps{caps=waiting}] -> + timer:sleep(2000), + get_caps({U, S, R}, Retry-1); + [#user_caps{caps=Caps}] -> Caps; - _ -> + _ -> nothing end. @@ -132,6 +147,13 @@ note_caps(Host, From, Caps) -> gen_server:cast(Proc, {note_caps, From, Caps}) end. +%% wait_caps should be called just before note_caps +%% it allows to lock get_caps usage for code using presence_probe +%% that may run before we get any chance to note_caps. +wait_caps(Host, From) -> + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + gen_server:cast(Proc, {wait_caps, From}). + %% get_features returns a list of features implied by the given caps %% record (as extracted by read_caps). It may block, and may signal a %% timeout error. @@ -192,6 +214,10 @@ receive_packet(_, _, _) -> receive_packet(_JID, From, To, Packet) -> receive_packet(From, To, Packet). +presence_probe(From, To, _) -> + ServerString = exmpp_jid:ldomain_as_list(To), + wait_caps(ServerString, From). + caps_to_binary(#caps{node = Node, version = Version, exts = Exts}) -> BExts = [list_to_binary(Ext) || Ext <- Exts], #caps{node = list_to_binary(Node), version = list_to_binary(Version), exts = BExts}. @@ -218,10 +244,11 @@ init([Host, _Opts]) -> {type, bag}, {attributes, record_info(fields, user_caps_resources)}]), mnesia:delete_table(user_caps_default), - mnesia:clear_table(user_caps), - mnesia:clear_table(user_caps_resources), + mnesia:clear_table(user_caps), % clean in case of explicitely set to disc_copies + mnesia:clear_table(user_caps_resources), % clean in case of explicitely set to disc_copies ejabberd_hooks:add(user_receive_packet, Host, ?MODULE, receive_packet, 30), ejabberd_hooks:add(s2s_receive_packet, Host, ?MODULE, receive_packet, 30), + ejabberd_hooks:add(presence_probe_hook, Host, ?MODULE, presence_probe, 20), {ok, #state{host = Host}}. maybe_get_features(#caps{node = Node, version = Version, exts = Exts}) -> @@ -273,15 +300,17 @@ handle_cast({note_caps, From, S = exmpp_jid:ldomain(From), R = exmpp_jid:resource(From), BJID = exmpp_jid:jid_to_binary(From), - mnesia:dirty_write(#user_caps{jid = BJID, caps = caps_to_binary(Caps)}), - case ejabberd_sm:get_user_resources(U, S) of - [] -> - % only store resource of caps aware external contacts - BUID = exmpp_jid:bare_jid_to_binary(From), - mnesia:dirty_write(#user_caps_resources{uid = BUID, resource = list_to_binary(R)}); - _ -> - ok - end, + mnesia:transaction(fun() -> + mnesia:dirty_write(#user_caps{jid = BJID, caps = caps_to_binary(Caps)}), + case ejabberd_sm:get_user_resources(U, S) of + [] -> + % only store resource of caps aware external contacts + BUID = exmpp_jid:bare_jid_to_binary(From), + mnesia:dirty_write(#user_caps_resources{uid = BUID, resource = list_to_binary(R)}); + _ -> + ok + end + end), %% Now, find which of these are not already in the database. SubNodes = [Version | Exts], case lists:foldl(fun(SubNode, Acc) -> @@ -312,6 +341,10 @@ handle_cast({note_caps, From, end, Requests, Missing), {noreply, State#state{disco_requests = NewRequests}} end; +handle_cast({wait_caps, From}, State) -> + BJID = exmpp_jid:jid_to_binary(From), + mnesia:dirty_write(#user_caps{jid = BJID, caps = waiting}), + {noreply, State}; handle_cast({disco_response, From, _To, #iq{id = ID, type = Type, payload = Payload}}, #state{disco_requests = Requests} = State) -> case {Type, Payload} of @@ -384,6 +417,7 @@ terminate(_Reason, State) -> Host = State#state.host, ejabberd_hooks:delete(user_receive_packet, Host, ?MODULE, receive_packet, 30), ejabberd_hooks:delete(s2s_receive_packet, Host, ?MODULE, receive_packet, 30), + ejabberd_hooks:delete(presence_probe_hook, Host, ?MODULE, presence_probe, 20), ok. code_change(_OldVsn, State, _Extra) -> diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 543768239..d5259bf2e 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -179,7 +179,7 @@ init([ServerHost, Opts]) -> ejabberd_hooks:add(disco_sm_identity, ServerHostB, ?MODULE, disco_sm_identity, 75), ejabberd_hooks:add(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), ejabberd_hooks:add(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75), - ejabberd_hooks:add(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50), + ejabberd_hooks:add(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 80), ejabberd_hooks:add(roster_in_subscription, ServerHostB, ?MODULE, in_subscription, 50), ejabberd_hooks:add(roster_out_subscription, ServerHostB, ?MODULE, out_subscription, 50), ejabberd_hooks:add(remove_user, ServerHostB, ?MODULE, remove_user, 50), @@ -448,57 +448,59 @@ send_loop(State) -> end, send_loop(State); {presence, User, Server, Resources, JID} -> -?INFO_MSG("got presence probe ~s@~s~p ~p",[User,Server,Resources,jlib:jid_tolower(JID)]), %% get resources caps and check if processing is needed - {HasCaps, ResourcesCaps} = lists:foldl(fun(Resource, {R, L}) -> - case mod_caps:get_caps({User, Server, Resource}) of - nothing -> {R, L}; - Caps -> {true, [{Resource, Caps} | L]} - end - end, {false, []}, Resources), - case HasCaps of - true -> - Host = State#state.host, - ServerHost = State#state.server_host, - Owner = jlib:short_prepd_bare_jid(JID), - lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = NodeId, options = Options}) -> - case get_option(Options, send_last_published_item) of - on_sub_and_presence -> - lists:foreach(fun({Resource, Caps}) -> - CapsNotify = case catch mod_caps:get_features(ServerHost, Caps) of - Features when is_list(Features) -> lists:member(Node ++ "+notify", Features); - _ -> false - end, -?INFO_MSG("notify ~s ~s",[Node, CapsNotify]), - case CapsNotify of - true -> - LJID = {User, Server, Resource}, - Subscribed = case get_option(Options, access_model) of - open -> true; - presence -> true; - whitelist -> false; % subscribers are added manually - authorize -> false; % likewise - roster -> - Grps = get_option(Options, roster_groups_allowed, []), - {OU, OS, _} = Owner, - element(2, get_roster_info(OU, OS, LJID, Grps)) + %% get_caps may be blocked few seconds, get_caps as well + %% so we spawn the whole process not to block other queries + spawn(fun() -> + {HasCaps, ResourcesCaps} = lists:foldl(fun(Resource, {R, L}) -> + case mod_caps:get_caps({User, Server, Resource}) of + nothing -> {R, L}; + Caps -> {true, [{Resource, Caps} | L]} + end + end, {false, []}, Resources), + case HasCaps of + true -> + Host = State#state.host, + ServerHost = State#state.server_host, + Owner = jlib:short_prepd_bare_jid(JID), + lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = NodeId, options = Options}) -> + case get_option(Options, send_last_published_item) of + on_sub_and_presence -> + lists:foreach(fun({Resource, Caps}) -> + CapsNotify = case catch mod_caps:get_features(ServerHost, Caps) of + Features when is_list(Features) -> lists:member(Node ++ "+notify", Features); + _ -> false end, - if Subscribed -> - send_items(Owner, Node, NodeId, Type, LJID, last); + case CapsNotify of true -> + LJID = {User, Server, Resource}, + Subscribed = case get_option(Options, access_model) of + open -> true; + presence -> true; + whitelist -> false; % subscribers are added manually + authorize -> false; % likewise + roster -> + Grps = get_option(Options, roster_groups_allowed, []), + {OU, OS, _} = Owner, + element(2, get_roster_info(OU, OS, LJID, Grps)) + end, + if Subscribed -> + send_items(Owner, Node, NodeId, Type, LJID, last); + true -> + ok + end; + false -> ok - end; - false -> - ok - end - end, ResourcesCaps); - _ -> - ok - end - end, tree_action(Host, get_nodes, [Owner, JID])); - false -> - ok - end, + end + end, ResourcesCaps); + _ -> + ok + end + end, tree_action(Host, get_nodes, [Owner, JID])); + false -> + ok + end + end), send_loop(State); stop -> ok @@ -800,7 +802,7 @@ terminate(_Reason, #state{host = Host, ejabberd_hooks:delete(disco_sm_identity, ServerHostB, ?MODULE, disco_sm_identity, 75), ejabberd_hooks:delete(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), ejabberd_hooks:delete(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75), - ejabberd_hooks:delete(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50), + ejabberd_hooks:delete(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 80), ejabberd_hooks:delete(roster_in_subscription, ServerHostB, ?MODULE, in_subscription, 50), ejabberd_hooks:delete(roster_out_subscription, ServerHostB, ?MODULE, out_subscription, 50), ejabberd_hooks:delete(remove_user, ServerHostB, ?MODULE, remove_user, 50), From c12b1870b73409089a0354a783237fb06e363532 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 12 May 2009 21:00:05 +0000 Subject: [PATCH 305/582] Fix bad transaction returncode in unsubscribe presence handler SVN Revision: 2074 --- ChangeLog | 5 +++++ src/mod_pubsub/mod_pubsub.erl | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 08bc3c68e..7e1cd8c79 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-05-12 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: Fix bad transaction returncode in + unsubscribe presence handler + 2009-05-11 Christophe Romain * src/mod_caps.erl: Prevent race condition when calling get_caps while diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index d5259bf2e..3f9f6f22f 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -736,10 +736,10 @@ handle_cast({unsubscribe, Subscriber, Owner}, State) -> true -> node_call(Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); false -> - ok + {result, ok} end; _ -> - ok + {result, ok} end end, transaction(Host, Node, Action, sync_dirty); From 3ca2d4dab306df85756012aacbce8bb2a5527301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20R=C3=A9mond?= Date: Wed, 13 May 2009 12:36:37 +0000 Subject: [PATCH 306/582] * src/ejabberd_debug.erl: Handled fprof based profiling (EJABS-872). * src/ejabberd_app.erl: Likewise. SVN Revision: 2075 --- src/ejabberd_app.erl | 2 +- src/ejabberd_debug.erl | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index d20e6cd99..7ea43fc2c 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -61,7 +61,7 @@ start(normal, _Args) -> cyrsasl:start(), % Profiling %ejabberd_debug:eprof_start(), - %fprof:trace([start, {file, "/tmp/fprof"}, {procs, ejabberd_debug:pids()}]), + %ejabberd_debug:fprof_start(), maybe_add_nameservers(), start_modules(), ejabberd_listener:start_listeners(), diff --git a/src/ejabberd_debug.erl b/src/ejabberd_debug.erl index 62641d6f5..f2152d851 100644 --- a/src/ejabberd_debug.erl +++ b/src/ejabberd_debug.erl @@ -26,16 +26,20 @@ -module(ejabberd_debug). --export([eprof_start/0, stop/0]). +-export([eprof_start/0, fprof_start/0, stop/0]). -export([pids/0]). eprof_start() -> eprof:start(), eprof:profile(pids()). +fprof_start() -> + fprof:trace([start, {file, "/tmp/fprof"}, {procs, pids()}]). + %% Stop all profilers stop() -> catch eprof:stop(), + catch fprof:stop(), ok. pids() -> From 35daf5df781c8e2659c036de4f4447efa18c8872 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 14 May 2009 21:12:12 +0000 Subject: [PATCH 307/582] No longer edit ChangeLog, will be auto generated for ejabberd releases. Added new call 'make changelog' which generates a ChangeLog file by prepending to the old file obtained from SVN the new lines obtained from SVN Log and formatted with svn2cl. ChangeLog will be generated and included in ejabberd releases. SVN Revision: 2076 --- ChangeLog | 8651 ----------------------------------------------- src/Makefile.in | 9 + 2 files changed, 9 insertions(+), 8651 deletions(-) delete mode 100644 ChangeLog diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index 7e1cd8c79..000000000 --- a/ChangeLog +++ /dev/null @@ -1,8651 +0,0 @@ -2009-05-12 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: Fix bad transaction returncode in - unsubscribe presence handler - -2009-05-11 Christophe Romain - - * src/mod_caps.erl: Prevent race condition when calling get_caps while - note_caps has not been handled yet (EJAB-934) - * src/mod_pubsub/mod_pubsub.erl: Likewise - -2009-05-08 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: Allow to get subscriptions on a given - node (EJAB-712); Improve XML schema validation on publish item; - Remove subscriptions of users whose authorization has been removed on - nodes with presence access model; Do not allow unsubscribed user to - subscribe node with presence access model. - - * src/mod_pubsub/mod_pubsub.erl: Handle Example 90 of XEP-0060 - (EJAB-909) - -2009-05-08 Mickael Remond - - * src/ejabberd_app.erl: Better support for profiling. - * src/ejabberd.erl: Likewise - * src/ejabberd_ctl.erl: Likewise - * src/ejabberd_debug.erl: Likewise - -2009-05-07 Christophe Romain - - * src/mod_caps.erl: Set debug message to DEBUG (from debian patch, - thanks to Sergei Golovan) - - * src/mod_pubsub/mod_pubsub.erl: Remove subscriptions when anonymous - user removed (EJAB-913) (thanks to Andy Skelton) - - * src/mod_pubsub/mod_pubsub.erl: Fix disco#items bug on root node, - and fix other minor typo from previous patch. - - * src/mod_pubsub/mod_pubsub.erl: Avoid calling get_user_resources - on non local domain when pep_sendlast_offline is enabled - - * src/mod_pubsub/mod_pubsub.erl: Reduce send_last_item load and number - of calls to get_caps - - * src/mod_pubsub/mod_pubsub.erl: Fix get_entity_* not returning node - * src/mod_pubsub/node_default.erl: Likewise - * src/mod_pubsub/nodetree_default.erl: Likewise - - * src/mod_pubsub/mod_pubsub.erl: Retract policy should obey - pubsub#publish_model (EJAB-871) (thanks to Matthew Baron) - * src/mod_pubsub/node_default.erl: Likewise - * src/mod_pubsub/node_mb.erl: Likewise - * src/mod_pubsub/node_dispatch.erl: Likewise - * src/mod_pubsub/node_buddy.erl: Likewise - * src/mod_pubsub/node_private.erl: Likewise - * src/mod_pubsub/node_public.erl: Likewise - * src/mod_pubsub/node_default.erl: Likewise - * src/mod_pubsub/node_pep.erl: Likewise - * src/mod_pubsub/node_club.erl: Likewise - * src/mod_pubsub/node_flat.erl: Likewise - * src/mod_pubsub/node.template: Likewise - -2009-05-06 Badlop - - * src/ejabberd_c2s.erl: Replace TYPE/1 with is_TYPE/1 (EJAB-922) - * src/ejabberd_logger_h.erl: - * src/ejabberd_s2s.erl: - * src/eldap/eldap.erl: - * src/mod_offline.erl: - * src/mod_offline_odbc.erl: - * src/mod_roster.erl: - * src/odbc/odbc_queries.erl: - * src/p1_fsm.erl: - * src/xml.erl: - - * src/Makefile.in: Prevent Erlang R13B compilation warning: - behaviour X undefined (EJAB-920) - - * src/ejabberd_loglevel.erl: Use dynamic_compile instead of - ram_file_io_server. Support definition of loglevels with integer - or atom. (thanks to Geoff Cant)(EJAB-919) - * src/dynamic_compile.erl: Added erlang module that converts - string to binary loadable code by Mats Cronqvist, Chris Newcombe, - and Jacob Vorreuter. - * src/ram_file_io_server.erl: Remove file not longer useful. - * src/ejabberd.app: Likewise - -2009-05-03 Badlop - - * src/mod_muc/mod_muc_room.erl: Fix badarg return (EJAB-899) - -2009-04-30 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: API change for major optimization - * src/mod_pubsub/pubsub.hrl: Likewise - * src/mod_pubsub/nodetree_default.erl: Likewise - * src/mod_pubsub/nodetree_virtual.erl: Likewise - * src/mod_pubsub/node_mb.erl: Likewise - * src/mod_pubsub/node_dispatch.erl: Likewise - * src/mod_pubsub/node_buddy.erl: Likewise - * src/mod_pubsub/node_private.erl: Likewise - * src/mod_pubsub/node_public.erl: Likewise - * src/mod_pubsub/node_default.erl: Likewise - * src/mod_pubsub/node_pep.erl: Likewise - * src/mod_pubsub/node_club.erl: Likewise - * src/mod_pubsub/node_flat.erl: Likewise - * src/mod_pubsub/node.template: Likewise - * src/mod_pubsub/gen_pubsub_node.erl: Likewise - * src/mod_pubsub/gen_pubsub_nodetree.erl: Likewise - - * src/mod_caps.erl: Reduce memory consumption and remove mnesia table - -2009-04-28 Badlop - - * src/ejabberd_hooks.erl: Support distributed hooks (EJAB-829) - - * src/ejabberd_hooks.erl: anonymous functions support. - -2009-04-27 Badlop - - * src/translate.erl: Support additional files (EJAB-925) - * contrib/extract_translations/extract_translations.erl: Likewise - * contrib/extract_translations/prepare-translation.sh: Likewise - - * src/win32_dns.erl: Fix problem parsing some win32 dns (EJAB-927) - - * src/cyrsasl_digest.erl: Fix auth verification (EJAB-863) - - * src/jlib.erl: Fix recursive call to speedup base64 - decoding (thanks to Jeffrey Rogiers)(EJAB-333) - -2009-04-24 Christophe Romain - - * src/odbc/ejabberd_odbc.erl: allow to run query bloc as erlang - function without transaction - - * src/mod_pubsub/mod_pubsub.erl: do not register handlers and hooks - while plugins and ets tables are not initialized. - -2009-04-23 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: improve send last published items - (not spawned as much) and allow to send last PEP items of our offline - contacts if configured for (fix discussion issue on standars ML) - -2009-04-22 Badlop - - * src/ejabberd.cfg.example: Fix English typos. Fix line length: - max 80 characters per line. Remove trailing blankspaces. Added - markers for Vim fold, you may want to add to $HOME/.vimrc this - line: set modeline - * src/ejabberdctl.cfg.example: Likewise - - * src/mod_muc/mod_muc.erl: Limit number of characters in Room ID, - Name and Description (EJAB-899) - * src/mod_muc/mod_muc_room.erl: Likewise - * doc/guide.tex: Likewise - * doc/guide.html: Likewise - - * src/cyrsasl.erl: Change API of check_password: pass a function - to generate the digest (thanks to Graham Whitted)(EJAB-863) - * src/cyrsasl_anonymous.erl: Likewise - * src/cyrsasl_digest.erl: Likewise - * src/cyrsasl_plain.erl: Likewise - * src/ejabberd_auth.erl: Likewise - * src/ejabberd_auth_anonymous.erl: Likewise - * src/ejabberd_auth_external.erl: Likewise - * src/ejabberd_auth_internal.erl: Likewise - * src/ejabberd_auth_ldap.erl: Likewise - * src/ejabberd_auth_odbc.erl: Likewise - * src/ejabberd_auth_pam.erl: Likewise - * src/ejabberd_c2s.erl: Likewise - - * src/ejabberd_c2s.erl: Fix for SASL Anonymous connections not - stored or purged (thanks to Andy Skelton)(EJAB-912) - - * src/ejabberd_c2s.erl: Fix for SASL Anonymous connections not - stored or purged (thanks to Andy Skelton)(EJAB-912) - - * src/mod_shared_roster.erl: Support in API to add 'all' as member - of a group (thanks to Martin Langhoff)(EJAB-916) - -2009-04-17 Badlop - - * doc/guide.tex: Document new ejabberdctl option. New section that - documents AccessCommands. (EJAB-910) - * doc/guide.html: Likewise - - * src/ejabberd_ctl.erl: New option to require auth in ejabberdctl - and restrict what commands and arguments can execute (EJAB-910) - * src/ejabberd_config.erl: Likewise - - * src/ejabberd_commands.erl: API to restrict who can execute what - commands and arguments (EJAB-910) - - * src/mod_caps.erl: Fix unbound variable - -2009-04-14 Badlop - - * doc/guide.tex: Explain that the recommended Erlang/OTP version - is R12B-5, and R13 is not supported yet. - * doc/guide.html: Likewise - * README: Likewise - - * src/mod_muc/mod_muc_log.erl: Linkify also xmpp:..., as it was - done previously (thanks to Konstantin Khomoutov)(EJAB-850) - -2009-03-20 Christophe Romain - - * src/mod_caps.erl: Better handling of presence hook and caps clean - (thanks to Jonathan Schleifer)(EJAB-707) - * src/ejabberd_c2s.erl: Likewise - * src/mod_pubsub/mod_pubsub.erl: Likewise - - * src/mod_pubsub/mod_pubsub.erl: Improve invalid-payload check, send - last published item to new resource only, thread message sending. - -2009-04-09 Badlop - - * src/msgs/pl.po: Fix some translations (thanks to Andrzej Smyk) - -2009-04-08 Badlop - - * src/mod_pubsub/mod_pubsub.erl: Announce PubSub features in the - server JID only if PEP is enabled (EJAB-905) - - * src/mod_muc/mod_muc.erl: English fixes (thanks to Glenn Sieb) - * src/mod_muc/mod_muc_log.erl: Likewise - * src/mod_muc/mod_muc_room.erl: Likewise - * src/mod_register.erl: Likewise - * src/web/ejabberd_web_admin.erl: Likewise - - * src/mod_pubsub/mod_pubsub.erl: Quickfix compilation errors. - - * src/mod_irc/mod_irc_connection.erl: Fix compilation warnings. - -2009-04-01 Badlop - - * doc/release_notes_2.0.5.txt: Added file for new release - -2009-03-24 Badlop - - * src/ejabberd_sm.erl: Partially retract SVN r1976 - EJAB-300 (EJAB-890). Check default privacy list when account, not - a specific session, receives a presence subscription - stanza (EJAB-300). - * src/ejabberd_c2s.erl: Likewise - -2009-03-20 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: implement roster acces model (thanks - to Andy Skelton)(EJAB-780) - -2009-03-19 Christophe Romain - - * src/ejabberdctl.template: Allow more environment variable overrides - in ejabberdctl (thanks to Brian Cully)(EJAB-891) - -2009-03-10 Badlop - - * doc/release_notes_2.0.4.txt: Added file for new release - - * src/tls/tls_drv.c: Fix encryption problem for ejabberd_http - after timeout (thanks to Alexey Shchepin)(EJAB-880) - -2009-03-10 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: Fix PEP with other domains and s2s - (EJAB-825). Also fixes send last published items in subscription. - - * src/mod_pubsub/node_default.erl: minor typo fix - -2009-03-09 Badlop - - * src/tls/tls_drv.c: Fix to support OpenSSL older than - 0.9.8f (EJAB-877)(thanks to Jonathan Schleifer) - * doc/guide.tex: It is again supported OpenSSL older than 0.9.8f - * doc/guide.html: Likewise - - * src/mod_proxy65/mod_proxy65_service.erl: if an ip option is not - defined, the module takes an IP address of a local - hostname (thanks to Evgeniy Khramtsov) - -2009-03-07 Badlop - - * src/Makefile.in: In SunOS, use different C flags (thanks to - Thomas)(EJAB-438) - * src/ejabberd_zlib/Makefile.in: Likewise - * src/mod_irc/Makefile.in: Likewise - * src/stringprep/Makefile.in: Likewise - * src/tls/Makefile.in: Likewise - - * src/ejabberd_c2s.erl: Enforce privacy rules also for - subscription requests (EJAB-300) - * src/ejabberd_sm.erl: Likewise - - * src/mod_privacy.erl: Temporary workaround to inconsistency - * src/mod_privacy_odbc.erl: Likewise - -2009-03-06 Badlop - - * src/eldap/eldap.erl: moves waiting for response queries to - pending queue on an LDAP connection failure (thanks to Evgeniy - Khramtsov) - - * src/eldap/eldap.erl: implemented queue for pending - queries (thanks to Evgeniy Khramtsov) - - * src/eldap/eldap.erl: Close a connection on tcp_error (thanks to - Evgeniy Khramtsov) - -2009-03-05 Badlop - - * src/ejabberd_app.erl: In a Windows machine, explicitly add the - nameservers, as it seems Erlang does not do itself (EJAB-860) - * src/win32_dns.erl: Get name servers from Windows registy (thanks - to Geoff Cant) - - * doc/guide.tex: Require OpenSSL 0.9.8f or higher (EJAB-877) - * doc/guide.html: Likewise - -2009-03-04 Badlop - - * src/ejabberd_auth.erl: If anonymous auth is enabled, when - checking if the account already exists in other auth methods, take - into account if the auth method failed (EJAB-882) - * src/ejabberd_auth_anonymous.erl: Likewise - * src/ejabberd_auth_external.erl: Likewise - * src/ejabberd_auth_internal.erl: Likewise - * src/ejabberd_auth_ldap.erl: Likewise - * src/ejabberd_auth_odbc.erl: Likewise - * src/ejabberd_auth_pam.erl: Likewise - - * src/mod_caps.erl: Fix two small compilation errors - -2009-03-04 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: Add roster subscriptions handling - so on_sub_and_presence if fully supported. - - * src/mod_pubsub/mod_pubsub.erl: Allow to send PEP events to all - connected ressources, even via s2s. - * src/mod_caps.erl: Likewise - -2009-03-03 Badlop - - * src/ejabberd_listener.erl: Fix report message of 'undef' error - - * src/ejabberd_listener.erl: Fix a minor compilation warning and - add EDoc comment - - * src/ejabberd_listener.erl: When stopping a listener, don't stop - the listener supervisor (EJAB-874) - - * src/ejabberd_listener.erl: More error detections - - * src/ejabberd_config.erl: Check certfiles are readable on server - start and listener start (EJAB-753) - * src/ejabberd_listener.erl: Likewise - - * src/ejabberd_listener.erl: Report error at startup if a listener - module isn't available or is not an ejabberd listener (EJAB-868) - - * src/mod_privacy.erl: Privacy List: deny presence-out all + send - presence to: presence is sent (EJAB-255) - * src/ejabberd_c2s.erl: Likewise - - * src/mod_privacy.erl: Only run roster_get_jid_info if privacy - list has subscription or group (thanks to George Hazan)(EJAB-851). - Sort items in privacy list by order before storing (EJAB-848) - * src/mod_privacy.hrl: Likewise - * src/mod_privacy_odbc.erl: Likewise - - * src/mod_muc/mod_muc_room.erl: Owner of a password protected room - must provide the password, like other participants (EJAB-867) - - * src/mod_muc/mod_muc_log.erl: Prevent XSS in MUC logs by - linkifying only a few known protocols (EJAB-850) - - * src/mod_muc/mod_muc.erl: Export function to create MUC - room (thanks to Eric Cestari) (EJAB-729) - - * src/mod_roster.erl: When account is deleted, cancel presence - subscription for all roster items (EJAB-790) - * src/mod_roster_odbc.erl: Likewise - - * src/mod_shared_roster.erl: Fix bug: a pending subscription - request, and later the requester added to the roster due to a - shared roster group, that request could neither be accepted or - rejected (thanks to Brian Cully)(EJAB-869) - - * src/web/ejabberd_http_poll.erl: Allow configuration of session - timeout, using new global option http_poll_timeout (EJAB-135) - * doc/guide.tex: Document new option - * doc/guide.html: Likewise - - * src/ejabberd_system_monitor.erl: Allow parametrizable watchdog - threshold: option watchdog_large_heap or chatting with the - watchdog bot (EJAB-545) - * src/ejabberd_config.erl: Likewise - * doc/guide.tex: Likewise - * doc/guide.html: Likewise - - * src/web/ejabberd_web_admin.erl: Show big integers with comma - separators for easy reading - - * src/web/ejabberd_web_admin.erl: Calls to the hook - webadmin_menu_node provide the node as first argument, and calls - to webadmin_menu_hostnode provide both the host and the node. Fix - call to make_menu_items, because webadmin_menu_node was called in - cases where webadmin_menu_hostnode should be called. Align to - right some table elements. - - * doc/Makefile: In Clean do not remove html. In new Distclean, - remove also html. - - * doc/Makefile: When cleaning, remove contributed_modules.tex - - * src/Makefile.in: Fix arguments to Install program - - * doc/guide.tex: Provide only an example of language option - * doc/guide.html: Likewise - - * doc/guide.tex: mod_muc can run in several nodes of cluster - * doc/guide.html: Likewise - - * doc/api/process-one.css: Add some style to HTML elements - - * src/ejabberd_listener.erl: Fix EDoc errors - * src/web/ejabberd_web_admin.erl: Likewise - - * src/ejabberd_hooks.erl: Explanation in EDoc of some functions - - * doc/guide.tex: Explain that account creation is only supported - by internal and odbc authentication methods - * doc/guide.html: Likewise - - * src/Makefile.in: The path to the installed copy of ejabberd - Guide is set in the environment variable - EJABBERD_DOC_PATH (EJAB-837). - * src/web/ejabberd_web_admin.erl: Likewise - * src/ejabberdctl.template: Likewise - * doc/guide.tex: Likewise - * doc/guide.html: Likewise - -2009-03-02 Pablo Polvorin - - * src/ejabberd_auth_anonymous.erl: Correct include declaration (thanks - to Badlop). Bug was introduced in r1863. - - * src/ejabberd_s2s_in.erl, src/ejabberd_s2s_out.erl: Serialize stanzas - to iolist(). - -2009-03-01 Pablo Polvorin - - * src/ejabberd_auth_anonymous.erl: Host argument for ejabberd_hooks's - functions must be in binary() format. - - * src/ejabberd_receiver.erl: Fix bug when clients connect using legacy - ssl (ejabberd_receiver:process_data/2 was called before initializing - the xmlstream). - - * src/mod_stats.erl: Elements and namespace for (XEP-0039) aren't know - by exmpp ("http://jabber.org/protocol/stats" is represented as a list()) - -2009-02-28 Badlop - - * src/mod_pubsub/node_default.erl: Fix that non-subscriber could - fetch items from Authorize node (thanks to Brian Cully)(EJAB-873) - -2009-02-27 Badlop - - * src/web/ejabberd_http.erl: Added a workaround for inet:peername - returning 'ebadf' - - * src/tls/tls_drv.c: S2S connection with STARTTLS fails to Gtalk - and recent Openfire (thanks to Philipp Hancke)(EJAB-877) - - * doc/guide.tex: No mention to the release date in ejabberd Guide - or release notes. The date of an ejabberd release is determined by - the date of the corresponding release announcement. - -2009-02-25 Badlop - - * src/mod_pubsub/mod_pubsub.erl: Fix incorrect implementation of - Pubsub payload requirements (thanks to Andy Skelton)(EJAB-823) - -2009-02-24 Pablo Polvorin - - * src/ejabberd_service.erl: Exmpp related fixed to the external - components service. - - * src/mod_echo.erl: Fix call to exmpp_xml:get_cdata_as_list/1. - - * src/mod_muc/mod_muc_log.erl: The logging code expect nicknames - to be in list() format. - -2009-02-23 Pablo Polvorin - - * src/ejabberd_c2s.erl, src/mod_echo.erl, src/mod_roster.erl, - src/mod_roster_odbc.erl: Use exmpp_jid:to_binary/1 when possible. - - * src/mod_roster_odbc.erl, src/odbc/ejabberd_odbc.erl: - ejabberd_odbc:escape/1 now can escape binaries too. This - avoid the need to convert a binary value to list() just to - sql-escape it. The escaped value returned is allways a list() - (ejabberd's odbc drivers only works on lists()) - - * src/ejabberd_c2s.erl, src/mod_caps.erl, src/ejabberd_receiver.erl: - Removed a couple of expensive function calls used as arguments for - ?DEBUG macros. All arguments used in the ?DEBUG macro are strictly - evaluated (even if the loglevel is higher). The same is true for - all log macros defined in ejabberd.hrl. We might need to use lazy - evaluation for the arguments, when they are expensive to generate - (wrap the arguments lists in a fun). - -2009-02-23 Christophe Romain - - * src/ejabberd_c2s.erl: Do not call mod_caps:clear_caps, this previous - optimization is too agressive and breaks PubSub/PEP standard behavior - (EJAB-854) - -2009-02-21 Pablo Polvorin - - * src/mod_roster.erl: Bugfix in remove_user/2: values already - in binary() format. - -2009-02-21 Badlop - - * src/ejabberd_auth.erl: Password is undefined when using digest - -2009-02-20 Pablo Polvorin - - * src/mod_offline_odbc.erl, src/mod_privacy_odbc.erl, - src/ejabberd_auth.erl, src/mod_vcard_odbc.erl, - src/mod_private_odbc.erl, src/mod_roster_odbc.erl: remove_user hook - actualized to expect binary arguments. - - * src/web/ejabberd_web_admin.erl: Fix add / remove users. - - * src/mod_configure.erl: Fix bug in form generation. - -2009-02-19 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: fix nodetree plugin resolver - - * src/mod_pubsub/mod_pubsub.erl: backport last changes from trunk - * src/mod_pubsub/node_mb.erl: Likewise - * src/mod_pubsub/node_buddy.erl: Likewise - * src/mod_pubsub/node_private.erl: Likewise - * src/mod_pubsub/node_public.erl: Likewise - * src/mod_pubsub/node_default.erl: Likewise - * src/mod_pubsub/node_pep.erl: Likewise - * src/mod_pubsub/node_club.erl: Likewise - -2009-02-18 Pablo Polvorin - - * src/ejabberd_auth.erl: Fix: for legacy authentication, the Digest - parameters could be 'undefined'. - - * src/mod_muc/mod_muc_room.erl: Typo. - - * src/ejabberd_c2s.erl: Remove comment for an already done TODO. - - * src/web/ejabberd_web_admin.erl, src/web/ejabberd_web_admin.hrl: - Many exmpp related fixes. Fix a bug when displaying users lists, - if we can't access the 'offline_msg' mnesia table (using mod_offline_odbc). - This fix should be temporal, we should find a better way to manage this - situation. The webadmin is usable again. - - * src/web/ejabberd_http.erl: Language must be in binary() format. - - * src/translate.erl: Remove a debug call to io:format/2. - - * src/ejabberd_sm.erl, src/mod_configure.erl, src/mod_disco.erl: - ejabberd_sm:get_user_resources/2 returns resources as binary(). - - * src/ejabberd_sm.erl: Bugfix in get_user_info/3. - - * src/mod_announce.erl: get_title/2 accepts node argument in binary() - or list() format. - -2009-02-13 Christophe Romain - - * src/ejabberd_auth.erl: prevent from calling - get_vh_registered_users/2 when not available - -2009-02-06 Jean-Sébastien Pédron - - * src/web/ejabberd_web.erl, src/web/ejabberd_http.erl: Add - documentation stub for some types. This will be filled later. - - * src/jlib.erl: Document the short JID type. - - * src/mod_roster.erl: Document the type of the argument(s) and the - returned type of every functions. Add guardians expression to exported - functions to ensure at an early stage that we were given the right - arguments. Fix table conversion to exmpp; many fields were left as - string(), preventing matching from working correctly. - (user_roster_item_parse_query/4): Fix a bug where the same variable - was used for two distinct purpose. Fix a bad usage of - exmpp_jid:jid_to_list/1. - -2009-02-05 Jean-Sébastien Pédron - - * src/ejabberd_auth.erl, src/ejabberd_auth_anonymous.erl, - src/ejabberd_auth_external.erl, src/ejabberd_auth_internal.erl, - src/ejabberd_auth_ldap.erl, src/ejabberd_auth_odbc.erl, - src/ejabberd_auth_pam.erl: Document the type of the argument(s) and - the returned type of every functions. - - * src/ejabberd_auth.erl, src/ejabberd_auth_anonymous.erl: Add - guardians expression to many functions to ensure at an early stage - that we were given the right arguments. Other modules are not changed - because they are only used by ejabberd_auth which already does the - check. - -2009-01-30 Jean-Sébastien Pédron - - * doc/api/Makefile: Disable "TODO:" interpretation in eDoc because - usually, the following text isn't in eDoc format. - -2009-01-23 Jean-Sébastien Pédron - - * src/cyrsasl.erl, src/cyrsasl_plain.erl, src/cyrsasl_anonymous.erl, - src/cyrsasl_digest.erl: Document every functions to clarify the types - to give and returned. - - * src/ejabberd_c2s.erl: exmpp_server_sasl:next_step/1 returns the - mechanism as list() again, so the call to binary_to_list/1 isn't - necessary anymore. - -2009-01-23 Badlop - - * src/odbc/mysql.sql: Fix complain about comment syntax - * src/odbc/pg.sql: Likewise - -2009-01-22 Pablo Polvorin - - * src/ejabberd_sm.erl: Fix typo (node -> lnode). - - * src/ejabberd_c2s.erl: Reuse the domain in binary() format to - make the jid. - -2009-01-22 Jean-Sébastien Pédron - - * src/web/ejabberd_web_admin.erl, src/ejabberd_listener.erl: Fix some - eDoc @spec directives. - - * src/ejabberd_sm.erl (get_vh_session_list/1): Remove a bad - list_to_binary/1; now that exmpp_stringprep return the correct type, - it was used on a binary(). - - * src/acl.erl: Document every functions to clarify the types to - give and returned. - -2009-01-21 Jean-Sébastien Pédron - - * src/acl.erl (match_acl/3): Use string() version of - User/Server/Resource to match an ACL. - - * src/cyrsasl.erl: Return invalid-mechanism when a mechanism isn't - supported instead of no-mechanism, which wasn't standard-compliant. - - * src/mod_pubsub/nodetree_virtual.erl (create_node/5): Use string() - version of UserName and UserHost. - - * src/mod_private.erl (process_iq_get/3, process_iq_set/3): Use - binary() version of LUser and LServer. - (convert_to_exmpp2/2): User and server are stored as binary(). - - * src/adhoc.erl, src/ejabberd_c2s.erl, src/ejabberd_s2s.erl, - src/ejabberd_s2s_in.erl, src/ejabberd_s2s_out.erl, - src/ejabberd_service.erl, src/ejabberd_sm.erl, - src/ejabberd_system_monitor.erl, src/jd2ejd.erl, src/jlib.erl, - src/mod_adhoc.erl, src/mod_announce.erl, src/mod_caps.erl, - src/mod_configure.erl, src/mod_configure2.erl, src/mod_disco.erl, - src/mod_irc/mod_irc.erl, src/mod_irc/mod_irc_connection.erl, - src/mod_last.erl, src/mod_last_odbc.erl, src/mod_muc/mod_muc.erl, - src/mod_muc/mod_muc_log.erl, src/mod_muc/mod_muc_room.erl, - src/mod_offline.erl, src/mod_offline_odbc.erl, src/mod_privacy.erl, - src/mod_privacy_odbc.erl, src/mod_proxy65/mod_proxy65_service.erl, - src/mod_pubsub/mod_pubsub.erl, src/mod_register.erl, - src/mod_roster.erl, src/mod_roster_odbc.erl, src/mod_service_log.erl, - src/mod_shared_roster.erl, src/mod_stats.erl, src/mod_vcard.erl, - src/mod_vcard_ldap.erl, src/mod_vcard_odbc.erl, - src/web/ejabberd_http_poll.erl, src/web/ejabberd_web.erl, - src/web/ejabberd_web_admin.erl: Now that #jid{} isn't part of the API - of Exmppp anymore, replace remaining direct usages by calls to - exmpp_jid. Replace exmpp_jid:make_bare_jid() by exmpp_jid:make_jid(). - Replace exmpp_jid:*_to_jid/1 by exmpp_jid:parse_jid/1. Instead - creating #xmlattr directly, use the new ?XMLATTR macro; it'll take - care of the anything-to-binary() conversion. - - * src/adhoc.erl, src/mod_caps.erl (read_caps/2), src/mod_offline.erl - (find_x_expire/2), src/mod_offline_odbc.erl, src/jd2ejd.erl, - src/mod_muc/mod_muc.erl, src/mod_irc/mod_irc_connection.erl, - src/mod_privacy_odbc.erl, src/mod_privacy.erl, src/jlib.erl, - src/mod_pubsub/mod_pubsub.erl, src/mod_stats.erl: Fix some bugs by - getting attributes as list() instead of binary(). - - * src/mod_muc/mod_muc.erl (terminate/2): Fix a bug where - binary_to_list/1 was called on a list(). - - * src/ejabberd_s2s_in.erl (is_packet_key/1): Fix a bug where recipient - and sender were used as binary() instead of list(), which is required - by the rest of the S2S code. - -2009-01-19 Pablo Polvorin - - * src/cyrsasl_digest.erl: Typo (prolists -> proplists). - -2009-01-19 Jean-Sébastien Pédron - - * src/cyrsasl_digest.erl: Replace hijacked usage of xml:get_attr_s/2 - by proper calls to proplists:get_value/3. Replace a call to - stringprep:tolower/1 by exmpp_stringprep:to_lower/1. - - * src/ejabberd_service.erl: Replace a call to xml:crypt/1 by - exmpp_xml:escape_using_entities/1. - -2009-01-19 Jean-Sébastien Pédron - - Merge from trunk (r1804 to r1829). - -2009-01-19 Jean-Sébastien Pédron - - Merge from trunk (r1752 to r1804). - - Note: this merge doesn't include the following revisions because it - was made by previous commits: - r1766, r1768, r1781, r1783, r1794, r1797, r1799, r1802. - -2009-01-19 Pablo Polvorin - - * src/translate.erl: Bugfix, ?MYLANG macro returns a list(). - -2009-01-19 Jean-Sébastien Pédron - - * src/ejabberd_auth_anonymous.erl: Fix accesses to the new #jid opaque - type. - -2009-01-17 Mickael Remond - - * src/ejabberd_c2s.erl: Added comments. - -2009-01-16 Jean-Sébastien Pédron - - Merge from trunk (r1734 to r1752). - - Note: this merge doesn't include the following revisions because it - was made by previous commits: - r1737, r1740, r1745, r1747, r1748. - - * src/jlib.hrl: Any deprecated content was removed from jlib.hrl. This - leaves only the new RSM records. - -2009-01-16 Badlop - - * src/mod_privacy.erl: Privacy list items must be processed in the - specified order (EJAB-848) - * src/mod_privacy_odbc.erl: Likewise - -2009-01-15 Pablo Polvorin - - * src/mod_muc/mod_muc.erl, src/mod_muc/mod_muc_room.erl: - Store registered nicknames, rooms and domains as binary(). - Use document_to_iolist/1 and iolist_size/1 instead of - document_to_list/1. - -2009-01-13 Badlop - - * doc/release_notes_2.0.3.txt: Add release notes - -2009-01-13 Mickael Remond - - * src/tls/Makefile.win32: Windows compilation support. - * src/tls/tls_drv.c: Likewise. - * src/tls/stdint.h: Likewise. - - * doc/guide.tex: Update Erlang version in Windows compilation - documentation. - -2009-01-13 Badlop - - * src/msgs/pl.po: Fix typo (thanks to Apag0r)(EJAB-844) - -2009-01-12 Badlop - - * src/web/ejabberd_web_admin.erl: Use textareas for large input - like ejabberd module options and listening port options. Show - result of POST more clearly. Ensure access rules are shown with - some minimum separation. Improve menu headers. (EJAB-562) - * src/web/ejabberd_web_admin.hrl: Likewise - * src/mod_offline.erl: Likewise - * src/mod_offline_odbc.erl: Likewise - * src/mod_roster.erl: Likewise - * src/mod_roster_odbc.erl: Likewise - * src/mod_shared_roster.erl: Likewise - - * src/ejabberd_listener.erl: New way to configure IP address and - IP version of listener. Support for definition of IP address in - string format, and implicit definition of IP - version (EJAB-388). Support for defining several listeners: all - with same port number but different IP addresses (EJAB-389)(thanks - to Fabrice Colliot and Sergei Golovan). Better report in WebAdmin - of problem when starting a listener. The old configuration method - of ip tuple and inet6 is fully supported for backwards - compatibility, but is not documented in the Guide anymore. - * src/ejabberd_config.erl: Likewise - * src/mod_proxy65/mod_proxy65_stream.erl: Likewise - * src/mod_proxy65/mod_proxy65_service.erl: Likewise - * src/web/ejabberd_web_admin.erl: Likewise - - * doc/guide.tex: Document the new way to configure IP address and - IP version of listener, undocument options ip and inet6 - * doc/guide.html: Likewise - - * src/web/ejabberd_web_admin.erl: New appearance of WebAdmin logo, - fixed logo-fill. - - * doc/guide.tex: Fix some English strings: JID -> Jabber ID; - jabberd 1.4 -> jabberd14; commited -> committed - * src/*/*.erl: Likewise - * src/msgs/*.msg: Likewise - * src/msgs/*.po: Likewise - -2009-01-12 Alexey Shchepin - - * src/odbc/ejabberd_odbc.erl: Fixed processing of UPDATE results - with pgsql - -2009-01-12 Badlop - - * doc/guide.tex: Update copyright date 2008 to 2009 (EJAB-842) - * doc/guide.html: Likewise - * src/*/*.erl: Likewise - * src/*/*.erl: Remove unneeded blankspaces in license text - -2009-01-11 Pablo Polvorin - - * src/mod_pubsub/mod_pubsub.erl: Fix typo, initial update - to new hooks API (using binaries). mod_pubsub is still - unusable with exmpp. - - * src/mod_caps.erl, src/ejabberd_c2s.erl: Apply commit - 1212 (caps handling fix), was incorrectly overwritten on - 1770. - -2009-01-11 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: fix owners cache and fix unsubscribe - permissions (thanks to Andy Skelton)(EJAB-840) - * src/mod_pubsub/node_default.erl: Likewise - -2009-01-10 Pablo Polvorin - - * src/mod_vcard_odbc.erl: Fix bug in user search. - - * src/mod_vcard_ldap.erl, src/mod_vcard.erl, src/mod_configure.erl, - src/ejabberd_sm.erl, src/mod_privacy_odbc.erl, src/ejabberd_c2s.erl, - src/ejabberd_local.erl, src/mod_privacy.erl, src/mod_adhoc.erl, - src/mod_pubsub/mod_pubsub.erl, src/mod_vcard_odbc.erl, - src/mod_stats.erl, src/mod_last.erl, src/mod_private.erl, - src/mod_roster.erl, src/mod_disco.erl, src/mod_private_odbc.erl, - src/mod_configure2.erl, src/mod_roster_odbc.erl, src/mod_register.erl, - src/mod_version.erl, src/mod_caps.erl, src/mod_last_odbc.erl, - src/mod_time.erl: Update gen_iq_handler API, require the 'Host' - argument to be in binary() format. - -2009-01-10 Christophe Romain - - * src/mod_pubsub/node_default.erl: fix unsubscription of full jid - subscribed node (thanks to Andy Skelton)(EJAB-839) - -2009-01-09 Pablo Polvorin - - * src/mod_muc/mod_muc_room.erl, src/mod_muc/mod_muc.erl - src/mod_offline_odbc.erl, src/mod_irc/mod_irc_connection.erl, - src/mod_irc/mod_irc.erl, src/ejabberd_c2s.erl, src/ejabberd_local.erl, - src/mod_pubsub/mod_pubsub.erl, src/ejabberd_s2s.erl, - src/mod_roster.erl, src/mod_roster_odbc.erl, src/ejabberd_s2s_out.erl, - src/mod_offline.erl, src/translate.erl: Adapt to new exmpp API where - get_id/1, get_lang/1, get_initiating_entity/1, get_receiving_entity/1 - and get_type/1 return binary(). - - * src/mod_pubsub/node_default.erl: Fix typo in variable name. - - * src/ejabberd_c2s.erl: Fix bug in handle_info/3 when dealing with - VCARD requests: convert to IQ struct before invoking gen_iq_handler. - -2009-01-09 Badlop - - * doc/guide.tex: Improve explanation of backup commands (EJAB-832) - * doc/guide.html: Likewise - - * src/web/ejabberd_web_admin.erl: New appearance of WebAdmin logo, - fixed logo-fill. - - * src/mod_configure.erl: Fix access check for vhost configuration - -2009-01-08 Mickael Remond - - * src/ejabberd_listener.erl: Define send timeout option to avoid - blocking on socket send (EJAB-746). - * src/ejabberd_s2s_out.erl: Likewise. - -2009-01-08 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: completely support subscription using - full JID (EJAB-701) - * src/mod_pubsub/node_default.erl: Likewise - - * src/mod_pubsub/node_default.erl: any entity can retrieve item when - node access model is "open" (thanks to Myers Carpenter)(EJAB-836) - - * src/mod_pubsub/node_default.erl: use of del_items - - * src/mod_pubsub/node.template: apply delete-any feature - * src/mod_pubsub/node_mb.erl: Likewise - * src/mod_pubsub/node_buddy.erl: Likewise - * src/mod_pubsub/node_private.erl: Likewise - * src/mod_pubsub/node_public.erl: Likewise - * src/mod_pubsub/node_pep.erl: Likewise - * src/mod_pubsub/node_default.erl: Likewise - * src/mod_pubsub/node_club.erl: Likewise - -2009-01-08 Pablo Polvorin - - * src/mod_vcard_ldap.erl, src/mod_muc/mod_muc.erl, src/mod_roster.hrl, - src/mod_offline_odbc.erl, src/ejabberd_s2s_in.erl, src/adhoc.erl, - src/mod_configure.erl, src/mod_irc/mod_irc_connection.erl, - src/mod_irc/mod_irc.erl, src/web/ejabberd_http_poll.erl, - src/mod_privacy_odbc.erl, src/ejabberd_c2s.erl, src/mod_announce.erl, - src/mod_privacy.erl, src/mod_adhoc.erl, src/mod_pubsub/mod_pubsub.erl, - src/mod_vcard_odbc.erl, src/mod_stats.erl, src/mod_last.erl, - src/mod_roster.erl, src/ejabberd_service.erl, src/mod_disco.erl, - src/mod_configure2.erl, src/mod_roster_odbc.erl, - src/ejabberd_s2s_out.erl, src/mod_last_odbc.erl: XML attributes as - binary(). Change Node argument to binary in the following hooks: - disco_local_items, disco_local_features, disco_local_identity, - disco_sm_items and disco_sm_identity. - -2009-01-07 Badlop - - * src/mod_roster.erl: Show hyperlinks to local contacts when - browsing roster of account in Web Admin (EJAB-480) - * src/mod_roster_odbc.erl: Likewise - - * src/web/ejabberd_web_admin.erl: WebAdmin serves Guide and links - to related sections; the path to guide.html can be configured with - option doc_path (EJAB-837) - * src/web/ejabberd_web_admin.hrl: Likewise - * src/mod_shared_roster.erl: Likewise - * doc/guide.tex: Likewise - * doc/guide.html: Likewise - -2009-01-06 Badlop - - * src/msgs/ru.po: Fix typo (thanks to Dominges) - * src/msgs/ru.msg: Likewise - -2009-01-05 Pablo Polvorin - - * src/mod_roster.erl: Fix typo. - -2009-01-05 Alexey Shchepin - - * src/tls/tls_drv.c: Added a flag to avoid certificate validation - * src/tls/tls.erl: Likewise - * src/ejabberd_c2s.erl: Likewise - -2009-01-03 Pablo Polvorin - - * src/mod_pubsub_node_default.erl: Fix typo. - - * src/mod_vcard.erl, src/mod_vcard_ldap.erl, src/ejabberd_hooks.erl, - src/mod_muc/mod_muc_room.erl, src/mod_muc/mod_muc.erl, - src/mod_muc/mod_muc_log.erl, src/mod_shared_roster.erl, - src/ejabberd_auth_odbc.erl, src/mod_offline_odbc.erl, - src/ejabberd_system_monitor.erl, src/ejabberd_s2s_in.erl, - src/mod_configure.erl, src/ejabberd_receiver.erl, - src/mod_irc/mod_irc.erl, src/ejabberd_sm.erl, - src/mod_privacy_odbc.erl, src/ejabberd_c2s.erl, src/mod_announce.erl, - src/ejabberd_local.erl, src/mod_privacy.erl, - src/ejabberd_auth_internal.erl, src/mod_adhoc.erl, src/mod_echo.erl, - src/jlib.erl, src/mod_vcard_odbc.erl, src/ejabberd_s2s.erl, - src/mod_stats.erl, src/ejabberd_router.erl, src/mod_last.erl, - src/mod_private.erl, src/mod_roster.erl, src/ejabberd_service.erl, - src/mod_disco.erl, src/mod_private_odbc.erl, src/mod_service_log.erl, - src/mod_configure2.erl, src/mod_roster_odbc.erl, src/mod_offline.erl, - src/mod_register.erl, src/mod_version.erl, src/mod_caps.erl, - src/mod_last_odbc.erl: Use exmpp API to access JID fields. Keep #jid - fields in binary format when possible. Change all 'user' and 'server' - arguments in all hooks to binary. Change internal tables of - ejabberd_sm, ejabberd_router, ejabberd_hooks, mod_last, mod_roster to - use binary() storage. - -2009-01-03 Badlop - - * src/*.erl: Fix EDoc comments - -2009-01-03 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: deliver notification depending on - presence-based-delivery configuration (EJAB-827). notification code - rewrite. - - * src/mod_pubsub/mod_pubsub.erl: code cleanning, minor bugfixes - * src/mod_pubsub/node_default.erl: Likewise - * src/mod_pubsub/node_pep.erl: Likewise - * src/mod_pubsub/pubsub.hrl: Likewise - - * src/mod_pubsub/mod_pubsub.erl: prevent subscribing with full jid, - waiting for full jid support (EJAB-701) - - * src/mod_pubsub/mod_pubsub.erl: use of delete-any feature instead of - delete-nodes for delete item use case (fix from erroneous definition - in XEP-0060) - - * src/mod_pubsub/mod_pubsub.erl: Added "access-whitelist" and - "member-affiliation" features (thanks to Andy Skelton)(EJAB-780) - -2008-12-29 Alexey Shchepin - - * src/ejabberd_c2s.erl: Bugfix in "from" attribute checking - -2008-12-29 Evgeniy Khramtsov - - * src/odbc/ejabberd_odbc.erl: Print meaningful error message when - an SQL transaction exceeds number of restarts. Also rollbacks - this transaction to prevent deadlocks. - - * src/odbc/odbc_queries.erl: replaced string:join/2 function. - Removed ugly "catch" statement from update_t/4. - WARNING: this change requires last version of mysql driver. - You can update it from ejabberd-modules repository. - -2008-12-28 Mickael Remond - - * src/ejabberd_c2s.erl: We should allow use of bare resource in from by - the client (partially revert r1727) (EJAB-812). - -2008-12-26 Badlop - - * src/web/ejabberd_web_admin.erl: Show in ejabberd Web Admin the - connection method and connected node of Jabber clients (thanks to - Oleg Palij)(EJAB-319) - - * src/ejabberd_config.erl: Option outgoing_s2s_options to define - s2s outgoing behaviour: IPv4, IPv6 and timeout (thanks to Stephan - Maka)(EJAB-665) - * src/ejabberd_s2s_out.erl: Likewise - * src/ejabberd_socket.erl: Likewise - * src/ejabberd.cfg.example: Likewise - * doc/guide.tex: Likewise - * doc/guide.html: Likewise - -2008-12-26 Evgeniy Khramtsov - - * src/odbc/ejabberd_odbc.erl: get rid of SERIALIZABLE isolation - level on MySQL connections. - * src/odbc/odbc_queries.erl: replaces all delete->insert chains - with update->insert. - * src/mod_privacy_odbc.erl: moved sql queries to odbc_queries.erl. - * src/mod_roster_odbc.erl: changed interface for odbc_queries.erl. - -2008-12-24 Badlop - - * src/aclocal.m4: Fixes in configure script: fix - disable-ejabberd_zlib and disable-pam; in case of problems, PAM - verification aborts with error instead of warning. (EJAB-787) - * src/configure.ac: Likewise - * src/configure: Likewise - -2008-12-23 Badlop - - * src/acl.erl: New ACL: shared_group (thanks to Maxim Ryazanov) - * doc/guide.tex: Likewise - - * src/mod_shared_roster.erl: Push new group members when - registered or manually added to group: EJAB-730 EJAB-731 EJAB-732 - EJAB-767 EJAB-794. When user is added to group, push it to other - members, and other members to it. When user is removed from group, - push deletion to other members, and other members to it. When user - is registered, push him to members of group @all@. When user is - deleted, push deletion to members of group @all@. Document several - functions in mod_shared_roster. - - * src/ejabberd_auth.erl: Rename hook user_registered to - register_user, for name consistency with the widely used hook - remove_user. Run hook register_user in ejabberd_auth, so it's run - when account is created with any method. Run hook remove_user in - ejabberd_auth, so it's run when account is deleted with any - method. - * src/ejabberd_auth_internal.erl: Likewise - * src/ejabberd_auth_ldap.erl: Likewise - * src/ejabberd_auth_odbc.erl: Likewise - * src/ejabberd_auth_pam.erl: Likewise - * src/mod_register.erl: Likewise - - * src/jlib.erl: Implementation of XEP-0059 Result Set - Management (thanks to Eric Cestari)(EJAB-807) - * src/jlib.hrl: Likewise - * src/mod_muc/mod_muc.erl: Likewise - -2008-12-23 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: Improve handling of PEP sent to - external contacts (EJAB-825) - * src/mod_caps.erl: Likewise - -2008-12-23 Badlop - - * src/mod_last.erl: Implement workaround for uptime statistic in - 32 bit machines, so it can show uptime greater than 50 - days (EJAB-610) - * src/mod_last_odbc.erl: Likewise - * src/ejabberd_config.erl: Store start time in local_config table - - * src/cyrsasl_digest.erl: Check digest-uri in SASL digest - authentication (thanks to Paul Guyot)(EJAB-569) - - * src/odbc/odbc_queries.erl: Fix removal of private_storage of an - account when the account is removed - - * src/mod_privacy.erl: Remove privacy lists of an account when the - account is removed (EJAB-720) - * src/mod_privacy_odbc.erl: Likewise - -2008-12-19 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: Fix send_last_published_item issue - when running on clustered table (thanks to Vincent Barat)(EJAB-793) - -2008-12-18 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: Check option of the nodetree instead - of checking configuration (thanks to Eric Cestari)(EJAB-737) - -2008-12-17 Pablo Polvorin - - * src/mod_muc/mod_muc_room.erl: Fix bug in MUC invite. - -2008-12-17 Jean-Sébastien Pédron - - Merge from trunk (r1730 to r1734). - -2008-12-16 Badlop - - * src/mod_pubsub/mod_pubsub.erl: Fix update pubsub tables from - ejabberd 1.x to 2.x (EJAB-817) - - * doc/guide.tex: Fix capitalization of some section titles - - * doc/guide.tex: Mention as optional Requirements: mysql, pgsql - and pam - - * src/ejabberd_admin.erl: Command reopen-log must also rotate - sasl.log (thanks to Alexander Tsvyashchenko)(EJAB-711) - * src/ejabberd_logger_h.erl: Export the function rotate_log/1 - * doc/guide.tex: Improve explanation of log files rotation - - * doc/guide.tex: Improve explanation of watchdog admins - option: only useful for developers (EJAB-816) - * src/ejabberd.cfg.example: Likewise - - * doc/guide.tex: Say 'higher' instead of 'newer' in requirements - * README: Likewise - - * doc/guide.tex: Simplify example mod_muc configuration - -2008-12-16 Jean-Sébastien Pédron - - Merge from trunk (r1709 to r1730). - - Ejabberd should be usable again. - -2008-12-16 Jean-Sébastien Pédron - - * src/mod_pubsub/mod_pubsub.erl: Convert to exmpp the parts recently - merged from trunk. Warning: Ejabberd is unusable because the rest of - trunk hasn't been merged yet! - -2008-12-15 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: Fix get_item_name deadlock on - transaction - -2008-12-12 Alexey Shchepin - - * src/ejabberd_c2s.erl: Bugfix in "from" attribute checking - -2008-12-10 Jean-Sébastien Pédron - - * src/eldap/eldap_utils.erl (case_insensitive_match/2): Replace - stringprep by exmpp_stringprep. - -2008-12-09 Christophe Romain - - * src/mod_pubsub: Merge from latest trunk (r1716). - -2008-12-09 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: prevent publish items with invalid - XML schema bugfix (EJAB-699) (previous commit was uncomplete) - and fix bug injected in previous commit - -2008-12-08 Christophe Romain - - * src/ejabberd_c2s.erl: Reduce memory consumption due to caps handling - * src/mod_pubsub/mod_pubsub.erl: Likewise - * src/mod_caps.erl: Likewise - - * src/mod_pubsub/mod_pubsub.erl: ignore unknown configuration fields - (EJAB-762) (thanks to Jack Moffitt) - - * src/mod_pubsub/mod_pubsub.erl: fix node authorization bug (EJAB-798) - send authorization update event (EJAB-799) (thanks to Brian Cully) - - * src/mod_pubsub/mod_pubsub.erl: add nodetree filtering and - authorization (EJAB-813) (thanks to Brian Cully) - * src/mod_pubsub/nodetree_default.erl: Likewise - * src/mod_pubsub/nodetree_virtual.erl: Likewise - * src/mod_pubsub/gen_pubsub_nodetree.erl: Likewise - - * src/mod_pubsub/mod_pubsub.erl: prevent publish items with invalid - XML schema (EJAB-699) - - * src/mod_pubsub/pubsub.hrl: remove unused pubsub_presence record - - * src/mod_pubsub/node_flat.erl: renamed from node_zoo - - * src/mod_pubsub/mod_pubsub.erl: reply to suscriptions options queries - with unsupported feature error (EJAB-713) - - * src/mod_pubsub/node_default.erl: remove pubsub_state record when - unsubscribing node without affiliation (EJAB-776) - -2008-12-08 Jean-Sébastien Pédron - - Merge from trunk (r1692 to r1709). - -2008-12-08 Jean-Sébastien Pédron - - * src/mod_pubsub/node_default.erl, src/mod_pubsub/node_pep.erl: Fix - acl:match_rule/3 call. It takes a #jid record, not a short JID. - - * src/mod_pubsub/node_buddy.erl, src/mod_pubsub/node_club.erl, - src/mod_pubsub/node_dispatch.erl, src/mod_pubsub/node_mb.erl, - src/mod_pubsub/node_private.erl, src/mod_pubsub/node_public.erl, - src/mod_pubsub/node_zoo.erl, src/mod_pubsub/nodetree_default.erl, - src/mod_pubsub/nodetree_virtual.erl: Finish the conversion of - mod_pubsub to Exmpp. - -2008-12-08 Mickael Remond - - * src/ejabberd_c2s.erl: Enforce client stanza from attribute - (EJAB-812). - * src/jlib.erl: Likewise. - -2008-12-05 Jean-Sébastien Pédron - - * src/ejabberd_receiver.erl, src/mod_offline_odbc.erl, - src/mod_vcard_odbc.erl, src/mod_private_odbc.erl, src/jd2ejd.erl: - Update Exmpp XML parser options. - - * src/gen_iq_handler.erl: Add the module and function names to the - error message, when a module crash. - - * src/mod_pubsub/mod_pubsub.erl, src/mod_pubsub/nodetree_default.erl, - src/mod_pubsub/node_default.erl, src/mod_pubsub/node_pep.erl: First - pass of Exmpp conversion for mod_pubsub. Several modules aren't - converted yet. Existent Mnesia tables written to disc are not - updated. There must be bugs, mostly because of the mix between #jid - record and short JIDs. - -2008-12-03 Jean-Sébastien Pédron - - * src/mod_proxy65/mod_proxy65_stream.erl, - src/mod_proxy65/mod_proxy65_service.erl: Convert mod_proxy65 to exmpp. - -2008-12-02 Badlop - - * src/mod_muc/mod_muc_room.erl: Move definitions to header file - * src/mod_muc/mod_muc_room.hrl: New header file - * src/Makefile.in: Likewise - -2008-12-01 Jean-Sébastien Pédron - - Merge from trunk (r1649 to r1692). - - * src/ejabberd_frontend_socket.erl: Fix two warnings about unused - variables. - -2008-12-01 Badlop - - * doc/guide.tex: New subsection Database Connection - * doc/guide.html: Likewise - -2008-11-28 Alexey Shchepin - - * src/mod_muc/mod_muc_room.erl: Clean user activity after timeout - (EJAB-804) - -2008-11-26 Badlop - - * src/ejabberdctl.template: Fix detection of ejabberdctl.cfg path - - * src/mod_irc/mod_irc.erl: Announce disco#info (thanks to Spike) - * src/mod_muc/mod_muc.erl: Announce disco#info disco#items - * src/mod_proxy65/mod_proxy65_service.erl: No announce disco#items - * src/mod_pubsub/mod_pubsub.erl: Announce disco#info disco#items - * src/mod_vcard.erl: Announce disco#info - - * src/gen_mod.erl: First store module options in ETS and Mnesia, - then start the module. In case of failure, remove options from - ETS. Until now the module was started before the options were - stored in database, and some modules started incorrectly because - they couldn't access the options from database; for instance - mod_muc_room required this for reading max_users option. - - * src/mod_muc/mod_muc_room.erl: Include the value of max_users - service option and the current max_users room option in the list - of allowed room limit values. - -2008-10-17 Christophe Romain - - * src/mod_pubsub/node_pep.erl: Fix get_node_affiliations resultset to - owner (Thanks to Michal Schmidt) - -2008-11-24 Evgeniy Khramtsov - - * src/eldap/Makefile.in: added +optimize and +driver - compilation options - * src/eldap/Makefile.win32: Likewise - -2008-11-23 Alexey Shchepin - - * src/ejabberd_receiver.erl: Hibernate after timeout - * src/ejabberd_frontend_socket.erl: Likewise - -2008-11-12 Badlop - - * src/web/ejabberd_http.erl: Include recognized headers in - request_headers as atoms, and others as strings (EJAB-778). - URL path should be tokenized by / and then decoded (EJAB-786). - - * doc/guide.tex: Improve legibility of mod_irc example config - -2008-11-10 Alexey Shchepin - - * src/tls/tls_drv.c: Don't create a SSL context on every - connection and disable SSLv2 on outgoing connections (EJAB-781) - -2008-11-08 Mickael Remond - - * src/ejabberd_s2s_out.erl: exports the DNS resolution - function. - -2008-11-06 Badlop - - * src/extauth.erl: When the extauth call fails or timeouts, deny - authorization. Use two timeouts: 60s for script initialization and - 10s for regular calls. (thanks to Kevin Crosbie from - Ravenpack) (EJAB-627) - -2008-11-04 Pablo Polvorin - - * src/mod_muc/mod_muc_log.erl: Convert to exmpp, fix recursive - directory creation. - - * src/mod_muc/mod_muc_room.erl: Default values as binary() instead of - list(). - -2008-11-03 Pablo Polvorin - - * src/ejabberd_app.erl: Start the exmpp application. - - * src/mod_muc/mod_muc.erl, src/mod_muc/mod_muc_room.erl: Convert to - exmpp. - -2008-11-03 Alexey Shchepin - - * src/ejabberd_c2s.erl: Disable zlib when STARTTLS is required - -2008-10-31 Jean-Sébastien Pédron - - * src/mod_last_odbc.erl (store_last_info/4): Fix a bug where the - status was not converted to list before calling - ejabberd_odbc:escape/1. - (get_last_info/2): Fix a bug where the status was returned as a list - instead of a binary. - -2008-10-27 Badlop - - * src/Makefile.in (clean-local): Delete also ejabberdctl.example - -2008-10-25 Badlop - - * src/translate.erl: When a translation file can't be loaded, show - detailed error message - - * src/ejabberd_ctl.erl: If ejabberd didn't start correctly: - 'ejabberdctl status' suggests to look in log files; any other - ejabberdctl command shows 'status'. - - * src/ejabberd_app.erl: Open ejabberd.log sooner, so errors during - ejabberd initialization are logged in that file (EJAB-777). Write - a log message when ejabberd finishes the start or stop. - -2008-10-24 Badlop - - * src/ejabberd_c2s.erl: Ensure unique ID in roster push (EJAB-721) - * src/mod_roster.erl: Likewise - * src/mod_roster_odbc.erl: Likewise - * src/mod_shared_roster.erl: Likewise - - * src/ejabberd_listener.erl: Fix listeners - * src/ejabberd_sup.erl: Likewise - * src/gen_mod.erl: Likewise - -2008-10-23 Alexey Shchepin - - * src/ejabberd_frontend_socket.erl: Fixed SSL sockets - -2008-10-20 Jean-Sébastien Pédron - - * src/mod_irc/mod_irc.erl, src/mod_irc/mod_irc_connection.erl: Convert - to exmpp. - -2008-10-17 Badlop - - * src/Makefile.in: docdir should be prefixed with DESTDIR (thanks - to Jack Moffitt)(EJAB-775) - -2008-10-17 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: fix badarg issue on get_roster_info - when allowed roster groups is not defined - - * src/mod_pubsub/mod_pubsub.erl: fix remove_user not unsubscribing - user (EJAB-684) - - * src/mod_pubsub/node_default.erl: does not write item when max_items - set to 0 (solves EJAB-768) - -2008-10-14 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: fix pubsub_publish_item hook - ServerHost parameter (EJAB-772) - -2008-10-13 Jean-Sébastien Pédron - - * src/web/ejabberd_http.erl, src/web/ejabberd_http_poll.erl, - src/web/ejabberd_web.erl, src/web/ejabberd_web_admin.erl, - src/web/ejabberd_web_admin.hrl: Convert to exmpp. The admin web - interface is working but HTTP polling seems broken in the trunk. - -2008-10-13 Jean-Sébastien Pédron - - Merge from trunk (r1613 to r1649). - - * src/jlib.erl: Remove all deprecated functions. - -2008-10-13 Jean-Sébastien Pédron - - * src/extauth.erl (call_port/2): Replace jlib:nameprep/1 by - exmpp_stringprep:nameprep/1. - - * src/gen_iq_handler.erl: Remove the deprecated list of converted - modules. - - * src/ejd2odbc.erl, src/jd2ejd.erl: Convert to exmpp. - -2008-10-13 Jerome Sautret - - * src/odbc/ejabberd_odbc.erl: log MySQL driver messages. - -2008-10-13 Badlop - - * src/web/ejabberd_web_admin.erl: When requesting page of - nonexistent user, show 'Not Found' page (EJAB-771) - -2008-10-12 Badlop - - * src/web/ejabberd_web_admin.erl: Run new hook - webadmin_user_parse_query when POST in web admin user - page (thanks to Oleg Palij)(EJAB-747) - * src/mod_offline.erl: Add button "Remove All Offline Messages" in - a user page (thanks to Oleg Palij)(EJAB-747) - * src/mod_offline_odbc.erl: Likewise - - * src/web/ejabberd_web_admin.erl: Improve Web Admin navigation - menu for vhosts and nodes (EJAB-734) - - * doc/guide.tex: Explain the new ejabberdctl command 'help' - * doc/guide.html: Likewise - - * src/mod_configure.erl: Update calls from ctl to - commands (EJAB-694) - * src/web/ejabberd_web_admin.erl: Likewise - - * src/ejabberd_sm.erl: Update from ctl to commands (EJAB-694) - * src/ejabberd_s2s.erl: Likewise - - * src/ejabberd_auth.erl: Update from ctl to commands (EJAB-694) - * src/ejabberd_auth_internal.erl: Likewise - * src/ejabberd_auth_ldap.erl: Likewise - * src/ejabberd_auth_odbc.erl: Likewise - - * src/ejabberdctl.template: Move help print to a separate - function (EJAB-694) - - * src/ejabberd_ctl.erl: Add frontend support for - commands (EJAB-694). Categorization and sorting of commands in - ejabberd_ctl help (EJAB-313). Lines in command line help of length - 80, and text formatting (EJAB-473) - - * src/ejabberd_app.erl: Initialize ejabberd_commands and start - ejabbed_admin (EJAB-694) - - * src/ejabberd_admin.erl: Implement commands from old - ejabberd_ctl (EJAB-694) - - * src/ejabberd_commands.erl: New 'ejabberd commands': separate - command definition and calling interface (EJAB-694) - * src/ejabberd_commands.hrl: Likewise - - * src/mod_proxy65/mod_proxy65.erl: Update so the listener starts - correctly (EJAB-303) - * src/mod_proxy65/mod_proxy65_service.erl: Likewise - - * src/ejabberd_app.erl: Start listeners explicitely at server - start after everything else (EJAB-303). Implement support in - ejabberd for 'independent listeners', which handle their - connections themselves: gen_tcp:listen, etc. - * src/ejabberd_listener.erl: Likewise - * src/ejabberd_socket.erl: Likewise - * src/ejabberd_sup.erl: Likewise - -2008-10-10 Jean-Sébastien Pédron - - * src/ejabberd_c2s.erl (is_auth_packet/1): Fix a bug where - legacy authentication informations were not search among the query - children but among the IQ children. Thanks to Pablo Polvorin! - - * src/mod_privacy_odbc.erl (item_to_raw/1): Fix a buf where a tuple - was passed to exmpp_jid:jid_to_list/1 instead of a #jid. Now we use - exmpp_jid:jid_to_list/3. Thanks to Pablo Polvorin! - - * src/ejabberd_s2s_in.erl (wait_for_feature_request/2), - src/ejabberd_router.erl (register_route/2, unregister_route/1), - src/ejabberd_ctl.erl (process/1), src/ejabberd_rdbms.erl - (needs_odbc/1): Replace jlib:nameprep/1 by exmpp_stringprep:nameprep/1 - and change the error handling. - - * src/ejabberd_config.erl (normalize_hosts/2): Replace jlib:nodeprep/1 - by exmpp_stringprep:nodeprep/1 and change the error handling. - - * src/ejabberd_c2s.erl (handle_sync_event/4): Remove a remaining - jlib:jid_remove_resource/1 call. - - * src/ejabberd_auth_internal.erl: Replace jlib:*prep/1 by - exmpp_stringprep:*prep/1 and change the error handling. - - * src/mod_vcard_odbc.erl (do_route/4): Replace jlib:iq_to_xml/1 by - exmpp_iq:iq_to_xmlel/1. - - * src/mod_roster_odbc.erl (user_roster_subscribe_jid/3): Fix a bug - where the wrong module was called (jlib instead of exmpp_jid). - - * src/ejabberd_app.erl (start/2): Don't start stringprep_sup. - - * src/ejabberd_system_monitor.erl: Convert to exmpp. - -2008-10-09 Jean-Sébastien Pédron - - * src/ejabberd_c2s.erl: Fix handling of unauthenticated stanzas which - are not request IQ. Thanks to Pablo Polvorin! - -2008-10-08 Jean-Sébastien Pédron - - Merge from trunk (r1563 to r1613). - -2008-10-07 Jean-Sébastien Pédron - - * src/ejabberd_local.erl: Fix a bug where an error stanza was not - created correctly, leading to ejabberd_c2s crash. - - * src/mod_stats.erl, src/mod_service_log.erl, src/mod_time.erl: - Convert to exmpp. - - * src/mod_private.erl, src/mod_private_odbc.erl, src/mod_version.erl: - Convert to exmpp. Thanks to Pablo Polvorin! - -2008-10-07 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: uncomment pubsub_publish_item hook - call (EJAB-765) - -2008-10-07 Jerome Sautret - - * src/mod_roster_odbc.erl: fix MySQL multiple requests issue. - -2008-10-06 Jean-Sébastien Pédron - - * src/ejabberd_sm.erl (process_iq/3): Fix a bug where we were matching - on #iq.type instead of #iq.kind, resulting in bad-request sent to the - client. - - * src/ejabberd_c2s.erl (process_privacy_iq/4): mod_privacy & friends - may return an empty list. Thanks to Pablo Polvorin! - - * src/mod_roster_odbc.erl (get_jid_info/4): Fix a confusion between - #jid and tuples. Thanks to Pablo Polvorin! - - * src/mod_privacy.erl, src/mod_privacy_odbc.erl: Convert to exmpp. - Thanks to Pablo Polvorin! - - * src/mod_privacy.erl: The Mnesia table wasn't updated when converting - from an old schema. - - * src/ejabberd_sm.erl, src/mod_roster.erl, src/mod_roster_odbc.erl: - Fix status handling by always using binaries: until now, we were - mixing lists and binaries in a non-working way. Thanks to Pablo - Polvorin! - -2008-10-06 Badlop - - * doc/guide.html: Regenerated - -2008-10-06 Jerome Sautret - - * src/ejabberd_rdbms.erl: fix SQL database reconnection - issues (EJAB-764) and add odbc_start_interval configuration - directive (default to 30 seconds). - * src/odbc/ejabberd_odbc.erl: likewise. - * src/odbc/ejabberd_odbc_sup.erl: likewise. - * doc/guide.tex: likewise. - -2008-10-03 Jerome Sautret - - * src/odbc/odbc_queries.erl: Fix empty query that fail on MySQL. - -2008-10-03 Jerome Sautret - - * src/mod_vcard_odbc: added vCard support for MS SQL Server 2005. - * src/odbc/odbc_queries.erl: likewise. - * src/odbc/mssql2005.sql: likewise. - -2008-10-02 Jean-Sébastien Pédron - - * src/mod_roster_odbc.erl: Fix a bug where a JID represented as a - tuple was used in a function expecting a #jid; thanks to Pablo - Polvorin again! - - * src/mod_announce.erl (get_stored_motd): - exmpp_xml:get_element_by_name/2 is deprecated; use - exmpp_xml:get_element/2 instead. - - * src/mod_echo.erl: In #jid, when the node isn't specified, it - defaults to the atom "undefined", not an empty binary. Fix a bug where - we expected an #xmlelement to have only one #xmlcdata child. - - * src/mod_last_odbc.erl (start/2, stop/1): The IQ registration must - use a namespace as atom, not list. - (process_local_iq/3, process_sm_iq/3, get_last/3): These functions - receive an #iq, not an #xmlel. - (store_last_info/4, remove_user/2): Add try/catch block around - exmpp_stringprep:*prep/1 uses. - -2008-10-01 Jean-Sébastien Pédron - - * src/mod_offline_odbc.erl, src/mod_vcard_odbc.erl, - src/mod_roster_odbc.erl: Fix multiple bugs in ODBC mods, thanks to - Pablo Polvorin! - -2008-10-01 Mickael Remond - - * src/mod_shared_roster.erl: Correct roster push when changing - a shared roster entry name (EJAB-738). - -2008-09-30 Badlop - - * src/*/Makefile.win32: Provide explicit beam filenames because - nmake does not accept wildcards (thanks to Attila - Vangel)(EJAB-543) - -2008-09-29 Jean-Sébastien Pédron - - * src/jlib.erl (parse_xdata_submit, parse_xdata_fields): Fix a bug - where exmpp_xml:get_attribute_from_list/3 was called with only 2 - arguments; this code has not been updated when exmpp_xml's API - changed... - - * src/mod_disco.erl: Remove compatilibity code. - - * src/ejabberd_c2s.erl: When the status is not specified in a presence - stanza, default to an empty binary, not an empty string; this is what - mod_last expects. - - * src/mod_last.erl: Add try/catch block around - exmpp_stringprep:*prep/1 uses. Add table conversion. - (get_last): Do not convert status to binary because it's already one. - - * src/mod_adhoc.erl: Remove compatibility code (not tested yet). - - * src/mod_shared_roster.erl: Convert to exmpp (not tested yet). - - * src/mod_roster.erl (push_item), src/mod_roster_odbc.erl (push_item): - Fix a bug in #xmlel construction: children must be a list. - - * src/ejabberd_receiver.erl: Add the {autoload_known, true} flag to - the XML parser options. This allows modules to extend the known - nss/names/attrs with their own data. - - * src/mod_configure2.erl: Fill exmpp_xml known list with the - nss/names/attrs used by this module. - -2008-09-25 Jean-Sébastien Pédron - - * src/jlib.erl (timestamp_to_xml): Create an #xmlel element, not an - old #xmlelement. - - * src/mod_offline.erl: Remove any compatibility code: the core of - Ejabberd expects new structures. Add table conversion. Add try/catch - block around exmpp_stringprep:*prep/1 uses. - -2008-09-24 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: Allow PEP node type to be mapped with - namespace (EJAB-739). Change get_items to use From (EJAB-751). (Thanks - to Eric Cestari) - * src/mod_pubsub/gen_pubsub_node.erl: Likewise - * src/mod_pubsub/node_dispatch.erl: Likewise - * src/mod_pubsub/node_buddy.erl: Likewise - * src/mod_pubsub/node_zoo.erl: Likewise - * src/mod_pubsub/node.template: Likewise - * src/mod_pubsub/node_private.erl: Likewise - * src/mod_pubsub/node_public.erl: Likewise - * src/mod_pubsub/node_default.erl: Likewise - * src/mod_pubsub/node_pep.erl: Likewise - * src/mod_pubsub/node_club.erl: Likewise - - * src/mod_pubsub/node_mb.erl: Added PEP microglobing node (Thanks to - Eric Cestari) - -2008-09-23 Jean-Sébastien Pédron - - * src/mod_vcard.erl (process_sm_iq): Fix a bug where a badmatch - exception was raised when the user didn't have a vCard. - (remove_user): Fix a bug where the exmpp_jid module was use instead of - exmpp_stringprep. - - * src/ejabberd_auth_odbc.erl (check_password), src/mod_roster.erl - (remove_user): Fix a typo in the exmpp_stringprep module name. - - * src/ejabberd_c2s.erl: Fix a misuse of exmpp_stanza:error/2: the - namespace argument (the first one) was missing. - (process_privacy_iq): Fix a bug where the #iq record was not converted - back to an #xmlel before calling ejabberd_router:route/3. - - * src/mod_register.erl: Convert to exmpp. - -2008-09-22 Jean-Sébastien Pédron - - * src/mod_vcard.erl (get_sm_features): Remove unappropriate - comments. - (do_route): Use the '_s' variants of NS_* macros instead of a call to - atom_to_list/1. - (filter_fields): A call to the stringprep module was left. - - * src/mod_vcard_ldap.erl, src/mod_vcard_odbc.erl: Convert to exmpp. - -2008-09-22 Mickael Remond - - * src/mod_configure.erl: Fix adhoc commands reply types for - "get-online-users-num" and "get-registered-users-num" (EJAB-756). - -2008-09-18 Jean-Sébastien Pédron - - * src/mod_roster_odbc.erl: Convert to exmpp. - - * src/mod_roster.erl (get_in_pending_subscriptions): Fix a bug where - the type of the presence stanza was lost. - (user_roster): Reorganize a few lines to match mod_roster_odbc. - -2008-09-16 Jean-Sébastien Pédron - - Merge from trunk (r1457 to r1563). - -2008-09-15 Badlop - - * doc/guide.tex: Fix explanation of mod_muc's anonymous - option. Make clear that an ejabberd_service can only serve a - single external component. Provide Mnesia directory when setting - clustering (thanks to Matthew Reilly) - -2008-09-12 Badlop - - * src/web/ejabberd_http.hrl: Provide Host, Port, Headers and - Transfer Protocol in request (thanks to Eric Cestari)(EJAB-560) - * src/web/ejabberd_http.erl: Likewise - -2008-09-02 Badlop - - * doc/guide.tex: Fix mod_proxy configuration example - * doc/guide.html: Likewise - -2008-09-02 Mickael Remond - - * src/odbc/mssql2000.sql: Script for MSSQL 2000 - * src/odbc/mssql2005.sql: Script for MSSQL 2005 (EJAB-535) - * src/odbc/mssql.sql: removed - -2008-08-27 Jean-Sébastien Pédron - - * src/mod_roster.erl: Remove a debugging io:format/2. - - * src/mod_caps.erl: handle_cast({disco_response, ...}, ...) now - receives an #iq record: update the code to handle this. - - * src/mod_vcard.erl: VCards are now stored as #xmlel. Mnesia tables - are converted during startup. - -2008-08-27 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: send last published events now - supports PEP events from unavailable users nodes (EJAB-698) - * src/ejabberd_c2s.erl: Likewise - -2008-08-26 Jean-Sébastien Pédron - - * src/jlib.erl: short_jid/1 and short_bare_jid/1 now produce a short - JID from the user-provided JID parts. To obtain a short JID from the - STRINGPREP'd parts, use the new short_prepd_jid/1 and - short_prepd_bare_jid/1 functions. Remove commented-out code and use - proper variable names. Those functions use the atom 'undefined' and - NOT the empty string anymore! - - * src/acl.erl, src/ejabberd_router.erl: Use the new functions from - jlib. - - * src/ejabberd_router.erl, src/ejabberd_local.erl, - src/ejabberd_sm.erl, src/ejabberd_s2s.erl, src/ejabberd_s2s_in.erl, - src/ejabberd_s2s_out.erl, src/ejabberd_c2s.erl: Remove the - compatibility code. It's becoming confusing to handle every case every - where. Also, in JIDs (normal and short), the atom "undefined' is - expected, not the empty string anymore! - - * src/mod_roster.hrl, src/mod_roster.erl: Remove compatibility code. - Use the atom 'undefined' in JIDs (normal and short). Add try/catch - blocks where Exmpp can raise exceptions. Remove some unused code. - Convert on-disk Mnesia database: JIDs, extra XML elements and - askmessage are concerned. By default, 'askmessage' is now an empty - binary instead of an empty string, for consistency's sake. Fix some - bugs. - -2008-08-26 Badlop - - * doc/release_notes_2.0.2.txt: Update for final release - - * doc/guide.tex: Windows binary installer requires MSVC++ 5 - * doc/guide.html: Likewise - -2008-08-26 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: get_items bugfix (EJAB-716) - -2008-08-25 Christophe Romain - - * src/mod_privacy_odbc.erl: Prevent case_clause error when - ejabber_odbc:sql_query returns {error, Reason} - * src/mod_vcard_odbc.erl: Likewise - * src/mod_last_odbc.erl: Likewise - * src/mod_offline_odbc.erl: Likewise - -2008-08-25 Badlop - - * src/ejabberd_check.erl: Detect correctly MSSQL and ODBC - configuration (EJAB-710) - -2008-08-24 Geoff Cant - - * src/mod_mud/mod_muc_room.erl: is_visitor/2 fix - use get_role - not get_affiliation - -2008-08-22 Badlop - - * src/ejabberd_router.erl: Fix call to mnesia match_object - -2008-08-21 Badlop - - * doc/guide.tex: Fix names of chatroom to room, user to occupant - * doc/guide.html: Likewise - -2008-08-18 Badlop - - * src/mod_muc/mod_muc_log.erl: MUC log files options: plaintext - format; filename with only room name (EJAB-596) - * doc/guide.tex: Document both options - * doc/guide.html: Likewise - - * src/mod_register.erl: Change password using mod_register always - returns success regardless of real result (EJAB-723) - * src/ejabberd_auth.erl: Likewise - * src/ejabberd_auth_external.erl: Likewise - * src/ejabberd_auth_internal.erl: Likewise - * src/ejabberd_auth_odbc.erl: Likewise - -2008-08-18 Christophe Romain - - * src/mod_pubsub/node_dispatch.erl: Fix call to unexported function - nodetree_default:get_subnodes/2 - -2008-08-17 Badlop - - * contrib/extract_translations/extract_translations.erl: Use - Gettext PO for translators, export to ejabberd MSG (EJAB-648) - * contrib/extract_translations/prepare-translation.sh: Likewise - * doc/guide.tex: Likewise - * doc/guide.html: Likewise - * src/Makefile.in: New option 'make translations' - * src/msgs/ejabberd.pot: Template translation file - * src/msgs/*.po: Generated from old MSG files - * src/msgs/*.msg: Automatic exported from PO files - -2008-08-16 Badlop - - * src/msgs/sv.msg: Fixed formatting typos - - * src/gen_mod.erl: Export stop_module_keep_config/2 (EJAB-706) - -2008-08-14 Jean-Sébastien Pédron - - * translate.erl (ascii_tolower): Accept 'undefined' as a language and - treat it as the empty string. - - * src/gen_iq_handler.erl, src/ejabberd_local.erl, src/ejabberd_sm.erl: - Remove the compatibility layer and always call modules with the new - #iq record from Exmpp. - - * src/mod_roster.erl, src/mod_vcard.erl, src/adhoc.erl, - src/mod_adhoc.erl, src/mod_configure.erl, src/mod_configure2.erl, - src/mod_disco.erl, src/mod_last.erl: Convert to the new #iq record - from Exmpp. - -2008-08-13 Badlop - - * doc/guide.tex: Explain that LDAP is read-only storage (thanks to - Evgeniy Khramtsov) - * doc/guide.html: Likewise - -2008-08-10 Badlop - - * src/msgs/eo.msg: Updated (thanks to Andreas van Cranenburgh) - * src/msgs/nl.msg: Updated (thanks to Andreas van Cranenburgh) - * src/msgs/sk.msg: Updated (thanks to Marek Becka) - * src/msgs/sv.msg: Updated (thanks to Thore Alstromer and Heysan) - -2008-08-09 Badlop - - * src/ejabberd_service.erl: Fix XEP-0114 compliance: define xmlns - in header of error response; include in response the JID of served - component not server (thanks to Sergei Golovan)(EJAB-717) - -2008-08-06 Jean-Sébastien Pédron - - * src/mod_offline.erl, src/mod_offline_odbc.erl, src/mod_echo.erl, - src/mod_last.erl, src/mod_configure2.erl, src/mod_last_odbc.erl, - src/gen_iq_handler.erl: Convert to exmpp. - - * src/adhoc.erl, src/mod_configure.erl, src/mod_roster.erl, - src/mod_disco.erl, src/mod_caps.erl: Update to use the new - exmpp_xml:get_attribute/{3,4} API. - - * src/ejabberd_c2s.erl, src/ejabberd_s2s_in.erl, - src/ejabberd_s2s_out.erl, src/ejabberd_service.erl, src/mod_adhoc.erl, - src/mod_caps.erl, src/mod_configure.erl, src/mod_disco.erl, - src/mod_echo.erl, src/mod_offline.erl, src/mod_roster.erl, - src/mod_vcard.erl: Update to use the new names used in exmpp_jid. - -2008-08-04 Jerome Sautret - - * src/odbc/ejabberd_odbc.erl: Restart the database connection when - it's lost or it reaches timeout with MySQL. Set transaction isolation level - to SERIALIZABLE when establishing connection to MySQL. - -2008-08-01 Badlop - - * doc/release_notes_2.0.2.txt: Added for ejabberd 2.0.2-beta1 - - * src/web/ejabberd_http.erl: Temporary solution for check of - packet size when HTTPS (EJAB-611)(EJAB-507)(EJAB-574) - -2008-07-31 Badlop - - * src/msgs/uk.msg: Fix: each string in a single line - * src/msgs/wa.msg: Likewise - - * src/msgs/es.msg: Fix typo - * src/msgs/gl.msg: Likewise - * src/msgs/pt-br.msg: Likewise - - * src/msgs/zh.msg: Fix some translations (thanks to Zhan Caibao) - - * src/msgs/ca.msg: Updated (thanks to Badlop) - * src/msgs/cs.msg: Updated (thanks to Lukas Poliuvk) - * src/msgs/de.msg: Updated (thanks to Nikolaus Polak) - * src/msgs/es.msg: Updated (thanks to Badlop) - * src/msgs/fr.msg: Updated (thanks to Christophe Romain) - * src/msgs/it.msg: Updated (thanks to Luca Brivio) - * src/msgs/ja.msg: Updated (thanks to Tsukasa Hamano) - * src/msgs/no.msg: Updated (thanks to Stian B. Barmen) - * src/msgs/pl.msg: Updated (thanks to Zbyszek Zolkiewski) - * src/msgs/pt-br.msg: Updated (thanks to Otavio Fernandes) - * src/msgs/ru.msg: Updated (thanks to Evgeniy Khramtsov) - * src/msgs/tr.msg: Updated (thanks to Doruk Fisek) - * src/msgs/uk.msg: Updated (thanks to Ruslan Rakhmanin) - * src/msgs/wa.msg: Updated (thanks to Pablo Saratxaga) - * src/msgs/zh.msg: Updated (thanks to Shelley Shyan) - - * README: Update location where mnesia, ebin and priv directories - are installed; install headers and doc (EJAB-696) - - * doc/guide.tex: Update Process-one name to ProcessOne (EJAB-708) - * doc/guide.html: Likewise - * doc/api/overview.edoc: Likewise - * src/*/*.erl: Likewise - * src/*/*.hrl: Likewise - * src/*/*.c: Likewise - * src/odbc/*.sql: Likewise - -2008-07-30 Badlop - - * src/mod_muc/mod_muc_room.erl: Support Reasons for all - affiliation and role changes (EJAB-306) - - * src/gen_mod.erl: When ejabberd is kindly stopped, don't forget - modules configuration (EJAB-706) - * src/ejabberd_app.erl: Likewise - -2008-07-28 Badlop - - * doc/guide.tex: Document how to get error message when ejabberd - crash dumps at start (EJAB-660) - * doc/guide.html: Likewise - -2008-07-25 Jean-Sébastien Pédron - - * src/adhoc.erl, src/mod_configure.erl, src/mod_announce.erl, - src/mod_adhoc.erl, src/gen_iq_handler.erl: Convert to exmpp. - -2008-07-25 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: Speedup startup with many pubsub - nodes (EJAB-669) - * src/mod_pubsub/nodetree_default.erl: Likewise - -2008-07-24 Badlop - - * doc/guide.tex: Include example PAM configuration file - ejabberd.pam (thanks to Evgeniy Khramtsov)(EJAB-704) - * doc/guide.html: Likewise - - * src/mod_proxy65/mod_proxy65_lib.erl: Send protocol compliant - SOCKS5 reply; this breaks support of uncompliant Psi<0.10 (thanks - to Felix Geyer)(EJAB-632) - * src/mod_proxy65/mod_proxy65_stream.erl: Likewise - - * src/mod_register.erl: When a registration is blocked due to IP - limitation, return description in error stanza (EJAB-692) - -2008-07-24 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: Allow owner to subscribe/get its own - node (EJAB-705) - -2008-07-24 Badlop - - * doc/guide.tex: Document room options allow_visitor_nickchange - and allow_visitor_status (EJAB-624) - * doc/guide.html: Likewise - -2008-07-23 Geoff Cant - - * src/mod_muc/mod_muc_room.erl: new room options, - allow_visitor_presence and allow_visitor_nickchange to - block/enable visitors to broadcast presence updates to the room - (EJAB-624). - * src/mod_muc/mod_muc_room.erl: renaming allow_visitor_presence to - allow_visitor_status and altering effect (when false) to remove - custom status tags in presence broadcasts to muc rooms by - visitors. - -2008-07-23 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: remove_user hook removes - subscriptions (EJAB-684), send the last published and not the - first published item (EJAB-675), remove the pubsub/nodes tree, - subscribing to a node sends only last items (EJAB-700) - * src/mod_pubsub/node_pep.erl: added acl and jid match on node - creation permission (EJAB-663) - * src/mod_pubsub/node_default.erl: fix node creation permission - issue for service - * src/mod_pubsub/node_zoo.erl: Likewise - -2008-07-22 Jean-Sébastien Pédron - - * src/mod_disco.erl, src/gen_iq_handler.erl: Convert to exmpp. - - * src/mod_caps.erl, src/gen_iq_handler.erl: Finish conversion to - exmpp. - - * src/ejabberd_local.erl (process_iq_reply): IQ handler are now always - called with arguments in the new format. - -2008-07-22 Badlop - - * src/ejabberd_config.erl: If syntax mistake in config file, show - specific error message (EJAB-616) - -2008-07-22 Alexey Shchepin - - * src/odbc/odbc_queries.erl: Fixed a typo - -2008-07-21 Jean-Sébastien Pédron - - * src/gen_iq_handler.erl: Prepare gen_iq_handler to pass arguments in - the new format to a built-in list of modules known to support them. - Other modules will still receive arguments in the old format. - - * src/mod_roster.erl, src/mod_vcard.erl, src/gen_iq_handler.erl: - Convert to exmpp. - - * src/mod_vcard.erl: One call to jlib:jid_to_string/1 was remaining. - - * src/jlib.erl: Add support for #xmlel to parse_xdata_submit/1 and - friends. This fixes the user search in mod_vcard. - -2008-07-03 Jerome Sautret - - * src/ejabberd_ctl.erl: Call reopen_log_hook for each virtual host. - -2008-07-17 Badlop - - * src/mod_muc/mod_muc_room.erl: Fix to allow a server admin to add - himself as owner of a room (EJAB-687) - -2008-07-17 Jean-Sébastien Pédron - - Merge revisions from 1444 to revision 1457 from trunk. - -2008-07-17 Jean-Sébastien Pédron - - * src/mod_caps.erl, src/ejabberd_c2s.erl: Start conversion to exmpp. - For now, only direct calls from ejabberd_c2s are done. Calls through - gen_iq_handler aren't. - -2008-07-17 Christophe Romain - - * src/web/Makefile.in: use -DSSL39 if compiling with R12 - -2008-07-16 Badlop - - * src/ejabberd_c2s.erl: Put auth_module in Info always (EJAB-549) - - * src/*.hrl: Get back all ejabberd header files to their original - placement in src/ subdirectories (EJAB-696) - * src/*/*.erl: Likewise - * src/*/Makefile.in: Likewise - * src/Makefile.in: Install header files in system include/ dir, - reproducing the subdirectory structure of src/ - - * src/ejabberdctl.template: Update environment variable names - -2008-07-15 Badlop - - * src/ejabberdctl.template: Small fix so arguments of the command - are also passed to erl - - * doc/guide.tex: Improve explanation of option 'hosts' in - ejabberd_service - * doc/guide.html: Likewise - -2008-07-15 Alexey Shchepin - - * src/web/ejabberd_http_poll.erl: Report connection's IP address - - * src/ejabberd_c2s.erl: Rolled back the previous IP getting patch - * src/ejabberd_sm.erl: Likewise - * src/ejabberd_receiver.erl: Likewise - * src/web/ejabberd_http_poll.erl: Likewise - -2008-07-15 Jean-Sébastien Pédron - - Merge revisions from 1434 to revision 1444 from trunk. - - * configure: Recreated with autoconf(1) after merge. - -2008-07-14 Badlop - - * doc/guide.tex: Update what permissions does enable-user grant - * doc/guide.html: Likewise - - * src/configure.ac: Don't explicitely put root privileges when a - user is not explicitely enabled - * src/configure: Likewise - * src/Makefile.in: Likewise - - * src/Makefile.in: Fix docdir so it recognizes prefix. If sbin dir - does not exist, create it. Fix cookiefile permission - check. (EJAB-696) - -2008-07-13 Badlop - - * src/configure.ac: Update installation permissions (EJAB-402) - * src/configure: Likewise - - * src/Makefile.in: The mnesia, ebin and priv dirs are now - installed in different locations. Install header files and - documentation (EJAB-696) - * doc/guide.tex: Likewise - * doc/guide.html: Likewise - - * include/*.hrl: Place for all ejabberd header files (EJAB-696) - * src/*/*.erl: Update references to header files - * src/*/Makefile.in: Include the include/ dir - - * src/configure.ac: Allow to execute ejabberd with a normal - system user (thanks to Viq)(EJAB-402) - * src/configure: Likewise - * src/ejabberdctl.template: Likewise - * src/Makefile.in: Likewise - * doc/guide.tex: Likewise - * doc/guide.html: Likewise - -2008-07-12 Badlop - - * src/configure.ac: Improve legibility - * src/aclocal.m4: Likewise - * src/configure: Likewise - - * src/ejabberdctl.template: Remove garbage variable. Document node - option - - * doc/guide.tex: Add references to sections. - * doc/guide.html: Likewise - -2008-07-11 Badlop - - * src/mod_register.erl: Revert support for io_lib newline, since - there is a standard character that representes newline (EJAB-501) - * doc/guide.tex: Update documentation to explain newline character - * doc/guide.html: Likewise - * src/ejabberd.cfg.example: Likewise - -2008-07-11 Jean-Sébastien Pédron - - Merge revisions from 1362 to revision 1434 from trunk. - -2008-07-11 Jean-Sébastien Pédron - - * src/ejabberd_s2s_in.erl, src/ejabberd_s2s_out.erl, - src/ejabberd_c2s.erl: Exmpp now takes care of stanza serialization and - compatible namespaces. - - * src/ejabberd_service.erl: Convert to exmpp. Note that this module - hasn't been tested yet! - -2008-07-10 Badlop - - * src/configure.ac: Don't check for erlang header file (EJAB-232) - * src/configure: Likewise - -2008-07-09 Jean-Sébastien Pédron - - * src/ejabberd_c2s.erl: Convert #xmlelement returned by the - 'c2s_stream_features' hook to #xmlel. - - * src/ejabberd_auth.erl, src/ejabberd_auth_internal.erl, - src/ejabberd_auth_odbc.erl, src/ejabberd_auth_ldap.erl, - src/ejabberd_auth_anonymous.erl: Convert to exmpp. - -2008-07-09 Badlop - - * src/configure.ac: Check for erlang header files (EJAB-232) - * src/configure: Likewise - - * src/mod_pubsub/mod_pubsub.erl: Fix compilation warnings - * src/mod_pubsub/node_zoo.erl: Likewise - - * src/mod_shared_roster.erl: Allow to get subscribed to a contact - that is already in the roster by means of a shared roster group: - add it to another roster group and it gets subscribed - automatically (EJAB-407) - - * src/mod_roster.erl: Likewise - - * src/mod_muc/mod_muc_log.erl: Fix XHTML compliance: ensure some - language is set, include ID attribute in each message, add - microseconds to ensure unique value (EJAB-497) - - * src/mod_register.erl: Support for io_lib newline character in - the body of welcome_message (EJAB-501) - * doc/guide.tex: Document the newline character - * src/ejabberd.cfg.example: Example usage of newline character - - * src/ejabberd_config.erl (load_file): error message on sasl.log - is not flattened (EJAB-616) - - * doc/guide.tex: mod_muc_log XMPP URI supports the updated version - RFC 5122 (EJAB-631) - * doc/guide.html: Likewise - -2008-07-08 Jean-Sébastien Pédron - - * src/cyrsasl.erl, src/cyrsasl_anonymous.erl, src/cyrsasl_digest.erl, - src/cyrsasl_plain.erl, src/ejabberd_c2s.erl: Errors are now atoms, not - strings anymore. - -2008-07-08 Badlop - - * tools/ejabberdctl: Work also when 'which' is unavailable - -2008-07-08 Christophe Romain - - * src/web/ejabberd_http_poll.erl: improve ip fetching patch - -2008-07-07 Badlop - - * src/Makefile.in: Spool, config and log dirs: writtable by owner, - readable by group, nothing by others (EJAB-686) - * doc/guide.tex: New section Securing sensible files - * doc/guide.html: Likewise - - * doc/guide.tex: Solaris Makefile install: use ginstall (thanks to - Jonathan Auer)(EJAB-649) - * doc/guide.html: Likewise - -2008-07-03 Jerome Sautret - - * src/mod_privacy_odbc.erl: Support for privacy lists in MySQL - (thanks to Igor Goryachev)(EJAB-538) - -2008-07-03 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: Fix permission control on item - retrieve (EJAB-453) - * src/mod_pubsub/node_dispatch.erl: Likewise - * src/mod_pubsub/node_buddy.erl: Likewise - * src/mod_pubsub/node_private.erl: Likewise - * src/mod_pubsub/node_public.erl: Likewise - * src/mod_pubsub/node_default.erl: Likewise - * src/mod_pubsub/node_pep.erl: Likewise - * src/mod_pubsub/node_club.erl: Likewise - * src/mod_pubsub/gen_pubsub_node.erl: Likewise - * src/mod_pubsub/node.template: Likewise - - * src/mod_pubsub/mod_pubsub.erl: Allow subscriber to request specific - items by ItemID; Allow to retrieve pubsub#title configuration (thanks - to Kevin Crosbie); Fix forbidden result on setting - affiliation/subscription - - * src/mod_pubsub/node_zoo.erl: Add node type without - home// constraint - - * src/ejabberd_local.erl: prevent iq_response table overload - (EJAB-608) - * src/mod_caps.erl: Likewise - - * src/web/ejabberd_http.erl: Retrieve correct IP from http connection - * src/web/ejabberd_http_poll.erl: Likewise - * src/ejabberd_receiver.erl: Likewise - * src/ejabberd_sm.erl: Likewise - * src/ejabberd_c2s.erl: Likewise - -2008-07-01 Jean-Sébastien Pédron - - * src/ejabberd_sm.erl: Convert to exmpp. - - * src/ejabberd_c2s.erl, src/ejabberd_s2s.erl, src/ejabberd_s2s_in.erl, - src/ejabberd_s2s_out.erl: Use the new clause of - exmpp_stanza:reply_with_error/2, exmpp_iq:error/2, - exmpp_iq:error_without_original/2 and the new - exmpp_jid:make_bare_jid/1. - - * src/jlib.erl: Add function short_bare_jid/1. - - * src/ejabberd_sm.erl: Forgot to convert a from the new to - the old record. - - * src/ejabberd_c2s.erl: Use jlib:short_bare_jid/1. Rewrite - is_auth_packet/1 to use new formats. Don't convert before - calling ejabberd_sm:set_presence/7. Don't convert broadcast children, - because it's an internal special element. - - * src/acl.erl: Convert to exmpp. - - * src/ejabberd_c2s.erl, src/ejabberd_s2s_in.erl: acl doesn't require - conversion anymore. - - * src/ejabberd_router.erl: Use a function to convert to old - structures instead of duplicating code inside the module. - - * src/gen_iq_handler.erl: Convert to exmpp. - - * src/ejabberd_sm.erl, src/ejabberd_c2s.erl: Don't convert - before calling gen_iq_handler:handle/7. - - * src/ejabberd_local.erl: Convert to exmpp. - - * src/jlib.erl: Accept new #xmlel in functions that create #iq. A - warning is printed when these functions are called with an old - #xmlelement. - - * src/ejabberd_router.erl: Change warning message. - - * src/ejabberd_sm.erl, src/ejabberd_c2s.erl, src/ejabberd_local.erl, - src/gen_iq_handler.erl: Do not use the #iq record anymore internally. - However it's still created and passed to other modules. - - * src/ejabberd_router.erl, src/ejabberd_sm.erl, - src/ejabberd_local.erl, src/ejabberd_s2s.erl: Routing is now done with - #xmlel. A warning is printed if those modules have to route an old - #xmlelement. - -2008-06-30 Jean-Sébastien Pédron - - * src/Makefile.in: Remove the -I flag for exmpp includes; the - -include_lib pragma is a better solution. - - * src/ejabberd_c2s.erl, src/ejabberd_s2s_in.erl, - src/ejabberd_s2s_out.erl: Use -include_lib instead of -include to - include exmpp.hrl. - - * src/ejabberd_s2s.erl: Convert to exmpp. - - * src/jlib.erl: Add function to convert to and from old ejabberd #jid - record. Move function short_jid/1 from ejabberd_c2s. - - * src/ejabberd_c2s.erl, src/ejabberd_s2s.erl, src/ejabberd_s2s_in.erl, - src/ejabberd_s2s_out.erl: Use the new functions from jlib. Use the new - exmpp_xml:node_to_list/3. - - * src/ejabberd_router.erl: Before doing any routing, the router print - a warning if old structures are used. Then it converts the structures - to the old format and route them. The router doesn't care about the - structures format but the conversion is necesary for code called from - this module. - - * src/ejabberd_c2s.erl, src/ejabberd_s2s.erl, src/ejabberd_s2s_in.erl, - src/ejabberd_s2s_out.erl: No conversion is done before calling - ejabberd_router:route/3. - -2008-06-29 Badlop - - * src/ejabberd_ctl.erl: Web Admin and Ad-hoc admin: dump only - persistent tables (EJAB-678) - - * src/mod_pubsub/node_pep.erl: Complain if mod_caps disabled and - mod_pubsub has PEP plugin enabled (EJAB-677) - -2008-06-28 Badlop - - * src/mod_muc/mod_muc_room.erl: Allow to store room - description (thanks to Christopher Dupont)(EJAB-670) - -2008-06-27 Jean-Sébastien Pédron - - * src/ejabberd_c2s.erl, src/ejabberd_s2s_out.erl, - src/ejabberd_s2s_in.erl: Use the new exmpp namespace macro names. - Update send_element/2 to use exmpp new to_list functions. - -2008-06-26 Jean-Sébastien Pédron - - * src/ejabberd_c2s.erl: Use a macro in ?DEFAULT_NS instead of the - namespace atom directly. Comment DBGFSM our again. Remove macro - ERR_SERVICE_UNAVAILABLE. - (wait_for_auth, is_auth_packet): An empty resource is returned as - 'undefined', not the empty string in the {auth, ...} tuple. - (handle_sync_event): Remove a debugging printf. - (handle_info/{route, ...}): Use macro IS_PRESENCE & friends instead of - direct matching with NS_JABBER_CLIENT and name. This way, the S2S - doesn't have to change the namespace of all its incoming stanzas to - NS_JABBER_CLIENT. - (send_element): For stanzas under the NS_JABBER_SERVER namespace, lie - to exmpp_xml by telling it that this namespace is the default one. - - * src/ejabberd_s2s_in.erl, src/ejabberd_s2s_out.erl: Convert to exmpp. - -2008-06-25 Jean-Sébastien Pédron - - * src/ejabberd_c2s.erl: Finish ejabberd_c2s conversion with the - functions related to offline stanzas. - - * src/ejabberd_c2s.erl (get_subscribed_and_online): Fix short JID - comparison; it was using 'undefined' instead of empty strings. - -2008-06-24 Jean-Sébastien Pédron - - * src/ejabberd_c2s.erl: The handle_info clause that treats routing - order is now converted. In-memory sets and dict still use the short - JID form with empty strings for unspecified fields. Users are able to - connect to ejabberd but some features don't seem to work proprerly. - - * src/ejabberd_c2s.erl: Use the new exmpp_stream:opening_reply/3 - function in wait_for_stream/2. The function terminate/3 is converted - to exmpp. - - * src/ejabberd_c2s.erl: Convert all presence-related functions. - -2008-06-23 Jean-Sébastien Pédron - - * src/ejabberd_c2s.erl (session_established): Convert JID to the - expected form outside of the C2S (empty fields must be set to the - empty string). This fixes the broken routing. - -2008-06-21 Badlop - - * src/web/ejabberd_http.erl: Support PUT and DELETE methods in - ejabberd_http (thanks to Eric Cestari)(EJAB-662) - - * doc/guide.tex: Explain that S2S outgoing first tries IPv4 and if - that fails then tries IPv6 - * doc/guide.html: Likewise - -2008-06-20 Jean-Sébastien Pédron - - * src/configure, src/aclocal.m4, src/Makefile.in: Add exmpp detection. - - * 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. - - * src/ejabberd_c2s.erl: Change the usage of #state.lang somewhat. - Fix value of DefaultLang: it doesn't contain the whole serialized - attribute. Use exmpp_jid:make_bare_jid/2 more. - -2008-06-19 Jean-Sébastien Pédron - - * src/ejabberd_receiver.erl: Replace the use of xml_stream by - exmpp_xmlstream. exmpp_xml is configured to produce old #xmlelement - records. exmpp_xmlstream is configured to send old xmlstreamstart - tuple. Users are able to connect to ejabberd. Next step: - ejabberd_c2s. - -2008-06-19 Jean-Sébastien Pédron - - Start the transition to exmpp. - -2008-06-18 Badlop - - * src/ejabberd.app: The ejabberd version number is defined in the - OTP application resource file, in the key 'vsn' (EJAB-657) - * src/ejabberd.hrl: The macro VERSION now consults the ejabberd - application key vsn - * src/configure.erl: Load the ejabberd application description - * doc/Makefile: Read ejabberd version from ejabberd.app vsn - * doc/api/Makefile: Likewise - -2008-06-18 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: get_default bugfix (EJAB-656) - -2008-06-13 Badlop - - * src/mod_muc/mod_muc_room.erl: Allow admins to send messages to - rooms even if not joined (EJAB-645) - * doc/guide.tex: Likewise - * doc/guide.html: Likewise - - * src/ejabberd.cfg.example: Add registration_timeout (EJAB-653) - - * doc/guide.tex: Table of listener modules converted to - description. Table of modules overview simplified, and module - names link to their sections. Document - ldap_local_filter (EJAB-179). Title in HTML is shorter. - Update several external URIs. - - * doc/guide.html: Regenerated with all the latest changes - -2008-06-12 Badlop - - * doc/guide.tex: Permanent reference URL for sections (EJAB-651). - Changes in CSS: verbatim text is indented and has grey background; - descriptions are indented; table borders are softer. Fix - indentation of verbatim text. - -2008-06-10 Badlop - - * src/ejabberd_c2s.erl: Bugfix: deliver messages when first - presence is Invisible (thanks to Dariusz Markowicz)(EJAB-262) - -2008-06-08 Badlop - - * doc/guide.tex: Small fixes (thanks to Christoph Anton Mitterer) - * doc/introduction.tex: Likewise - * doc/guide.html: Likewise - -2008-06-05 Badlop - - * doc/guide.tex: Document ejabberdctl status code (EJAB-633) - * doc/guide.html: Likewise - -2008-06-04 Badlop - - * src/msgs/pl.msg: Bugfix in arguments of translated string that - could crash the room (thanks to Anastasia Gornostaeva) - -2008-05-31 Badlop - - * src/web/ejabberd_web.erl (make_xhtml/2): Allow to include - elements in the HTTP header - - * src/odbc/odbc_queries.erl (del_user_return_password): Return - password (thanks to Oleg Palij) - -2008-05-22 Mickael Remond - - * src/ejabberd_s2s.erl: Added s2s_send_packet and s2s_receive_packet - hooks (EJAB-635). - * src/ejabberd_s2s_in.erl: Likewise. - - * src/ejabberd_c2s.erl: user_send_packet hook now called on all packets - including presence packets (EJAB-634) - -2008-05-22 Badlop - - * README: R12 support: remove compilation warning (EJAB-630) - -2008-05-19 Badlop - - * doc/guide.html: Update - - * src/configure.ac: R12 support: remove compilation - warning (EJAB-630) - * src/configure: Likewise - * doc/guide.tex: Likewise - - * doc/guide.tex: Describe how to disable registration - limitation (EJAB-614) - -2008-05-19 Mickael Remond - - * src/ejabberd_s2s_out.erl: Avoid an harmless error (function clause in - logs) - -2008-05-17 Badlop - - * src/extauth.erl: Log strange responses from extauth script. Use - timeout (EJAB-627) - -2008-05-16 Badlop - - * src/mod_muc/mod_muc_room.erl: Allow change_state of a room - -2008-05-16 Christophe Romain - - * src/ejabberd_s2s_out.erl: Change FSMTIMEOUT to 30s - -2008-05-12 Badlop - - * src/mod_muc/mod_muc_room.erl: Return Forbidden error message - when user sends private message in a room that disallows - it (EJAB-595) - - * src/web/ejabberd_http.erl (parse_auth): Allow password that - include colon character (EJAB-622) - -2008-05-09 Mickael Remond - - * src/mod_ip_blacklist.erl: Better error handling (EJAB-625). - -2008-05-05 Mickael Remond - - * src/ejabberd_c2s.erl: Added C2S blacklist support (EJAB-625). - * src/mod_ip_blacklist.erl: Likewise. - * src/jlib.erl: Added IP format tuple to string function. - * src/ejabberd_socket.erl: Properly handled c2s start failure (happen - for blacklisted IP). - -2008-05-04 Alexey Shchepin - - * src/ejabberd_receiver.erl: Don't activate a socket untill its - receiver process is controlling it - -2008-04-30 Christophe Romain - - * src/mod_caps.erl: XEP-0115 patch (EJAB-618) - -2008-04-29 Badlop - - * src/ejabberd_s2s_out.erl: Improve confusing log message in s2s - connection: wait_for_validation connect timeout (EJAB-617) - - * src/ejabberd.cfg.example: Small improvements in explanations - - * doc/guide.tex: Document MUC room options (EJAB-619) - -2008-04-28 Badlop - - * doc/guide.tex: Document the option max_s2s_connections - -2008-04-28 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: remove unused served_hosts option - and make init message be debug and not info - -2008-04-27 Alexey Shchepin - - * src/mod_muc/mod_muc_room.erl: Fixed room shaper processing - -2008-04-26 Badlop - - * src/mod_shared_roster.erl: Fix for new registered accounts not - being immediately shown in an 'all' special shared roster - group (thanks to Alexey Shchepin) (EJAB-71) - * src/mod_register.erl: New vhost event user_registered - - * doc/guide.tex: Document option registration_timeout (EJAB-614) - -2008-04-25 Badlop - - * src/ejabberd_c2s.erl: Added forbidden_session_hook - - * src/acl.erl: New access types: resource, resource_regexp and - resource_glob - * doc/guide.tex: Likewise - -2008-04-23 Alexey Shchepin - - * src/treap.erl: Bugfix - - * src/mod_register.erl: Fixed table creation, timeout isn't - activated when registration fails - - * src/mod_register.erl: Restrict registration frequency per IP or - user (EJAB-614) - * src/ejabberd_c2s.erl: Pass IP to the c2s_unauthenticated_iq hook - * src/ejabberd_config.erl: Added registration_timeout option - - * src/treap.erl: Treaps implementation - -2008-04-22 Badlop - - * src/ejabberd_auth.erl: Improve anonymous authentication to not - remove rosters accidentally (EJAB-549). New functions in - ejabberd_auth to get/check password and know which module accepted - the authentication. New element 'auth_module' in ejabberd_c2s - record 'statedata'. Cyrsasl provides a new property in the - response: {auth_module, AuthModule}. - * src/ejabberd_auth_anonymous.erl: Likewise - * src/ejabberd_c2s.erl: Likewise - * src/cyrsasl_anonymous.erl: Likewise - * src/cyrsasl_digest.erl: Likewise - * src/cyrsasl_plain.erl: Likewise - -2008-04-18 Badlop - - * src/ejabberd_s2s_out.erl: Fix long timeout when reconnecting s2s - after a remote server crash (EJAB-540) - * src/ejabberd_s2s_in.erl: Likewise - * src/ejabberd_s2s.erl: Likewise - * doc/guide.tex: Likewise - -2008-04-16 Badlop - - * doc/guide.tex: Clarification: PEP is enabled in default config - -2008-04-14 Christophe Romain - - * src/mod_caps.erl: Cache negative response (EJAB-474) - -2008-04-12 Badlop - - * src/web/ejabberd_web_admin.erl: Include Last-Modified HTTP - header in responses to allow caching (EJAB-546) - -2008-04-11 Badlop - - * src/Makefile.in: Improved indentation of GCC call - * src/ejabberd_zlib/Makefile.in: Likewise - * src/mod_irc/Makefile.in: Likewise - * src/stringprep/Makefile.in: Likewise - * src/tls/Makefile.in: Likewise - - * src/ejabberd_listener.erl (start_listener): Revert SVN r1260. - -2008-04-11 Alexey Shchepin - - * src/ejabberd_config.erl: Removed a dependency on string:to_upper - - * src/tls/tls_drv.c: Fixed gcc signedness warnings (EJAB-447) - * src/ejabberd_zlib/ejabberd_zlib_drv.c: Likewise - - * src/expat_erl.c: Removed R9B workaround (EJAB-447) - -2008-04-10 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: fix identity and database update - bugfix - * src/mod_pubsub/nodetree_default.erl: Likewise - -2008-04-10 Mickael Remond - - * src/ejabberd_c2s.erl: Uniform default value for empty privacy - list. Fixes (EJAB-603). - -2008-04-08 Badlop - - * src/ejabberd_auth_ldap.erl: LDAP function to get the number of - registered users is too slow (EJAB-331): set timeout in LDAP - search queries (thanks to Evgeniy Khramtsov) and return the number - of registered users. - -2008-04-07 Mickael Remond - - * doc/guide.tex: Documented the IQ discipline {queue, N}. - * doc/guide.html: Likewise. - -2008-04-05 Badlop - - * doc/guide.tex: Fix default_room_opts with default_room_options - * doc/guide.html: Likewise - -2008-04-04 Badlop - - * src/ejabberd_auth_ldap.erl (get_vh_registered_users_number): New - function that returns 0 registered users (EJAB-331). - - * src/ejabberd_c2s.erl (process_presence_probe): Don't route a - presence probe to oneself (EJAB-498) - -2008-04-02 Badlop - - * src/ejabberd_config.erl: Add support to include additional - configuration files. Add support for macro definition and - usage. (EJAB-593) - * doc/guide.tex: Likewise - * doc/guide.html: Likewise - -2008-04-02 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: add condition inclusion of pep in - disco identity (EJAB-564) - - * src/Makefile.in: Do not ignore values passed from configure - (thanks to Justin Boffemmyer)(EJAB-592) - -2008-04-01 Badlop - - * doc/guide.tex: Updated command line parameters, epmd section - * doc/guide.html: Likewise - - * doc/api/Makefile: Report the correct ejabberd version. When - cleaning, remove also erlang.png - - * src/mod_muc/mod_muc_room.erl: Update source code to prevent - warning messages from EDoc - * src/mod_pubsub/mod_pubsub.erl: Likewise - * src/mod_pubsub/node_default.erl: Likewise - * src/mod_pubsub/nodetree_default.erl: Likewise - * src/mod_pubsub/nodetree_virtual.erl: Likewise - * src/mod_pubsub/pubsub.hrl: Likewise - -2008-04-01 Christophe Romain - - * src/ejabberdctl.template: Add firewalling port range definition - * src/ejabberdctl.cfg.example: Likewise - -2008-03-31 Badlop - - * src/ejabberd_listener.erl: Remove code of the unused listening - socket option 'ssl' (EJAB-159) - * src/ejabberd_app.erl: Likewise - - * doc/webadmmain.png: Updated to ejabberd 2.0.0 - * doc/webadmmainru.png: Likewise - - * doc/disco.png: Removed because not used - - * doc/guide.tex: Fix Latex reference to webadmin section. Update - explanation of screenshots. Update xmpp addresses of Mickael - Remond and Sander Devrieze. - * doc/guide.html: Likewise - - * doc/Makefile: Remove the Hevea deprecated option -noiso - * doc/guide.html: Likewise - * doc/dev.html: Likewise - * doc/features.html: Likewise - - * src/ejabberd_listener.erl (start_listener): Start also the - supervisor of the module - -2008-03-27 Badlop - - * doc/guide.tex: Fix epam location (thanks to Evgeniy Khramtsov) - * doc/guide.html: Likewise - -2008-03-26 Badlop - - * src/Makefile.in: Support for parallel compilation with 'make -j' - in multi core CPUs: fix compilation dependencies; compile - behaviors before other source code. (thanks to Jonathan Schleifer) - * src/mod_pubsub/Makefile.in: Likewise - * src/eldap/Makefile.in: Likewise - -2008-03-26 Alexey Shchepin - - * src/ejabberd_local.erl: The iq_response table wasn't cloned - automatically on all nodes which resulted in a single point of - failure - -2008-03-25 Badlop - - * src/Makefile.in: Failure to install epam is not - critical (EJAB-573). Only try to install epam if pam was enabled - in configure script (thanks to Etan Reisner)(EJAB-586) - -2008-03-24 Badlop - - * doc/guide.tex: mod_vcard_ldap replace NICK with NICKNAME (thanks - to Andreas Ntaflos) - * doc/guide.html: Likewise - - * src/msgs/de.msg: Fix irc typo (thanks to Jonathan Schleifer) - * src/msgs/cs.msg: Likewise - * src/msgs/pl.msg: Likewise - * src/msgs/sk.msg: Likewise - -2008-03-22 Mickael Remond - - * src/eldap/Makefile.in: Generate ELDAPv3.beam during first Makefile - pass (EJAB-583). - -2008-03-22 Badlop - - * doc/guide.tex: Document service_check_from (EJAB-576) - * doc/guide.html: Likewise - -2008-03-21 Badlop - - * src/mod_caps.erl: Move two log calls ERROR_MSG to DEBUG - * src/shaper.erl: Move log call INFO_MSG to DEBUG - - * doc/guide.tex: Document s2s_default_policy and - s2s_host (EJAB-575) - * doc/guide.html: Likewise - -2008-03-21 Christophe Romain - - * src/pam/epam.erl: Seek epam binary into priv/bin (EJAB-573) - * src/ejabberd.erl: Likewise - * src/Makefile.in: Likewise - * src/ejabberdctl.template: Likewise - * tools/ejabberdctl: Likewise - - * src/mod_pubsub/mod_pubsub.erl: Pubsub subscription is now wrapped in - pubsub tags (EJAB-580) - -2008-03-21 Badlop - - * src/cyrsasl_digest.erl: Rewrite io:format calls to loglevel - macros (EJAB-555) - * src/ejabberd_auth.erl: Likewise - * src/ejabberd_ctl.erl: Likewise - * src/ejabberd_loglevel.erl: Likewise - * src/ejabberd_s2s.erl: Likewise - * src/ejabberd_sm.erl: Likewise - * src/ejabberd_update.erl: Likewise - * src/extauth.erl: Likewise - * src/mod_irc/mod_irc.erl: Likewise - * src/shaper.erl: Likewise - * src/tls/tls.erl: Likewise - * src/web/ejabberd_http_poll.erl: Likewise - - * src/ejabberd.hrl: New macro ?PRINT(Format, Args) to print in - standard output - -2008-03-20 Badlop - - * doc/guide.tex: Improve explanation of how to start ejabberd when - binary installer. Don't recommend R12 in Windows compilation. - Describe what happens if maxrate shaper is exceeded. - * doc/guide.html: Likewise - -2008-03-20 Mickael Remond - - * src/eldap.erl: Improved logging. We now use ejabberd logging - framework (EJAB-582). - - * src/eldap.erl: Faster LDAP reconnection (Thanks to Christophe - Romain) (EJAB-581) - -2008-03-17 Mickael Remond - - * src/ejabberd_s2s.erl: Only trigger s2s_connect_hook on - successful connection (EJAB-566) - * src/ejabberd_s2s_out.erl: Likewise - -2008-03-15 Mickael Remond - - * src/ejabberd_ctl.erl: API improvement: Added - reopen_log_hook (EJAB-565) - - * src/ejabberd_s2s.erl: API improvement: Added s2s_connect_hook - (EJAB-566). - -2008-03-13 Badlop - - * src/odbc/ejabberd_odbc.erl: Start ODBC explicitely because - Erlang R12 doesn't start automatically like in R11 and - older (thanks to Sergei Golovan)(EJAB-541) - - * src/ejabberd.hrl: Removed unused ejabberd_debug and - PRIVACY_SUPPORT. Reordered the remaining options - - * doc/guide.tex: Describe option Matches in mod_vcard_ldap (thanks - to Evgeniy Khramtsov)(EJAB-530). Fix typo in the description of - ldap_server option. - * doc/guide.html: Likewise - - * src/mod_echo.erl: Small change to avoid a compilation warning of - unused function - -2008-03-12 Badlop - - * src/web/ejabberd_web_admin.erl (term_to_string): Show Erlang - terms in one line in Erlang R12 (EJAB-503) - -2008-03-11 Badlop - - * src/ejabberd_s2s_in.erl (get_cert_domains): When compiling with - Erlang R12, replace the calls to deprecated module PKIX1Explicit88 - with OTP-PKIX (EJAB-556) - -2008-03-10 Badlop - - * src/ejabberd_update.erl: Fix crash when browsing the Update - page in Erlang R12 (EJAB-552) - -2008-03-09 Alexey Shchepin - - * src/web/ejabberd_http_poll.erl: Fixed HTTP headers when a - requested session doesn't exist - -2008-03-09 Badlop - - * src/mod_proxy65/mod_proxy65_service.erl: Implement alternative - to the deprecated function inet:ip_to_bytes (thanks to Evgeniy - Khramtsov)(EJAB-542) - -2008-03-07 Mickael Remond - - * src/eldap/eldap_pool.erl: Improved logging - -2008-03-04 Badlop - - * doc/guide.tex: Improve documentation of host_config - add (EJAB-544) - * doc/guide.html: Likewise - * src/ejabberd.cfg.example: Likewise - * src/ejabberd_config.erl: Likewise - - * doc/guide.tex: mod_announce recommends, but doesn't require - mod_adhoc (thanks to Anastasia Gornostaeva) - * doc/guide.html: Likewise - * src/ejabberd.cfg.example: Likewise - -2008-03-03 Alexey Shchepin - - * src/tls/tls.erl: recv_data/2 doesn't throw exceptions now - * src/ejabberd_zlib/ejabberd_zlib.erl: Likewise - -2008-02-29 Alexey Shchepin - - * src/mod_roster.erl: Fixed "from" attribute in roster pushes - * src/mod_roster_odbc.erl: Likewise - -2008-02-28 Badlop - - * src/ejabberd_app.erl (prep_stop): Stop modules when stopping - ejabberd (EJAB-536) - * src/mod_caps.erl (stop): Probably not needed to stop supervisor - child (EJAB-536) - * src/mod_muc/mod_muc.erl (room_destroyed): Catch message - sending (EJAB-536) - * src/mod_muc/mod_muc_room.erl (init): Ensure rooms are called - when the process dies due to a linked die (EJAB-536) - -2008-02-27 Mickael Remond - - * src/ejabberd_check.erl: Separate config loading from - configuration sanity checks (EJAB-533) - * src/src/ejabberd_app.erl: Likewise - * src/ejabberd_app.erl: Likewise - -2008-02-26 Badlop - - * src/msgs/it.msg: Updated (thanks to Smart2128) - -2008-02-21 Badlop - - * doc/release_notes_2.0.0.txt: Small fixes and update date - -2008-02-20 Badlop - - * README: Updated to match the content of the ejabberd Guide - - * doc/release_notes_2.0.0.txt: Updated version number and date - - * doc/guide.tex: Mentioned the problems about Windows service - * doc/guide.html: Likewise - - * src/msgs/ru.msg: Updated (thanks to Konstantin Khomoutov) - * src/msgs/zh.msg: Updated (thanks to Mike Wang and Zhan Caibao) - -2008-02-19 Badlop - - * src/msgs/ca.msg: Updated (thanks to Vicent Alberola Canet) - * src/msgs/cs.msg: Updated (thanks to Lukas Polivka) - * src/msgs/de.msg: Updated (thanks to Cord Beermann and Nikolaus - Polak) - * src/msgs/eo.msg: Updated (thanks to Andreas van Cranenburgh) - * src/msgs/es.msg: Updated - * src/msgs/fr.msg: Updated (thanks to Christophe Romain) - * src/msgs/gl.msg: Updated (thanks to Carlos E. Lopez) - * src/msgs/nl.msg: Updated (thanks to Andreas van Cranenburgh) - * src/msgs/no.msg: Updated (thanks to Stian B. Barmen) - * src/msgs/pt-br.msg: Updated (thanks to Otavio Fernandes) - * src/msgs/uk.msg: Updated (thanks to Stoune and Ruslan Rakhmanin) - -2008-02-19 Christophe Romain - - * src/odbc/ejabberd_odbc.erl: add pgsql driver monitoring - -2008-02-19 Mickael Remond - - * src/ejabberd_config.erl: dirty_get_registered_users now - correctly returns all users for all vhosts no matter which - back-end is used (EJAB-527) - * src/ejabberd_auth_odbc.erl: Likewise - * src/ejabberd_auth_internal.erl: Likewise - * src/ejabberd_auth.erl: Likewise - * src/ejabberd_auth_external.erl: Likewise - * src/ejabberd_auth_ldap.erl: Likewise - -2008-02-18 Christophe Romain - - * src/ejabberd_c2s.erl: Bug in get_conn_type since SVN r1194 crashes - http-bind and http-poll (thanks to Brian Cully) (EJAB-526) - -2008-02-15 Badlop - - * doc/release_notes_2.0.0.txt: Describe in the Release Notes the - upgrade instructions (EJAB-522) - -2008-02-15 Christophe Romain - - * src/ejabberd_sm.erl: Retreive connection type in - sm_register_connection_hook - * src/ejabberd_c2s.erl: Likewise - * src/ejabberd_auth_anonymous.erl: Likewise - -2008-02-14 Badlop - - * src/mod_muc/mod_muc_room.erl: Allow unmoderated rooms (EJAB-437) - * src/msgs/*: Recover old translations to several languages from - ejabberd 1.1.4 - -2008-02-14 Alexey Shchepin - - * src/cyrsasl_digest.erl: Unquote backslash in DIGEST-MD5 quoted - strings (EJAB-304) - - * src/mod_roster.erl: Removed the ancient Psi roster workaround - * src/mod_roster_odbc.erl: Likewise - -2008-02-12 Badlop - - * src/web/ejabberd_web_admin.erl: Fixed native support for all the - ACL types (EJAB-253) - - * src/acl.erl: Normalize ACL before adding to the configuration - tables (EJAB-521) - -2008-02-11 Mickael Remond - - * src/ejabberd_auth.erl: Do not allow empty password at - creation. On authent, check in all cases that password is not - empty. - * src/ejabberd_auth_odbc.erl: Likewise - * src/ejabberd_auth_internal.erl: Likewise - * src/ejabberd_auth_external.erl: Likewise - - * src/ejabberd_receiver.erl: Avoid crash to appear in log, when - trying to close a stream with an undefined state. - -2008-02-11 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: Bugfix: event used in place of x when - xmlns is pubsub#event (EJAB-518) - -2008-02-11 Badlop - - * src/mod_muc/mod_muc_room.erl: Bugfix: local message stanza may - not have an attribute From (EJAB-515) - -2008-02-08 Badlop - - * src/mod_muc/mod_muc_room.erl: Include the error condition in the - presence status when kicking a participant due to an error - stanza (EJAB-496) - - * src/ejabberd.cfg.example: Document options to SQL keep alive - interval and pool size (EJAB-206) - * doc/guide.tex: Likewise - * doc/guide.html: Likewise - -2008-02-06 Badlop - - * src/mod_muc/mod_muc_room.erl: Support for decline of invitation - to MUC room (EJAB-515) - -2008-02-06 Mickael Remond - - * src/mod_pubsub/node_buddy.erl: Fixed typo - * src/mod_pubsub/node_club.erl: Likewise - * src/mod_pubsub/node_dispatch.erl: Likewise - * src/mod_pubsub/node_pep.erl: Likewise - * src/mod_pubsub/node_private.erl: Likewise - * src/mod_pubsub/node.template: Likewise - - * src/mod_pubsub/gen_pubsub_node.erl: API improvement: Added a way - to generate custom item name - * src/mod_pubsub/node_dispatch.erl: Likewise - * src/mod_pubsub/node_buddy.erl: Likewise - * src/mod_pubsub/node_private.erl: Likewise - * src/mod_pubsub/node_club.erl: Likewise - * src/mod_pubsub/node_public.erl: Likewise - * src/mod_pubsub/node_default.erl: Likewise - * src/mod_pubsub/node_pep.erl: Likewise - * src/mod_pubsub/mod_pubsub.erl: Small API improvements and - refactoring - -2008-02-04 Badlop - - * src/ejabberd.hrl: Updated version to 2.1.0-alpha - * doc/dev.html: Likewise - * doc/features.html: Likewise - * doc/guide.html: Likewise - * doc/version.tex: Likewise - -2008-02-04 Alexey Shchepin - - * src/mod_muc/mod_muc_room.erl: Append "(n/a)" to disco room - descriptions when a number of occupants is not available - -2008-02-02 Mickael Remond - - * src/mod_pubsub/nodetree_virtual.erl: Fixed error report at startup. - - * src/mod_pubsub/mod_pubsub.erl: Added the from field in the - get_subnodes pubsub plugin API function. This is usefull to write - plugins to generate the pubsub hierarchy dynamically, based on who - is doing the browsing request. - * src/mod_pubsub/gen_pubsub_nodetree.erl: Likewise - * src/mod_pubsub/nodetree_default.erl: Likewise - * src/mod_pubsub/nodetree_virtual.erl: Likewise - -2008-01-30 Badlop - - * doc/guide.tex: Removed the option served_hosts in mod_pubsub - because it does not work correctly yet (EJAB-504) - * doc/guide.html: Likewise - - * src/mod_echo.erl: Put in comments the call to the educational - function do_client_version - -2008-01-29 Badlop - - * src/mod_muc/mod_muc_room.erl: MUC kicks a participant if sends a - private message with type=error (EJAB-496) - -2008-01-25 Badlop - - * doc/introduction.tex: Updated list of languages - * doc/release_notes_2.0.0.txt: Likewise - - * src/msgs/eo.msg: New Esperanto translation (thanks to Andreas - van Cranenburgh) - - * src/msgs/no.msg: New Norwegian translation (thanks to Stian - B. Barmen) - - * doc/Makefile: Fixed small problem with contributed_modules.tex - -2008-01-25 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: Setting boolean node configuration - fixed (EJAB-509) - * src/mod_pubsub/node_default.erl: Use roster_groups_allowed instead - of access_roster_groups (EJAB-508) - * src/mod_pubsub/node_pep.erl: Likewise - * src/mod_pubsub/node_buddy.erl: Likewise - * src/mod_pubsub/node_club.erl: Likewise - * src/mod_pubsub/node_dispatch.erl: Likewise - * src/mod_pubsub/node_private.erl: Likewise - * src/mod_pubsub/node_public.erl: Likewise - -2008-01-16 Badlop - - * doc/guide.tex: Updated the names of log files. - * doc/guide.html: Likewise - - * src/mod_muc/mod_muc_room.erl: Added log messages for room - destroy - - * src/mod_caps.erl: Small beautify of log error messages - -2008-01-15 Badlop - - * doc/guide.tex: Improved the documentation of Binary - installer. Updated the requirements, specifically: Erlang R10B-9 - is required as minimum, and R12 is not yet supported. Added - section Upgrading ejabberd. Improved documentation about Erlang - runtime system environment variables and command-line parameters. - * doc/guide.html: Likewise - - * doc/release_notes_2.0.0.txt: Updated to RC1 - * doc/version.tex: Likewise - * src/ejabberd.hrl: Likewise - - * doc/introduction.tex: Updated to 22 languages - - * doc/Makefile: Ensure that Bash is used - - * doc/guide.tex: Updated copyright dates to 2008. - * src/*: Likewise - -2008-01-15 Jerome Sautret - - * src/Makefile.in: Allow compilation with Erlang R12 (EJAB-446) - (thanks to Sergei Golovan and Maxim Treskin). Erlang R12 version is - not supported and not recommended for production servers. - * src/aclocal.m4: Likewise - * src/configure.ac: Likewise - * src/configure: Likewise - * src/ejabberd_s2s_in.erl: Likewise - -2008-01-13 Badlop - - * src/ejabberdctl.template: Instead of using the Erlang kernel - variable 'inetrc', use the ERL_INETRC environment variable that is - available since Erlang/OTP R10B-5. - -2008-01-12 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: set_subscription fix (EJAB-494) - -2008-01-11 Christophe Romain - - * src/mod_caps.erl: don't ask capabilities to MUC room participants - (EJAB-478) - -2008-01-10 Christophe Romain - - * src/mod_pubsub/nodetree_default: Force PEP parent node to be [] - - * src/mod_pubsub/mod_pubsub.erl: Send last published PEP event now checks - the correct peer caps (EJAB-491) - * src/ejabberd_c2s.erl: Likewise - -2008-01-09 Badlop - - * src/mod_muc/mod_muc_room.erl: MUC kicks a participant if sends a - private message with type=error (EJAB-496) - -2008-01-08 Badlop - - * src/ejabberdctl.template: Removed the option ERL_FULLSWEEP_AFTER - because it is almost useless regarding ejabberd's performance. - * src/ejabberdctl.cfg.example: Likewise - -2008-01-08 Christophe Romain - - * doc/Makefile: fix version.tex generation bug - -2008-01-01 Badlop - - * src/web/ejabberd_web_admin.erl: Uniformize the name of - ejabberd's web admin to: 'Web Admin' (EJAB-472) - * doc/guide.tex: Likewise - * doc/introduction.tex: Likewise - - * src/web/ejabberd_web_admin.erl: Uniformize ejabberd name in the - text using the Latex command - - * src/mod_muc/mod_muc_room.erl: Resend 'continue' elements in muc - room invitations (EJAB-490) - - * src/ejabberdctl.template: Create logs_dir if doesn't exist. New - parameters --config, --ctl-config, --logs, --spool. Crash dump - renamed to erl_crash_DATETIME.dump. - - * src/ejabberdctl.template: Backport improvements from binary - installer (EJAB-488): options are simple values; enable Kernel - Poll by default, set SMP to auto, set max ports to 32000, max - processes to 250000. - * src/ejabberdctl.cfg.example: Likewise - - * src/ejabberd.inetrc: Renamed ejabberd.inetrc to inetrc - * src/inetrc: Likewise - * src/Makefile.in: Likewise - * doc/guide.tex: Likewise - -2007-12-31 Badlop - - * src/msgs/ca.msg: Updated (thanks to Vicent Alberola Canet) - -2007-12-29 Alexey Shchepin - - * src/ejabberd_s2s_out.erl: Fixed behavior when outgoing_s2s_port - option is not defined (EJAB-487) - -2007-12-27 Badlop - - * src/mod_vcard_ldap.erl: Fix some field names (EJAB-483) - -2007-12-26 Badlop - - * src/web/ejabberd_web_admin.erl: Translate menu items of webadmin - hooks in each module (EJAB-485) - * src/mod_shared_roster.erl: Likewise - - * src/web/ejabberd_web_admin.erl: max_user_sessions access rule - contains an integer, but webadmin always expects atoms (EJAB-482) - -2007-12-25 Badlop - - * src/mod_configure.erl: Bugfix, update to match changes in - mod_announce SVN r1099 - -2007-12-24 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: remove useless get_roster_info call in - presence_probe handling when access rule is presence - -2007-12-24 Mickael Remond - - * doc/release_notes_2.0.0.txt: ejabberd 2.0.0 beta 1 release - notes. - -2007-12-23 Badlop - - * src/msgs/vi.msg: New Vietnamese translation (thanks to EQHO - Communications) - - * src/msgs/th.msg: New Thai translation (thanks to EQHO - Communications) - - * src/msgs/gl.msg: Updated (thanks to Carlos E. Lopez) - - * src/mod_muc/mod_muc_room.erl: Log room creation and - destruction. Ensure JID of owners of MUC room are user, not - server (EJAB-435) - -2007-12-22 Badlop - - * src/ejabberd.app: Update ejabberd.app: add new erlang - modules (EJAB-466) - - * doc/introduction.tex: Small updates - - * doc/guide.tex: Small fixes in Install. Added http_bind to - Listening Ports. - - * src/web/ejabberd_http.erl: Add 'http_bind' option for easy - configuration of HTTP-Binding - - * src/mod_announce.erl: Fixed unnoticeable bug related to Node - matching. Renamed some nonstandard node names according to - XEP-0133. Small reordering of clauses. When editing MOTD, display - current value (EJAB-475) - -2007-12-22 Christophe Romain - - * src/ejabberd_sm.erl: change incoming_presence_hook to - presence_probe_hook - * src/ejabberd_c2s.erl: Likewise - - * src/mod_pubsub/mod_pubsub.erl: send last pep item bugfix and - broadcast optimization (EJAB-468) (EJAB-467) (EJAB-460) (EJAB-469) - * src/mod_pubsub/pubsub.hrl: Likewise - * src/mod_pubsub/node_default.erl: Likewise - -2007-12-22 Badlop - - * src/mod_caps.erl: Bugfix in timeout checking. Check for timeout - when an error response is received, and also before querying - -2007-12-21 Badlop - - * src/ejabberd_ctl.erl: Added new command: mnesia (thanks to - Tsukasa Hamano) - -2007-12-21 Mickael Remond - - * src/msgs/fr.msg: Updated French translation (EJAB-295) - -2007-12-21 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: disco#items bugfix (EJAB-465) - -2007-12-21 Badlop - - * src/msgs/uk.msg: Updated (thanks to Ruslan Rakhmanin) - - * src/msgs/de.msg: Updated (thanks to Nikolaus Polak and Cord - Beermann) - - * contrib/extract_translations/prepare-translation.sh: Small fix - -2007-12-20 Badlop - - * src/mod_caps.erl: Don't include the Node attribute from C - element in the disco#info query - -2007-12-20 Christophe Romain - - * doc/guide.tex: Explain how to launch installer and improve - ejabberdctl usage example (EJAB-420) - * doc/guide.html: Likewise - - * src/mod_pubsub/mod_pubsub.erl: PEP notification bugfix - - * src/odbc/odbc_queries.erl: User count performance improvements - (EJAB-239) - -2007-12-20 Badlop - - * src/msgs/zh.msg: Small update (thanks to Shelley Shyan) - - * src/msgs/ru.msg: Small update (thanks to Konstantin Khomoutov) - -2007-12-19 Badlop - - * src/msgs/pl.msg: Updated (thanks to Andrzej Smyk)(EJAB-463) - - * src/msgs/de.msg: Updated (thanks to Cord Beermann) - - * src/msgs/es.msg: Small update (thanks to Badlop) - - * src/msgs/cs.msg: Small update (thanks to Lukas Polivka alias - Spike411) - - * src/web/ejabberd_web_admin.erl: No need to translate copyright - notice - -2007-12-18 Badlop - - * src/mod_muc/mod_muc_log.erl: Add handling of kicks 321, 322, 332 - - * doc/guide.tex: Document mod_privacy_odbc - - * doc/Makefile: Support for conditional inclusion of documentation - from contributed modules - * doc/guide.tex: Likewise - -2007-12-18 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: Purge related pep nodes at remove_user - * src/mod_pubsub/node_pep.erl: Likewise - -2007-12-17 Badlop - - * src/ejabberd_zlib/Makefile.in: Compile all erl files found in - the directory, so it isn't needed to provide an explicit list of - target files - * src/eldap/Makefile.in: Likewise - * src/mod_irc/Makefile.in: Likewise - * src/mod_muc/Makefile.in: Likewise - * src/mod_proxy65/Makefile.in: Likewise - * src/mod_pubsub/Makefile.in: Likewise - * src/odbc/Makefile.in: Likewise - * src/pam/Makefile.in: Likewise - * src/stringprep/Makefile.in: Likewise - * src/tls/Makefile.in: Likewise - * src/web/Makefile.in: Likewise - * src/ejabberd_zlib/Makefile.win32: Likewise - * src/eldap/Makefile.win32: Likewise - * src/mod_irc/Makefile.win32: Likewise - * src/mod_muc/Makefile.win32: Likewise - * src/mod_proxy65/Makefile.win32: Likewise - * src/mod_pubsub/Makefile.win32: Likewise - * src/odbc/Makefile.win32: Likewise - * src/stringprep/Makefile.win32: Likewise - * src/tls/Makefile.win32: Likewise - * src/web/Makefile.win32: Likewise - - * doc/guide.tex: Remove 'ssl' option from documentation and - configuration load (EJAB-461) - * src/ejabberd_listener.erl: Likewise - - * src/msgs/cs.msg: Small typo (thanks to Lukas Polivka alias - Spike411) - - * src/ejabberd.cfg.example: Small change in order of options - -2007-12-15 Badlop - - * src/mod_irc/iconv.erl: Changed order of handle_info - clause (EJAB-290) - * src/stringprep/stringprep.erl: Likewise - - * src/eldap/eldap.erl: Removed handle_sync_event clause because it - is never called (EJAB-290) - - * src/mod_irc/mod_irc.erl: No need to translate copyright notice - * src/mod_muc/mod_muc.erl: Likewise - * src/mod_proxy65/mod_proxy65_service.erl: Likewise - * src/mod_pubsub/mod_pubsub.erl: Likewise - * src/mod_vcard.erl: Likewise - * src/mod_vcard_ldap.erl: Likewise - * src/mod_vcard_odbc.erl: Likewise - * src/msgs/*.msg: Likewise - - * contrib/extract_translations/prepare-translation.sh: Bugfix - -2007-12-14 Badlop - - * src/msgs/*: Unified file format: First line is SVN Id - tag. Second is Language name. Next lines are authors, adding the - new ones on top. Each string must be in a single line (to - facilitate the automatic removal of unused strings). Last four - lines report file format for Emacs and Vim. - - * contrib/extract_translations/prepare-translation.sh: New - features: extract all translations, include explanation for - translators in the file, remove unused strings from file, include - unused strings in a section for reference, provide information - about current translation and number of missing strings, compress - the files to a zip - - * contrib/extract_translations/extract_translations.erl: Reverted - to the original version - -2007-12-14 Alexey Shchepin - - * src/ejabberd_s2s_out.erl: Bugfix - -2007-12-12 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: presence handler bugfix - * src/mod_pubsub/node_default.erl: Allow send last item on presence - -2007-12-12 Badlop - - * src/msgs/it.msg: Updated (thanks to Luca Brivio) - -2007-12-11 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: notification broadcast bugfix - - * src/jlib.hrl: add pubsub namespace - -2007-12-11 Badlop - - * src/msgs/tr.msg: New translation (thanks to Doruk Fisek) - - * src/msgs/zh.msg: Updated (thanks to Shelley Shyan) - -2007-12-10 Badlop - - * src/msgs/ja.msg: Updated (thanks to Tsukasa Hamano) - - * doc/guide.tex: Small improvement in mod_shared_roster - - * src/mod_irc/mod_irc.erl: Bugfix in ACL check (thanks to Sergei - Golovan) - -2007-12-10 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: database upgrade and auto-create - pep node bugfix - -2007-12-09 Mickael Remond - - * src/web/ejabberd_http.erl: Fixed URL decoding code (EJAB-450) - - * src/msg/fr.msg: Added missing space. - -2007-12-09 Badlop - - * src/msgs/ru.msg: Updated (thanks to Konstantin Khomoutov) - -2007-12-08 Badlop - - * src/msgs/ja.msg: New translation (thanks to Tsukasa Hamano) - - * src/msgs/nl.msg: Updated (thanks to Andreas van Cranenburgh) - - * src/ejabberd_config.erl: Report human-readable message when - Mnesia spool files are not readable. - -2007-12-08 Mickael Remond - - * src/ejabberd_s2s_out.erl: Increase dialback timeout as dialback can - sometimes take longer than expected. - -2007-12-08 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: disco_sm_items bugfix - -2007-12-07 Alexey Shchepin - - * src/ejabberd_sm.erl: Bugfix - -2007-12-07 Badlop - - * src/Makefile.in: Fix compilation warnings: Part 5: To fix a - warning about behaviour undefined, the erlang module that - implements the behaviour must be compiled before the module that - uses such behaviour (EJAB-290) - - * src/eldap/eldap.erl: Fix compilation warnings: Part 4 (EJAB-290) - * src/web/ejabberd_web_admin.erl: Likewise - - * src/mod_irc/iconv.erl: Fix compilation warnings: 3 (EJAB-290) - * src/mod_irc/mod_irc.erl: Likewise - * src/mod_irc/mod_irc_connection.erl: Likewise - * src/mod_pubsub/mod_pubsub.erl: Likewise - * src/stringprep/stringprep.erl: Likewise - * src/web/ejabberd_http.erl: Likewise - * src/web/ejabberd_http_poll.erl: Likewise - - * src/mod_caps.erl: Fix compilation warnings: Part 2 (EJAB-290) - * src/mod_configure.erl: Likewise - * src/mod_configure2.erl: Likewise - * src/mod_offline_odbc.erl: Likewise - * src/mod_shared_roster.erl: Likewise - * src/mod_stats.erl: Likewise - * src/mod_version.erl: Likewise - - * src/cyrsasl.erl: Fix compilation warnings: Part 1 (EJAB-290) - * src/ejabberd_auth_odbc.erl: Likewise - * src/ejabberd_config.erl: Likewise - * src/ejabberd_hooks.erl: Likewise - * src/ejabberd_s2s_out.erl: Likewise - * src/ejabberd_sm.erl: Likewise - * src/idna.erl: Likewise - * src/jd2ejd.erl: Likewise - -2007-12-06 Badlop - - * src/**/*.erl: Remove Erlang module attribute 'vsn' because it - doesn't provide any worth feature, and it difficults hot code - update (EJAB-440) - - * src/ejabberdctl.cfg.example: Explain that each connection uses - two or three ports (thanks to Max Loparyev) - - * src/configure: Regenerated - * doc/dev.html: Likewise - * doc/features.html: Likewise - * doc/guide.html: Likewise - * doc/version.tex: Likewise - - * doc/introduction.tex: Updated number of translated languages - - * src/web/ejabberd_web_admin.erl: Support more native acl_type on - web interface (EJAB-253) - - * src/ejabberd_c2s.erl: Increase the timeout of open socket - without authentication to 60 seconds because many Jabber clients - are not yet capable of handling this correctly (EJAB-355) - - * src/Makefile.in: Allow compilation with HiPE, disabled by - default, undocumented and unrecommended because it is experimental - and doesn't seem to provide meaningful gains currently (thanks to - Samuel Tardieu) (EJAB-412) - * src/configure.ac: Likewise - - * src/msgs/cs.msg: Updated (thanks to Lukas Polivka alias - Spike411) - - * src/mod_muc/mod_muc.erl: Catch creation of table - muc_online_users: it may be already created by other mod_muc - instance - - * doc/Makefile: Remove bashism - - * doc/guide.tex: Document how to change computer - hostname (EJAB-320) - - * src/web/ejabberd_http.erl: Change loglevel for http - queries (EJAB-363) - * src/web/ejabberd_web_admin.erl: Likewise - - * doc/guide.tex: Add mod_caps and improve mod_pubsub documentation - * src/ejabberd.cfg.example: Added mod_caps enabled by default - -2007-12-06 Christophe Romain - - * src/mod_pubsub/node_dispatch.erl: Correct syntax issue - * src/mod_pubsub/Makefile.in: include example plugins - * src/mod_pubsub/Makefile.win32: likewise - * src/ejabberd.cfg.example: use default and pep pubsub plugins - * doc/guide.tex: add nodetree and plugins pubsub option - * doc/guite.html: likewise - -2007-12-06 Badlop - - * doc/guide.tex: Document the Debug Console (EJAB-395) - - * src/ejabberdctl.template: The parameter 'kernel inetrc' is used - even with -sname to guarantee the same behaviour that when using - -name (EJAB-317) - - * doc/guide.tex: Improvements in sections: Start, Creating Initial - Account, Module Overview, Managing an ejabberd server, and - Debugging - -2007-12-05 Badlop - - * doc/guide.tex: Added explanations about epmd, cookie and node - name (EJAB-251) - - * src/msgs/zh.msg: Updated (thanks to Shelley Shyan) - - * src/mod_muc/mod_muc_room.erl: Rephrase the invitation sentence - to make more natural - - * src/msgs/es.msg: Updated - - * src/ejabberd.hrl: Set more proper version number - - * contrib/extract_translations/extract_translations.erl: Don't - report [] to be translated. Identify unusued strings. - -2007-12-04 Badlop - - * .gitignore: Removed (EJAB-441) - * src/.cvsignore: Likewise - - * src/mod_pubsub/mod_pubsub.erl: Bugfix: don't report the Jabber - server as a pubsub service. Fixed URI. - -2007-12-03 Mickael Remond - - * src/mod_muc.erl: Added option to limit the number of room a user is - allowed to connect to (EJAB-445). - * src/mod_muc_room.erl: Likewise. - * doc/guide.tex: Likewise.:ChangeLog - -2007-12-02 Badlop - - * src/ejabberdctl.cfg.example: Bugfix in kernel poll. Added SMP - option. Reorganization of options - * src/ejabberdctl.template: Added SMP option - - * src/Makefile.in: New options make uninstall and - uninstall-all (EJAB-293) - -2007-12-01 Mickael Remond - - * doc/Makefile: echo seems to interpret \n and \v under MacOSX - Leopard. I fixed the problem but let me know if it breaks build - chain in other contexts. - - * Doc/guide.tex: Updated Windows compilation instructions. - * src/configure.erl: Likewise. - - * doc/ejabberd.hrl: Preparing ejabberd 2.0.0 beta release. - * doc/version.tex: Likewise. - - * src/tls/Makefile.win32: Updated for latest Win32 OpenSSL library. - - * src/odbc_queries.erl: Added a default define value so that we - can recompile the file manually with a simple erlc command (with - the default generic value). - -2007-12-01 Alexey Shchepin - - * src/mod_pubsub/Makefile.in: Removed mod_pubsub_old mentioning - * src/mod_pubsub/Makefile.win32: Likewise - - * src/odbc/odbc_queries.erl: Reverted the previous patch because - it produces "redefining macro 'generic'" compilation error - - * src/mod_caps.erl: CAPS support (thanks to Magnus Henoch) - * src/ejabberd_local.erl: Support for IQ responses - * src/jlib.erl: Added iq_query_or_response_info/1 function - * src/jlib.hrl: Added NS_PUBSUB_ERRORS and NS_CAPS - - * src/mod_pubsub/Makefile.in: New pubsub+pep implementation - (thanks to Christophe Romain and Magnus Henoch) - * src/ejabberd_sm.erl: Added get_session_pid/3 function - * src/ejabberd_c2s.erl: Added get_subscribed_and_online/1 function - -2007-11-30 Mickael Remond - - * src/odbc_queries.erl: Added a default define value so that we - can recompile the file manually with a simple erlc command. - -2007-11-29 Badlop - - * src/mod_vcard.erl: Add type of x:data field to search results - (thanks to Robin Redeker) (EJAB-327) - * src/mod_vcard_ldap.erl: Likewise - * src/mod_vcard_odbc.erl: Likewise - - * src/aclocal.m4: Fix autoconf caching for SSL libraries (thanks - to Michael Shields) (EJAB-439) - - * src/configure.ac: Don't hardcode gcc and gcc options in - Makefiles (thanks to Etan Reisner) (EJAB-436) - * src/Makefile.in: Likewise - * src/ejabberd_zlib/Makefile.in: Likewise - * src/eldap/Makefile.in: Likewise - * src/mod_irc/Makefile.in: Likewise - * src/mod_muc/Makefile.in: Likewise - * src/mod_proxy65/Makefile.in: Likewise - * src/mod_pubsub/Makefile.in: Likewise - * src/odbc/Makefile.in: Likewise - * src/pam/Makefile.in: Likewise - * src/stringprep/Makefile.in: Likewise - * src/tls/Makefile.in: Likewise - * src/web/Makefile.in: Likewise - - * src/mod_muc/mod_muc_room.erl: Hide the option 'Make room - moderated' because it isn't implemented, and set the default value - of 'moderated' to true because that is the behaviour - implemented (EJAB-419) - -2007-11-28 Badlop - - * doc/guide.tex: It should be made more clear that domain_certfile - works for both s2s and c2s connections (EJAB-212). Added another - example of listening ports. - - * doc/guide.tex: Update URI of ejabberd official home page, URI - of ejabberd.jabber.ru, and copyright dates (EJAB-366) - * doc/introduction.tex: Likewise - * src/ejabberd.hrl: Likewise - * src/ejabberd_admin.erl: Likewise - * src/mod_irc/mod_irc.erl: Likewise - * src/mod_irc/mod_irc_connection.erl: Likewise - * src/mod_muc/mod_muc.erl: Likewise - * src/mod_muc/mod_muc_log.erl: Likewise - * src/mod_proxy65/mod_proxy65_service.erl: Likewise - * src/mod_pubsub/mod_pubsub.erl: Likewise - * src/mod_vcard.erl: Likewise - * src/mod_vcard_ldap.erl: Likewise - * src/mod_vcard_odbc.erl: Likewise - * src/msgs/*.msg: Updated - * src/web/ejabberd_web_admin.erl: Likewise - -2007-11-27 Badlop - - * src/gen_mod.erl: Update in database the configuration changes in - modules (EJAB-330) - - * src/mod_configure.erl: The command get-user-lastlogin is now - compatible with both Mnesia and ODBC (EJAB-383) - * src/mod_last.erl: Likewise - * src/mod_last_odbc.erl: Likewise - - * doc/guide.tex: Document ejabberd_http's - request_handlers (EJAB-372). Fixed small Latex problems. - Sort options of listening sockets. - -2007-11-27 Alexey Shchepin - - * src/mod_announce.erl: Bugfix (thanks to Christophe Romain) - -2007-11-27 Badlop - - * doc/guide.tex: Added clarification about LDAP default port - (thanks to Christophe Romain). - - * src/mod_vcard.erl: Ensure mod_vcard to respect FORM_TYPE - registry (EJAB-328). - * src/mod_vcard_ldap.erl: Likewise. - * src/mod_vcard_odbc.erl: Likewise. - * doc/guide.tex: Updated documentation. - - * src/mod_muc/mod_muc_room.erl: Don't show the room name as the - room description (EJAB-382). - -2007-11-26 Badlop - - * src/ejabberd.cfg.example: Added example configuration of - databases. - - * doc/guide.tex: Fixed several typos. - - * src/ejabberd_config.erl: Print error when the configuration - requires ODBC, MySQL or PostgreSQL libraries but are not installed - (EJAB-210). - - * src/web/ejabberd_web_admin.erl: Added a favicon (EJAB-379). - - * src/msgs/wa.msg: New Walon translation (thanks to Pablo - Saratxaga) (EJAB-374). - - * doc/guide.tex: Describe how ejabberd treats ejabberd.cfg file - (EJAB-384). - - * src/ejabberd.cfg.example: Huge reorganization and grouping of - options (EJAB-392). - - * doc/guide.tex: Describe in mod_muc: nick register and service - admin message (EJAB-400). - - * src/mod_echo.erl: Example function that demonstrates how to - receive XMPP packets using Erlang's message passing mechanism - (EJAB-247). - - * src/ejabberdctl.template: Removed bashisms (EJAB-399). Set - environment variables instead of passing parameters when calling - erl (EJAB-421). Write erl_crash.dump in the log/ directory, with - unique filename (EJAB-433). - - * src/ejabberd_ctl.erl: Improvements in the help messages - (EJAB-399). - - * doc/guide.tex: Improvements in sections ejabberdctl, and Install - from Source (EJAB-399). - -2007-11-25 Alexey Shchepin - - * src/ejabberd_router.erl: Bugfix - - * src/ejabberd_s2s_out.erl: Bugfix - - * src/ejabberd_sm.erl: Optimized check_max_sessions (thanks to - Christophe Romain) - -2007-11-22 Mickael Remond - - * src/ejabberd_config.erl: Improved error message when ejabberd - config file is not found. - -2007-11-16 Christophe Romain - - * src/ejabberd_auth_internal.erl: Better count management and - batch users retrieval internal database - -2007-11-14 Mickael Remond - - * examples/extauth/check_pass_null.pl: Fixed external - authentication example script (EJAB-404) - -2007-11-05 Mickael Remond - - * src/ejabberd_config.erl: Refactoring: Move internal data - structure to an include file. - * src/ejabberd_config.hrl: Likewise. - -2007-11-03 Mickael Remond - - * src/ejabberd_auth.erl: Better count management and batch users - retrieval for relational database (Thanks to Massimiliano Mirra). - * src/ejabberd_auth_odbc.erl: Likewise. - * src/odbc/odbc_queries.erl: Likewise. - -2007-11-02 Mickael Remond - - * src/web/ejabberd_http_poll.erl: Refactoring. Moved c2s limits - acquisition to a separate module. - * src/ejabberd_c2s_config.erl: Likewise. - -2007-11-01 Mickael Remond - - * src/web/ejabberd_http_poll.erl: Support for c2s ACL access, - max_stanza and shaper on http_poll connections (EJAB-243, - EJAB-415, EJAB-416) - -2007-10-30 Jerome Sautret - - * src/ejabberd_s2s.erl: don't use the resource of the sender to choose - a s2s connection to ensure that a muc room always uses the same - connection (EJAB-360) - -2007-10-23 Christophe Romain - - * doc/dev.tex: Added extauth script details (EJAB-334) - -2007-10-17 Christophe Romain - - * src/ejabberdctl.template: Bugfix on previous change (EJAB-380) - -2007-10-17 Alexey Shchepin - - * src/ejabberdctl.template: Several improvements (EJAB-380) - (thanks to Sander Devrieze, Sergei Golovan, Torsten Werner and - Badlop) - * src/ejabberdctl.cfg.example: Likewise - * src/ejabberd.inetrc: Likewise - * src/Makefile.in: Likewise - - * src/mod_privacy.erl: Bugfix - -2007-10-07 Alexey Shchepin - - * src/mod_vcard_odbc.erl: Reverted previous change - -2007-10-06 Alexey Shchepin - - * src/mod_vcard_odbc.erl: Bugfix - - * src/mod_offline_odbc.erl: Bugfix - -2007-10-01 Alexey Shchepin - - * src/ejabberd_auth_pam.erl: Support for PAM authentication (EJAB-307) - (thanks to Evgeniy Khramtsov) - * src/ejabberd.cfg.example: Likewise - * src/configure.ac: Likewise - * src/aclocal.m4: Likewise - * src/Makefile.in: Likewise - * examples/ejabberd.pam: Likewise - * doc/guide.tex: Likewise - -2007-09-28 Christophe Romain - - * src/odbc/mysql.sql: Added some missing NOT NULL restrictions - * src/odbc/mssql.sql: Likewise - * src/odbc/pg.sql: Likewise - -2007-09-27 Christophe Romain - - * src/ejabberdctl.template: apply rootdir patch from Badlop (EJAB-385) - * tools/ejabberdctl: define EJABBERD_EBIN as from ejabberdctl.template - -2007-09-25 Alexey Shchepin - - * src/ejabberd_s2s.erl: Max number of connections and max number - of connections per node now can be specified via - max_s2s_connections and max_s2s_connections_per_node acl rules - -2007-09-14 Mickael Remond - - * src/ejabberd_s2s_out.erl: Changed to actual p1_fsm behaviour. It - was working correctly as the API of p1_fsm and gen_fsm is strictly - the same. - - * src/ejabberd_s2s_in.erl: Added debug hook for s2s loop (EJAB-358). - - * src/ejabberd_c2s.erl: Added debug hook for c2s loop (EJAB-358). - - * src/ejabberd_s2s.erl: open all missing connections if - needed (Jerome Sautret). - - * src/ejabberd_s2s.erl: don't check blacklist for services (Jerome - Sautret). - - * src/ejabberd_s2s.erl: Try to open all s2s connections at the - same time, to guarantee the right order of the packets (Jerome - Sautret). - - * src/ejabberd_s2s.erl: max_s2s_connexions_number local parameter - added (Jerome Sautret). - - * src/ejabberd_s2s_out.erl: Implements s2s negociation timeouts - and s2s connection retrial interval (EJAB-357, EJAB-294). - - * src/ejabberd_c2s.erl: Implements timeouts during session opening - negociation (EJAB-355). - - * doc/guide.tex: Documentation for new configure option - --disable-transient-supersisors (EJAB-354). - - * src/ejabberd_c2s.erl: Option to prevent the use of Erlang OTP - supervisor for transient processes (EJAB-354). - * src/ejabberd_s2s_in.erl: Likewise. - * src/ejabberd_s2s_out.erl: Likewise. - * src/mod_muc/mod_muc_room.erl: Likewise. - * src/configure.ac: Likewise. - * src/configure: Likewise. - * src/Makefile.in: Likewise. - * src/mod_muc/Makefile.in: Likewise. - - * src/ejabberd_s2s_out.erl: Moved s2s connexion information from - INFO level to DEBUG level and more human readable information - explai - - * src/ejabberd_s2s_in.erl: Moved s2s connexion information from - INFO level to DEBUG level (EJAB-353). - - * src/ejabberd_s2s_out.erl: open up to 3 s2s outgoing connection - per domain pair (Jerome Sautret). - * src/ejabberd_s2s.erl: Likewise. - -2007-09-11 Alexey Shchepin - - * src/gen_mod.erl: Added get_module_opt_host/3 (thanks to Badlop) - -2007-09-10 Mickael Remond - - * src/guide.tex: Fix: user_regexp acls are valid for all local - users (all vhosts). - -2007-09-06 Mickael Remond - - * src/guide.tex: Improved documentation for adding a vhost - specific option (EJAB-297). - - * src/mod_configure.erl: Virtual host support for - mod_configure (Thanks to Badlop) (EJAB-285). - -2007-09-05 Alexey Shchepin - - * src/mod_offline_odbc.erl: Bugfix - -2007-09-04 Mickael Remond - - * src/mod_register.erl: update ejabberd commands to support - XEP-0133 (initial patch by Badlop) (EJAB-325). - * src/mod_configure.erl: Likewise. - * src/mod_announce.erl: Likewise. - * src/jlib.hrl: Likewise. - * src/ejabberd.cfg.example: Likewise. - * doc/guide.tex: Likewise. - -2007-09-03 Mickael Remond - - * examples/extauth/check_pass_null.pl: Perl is generally available - as a default in most Linux distributions. - -2007-09-02 Alexey Shchepin - - * src/jlib.erl: Removed http_base_64:decode call - - * src/mod_muc/mod_muc_room.erl: Added logging of MUC admin/owner - queries - -2007-09-01 Alexey Shchepin - - * src/mod_muc/mod_muc_room.erl: Added user_message_shaper and - room_shaper options - * src/mod_muc/mod_muc.erl: Likewise - -2007-08-31 Mickael Remond - - * doc/guide.tex: Minor examples improvement in LDAP - example (Thanks to Badlop) (EJAB-272). - - * doc/guide.tex: Documentation for mod_muc option for server-wide - limitation of the maximum number of users per room (EJAB-344). - - * doc/guide.tex: Documentation for mod_muc option to allow admin - to enter room even if the maximum number of users - reached (EJAB-345). - - * src/web/ejabberd_web_admin.erl: Make the web interface pages - "translatable" (Thanks to Badlop) (EJAB-11). - -2007-08-29 Alexey Shchepin - - * src/ejabberd.cfg.example: Updated mod_muc 'host' option default - value (thanks to Badlop) - - * src/mod_muc/mod_muc_room.erl: The mod_muc option max_users now - limits max number of users in rooms and max_users_admin_threshold - sets a number of admin or owner accounts allowd to join after - max_users occupants - -2007-08-29 Mickael Remond - - * doc/guide.tex: Documentation for XML based optimisation build - time option (EJAB-298) - -2007-08-29 Alexey Shchepin - - * src/mod_muc/mod_muc_log.erl: Added missed HTMLization in a - nickname change logging (thanks to Badlop) - -2007-08-28 Mickael Remond - - * src/mod_muc/mod_muc_room.erl: Changed default max number of user - in a room to 200 (EJAB-248) - - * src/mod_offline_odbc.erl: Implements quota for offline messages - in relational database (EJAB-314) - * src/odbc/odbc_queries.erl: Likewise - -2007-08-28 Alexey Shchepin - - * doc/guide.tex: Described @HOST@ feature (thanks to Badlop) - -2007-08-26 Mickael Remond - - * src/mod_muc/mod_muc_room.erl: Implements muc max users option - from XEP-0045 (Thanks to Jerome Sautret) (EJAB-248). - -2007-08-26 Alexey Shchepin - - * doc/guide.tex: Removed mentions of unexistent 'hosts' modules - option (thanks to Badlop) - -2007-08-25 Alexey Shchepin - - * src/gen_mod.erl: Substitute @HOST@ with hostname in the 'host' - option (thanks to Badlop) - * src/mod_vcard.erl: Likewise - * src/mod_vcard_ldap.erl: Likewise - * src/mod_vcard_odbc.erl: Likewise - * src/mod_muc/mod_muc.erl: Likewise - * src/mod_irc/mod_irc.erl: Likewise - * src/mod_echo.erl: Likewise - * src/mod_pubsub/mod_pubsub.erl: Likewise - * src/mod_proxy65/mod_proxy65_service.erl: Likewise - -2007-08-24 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Moved roster stuff to mod_roster* - * src/mod_roster.erl: Likewise - * src/mod_roster_odbc.erl: Likewise - -2007-08-23 Alexey Shchepin - - * src/ejabberd_sm.erl: Removed check which denies resource to - receive its own presence - - * src/web/ejabberd_web_admin.erl: Added hooks to allow plugins to - add their pages without modifying ejabberd_web_admin.erl (thanks - to Badlop) - * src/web/ejabberd_web_admin.hrl: Macro definitions moved here - * src/mod_shared_roster.erl: Updated - * src/mod_offline.erl: Likewise - * src/mod_offline_odbc.erl: Likewise - -2007-08-22 Alexey Shchepin - - * src/jlib.erl: Use http_base_64:decode if available - -2007-08-20 Alexey Shchepin - - * src/mod_roster.erl: Don't send roster push when unsubscribing in - "None + Pending In" state - * src/mod_roster_odbc.erl: Likewise - - * src/mod_offline.erl: Renamed MAX_OFFLINE_MSGS to MaxOfflineMsgs - -2007-08-16 Jerome Sautret - - * src/odbc/ejabberd_odbc_sup.erl: Add an odbc_pool_size config - file option to choose the number of SQL connection in each - pool (EJAB-58). - * src/odbc/ejabberd_odbc.erl: Add an odbc_keepalive_interval - config file option to perform a keep alive query at given - interval (EJAB-206). - -2007-08-13 Mickael Remond - - * src/mod_offline.erl: Added a config option to define the maximum - number of offline messages per user (EJAB-314). - - * doc/guide.tex: Added documentation for the mod_offline quota - (EJAB-314). - - * doc/guide.tex: Remove release notes (EJAB-323). - - * src/mod_offline.erl: Returns an error message to sender when - message is discarded due to quota (EJAB-314). - -2007-08-12 Mickael Remond - - * src/odbc/ejabberd_odbc.erl: UTF-8 support for MySQL5 (EJAB-318). - -2007-08-09 Alexey Shchepin - - * doc/guide.tex: Minor update (thanks to Sergei Golovan) - -2007-08-08 Mickael Remond - - * src/mod_offline.erl: Only count messages if a quota has been - actually set (EJAB-314). - * src/p1_mnesia.erl: Minor coding style change. - -2007-08-07 Mickael Remond - - * src/mod_offline.erl: Started implementation of mod_offline - quota. For now, it require change in code. Will be turn into a - config file parameter soon. (EJAB-314). - * src/p1_mnesia.erl: Added memory efficient record count in - Mnesia. - -2007-08-03 Mickael Remond - - * src/mod_announce.erl: Added support to all the announce features - described in documentation. Access to all announce features - through command line, adhoc commands and disco (Thanks to - Badlop) (EJAB-18). - * src/gen_mod.erl: Likewise. - * doc/guide.tex: Likewise. - -2007-08-02 Alexey Shchepin - - * src/mod_muc/mod_muc.erl: Added default_room_options option - (thanks to Etan Reisner and Badlop) - * src/mod_muc/mod_muc_room.erl: Likewise - * doc/guide.tex: Updated - -2007-08-01 Mickael Remond - - * doc/guide.tex: Front page table formatting that render correctly - in HTML and update mentionning CEAN as a way to install - ejabberd (Thanks to Badlop) (EJAB-272). - - * src/ejabberd_s2s_out.erl: Avoid bouncing messages twice if - terminate happens during open_socket. - - * src/ejabberd_s2s_out.erl: On terminate, bounce internal process - queue and Erlang message queue. - - * src/mod_private.erl: Reduce memory consumption on user private - storage removal (EJAB-299). - -2007-07-31 Mickael Remond - - * src/xml.erl: Making use of CDATA escaping optional through with - a compile time option (EJAB-298). - * src/Makefile.in: Likewise. - * src/configure.ac: Likewise. - -2007-07-31 Alexey Shchepin - - * src/mod_version.erl: Added option to hide OS version (thanks to - Badlop) - * doc/guide.tex: Updated - - * src/msgs/zh.msg: Updated (thanks to Shelley Shyan) - - * src/msgs/es.msg: Updated (thanks to Badlop) - - * src/msgs/gl.msg: New galician translation (thanks to - Carlos E. Lopez) - - * src/ejabberd_config.erl: Added possibility for appending values - to config options (thanks to Badlop) - * doc/guide.tex: Updated - -2007-07-30 Mickael Remond - - * src/xml.erl: Better escaping management with CDATA. We only add - CDATA enclosure when needed. CDATA end token is properly escaped. - - * src/xml.erl: Only wrap xmldata nodes in xml cdata "tag" if - bigger than 50 bytes. Shorter xmlcdata nodes will be escaped. - - * src/tls/tls_drv.c: Sends the entire certificate chain (EJAB-209). - - * src/acl.erl: Remove compilation warnings (EJAB-290). - - * src/xml_stream.erl: Group CDATA on a single xmlcdata - node (splitting is not relevant as dependant on TCP/IP packet - fragmentation) (EJAB-292). - - * src/xml.erl: Remove compilation warnings (EJAB-290). - - * src/xml.erl: Do not crypt binary CData, but enclose the value in - XML CDATA "tag". - - * src/xml.erl: Code clean-up: removed old code in comments. - -2007-07-28 Mickael Remond - - * src/mod_roster_odbc.erl: Better error management when bad JID in - roster table (EJAB-289). - -2007-07-26 Mickael Remond - - * src/web/ejabberd_web_admin.erl: Code clean-up. - - * src/mod_offline.erl: Code clean-up. - - * src/gen_mod.erl: Throw error more cleanly. - - * src/mod_configure.erl: One ACL call was not virtual host - compliant. - - * src/ejabberd_auth_odbc.erl: Fixed wrong call preventing user - removal with relational databases. - - * src/mod_last_odbc.erl: Adapted to mod_privacy changes. - * src/mod_privacy_odbc.erl: Refactoring to extract records in - include file. - - * src/mod_last.erl: Adapted to mod_privacy changes. - * src/mod_privacy.erl: Refactoring to extract records in include - file. - * src/mod_privacy.hrl: Likewise. - - * src/mod_roster_odbc.erl: Fixed wrong call. - -2007-07-24 Mickael Remond - - * doc/guide.tex: Added recommandations on max_stanza options - usage. - - * src/ejabberd_s2s_out.erl: Autodisconnect s2s connections which - are overloaded (EJAB-287). - * src/p1_fsm.erl: Likewise. - -2007-07-19 Mickael Remond - - * src/ejabberd_s2s_in.erl: Add s2s whitelist / blacklist support - on incoming s2s connections (EJAB-283) - * src/ejabberd_s2s.erl: Likewise - -2007-07-18 Mickael Remond - - * src/ejabberd_s2s.erl: Fixed typos. - - * src/ejabberd_s2s.erl: Implements s2s hosts whitelist / blacklist - * src/ejabberd.cfg.example: Likewise - - * src/ejabberd_s2s_out.erl: Make s2s connections more robust - * src/ejabberd_s2s.erl: Likewise - -2007-07-17 Mickael Remond - - * src/mod_configure.erl: Bugfix: Show only virtual host users - on admin disco for all users (EJAB-268) (Thanks to Badlop). - - * src/mod_muc/mod_muc_log.erl: Recognise more URI schemes in - logged HTML (EJAB-279) (Thanks to qu1j0t3). - - * src/ejabberd_s2s_out.erl: Improved place of the INFO / - DEBUG printout. - - * src/odbc/ejabberd_odbc.erl: Better error handling for MySQL - native driver (EJAB-224). - -2007-07-15 Alexey Shchepin - - * src/ejabberd_s2s.erl: Added remove_connection/3 - * src/ejabberd_s2s_out.erl: Bugfix: remove only own s2s record - -2007-07-11 Alexey Shchepin - - * src/ejabberd_s2s_out.erl: Bounce packets after unregistering s2s - connection, not before - -2007-07-11 Mickael Remond - - * src/mod_echo.erl: mod_echo does not reply to other - components. This is to make sure that a component will not - discover its own capabilities (Thanks to Badlop) (EJAB-281). - * src/ejabberd.cfg.example: disable mod_echo in the example config - file. mod_echo is mainly a development/test module. - -2007-07-09 Mickael Remond - - * src/odbc/mssql.sql: Nickname cannot be null in rosterusers table - (MSSQL) - * src/odbc/mysql.sql: Likewise - * src/odbc/pg.sql: Likewise - -2007-06-29 Mickael Remond - - * src/ejabberd_config.erl: Normalize hostnames in config file. If mixed - case is used, the hostname will be now useable (EJAB-277). - * src/stringprep/stringprep_sup.erl: Likewise - * src/stringprep/Makefile.in: Likewise - * src/stringprep/Makefile.win32: Likewise - * src/ejabberd_app.erl: Likewise - -2007-06-28 Mickael Remond - - * src/ejabberd_auth_anonymous.erl: Do not purge non anonymous accounts - when using anonymous authentication with another type of auth. - - * src/ejabberd_service.erl: Added an option to disable from attribute - checks in packets coming from an external component (EJAB-275) - * doc/guide.tex: Likewise - - * doc/guide.tex: Documentation rework started (EJAB-272) - * doc/introduction.tex: Likewise - -2007-06-28 Christophe Romain - - * src/web/ejabberd_web_admin.erl: corrects (EJAB-273), - remove obsolete OnlineUsers calculation - -2007-06-26 Alexey Shchepin - - * src/mod_muc/mod_muc_room.erl: Include in MUC invitations - for older clients (thanks to Michael Scherer) - -2007-06-25 Mickael Remond - - * doc/guide.tex: Typos - - * src/mod_muc/mod_muc_room.erl: New anti-abuse options: - min_presence_interval and min_message_interval - * doc/guide.tex: Likewise - - * doc/guide.tex: Documentation improvements on watchdog - - * doc/guide.tex: No need to escape underscore in Latex verbatim - sections - - * doc/guide.tex: Watchdog alert documentation - * src/ejabberd.cfg.example: Likewise - -2007-06-22 Alexey Shchepin - - * src/mod_irc/mod_irc.erl: Added an option for default IRC - encoding (thanks to Badlop) (EJAB-452) - * doc/guide.tex: Updated - - * src/mod_disco.erl: Don't override accumulated value in - get_local_identity/5 (thanks to Magnus Henoch and Badlop) - - * src/web/ejabberd_web_admin.erl: Added links to server and - virtual host homes (thanks to Badlop) - -2007-06-20 Mickael Remond - - * src/mod_muc/mod_muc_room.erl: It is now possible to limit who is - allowed to create persistent MUC rooms (Thanks to Badlop) (EJAB-257) - * src/mod_muc/mod_muc.erl: Likewise - * doc/guide.tex: Likewise - * src/ejabberd.cfg.example: Likewise - -2007-06-18 Mickael Remond - - * src/odbc/odbc_queries.erl: Added missing users_number/1 for MSSQL - (EJAB-239). - -2007-06-12 Alexey Shchepin - - * src/mod_roster_odbc.erl: Fixed typo - -2007-06-10 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Show IP address of connected - resources on user info page (thanks to Oleg Palij) - -2007-06-07 Alexey Shchepin - - * src/ejabberd_config.erl: Fixed "language" option processing - (thanks to Badlop) - - * src/msgs/zh.msg: Updated (thanks to Shelley Shyan) - - * src/msgs/ca.msg: New Catalan translation (thanks to Vicent - Alberola) - -2007-06-05 Mickael Remond - - * src/xml.erl: Add new helper function get_subtag_cdata/2. - -2007-05-31 Alexey Shchepin - - * src/mod_vcard_odbc.erl: Fix for previous commit (thanks to - Badlop) - -2007-05-29 Mickael Remond - - * src/mod_vcard_odbc.erl: Make service description translatable in - discovery (EJAB-236) - * src/mod_vcard_ldap.erl: Likewise - - * src/Makefile.in: Added Dialyzer target (EJAB-189 - Thanks - to Geoff Cant) - * src/Makefile.in: Build XmppAddr.beam in a single pass - * src/mod_muc/Makefile.in: +debug_info directive support - * src/stringprep/Makefile.in: Likewise - * src/mod_irc/Makefile.in: Likewise - * src/web/Makefile.in: Likewise - * src/eldap/Makefile.in: Likewise - * src/mod_pubsub/Makefile.in: Likewise - * src/ejabberd_zlib/Makefile.in: Likewise - * src/mod_proxy65/Makefile.in: Likewise - * src/tls/Makefile.in: Likewise - * src/odbc/Makefile.in: Likewise - - * src/mod_vcard.erl: Make services description translatable in - discovery (EJAB-236 - thanks to Badlop) - * src/mod_muc/mod_muc.erl: Likewise - * src/mod_irc/mod_irc.erl: Likewise - * src/mod_pubsub/mod_pubsub.erl: Likewise - * src/mod_proxy65/mod_proxy65_service.erl: Likewise - * src/msgs/fr.msg: Added service description translation - -2007-05-21 Alexey Shchepin - - * src/ejabberdctl.template: Updated version of ejabberdctl (thanks - to Christophe Romain) - * tools/ejabberdctl: Likewise - * src/Makefile.in: Updated - - * src/ejabberd_sm.erl: Updated the session table to store - additional session info - * src/ejabberd_c2s.erl: Report IP address to ejabberd_sm (thanks - to Christophe Romain) - -2007-05-18 Alexey Shchepin - - * src/msgs/zh.msg: New chinese translation (thanks to Shelley - Shyan) - -2007-05-16 Alexey Shchepin - - * src/mod_muc/mod_muc_room.erl: Corrected error messages when - trying to join members-only room (thanks to Badlop) - - * src/ejabberd_c2s.erl: Added c2s_update_presence hook - -2007-05-14 Alexey Shchepin - - * src/ejd2odbc.erl: Bugfix (thanks to Badlop) - -2007-05-12 Alexey Shchepin - - * src/ejabberd_auth.erl: Added get_vh_registered_users_number/1 - function - * src/ejabberd_auth_odbc.erl: Likewise - * src/odbc/odbc_queries.erl: Added users_number/1 function - * src/ejabberd.cfg.example: Added an example for - pgsql_users_number_estimate option - * src/mod_stats.erl: Updated - * src/web/ejabberd_web_admin.erl: Likewise - - * src/ejabberd_auth_anonymous.erl: Added anonymous_purge_hook - (thanks to Christophe Romain and Mickael Remond) - * src/mod_offline.erl: Likewise - * src/mod_offline_odbc.erl: Likewise - * src/mod_roster.erl: Likewise - * src/mod_roster_odbc.erl: Likewise - -2007-05-09 Alexey Shchepin - - * src/mod_muc/mod_muc.erl: Bugfix - -2007-05-07 Alexey Shchepin - - * src/ejabberd_receiver.erl: Workaround for inet_drv bug - - * src/web/ejabberd_http_poll.erl: Added sockname/1 and peername/1 - stubs - - * src/web/ejabberd_http.hrl: Added "ip" field in the "request" - record (thanks to Jerome Sautret and Mickael Remond) - * src/web/ejabberd_http.erl: Likewise - -2007-05-03 Alexey Shchepin - - * src/ejabberd_sm.erl: Added set_presence_hook - * src/ejabberd_c2s.erl: Likewise - - * src/ejabberd_sm.erl: Added check for existence of incoming - subscription destination - - * src/msgs/it.msg: Added italian translation (thanks to Luca - Brivio) - - * src/mod_muc/mod_muc_room.erl: More accurate invitation errors - (thanks to Magnus Henoch) - -2007-04-26 Alexey Shchepin - - * src/mod_roster_odbc.erl: Don't deliver roster items in "None + - Pending In" state - * src/mod_roster.erl: Likewise - -2007-04-12 Alexey Shchepin - - * src/ejabberd_socket.erl: Added API for monitoring socket - processes - * src/ejabberd_frontend_socket.erl: Likewise - * src/ejabberd_c2s.erl: Added socket monitoring - - * src/mod_muc/mod_muc_room.erl: Fixed the stop reason for the - destroy event - -2007-04-09 Alexey Shchepin - - * src/ejabberd_sm.erl: Minor optimisation - - * src/ejabberd_system_monitor.erl: Experimental watchdog - * src/ejabberd_sup.erl: Likewise - * src/ejabberd_config.erl: Likewise - -2007-03-22 Mickael Remond - - * src/guide.tex: Fixed typo. - -2007-03-22 Alexey Shchepin - - * src/mod_muc/mod_muc.erl: Better behaviour under high load - -2007-03-18 Alexey Shchepin - - * src/ejabberd_s2s.erl: Don't bounce packets with "error" and - "result" type - - * src/ejabberd_s2s.erl: Fixed spelling - - * src/ejabberd_s2s.erl: Don't start s2s process for existing - connection in case of race condition - -2007-03-13 Alexey Shchepin - - * src/ejabberd_service.erl: Added shaper_rule option, changed - service connection log message - -2007-03-13 Mickael Remond - - * src/ejabberd_service.erl: Add extra info in the log about which - components is connected and which Erlang process is handling - it. This is usefull in context where many types of components are - used (Thanks to Jerome Sautret) (EJAB-211). - -2007-03-10 Mickael Remond - - * src/web/ejabberd_http.erl: Support for binaries in ejabberd HTTP - server (Thanks to Massimiliano Mirra) (EJAB-197). - - * src/configure.ac: autoconf improvements (thanks to Tony Finch) - (EJAB-204). - * src/aclocal.m4: Likewise. - - * src/odbc/ejabberd_odbc.erl: ejabberd admin can now choose the - relational database port to use from ejabberd configuration file - (EJAB-195). - * src/doc/guide.tex: Likewise. - -2007-03-02 Mickael Remond - - * src/mod_muc/mod_muc_log.erl: Fix wrong return on check access - log. - -2007-03-01 Alexey Shchepin - - * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) - * src/msgs/uk.msg: Likewise - -2007-02-22 Alexey Shchepin - - * src/mod_pubsub/mod_pubsub.erl: Bugfix - - * src/mod_proxy65/mod_proxy65_sm.erl: Cluster support (thanks to - Evgeniy Khramtsov) - - * src/mod_proxy65/mod_proxy65_stream.erl: Code cleanup (thanks to - Evgeniy Khramtsov) - - * src/mod_proxy65/mod_proxy65.hrl: Fixed typo (thanks to Evgeniy - Khramtsov) - -2007-02-20 Alexey Shchepin - - * src/ejabberd_c2s.erl: Init shaper with a default value first - after stream opening - - * src/ejabberd_c2s.erl: Log failed SASL login attempts - * src/cyrsasl.erl: Updated API - * src/cyrsasl_plain.erl: Likewise - * src/cyrsasl_digest.erl: Likewise - -2007-02-19 Mickael Remond - - * src/mod_muc/mod_muc_room.erl: Added an option set affiliations. - - * doc/api/*: Added Erlang documentation generation script - (EJAB-188). - * doc/version.tex: Updated. - * src/ejabberd.app: Updated. - - * src/odbc/pg.sql: last table, state column cannot be NULL - (EJAB-191). - * src/odbc/mysql.sql: likewise. - * src/odbc/mssql.sql: likewise. - - * src/ejabberd_auth_ldap.erl: prevent anonymous bind on LDAP - servers as ejabberd is providing other anonymous authentication - mechanism (EJAB-190). - - * src/cyrsasl_plain.erl: bad-auth error code replaced by - not-authorized (EJAB-187). - - * src/aclocal.m4: configure --with-erlang option is now working - (Thanks to Jerome Sautret) (EJAB-186). - - * src/mod_muc/mod_muc_log.erl: Spam prevention: The default - behaviour is now to use the nofollow rel attributes for links that - are submitted by users (EJAB-185). - * doc/guide.tex: Likewise. - - * src/mod_muc/mod_muc_room.erl: API improvement: Implementation of - an event to destroy MUC room from an external application (Thanks - to Massimiliano Mirra) (EJAB-184). - -2007-02-18 Alexey Shchepin - - * src/ejabberd_s2s.erl: Confirm to RFC3920 section 10.3 (thanks to - Jerome Sautret) - -2007-02-18 Mickael Remond - - * src/mod_muc/mod_muc.erl: Node now try to clean its own online room - when restarting (EJAB-182). - -2007-02-13 Alexey Shchepin - - * src/mod_muc/mod_muc.erl: Clean online room table on cluster node - restart - -2007-02-13 Mickael Remond - - * src/ejabberd_auth_ldap.erl: Added ldap_local_filter option. This - option provide an optimisation to reduce LDAP directory load when - using attribute-based filters. - -2007-02-04 Alexey Shchepin - - * src/web/ejabberd_http.erl: Added separate version of - element_to_string for HTML encoding - * src/xml.erl: Reverted previous change - -2007-02-04 Mickael Remond - - * src/xml.erl: ' entity replaced by ' Should work more - universaly (in HTML and XML). - -2007-01-30 Alexey Shchepin - - * src/mod_roster_odbc.erl: Bugfix (thanks to asdx - ) - * src/ejd2odbc.erl: Likewise - -2007-01-27 Mickael Remond - - * src/mod_vcard_ldap.erl: LDAP server pool support (thanks to Evgeniy - Khramtsov) - * src/eldap/Makefile.in: Likewise - * src/ejabberd_auth_ldap.erl: Likewise - * src/eldap_pool.erl: Likewise - - * src/eldap/eldap_utils.erl: Implemented LDAP domain substitution - - * src/eldap/eldap.erl: Implemented queue to avoid bind deadlock under - heavy load (thanks to Evgeniy Khramtsov) - * src/eldap/eldap.hrl: Likewise - -2007-01-26 Mickael Remond - - * doc/guide.tex: Fixed typos in labels. - -2007-01-25 Mickael Remond - - * src/eldap/Makefile.win32: fix build error on Windows. - -2007-01-25 Alexey Shchepin - - * src/web/*: Plugin architecture for HTTP modules (thanks to - Massimiliano Mirra) - -2007-01-24 Mickael Remond - - * doc/guide.tex: Documentation for the - domain_balancing_component_number option. - - * doc/guide.tex: Documentation for domain balancing. - - * doc/guide.tex: mod_muc now supports cluster. - - * doc/guide.tex: Updated the max_user_sessions section. - -2007-01-19 Alexey Shchepin - - * src/mod_muc/mod_muc.erl: Now mod_muc can be distributed on - several nodes - * src/mod_muc/mod_muc_room.erl: Likewise - - * src/ejabberd_router.erl: Added bare_source and bare_destination - service balancing options and domain_balancing_component_number - option for specifying the number of connected components for the - domain - * src/ejabberd_config.erl: Likewise - -2007-01-11 Mickael Remond - - * doc/guide.tex: Latex / Hevea related improvements for - documentation generation (thanks to Sander Devrieze). - * doc/introduction.tex: Likewise. - * doc/dev.tex: Likewise. - * doc/features.tex: Likewise. - -2007-01-08 Christophe Romain - - * src/mod_pubsub/mod_pubsub.erl: add presence_based_delivery - cluster support - -2007-01-05 Alexey Shchepin - - * src/mod_muc/mod_muc_log.erl: Remove 'right-to-left override' - unicode character (thanks to Badlop) - -2006-12-31 Alexey Shchepin - - * src/ejabberd_s2s_out.erl: Bugfix - -2006-12-21 Mickael Remond - - * src/mod_private_odbc: Bugfix: an internal error was returned - instead of the actual private data. This is now working as expected. - -2006-12-21 Alexey Shchepin - - * src/ejd2odbc.erl: Bugfix - -2006-12-16 Mickael Remond - - * README: Added this file as a quickstart guide. - -2006-12-15 Mickael Remond - - * src/mod_echo.erl: The mod_echo can now be stopped without errors. - This is not a major issue, but can mislead other developers learning - from this example and test module (Thanks to Magnus Henoch). - - * TODO: Removed. The roadmap is managed on: - http://support.process-one.net/browse/EJAB - - * src/ejabberd_ctl.erl: Bugfix: Now display all register commands for a - vhost and not only one (Thanks to Badlop). - * src/ejabberd.cfg.example: Fixed typo. - -2006-12-14 Mickael Remond - - * src/ejabberd_config.erl: Added loglevel option. It is now possible to - configure ejabberd dynamic loglevel from the config file. - -2006-12-08 Alexey Shchepin - - * src/ejabberd_receiver.erl: Bugfix - - * src/ejabberd_c2s.erl: Bugfix - -2006-12-05 Alexey Shchepin - - * src/mod_roster_odbc.erl: Better error handling - - * src/web/ejabberd_http_poll.erl: Minor fix - -2006-12-04 Mickael Remond - - * src/ejabberd_loglevel.erl: Preliminary dynamic loglevel support. - Debug can be enabled with the command "ejabberd_loglevel:set(5)". - * src/ejabberd_app.erl: Likewise. - * src/ejabberd.hrl: Likewise (More log levels are now supported). - * src/ram_file_io_server.erl: Likewise (Needed to dynamically - recompile the error logger). - -2006-12-01 Alexey Shchepin - - * src/ejabberd_receiver.erl: Bugfix - -2006-11-30 Mickael Remond - - * src/mod_proxy65/mod_proxy65_services.erl: We now try to get the - address of the component (if registered in DNS) or otherwise get the - IP of the XMPP domain. - -2006-11-29 Mickael Remond - - * src/ejabberd_logger_h.erl: Removed useless comments. - -2006-11-28 Mickael Remond - - * src/mod_proxy65/mod_proxy65_services.erl: Now using all interfaces as - default value for proxy listen parameter. - - * src/ejabberd_c2s.erl: User login in with negative priority must not - receive offline messages (Thanks to Badlop). - -2006-11-24 Mickael Remond - - * doc/guide.tex: Fixed regexp ACL configuration examples - (Thanks to Massimiliano Mirra). - - * src/muc/mod_muc_room.erl: API improvement. It is now possible - to read and write a room config from a developer module (Thanks - to Massimiliano Mirra). - -2006-11-23 Alexey Shchepin - - * src/eldap/eldap.erl: Bugfix (thanks to Evgeniy Khramtsov) - - * src/ejabberd_sm.erl: The max_user_sessions option is now - configured via access rule - * src/ejabberd.cfg.example: Likewise - -2006-11-20 Mickael Remond - - * src/ejd2odbc.erl: Copy mod_private data from Mnesia to - relational database. - * src/odbc/odbc_queries.erl: Refactoring. - * src/odbc/mssql.sql: Likewise. - * doc/guide.tex: Doc updated to mention mod_private_odbc. - - * src/odbc/mysql.sql: Started integration of mod_privacy_odbc for - MySQL and MSSQL. - * src/odbc/mssql.sql: Likewise. - -2006-11-15 Mickael Remond - - * src/mod_muc/mod_muc_room.erl: API improvement: It is now easier to - extract data from the MUC room process. - -2006-11-07 Alexey Shchepin - - * src/ejabberd_node_groups.erl: Support for node tagging - * src/ejabberd_sup.erl: Likewise - * src/ejabberd_frontend_socket.erl: Use node tags to determine - backend nodes - * src/ejabberd_config.erl: Added node_type and cluster_nodes - options - * src/ejabberd_app.erl: Establish connections to the nodes from - the cluster_nodes option - - * src/ejabberd_router.erl: Added balancing method option - * src/ejabberd_config.erl: Likewise - -2006-11-05 Mickael Remond - - * src/mod_private_odbc.erl: Support for MySQL and MSSQL. - * src/odbc/odbc_queries.erl: Likewise. - * src/odbc/mysql.sql: Likewise. - * src/odbc/mssql.sql: Likewise. - -2006-11-04 Mickael Remond - - * src/eldap_utils.erl: Fixed missing export. - - * src/odbc/pg.sql: Database scripts consistency. - * src/odbc/mysql.sql: Likewise. - * src/odbc/mssql.sql: Likewise. - - * src/odbc/mysql: Database creation script should now be compliant - with MySQL 4.0.x. - -2006-10-29 Mickael Remond - - * doc/guide.tex: XEP-0065 proxy documentation (thanks to Evgeniy - Khramtsov). - -2006-10-28 Mickael Remond - - * src/ejabberd.cfg.example: Changed the anonymous example a bit to - work in most cases. - * doc/guide.tex: Likewise. - -2006-10-28 Alexey Shchepin - - * src/mod_proxy65/: XEP-0065 proxy (thanks to Evgeniy Khramtsov) - * src/Makefile.win32: Likewise - * src/Makefile.in: Likewise - * src/configure.ac: Likewise - * src/jlib.hrl: Likewise - * src/ejabberd.hrl: Added the ejabberd URL - -2006-10-27 Mickael Remond - - * src/guide.tex: Fixed typos. - -2006-10-25 Mickael Remond - - * src/ejabberd_rdbms.erl: It is now possible to use ldap or internal - authentication with some other modules using relationnal database - storage. Refactored relational databases connections initialisation. - * src/ejabberd_auth_odbc.erl: Likewise. odbc supervisor startup is now - delegated to the ejabberd rdbms module. - * src/ejabberd_app.erl: Likewise. - -2006-10-17 Alexey Shchepin - - * src/ejabberd_socket.erl: Added sockname/1 and peername/1 - functions - * src/ejabberd_frontend_socket.erl: Likewise - * src/tls/tls.erl: Likewise - * src/ejabberd_zlib/ejabberd_zlib.erl: Likewise - - * src/mod_private_odbc.erl: Private storage support using odbc - * src/odbc/pg.sql: Likewise - -1999-11-30 Mickael Remond - - * src/ejabberd_auth_ldap.erl: LDAP authentication now allows to - match on several alternative attributes (thanks to Evgeniy - Khramtsov). - * src/mod_vcard_ldap.erl: Likewise. - * doc/guide.tex: Updated. - * eldap_utils.erl: Refactoring. - * src/eldap/Makefile.in: Likewise. - -2006-10-09 Alexey Shchepin - - * src/mod_privacy_odbc.erl: Privacy rules support using odbc - * src/odbc/pg.sql: Likewise - -2006-10-06 Alexey Shchepin - - * src/web/ejabberd_http_poll.erl: Bugfix - -2006-10-05 Alexey Shchepin - - * src/mod_privacy.erl: Use hooks instead of direct function calls - * src/ejabberd_c2s.erl: Updated - -2006-10-01 Alexey Shchepin - - * src/shaper.erl: Bugfix - * src/ejabberd_config.erl: Likewise - - * src/ejabberd_frontend_socket.erl: Support for frontend - connection manager - * src/ejabberd_c2s.erl: Likewise - * src/ejabberd_listener.erl: Likewise - * src/ejabberd_s2s_in.erl: Likewise - * src/ejabberd_service.erl: Likewise - * src/ejabberd_socket.erl: Likewise - * src/web/ejabberd_http_poll.erl: Likewise - -2006-09-27 Mickael Remond - - * doc/release_notes_1.1.2.txt: Minor fixes. - - * doc/guide.tex: Fixed Latexish typos. - -2006-09-26 Mickael Remond - - * doc/release_notes_1.1.2.txt: Draft release notes. - - * src/msgs/pl.msg: Updated (thanks to Andrzej Smyk). - - * src/ejabberd_s2s.erl: More precise message for the new s2s - statistic command. - - * src/mod_muc/mod_muc_room.erl: Minor english update. - * src/msgs/pl.msg: Likewise. - * src/msgs/uk.msg: Likewise. - * src/msgs/pt-br.msg: Likewise. - * src/msgs/cs.msg: Likewise. - * src/msgs/ru.msg: Likewise. - * src/msgs/es.msg: Likewise. - * src/msgs/fr.msg: Likewise. - * src/msgs/de.msg: Likewise. - * src/msgs/nl.msg: Likewise. - - * src/msgs/pt-br.msg: Updated Brazilian translation (thanks to - Renato Botelho) and clean-up. - -2006-09-25 Mickael Remond - - * src/msgs/de.msg: Updated German translation (thanks to Nikolaus - Polak). - - * src/ejabberd.app: Version update for ejabberd 1.1.2. - - * src/msgs/pl.msg: Updated Polish translation (thanks to Zbyszek - Zolkiewski). - - * src/msgs/de.msg: Updated German translation (thanks to Marvin - Preuss). - - * src/msgs/nl.msg: Updated Dutch translation (thanks to Sander - Devrieze). - - * src/msgs/cs.msg: Updated Czech translation and removed unused - strings. - - * doc/introduction.tex: Minor doc updates for release 1.1.2. - -2006-09-25 Alexey Shchepin - - * src/ejabberd_s2s.erl: Added incoming-s2s-number and - outgoing-s2s-number ejabberdctl commands - - * src/ejabberd_socket.erl: Support for non-xml sockets - * src/ejabberd_c2s.erl: Likewise - * src/ejabberd_s2s_in.erl: Likewise - * src/ejabberd_service.erl: Likewise - * src/web/ejabberd_http.erl: Likewise - -2006-09-24 Mickael Remond - - * src/msgs/es.msg: Updated Spanish translation (thanks to Badlop). - - * src/mod_muc/mod_muc_room.erl: Strings update (thanks to Sergei - Golovan). - * src/msgs/ru.msg: Updated Russian translation (thanks to Sergei - Golovan). - * src/msgs/uk.msg: Updated Ukrainian translation (thanks to Sergei - Golovan). - * src/msgs/fr.msg: Update French translation. - - * src/doc/guide.html: Minor W3C compliance fix in an Hevea - generated URL. - - * src/doc/features.html: Added to be consistent (guide.html is in - the repository to make Latex optional, but still allow access to - the doc). - -2006-09-23 Mickael Remond - - * src/ejabberd.hrl: Updated to version 1.1.2 - -2006-09-23 Alexey Shchepin - - * src/eldap/eldap.erl: Enable the keepalive socket option (thanks - to Evgeniy Khramtsov) - - * src/ejabberd_auth_ldap.erl: Now uses two LDAP connections - (thanks to Evgeniy Khramtsov) - - * src/eldap/eldap_filter.erl: Bugfix (thanks to Evgeniy Khramtsov) - * src/mod_vcard_ldap.erl: Likewise - -2006-09-22 Mickael Remond - - * src/msgs/cs.msg: Added Czech translation (thanks to Milos Svasek). - - * src/mod_muc/mod_muc.erl: Component name is now more user friendly - (thanks to Badlop). - * src/mod_irc/mod_irc.erl: Likewise. - * src/mod_pubsub/mod_pubsub.erl: Likewise. - - * src/msgs/fr.msg: updated French translation. - - * doc/guide.tex: Large improvements for ejabberd 1.1.2 (thanks to - Sander Devrieze) - * doc/version.tex: Likewise. - * doc/features.tex: Likewise. - * doc/Makefile: Likewise. - * doc/dev.tex: Likewise. - -2006-09-14 Mickael Remond - - * doc/guide.tex: Minor fix on index generation. - -2006-09-14 Alexey Shchepin - - * doc/guide.tex: Updated (thanks to Evgeniy Khramtsov) - - * src/ejabberd_auth_ldap.erl: Better LDAP support (thanks to - Evgeniy Khramtsov) - * src/mod_vcard_ldap.erl: Likewise - * src/eldap/eldap_filter.erl: Likewise - -2006-09-11 Mickael Remond - - * src/odbc/mssql.sql: Removed unused fields. - -2006-09-10 Alexey Shchepin - - * src/ejd2odbc.erl: Updated - - * src/mod_muc/mod_muc_log.erl: Fixed html special characters - escaping, added new image buttons, chatroom titles now point to - xmpp: URIs (thanks to Badlop) - - * src/ejabberd_listener.erl: Bugfix - -2006-09-05 Mickael Remond - - * src/mod_muc/mod_muc.erl: It is now possible to configure the MUC room - history feature. A new option has been added in ejabberd muc module - configuration (history_size) to define the size of the history. 0 is - used to disable the feature. - * src/mod_muc/mod_muc_room.erl: Likewise. - * doc/guide.tex: Likewise. - -2006-09-05 Alexey Shchepin - - * src/ejabberd_socket.erl: All XML socket operations moved here - * src/ejabberd_listener.erl: Updated - * src/ejabberd_receiver.erl: Likewise - * src/ejabberd_c2s.erl: Likewise - * src/ejabberd_s2s_in.erl: Likewise - * src/ejabberd_s2s_out.erl: Likewise - * src/ejabberd_service.erl: Likewise - - * src/mod_shared_roster.erl: Bugfix - - * src/mod_roster_odbc.erl: Bugfix - -2006-09-03 Mickael Remond - - * src/odbc/odbc_queries.erl: Support for Microsoft SQL Server as a - database backend (via ODBC). - * src/odbc/ejabberd_odbc.erl: Likewise. - * src/odbc/mssql.sql: Likewise. - * src/odbc/Makefile.in: Likewise. - * src/ejabberd_auth_odbc.erl: Likewise. - * src/mod_offline_odbc.erl: Likewise. - * src/mod_roster_odbc.erl: Likewise. - * src/mod_last_odbc.erl: Likewise. - * src/configure.ac: Likewise - * doc/guide.tex: Likewise. - * doc/introduction.tex: Likewise. - * src/odbc/pg.sql: Minor fix. - -2006-08-28 Mickael Remond - - * Makefile.in: Fix for MacOSX compilation. - * ejabberd_zlib/Makefile.in: Likewise. - * mod_irc/Makefile.in: Likewise. - * stringprep/Makefile.in: Likewise. - * tls/Makefile.in: Likewise. - - * src/ejabberd.app: Updated to the current version. - -2006-08-27 Alexey Shchepin - - * src/mod_muc/mod_muc_room.erl: Fixed logging configuring - permission check - -2006-08-14 Alexey Shchepin - - * src/ejabberd_router.erl: Now filter_packet hook works in - 'global' context - -2006-08-04 Alexey Shchepin - - * src/tls/tls_drv.c: Report OpenSSL error messages (thanks to - Magnus Henoch) - - * src/mod_muc/mod_muc_room.erl: Use standardized MUC room - configuration fields (thanks to Magnus Henoch and Andy Turner) - -2006-08-02 Alexey Shchepin - - * src/mod_roster_odbc.erl: Bugfix - -2006-07-28 Mickael Remond - - * src/ejabberd_c2s.erl: Bugfix: added a missing catch and fixed the - error code used on unknown namespace. - * src/ejabberd_s2s_out.erl: Improved s2s connection negociation - (dialback namespace usage) when using tls. - * src/ejabberd_sm.erl: Fixed the error code used on unknown namespace. - * src/mod_register.erl: ejabberd now sends iq result and stream end on - user remove. - -2006-07-16 Mickael Remond - - * src/acl.erl: The server does not crash anymore on wrong acl rule. Add - rule error message in log file. - -2006-07-07 Mickael Remond - - * src/web/ejabberd_web_admin.erl: User creation form now creates the - user for the current virual host only and does not require to type - the hostname. - * src/jlib.erl: String to JID conversion now returns an error if the - JID string contains two arobases. - -2006-07-06 Mickael Remond - - * src/mod_shared_roster.erl: Shared roster entries can now be moved or - rename from a client without breaking current presence status. - * src/mod_roster.erl: Likewise. - * src/mod_roster_odbc.erl: Likewise. - - * src/mod_muc/mod_muc_room.erl: Fixed the order in which room presence - packets are sent (First existing presence to new occupant, then new - occupant presence to existing users. - -2006-07-05 Mickael Remond - - * src/web/ejabberd_web_admin.erl: More flexible parsing the shared - roster members list from the configuration form. - * src/mod_shared_roster.erl: Deletng a shared roster group now - correctly deletes its user entries. - - * src/mod_shared_roster.erl: The logged user (self) is now removed from - the shared roster list. - * src/ejabberd_auth.erl: Better handling of errors when the server for - authentication is unknown. - -2006-06-19 Alexey Shchepin - - * src/ejabberd_s2s_in.erl: Removed needless check for xmlns:db - when starttls is enabled - -2006-06-15 Mickael Remond - - * src/web/ejabberd_http_poll.erl: Bugfix: using tuple instead of a Pid - to send Erlang messages in a rarely used case. - -2006-06-13 Mickael Remond - - * src/ejabberd_auth.erl: Fixed broken multiple connection with - anonymous login problem. - * src/ejabberd_auth_anonymous.erl: Likewise. - -2006-06-07 Mickael Remond - - * src/mod_pubsub/mod_pubsub.erl: Support for pubsub node creation - ACL. It is now possible to limit the node creation rights using an - ACL from ejabberd config file (Thanks to Christophe Romain). - * doc/guide.tex: Likewise. - * src/ejabberd.cfg.example. - - * src/mod_pubsub/mod_pubsub.erl: Discovery query on an item does - no more return an "item not found error". Discovery stop correctly - at the item level (Thanks to Christophe Romain). - -2006-06-02 Mickael Remond - - * src/web/ejabberd_http_poll.erl: Messages polled between the - the last client request and the polling timeout were lost. Those - messages are now resent using ejabberd routing mechanisms. - - * src/web/ejabberd_http.erl: The web module now accepts HTTP - absolute URL (used behind a proxy). This apply to HTTP polling and - to the web interface (Thanks to Jean-Sebastien Pedron). - -2006-05-29 Mickael Remond - - * src/mod_roster.erl: According to RFC3921 section 9.2, outbound - subscribe presence packets must be sent, even if the user has already - asked for subcription previously (subscription: none and pending: out). - The mod_roster now conforms to this behaviour. - * src/mod_roster_odbc.erl: Likewise. - -2006-05-27 Mickael Remond - - * src/configure.ac: Added an optional check for krb5.h in - configure. ejabberd can now be build directly on RedHat and - OpenBSD. - -2006-05-27 Alexey Shchepin - - * src/msgs/sk.msg: Slovak translation (thanks to Juraj Michalek - and SkLUG) - -2006-05-26 Alexey Shchepin - - * src/odbc/pg.sql: Updated - - * src/mod_shared_roster.erl: Updated - - * src/ejabberd_sm.erl: Bugfix - - * src/mod_roster.erl: Bugfix - * src/mod_roster_odbc.erl: Likewise - -2006-05-23 Mickael Remond - - * src/mod_roster.erl: The subscribe request are now resend at login as - long as they have not been answered. mod_roster do no more depends on - mod_offline. - * src/ejabberd_sm.erl: Likewise. - * src/ejabberd_c2s.erl: Likewise. - * src/mod_roster_odbc.erl: Likewise (The ODBC/relational support has - not yet been tested). - * src/mod_roster.hrl: Likewise. - * src/mod_offline.erl: Likewise. - * src/mod_offline_odbc.erl: Likewise. - * odbc/pg.sql: Likewise. - * odbc/mysql.sql: Likewise. - -2006-05-22 Mickael Remond - - * src/ejabberd_sm.erl: The max_user_sessions has been moved to - host configuration. - * src/ejabberd.cfg.example: Likewise. - * doc/guide.tex: Likewise. - -2006-05-21 Mickael Remond - - * src/ejabberd_sm.erl: An option to limit the number of opened sessions - for a given user have been added. As a default, a given user can only - log in 10 times with different resources. After that, new connections - replace the older ones. - * src/ejabberd.cfg.example: Likewise. - * doc/guide.tex: Likewise. - -2006-05-15 Mickael Remond - - * src/web/ejabberd_http_poll.erl: Timeout disconnection were not - properly handled after "active once" migration. This is now fixed. - -2006-05-07 Mickael Remond - - * src/mod_configure.erl: Unknown tables or tables from now unused - modules are ignored during restore. The restore can now be performed in - such case. - * src/web/ejabberd_web_admin.erl: Likewise. - * src/ejabberd_admin.erl: Code refactoring. Common Mnesia database - restore function. - - * src/ejabberd_ctl.erl: Now prints a user-friendly when trying to - restore a backup from a non-existent file. - - * src/ejabberd_ctl.erl: Added a way to delete the older message - from the offline message table. This function is only available if - offline message queue is stored in Mnesia internal database. The - function delete_old_messages is not available in mod_offline_odbc. - -2006-05-01 Mickael Remond - - * src/ejabberd_ctl.erl: Unknown tables or tables from now unused - modules are ignored during restore. The restore can now be performed in - such case. - -2006-04-28 Mickael Remond - - * src/ejabberd.hrl: release 1.1.1 - * doc/version.tex: Likewise - * doc/guide.tex: Likewise - -2006-04-28 Alexey Shchepin - - * src/cyrsasl.erl: Bugfix: anonymous authentication was always - enabled - -2006-04-27 Mickael Remond - - * src/ejabberd_ctl.erl: The status now only returns "started" if - ejabberd is started and ready to accept requests. - -2006-04-24 Alexey Shchepin - - * doc/guide.tex: Added a documentation for max_stanza_size option - -2006-04-24 Mickael Remond - - * src/ejabberd.hrl: Updated for version 1.1.0. - -2006-04-23 Alexey Shchepin - - * src/configure: Removed '==' bashism (thanks to Magnus Henoch) - * src/aclocal.m4: Likewise - - * src/ejabberd_c2s.erl: Resend messages when leaving negative - presence state (thanks to Magnus Henoch) - -2006-04-23 Mickael Remond - - * src/msgs/fr.msg: Updated - * src/msgs/de.msg: Updated (thanks to Nikolaus Polak) - * src/ejabberd_sm.erl: Now delivering messages to all resources with - max equal priority when this priority is non-negative. - - * src/guide.tex: Added documentation for native database configuration. - -2006-04-22 Alexey Shchepin - - * src/msgs/pt-br.msg: Updated (thanks to Lucius Curado) - - * src/xml_stream.erl: Support for stanza size limit (thanks to - Igor Goryachev) - * src/ejabberd_receiver.erl: Likewise - * src/ejabberd_c2s.erl: Likewise - * src/ejabberd_s2s_in.erl: Likewise - * src/ejabberd.cfg.example: Updated - - * src/ejabberd_auth.erl: Fixed try_register/3 behaviour - -2006-04-20 Mickael Remond - - * src/ejabberd.cfg.example: Update of the example for anonymous. - Removed unnecessary parameter. - * src/ejabberd_auth_anonymous.erl: Removed unnecessary parameter / - bugfix. - * src/ejabberd_auth.erl: Bugfix: We now are forced to check is an - anonymous user is log under a given user name before trying to - register it. - * doc/guide.tex: Updated (SASL anonymous and anonymous login). - -2006-04-19 Alexey Shchepin - - * src/msgs/pl.msg: Updated (thanks to Andrzej Smyk) - -2006-04-13 Alexey Shchepin - - * src/xml_stream.erl: Cleanup - - * src/ejabberd_service.erl: Updated to use ejabberd_receiver - -2006-04-12 Alexey Shchepin - - * src/ejabberd_c2s.erl: Minor fix - - * src/ejabberd_c2s.erl: Bugfix (thanks to Sergei Golovan) - - * doc/guide.tex: Updated (thanks to Sergei Golovan) - - * src/msgs/nl.msg: Updated (thanks to Sander Devrieze) - -2006-04-11 Alexey Shchepin - - * src/msgs/es.msg: Updated (thanks to Badlop) - - * src/ejabberd.cfg.example: Updated (thanks to Badlop) - - * doc/guide.tex: Updated (thanks to Badlop) - -2006-04-07 Mickael Remond - - * src/mod_pubsub/mod_pubsub.erl: Fixed pubsub root node creation - (conflict error was send on node creation) - -2006-04-07 Alexey Shchepin - - * src/ejabberd_sm.erl: SASL Anonymous + Anonymous login support - (thanks to Mickael Remond and Magnus Henoch) - * src/ejabberd_c2s.erl: Likewise - * src/ejabberd_auth.erl: Likewise - * src/ejabberd_auth_anonymous.erl: Likewise - * src/cyrsasl.erl: Likewise - * src/cyrsasl_anonymous.erl: Likewise - * src/ejabberd.cfg.example: Likewise - -2006-04-06 Alexey Shchepin - - * src/expat_erl.c: Use binaries for CDATA - * src/xml.erl: Likewise - -2006-04-02 Alexey Shchepin - - * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) - * src/msgs/uk.msg: Likewise - - * src/mod_configure.erl: Updated translation strings (thanks to - Sergei Golovan) - * src/web/ejabberd_web_admin.erl: Likewise - - * src/ejabberd_s2s_in.erl: Changed a path to PKIX includes (thanks - to Sergei Golovan) - -2006-04-01 Mickael Remond - - * src/Makefile.in: Added an option to compile ejabberd with debug - print-out (make ejabberd_debug=true). - * src/ejabberd_c2s.erl: Added a new debug printout: We can now print - the XML packets send by the server. - -2006-03-31 Alexey Shchepin - - * src/ejabberd_c2s.erl: Bugfix - -2006-03-25 Alexey Shchepin - - * src/ejabberd_c2s.erl: Enable zlib only over TCP - -2006-03-18 Alexey Shchepin - - * src/ejabberd_c2s.erl: Bugfix (thanks to Sergei Golovan) - -2006-03-17 Alexey Shchepin - - * src/mod_privacy.erl: Fixed privacy list pushing (thanks to - Sergei Golovan) - * src/ejabberd_c2s.erl: Likewise - -2006-03-16 Mickael Remond - - * src/ejabberd_sm.erl: Remove unnecessary use delete_object, which can, - in some context break indexes, when used on non bag table. - -2006-03-16 Alexey Shchepin - - * src/ejabberd_c2s.erl: Bugfix - -2006-03-14 Alexey Shchepin - - * src/xml_stream.erl: Added catching of gen_fsm:send_event errors - - * src/ejabberd_s2s_out.erl: Better support for multiple SRV - records (thanks to Sergei Golovan) - - * src/mod_muc/mod_muc_log.erl: Support for chatroom logging - (thanks to Badlop) - * src/mod_muc/mod_muc_room.erl: Likewise - * src/mod_muc/Makefile.in: Likewise - * src/mod_muc/Makefile.win32: Likewise - -2006-03-11 Alexey Shchepin - - * src/gen_iq_handler.erl: Added support for {queues, N} IQ handler - type - -2006-03-06 Alexey Shchepin - - * src/mod_muc/mod_muc_room.erl: Bugfix - -2006-03-05 Alexey Shchepin - - * src/ejabberd_c2s.erl: Bugfix - - * src/ejabberd_auth_odbc.erl: Bugfix - -2006-03-04 Mickael Remond - - * src/ejabberd_logger_h.erl: reopen-log function now rename the log - file if it has not been already renamed by a logrotate process. This - change allow ejabberd administrators to rotate log files on Windows - (EJAB-52). - -2006-02-27 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Added a interface for node - updating - * src/ejabberd_update.erl: Added function update_info/0 - -2006-02-25 Alexey Shchepin - - * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) - * src/msgs/uk.msg: Likewise - - * contrib/extract_translations/extract_translations.erl: Minor - update (thanks to Sergei Golovan) - - * src/ejabberd_zlib/Makefile.win32: Zlib support for Windows build - (thanks to Sergei Golovan) - * src/Makefile.win32: Likewise - * src/configure.erl: Likewise - -2006-02-20 Alexey Shchepin - - * src/ejabberd_ctl.erl: Added API for virtual host specific - commands, removed registered-users command - * src/ejabberd_auth.erl: Added processing of registered-users - command - * src/ejabberd_auth_internal.erl: Likewise - * src/ejabberd_auth_ldap.erl: Likewise - * src/ejabberd_auth_odbc.erl: Likewise - * src/ejabberd_app.erl: Added inititalization of ejabberd_ctl - * src/ejabberd_sm.erl: Minor update - -2006-02-18 Alexey Shchepin - - * src/mod_irc/mod_irc_connection.erl: Added handling for "%", "&" - and "~" prefixes in IRC nicknames (thanks to Vladimir Kulev) - - * src/mod_irc/mod_irc_connection.erl: Added /msg and /ctcp - commands, improved handling of channel topic and kick, mirc colors - now filtered, other minor improvements (thanks to Oleg V. Motienko - and Magnus Henoch) - - * src/mod_configure.erl: Improved strings (thanks to Sander - Devrieze) - * src/mod_vcard.erl: Likewise - * src/mod_vcard_ldap.erl: Likewise - * src/mod_vcard_odbc.erl: Likewise - * src/web/ejabberd_web_admin.erl: Likewise - -2006-02-15 Alexey Shchepin - - * src/mod_service_log.erl: Bugfix (thanks to Badlop) - - * src/jd2ejd.erl: Use mod_vcard_odbc if it is loaded (thanks to - Tomasz Sterna) - -2006-02-14 Alexey Shchepin - - * src/ejabberd_sm.erl: Added a few ejabberdctl commands - - * src/ejabberd_ctl.erl: New interface for command registration - -2006-02-13 Alexey Shchepin - - * src/ejabberd_ctl.erl: Partially rewritten - * src/ejabberd_ctl.hrl: Definitions of exit status codes moved - here - -2006-02-12 Alexey Shchepin - - * src/mod_roster_odbc.erl: Bugfix - -2006-02-08 Alexey Shchepin - - * src/odbc/ejabberd_odbc.erl: Reconnect on ODBC connection closing - -2006-02-07 Mickael Remond - - * src/ejabberd_auth.erl: plugin authentication modules can now - be used in the configuration file: {auth_method, module} will now - use the module ejabberd_auth_module.erl for authentication. - -2006-02-05 Alexey Shchepin - - * src/mod_muc/mod_muc_room.erl: Kick non-members when room - reconfigured to be member-only or when membership is revoked in - member-only room, allowed "true" and "false" in x:data forms - (thanks to Sergei Golovan) - - * src/mod_configure.erl: Added "Host" parameter to get_form and - set_form functions (thanks to Sergei Golovan) - - * src/ejabberd_s2s_out.erl: Bugfix - - * src/msgs/es.msg: Updated (thanks to Badlop) - - * src/web/ejabberd_web.erl: Bugfix (thanks to Badlop) - - * src/mod_irc/mod_irc.erl: Updated copyright dates - * src/mod_muc/mod_muc.erl: Likewise - * src/mod_pubsub/mod_pubsub.erl: Likewise - * src/mod_vcard.erl: Likewise - * src/mod_vcard_ldap.erl: Likewise - * src/mod_vcard_odbc.erl: Likewise - * src/web/ejabberd_web_admin.erl: Likewise - -2006-02-03 Alexey Shchepin - - * src/ejabberd_auth_odbc.erl: Added ejabberd_odbc_sup to ejabberd - supervision tree - - * src/web/ejabberd_http.erl: Authentication check moved to - ejabberd_web.erl - * src/web/ejabberd_web.erl: Likewise - - * src/web/Makefile.in: Added ejabberd_http.hrl dependency - - * src/web/ejabberd_http_poll.erl: Updated to use {active, once} - socket mode - - * src/mod_irc/mod_irc.erl: Updated to use gen_server behaviour and - ejabberd supervision tree - * src/mod_irc/mod_irc_connection.erl: Likewise - -2006-02-02 Mickael Remond - - * src/configure.ac: --prefix option can now override the default - install dir - * src/configure: Likewise - * src/Makefile.in: Likewise - -2006-02-02 Alexey Shchepin - - * src/mod_pubsub/mod_pubsub.erl: Updated to use gen_server - behaviour and ejabberd supervision tree - * src/mod_echo.erl: Likewise - -2006-02-01 Alexey Shchepin - - * src/mod_muc/mod_muc.erl: Added a supervisor for conference room - processes - * src/mod_muc/mod_muc_room.erl: Likewise - -2006-01-29 Alexey Shchepin - - * src/odbc/pg.sql: Fixed syntax error - -2006-01-28 Alexey Shchepin - - * src/ejabberd_router.erl: Updated to use gen_server behaviour - * src/ejabberd_sm.erl: Likewise - * src/ejabberd_s2s.erl: Likewise - * src/gen_iq_handler.erl: Likewise - - * src/ejabberd_sup.erl: Added supervisor for ejabberd_receiver - * src/ejabberd_receiver.erl: Updated - -2006-01-27 Alexey Shchepin - - * src/ejabberd_update.erl: Support for run-time ejabberd updating - (not completed) - * src/ejabberd_c2s.erl: Added 'update_info' module attribute for - testing ejabberd_update - -2006-01-25 Alexey Shchepin - - * src/ejabberd_c2s.erl: Remove top-level xmlns from incoming - stanzas - * src/ejabberd_s2s_in.erl: Likewise - * src/ejabberd_service.erl: Likewise - - * src/ejabberd_c2s.erl: Better error handling for stream - compression support (thanks to Sergei Golovan) - -2006-01-24 Alexey Shchepin - - * src/mod_roster_odbc.erl: Bugfix - -2006-01-23 Alexey Shchepin - - * src/ejabberd_sm.erl: Partially rewritten to work more - efficiently and avoid race conditions - * src/ejabberd_c2s.erl: Likewise - -2006-01-21 Alexey Shchepin - - * src/mod_irc/mod_irc_connection.erl: Cleanup - -2006-01-20 Mickael Remond - - * src/ejabberd_receiver.erl: Added new debugging trace: It is now - possible to dump the XML stream received from a client (usefull for - client debugging). - -2006-01-19 Alexey Shchepin - - * src/aclocal.m4: Updated for zlib support - * src/configure.ac: Likewise - - * src/mod_muc/mod_muc_room.erl: Weakened presence filtering, added - warning in non-anonymous rooms, room destroying updated to latest - JEP-0045, added a number of occupants and room name in room's - disco#info reply, miscellaneous internal changes (thanks to Sergei - Golovan) - - * src/mod_muc/mod_muc.erl: Better support for nick unregistration - (thanks to Sergei Golovan) - - * src/ejabberd_zlib/ejabberd_zlib.erl: Zlib support (thanks to - Sergei Golovan) - * src/ejabberd_zlib/ejabberd_zlib_drv.c: Likewise - * src/ejabberd_zlib/Makefile.in: Likewise - * src/ejabberd_c2s.erl: Stream compression support (JEP-0138) - * src/ejabberd_receiver.erl: Likewise - - * src/mod_disco.erl: Don't split node name before calling hooks - (thanks to Sergei Golovan) - - * src/mod_configure.erl: Support for configuration using ad-hoc - commands (thanks to Sergei Golovan) - - * src/mod_announce.erl: Support for sending announce messages - using ad-hoc commands (thanks to Sergei Golovan) - - * src/mod_adhoc.erl: Ad-hoc support (JEP-0050) (thanks to Magnus - Henoch) - * src/adhoc.erl: Likewise - * src/adhoc.hrl: Likewise - - * src/jlib.hrl: Updated (thanks to Sergei Golovan) - - * src/gen_mod.erl: Added function is_loaded/2 (thanks to Sergei - Golovan) - - * src/ejabberd_service.erl: Changed error message on handshake - error (thanks to Sergei Golovan) - - * src/ejabberd.cfg.example: Updated (thanks to Sergei Golovan) - -2006-01-13 Mickael Remond - - * src/odbc/ejabberd_odbc.erl: underscore and percent are now only - escaped in like queries. MySQL where not escaping those escaped - characters in other context. - * src/mod_vcard_odbc.erl: likewise. - * src/odbc/mysql.sql: Fixed MySQL database creation script: Was - not properly working with all MySQL version. - * src/odbc/ejabberd_odbc.erl: Added a way to retry database - connection connect for 5 minutes when the connection is lost. No - further connection is retry after. - * src/odbc/ejabberd_odbc_sup.erl: likewise. - -2006-01-13 Alexey Shchepin - - * src/ejabberd_service.erl: Bugfix - - * src/ejabberd_receiver.erl: Rewritten to use {active, once} mode - for socket - * src/ejabberd_c2s.erl: Update - * src/ejabberd_listener.erl: Likewise - * src/ejabberd_s2s_in.erl: Likewise - * src/ejabberd_s2s_out.erl: Likewise - * src/ejabberd_service.erl: Likewise - * src/shaper.erl: Likewise - * src/tls/tls.erl: Likewise - * src/web/ejabberd_http.erl: Likewise - -2006-01-02 Mickael Remond - - * src/odbc/ejabberd_odbc.erl: Native MySQL support - -2005-12-24 Alexey Shchepin - - * src/ejabberd_logger_h.erl: Speed optimizations - -2005-12-22 Alexey Shchepin - - * src/Makefile.in: Clean results of ASN.1 compiler (thanks to - Sergei Golovan) - - * src/win32/ejabberd.nsh: Removed (thanks to Sergei Golovan) - -2005-12-22 Mickael Remond - - * src/odbc/ejabberd_odbc.erl: Added error message on ODBC - connection to help ODBC configuration troubleshooting. - -2005-12-22 Alexey Shchepin - - * src/Makefile.win32: Updated (thanks to Sergei Golovan) - * src/configure.erl: Likewise - * src/win32/CheckReqs.ini: Likewise - * src/win32/CheckReqs1.ini: Likewise - * src/win32/CheckReqs1H.ini: Likewise - * src/win32/ejabberd.nsh: Likewise - * src/win32/ejabberd.nsi: Likewise - - * src/odbc/ejabberd_odbc.erl: Bugfix - -2005-12-21 Mickael Remond - - * src/odbc/mysql.sql: Database description for MySQL Database 4.1 - (Max version, with Innodb) - * src/ejabberd_auth_odbc.erl: MySQL ODBC support - * src/mod_offline_odbc.erl: Likewise - * src/mod_vcard_odbc.erl: Likewsie - * src/mod_roster_odbc.erl: Likewise - * src/odbc/ejabberd_odbc.erl: Likewise - * src/mod_last_odbc.erl: Likewise - -2005-12-16 Mickael Remond - - * doc/Makefile: Added helper to generate the docs (Thanks to Sander - Devrieze) - * doc/guide.tex: Added ejabberd 1.0.0 release notes. - * doc/dev.tex: Code clean-up (Thanks to Sander Devrieze) - -2005-12-16 Alexey Shchepin - - * doc/features.tex: Added feature sheet (Thanks to Sander - Devrieze) - -2005-12-14 Alexey Shchepin - - * src/mod_irc/iconv_erl.c: Bugfix (thanks to Tomas Janousek) - -2005-12-13 Alexey Shchepin - - * src/win32/ejabberd.nsi: Updated (thanks to Maxim Ryazanov) - - * src/ejabberd.hrl: Updated version - * src/ejabberd.app: Likewise - * doc/version.tex: Likewise - -2005-12-13 Mickael Remond - - * doc/release_notes_1.0.0.txt: Added preliminary version of ejabberd - 1.0.0 release notes. - * doc/guide.html: Generated the updated HTML version of the documentation. - -2005-12-11 Alexey Shchepin - - * src/mod_roster.erl: Workaround for gateway subscriptions now - should be enabled with --enable-roster-gateway-workaround - * src/mod_roster_odbc.erl: Likewise - * src/configure.ac: Likewise - * src/Makefile.in: Likewise - -2005-12-10 Alexey Shchepin - - * src/ejabberd_service.erl: Added logging of termination - - * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) - * src/msgs/uk.msg: Likewise - - * src/msgs/*.msg: Updated (thanks to Badlop) - -2005-12-08 Mickael Remond - - * contribs/contrib/extract_translations/prepare-translation.sh: - Small improvements. - * src/msgs/fr.msg: Updated - -2005-12-07 Alexey Shchepin - - * src/msgs/pl.msg: Fixed syntax error - - * src/mod_offline.erl: Don't store headline messages - * src/mod_offline_odbc.erl: Likewise - -2005-12-06 Alexey Shchepin - - * doc/guide.tex: Updated - -2005-12-06 Mickael Remond - - * src/ejabberd.cfg.example: Updated - - * src/Makefile.*: Can now be build when the Erlang environment is - not Erlang/OTP but the Erlang REPOS CDROM. Still compatible with - standard Erlang/OTP install - * aclocal.m4: Likewise - * src/Makefile.*: Can now be build with Erlang debug_info with - 'make debug=true' - -2005-12-06 Alexey Shchepin - - * src/msgs/pt-br.msg: Updated (thanks to Victor Hugo dos Santos) - - * src/msgs/pl.msg: Updated (thanks to Andrzej Smyk) - - * src/msgs/sv.msg: Updated (thanks to Magnus Henoch) - - * src/msgs/de.msg: Updated (thanks to Patrick Dreker) - -2005-11-30 Mickael Remond - - * doc/yozhikheader.png: Added feature sheet header (Thanks to Sander - Devrieze) - -2005-11-28 Mickael Remond - - * doc/guide.tex: Improved and updated documentation (Thanks to Sander - Devrieze) - * doc/guide.html: Likewise - * doc/features.tex: Likewise - * doc/introduction.tex: Likewise - * doc/version.tex: Likewise - * doc/logo.png: New logo for ejabberd doc (Thanks to Sander Devrieze) - -2005-11-26 Alexey Shchepin - - * src/web/ejabberd_http.erl: Now web interface is compliant to - XHTML 1.0 Transitional (thanks to Sander Devrieze) - * src/web/ejabberd_web_admin.erl: Likewise - -2005-11-25 Alexey Shchepin - - * doc/Makefile: Now really added - -2005-11-22 Alexey Shchepin - - * src/mod_roster.erl: The "id" attribute of roster push packet was - missed (thanks to Maxim Ryazanov) - * src/mod_roster_odbc.erl: Likewise - - * src/web/ejabberd_web_admin.erl: Fixed encoding of user names in - URLs - - * src/web/ejabberd_http.erl: Added url_encode function from yaws - - * src/ejabberd_c2s.erl: Send stream error when connection is - replaced (thanks to Maxim Ryazanov) - -2005-11-19 Mickael Remond - - * contrib/extract_translations/prepare-translation.sh: Added - wrapper to extract_translation.erl (thanks to Badlop) - -2005-11-19 Alexey Shchepin - - * src/mod_vcard.erl: Fixed xmlns in disco items replies (thanks to - Maxim Ryazanov) - * src/mod_vcard_ldap.erl: Likewise - * src/mod_vcard_odbc.erl: Likewise - - * src/tls/Makefile.in: Use CPPFLAGS (thanks to Magnus Henoch) - -2005-11-17 Alexey Shchepin - - * src/ejabberd_s2s_in.erl: Support for dNSName certificate field - and DNS name matching - * src/XmppAddr.asn1: Moved here from src/tls/XmppAddr.asn1 - * src/tls/XmppAddr.asn1: Likewise - * src/Makefile.in: Updated - * src/tls/Makefile.in: Updated - -2005-11-16 Alexey Shchepin - - * src/odbc/ejabberd_odbc.erl: Support for mnesia-like transaction - interface - * src/mod_roster_odbc.erl: Updated to use - ejabberd_odbc:sql_transaction/2 - -2005-11-12 Alexey Shchepin - - * src/ejabberd_s2s_out.erl: Fixed invalid behaviour upon - connecting to host with invalid domain - * src/ejabberd_s2s.erl: Likewise - -2005-11-05 Alexey Shchepin - - * src/ejabberd_config.erl: Support for per host certificates - * src/ejabberd_c2s.erl: Likewise - * src/ejabberd_s2s_out.erl: Likewise - * src/ejabberd.cfg.example: Updated - - * src/ejabberd_s2s_in.erl: Fixed id-on-xmppAddr processing - -2005-11-03 Alexey Shchepin - - * src/mod_disco.erl: Fixed extra_domains option processing - - * src/ejabberd_s2s_out.erl: Support for STARTTLS+SASL EXTERNAL - (not well-tested yet) - * src/ejabberd_s2s_in.erl: Likewise - * src/tls/tls.erl: Likewise - * src/tls/tls_drv.c: Likewise - * src/tls/XmppAddr.asn1: Likewise - * src/tls/Makefile.in: Likewise - -2005-10-30 Alexey Shchepin - - * src/mod_disco.erl: Minor fix - -2005-10-29 Alexey Shchepin - - * src/mod_roster_odbc.erl: Bugfix - -2005-10-25 Alexey Shchepin - - * src/tls/tls.erl: Accept {error,already_loaded} from - erl_ddll:load_driver/2 - * src/stringprep/stringprep.erl: Likewise - * src/mod_irc/iconv.erl: Likewise - * src/ejabberd_app.erl: Likewise - - * src/tls/tls_drv.c: Support for "connect" method - * src/tls/tls.erl: Likewise - - * src/ejabberd_s2s_in.erl: Support for STARTTLS+Dialback - * src/ejabberd_s2s_out.erl: Likewise - * src/ejabberd_receiver.erl: Added a few hacks ({active,once} mode - should be used instead of recv/3 call to avoid them) - * src/ejabberd_config.erl: Added s2s_use_starttls and s2s_certfile - options - * src/ejabberd.cfg.example: Likewise - -2005-10-22 Alexey Shchepin - - * src/ejabberd_app.erl: Try to load tls_drv at startup to avoid - unloading of libssl (thanks to Brian Campbell) - -2005-10-20 Alexey Shchepin - - * src/odbc/pg.sql: Added spool.seq field for offline messages - sorting - * src/mod_offline_odbc.erl: Likewise - -2005-10-18 Alexey Shchepin - - * src/mod_roster_odbc.erl: Bugfix - -2005-10-16 Alexey Shchepin - - * src/gen_iq_handler.erl: Bugfix - -2005-10-15 Alexey Shchepin - - * src/ejabberd_auth_odbc.erl: Minor fix - - * src/odbc/ejabberd_odbc.erl: Updated pgsql support - - * src/mod_roster_odbc.erl: Bugfix - - * src/ejabberd_c2s.erl: Updated to work correctly with - mod_vcard_odbc - -2005-10-13 Alexey Shchepin - - * src/odbc/ejabberd_odbc.erl: Experimental support for pgsql - library - - * src/ejabberd_auth_odbc.erl: Bugfix - - * src/mod_roster_odbc.erl: Bugfix - -2005-10-07 Alexey Shchepin - - * src/ejd2odbc.erl: Added vCard converter - - * src/mod_vcard_odbc.erl: vCard support via ODBC - - * src/odbc/pg.sql: Updated - -2005-09-18 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Updated API for better - integration with J-EAI web interface - - * src/mod_shared_roster.erl: Now possible to specify all users on - virtual host in group - * src/web/ejabberd_web_admin.erl: Likewise - -2005-09-15 Alexey Shchepin - - * src/jlib.erl: Bugfix - -2005-09-10 Alexey Shchepin - - * src/ejd2odbc.erl: Updated - -2005-09-04 Alexey Shchepin - - * src/mod_disco.erl: Disco publishing support (thanks to Magnus - Henoch) - - * src/mod_disco.erl: Functions register_sm_feature and - register_sm_node replaced with hooks (thanks to Sergei Golovan) - * src/mod_vcard.erl: Updated - * src/mod_vcard_ldap.erl: Likewise - - * src/mod_disco.erl: Now mod_disco doesn't depend on mod_configure - (thanks to Sergei Golovan) - * src/mod_configure.erl: Likewise - -2005-08-29 Alexey Shchepin - - * src/ejd2odbc.erl: Converter from mnesia to ODBC - - * src/mod_offline_odbc.erl: Minor fix - -2005-08-25 Alexey Shchepin - - * src/mod_vcard_ldap.erl: Bugfix - - * src/mod_vcard.erl: Bugfix - -2005-08-23 Alexey Shchepin - - * src/ejabberd_auth_odbc.erl: Bugfix - -2005-08-21 Alexey Shchepin - - * doc/dev.tex: Updated - -2005-08-11 Alexey Shchepin - - * src/cyrsasl_digest.erl: Fixed challenge/response parsing (thanks - to Martin Pokorny) - -2005-08-07 Alexey Shchepin - - * src/msgs/pl.msg: Updated (thanks to Andrew Smyk) - - * src/web/ejabberd_web_admin.erl: Bugfix (thanks to Badlop) - -2005-08-05 Alexey Shchepin - - * src/win32/inetrc: Added (thanks to Sergei Golovan) - - * src/Makefile.win32: Updated (thanks to Sergei Golovan) - * src/win32/ejabberd.cfg: Likewise - * src/win32/ejabberd.nsi: Likewise - - * doc/guide.tex: Updated - - * src/ejabberd.hrl: Updated version - -2005-08-01 Alexey Shchepin - - * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) - * src/msgs/uk.msg: Likewise - - * src/msgs/es.msg: Updated (thanks to Badlop) - - * src/msgs/nl.msg: Updated (thanks to Sander Devrieze) - -2005-08-01 Mickael Remond - - * (all): ejabberd-0.9.8 released - - * src/msgs/fr.msg: Updated - -2005-07-31 Alexey Shchepin - - * src/ejabberd_config.erl: Added host_config option - * doc/guide.tex: Updated - - * src/ejabberd_auth_ldap.erl: Bugfix - - * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) - * src/msgs/uk.msg: Likewise - - * src/msgs/de.msg: Updated (thanks to Torsten Werner) - - * src/web/ejabberd_web_admin.erl: Fixed CSS style sheet to be - standards compliant (thanks to Sander Devrieze) - -2005-07-29 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Added "Virtual Hosts" page - -2005-07-27 Alexey Shchepin - - * src/ejabberd_router.erl: Added filter_packet hook - -2005-07-26 Alexey Shchepin - - * src/jd2ejd.erl: Updated to work with ODBC - - * src/mod_roster_odbc.erl: Updated - -2005-07-22 Alexey Shchepin - - * src/mod_offline_odbc.erl: Bugfix - - * src/mod_last_odbc.erl: Bugfix - -2005-07-20 Alexey Shchepin - - * src/mod_pubsub/mod_pubsub.erl: Updated to J-EAI version - -2005-07-15 Alexey Shchepin - - * src/acl.erl: Slightly changed "access" option processing - - * src/mod_disco.erl: Fixed processing of host features and - extra_domains option - - * src/ejabberd_c2s.erl: Processing of jabber:iq:register totally - moved to mod_register.erl (thanks to Sergei Golovan) - * src/mod_register.erl: Likewise - - * src/win32/ejabberd.nsi: Added two pictures in installer (thanks - to Maxim Ryazanov) - * src/win32/ejabberd_header.bmp: Likewise - * src/win32/ejabberd_intro.bmp: Likewise - - * src/web/ejabberd_web_admin.erl: Fixed spelling of word - "authentication" - * src/ejabberd_c2s.erl: Likewise - -2005-07-13 Alexey Shchepin - - * src/mod_register.erl: Bugfix - - * src/mod_vcard.erl: Bugfix - - * src/ejabberd_app.erl: Updated to allow different authentication - methods for different virtual hosts - * src/ejabberd_auth.erl: Likewise - * src/ejabberd_auth_external.erl: Likewise - * src/ejabberd_auth_internal.erl: Likewise - * src/ejabberd_auth_ldap.erl: Likewise - * src/ejabberd_auth_odbc.erl: Likewise - * src/cyrsasl.erl: Likewise - * src/cyrsasl_digest.erl: Likewise - * src/cyrsasl_plain.erl: Likewise - * src/ejabberd_c2s.erl: Likewise - * src/ejabberd_config.erl: Likewise - * src/extauth.erl: Likewise - * src/mod_last_odbc.erl: Likewise - * src/mod_offline_odbc.erl: Likewise - * src/mod_roster_odbc.erl: Likewise - * src/odbc/ejabberd_odbc.erl: Likewise - * src/odbc/ejabberd_odbc_sup.erl: Likewise - -2005-07-03 Alexey Shchepin - - * src/ejabberd_app.erl: Bugfix - - * src/ejabberd_config.erl: Bugfix - -2005-06-30 Alexey Shchepin - - * src/mod_offline.erl: Bugfix - -2005-06-20 Alexey Shchepin - - * (all): Enhanced virtual hosting support - -2005-05-28 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Bugfix - -2005-05-25 Alexey Shchepin - - * src/msgs/pt-br.msg: New Brazilian Portuguese translation (thanks - to Felipe Brito Vasconcellos) - -2005-05-23 Alexey Shchepin - - * (all): ejabberd-0.9.1 released - - * src/msgs/fr.msg: Updated (thanks to Mickael Remond) - - * src/odbc/Makefile.in: Added - - * src/configure.ac: Updated for odbc support - * src/Makefile.in: Likewise - - * src/aclocal.m4: Bugfix - - * src/mod_last_odbc.erl: Added store_last_info/4 function (thanks - to Sergei Golovan) - * src/mod_last.erl: Likewise - - * src/jd2ejd.erl: Support for exporting iq:last information, - better error handling (thanks to Sergei Golovan) - - * src/ejabberd_ctl.erl: Added "import-file" and "import-dir" - commands (thanks to Sergei Golovan) - - * doc/guide.tex: Updated (thanks to Sergei Golovan) - * doc/dev.tex: Likewise - * doc/disco.png: Likewise - * doc/discorus.png: Likewise - * doc/webadmin.png: Likewise - * doc/webadminru.png: Likewise - - * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) - * src/msgs/uk.msg: Likewise - - * src/web/ejabberd_web_admin.erl: Updated CSS, added modules - management, fixed bug with configuring of listened ports on - different nodes (thanks to Sergei Golovan) - - * src/gen_mod.erl: Added function loaded_modules_with_opts/0, new - API for module stopping (thanks to Sergei Golovan) - * src/mod_muc/mod_muc.erl: Moved a process name to a macros, - updated module stopping (thanks to Sergei Golovan) - * src/mod_irc/mod_irc.erl: Likewise - * src/mod_pubsub/mod_pubsub.erl: Likewise - * src/mod_announce.erl: Updated module stopping (thanks to Sergei - Golovan) - * src/mod_echo.erl: Likewise - * src/mod_offline.erl: Likewise - - * src/web/ejabberd_http.erl: "Connection:" header value now - matched case-insensitive, and returned to client, replaced - duplicate is_space($\r) with is_space($\t) (thanks to Maxim - Ryazanov) - -2005-05-21 Alexey Shchepin - - * src/mod_pubsub/mod_pubsub.erl: Fixed XML element name for - pubsub#event namespace (thanks to Magnus Henoch) - - * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) - * src/msgs/uk.msg: Likewise - - * src/msgs/es.msg: Updated (thanks to Badlop) - -2005-05-19 Alexey Shchepin - - * src/mod_pubsub/mod_pubsub.erl: Now possible to subscribe to a - pubsub node with a JID that includes a resource (thanks to Martijn - van Beers) - - * src/stringprep/uni_parse2.tcl: Bugfix - * src/stringprep/stringprep_drv.c: Likewise - * src/stringprep/uni_norm.c: Regenerated - -2005-05-18 Alexey Shchepin - - * src/mod_irc/mod_irc_connection.erl: Added support for WHOIS - requests and reply to USERINFO (thanks to Oleg V. Motienko) - -2005-05-17 Alexey Shchepin - - * src/stringprep/stringprep_drv.c: Bugfix - -2005-05-16 Alexey Shchepin - - * src/win32/ejabberd.cfg: Updated (thanks to Sergei Golovan) - - * src/odbc/Makefile.win32: Added (thanks to Sergei Golovan) - - * src/Makefile.win32: Updated (thanks to Sergei Golovan) - -2005-05-15 Alexey Shchepin - - * src/jd2ejd.erl: Fixed private xml setting - - * src/mod_last.erl: Bugfix - * src/mod_last_odbc.erl: Likewise - - * src/mod_pubsub/mod_pubsub.erl: Fixed service stopping - -2005-05-09 Alexey Shchepin - - * src/mod_muc/mod_muc_room.erl: Fixed bug with storing - affiliations of invited users in members-only room (thanks to - Sergei Golovan) - - * src/ejabberd_c2s.erl: Fixed starttls_required behaviour for - legacy connections (thanks to Brian Campbell) - - * src/web/ejabberd_web_admin.erl: Images now specified via CSS, - design slightly updated, added last activity statistics (thanks to - Sergei Golovan) - -2005-05-07 Alexey Shchepin - - * src/stringprep/stringprep_drv.c: Added check for bidi - - * src/stringprep/uni_parse.tcl: Now handle all Unicode code points - up to U+10FFFF - * src/stringprep/uni_parse2.tcl: Likewise - * src/stringprep/uni_data.c: Regenerated - * src/stringprep/uni_norm.c: Likewise - -2005-05-06 Alexey Shchepin - - * src/stringprep/uni_norm.c: Regenerated with Unicode 3.2 tables - as required by RFC3454 - - * src/stringprep/uni_parse2.tcl: Bugfixes - - * src/stringprep/stringprep_drv.c: Bugfixes, added hangul - composition - -2005-05-05 Mickael Remond - - * src/msgs/fr.msg: Added missing version 0.9 fields and removed unused - ones. - -2005-05-04 Alexey Shchepin - - * src/mod_muc/mod_muc_room.erl: Store ban reasons for outcast - items, updated affiliation matching rules to latest JEP-0045 - -2005-05-02 Alexey Shchepin - - * src/mod_muc/mod_muc_room.erl: Updated changing roles and - affiliations tables to latest JEP-0045 - -2005-05-01 Mickael Remond - - * src/msgs/fr.msg: Updated - -2005-05-01 Alexey Shchepin - - * src/msgs/sw.msg: Renamed to sv.msg - * src/msgs/sv.msg: Likewise - - * src/msgs/pl.msg: Updated (thanks to Andrew Smyk) - - * contrib/extract_translations/README: Better phrasing (thanks to - Sergei Golovan) - - * contrib/extract_translations/extract_translations.erl: Fix to - avoid duplication of lines (thanks to Sergei Golovan) - - * src/msgs/sw.msg: New Swedish translation (thanks to Magnus - Henoch) - - * src/msgs/pt.msg: New Portuguese translation (thanks to iceburn) - - * src/msgs/es.msg: Updated (thanks to Badlop) - - * src/msgs/nl.msg: Updated (thanks to Sander Devrieze) - -2005-04-27 Alexey Shchepin - - * src/ejabberd_auth_ldap.erl: Added listing of users support - - * src/ejabberd.cfg.example: Updated LDAP options - - * src/ejabberd_ctl.erl: Better spelling, now prints full file - paths, fixed checking of mnesia:install_fallback result, now - "dump" command dumps only persistent tables - - * contrib/extract_translations/: A tool for extracting of - translation strings from ejabberd code (thanks to Sergei Golovan) - -2005-04-26 Alexey Shchepin - - * src/mod_vcard_ldap.erl: Bugfix (thanks to Mickael Remond) - -2005-04-24 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Added translation to submit - button and "shared roster groups" header (thanks to iceburn and - Sergei Golovan) - - * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) - * src/msgs/uk.msg: Likewise - - * src/mod_muc/mod_muc_room.erl: Minor update to simplify - translation (thanks to Sergei Golovan) - - * src/tls/tls_drv.c: Reverted previous patch - -2005-04-22 Alexey Shchepin - - * doc/guide.tex: Added mod_shared_roster documentation - - * src/ejabberd.hrl: Updated version - -2005-04-21 Alexey Shchepin - - * src/jd2ejd.erl: Bugfix - -2005-04-20 Alexey Shchepin - - * src/ejabberd_auth.erl: Added check for domain of registered user - - * src/web/ejabberd_web_admin.erl: Fixed user registration via web - interface, fixed path to user's offline messages (thanks to - Mickael Remond) - - * src/mod_disco.erl: Fixed domain listing when one virtual host is - a subdomain of another - -2005-04-18 Alexey Shchepin - - * (all): ejabberd-0.9 released - - * src/web/ejabberd_web_admin.erl: Added link to shared roster page - - * src/odbc/ejabberd_odbc.erl: ODBC connection string can be - specified via odbc_server option now - * src/ejabberd.cfg.example: Added ODBC usage example - - * doc/guide.tex: Updated - - * src/msgs/pl.msg: New Polish translation (thanks to Andrew Smyk) - -2005-04-17 Alexey Shchepin - - * (all): Merged virtual hosting support - -2005-04-09 Alexey Shchepin - - * src/ejabberd_c2s.erl: Send new id for each new stream inside one - session (thanks to Maxim Ryazanov) - - * src/tls/tls_drv.c: Now reads all certificates from certificate - file instead of reading only first one (thanks to Karl-Johan - Karlsson) - -2005-04-06 Alexey Shchepin - - * examples/transport-configs/init-scripts/jabber-gg-transport: - Fixed typo (thanks to Sander Devrieze) - -2005-04-05 Alexey Shchepin - - * examples/transport-configs/configs/msn-transport.xml: Fixed typo - (thanks to Sander Devrieze) - -2005-04-02 Alexey Shchepin - - * examples/transport-configs/: Updated (thanks to Sander Devrieze) - -2005-03-31 Alexey Shchepin - - * src/ejabberd_ctl.erl: Bugfix - -2005-03-17 Alexey Shchepin - - * src/mod_muc/mod_muc_room.erl: Bugfix - -2005-03-15 Alexey Shchepin - - * src/ejabberd_sm.erl: Bugfix - -2005-03-12 Alexey Shchepin - - * src/ejabberd_router.erl: Bugfix - -2005-01-14 Alexey Shchepin - - * src/mod_irc/mod_irc_connection.erl: Added filtering of quit - status - -2005-01-04 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Copyright update - * src/mod_vcard_ldap.erl: Likewise - * src/mod_vcard.erl: Likewise - * src/mod_pubsub/mod_pubsub.erl: Likewise - * src/mod_muc/mod_muc.erl: Likewise - * src/mod_irc/mod_irc.erl: Likewise - -2004-12-30 Alexey Shchepin - - * src/odbc/ejabberd_odbc.erl: Load-balance ODBC requests between - several connections - - * src/odbc/ejabberd_odbc_sup.erl: Supervisor for ODBC connections - - * src/mod_muc/mod_muc_room.erl: Added missed type='form' attribute - in room configuration response (thanks to Badlop) - -2004-12-19 Alexey Shchepin - - * src/mod_roster_odbc.erl: Roster support via ODBC (not completed) - - * src/ejabberd_auth_internal.erl: Added remove_user hook - * src/ejabberd_auth_odbc.erl: Likewise - * src/mod_roster.erl: Use remove_user hook - * src/mod_offline.erl: Likewise - * src/mod_offline_odbc.erl: Likewise - * src/mod_last.erl: Likewise - * src/mod_last_odbc.erl: Likewise - * src/mod_vcard.erl: Likewise - * src/mod_private.erl: Likewise - - * src/mod_roster.erl: Added hooks for functions exported by - mod_roster - * src/ejabberd_c2s.erl: Likewise - * src/ejabberd_sm.erl: Likewise - * src/mod_privacy.erl: Likewise - * src/mod_last.erl: Likewise - * src/mod_last_odbc.erl: Likewise - -2004-12-14 Alexey Shchepin - - * src/ejabberd_sm.erl: Updated missed message passing from - previous patch - -2004-12-13 Alexey Shchepin - - * src/odbc/pg.sql: DB creation script for postgres - - * src/odbc/ejabberd_odbc.erl: Experimental support for ODBC - * src/mod_last_odbc.erl: Likewise - * src/mod_offline_odbc.erl: Likewise - * src/ejabberd_auth_odbc.erl: Likewise - * src/ejabberd_auth.erl: Likewise - -2004-12-12 Alexey Shchepin - - * src/mod_stats.erl: Minor optimizations - - * src/ejabberd_sm.erl: Added unset_presence_hook - * src/mod_last.erl: Use unset_presence_hook instead of direct call - - * src/ejabberd_auth.erl: Splitted into ejabberd_auth_internal.erl, - ejabberd_auth_ldap.erl, and ejabberd_auth_external.erl, - * src/ejabberd_auth_internal.erl: Likewise - * src/ejabberd_auth_ldap.erl: Likewise - * src/ejabberd_auth_external.erl: Likewise - -2004-12-05 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Changed type of password field - to "password" - - * src/jlib.hrl: More stream error defines (thanks to Sergei - Golovan) - - * src/ejabberd_c2s.erl: Support for starttls_required option - (thanks to Sergei Golovan) - - * src/mod_muc/mod_muc_room.erl: Fixed mistake in case condition - (thanks to Sergei Golovan) - - * src/xml_stream.erl: Added function parse_element/1 - - * src/expat_erl.c: Added PARSE_FINAL_COMMAND - -2004-12-03 Alexey Shchepin - - * src/ejabberd_listener.erl: Enable keepalive option - - * src/xml_stream.erl: Added API for managing xml streams without - creating process - * src/ejabberd_receiver.erl: Use this API, now 2 processes are - created per C2S connection - -2004-12-01 Alexey Shchepin - - * src/expat_erl.c: Now uses port control instead of port output - * src/xml_stream.erl: Likewise - -2004-11-30 Alexey Shchepin - - * src/stringprep/stringprep.erl: Now register port instead of - storing it in ets table - -2004-11-28 Alexey Shchepin - - * doc/guide.tex: Updated URLs to R10C release - -2004-11-20 Alexey Shchepin - - * src/mod_vcard.erl: Added missed index - -2004-11-08 Alexey Shchepin - - * doc/guide.tex: Updated (thanks to Sander Devrieze) - -2004-11-05 Alexey Shchepin - - * src/aclocal.m4: Fixed headers detecting in AM_WITH_OPENSSL - (thanks to Leif Johansson) - - * src/ejabberd_auth.erl: Added support for ldap_rootdn and - ldap_password options (thanks to Stefan de Konink) - * src/mod_vcard_ldap.erl: Likewise - - * src/ejabberd_router.erl: Now possible to route packet via - function call instead of message sending - * src/ejabberd_sm.erl: Added function route/3, use it in route - table - * src/ejabberd_local.erl: Likewise - * src/ejabberd_s2s.erl: Likewise - -2004-10-23 Alexey Shchepin - - * (all): Fixed spelling of word "authentication" - - * src/*/Makefile.in: Replaced erlc with @ERLC@ - -2004-10-15 Alexey Shchepin - - * src/ejabberd_s2s.erl: Added remove_connection/1 - * src/ejabberd_s2s_out.erl: Use ejabberd_s2s:remove_connection/1 - - * src/ejabberd_s2s_in.erl: Minor cleanup - - * examples/transport-configs/: Transport config examples (thanks - to Sander Devrieze) - - * src/msgs/de.msg: German translation (thanks to Marina Hahn) - -2004-10-12 Alexey Shchepin - - * src/win32/: Updated (thanks to Sergei Golovan) - - * src/msgs/es.msg: Updated (thanks to Badlop) - - * src/mod_irc/iconv_erl.c: Bugfix (thanks to Jacek Konieczny) - -2004-10-10 Alexey Shchepin - - * (all): ejabberd-0.7.5 released - - * src/tls/Makefile.win32: Added (thanks to Sergei Golovan) - - * src/win32/: Updated (thanks to Sergei Golovan) - -2004-10-09 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Fixed user listing - - * src/msgs/uk.msg: Updated (thanks to Sergei Golovan) - - * src/msgs/nl.msg: Updated (thanks to Sander Devrieze) - - * src/msgs/ua.msg: Renamed to uk.msg - - * COPYING: Added permission to link with OpenSSL - -2004-10-08 Alexey Shchepin - - * src/msgs/ua.msg: Updated (thanks to Sergei Golovan) - - * src/mod_muc/mod_muc_room.erl: Fixed room destroying - - * src/ejabberd.cfg.example: Updated - - * src/ejabberd_sm.erl: Fixed message routing when all resources - have negative priority - - * src/msgs/*.msg: Updated (thanks to Sergei Golovan) - - * src/web/ejabberd_web_admin.erl: Table titles now bold (thanks to - Sergei Golovan) - -2004-10-06 Alexey Shchepin - - * doc/guide.tex: Updated - - * src/ejabberd_s2s_out.erl: Fixed socket closing condition - -2004-10-05 Alexey Shchepin - - * src/web/ejabberd_http_poll.erl: Properly handle bad requests - - * src/web/ejabberd_web_admin.erl: Ported features from J-EAI - -2004-09-30 Alexey Shchepin - - * src/web/ejabberd_http.erl: Fixed processing of POST body for - HTTP Polling - - * src/web/ejabberd_http.erl: Support for "Connection" HTTP header - (thanks to Sergei Golovan) - - * src/translate.erl: Much better handling of xml:lang (thanks to - Sergei Golovan) - -2004-09-29 Alexey Shchepin - - * src/ejabberd_listener.erl: Check result of controlling_process - - * src/web/ejabberd_http.erl: Bugfix - -2004-09-27 Alexey Shchepin - - * src/Makefile.in: Updated (thanks to Badlop) - -2004-09-26 Alexey Shchepin - - * src/aclocal.m4: Better expat and openssl detection (thanks to - Anton Vanin) - - * src/**/Makefile.in: Updated (thanks to Anton Vanin) - * src/configure.ac: Likewise - -2004-09-25 Alexey Shchepin - - * src/jlib.hrl: Added namespace for iq-register stream feature - * src/ejabberd_c2s.erl: Send iq-register feature - - * src/ejabberd_config.erl: Config file can be configured via - environment variable (thanks to Mickael Remond) - - * src/web/ejabberd_http.erl: Added SSL support (thanks to Sergei - Golovan) - - * src/msgs/*.msg: Updated (thanks to Sergei Golovan) - - * src/jlib.hrl: Updated error codes (thanks to Sergei Golovan) - * src/ejabberd_c2s.erl: Likewise - -2004-09-17 Alexey Shchepin - - * src/mod_muc/mod_muc_room.erl: Send password in room invitation - (thanks to Sergei Golovan) - - * src/mod_disco.erl: Added registration of sm features and nodes - (thanks to Sergei Golovan) - * src/mod_vcard.erl: Register vcard-temp feature (thanks to Sergei - Golovan) - - * src/jlib.erl: Added functions now_to_utc_string/1, - now_to_local_string/1, and datetime_string_to_timestamp/1 (thanks - to Sergei Golovan) - * src/mod_muc/mod_muc_room.erl: Use time parsing functions from - jlib (thanks to Sergei Golovan) - -2004-09-16 Alexey Shchepin - - * ejabberd/src/mod_pubsub/mod_pubsub.erl: Bugfix (thanks to - Mickael Remond) - -2004-09-15 Alexey Shchepin - - * src/mod_pubsub/mod_pubsub.erl: Bugfix - -2004-09-10 Alexey Shchepin - - * tools/ejabberdctl: Added call to "exec" (thanks to Sergei - Golovan) - - * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) - - * src/mod_vcard.erl: Support for searching of prefix substring and - limiting of result items (thanks to Sergei Golovan) - - * src/mod_offline.erl: Support for message expiration (JEP-0023) - (thanks to Sergei Golovan) - * src/jlib.hrl: Added NS_EXPIRE macros (thanks to Sergei Golovan) - - * src/ejabberd_logger_h.erl: Added reopen_log/0 (thanks to Sergei - Golovan) - - * src/ejabberd_ctl.erl: Added return codes, updated "reopen-log" - command, added "delete-expired-messages" and "status" commands - (thanks to Sergei Golovan) - - * doc/guide.tex: Updated (thanks to Sergei Golovan) - -2004-09-04 Alexey Shchepin - - * src/mod_roster.erl: Removed useless transactions - -2004-08-28 Alexey Shchepin - - * doc/guide.tex: Fix (thanks to Sander Devrieze) - -2004-08-27 Alexey Shchepin - - * src/xml_stream.erl: Few optimizations - -2004-08-24 Alexey Shchepin - - * src/mod_service_log.erl: Support for logging of user packets via - external service (e.g. bandersnatch) - * doc/guide.tex: Updated - -2004-08-23 Alexey Shchepin - - * src/mod_offline.erl: Added entire table locking on large message - queue - - * src/ejabberd_sm.erl: Added offline_subscription_hook - * src/mod_offline.erl: Use offline_subscription_hook - - * src/configure.erl: Updated (thanks to Sergei Golovan) - * src/Makefile.win32: Likewise - * src/tls/Makefile.win32: Likewise - * src/win32/: Likewise - - * src/mod_announce.erl: Added announce to all users (thanks to - Sergei Golovan) - * doc/guide.tex: Updated (thanks to Sergei Golovan) - -2004-08-14 Alexey Shchepin - - * src/msgs/nl.msg: Updated (thanks to Sander Devrieze) - - * src/web/ejabberd_http_poll.erl: Fixed sending of Set-Cookie - header - -2004-08-12 Alexey Shchepin - - * src/ejabberd_c2s.erl: Bugfix in resend_offline_messages/1 - - * src/mod_announce.erl: New module to manage announce messages - (thanks to Sergei Golovan) - - * src/ejabberd_local.erl: Moved processing of announce messages to - mod_announce (thanks to Sergei Golovan) - - * src/ejabberd_c2s.erl: Added several hooks - - * src/ejabberd_hooks.erl: Fixed run_fold (thanks to Sergei - Golovan) - - * src/ejabberd.cfg.example: Updated (thanks to Sergei Golovan) - - * doc/guide.tex: Updated (thanks to Sergei Golovan) - -2004-08-08 Alexey Shchepin - - * src/ejabberd_c2s.erl: Use resend_offline_messages_hook to fetch - offline messages - * src/mod_offline.erl: Likewise - - * src/mod_offline.erl: Added table locking in - remove_old_messages/1 - - * src/ejabberd_sm.erl: Use offline_message_hook to store offline - messages - * src/mod_offline.erl: Likewise - - * src/ejabberd_hooks.erl: Hooks support - * src/ejabberd_sup.erl: Added ejabberd_hooks - - * doc/guide.tex: Updated - - * src/ejabberd.cfg.example: Updated - - * src/ejabberd_c2s.erl: Changed TLS options (thanks to Sergei - Golovan) - -2004-08-05 Alexey Shchepin - - * src/aclocal.m4: Updated to check for openssl library (thanks to - AV) - * src/configure.ac: Likewise - * src/configure: Likewise - * src/Makefile.in: Likewise - * src/tls/Makefile.in: Likewise - -2004-08-03 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Added user's roster page - - * src/mod_irc/mod_irc_connection.erl: Bugfix - -2004-08-01 Alexey Shchepin - - * src/tls/tls.erl: Added recv_data/2 function - - * src/jlib.erl: Added NS_TLS macro - - * src/ejabberd_receiver.erl: Support for STARTTLS - * src/ejabberd_c2s.erl: Likewise - -2004-07-30 Alexey Shchepin - - * examples/extauth/check_pass_null.pl: A reference "null" - implementation of external authentication script (thanks to Leif - Johansson) - - * src/extauth.erl: Support for external authentication - (thanks to Leif Johansson) - * src/ejabberd_auth.erl: Likewise - - * src/mod_vcard_ldap.erl: A drop-in replacement for mod_vcard.erl - which uses ldap for JUD and vCard (thanks to Leif Johansson) - -2004-07-28 Alexey Shchepin - - * src/tls/tls_drv.c: Added freeing of SSL stuff - - * src/xml_stream.erl: Added start/2 function - * src/ejabberd_receiver.erl: Now using xml_stream:start/2 - -2004-07-27 Alexey Shchepin - - * src/ejabberd_c2s.erl: Support for TLS library (not completed) - - * src/tls/tls_drv.c: Updated to return binaries instead of lists - * src/tls/tls.erl: Likewise - -2004-07-26 Alexey Shchepin - - * src/tls/tls.erl: Updated - -2004-07-25 Alexey Shchepin - - * src/tls/: Library for TLS support (not completed) - - * src/ejabberd_auth.erl: Now uses two LDAP connections - - * src/ejabberd_c2s.erl: Return resource on get_presence request - (thanks to Mickael Remond) - - * src/mod_configure2.erl: Bugfix (thanks to Sergei Golovan) - - * src/msgs/ua.msg: New Ukrainian translation (thanks to usercard) - - * src/msgs/nl.msg: Updated (thanks to Sander Devrieze) - -2004-07-23 Alexey Shchepin - - * src/eldap/eldap.erl: Bugfix - -2004-07-13 Alexey Shchepin - - * (all): ejabberd-0.7 released - - * src/web/ejabberd_web_admin.erl: Better i18n support (thanks to - Sergei Golovan) - - * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) - - * src/msgs/fr.msg: Added missed entries (thanks to Sergei Golovan) - * src/msgs/nl.msg: Likewise - - * src/msgs/es.msg: New spanish translation (thanks to Badlop) - -2004-07-11 Alexey Shchepin - - * src/mod_last.erl: Supprot for storing status from latest - unavailable presence (thanks to Sergei Golovan) - * src/ejabberd_sm.erl: Likewise - * src/ejabberd_c2s.erl: Likewise - - * src/mod_vcard.erl: Minor update (thanks to Sergei Golovan) - - * src/mod_register.erl: Added "access" option (thanks to Sergei - Golovan) - * src/mod_irc/mod_irc.erl: Likewise - * src/ejabberd.cfg.example: Updated - * src/win32/ejabberd.cfg: Likewise - - * src/mod_privacy.erl: Fixed module stopping (thanks to Sergei - Golovan) - * src/mod_private.erl: Likewise - - * src/gen_mod.erl: Added function get_module_opt/3 (thanks to - Sergei Golovan) - - * src/ejabberd_local.erl: Minor fix (thanks to Sergei Golovan) - - * doc/guide.tex: Updated (thanks to Sergei Golovan) - -2004-07-10 Alexey Shchepin - - * src/mod_roster.erl: Removed superfluous include_lib line - - * doc/guide.tex: Updated - - * src/msgs/fr.msg: Updated (thanks to Sergei Golovan) - - * src/mod_irc/mod_irc.erl: Added handler for disco items requests - (thanks to Sergei Golovan) - - * src/mod_vcard.erl: Added option for JUD disabling (thanks to - Sergei Golovan) - - * src/mod_configure2.erl: Fixed module stopping (thanks to Sergei - Golovan) - * src/mod_last.erl: Likewise - * src/mod_privacy.erl: Likewise - * src/mod_register.erl: Likewise - * src/mod_roster.erl: Likewise - * src/mod_vcard.erl: Likewise - - * src/jd2ejd.erl: Added emergency catches (thanks to Sergei - Golovan) - * src/mod_last.erl: Likewise - - * src/ejabberd_sm.erl: Removed needless call to - mod_disco:unregister_feature (thanks to Sergei Golovan) - - * src/ejabberd_local.erl: Better support for mod_disco (thanks to - Sergei Golovan) - * src/mod_disco.erl: Likewise - - * src/translate.erl: Suport for "default language" option (thanks - to Sergei Golovan) - * src/ejabberd_config.erl: Likewise - * src/ejabberd_c2s.erl: Likewise - * src/ejabberd.hrl: Added 'MYLANG' macros - - * src/ejabberd.cfg.example: Updated (thanks to Sergei Golovan) - - * doc/guide.tex: Updated (thanks to Sergei Golovan) - -2004-07-09 Alexey Shchepin - - * src/win32/ejabberd.cfg: Updated (thanks to Sergei Golovan) - -2004-07-07 Alexey Shchepin - - * src/Makefile.win32: Updated (thanks to Sergei Golovan) - - * src/Makefile.in: Added installation of ejabberd.cfg (thanks to - Sergei Golovan) - - * src/web/ejabberd_http.erl: Fixed support for HTTP/1.0 clients - -2004-07-06 Alexey Shchepin - - * doc/guide.tex: Updated (thanks to Sergei Golovan) - - * src/ejabberd_auth.erl: Minor fix - - * src/ejabberd_c2s.erl: Fixed sending of presence to own resources - -2004-06-18 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Added configuration of listened - ports - * src/ejabberd_listener.erl: Added API for configuration of port - listeners - - * src/web/ejabberd_web_admin.erl: Fixed "Stop" button on node - management page - -2004-05-22 Alexey Shchepin - - * src/msgs/nl.msg: Dutch translation (thanks to Sander Devrieze) - - * src/web/ejabberd_http.erl: Added options for enabling HTTP - polling and admin interface - * src/web/ejabberd_web.erl: Likewise - * src/ejabberd.cfg.example: Updated - - * src/web/ejabberd_web_admin.erl: Updated - - * doc/guide.tex: Updated - -2004-05-17 Alexey Shchepin - - * src/mod_muc/mod_muc.erl: Added access rules for using serveice - and creating rooms (thanks to Sergei Golovan) - - * src/win32/ejabberd.nsi: Updated (thanks to Sergei Golovan) - * src/win32/CheckUserH.ini: Likewise - - * src/translate.erl: Search translations in priv_dir instead of - lib_dir (thanks to Sergei Golovan) - - * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) - - * src/ejabberd.cfg.example: Updated (thanks to Sergei Golovan) - - * src/**/Makefile.in: Updated (thanks to Sergei Golovan) - * src/**/Makefile.win32: Likewise - -2004-05-16 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Updated - -2004-05-14 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Updated - -2004-05-09 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Updated - - * src/ejabberd_listener.erl: Added API for adding/removing - listeners - -2004-05-08 Alexey Shchepin - - * doc/guide.tex: Updated - - * src/ejabberd_listener.erl: Now possible to specify interface on - which one socket will be listened, also added another way to - specify SSL options - * src/ejabberd.cfg.example: Updated - -2004-05-07 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Updated (thanks to Andrey - Zamaraev) - -2004-05-05 Alexey Shchepin - - * src/ejabberd_ctl.erl: Added command for listing all registered - users - - * src/ejabberd_ctl.erl: Bugfix, support for text-load and restore - (thanks to Leif Johansson) - -2004-05-04 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Updated - -2004-05-01 Alexey Shchepin - - * src/web/ejabberd_http.erl: 'Accept-Language' header support - * src/web/ejabberd_web_admin.erl: Likewise - * src/msgs/ru.msg: Updated - - * src/mod_muc/mod_muc_room.erl: Send status code "201" on room - creation - -2004-04-27 Alexey Shchepin - - * src/translate.erl: Search translations directory in priv_dir - instead of lib_dir (thanks to Sergei Golovan) - - * src/**/Makefile.in: Updated (thanks to Sergei Golovan) - - * src/win32/: Win32 installer stuff (thanks to Sergei Golovan) - - * src/**/Makefile.win32: Updated (thanks to Sergei Golovan) - * src/configure.bat: Likewise - * src/configure.erl: Likewise - - * doc/guide.tex: Updated (thanks to Sergei Golovan) - -2004-04-26 Alexey Shchepin - - * src/web/ejabberd_web_admin.erl: Better design for administration - interface (not completed) (thanks to Andrey Zamaraev) - * src/web/ejabberd_http.erl: Updated - * src/web/ejabberd_web.erl: Likewise - -2004-04-17 Alexey Shchepin - - * src/web/ejabberd_http.erl: Increased receive buffer - - * src/mod_irc/mod_irc_connection.erl: Support for "/quote" command - -2004-04-15 Alexey Shchepin - - * src/ejabberd.erl: Added searching of files in code:priv_lib - (thanks to Sergei Golovan) - * src/translate.erl: Likewise - - * src/ejabberd_app.erl: Added "log_path" configuration parameter - (thanks to Sergei Golovan) - - * src/**/Makefile.win32: Updated (thanks to Sergei Golovan) - - * src/**/*.c: Updated (thanks to Sergei Golovan) - - * src/configure.erl: Added writing of version to Makefile.inc - (thanks to Sergei Golovan) - - * doc/guide.tex: Updated link to expat (thanks to Sergei Golovan) - -2004-04-10 Alexey Shchepin - - * src/idna.erl: Support for IDNA (RFC3490) - * src/ejabberd_s2s_out.erl: Likewise - -2004-04-03 Alexey Shchepin - - * src/xml.erl: element_to_string/1 and crypt/1 now returns deep - list - * src/mod_muc/mod_muc_room.erl (add_message_to_history): Replaced - string:len with lists:flatlength - -2004-03-21 Alexey Shchepin - - * (all): Updated win32 stuff (thanks to Sergei Golovan) - - * src/web/ejabberd_web.erl: Added interface for access rules - configuration - -2004-03-20 Alexey Shchepin - - * doc/guide.tex: Updated - - * src/web/ejabberd_web.erl: Updated - - * src/web/ejabberd_http.erl: Bugfix - -2004-03-16 Alexey Shchepin - - * src/mod_roster.erl: Bugfix - - * src/ejabberd_s2s.erl: More verbose error handling - -2004-03-15 Alexey Shchepin - - * src/web/ejabberd_web.erl: Minor update - -2004-03-14 Alexey Shchepin - - * src/web/ejabberd_web.erl: Added interface for users listsing and - statistics - -2004-03-13 Alexey Shchepin - - * src/web/ejabberd_web.erl: New interface for ACLs editing - - * src/web/ejabberd_http_poll.erl: Fixed "Content-Type" header, - "Set-Cookie" is included only in first response in session, added - missed behaviour definition - - * src/web/ejabberd_http.erl: "Content-Type" header now can be - changed - -2004-03-12 Alexey Shchepin - - * src/web/ejabberd_web.erl: Experiments with web-interface - - * src/configure.ac: Updated - * src/Makefile.in: Likewise - -2004-03-10 Alexey Shchepin - - * src/web/ejabberd_http.erl: Removed debugging output - - * src/ejabberd_c2s.erl: Fixed processing of get_presence request - (thanks to Mickael Remond) - -2004-03-08 Alexey Shchepin - - * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) - - * src/mod_muc/mod_muc_room.erl: Now private conferences are - visible to admins and owners of this conference (thanks to Sergei - Golovan) - - * src/mod_muc/mod_muc.erl: More xml:lang support (thanks to Sergei - Golovan) - - * src/mod_vcard.erl: Better processing of EMAIL tag (thanks to - Sergei Golovan) - - * src/ejabberd_s2s_out.erl: Added "catch" to "open_socket" (thanks - to Sergei Golovan) - -2004-03-07 Alexey Shchepin - - * src/web/ejabberd_http_poll.erl: Completed - -2004-03-06 Alexey Shchepin - - * src/web/: Support for HTTP Polling (JEP-0025) (almost complete) - -2004-03-04 Alexey Shchepin - - * src/web/: Updated - -2004-03-03 Alexey Shchepin - - * src/web/: Minor update - -2004-03-02 Alexey Shchepin - - * src/web/: Small HTTP server and admin web-interface to ejabberd - (not completed yet) - * src/ejabberd_sup.erl: Added HTTP processes supervisor - - * src/ejabberd_c2s.erl: Added API to ask presence (thanks to - Mickael Remond) - - * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) - - * src/mod_muc/mod_muc_room.erl: Updated date parser (thanks to - Sergei Golovan) - - * src/mod_muc/mod_muc.erl: Added error descriptions (thanks to - Sergei Golovan) - * src/mod_muc/mod_muc_room.erl: Likewise - - * src/mod_vcard.erl: Fixed vCard tag (thanks to Sergei Golovan) - * src/mod_irc/mod_irc.erl: Likewise - * src/mod_pubsub/mod_pubsub.erl: Likewise - - * src/jlib.hrl: Added macros for errors with (thanks to - Sergei Golovan) - -2004-02-26 Alexey Shchepin - - * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) - - * src/mod_muc/mod_muc_room.erl: Updated error codes, removed - trailing "-" in history. updated subject sending, added - in configuration form (thanks to Sergei Golovan) - - * src/mod_irc/mod_irc.erl: Added vCard, ejabberd:configure - replaced with jabber:iq:register (thanks to Sergei Golovan) - - * src/mod_configure.erl: Updated "xml:lang" usage, updated some - messages (thanks to Sergei Golovan) - * src/mod_configure2.erl: Likewise - * src/mod_disco.erl: Likewise - * src/mod_register.erl: Likewise - * src/mod_vcard.erl: Likewise - * src/mod_irc/mod_irc.erl: Likewise - * src/mod_muc/mod_muc.erl: Likewise - * src/mod_muc/mod_muc_room.erl: Likewise - * src/mod_pubsub/mod_pubsub.erl: Likewise - - * src/jlib.hrl: Added "lang" field in "iq" record (thanks to - Sergei Golovan) - * src/jlib.erl: Likewise - - * src/ejabberd_c2s.erl: Updated to latest JEP-0078 (thanks to - Sergei Golovan) - -2004-02-18 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_sm.erl: Bugfix - -2004-02-15 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/mod_muc_room.erl: Support for history management - (thanks to Sergei Golovan) - - * src/mod_stats.erl: Updated error codes (thanks to Sergei - Golovan) - * src/mod_irc/mod_irc.erl: Likewise - - * src/mod_configure.erl: "jabber:iq:data" replaced with - "ejabberd:config" namespace (thanks to Sergei Golovan) - * src/mod_disco.erl: Likewise - -2004-02-12 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: Added <session/> to stream features - -2004-02-10 Alexey Shchepin <alexey@sevcom.net> - - * src/msgs/ru.msg: Updated (thanks to Sergei Golovan) - - * src/mod_irc/mod_irc.erl: Now uses "ejabberd:config" namespace - (thanks to Sergei Golovan) - - * src/mod_disco.erl: Fixed disco category and type (thanks to - Sergei Golovan) - * src/mod_pubsub/mod_pubsub.erl: Likewise - - * src/jlib.hrl: Added "ejabberd:config" namespace (thanks to - Sergei Golovan) - -2004-01-27 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_ctl.erl: Added command for log reopening - -2004-01-18 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_ctl.erl: Added commands for backup processing - - * src/ejabberd_c2s.erl: Added processing of xml:lang according to - latest XMPP-IM draft - - * src/xml.erl: Added replace_tag_attr/3 function - - * src/mod_roster.erl: Added auto-reply on incoming subscription - request according to latest XMPP-IM draft - - * src/mod_offline.erl: Added pop_offline_messages/1 function - * src/ejabberd_c2s.erl: Updated sending of offline messages - -2004-01-17 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/mod_muc_room.erl: Bugfix, updated error codes - (thanks to Sergei Golovan) - - * src/jlib.hrl: Updated error codes (thanks to Sergei Golovan) - -2004-01-11 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: Fixed bind namespace - - * src/ejabberd_ctl.erl: New module for ejabberd administration - * tools/ejabberdctl: Shell script for ejabberd administration - - * src/mod_vcard.erl: Copyright update - - * src/ejabberd_service.erl: Now possible to specify access rules - for service - * src/ejabberd.cfg.example: Updated - -2004-01-06 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_router.erl: Added monitoring of processess that - serve domains - - * src/ejabberd_app.erl: Bugfix - -2004-01-03 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_router.erl (do_route/3): Slightly changed behaviour - -2004-01-01 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_sm.erl (do_route/3): Minor fix - - * src/ejabberd_sm.erl (route_message/3): Minor changes - -2003-12-28 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_app.erl: Now possible to specify path to log file - via "EJABBERD_LOG_PATH" environment variable - - * src/translate.erl: Now possible to specify path to "msgs" - directory via "EJABBERD_MSGS_PATH" environment variable - - * src/ejabberd.erl: Added get_so_path/0 function - * src/ejabberd_app.erl: Use ejabberd:get_so_path/0 to load .so - * src/mod_irc/iconv.erl: Likewise - * src/stringprep/stringprep.erl: Likewise - -2003-12-24 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: Presence probe now sended from full JID - - * src/mod_roster.erl: Bugfix - -2003-12-23 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: Bugfix - -2003-12-21 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_roster.erl: Added workaround for legacy gateways - (passing of "subscribed" presence) - - * src/ejabberd_sm.erl: Minor fix in subscription processing - -2003-12-17 Alexey Shchepin <alexey@sevcom.net> - - * src/jlib.hrl: Added declaration of "iq" record - * (all): Updated to use "iq" record - -2003-12-14 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_local.erl: Replaced register_local_route to - register_route - * src/ejabberd_service.erl: Likewise - * src/mod_echo.erl: Likewise - * src/mod_vcard.erl: Likewise - - * src/ejabberd_router.erl: Partially rewrited - * src/ejabberd_sm.erl: Likewise - -2003-12-13 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_s2s.erl: Partially rewrited - - * src/mod_roster.erl: Removed debugging code - -2003-12-12 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_s2s_out.erl: Bugfix - -2003-12-11 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_roster.erl: Updated subscription handling to latest - XMPP-IM draft - -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> - - * src/ejabberd_c2s.erl: Bugfix in processing of connection - replacement - -2003-11-28 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: Added workaround for some Java clients - -2003-11-27 Alexey Shchepin <alexey@sevcom.net> - - * examples/mtr/ejabberd.cfg: Updated (thanks to Marshall T. Rose) - - * src/ejabberd_auth.erl: LDAP attribute that holds user ID now - configurable - * src/ejabberd.cfg.example: Updated - -2003-11-26 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: Fixed processing of presence probe from - client - -2003-11-23 Alexey Shchepin <alexey@sevcom.net> - - * src/cyrsasl_digest.erl: Bugfix (thanks to Sergei Golovan) - - * src/ejabberd.cfg.example: Updated - - * src/ejabberd_auth.erl: Support for LDAP authentication - * src/cyrsasl_digest.erl: Likewise - * src/mod_register.erl: Likewise - * src/ejabberd_c2s.erl: Likewise - - * src/eldap/: Imported "eldap" package - - * src/ejabberd_sm.erl: Bugfix - -2003-11-16 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/mod_muc_room.erl: Bugfixes - - * (all): Version 0.5 released - -2003-11-13 Alexey Shchepin <alexey@sevcom.net> - - * examples/mtr/ejabberd: Updated (thanks to Marshall T. Rose) - - * src/Makefile.in: Added installation of msgs/ directory - -2003-11-11 Alexey Shchepin <alexey@sevcom.net> - - * doc/dev.tex: Developers documentation (not completed) - - * src/ejabberd_c2s.erl: Better handling of malformed JIDs - - * src/mod_register.erl (try_register/2): Now returns "jid - malformed" error if user name is invalid - -2003-11-10 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd.cfg.example: Updated - - * src/ejabberd_s2s_in.erl: Added support for shapers - - * src/ejabberd_c2s.erl: Moved receiver functions to - ejabberd_receiver module - * src/ejabberd_s2s_in.erl: Likewise - * src/ejabberd_receiver.erl: Likewise - - * src/mod_muc/mod_muc_room.erl: Bugfix - - * src/ejabberd_sm.erl (route_message/3): Bugfix - -2003-11-09 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_sm.erl: Bugfix for previous resource handling - change - - * src/mod_configure.erl: Password changing now implemented - -2003-11-07 Alexey Shchepin <alexey@sevcom.net> - - * src/cyrsasl.erl: Updated SASL authentication - * src/ejabberd_c2s.erl: Likewise - - * src/ejabberd_sm.erl: Better resource handling - - * src/jlib.hrl: Added NS_BIND macros - -2003-11-06 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_configure2.erl: Added reporting of outgoing S2S - connections number - - * src/mod_disco.erl (get_outgoing_s2s): Minor fix - -2003-11-02 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_configure2.erl: Yet another configure interface (not - completed yet) - -2003-11-01 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_last.erl: Added remove_user/1 function - - * src/mod_configure.erl: Removing of user's stuff moved to - ejabberd_auth - * src/ejabberd_auth.erl: Likewise - -2003-10-31 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_irc/mod_irc_connection.erl: Updated to work more - correctly with latest jlib - -2003-10-30 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: More strong check for authenticated JID - - * src/mod_roster.erl: Bugfix - -2003-10-29 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_listener.erl: Fixed starting of SSL connection - - * src/ejabberd_s2s_in.erl: Partially rewriten - - * src/ejabberd_router.erl: More verbose error report - * src/ejabberd_local.erl: Likewise - * src/ejabberd_sm.erl: Likewise - - * src/ejabberd_s2s_out.erl: Updated to be compatible with R9C - - * src/ejabberd_c2s.erl: Minor fix - -2003-10-28 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_listener.erl: Added handling of accept errors, - added timeout value to ssl:accept - - * src/mod_vcard.erl: Added checks for all empty input fields - - * src/mod_offline.erl: More strong checks for stored packets - - * src/ejabberd_sm.erl: Bugfix - -2003-10-27 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_auth.erl: Minor change in check_password/4 - - * src/mod_roster.erl: Workaround for PSI bug with roster - - * src/ejabberd_logger_h.erl: Added support for log rotation - -2003-10-24 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_offline.erl: Added function remove_old_messages/1 - - * src/mod_last.erl: jabber:iq:last support (JEP-0012) - * src/ejabberd_sm.erl: Likewise - - * src/jlib.hrl: Added NS_LAST macros - -2003-10-23 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_logger_h.erl: New error_logger handler - * src/ejabberd_app.erl: Now uses ejabberd_logger_h.erl - -2003-10-21 Alexey Shchepin <alexey@sevcom.net> - - * src/Makefile.in: Added install rule - - * src/jlib.erl: Added checks for JID parts length - -2003-10-20 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_vcard.erl: Added checks for stringprep results - - * src/expat_erl.c: Workaround for EI encode_string bug - - * src/xml_stream.erl: Slightly changed protocol to expat driver - * src/expat_erl.c: Likewise - - * src/mod_configure.erl: Minor fix - -2003-10-19 Alexey Shchepin <alexey@sevcom.net> - - * doc/guide.tex: Fixed typo - - * src/ejabberd_local.erl: Added support for announce/online - messages - - * src/ejabberd.cfg.example: Updated - - * src/mod_register.erl: Added support for sending registration - notifications - -2003-10-18 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_service.erl: Added supports for multiple hosts per - service - - * src/Makefile.in: Minor fix - -2003-10-17 Alexey Shchepin <alexey@sevcom.net> - - * src/configure.ac: Build system now done using autoconf (thanks - to Balabanov Dmitry) - * src/aclocal.m4: Likewise - * src/**/Makefile.in: Likewise - - * src/mod_roster.erl (process_item_set_t): Slightly improved - performance - - * src/jd2ejd.erl: Added missed closing of XML stream process, - removed timeout value from import_file/1 - - * src/ejabberd_auth.erl: Added checks for invalid user name - -2003-10-16 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_configure.erl: Fixed some error codes - - * src/cyrsasl_digest.erl: Bugfix (thanks to Justin Karneges) - -2003-10-14 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_local.erl: Bugfix - - * src/mod_register.erl: Added support for sending of "welcome" - message - * src/ejabberd.cfg.example: Updated - - * src/ejabberd_s2s_out.erl: Replaced "_jabber-server" with - "_xmpp-server" - -2003-10-12 Alexey Shchepin <alexey@sevcom.net> - - * doc/guide.tex: Updated - - * src/ejabberd_s2s_out.erl: Added support for IPv6 and - "_jabber-server.tcp" lookups - - * src/jlib.erl (string_to_jid1): Bugfix - - * src/ejabberd_config.erl: Now possible to specify path to config - file in command line - -2003-10-11 Alexey Shchepin <alexey@sevcom.net> - - * doc/guide.tex: Updated - - * src/ejabberd.cfg: Added "register" rule, added some comments, - this file renamed to ejabberd.cfg.example - - * src/mod_register.erl (try_register): Fixed error reply, added - check for "register" access rule - -2003-10-10 Alexey Shchepin <alexey@sevcom.net> - - * src/stringprep/Makefile.win32: Added Makefile for Win32 (thanks - to Sergei Golovan) - - * src/stringprep/stringprep_drv.c: Removed needless iconv.h - include - - * src/ejabberd_c2s.erl: Added filtering of presence packets with - privacy rules - - * src/mod_roster.erl (get_jid_info): Bugfix - - * src/ejabberd_app.erl: Removed periodical dumping of opened ports - -2003-10-09 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: Added authentication logging - - * src/ejabberd_listener.erl: Added logging of accepted connections - - * src/stringprep/stringprep_drv.c: Cleanup - - * src/jd2ejd.erl: Added support for iq:private importing - - * src/mod_configure.erl: Fixed user removal - - * src/mod_private.erl: Added remove_user/1 - - * doc/guide.tex: Updated - - * src/mod_disco.erl: Added "extra_domains" option - -2003-10-08 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: Added support for "jid-malformed" error - - * src/stringprep/stringprep_drv.c: Bugfix - -2003-10-07 Alexey Shchepin <alexey@sevcom.net> - - * (all): Changed JID storage format, added support for stringprep - - * src/stringprep/: Added support for Unicode normalization form KC - -2003-10-05 Alexey Shchepin <alexey@sevcom.net> - - * src/stringprep/: Added support for case convertion to multiple - characters - - * src/cyrsasl_digest.erl: Temporary removed "auth-int" QOP - -2003-09-28 Alexey Shchepin <alexey@sevcom.net> - - * src/stringprep/stringprep_drv.c: Added support for nameprep, - nodeprep and resourceprep - * src/stringprep/stringprep.erl: Likewise - - * src/ejabberd_sup.erl: Added loading of stringprep - - * src/ejabberd_sm.erl: Cleanup - -2003-09-26 Alexey Shchepin <alexey@sevcom.net> - - * src/stringprep/: Support for stringprep (not completed yet) - -2003-09-24 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/mod_muc.erl: Replaced io:format calls to ?DEBUG ones - -2003-09-19 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/mod_muc_room.erl: Debug output switched off - - * src/mod_disco.erl: Server identity changed to "service/im" - - * src/mod_register.erl: Fixed jabber:iq:register handler - registration, fixed registration removal processing - -2003-09-16 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_disco.erl: Now only admin can discovery some nodes, - fixed "node" attribute in replies - -2003-09-10 Alexey Shchepin <alexey@sevcom.net> - - * examples/mtr/ejabberd.cfg: Updated (thanks to Marshall T. Rose) - * examples/mtr/ejabberd: Likewise - -2003-09-06 Alexey Shchepin <alexey@sevcom.net> - - * examples/mtr/ejabberd.cfg: Updated (thanks to Marshall T. Rose) - -2003-09-04 Alexey Shchepin <alexey@sevcom.net> - - * examples/mtr/*: Example config and scripts for NetBSD (thanks to - Marshall T. Rose) - -2003-09-03 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_s2s_in.erl: Fixed "id" attribute processing - * src/ejabberd_s2s_out.erl: Likewise - - * src/ejabberd_c2s.erl: Added sending of empty <stream:features/> - element after opening of authenticated stream - -2003-09-02 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_s2s_in.erl: Temporary hack for "id" attribute - processing - * src/ejabberd_s2s_out.erl: Likewise - -2003-08-30 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_listener.erl: Fixed SSL options - -2003-08-18 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: Support for filtering of incoming messages - and IQs, presence filtering will be after some xmpp-im - clarifications - -2003-08-15 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/mod_muc.erl: Fixed handling of room names with - uppercase letters - - * src/mod_muc/mod_muc_room.erl: Added support for - password-protected rooms - -2003-08-12 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_irc/mod_irc_connection.erl: Added handling for - jabber:iq:version and jabber:iq:time requests, participant address - now added to presence status - -2003-08-03 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_privacy.erl: Privacy rules support (not completed yet) - * src/ejabberd_c2s.erl: Likewise - * src/mod_roster.erl: Likewise - -2003-07-27 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_pubsub/mod_pubsub.erl (create_new_node): Bugfix - -2003-07-21 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_vcard.erl: Bugfix - - * src/mod_roster.erl: Bugfix - - * src/jlib.hrl: Added iq:privacy namespace - - * src/mod_irc/mod_irc_connection.erl: Added support for NOTICE and - CODEPAGE commands, better support for QUIT and PART commands - (thanks to Oleg V. Motienko) - -2003-07-20 Alexey Shchepin <alexey@sevcom.net> - - * (all): Reorganized supervision tree - -2003-07-19 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_register.erl: Bugfix - -2003-07-14 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_s2s_out.erl: Close connection after key - verification - - * src/ejabberd_c2s.erl: start replaced with start_link - * src/ejabberd_s2s_in.erl: Likewise - * src/ejabberd_s2s_out.erl: Likewise - * src/ejabberd_service.erl: Likewise - - * src/ejabberd_listener.erl: Now uses proc_lib to spawn listeners, - removed 3rd parameter in listener configuration (assumed to equal - start_link) - - * src/ejabberd.rel: Updated - - * doc/guide.tex: Small changes - - * doc/Makefile: Added implicit charset specification to hevea - -2003-07-12 Alexey Shchepin <alexey@sevcom.net> - - * doc/guide.tex: Updated (thanks to Sergei Golovan) - - * src/expat_erl.c: Added #ifdef for WIN32 (thanks to Sergei - Golovan) - * src/mod_irc/iconv_erl.c: Likewise - - * src/configure.erl: Defines ERLANG_DIR variable (thanks to Sergei - Golovan) - * **/Makefile: Use ERLANG_DIR (thanks to Sergei Golovan) - - * **/Makefile.win32: Makefiles for windows build (thanks to Sergei - Golovan) - * src/configure.bat: Configuration script for windows (thanks to - Sergei Golovan) - -2003-07-09 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_pubsub/mod_pubsub.erl: Added suport for meta-node - "pubsub/nodes" - -2003-07-08 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_pubsub/mod_pubsub.erl: Most of functions now works - -2003-07-07 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_pubsub/mod_pubsub.erl: Pub/sub implementation (not - completed yet) - -2003-07-05 Alexey Shchepin <alexey@sevcom.net> - - * src/jlib.hrl: Added pub/sub namespaces - -2003-07-03 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_irc/iconv_erl.c (iconv_erl_control): Bugfix - -2003-06-30 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/mod_muc_room.erl: Fixed room destroying - * src/mod_muc/mod_muc.erl: Likewise - -2003-06-29 Alexey Shchepin <alexey@sevcom.net> - - * src/jlib.hrl: Error stanzas updated to confirm latest xmpp-core - -2003-06-20 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: Returned stream restarting - -2003-06-10 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: Removed stream restarting - -2003-06-07 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: SASL support updated to xmpp-core-13 - -2003-06-06 Alexey Shchepin <alexey@sevcom.net> - - * src/cyrsasl*.erl: Support for authzid - -2003-06-03 Alexey Shchepin <alexey@sevcom.net> - - * src/msgs/fr.msg: New french translation (thanks to Vincent Ricard) - -2003-05-31 Alexey Shchepin <alexey@sevcom.net> - - * src/jlib.hrl: Updated SASL namespace - -2003-05-29 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_service.erl: Proper handling of bad XML - - * src/mod_muc/mod_muc_room.erl: Append number of participants in - disco replies if requester allowed to see participant list - - * src/mod_muc/mod_muc.erl (iq_disco_items): Pass requester JID to - room process - - * src/mod_irc/mod_irc_connection.erl: Exit on receiving of - presence or message error - - * src/mod_irc/mod_irc_connection.erl (handle_info): Return - "feature not implemented" on iq request with unknown namespace - -2003-05-18 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/mod_muc.erl: Now body of message from admin to MUC - service is broadcasted to all conferences - * src/mod_muc/mod_muc_room.erl: Likewise - -2003-05-15 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_s2s.erl: Added error catching for do_route/3 - * src/ejabberd_local.erl: Likewise for do_route/4 - - * src/msgs/ru.msg: Updated - - * src/mod_muc/mod_muc_room.erl: New option to allow to view list - of participants for non-ones via disco#items - - * src/mod_muc/mod_muc_room.erl: Store room subject with - configuration options - -2003-05-14 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/mod_muc_room.erl: Remove user from room on receiving - of message or presence error from him - -2003-05-12 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_s2s_out.erl: Fixed error replies, added timeouts - * src/ejabberd_s2s_in.erl: Likewise - -2003-05-09 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_local.erl: Updated missed errors to new style - * src/mod_register.erl: Likewise - * src/mod_version.erl: Likewise - * src/mod_time.erl: Likewise - * src/mod_stats.erl: Likewise - * src/mod_register.erl: Likewise - * src/mod_private.erl: Likewise - * src/mod_configure.erl: Likewise - * src/ejabberd_sm.erl: Likewise - * src/ejabberd_service.erl: Likewise - * src/ejabberd_c2s.erl: Likewise - * src/ejabberd_s2s_out.erl: Likewise - * src/mod_vcard.erl: Likewise - * src/mod_roster.erl: Likewise - - * src/mod_muc/mod_muc.erl: Added vcard to mod_muc module - - * src/ejabberd_app.erl: Dump list of opened ports every hour - - * src/ejabberd.hrl: Added INFO_MSG macros, ERROR_LOG_PATH renamed - to LOG_PATH - -2003-05-08 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/mod_muc.erl: Denied usage of empty nick - -2003-05-07 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/mod_muc.erl: Return bad-request if no x:data form - submited with nick registration - - * src/mod_muc/mod_muc_room.erl: Don't check permissions on disco - info query processing - -2003-04-29 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: Workaround to make SSL work properly - -2003-04-28 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_irc/mod_irc_connection.erl: Fixed URL to ejabberd - -2003-04-17 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/mod_muc.erl: Support for nick registration - -2003-04-15 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: Some fixes in work with socket - -2003-04-13 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/mod_muc_room.erl: Support for members-only - conferences, invitations. Bugfix in affiliation change processing - - * src/jlib.hrl: Added jabber:x:conference namespace definition - -2003-04-07 Alexey Shchepin <alexey@sevcom.net> - - * src/jlib.hrl: Added jaber:iq:auth:error namespace and - appropriate errors - * src/ejabberd_c2s.erl: Use auth:error in appropriate places - - * src/jlib.hrl: Changed stream error and stanza error namespace - names due to last XMPP Core changes - -2003-03-28 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/mod_muc_room.erl: Added support for grant/revoke - administrative/owner priveledges, fixed work with affiliations - -2003-03-27 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd.cfg: Updated - - * src/mod_muc/mod_muc_room.erl: Support for service admin, - kick/ban reasons, more options - - * src/msgs/ru.msg: Added translations for MUC messages - - * src/ejabberd_s2s_in.erl: Bugfix - - * src/mod_muc/: Small fixes in discovering - -2003-03-26 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/: Support for discovering service and more - configuration options - -2003-03-25 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/: Support for more configuration options and - persistent rooms - -2003-03-23 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_muc/: MUC support (not completed yet) - -2003-03-15 Alexey Shchepin <alexey@sevcom.net> - - * src/xml_stream.erl: Removed "link" which cause not improper - closing of xml connections - -2003-03-14 Alexey Shchepin <alexey@sevcom.net> - - * src/jlib.hrl: Added "invalid-namespace" error - * src/ejabberd_c2s.erl: Likewise - -2003-03-12 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_s2s_out.erl: Fixed ports leak - * src/ejabberd_listener.erl: Likewise - - * src/ejabberd_c2s.erl: Fixes for SASL support - - * src/cyrsasl.erl: Fixes - - * src/cyrsasl_digest.erl: DIGEST-MD5 SASL mechanism support - -2003-03-09 Alexey Shchepin <alexey@sevcom.net> - - * src/cyrsasl*.erl: SASL support (currently support only PLAIN - mechanism) - * src/ejabberd_c2s.erl: Likewise - - (all): Support for new-style error elements (except old errors - "Not Acceptable", "Not Found", "Invalid Namespace" and "Server - Connect Failed", so ejabberd may work unstable) - -2003-03-02 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: More correct stream closing - -2003-02-27 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_irc/mod_irc_connection.erl: Support for topic changes - -2003-02-24 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_irc/mod_irc_connection.erl: /kick support - -2003-02-23 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_irc/: Added configuration interface - - * src/mod_configure.erl: Use jabber:iq:data instead of - jabber:x:data - * src/mod_disco.erl: Likewise - -2003-02-22 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_configure.erl: Backup management support - * src/mod_disco.erl: Likewise - -2003-02-21 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_offline.erl: Now possible to unload this module - * src/ejabberd_sm.erl: Added checks to work correctly when - mod_offline not loaded - * src/ejabberd_c2s.erl: Likewise - - * src/mod_register.erl: Added support for users removal - - * src/ejabberd_auth.erl: Added function to remove user only if - specified password correct - - * src/mod_irc/mod_irc_connection.erl: Fixed bug with changing - availability status, added processing of "QUIT" message - -2003-02-20 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_roster.erl: Fixed bug with handling of roster set - stanzas which contains CDATA - - * src/mod_irc/mod_irc_connection.erl (handle_info/3): Fixed - parsing of string that have "\n" line separators (not "\r\n") - -2003-02-18 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_irc/: Added support for private chats, nicks changes and - error handling - -2003-02-17 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_irc/: Still not completed... - -2003-02-16 Alexey Shchepin <alexey@sevcom.net> - - * src/mod_irc/: New IRC transport (not completed yet) - -2003-02-14 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_service.erl: Answer "Bad Request" on unknown tags - -2003-02-13 Alexey Shchepin <alexey@sevcom.net> - - * src/ejabberd_c2s.erl: Bugfix: close socket when stream is closed - - * src/mod_offline.erl: Now all offline packets processed in - separate queue to avoid delaying of other packets transmission. - Also all packets in queue processed in one transaction. - -2003-02-11 Alexey Shchepin <alexey@sevcom.net> - - * (all): Version 0.1-alpha released diff --git a/src/Makefile.in b/src/Makefile.in index a64f81337..a311081f1 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -277,3 +277,12 @@ Makefile: Makefile.in dialyzer: $(BEAMS) @dialyzer -c . + +LASTSVNREVCHANGELOG = 2075 +changelog: + svn up -r $(LASTSVNREVCHANGELOG) ../ChangeLog + mv ../ChangeLog ../ChangeLog.old + svn2cl -r BASE:$(LASTSVNREVCHANGELOG) -o ../ChangeLog --group-by-day \ + --separate-daylogs --break-before-msg --reparagraph .. + cat ../ChangeLog.old >> ../ChangeLog + rm ../ChangeLog.old From ee8ed2828a4ec3e99622be4fe43884d5302bdced Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Fri, 15 May 2009 22:55:29 +0000 Subject: [PATCH 308/582] The --node argument overwrites the value of ejabberdctl.cfg SVN Revision: 2082 --- src/ejabberdctl.template | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template index 5054d89b3..dcb8f2ac9 100644 --- a/src/ejabberdctl.template +++ b/src/ejabberdctl.template @@ -21,7 +21,7 @@ while [ $# -ne 0 ] ; do shift case $PARAM in --) break ;; - --node) ERLANG_NODE=$1; shift ;; + --node) ERLANG_NODE_ARG=$1; shift ;; --config-dir) ETCDIR=$1 ; shift ;; --config) EJABBERD_CONFIG_PATH=$1 ; shift ;; --ctl-config) EJABBERDCTL_CONFIG_PATH=$1 ; shift ;; @@ -51,6 +51,9 @@ fi if [ "$EJABBERD_DOC_PATH" = "" ] ; then EJABBERD_DOC_PATH=@DOCDIR@ fi +if [ "$ERLANG_NODE_ARG" != "" ] ; then + ERLANG_NODE=$ERLANG_NODE_ARG +fi # check the proper system user is used ID=`id -g` From a63f5485289d1af5e14990fccded8af42b331459 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Fri, 15 May 2009 22:56:13 +0000 Subject: [PATCH 309/582] Allow to define additional Erlang options in ejabberdctl.cfg (thanks to Sergei Golovan) SVN Revision: 2083 --- src/ejabberdctl.cfg.example | 20 +++++++++++++++++++- src/ejabberdctl.template | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/ejabberdctl.cfg.example b/src/ejabberdctl.cfg.example index d6bb80e16..0c8d0c5a6 100644 --- a/src/ejabberdctl.cfg.example +++ b/src/ejabberdctl.cfg.example @@ -78,7 +78,23 @@ #ERL_MAX_ETS_TABLES=1400 #. -#' ERLANG_NODE +#' ERL_OPTIONS: Additional Erlang options +# +# The next variable allows to specify additional options passed to erlang while +# starting ejabberd. Some useful options are -noshell, -detached, -heart. When +# ejabberd is started from an init.d script options -noshell and -detached are +# added implicitly. See erl(1) for more info. +# +# It might be useful to add "-pa /usr/local/lib/ejabberd/ebin" if you +# want to add local modules in this path. +# +# Default: "" +# +#ERL_OPTIONS="" + +#. +#' ERLANG_NODE: Erlang node name +# # The next variable allows to explicitly specify erlang node for ejabberd # It can be given in different formats: # ERLANG_NODE=ejabberd @@ -94,4 +110,6 @@ # #ERLANG_NODE=ejabberd +#. +#' # vim: foldmarker=#',#. foldmethod=marker: diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template index dcb8f2ac9..5ed63b70e 100644 --- a/src/ejabberdctl.template +++ b/src/ejabberdctl.template @@ -79,7 +79,7 @@ else KERNEL_OPTS="-kernel inet_dist_listen_min ${FIREWALL_WINDOW%-*} inet_dist_listen_max ${FIREWALL_WINDOW#*-}" fi -ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $KERNEL_OPTS" +ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $ERL_OPTIONS $KERNEL_OPTS" # define additional environment variables if [ "$EJABBERDDIR" = "" ]; then From 23509c1688e09fa9782c75e70bc0bdf0f4b61739 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Fri, 15 May 2009 22:56:55 +0000 Subject: [PATCH 310/582] New command to convert mnesia nodename, copied from OTP and Debian SVN Revision: 2084 --- src/ejabberd_admin.erl | 52 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl index 8caf6e5ff..d7f00b185 100644 --- a/src/ejabberd_admin.erl +++ b/src/ejabberd_admin.erl @@ -42,6 +42,7 @@ dump_mnesia/1, load_mnesia/1, install_fallback_mnesia/1, dump_to_textfile/1, + mnesia_change_nodename/4, restore/1 % Still used by some modules ]). @@ -114,6 +115,12 @@ commands() -> module = ?MODULE, function = delete_old_messages, args = [{days, integer}], result = {res, rescode}}, + #ejabberd_commands{name = mnesia_change_nodename, tags = [mnesia], + desc = "Change the erlang node name in a backup file", + module = ?MODULE, function = mnesia_change_nodename, + args = [{oldnodename, string}, {newnodename, string}, + {oldbackup, string}, {newbackup, string}], + result = {res, restuple}}, #ejabberd_commands{name = backup, tags = [mnesia], desc = "Store the database to backup file", module = ?MODULE, function = backup_mnesia, @@ -376,3 +383,48 @@ install_fallback_mnesia(Path) -> {cannot_fallback, String} end. +mnesia_change_nodename(FromString, ToString, Source, Target) -> + From = list_to_atom(FromString), + To = list_to_atom(ToString), + Switch = + fun + (Node) when Node == From -> + io:format(" - Replacing nodename: '~p' with: '~p'~n", [From, To]), + To; + (Node) when Node == To -> + %% throw({error, already_exists}); + io:format(" - Node: '~p' will not be modified (it is already '~p')~n", [Node, To]), + Node; + (Node) -> + io:format(" - Node: '~p' will not be modified (it is not '~p')~n", [Node, From]), + Node + end, + Convert = + fun + ({schema, db_nodes, Nodes}, Acc) -> + io:format(" +++ db_nodes ~p~n", [Nodes]), + {[{schema, db_nodes, lists:map(Switch,Nodes)}], Acc}; + ({schema, version, Version}, Acc) -> + io:format(" +++ version: ~p~n", [Version]), + {[{schema, version, Version}], Acc}; + ({schema, cookie, Cookie}, Acc) -> + io:format(" +++ cookie: ~p~n", [Cookie]), + {[{schema, cookie, Cookie}], Acc}; + ({schema, Tab, CreateList}, Acc) -> + io:format("~n * Checking table: '~p'~n", [Tab]), + Keys = [ram_copies, disc_copies, disc_only_copies], + OptSwitch = + fun({Key, Val}) -> + case lists:member(Key, Keys) of + true -> + io:format(" + Checking key: '~p'~n", [Key]), + {Key, lists:map(Switch, Val)}; + false-> {Key, Val} + end + end, + Res = {[{schema, Tab, lists:map(OptSwitch, CreateList)}], Acc}, + Res; + (Other, Acc) -> + {[Other], Acc} + end, + mnesia:traverse_backup(Source, Target, Convert, switched). From 5bd67495ed48cc59f07b4b0252d6edbf7cde1258 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Fri, 15 May 2009 22:57:40 +0000 Subject: [PATCH 311/582] Document how to convert Mnesia node name SVN Revision: 2085 --- doc/guide.html | 41 ++++++++++++++++++++++++--------- doc/guide.tex | 61 +++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 84 insertions(+), 18 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 39740f51e..3bd1d7a2b 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -3270,16 +3270,37 @@ so it stores the name of the Erlang node in it (see section <A HREF="#nodename"> The name of an Erlang node includes the hostname of the computer. So, the name of the Erlang node changes if you change the name of the machine in which <TT>ejabberd</TT> runs, -or when you move <TT>ejabberd</TT> to a different machine.</P><P>So, if you want to change the computer hostname where <TT>ejabberd</TT> is installed, -you must follow these instructions: -</P><OL CLASS="enumerate" type=1><LI CLASS="li-enumerate"> - In the old server, backup the Mnesia database using the Web Admin or <TT>ejabberdctl</TT>. - For example: -<PRE CLASS="verbatim">ejabberdctl backup /tmp/ejabberd-oldhost.backup -</PRE> </LI><LI CLASS="li-enumerate">In the new server, restore the backup file using the Web Admin or <TT>ejabberdctl</TT>. - For example: -<PRE CLASS="verbatim">ejabberdctl restore /tmp/ejabberd-oldhost.backup -</PRE></LI></OL><P> <A NAME="secure"></A> </P><!--TOC chapter Securing <TT>ejabberd</TT>--> +or when you move <TT>ejabberd</TT> to a different machine.</P><P>You have two ways to use the old Mnesia database in an ejabberd with new node name: +put the old node name in <TT>ejabberdctl.cfg</TT>, +or convert the database to the new node name.</P><P>Those example steps will backup, convert and load the Mnesia database. +You need to have either the old Mnesia spool dir or a backup of Mnesia. +If you already have a backup file of the old database, you can go directly to step 5. +You also need to know the old node name and the new node name. +If you don’t know them, look for them by executing <TT>ejabberdctl</TT> +or in the ejabberd log files.</P><P>Before starting, setup some variables: +</P><PRE CLASS="verbatim">OLDNODE=ejabberd@oldmachine +NEWNODE=ejabberd@newmachine +OLDFILE=/tmp/old.backup +NEWFILE=/tmp/new.backup +</PRE><OL CLASS="enumerate" type=1><LI CLASS="li-enumerate"> +Start ejabberd enforcing the old node name: +<PRE CLASS="verbatim">ejabberdctl --node $OLDNODE start +</PRE></LI><LI CLASS="li-enumerate">Generate a backup file: +<PRE CLASS="verbatim">ejabberdctl --node $OLDNODE backup $OLDFILE +</PRE></LI><LI CLASS="li-enumerate">Stop the old node: +<PRE CLASS="verbatim">ejabberdctl --node $OLDNODE stop +</PRE></LI><LI CLASS="li-enumerate">Make sure there aren’t files in the Mnesia spool dir. For example: +<PRE CLASS="verbatim">mkdir /var/lib/ejabberd/oldfiles +mv /var/lib/ejabberd/*.* /var/lib/ejabberd/oldfiles/ +</PRE></LI><LI CLASS="li-enumerate">Start ejabberd. There isn’t any need to specify the node name anymore: +<PRE CLASS="verbatim">ejabberdctl start +</PRE></LI><LI CLASS="li-enumerate">Convert the backup to new node name: +<PRE CLASS="verbatim">ejabberdctl mnesia_change_nodename $OLDNODE $NEWNODE $OLDFILE $NEWFILE +</PRE></LI><LI CLASS="li-enumerate">Import the new backup: +<PRE CLASS="verbatim">ejabberdctl restore $NEWFILE +</PRE></LI><LI CLASS="li-enumerate">Check that the information of the old database is available: accounts, rosters... +After you finish, remember to delete the temporary backup files from public directories. +</LI></OL><P> <A NAME="secure"></A> </P><!--TOC chapter Securing <TT>ejabberd</TT>--> <H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc70">Chapter 5</A>  <A HREF="#secure">Securing <TT>ejabberd</TT></A></H1><!--SEC END --><P> <A NAME="secure"></A> </P><P> <A NAME="firewall"></A> </P><!--TOC section Firewall Settings--> <H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc71">5.1</A>  <A HREF="#firewall">Firewall Settings</A></H2><!--SEC END --><P> <A NAME="firewall"></A> </P><P>You need to take the following TCP ports in mind when configuring your firewall: diff --git a/doc/guide.tex b/doc/guide.tex index 1c81860c1..404abcd32 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -4202,19 +4202,64 @@ So, the name of the Erlang node changes if you change the name of the machine in which \ejabberd{} runs, or when you move \ejabberd{} to a different machine. -So, if you want to change the computer hostname where \ejabberd{} is installed, -you must follow these instructions: +You have two ways to use the old Mnesia database in an ejabberd with new node name: +put the old node name in \term{ejabberdctl.cfg}, +or convert the database to the new node name. + +Those example steps will backup, convert and load the Mnesia database. +You need to have either the old Mnesia spool dir or a backup of Mnesia. +If you already have a backup file of the old database, you can go directly to step 5. +You also need to know the old node name and the new node name. +If you don't know them, look for them by executing \term{ejabberdctl} +or in the ejabberd log files. + +Before starting, setup some variables: +\begin{verbatim} +OLDNODE=ejabberd@oldmachine +NEWNODE=ejabberd@newmachine +OLDFILE=/tmp/old.backup +NEWFILE=/tmp/new.backup +\end{verbatim} + \begin{enumerate} - \item In the old server, backup the Mnesia database using the Web Admin or \term{ejabberdctl}. - For example: +\item Start ejabberd enforcing the old node name: \begin{verbatim} -ejabberdctl backup /tmp/ejabberd-oldhost.backup +ejabberdctl --node $OLDNODE start \end{verbatim} - \item In the new server, restore the backup file using the Web Admin or \term{ejabberdctl}. - For example: + +\item Generate a backup file: \begin{verbatim} -ejabberdctl restore /tmp/ejabberd-oldhost.backup +ejabberdctl --node $OLDNODE backup $OLDFILE \end{verbatim} + +\item Stop the old node: +\begin{verbatim} +ejabberdctl --node $OLDNODE stop +\end{verbatim} + +\item Make sure there aren't files in the Mnesia spool dir. For example: +\begin{verbatim} +mkdir /var/lib/ejabberd/oldfiles +mv /var/lib/ejabberd/*.* /var/lib/ejabberd/oldfiles/ +\end{verbatim} + +\item Start ejabberd. There isn't any need to specify the node name anymore: +\begin{verbatim} +ejabberdctl start +\end{verbatim} + +\item Convert the backup to new node name: +\begin{verbatim} +ejabberdctl mnesia_change_nodename $OLDNODE $NEWNODE $OLDFILE $NEWFILE +\end{verbatim} + +\item Import the new backup: +\begin{verbatim} +ejabberdctl restore $NEWFILE +\end{verbatim} + +\item Check that the information of the old database is available: accounts, rosters... +After you finish, remember to delete the temporary backup files from public directories. \end{enumerate} From 0a9581a37529ff4ca8c30e549350a5a611d92d14 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Mon, 18 May 2009 11:41:53 +0000 Subject: [PATCH 312/582] LDAP bind attempts: log warnings and increase timeout after reject. Merged from trunk SVN r2086: Log warnings on unsuccessful LDAP bind attempts. Increase timeout before the next LDAP bind attempt up to five seconds if the last bind attempt was rejected by the LDAP server ("soft" error) (thanks to Konstantin Khomoutov) SVN Revision: 2087 --- src/eldap/eldap.erl | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/eldap/eldap.erl b/src/eldap/eldap.erl index 5d7652fcc..6a16b9b54 100644 --- a/src/eldap/eldap.erl +++ b/src/eldap/eldap.erl @@ -91,6 +91,8 @@ -define(SEND_TIMEOUT, 30000). -define(MAX_TRANSACTION_ID, 65535). -define(MIN_TRANSACTION_ID, 0). +%% Grace period after "soft" LDAP bind errors: +-define(GRACEFUL_RETRY_TIMEOUT, 5000). -record(eldap, {version = ?LDAP_VERSION, hosts, % Possible hosts running LDAP servers @@ -474,11 +476,14 @@ handle_info({tcp, _Socket, Data}, wait_bind_response, S) -> case catch recvd_wait_bind_response(Data, S) of bound -> dequeue_commands(S); - {fail_bind, _Reason} -> + {fail_bind, Reason} -> + report_bind_failure(S#eldap.host, S#eldap.port, Reason), + {next_state, connecting, close_and_retry(S, ?GRACEFUL_RETRY_TIMEOUT)}; + {'EXIT', Reason} -> + report_bind_failure(S#eldap.host, S#eldap.port, Reason), {next_state, connecting, close_and_retry(S)}; - {'EXIT', _Reason} -> - {next_state, connecting, close_and_retry(S)}; - {error, _Reason} -> + {error, Reason} -> + report_bind_failure(S#eldap.host, S#eldap.port, Reason), {next_state, connecting, close_and_retry(S)} end; @@ -790,7 +795,7 @@ check_tag(Data) -> _ -> throw({error,decoded_tag}) end. -close_and_retry(S) -> +close_and_retry(S, Timeout) -> catch gen_tcp:close(S#eldap.fd), Queue = dict:fold( fun(_Id, [{Timer, Command, From, _Name}|_], Q) -> @@ -799,9 +804,16 @@ close_and_retry(S) -> (_, _, Q) -> Q end, S#eldap.req_q, S#eldap.dict), - erlang:send_after(?RETRY_TIMEOUT, self(), {timeout, retry_connect}), + erlang:send_after(Timeout, self(), {timeout, retry_connect}), S#eldap{fd=null, req_q=Queue, dict=dict:new()}. +close_and_retry(S) -> + close_and_retry(S, ?RETRY_TIMEOUT). + +report_bind_failure(Host, Port, Reason) -> + ?WARNING_MSG("LDAP bind failed on ~s:~p~nReason: ~p", + [Host, Port, Reason]). + %%----------------------------------------------------------------------- %% Sort out timed out commands %%----------------------------------------------------------------------- @@ -864,8 +876,7 @@ connect_bind(S) -> host = Host, bind_timer = Timer}}; {error, Reason} -> - ?ERROR_MSG("LDAP bind failed on ~s:~p~nReason: ~p", - [Host, S#eldap.port, Reason]), + report_bind_failure(Host, S#eldap.port, Reason), NewS = close_and_retry(S), {ok, connecting, NewS#eldap{host = Host}} end; From b473862da6e654823c0d40bb9df9ee9734f844c3 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 19 May 2009 09:39:13 +0000 Subject: [PATCH 313/582] Added API function to get current S2S connections with information get_info_s2s_connections(Type) returns a list of incoming (or outgoing) S2S connections with information for each one including IP address, port number, TLS options... (thanks to Juan Pablo Carlino) SVN Revision: 2089 --- src/ejabberd_s2s.erl | 31 +++++++++++++++++++++++++++++++ src/ejabberd_s2s_in.erl | 29 +++++++++++++++++++++++++++++ src/ejabberd_s2s_out.erl | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index e25566d75..835f4db4a 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -46,6 +46,8 @@ %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). +%% ejabberd API +-export([get_info_s2s_connections/1]). -include_lib("exmpp/include/exmpp.hrl"). @@ -520,3 +522,32 @@ allow_host(MyServer, S2SHost) -> _ -> true %% The default s2s policy is allow end end. + +%% Get information about S2S connections of the specified type. +%% @spec (Type) -> [Info] +%% where Type = in | out +%% Info = [{InfoName::atom(), InfoValue::any()}] +get_info_s2s_connections(Type) -> + ChildType = case Type of + in -> ejabberd_s2s_in_sup; + out -> ejabberd_s2s_out_sup + end, + Connections = supervisor:which_children(ChildType), + get_s2s_info(Connections,Type). + +get_s2s_info(Connections,Type)-> + complete_s2s_info(Connections,Type,[]). +complete_s2s_info([],_,Result)-> + Result; +complete_s2s_info([Connection|T],Type,Result)-> + {_,PID,_,_}=Connection, + State = get_s2s_state(PID), + complete_s2s_info(T,Type,[State|Result]). + +get_s2s_state(S2sPid)-> + Infos = case gen_fsm:sync_send_all_state_event(S2sPid,get_state_infos) of + {state_infos, Is} -> [{status, open} | Is]; + {noproc,_} -> [{status, closed}]; %% Connection closed + {badrpc,_} -> [{status, error}] + end, + [{s2s_pid, S2sPid} | Infos]. diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index ea1f3e597..0676abbcc 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -500,6 +500,35 @@ stream_established(closed, StateData) -> %%---------------------------------------------------------------------- handle_event(_Event, 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, StateData) -> + SockMod = StateData#state.sockmod, + {Addr,Port} = try SockMod:peername(StateData#state.socket) of + {ok, {A,P}} -> {A,P}; + {error, _} -> {unknown,unknown} + catch + _:_ -> {unknown,unknown} + end, + Infos = [ + {direction, in}, + {statename, StateName}, + {addr, Addr}, + {port, Port}, + {streamid, StateData#state.streamid}, + {tls, StateData#state.tls}, + {tls_enabled, StateData#state.tls_enabled}, + {tls_options, StateData#state.tls_options}, + {authenticated, StateData#state.authenticated}, + {shaper, StateData#state.shaper}, + {sockmod, SockMod} + ], + Reply = {state_infos, Infos}, + {reply,Reply,StateName,StateData}; %%---------------------------------------------------------------------- %% Func: handle_sync_event/4 diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 029e3e631..9641e5c11 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -700,6 +700,42 @@ stream_established(closed, StateData) -> handle_event(_Event, StateName, StateData) -> {next_state, StateName, StateData, get_timeout_interval(StateName)}. +%%---------------------------------------------------------------------- +%% 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, StateData) -> + {Addr,Port} = try ejabberd_socket:peername(StateData#state.socket) of + {ok, {A,P}} -> {A,P}; + {error, _} -> {unknown,unknown} + catch + _:_ -> + {unknown,unknown} + end, + Infos = [ + {direction, out}, + {statename, StateName}, + {addr, Addr}, + {port, Port}, + {streamid, StateData#state.streamid}, + {use_v10, StateData#state.use_v10}, + {tls, StateData#state.tls}, + {tls_required, StateData#state.tls_required}, + {tls_enabled, StateData#state.tls_enabled}, + {tls_options, StateData#state.tls_options}, + {authenticated, StateData#state.authenticated}, + {db_enabled, StateData#state.db_enabled}, + {try_auth, StateData#state.try_auth}, + {myname, StateData#state.myname}, + {server, StateData#state.server}, + {delay_to_retry, StateData#state.delay_to_retry}, + {verify, StateData#state.verify} + ], + Reply = {state_infos, Infos}, + {reply,Reply,StateName,StateData}; + %%---------------------------------------------------------------------- %% Func: handle_sync_event/4 %% Returns: {next_state, NextStateName, NextStateData} | From 2e26b6bf8b5521cf19c0ee8487f26b318ba35fde Mon Sep 17 00:00:00 2001 From: Christophe Romain <christophe.romain@process-one.net> Date: Tue, 19 May 2009 22:29:28 +0000 Subject: [PATCH 314/582] PubSub: improve get_entity_* API SVN Revision: 2091 --- src/mod_pubsub/mod_pubsub.erl | 71 ++++++++++++++--------------- src/mod_pubsub/node_default.erl | 46 +++++++++++-------- src/mod_pubsub/node_pep.erl | 33 +++++++++++--- src/mod_pubsub/nodetree_virtual.erl | 12 ++--- src/mod_pubsub/pubsub.hrl | 12 ++--- 5 files changed, 98 insertions(+), 76 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 3f9f6f22f..ca614bd92 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -227,9 +227,9 @@ init_plugins(Host, ServerHost, Opts) -> gen_mod:get_opt(nodetree, Opts, ?STDTREE)), ?DEBUG("** tree plugin is ~p",[TreePlugin]), TreePlugin:init(Host, ServerHost, Opts), - Plugins = lists:usort(gen_mod:get_opt(plugins, Opts, []) ++ [?STDNODE]), - PepMapping = lists:usort(gen_mod:get_opt(pep_mapping, Opts, [])), - ?DEBUG("** PEP Mapping : ~p~n",[PepMapping]), + Plugins = gen_mod:get_opt(plugins, Opts, [?STDNODE]), + PepMapping = gen_mod:get_opt(pep_mapping, Opts, []), + ?DEBUG("** PEP Mapping : ~p~n",[PepMapping]), lists:foreach(fun(Name) -> ?DEBUG("** init ~s plugin",[Name]), Plugin = list_to_atom(?PLUGIN_PREFIX ++ Name), @@ -389,14 +389,10 @@ send_loop(State) -> lists:foreach( fun({Node, subscribed, SubJID}) -> if (SubJID == LJID) or (SubJID == BJID) -> - case tree_action(Host, get_node, [Host, Node, JID]) of - #pubsub_node{options = Options, type = Type, id = NodeId} -> - case get_option(Options, send_last_published_item) of - on_sub_and_presence -> - send_items(Host, Node, NodeId, Type, SubJID, last); - _ -> - ok - end; + #pubsub_node{options = Options, type = Type, id = NodeId} = Node, + case get_option(Options, send_last_published_item) of + on_sub_and_presence -> + send_items(Host, Node, NodeId, Type, SubJID, last); _ -> ok end; @@ -708,18 +704,19 @@ handle_cast({remove_user, LUser, LServer}, State) -> lists:foreach(fun(PType) -> {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Owner]), lists:foreach(fun - ({Node, subscribed, JID}) -> - unsubscribe_node(Host, Node, Owner, JID, all); - (_) -> + ({#pubsub_node{nodeid = {H, N}}, subscribed, JID}) -> + unsubscribe_node(H, N, Owner, JID, all); + (_) -> ok - end, Subscriptions) + end, Subscriptions), + {result, Affiliations} = node_action(Host, PType, get_entity_affiliations, [Host, Owner]), + lists:foreach(fun + ({#pubsub_node{nodeid = {H, N}}, owner}) -> + delete_node(H, N, Owner); + (_) -> + ok + end, Affiliations) end, State#state.plugins), - %% remove user's PEP nodes - lists:foreach(fun(#pubsub_node{nodeid={NodeKey, NodeName}}) -> - delete_node(NodeKey, NodeName, Owner) - end, tree_action(Host, get_nodes, [jlib:short_prepd_bare_jid(Owner), Owner])), - %% remove user's nodes - delete_node(Host, ["home", LServer, LUser], Owner), {noreply, State}; handle_cast({unsubscribe, Subscriber, Owner}, State) -> @@ -729,20 +726,18 @@ handle_cast({unsubscribe, Subscriber, Owner}, State) -> {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), lists:foreach(fun ({Node, subscribed, JID}) -> - Action = fun(#pubsub_node{options = Options, owners = Owners, type = Type, id = NodeId}) -> - case get_option(Options, access_model) of - presence -> - case lists:member(BJID, Owners) of - true -> - node_call(Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); - false -> - {result, ok} - end; - _ -> - {result, ok} - end - end, - transaction(Host, Node, Action, sync_dirty); + #pubsub_node{options = Options, owners = Owners, type = Type, id = NodeId} = Node, + case get_option(Options, access_model) of + presence -> + case lists:member(BJID, Owners) of + true -> + node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); + false -> + {result, ok} + end; + _ -> + {result, ok} + end; (_) -> ok end, Subscriptions) @@ -2047,7 +2042,7 @@ get_affiliations(Host, JID, Plugins) when is_list(Plugins) -> {ok, Affiliations} -> Entities = lists:flatmap( fun({_, none}) -> []; - ({Node, Affiliation}) -> + ({#pubsub_node{nodeid = {_, Node}}, Affiliation}) -> [#xmlel{ns = ?NS_PUBSUB, name = 'affiliation', attrs = [?XMLATTR('node', node_to_string(Node)), ?XMLATTR('affiliation', affiliation_to_string(Affiliation))]}] @@ -2189,7 +2184,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> Entities = lists:flatmap( fun({_, none}) -> []; - ({SubsNode, Subscription}) -> + ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription}) -> case Node of [] -> [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = @@ -2203,7 +2198,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> end; ({_, none, _}) -> []; - ({SubsNode, Subscription, SubJID}) -> + ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubJID}) -> case Node of [] -> [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 21c20770e..bd972b550 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -549,14 +549,21 @@ purge_node(NodeId, Owner) -> %% the default PubSub module. Otherwise, it should return its own affiliation, %% that will be added to the affiliation stored in the main %% <tt>pubsub_state</tt> table.</p> -get_entity_affiliations(_Host, Owner) -> +get_entity_affiliations(Host, Owner) -> GenKey = jlib:short_prepd_bare_jid(Owner), - States = mnesia:match_object( - #pubsub_state{stateid = {GenKey, '_'}, _ = '_'}), - Tr = fun(#pubsub_state{stateid = {_, N}, affiliation = A}) -> - {get_nodename(N), A} - end, - {result, lists:map(Tr, States)}. + States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'}), + Reply = lists:foldl(fun(#pubsub_state{stateid = {_, N}, affiliation = A}, Acc) -> + case mnesia:index_read(pubsub_node, N, #pubsub_node.id) of + [#pubsub_node{nodeid = {H, _}} = Node] -> + case H of + Host -> [{Node, A}|Acc]; + _ -> Acc + end; + _ -> + Acc + end + end, [], States), + {result, Reply}. get_node_affiliations(NodeId) -> {result, States} = get_states(NodeId), @@ -590,7 +597,7 @@ set_affiliation(NodeId, Owner, Affiliation) -> %% the default PubSub module. Otherwise, it should return its own affiliation, %% that will be added to the affiliation stored in the main %% <tt>pubsub_state</tt> table.</p> -get_entity_subscriptions(_Host, Owner) -> +get_entity_subscriptions(Host, Owner) -> {U, D, _} = SubKey = jlib:short_prepd_jid(Owner), GenKey = jlib:short_prepd_bare_jid(SubKey), States = case SubKey of @@ -601,10 +608,18 @@ get_entity_subscriptions(_Host, Owner) -> ++ mnesia:match_object( #pubsub_state{stateid = {SubKey, '_'}, _ = '_'}) end, - Tr = fun(#pubsub_state{stateid = {J, N}, subscription = S}) -> - {get_nodename(N), S, J} - end, - {result, lists:map(Tr, States)}. + Reply = lists:foldl(fun(#pubsub_state{stateid = {J, N}, subscription = S}, Acc) -> + case mnesia:index_read(pubsub_node, N, #pubsub_node.id) of + [#pubsub_node{nodeid = {H, _}} = Node] -> + case H of + Host -> [{Node, S, J}|Acc]; + _ -> Acc + end; + _ -> + Acc + end + end, [], States), + {result, Reply}. get_node_subscriptions(NodeId) -> {result, States} = get_states(NodeId), @@ -808,10 +823,3 @@ can_fetch_item(none, subscribed) -> true; can_fetch_item(none, none) -> false; can_fetch_item(_Affiliation, _Subscription) -> false. -%% @spec (NodeId) -> Node -%% @doc retreive pubsubNode() representation giving a NodeId -get_nodename(NodeId) -> - case mnesia:index_read(pubsub_node, NodeId, #pubsub_node.id) of - [#pubsub_node{nodeid = {_, Node}}] -> Node; - _ -> [] - end. diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index 1c1e0fc3d..01523a087 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -182,8 +182,29 @@ get_affiliation(NodeId, Owner) -> set_affiliation(NodeId, Owner, Affiliation) -> node_default:set_affiliation(NodeId, Owner, Affiliation). -get_entity_subscriptions(_Host, _Owner) -> - {result, []}. +get_entity_subscriptions(_Host, Owner) -> + {U, D, _} = SubKey = jlib:jid_tolower(Owner), + GenKey = jlib:jid_remove_resource(SubKey), + States = case SubKey of + GenKey -> mnesia:match_object( + #pubsub_state{stateid = {{U, D, '_'}, '_'}, _ = '_'}); + _ -> mnesia:match_object( + #pubsub_state{stateid = {GenKey, '_'}, _ = '_'}) + ++ mnesia:match_object( + #pubsub_state{stateid = {SubKey, '_'}, _ = '_'}) + end, + Reply = lists:foldl(fun(#pubsub_state{stateid = {J, N}, subscription = S}, Acc) -> + case mnesia:index_read(pubsub_node, N, #pubsub_node.id) of + [#pubsub_node{nodeid = {H, _}} = Node] -> + case H of + {_, D, _} -> [{Node, S, J}|Acc]; + _ -> Acc + end; + _ -> + Acc + end + end, [], States), + {result, Reply}. get_node_subscriptions(NodeId) -> %% note: get_node_subscriptions is used for broadcasting @@ -193,11 +214,11 @@ get_node_subscriptions(NodeId) -> %% DO NOT REMOVE node_default:get_node_subscriptions(NodeId). -get_subscription(_NodeId, _Owner) -> - {result, none}. +get_subscription(NodeId, Owner) -> + node_default:get_subscription(NodeId, Owner). -set_subscription(_NodeId, _Owner, _Subscription) -> - ok. +set_subscription(NodeId, Owner, Subscription) -> + node_default:set_subscription(NodeId, Owner, Subscription). get_states(NodeId) -> node_default:get_states(NodeId). diff --git a/src/mod_pubsub/nodetree_virtual.erl b/src/mod_pubsub/nodetree_virtual.erl index 5fb77e217..1083e5581 100644 --- a/src/mod_pubsub/nodetree_virtual.erl +++ b/src/mod_pubsub/nodetree_virtual.erl @@ -26,10 +26,9 @@ %%% @doc The module <strong>{@module}</strong> is the PubSub node tree plugin that %%% allow virtual nodes handling. %%% <p>PubSub node tree plugins are using the {@link gen_nodetree} behaviour.</p> -%%% <p><strong>The API isn't stabilized yet</strong>. The pubsub plugin -%%% development is still a work in progress. However, the system is already -%%% useable and useful as is. Please, send us comments, feedback and -%%% improvements.</p> +%%% This plugin development is still a work in progress. Due to optimizations in +%%% mod_pubsub, this plugin can not work anymore without altering functioning. +%%% Please, send us comments, feedback and improvements.</p> -module(nodetree_virtual). -author('christophe.romain@process-one.net'). @@ -84,14 +83,13 @@ options() -> set_node(_NodeRecord) -> ok. -get_node(Host, Node, _From) -> - get_node(Host, Node). - %% @spec (Host, Node) -> pubsubNode() %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() %% @doc <p>Virtual node tree does not handle a node database. Any node is considered %% as existing. Node record contains default values.</p> +get_node(Host, Node, _From) -> + get_node(Host, Node). get_node(Host, Node) -> #pubsub_node{nodeid = {Host, Node}}. diff --git a/src/mod_pubsub/pubsub.hrl b/src/mod_pubsub/pubsub.hrl index 87088eb6a..dc95e3378 100644 --- a/src/mod_pubsub/pubsub.hrl +++ b/src/mod_pubsub/pubsub.hrl @@ -82,8 +82,8 @@ %%% @type pubsubNode() = #pubsub_node{ %%% nodeid = {Host::host(), Node::pubsubNode()}, -%%% parentid = {Host::host(), Node::pubsubNode()}, -%%% nodeidx = int(). +%%% parentid = Node::pubsubNode(), +%%% nodeidx = int(). % can be anything you want %%% type = nodeType(), %%% options = [nodeOption()]} %%% <p>This is the format of the <tt>nodes</tt> table. The type of the table @@ -98,7 +98,7 @@ }). %%% @type pubsubState() = #pubsub_state{ -%%% stateid = {ljid(), pubsubNodeId()}}, +%%% stateid = {ljid(), nodeidx()}}, %%% items = [ItemId::string()], %%% affiliation = affiliation(), %%% subscription = subscription()}. @@ -111,9 +111,9 @@ }). %%% @type pubsubItem() = #pubsub_item{ -%%% itemid = {ItemId::string(), pubsubNodeId()}}, -%%% creation = {ljid(), now()}, -%%% modification = {ljid(), now()}, +%%% itemid = {ItemId::string(), nodeidx()}}, +%%% creation = {now(), ljid()}, +%%% modification = {now(), ljid()}, %%% payload = XMLContent::string()}. %%% <p>This is the format of the <tt>published items</tt> table. The type of the %%% table is: <tt>set</tt>,<tt>disc</tt>,<tt>fragmented</tt>.</p> From 8be73967fd896ee63c6ce22aba16f9b4d7b9e7ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20R=C3=A9mond?= <mickael.remond@process-one.net> Date: Thu, 21 May 2009 16:28:49 +0000 Subject: [PATCH 315/582] * src/odbc/ejabberd_odbc.erl: Support for nested transactions (EJABS-859) (EJAB-940) (CR-EJAB-10) SVN Revision: 2094 --- src/odbc/ejabberd_odbc.erl | 174 ++++++++++++++++++++++--------------- 1 file changed, 106 insertions(+), 68 deletions(-) diff --git a/src/odbc/ejabberd_odbc.erl b/src/odbc/ejabberd_odbc.erl index be1c315a8..5376694ae 100644 --- a/src/odbc/ejabberd_odbc.erl +++ b/src/odbc/ejabberd_odbc.erl @@ -70,8 +70,8 @@ start_link(Host, StartInterval) -> gen_server:start_link(ejabberd_odbc, [Host, StartInterval], []). sql_query(Host, Query) -> - gen_server:call(ejabberd_odbc_sup:get_random_pid(Host), - {sql_query, Query}, ?TRANSACTION_TIMEOUT). + Msg = {sql_query, Query}, + sql_call(Host, Msg,). %% SQL transaction based on a list of queries %% This function automatically @@ -85,13 +85,24 @@ sql_transaction(Host, Queries) when is_list(Queries) -> sql_transaction(Host, F); %% SQL transaction, based on a erlang anonymous function (F = fun) sql_transaction(Host, F) -> - gen_server:call(ejabberd_odbc_sup:get_random_pid(Host), - {sql_transaction, F}, ?TRANSACTION_TIMEOUT). + Msg = {sql_transaction, F}, + sql_call(Host, Msg). %% SQL bloc, based on a erlang anonymous function (F = fun) sql_bloc(Host, F) -> - gen_server:call(ejabberd_odbc_sup:get_random_pid(Host), - {sql_bloc, F}, ?TRANSACTION_TIMEOUT). + Msg = {sql_bloc, F}, + sql_call(Host, Msg). + +sql_call(Host, Msg) -> + case get(?STATE_KEY) of + undefined -> + gen_server:call(ejabberd_odbc_sup:get_random_pid(Host), + Msg, ?TRANSACTION_TIMEOUT); + State -> + %% Query, Transaction or Bloc nested inside transaction + nested_op(Msg, State) + end. + %% This function is intended to be used from inside an sql_transaction: sql_query_t(Query) -> @@ -176,42 +187,8 @@ init([Host, StartInterval]) -> %% {stop, Reason, Reply, State} | (terminate/2 is called) %% {stop, Reason, State} (terminate/2 is called) %%---------------------------------------------------------------------- -handle_call({sql_query, Query}, _From, State) -> - case sql_query_internal(State, Query) of - % error returned by MySQL driver - {error, "query timed out"} = Reply -> - {stop, timeout, Reply, State}; - % error returned by MySQL driver - {error, "Failed sending data on socket"++_} = Reply -> - {stop, closed, Reply, State}; - Reply -> - {reply, Reply, State} - end; -handle_call({sql_transaction, F}, _From, State) -> - case execute_transaction(State, F, ?MAX_TRANSACTION_RESTARTS, "") of - % error returned by MySQL driver - {error, "query timed out"} -> - {stop, timeout, State}; - % error returned by MySQL driver - {error, "Failed sending data on socket"++_} = Reply -> - {stop, closed, Reply, State}; - Reply -> - {reply, Reply, State} - end; -handle_call({sql_bloc, F}, _From, State) -> - case execute_bloc(State, F) of - % error returned by MySQL driver - {error, "query timed out"} -> - {stop, timeout, State}; - % error returned by MySQL driver - {error, "Failed sending data on socket"++_} = Reply -> - {stop, closed, Reply, State}; - Reply -> - {reply, Reply, State} - end; -handle_call(_Request, _From, State) -> - Reply = ok, - {reply, Reply, State}. +handle_call(Command, _From, State) -> + dispatch_sql_command(Command, State). %%---------------------------------------------------------------------- %% Func: handle_cast/2 @@ -259,14 +236,36 @@ terminate(_Reason, State) -> %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- +dispatch_sql_command({sql_query, Query}, State) -> + abort_on_driver_error(sql_query_internal(State, Query), State); +dispatch_sql_command({sql_transaction, F}, State) -> + abort_on_driver_error( + execute_transaction(State, F, ?MAX_TRANSACTION_RESTARTS, ""), State); +dispatch_sql_command({sql_bloc, F}, State) -> + abort_on_driver_error(execute_bloc(State, F), State); +dispatch_sql_command(Request, State) -> + ?WARNING_MSG("Unexpected call ~p.", [Request]), + {reply, ok, State}. + sql_query_internal(State, Query) -> - case State#state.db_type of - odbc -> - odbc:sql_query(State#state.db_ref, Query); - pgsql -> - pgsql_to_odbc(pgsql:squery(State#state.db_ref, Query)); - mysql -> - mysql_to_odbc(mysql_conn:fetch(State#state.db_ref, Query, self())) + Nested = case get(?STATE_KEY) of + undefined -> put(?STATE_KEY, State), false; + _State -> true + end, + Result = case State#state.db_type of + odbc -> + odbc:sql_query(State#state.db_ref, Query); + pgsql -> + pgsql_to_odbc(pgsql:squery(State#state.db_ref, Query)); + mysql -> + ?DEBUG("MySQL, Send query~n~p~n", [Query]), + R = mysql_to_odbc(mysql_conn:fetch(State#state.db_ref, Query, self())), + ?DEBUG("MySQL, Received result~n~p~n", [R]), + R + end, + case Nested of + true -> Result; + false -> erase(?STATE_KEY), Result end. execute_transaction(State, _F, 0, Reason) -> @@ -280,30 +279,69 @@ execute_transaction(State, _F, 0, Reason) -> sql_query_internal(State, "rollback;"), {aborted, restarts_exceeded}; execute_transaction(State, F, NRestarts, _Reason) -> - put(?STATE_KEY, State), - sql_query_internal(State, "begin;"), - case catch F() of - {aborted, Reason} -> - execute_transaction(State, F, NRestarts - 1, Reason); - {'EXIT', Reason} -> - sql_query_internal(State, "rollback;"), - {aborted, Reason}; - Res -> - sql_query_internal(State, "commit;"), - {atomic, Res} + Nested = case get(?STATE_KEY) of + undefined -> + put(?STATE_KEY, State), + sql_query_internal(State, "begin;"), + false; + _State -> + true + end, + Result = case catch F() of + {aborted, Reason} -> + execute_transaction(State, F, NRestarts - 1, Reason); + {'EXIT', Reason} -> + sql_query_internal(State, "rollback;"), + {aborted, Reason}; + Res -> + {atomic, Res} + end, + case Nested of + true -> Result; + false -> sql_query_internal(State, "commit;"), erase(?STATE_KEY), Result end. execute_bloc(State, F) -> - put(?STATE_KEY, State), - case catch F() of - {aborted, Reason} -> - {aborted, Reason}; - {'EXIT', Reason} -> - {aborted, Reason}; - Res -> - {atomic, Res} + Nested = case get(?STATE_KEY) of + undefined -> put(?STATE_KEY, State), false; + _State -> true + end, + Result = case catch F() of + {aborted, Reason} -> + {aborted, Reason}; + {'EXIT', Reason} -> + {aborted, Reason}; + Res -> + {atomic, Res} + end, + case Nested of + true -> Result; + false -> erase(?STATE_KEY), Result end. +nested_op(Op, State) -> + case dispatch_sql_command(Op, State) of + {reply, Res, NewState} -> + put(?STATE_KEY, NewState), + Res; + {stop, _Reason, Reply, NewState} -> + put(?STATE_KEY, NewState), + throw({aborted, Reply}); + {noreply, NewState} -> + put(?STATE_KEY, NewState), + exit({bad_op_in_nested_txn, Op}) + end. + +abort_on_driver_error({error, "query timed out"} = Reply, State) -> + %% mysql driver error + {stop, timeout, Reply, State}; +abort_on_driver_error({error, "Failed sending data on socket"++_} = Reply, State) -> + %% mysql driver error + {stop, closed, Reply, State}; +abort_on_driver_error(Reply, State) -> + {reply, Reply, State}. + + %% == pure ODBC code %% part of init/1 From b6b4b0cdf9009b23451795f88fa32663e51cffe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20R=C3=A9mond?= <mickael.remond@process-one.net> Date: Thu, 21 May 2009 16:43:33 +0000 Subject: [PATCH 316/582] * trunk/src/odbc/ejabberd_odbc.erl: Fix typo (EJABS-859) (EJAB-940) (CR-EJAB-10) * branches/road-to-exmpp/src/odbc/ejabberd_odbc.erl: Likewise. SVN Revision: 2095 --- src/odbc/ejabberd_odbc.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/odbc/ejabberd_odbc.erl b/src/odbc/ejabberd_odbc.erl index 5376694ae..a85aa2d77 100644 --- a/src/odbc/ejabberd_odbc.erl +++ b/src/odbc/ejabberd_odbc.erl @@ -71,7 +71,7 @@ start_link(Host, StartInterval) -> sql_query(Host, Query) -> Msg = {sql_query, Query}, - sql_call(Host, Msg,). + sql_call(Host, Msg). %% SQL transaction based on a list of queries %% This function automatically From dc3899dfd9ee293a9f2f54bdb5b60b8d05099ecc Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Mon, 25 May 2009 11:19:28 +0000 Subject: [PATCH 317/582] Decrease proxy65 buffer sizes to 8192 bytes. The original size of 65535 confused clients with tight shapers (thanks to Evgeniy Khramtsov) SVN Revision: 2097 --- src/mod_proxy65/mod_proxy65_stream.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod_proxy65/mod_proxy65_stream.erl b/src/mod_proxy65/mod_proxy65_stream.erl index 045965439..29f55c188 100644 --- a/src/mod_proxy65/mod_proxy65_stream.erl +++ b/src/mod_proxy65/mod_proxy65_stream.erl @@ -90,8 +90,8 @@ init([Socket, Host, Opts]) -> process_flag(trap_exit, true), AuthType = gen_mod:get_opt(auth_type, Opts, anonymous), Shaper = gen_mod:get_opt(shaper, Opts, none), - RecvBuf = gen_mod:get_opt(recbuf, Opts, 65535), - SendBuf = gen_mod:get_opt(sndbuf, Opts, 65535), + RecvBuf = gen_mod:get_opt(recbuf, Opts, 8192), + SendBuf = gen_mod:get_opt(sndbuf, Opts, 8192), TRef = erlang:send_after(?WAIT_TIMEOUT, self(), stop), inet:setopts(Socket, [{active, true}, {recbuf, RecvBuf}, {sndbuf, SendBuf}]), {ok, wait_for_init, #state{host = Host, From 18ae44f9302ab0c884b234927e4def295c535167 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Mon, 25 May 2009 17:16:54 +0000 Subject: [PATCH 318/582] Support LDAPS with TLS (EJAB-109)(thanks to Thomas Baden, Andy Harb, Sergei Golovan, Anton Podavalov) SVN Revision: 2099 --- doc/guide.html | 17 ++++-- doc/guide.tex | 17 ++++-- src/ejabberd.cfg.example | 19 +++++-- src/ejabberd_auth_ldap.erl | 15 ++++-- src/eldap/eldap.erl | 107 ++++++++++++++++++++++++++++--------- src/eldap/eldap.hrl | 3 ++ src/eldap/eldap_pool.erl | 6 +-- src/mod_vcard_ldap.erl | 24 +++++++-- 8 files changed, 159 insertions(+), 49 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 3bd1d7a2b..09176d608 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -1532,12 +1532,15 @@ create accounts, change password or edit vCard that is stored in LDAP.</P><P> <A </P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>ldap_servers</TT></B></DT><DD CLASS="dd-description"> List of IP addresses or DNS names of your LDAP servers. This option is required. +</DD><DT CLASS="dt-description"><B><TT>ldap_encrypt</TT></B></DT><DD CLASS="dd-description"> Type of connection encryption to the LDAP server. +Allowed values are: <TT>none</TT>, <TT>tls</TT>. +Note that STARTTLS is not supported. +The default value is: <TT>none</TT>. </DD><DT CLASS="dt-description"><B><TT>ldap_port</TT></B></DT><DD CLASS="dd-description"> Port to connect to your LDAP server. -The initial default value is 389, so it is used when nothing is set into the -configuration file. +The default port is 389 if encryption is disabled; and 636 if encryption is enabled. If you configure a value, it is stored in <TT>ejabberd</TT>’s database. Then, if you remove that value from the configuration file, -the value previously stored in the database will be used instead of the default 389. +the value previously stored in the database will be used instead of the default port. </DD><DT CLASS="dt-description"><B><TT>ldap_rootdn</TT></B></DT><DD CLASS="dd-description"> Bind DN. The default value is <TT>""</TT> which means ‘anonymous connection’. </DD><DT CLASS="dt-description"><B><TT>ldap_password</TT></B></DT><DD CLASS="dd-description"> Bind password. The default @@ -1592,14 +1595,18 @@ Example values: <H5 CLASS="paragraph"><!--SEC ANCHOR --><A HREF="#ldapcommonexample">Common example</A></H5><!--SEC END --><P> <A NAME="ldapcommonexample"></A> </P><P>Let’s say <TT>ldap.example.org</TT> is the name of our LDAP server. We have users with their passwords in <TT>"ou=Users,dc=example,dc=org"</TT> directory. Also we have addressbook, which contains users emails and their additional -infos in <TT>"ou=AddressBook,dc=example,dc=org"</TT> directory. Corresponding -authentication section should looks like this:</P><PRE CLASS="verbatim">%% Authentication method +infos in <TT>"ou=AddressBook,dc=example,dc=org"</TT> directory. +The connection to the LDAP server is encrypted using TLS, +and using the custom port 6123. +Corresponding authentication section should looks like this:</P><PRE CLASS="verbatim">%% Authentication method {auth_method, ldap}. %% DNS name of our LDAP server {ldap_servers, ["ldap.example.org"]}. %% Bind to LDAP server as "cn=Manager,dc=example,dc=org" with password "secret" {ldap_rootdn, "cn=Manager,dc=example,dc=org"}. {ldap_password, "secret"}. +{ldap_encrypt, tls}. +{ldap_port, 6123}. %% Define the user's base {ldap_base, "ou=Users,dc=example,dc=org"}. %% We want to authorize users from 'shadowAccount' object class only diff --git a/doc/guide.tex b/doc/guide.tex index 404abcd32..195fb875e 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -2057,12 +2057,15 @@ Parameters: \begin{description} \titem{ldap\_servers} \ind{options!ldap\_server}List of IP addresses or DNS names of your LDAP servers. This option is required. +\titem{ldap\_encrypt} \ind{options!ldap\_encrypt}Type of connection encryption to the LDAP server. +Allowed values are: \term{none}, \term{tls}. +Note that STARTTLS is not supported. +The default value is: \term{none}. \titem{ldap\_port} \ind{options!ldap\_port}Port to connect to your LDAP server. - The initial default value is~389, so it is used when nothing is set into the -configuration file. +The default port is~389 if encryption is disabled; and 636 if encryption is enabled. If you configure a value, it is stored in \ejabberd{}'s database. Then, if you remove that value from the configuration file, -the value previously stored in the database will be used instead of the default 389. +the value previously stored in the database will be used instead of the default port. \titem{ldap\_rootdn} \ind{options!ldap\_rootdn}Bind DN. The default value is~\term{""} which means `anonymous connection'. \titem{ldap\_password} \ind{options!ldap\_password}Bind password. The default @@ -2137,8 +2140,10 @@ You can authenticate users against an LDAP directory. Available options are: Let's say \term{ldap.example.org} is the name of our LDAP server. We have users with their passwords in \term{"ou=Users,dc=example,dc=org"} directory. Also we have addressbook, which contains users emails and their additional -infos in \term{"ou=AddressBook,dc=example,dc=org"} directory. Corresponding -authentication section should looks like this: +infos in \term{"ou=AddressBook,dc=example,dc=org"} directory. +The connection to the LDAP server is encrypted using TLS, +and using the custom port 6123. +Corresponding authentication section should looks like this: \begin{verbatim} %% Authentication method @@ -2148,6 +2153,8 @@ authentication section should looks like this: %% Bind to LDAP server as "cn=Manager,dc=example,dc=org" with password "secret" {ldap_rootdn, "cn=Manager,dc=example,dc=org"}. {ldap_password, "secret"}. +{ldap_encrypt, tls}. +{ldap_port, 6123}. %% Define the user's base {ldap_base, "ou=Users,dc=example,dc=org"}. %% We want to authorize users from 'shadowAccount' object class only diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index 9f8c34b24..7161e5e34 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -234,17 +234,28 @@ %% List of LDAP servers: %%{ldap_servers, ["localhost"]}. %% -%% LDAP attribute that holds user ID: -%%{ldap_uids, [{"mail", "%u@mail.example.org"}]}. +%% Encryption of connection to LDAP servers: +%%{ldap_encrypt, none}. +%%{ldap_encrypt, tls}. %% -%% Search base of LDAP directory: -%%{ldap_base, "dc=example,dc=com"}. +%% Port connect to LDAP servers: +%%{ldap_port, 389}. +%%{ldap_port, 636}. %% %% LDAP manager: %%{ldap_rootdn, "dc=example,dc=com"}. %% %% Password to LDAP manager: %%{ldap_password, "******"}. +%% +%% Search base of LDAP directory: +%%{ldap_base, "dc=example,dc=com"}. +%% +%% LDAP attribute that holds user ID: +%%{ldap_uids, [{"mail", "%u@mail.example.org"}]}. +%% +%% LDAP filter: +%%{ldap_filter, "(objectClass=shadowAccount)"}. %% %% Anonymous login support: diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl index 7a31d6bae..a373a0678 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -66,6 +66,7 @@ servers, backups, port, + encrypt, dn, password, base, @@ -137,13 +138,15 @@ init(Host) -> State#state.backups, State#state.port, State#state.dn, - State#state.password), + State#state.password, + State#state.encrypt), eldap_pool:start_link(State#state.bind_eldap_id, State#state.servers, State#state.backups, State#state.port, State#state.dn, - State#state.password), + State#state.password, + State#state.encrypt), {ok, State}. %% @spec () -> true @@ -443,8 +446,13 @@ parse_options(Host) -> undefined -> []; Backups -> Backups end, + LDAPEncrypt = ejabberd_config:get_local_option({ldap_encrypt, Host}), LDAPPort = case ejabberd_config:get_local_option({ldap_port, Host}) of - undefined -> 389; + undefined -> case LDAPEncrypt of + tls -> ?LDAPS_PORT; + starttls -> ?LDAP_PORT; + _ -> ?LDAP_PORT + end; P -> P end, RootDN = case ejabberd_config:get_local_option({ldap_rootdn, Host}) of @@ -479,6 +487,7 @@ parse_options(Host) -> servers = LDAPServers, backups = LDAPBackups, port = LDAPPort, + encrypt = LDAPEncrypt, dn = RootDN, password = Password, base = LDAPBase, diff --git a/src/eldap/eldap.erl b/src/eldap/eldap.erl index 6a16b9b54..3c3e736ae 100644 --- a/src/eldap/eldap.erl +++ b/src/eldap/eldap.erl @@ -42,6 +42,12 @@ %%% Modified by Mickael Remond <mremond@process-one.net> %%% Now use ejabberd log mechanism +%%% Modified by: +%%% Thomas Baden <roo@ham9.net> 2008 April 6th +%%% Andy Harb <Ahmad.N.Abou-Harb@jpl.nasa.gov> 2008 April 28th +%%% Anton Podavalov <a.podavalov@gmail.com> 2009 February 22th +%%% Added LDAPS support, modeled off jungerl eldap.erl version. +%%% NOTICE: STARTTLS is not supported. %%% -------------------------------------------------------------------- -vc('$Id$ '). @@ -61,7 +67,7 @@ -include("ejabberd.hrl"). %% External exports --export([start_link/1, start_link/5]). +-export([start_link/1, start_link/6]). -export([baseObject/0,singleLevel/0,wholeSubtree/0,close/1, equalityMatch/2,greaterOrEqual/2,lessOrEqual/2, @@ -94,10 +100,17 @@ %% Grace period after "soft" LDAP bind errors: -define(GRACEFUL_RETRY_TIMEOUT, 5000). +-define(SUPPORTEDEXTENSION, "1.3.6.1.4.1.1466.101.120.7"). +-define(SUPPORTEDEXTENSIONSYNTAX, "1.3.6.1.4.1.1466.115.121.1.38"). +-define(STARTTLS, "1.3.6.1.4.1.1466.20037"). + -record(eldap, {version = ?LDAP_VERSION, hosts, % Possible hosts running LDAP servers host = null, % Connected Host LDAP server port = 389, % The LDAP server port + sockmod, % SockMod (gen_tcp|tls) + tls = none, % LDAP/LDAPS (none|starttls|tls) + tls_options = [], fd = null, % Socket filedescriptor. rootdn = "", % Name of the entry to bind as passwd, % Password for (above) entry @@ -114,9 +127,9 @@ start_link(Name) -> Reg_name = list_to_atom("eldap_" ++ Name), gen_fsm:start_link({local, Reg_name}, ?MODULE, [], []). -start_link(Name, Hosts, Port, Rootdn, Passwd) -> +start_link(Name, Hosts, Port, Rootdn, Passwd, Encrypt) -> Reg_name = list_to_atom("eldap_" ++ Name), - gen_fsm:start_link({local, Reg_name}, ?MODULE, {Hosts, Port, Rootdn, Passwd}, []). + gen_fsm:start_link({local, Reg_name}, ?MODULE, {Hosts, Port, Rootdn, Passwd, Encrypt}, []). %%% -------------------------------------------------------------------- %%% Get status of connection. @@ -380,16 +393,34 @@ get_handle(Name) when is_list(Name) -> list_to_atom("eldap_" ++ Name). %%---------------------------------------------------------------------- init([]) -> case get_config() of - {ok, Hosts, Rootdn, Passwd} -> - init({Hosts, Rootdn, Passwd}); + {ok, Hosts, Rootdn, Passwd, Encrypt} -> + init({Hosts, Rootdn, Passwd, Encrypt}); {error, Reason} -> {stop, Reason} end; -init({Hosts, Port, Rootdn, Passwd}) -> +init({Hosts, Port, Rootdn, Passwd, Encrypt}) -> + catch ssl:start(), + {X1,X2,X3} = erlang:now(), + ssl:seed(integer_to_list(X1) ++ integer_to_list(X2) ++ integer_to_list(X3)), + PortTemp = case Port of + undefined -> + case Encrypt of + tls -> + ?LDAPS_PORT; + starttls -> + ?LDAP_PORT; + _ -> + ?LDAP_PORT + end; + PT -> PT + end, + TLSOpts = [verify_none], {ok, connecting, #eldap{hosts = Hosts, - port = Port, + port = PortTemp, rootdn = Rootdn, passwd = Passwd, + tls = Encrypt, + tls_options = TLSOpts, id = 0, dict = dict:new(), req_q = queue:new()}, 0}. @@ -438,7 +469,7 @@ active(Event, From, S) -> %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- handle_event(close, _StateName, S) -> - catch gen_tcp:close(S#eldap.fd), + catch (S#eldap.sockmod):close(S#eldap.fd), {stop, normal, S}; handle_event(_Event, StateName, S) -> @@ -467,11 +498,13 @@ handle_sync_event(_Event, _From, StateName, S) -> %% %% Packets arriving in various states %% -handle_info({tcp, _Socket, Data}, connecting, S) -> +handle_info({Tag, _Socket, Data}, connecting, S) + when Tag == tcp; Tag == ssl -> ?DEBUG("tcp packet received when disconnected!~n~p", [Data]), {next_state, connecting, S}; -handle_info({tcp, _Socket, Data}, wait_bind_response, S) -> +handle_info({Tag, _Socket, Data}, wait_bind_response, S) + when Tag == tcp; Tag == ssl -> cancel_timer(S#eldap.bind_timer), case catch recvd_wait_bind_response(Data, S) of bound -> @@ -487,8 +520,9 @@ handle_info({tcp, _Socket, Data}, wait_bind_response, S) -> {next_state, connecting, close_and_retry(S)} end; -handle_info({tcp, _Socket, Data}, StateName, S) - when StateName == active orelse StateName == active_bind -> +handle_info({Tag, _Socket, Data}, StateName, S) + when (StateName == active orelse StateName == active_bind) andalso + (Tag == tcp orelse Tag == ssl) -> case catch recvd_packet(Data, S) of {response, Response, RequestType} -> NewS = case Response of @@ -509,12 +543,14 @@ handle_info({tcp, _Socket, Data}, StateName, S) {next_state, StateName, S} end; -handle_info({tcp_closed, _Socket}, Fsm_state, S) -> +handle_info({Tag, _Socket}, Fsm_state, S) + when Tag == tcp_closed; Tag == ssl_closed -> ?WARNING_MSG("LDAP server closed the connection: ~s:~p~nIn State: ~p", [S#eldap.host, S#eldap.port ,Fsm_state]), {next_state, connecting, close_and_retry(S)}; -handle_info({tcp_error, _Socket, Reason}, Fsm_state, S) -> +handle_info({Tag, _Socket, Reason}, Fsm_state, S) + when Tag == tcp_error; Tag == ssl_error -> ?DEBUG("eldap received tcp_error: ~p~nIn State: ~p", [Reason, Fsm_state]), {next_state, connecting, close_and_retry(S)}; @@ -597,7 +633,7 @@ send_command(Command, From, S) -> protocolOp = {Name, Request}}, ?DEBUG("~p~n",[{Name, Request}]), {ok, Bytes} = asn1rt:encode('ELDAPv3', 'LDAPMessage', Message), - case gen_tcp:send(S#eldap.fd, Bytes) of + case (S#eldap.sockmod):send(S#eldap.fd, Bytes) of ok -> Timer = erlang:start_timer(?CMD_TIMEOUT, self(), {cmd_timeout, Id}), New_dict = dict:store(Id, [{Timer, Command, From, Name}], S#eldap.dict), @@ -796,7 +832,7 @@ check_tag(Data) -> end. close_and_retry(S, Timeout) -> - catch gen_tcp:close(S#eldap.fd), + catch (S#eldap.sockmod):close(S#eldap.fd), Queue = dict:fold( fun(_Id, [{Timer, Command, From, _Name}|_], Q) -> cancel_timer(Timer), @@ -863,16 +899,28 @@ polish([], Res, Ref) -> %%----------------------------------------------------------------------- connect_bind(S) -> Host = next_host(S#eldap.host, S#eldap.hosts), - TcpOpts = [{packet, asn1}, {active, true}, {keepalive, true}, - {send_timeout, ?SEND_TIMEOUT}, binary], ?INFO_MSG("LDAP connection on ~s:~p", [Host, S#eldap.port]), - case gen_tcp:connect(Host, S#eldap.port, TcpOpts) of + SocketData = case S#eldap.tls of + tls -> + SockMod = ssl, + SslOpts = [{packet, asn1}, {active, true}, {keepalive, true}, + binary], + ssl:connect(Host, S#eldap.port, SslOpts); + %% starttls -> %% TODO: Implement STARTTLS; + _ -> + SockMod = gen_tcp, + TcpOpts = [{packet, asn1}, {active, true}, {keepalive, true}, + {send_timeout, ?SEND_TIMEOUT}, binary], + gen_tcp:connect(Host, S#eldap.port, TcpOpts) + end, + case SocketData of {ok, Socket} -> - case bind_request(Socket, S) of + case bind_request(Socket, S#eldap{sockmod = SockMod}) of {ok, NewS} -> Timer = erlang:start_timer(?BIND_TIMEOUT, self(), {timeout, bind_timeout}), {ok, wait_bind_response, NewS#eldap{fd = Socket, + sockmod = SockMod, host = Host, bind_timer = Timer}}; {error, Reason} -> @@ -896,7 +944,7 @@ bind_request(Socket, S) -> protocolOp = {bindRequest, Req}}, ?DEBUG("Bind Request Message:~p~n",[Message]), {ok, Bytes} = asn1rt:encode('ELDAPv3', 'LDAPMessage', Message), - case gen_tcp:send(Socket, Bytes) of + case (S#eldap.sockmod):send(Socket, Bytes) of ok -> {ok, S#eldap{id = Id}}; Error -> Error end. @@ -970,8 +1018,8 @@ get_config() -> case file:consult(File) of {ok, Entries} -> case catch parse(Entries) of - {ok, Hosts, Port, Rootdn, Passwd} -> - {ok, Hosts, Port, Rootdn, Passwd}; + {ok, Hosts, Port, Rootdn, Passwd, Encrypt} -> + {ok, Hosts, Port, Rootdn, Passwd, Encrypt}; {error, Reason} -> {error, Reason}; {'EXIT', Reason} -> @@ -986,7 +1034,8 @@ parse(Entries) -> get_hosts(host, Entries), get_integer(port, Entries), get_list(rootdn, Entries), - get_list(passwd, Entries)}. + get_list(passwd, Entries), + get_atom(encrypt, Entries)}. get_integer(Key, List) -> case lists:keysearch(Key, 1, List) of @@ -1008,6 +1057,16 @@ get_list(Key, List) -> throw({error, "No Entry in Config for " ++ atom_to_list(Key)}) end. +get_atom(Key, List) -> + case lists:keysearch(Key, 1, List) of + {value, {Key, Value}} when 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. + get_hosts(Key, List) -> lists:map(fun({Key1, {A,B,C,D}}) when is_integer(A), is_integer(B), diff --git a/src/eldap/eldap.hrl b/src/eldap/eldap.hrl index 5ffc464c9..95aa6f9c5 100644 --- a/src/eldap/eldap.hrl +++ b/src/eldap/eldap.hrl @@ -19,6 +19,9 @@ %%% %%%---------------------------------------------------------------------- +-define(LDAP_PORT, 389). +-define(LDAPS_PORT, 636). + -record(eldap_search, {scope = wholeSubtree, base = [], filter, diff --git a/src/eldap/eldap_pool.erl b/src/eldap/eldap_pool.erl index f714129b5..d7f3acfab 100644 --- a/src/eldap/eldap_pool.erl +++ b/src/eldap/eldap_pool.erl @@ -29,7 +29,7 @@ %% API -export([ - start_link/6, + start_link/7, bind/3, search/2 ]). @@ -45,12 +45,12 @@ bind(PoolName, DN, Passwd) -> search(PoolName, Opts) -> do_request(PoolName, {search, [Opts]}). -start_link(Name, Hosts, Backups, Port, Rootdn, Passwd) -> +start_link(Name, Hosts, Backups, Port, Rootdn, Passwd, Encrypt) -> PoolName = make_id(Name), pg2:create(PoolName), lists:foreach(fun(Host) -> ID = erlang:ref_to_list(make_ref()), - case catch eldap:start_link(ID, [Host|Backups], Port, Rootdn, Passwd) of + case catch eldap:start_link(ID, [Host|Backups], Port, Rootdn, Passwd, Encrypt) of {ok, Pid} -> pg2:join(PoolName, Pid); _ -> diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index 4f907be80..148d6b0af 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -63,6 +63,7 @@ servers, backups, port, + encrypt, dn, base, password, @@ -183,7 +184,8 @@ init([Host, Opts]) -> State#state.backups, State#state.port, State#state.dn, - State#state.password), + State#state.password, + State#state.encrypt), case State#state.search of true -> ejabberd_router:register_route(State#state.myhost); @@ -653,11 +655,22 @@ parse_options(Host, Opts) -> ejabberd_config:get_local_option({ldap_servers, Host}); Backups -> Backups end, - LDAPPort = case gen_mod:get_opt(ldap_port, Opts, undefined) of + LDAPEncrypt = case gen_mod:get_opt(ldap_encrypt, Opts, undefined) of + undefined -> + ejabberd_config:get_local_option({ldap_encrypt, Host}); + E -> E + end, + LDAPPortTemp = case gen_mod:get_opt(ldap_port, Opts, undefined) of + undefined -> + ejabberd_config:get_local_option({ldap_port, Host}); + PT -> PT + end, + LDAPPort = case LDAPPortTemp of undefined -> - case ejabberd_config:get_local_option({ldap_port, Host}) of - undefined -> 389; - P -> P + case LDAPEncrypt of + tls -> ?LDAPS_PORT; + starttls -> ?LDAP_PORT; + _ -> ?LDAP_PORT end; P -> P end, @@ -727,6 +740,7 @@ parse_options(Host, Opts) -> servers = LDAPServers, backups = LDAPBackups, port = LDAPPort, + encrypt = LDAPEncrypt, dn = RootDN, base = LDAPBase, password = Password, From 55bebb0f620c356117f2664d2b0491e47edeba02 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 26 May 2009 17:20:09 +0000 Subject: [PATCH 319/582] Implement XEP-158 CAPTCHA Forms, support in mod_muc, sample script (thanks to Evgeniy Khramtsov)(EJAB-895) SVN Revision: 2102 --- src/ejabberd_captcha.erl | 389 +++++++++++++++++++++++++++++++++++ src/ejabberd_config.erl | 4 + src/ejabberd_sup.erl | 8 + src/jlib.hrl | 6 + src/mod_muc/mod_muc_room.erl | 115 +++++++++-- src/mod_muc/mod_muc_room.hrl | 2 + src/web/ejabberd_http.erl | 4 + tools/captcha.sh | 21 ++ 8 files changed, 535 insertions(+), 14 deletions(-) create mode 100644 src/ejabberd_captcha.erl create mode 100644 tools/captcha.sh diff --git a/src/ejabberd_captcha.erl b/src/ejabberd_captcha.erl new file mode 100644 index 000000000..8813d82d2 --- /dev/null +++ b/src/ejabberd_captcha.erl @@ -0,0 +1,389 @@ +%%%------------------------------------------------------------------- +%%% File : ejabberd_captcha.erl +%%% Author : Evgeniy Khramtsov <xramtsov@gmail.com> +%%% Description : CAPTCHA processing. +%%% +%%% Created : 26 Apr 2008 by Evgeniy Khramtsov <xramtsov@gmail.com> +%%%------------------------------------------------------------------- +-module(ejabberd_captcha). + +-behaviour(gen_server). + +%% API +-export([start_link/0]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +-export([create_captcha/6, build_captcha_html/2, check_captcha/2, + process_reply/1, process/2, is_feature_available/0]). + +-include_lib("exmpp/include/exmpp.hrl"). + +-include("jlib.hrl"). +-include("ejabberd.hrl"). +-include("web/ejabberd_http.hrl"). + +-define(VFIELD(Type, Var, Value), + {xmlelement, "field", [{"type", Type}, {"var", Var}], + [{xmlelement, "value", [], [Value]}]}). + +-define(CAPTCHA_TEXT(Lang), translate:translate(Lang, "Enter the text you see")). +-define(CAPTCHA_LIFETIME, 120000). % two minutes + +-record(state, {}). +-record(captcha, {id, pid, key, tref, args}). + +-define(T(S), + case catch mnesia:transaction(fun() -> S end) of + {atomic, Res} -> + Res; + {_, Reason} -> + ?ERROR_MSG("mnesia transaction failed: ~p", [Reason]), + {error, Reason} + end). + +%%==================================================================== +%% API +%%==================================================================== +%%-------------------------------------------------------------------- +%% Function: start_link() -> {ok,Pid} | ignore | {error,Error} +%% Description: Starts the server +%%-------------------------------------------------------------------- +start_link() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). + +create_captcha(Id, SID, From, To, Lang, Args) + when is_list(Id), is_list(SID) -> + case create_image() of + {ok, Type, Key, Image} -> + B64Image = jlib:encode_base64(binary_to_list(Image)), + JID = exmpp_jid:jid_to_list(From), + CID = "sha1+" ++ sha:sha(Image) ++ "@bob.xmpp.org", + Data = {xmlelement, "data", + [{"xmlns", ?NS_BOB}, {"cid", CID}, + {"max-age", "0"}, {"type", Type}], + [{xmlcdata, B64Image}]}, + Captcha = + {xmlelement, "captcha", [{"xmlns", ?NS_CAPTCHA}], + %% ?NS_DATA_FORMS is 'jabber:x:data' + [{xmlelement, "x", [{"xmlns", "jabber:x:data"}, {"type", "form"}], + [?VFIELD("hidden", "FORM_TYPE", {xmlcdata, ?NS_CAPTCHA}), + ?VFIELD("hidden", "from", {xmlcdata, exmpp_jid:jid_to_list(To)}), + ?VFIELD("hidden", "challenge", {xmlcdata, Id}), + ?VFIELD("hidden", "sid", {xmlcdata, SID}), + {xmlelement, "field", [{"var", "ocr"}, {"label", ?CAPTCHA_TEXT(Lang)}], + [{xmlelement, "media", [{"xmlns", ?NS_MEDIA}], + [{xmlelement, "uri", [{"type", Type}], + [{xmlcdata, "cid:" ++ CID}]}]}]}]}]}, + BodyString1 = translate:translate(Lang, "Your messages to ~s are being blocked. To unblock them, visit ~s"), + BodyString = io_lib:format(BodyString1, [JID, get_url(Id)]), + Body = {xmlelement, "body", [], + [{xmlcdata, BodyString}]}, + OOB = {xmlelement, "x", [{"xmlns", ?NS_OOB}], + [{xmlelement, "url", [], [{xmlcdata, get_url(Id)}]}]}, + Tref = erlang:send_after(?CAPTCHA_LIFETIME, ?MODULE, {remove_id, Id}), + case ?T(mnesia:write(#captcha{id=Id, pid=self(), key=Key, + tref=Tref, args=Args})) of + ok -> + {ok, [Body, OOB, Captcha, Data]}; + _Err -> + error + end; + _Err -> + error + 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() +build_captcha_html(Id, Lang) -> + case mnesia:dirty_read(captcha, Id) of + [#captcha{}] -> + ImgEl = {xmlelement, "img", [{"src", get_url(Id ++ "/image")}], []}, + TextEl = {xmlcdata, ?CAPTCHA_TEXT(Lang)}, + IdEl = {xmlelement, "input", [{"type", "hidden"}, + {"name", "id"}, + {"value", Id}], []}, + KeyEl = {xmlelement, "input", [{"type", "text"}, + {"name", "key"}, + {"size", "10"}], []}, + FormEl = {xmlelement, "form", [{"action", get_url(Id)}, + {"name", "captcha"}, + {"method", "POST"}], + [ImgEl, + {xmlelement, "br", [], []}, + TextEl, + {xmlelement, "br", [], []}, + IdEl, + KeyEl, + {xmlelement, "br", [], []}, + {xmlelement, "input", [{"type", "submit"}, + {"name", "enter"}, + {"value", "OK"}], []} + ]}, + {FormEl, {ImgEl, TextEl, IdEl, KeyEl}}; + _ -> + captcha_not_found + end. + +%% @spec (Id::string(), ProvidedKey::string()) -> captcha_valid | captcha_non_valid | captcha_not_found +check_captcha(Id, ProvidedKey) -> + ?T(case mnesia:read(captcha, Id, write) of + [#captcha{pid=Pid, args=Args, key=StoredKey, tref=Tref}] -> + mnesia:delete({captcha, Id}), + erlang:cancel_timer(Tref), + if StoredKey == ProvidedKey -> + Pid ! {captcha_succeed, Args}, + captcha_valid; + true -> + Pid ! {captcha_failed, Args}, + captcha_non_valid + end; + _ -> + captcha_not_found + end). + +process_reply(El) -> + case {exmpp_xml:element_matches(El, captcha), + exmpp_xml:get_element(El, x)} of + {false, _} -> + {error, malformed}; + {_, undefined} -> + {error, malformed}; + {true, Xdata} -> + Fields = jlib:parse_xdata_submit(Xdata), + [Id | _] = proplists:get_value("challenge", Fields, [none]), + [OCR | _] = proplists:get_value("ocr", Fields, [none]), + ?T(case mnesia:read(captcha, Id, write) of + [#captcha{pid=Pid, args=Args, key=Key, tref=Tref}] -> + mnesia:delete({captcha, Id}), + erlang:cancel_timer(Tref), + if OCR == Key -> + Pid ! {captcha_succeed, Args}, + ok; + true -> + Pid ! {captcha_failed, Args}, + {error, bad_match} + end; + _ -> + {error, not_found} + end) + end. + + +process(_Handlers, #request{method='GET', lang=Lang, path=[_, Id]}) -> + case build_captcha_html(Id, Lang) of + {FormEl, _} when is_tuple(FormEl) -> + Form = + {xmlelement, "div", [{"align", "center"}], + [FormEl]}, + ejabberd_web:make_xhtml([Form]); + captcha_not_found -> + ejabberd_web:error(not_found) + end; + +process(_Handlers, #request{method='GET', path=[_, Id, "image"]}) -> + case mnesia:dirty_read(captcha, Id) of + [#captcha{key=Key}] -> + case create_image(Key) of + {ok, Type, _, Img} -> + {200, + [{"Content-Type", Type}, + {"Cache-Control", "no-cache"}, + {"Last-Modified", httpd_util:rfc1123_date()}], + Img}; + _ -> + ejabberd_web:error(not_found) + end; + _ -> + ejabberd_web:error(not_found) + end; + +process(_Handlers, #request{method='POST', q=Q, lang=Lang, path=[_, Id]}) -> + ProvidedKey = proplists:get_value("key", Q, none), + case check_captcha(Id, ProvidedKey) of + captcha_valid -> + Form = + {xmlelement, "p", [], + [{xmlcdata, + translate:translate(Lang, "The captcha is valid.") + }]}, + ejabberd_web:make_xhtml([Form]); + captcha_non_valid -> + ejabberd_web:error(not_allowed); + captcha_not_found -> + ejabberd_web:error(not_found) + end. + + +%%==================================================================== +%% gen_server callbacks +%%==================================================================== +init([]) -> + mnesia:create_table(captcha, + [{ram_copies, [node()]}, + {attributes, record_info(fields, captcha)}]), + mnesia:add_table_copy(captcha, node(), ram_copies), + check_captcha_setup(), + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, bad_request, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info({remove_id, Id}, State) -> + ?DEBUG("captcha ~p timed out", [Id]), + _ = ?T(case mnesia:read(captcha, Id, write) of + [#captcha{args=Args, pid=Pid}] -> + Pid ! {captcha_failed, Args}, + mnesia:delete({captcha, Id}); + _ -> + ok + end), + {noreply, State}; + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +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() -> + %% Six numbers from 1 to 9. + Key = string:substr(randoms:get_string(), 1, 6), + create_image(Key). + +create_image(Key) -> + FileName = get_prog_name(), + Cmd = lists:flatten(io_lib:format("~s ~s", [FileName, Key])), + case cmd(Cmd) of + {ok, <<16#89, $P, $N, $G, $\r, $\n, 16#1a, $\n, _/binary>> = Img} -> + {ok, "image/png", Key, Img}; + {ok, <<16#ff, 16#d8, _/binary>> = Img} -> + {ok, "image/jpeg", Key, Img}; + {ok, <<$G, $I, $F, $8, X, $a, _/binary>> = Img} when X==$7; X==$9 -> + {ok, "image/gif", Key, Img}; + {error, enodata = Reason} -> + ?ERROR_MSG("Failed to process output from \"~s\". " + "Maybe ImageMagick's Convert program is not installed.", + [Cmd]), + {error, Reason}; + {error, Reason} -> + ?ERROR_MSG("Failed to process an output from \"~s\": ~p", + [Cmd, Reason]), + {error, Reason}; + _ -> + Reason = malformed_image, + ?ERROR_MSG("Failed to process an output from \"~s\": ~p", + [Cmd, Reason]), + {error, Reason} + end. + +get_prog_name() -> + case ejabberd_config:get_local_option(captcha_cmd) of + FileName when is_list(FileName) -> + FileName; + _ -> + "" + end. + +get_url(Str) -> + case ejabberd_config:get_local_option(captcha_host) of + Host when is_list(Host) -> + "http://" ++ Host ++ "/captcha/" ++ Str; + _ -> + "http://" ++ ?MYNAME ++ "/captcha/" ++ Str + end. + +%%-------------------------------------------------------------------- +%% Function: cmd(Cmd) -> Data | {error, Reason} +%% Cmd = string() +%% Data = binary() +%% Description: os:cmd/1 replacement +%%-------------------------------------------------------------------- +-define(CMD_TIMEOUT, 5000). +-define(MAX_FILE_SIZE, 64*1024). + +cmd(Cmd) -> + Port = open_port({spawn, Cmd}, [stream, eof, binary]), + TRef = erlang:start_timer(?CMD_TIMEOUT, self(), timeout), + recv_data(Port, TRef, <<>>). + +recv_data(Port, TRef, Buf) -> + receive + {Port, {data, Bytes}} -> + NewBuf = <<Buf/binary, Bytes/binary>>, + if size(NewBuf) > ?MAX_FILE_SIZE -> + return(Port, TRef, {error, efbig}); + true -> + recv_data(Port, TRef, NewBuf) + end; + {Port, {data, _}} -> + return(Port, TRef, {error, efbig}); + {Port, eof} when Buf /= <<>> -> + return(Port, TRef, {ok, Buf}); + {Port, eof} -> + return(Port, TRef, {error, enodata}); + {timeout, TRef, _} -> + return(Port, TRef, {error, timeout}) + end. + +return(Port, TRef, Result) -> + case erlang:cancel_timer(TRef) of + false -> + receive + {timeout, TRef, _} -> + ok + after 0 -> + ok + end; + _ -> + ok + end, + catch port_close(Port), + Result. + +is_feature_enabled() -> + case get_prog_name() of + "" -> false; + Prog when is_list(Prog) -> true + end. + +is_feature_available() -> + case is_feature_enabled() of + false -> false; + true -> + case create_image() of + {ok, _, _, _} -> true; + _Error -> false + end + end. + +check_captcha_setup() -> + case is_feature_enabled() andalso not is_feature_available() of + true -> + ?CRITICAL_MSG("Captcha is enabled in the option captcha_cmd, " + "but it can't generate images.", []); + false -> + ok + end. diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index a5b47ed94..883e484b5 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -378,6 +378,10 @@ process_term(Term, State) -> add_option(registration_timeout, Timeout, State); {ejabberdctl_access_commands, ACs} -> add_option(ejabberdctl_access_commands, ACs, State); + {captcha_cmd, Cmd} -> + add_option(captcha_cmd, Cmd, State); + {captcha_host, Host} -> + add_option(captcha_host, Host, State); {loglevel, Loglevel} -> ejabberd_loglevel:set(Loglevel), State; diff --git a/src/ejabberd_sup.erl b/src/ejabberd_sup.erl index 7a650cc35..6163dfee0 100644 --- a/src/ejabberd_sup.erl +++ b/src/ejabberd_sup.erl @@ -84,6 +84,13 @@ init([]) -> brutal_kill, worker, [ejabberd_local]}, + Captcha = + {ejabberd_captcha, + {ejabberd_captcha, start_link, []}, + permanent, + brutal_kill, + worker, + [ejabberd_captcha]}, Listener = {ejabberd_listener, {ejabberd_listener, start_link, []}, @@ -170,6 +177,7 @@ init([]) -> SM, S2S, Local, + Captcha, ReceiverSupervisor, C2SSupervisor, S2SInSupervisor, diff --git a/src/jlib.hrl b/src/jlib.hrl index 479781431..02e419b28 100644 --- a/src/jlib.hrl +++ b/src/jlib.hrl @@ -19,5 +19,11 @@ %%% %%%---------------------------------------------------------------------- +%% CAPTCHA related NSes. +-define(NS_OOB, "jabber:x:oob"). +-define(NS_CAPTCHA, "urn:xmpp:captcha"). +-define(NS_MEDIA, "urn:xmpp:media-element"). +-define(NS_BOB, "urn:xmpp:bob"). + -record(rsm_in, {max, direction, id, index}). -record(rsm_out, {count, index, first, last}). diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 033c537a9..6c76008e5 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -50,6 +50,7 @@ -include("ejabberd.hrl"). -include("mod_muc_room.hrl"). +-include("jlib.hrl"). %% Used for captcha -define(MAX_USERS_DEFAULT_LIST, [5, 10, 20, 30, 50, 100, 200, 500, 1000, 2000, 5000]). @@ -329,7 +330,8 @@ normal_state({route, From, undefined, (XMLNS == ?NS_MUC_ADMIN) or (XMLNS == ?NS_MUC_OWNER) or (XMLNS == ?NS_DISCO_INFO) or - (XMLNS == ?NS_DISCO_ITEMS) -> + (XMLNS == ?NS_DISCO_ITEMS) or + (XMLNS == ?NS_CAPTCHA) -> Res1 = case XMLNS of ?NS_MUC_ADMIN -> process_iq_admin(From, Type, Lang, SubEl, StateData); @@ -338,7 +340,9 @@ normal_state({route, From, undefined, ?NS_DISCO_INFO -> process_iq_disco_info(From, Type, Lang, StateData); ?NS_DISCO_ITEMS -> - process_iq_disco_items(From, Type, Lang, StateData) + process_iq_disco_items(From, Type, Lang, StateData); + ?NS_CAPTCHA -> + process_iq_captcha(From, Type, Lang, SubEl, StateData) end, {IQRes, NewStateData} = case Res1 of @@ -707,6 +711,30 @@ handle_info(process_room_queue, normal_state = StateName, StateData) -> {empty, _} -> {next_state, StateName, StateData} end; +handle_info({captcha_succeed, From}, normal_state, StateData) -> + NewState = case ?DICT:find(From, StateData#state.robots) of + {ok, {Nick, Packet}} -> + Robots = ?DICT:store(From, passed, StateData#state.robots), + add_new_user(From, Nick, Packet, StateData#state{robots=Robots}); + _ -> + StateData + end, + {next_state, normal_state, NewState}; +handle_info({captcha_failed, From}, normal_state, StateData) -> + NewState = case ?DICT:find(From, StateData#state.robots) of + {ok, {Nick, Packet}} -> + Robots = ?DICT:erase(From, StateData#state.robots), + Err = exmpp_stanza:reply_with_error( + Packet, ?ERR(Packet, 'not-authorized', undefined, "")), + ejabberd_router:route( % TODO: s/Nick/""/ + jid_replace_resource( + StateData#state.jid, Nick), + From, Err), + StateData#state{robots=Robots}; + _ -> + StateData + end, + {next_state, normal_state, NewState}; handle_info(_Info, StateName, StateData) -> {next_state, StateName, StateData}. @@ -1512,8 +1540,8 @@ add_new_user(From, Nick, Packet, StateData) -> From, Err), StateData; {_, _, _, Role} -> - case check_password(ServiceAffiliation, - exmpp_xml:get_child_elements(Packet), + case check_password(ServiceAffiliation, Affiliation, + exmpp_xml:get_child_elements(Packet), From, StateData) of true -> NewState = @@ -1550,7 +1578,8 @@ add_new_user(From, Nick, Packet, StateData) -> true -> NewState#state{just_created = false}; false -> - NewState + Robots = ?DICT:erase(From, StateData#state.robots), + NewState#state{robots = Robots} end; nopass -> ErrText = "The password is required to enter this room", @@ -1561,6 +1590,29 @@ add_new_user(From, Nick, Packet, StateData) -> StateData#state.jid, Nick), From, Err), StateData; + captcha_required -> + ID = randoms:get_string(), + SID = case exmpp_stanza:get_id(Packet) of undefined -> ""; SID1 -> SID1 end, + RoomJID = StateData#state.jid, + To = jid_replace_resource(RoomJID, Nick), + case ejabberd_captcha:create_captcha( + ID, SID, RoomJID, To, Lang, From) of + {ok, CaptchaEls} -> + MsgPkt = {xmlelement, "message", [{"id", ID}], CaptchaEls}, + Robots = ?DICT:store(From, + {Nick, Packet}, StateData#state.robots), + ejabberd_router:route(RoomJID, From, MsgPkt), + StateData#state{robots = Robots}; + error -> + ErrText = "Unable to generate a captcha", + Err = exmpp_stanza:reply_with_error( + Packet, ?ERR(Packet, 'internal-server-error', Lang, ErrText)), + ejabberd_router:route( % TODO: s/Nick/""/ + jid_replace_resource( + StateData#state.jid, Nick), + From, Err), + StateData + end; _ -> ErrText = "Incorrect password", Err = exmpp_stanza:reply_with_error( @@ -1573,13 +1625,13 @@ add_new_user(From, Nick, Packet, StateData) -> end end. -check_password(owner, _Els, _StateData) -> +check_password(owner, _Affiliation, _Els, _From, _StateData) -> %% Don't check pass if user is owner in MUC service (access_admin option) true; -check_password(_ServiceAffiliation, Els, StateData) -> +check_password(_ServiceAffiliation, Affiliation, Els, From, StateData) -> case (StateData#state.config)#config.password_protected of false -> - true; + check_captcha(Affiliation, From, StateData); true -> Pass = extract_password(Els), case Pass of @@ -1590,11 +1642,25 @@ check_password(_ServiceAffiliation, Els, StateData) -> Pass -> true; _ -> - false + false end end end. +check_captcha(Affiliation, From, StateData) -> + case (StateData#state.config)#config.captcha_protected + andalso ejabberd_captcha:is_feature_available() of + true when Affiliation == none -> + case ?DICT:find(From, StateData#state.robots) of + {ok, passed} -> + true; + _ -> + captcha_required + end; + _ -> + true + end. + extract_password([]) -> false; extract_password([#xmlel{ns = XMLNS} = El | Els]) -> @@ -2758,8 +2824,9 @@ get_config(Lang, StateData, From) -> end, Res = [#xmlel{name = 'title', children = [ #xmlcdata{cdata = - translate:translate(Lang, "Configuration for ") ++ - exmpp_jid:jid_to_list(StateData#state.jid)}]}, + io_lib:format(translate:translate(Lang, "Configuration of room ~s"), + [exmpp_jid:jid_to_list(StateData#state.jid)]) + }]}, #xmlel{name = 'field', attrs = [?XMLATTR('type', <<"hidden">>), ?XMLATTR('var', <<"FORM_TYPE">>)], children = [#xmlel{name = 'value', children = [#xmlcdata{cdata = @@ -2865,9 +2932,14 @@ get_config(Lang, StateData, From) -> ?BOOLXFIELD("Allow visitors to change nickname", "muc#roomconfig_allowvisitornickchange", Config#config.allow_visitor_nickchange) - ] ++ - - + ] ++ + case ejabberd_captcha:is_feature_available() of + true -> + [?BOOLXFIELD("Make room captcha protected", + "captcha_protected", + Config#config.captcha_protected)]; + false -> [] + end ++ case mod_muc_log:check_access_log( StateData#state.server_host, From) of allow -> @@ -2954,6 +3026,8 @@ set_xoption([{"members_by_default", [Val]} | Opts], Config) -> ?SET_BOOL_XOPT(members_by_default, Val); set_xoption([{"muc#roomconfig_membersonly", [Val]} | Opts], Config) -> ?SET_BOOL_XOPT(members_only, Val); +set_xoption([{"captcha_protected", [Val]} | Opts], Config) -> + ?SET_BOOL_XOPT(captcha_protected, Val); set_xoption([{"muc#roomconfig_allowinvites", [Val]} | Opts], Config) -> ?SET_BOOL_XOPT(allow_user_invites, Val); set_xoption([{"muc#roomconfig_passwordprotectedroom", [Val]} | Opts], Config) -> @@ -3045,6 +3119,7 @@ set_opts([{Opt, Val} | Opts], StateData) -> members_only -> StateData#state{config = (StateData#state.config)#config{members_only = Val}}; allow_user_invites -> StateData#state{config = (StateData#state.config)#config{allow_user_invites = Val}}; password_protected -> StateData#state{config = (StateData#state.config)#config{password_protected = Val}}; + captcha_protected -> StateData#state{config = (StateData#state.config)#config{captcha_protected = Val}}; password -> StateData#state{config = (StateData#state.config)#config{password = Val}}; anonymous -> StateData#state{config = (StateData#state.config)#config{anonymous = Val}}; logging -> StateData#state{config = (StateData#state.config)#config{logging = Val}}; @@ -3087,6 +3162,7 @@ make_opts(StateData) -> ?MAKE_CONFIG_OPT(members_only), ?MAKE_CONFIG_OPT(allow_user_invites), ?MAKE_CONFIG_OPT(password_protected), + ?MAKE_CONFIG_OPT(captcha_protected), ?MAKE_CONFIG_OPT(password), ?MAKE_CONFIG_OPT(anonymous), ?MAKE_CONFIG_OPT(logging), @@ -3226,6 +3302,17 @@ process_iq_disco_items(From, get, _Lang, StateData) -> {error, 'forbidden'} end. +process_iq_captcha(_From, get, _Lang, _SubEl, _StateData) -> + {error, 'not-allowed'}; + +process_iq_captcha(_From, set, _Lang, SubEl, StateData) -> + case ejabberd_captcha:process_reply(SubEl) of + ok -> + {result, [], StateData}; + _ -> + {error, 'not-acceptable'} + end. + get_title(StateData) -> case (StateData#state.config)#config.title of "" -> diff --git a/src/mod_muc/mod_muc_room.hrl b/src/mod_muc/mod_muc_room.hrl index 3acf1013a..2ff1c1814 100644 --- a/src/mod_muc/mod_muc_room.hrl +++ b/src/mod_muc/mod_muc_room.hrl @@ -37,6 +37,7 @@ public_list = true, persistent = false, moderated = true, + captcha_protected = false, members_by_default = true, members_only = false, allow_user_invites = false, @@ -66,6 +67,7 @@ jid, config = #config{}, users = ?DICT:new(), + robots = ?DICT:new(), affiliations = ?DICT:new(), history, subject = "", diff --git a/src/web/ejabberd_http.erl b/src/web/ejabberd_http.erl index 71895bf3f..0310737b5 100644 --- a/src/web/ejabberd_http.erl +++ b/src/web/ejabberd_http.erl @@ -114,6 +114,10 @@ start_link({SockMod, Socket}, Opts) -> {value, {request_handlers, H}} -> H; false -> [] end ++ + case lists:member(captcha, Opts) of + true -> [{["captcha"], ejabberd_captcha}]; + false -> [] + end ++ case lists:member(web_admin, Opts) of true -> [{["admin"], ejabberd_web_admin}]; false -> [] diff --git a/tools/captcha.sh b/tools/captcha.sh new file mode 100644 index 000000000..2b18d93ad --- /dev/null +++ b/tools/captcha.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +SIGN=$(($RANDOM % 2)) + +R1=$(($RANDOM % 20)) +R2=$(($RANDOM % 10 + 40)) + +if [ $SIGN -eq "0" ]; then + S1=$(( -1*($RANDOM % 20 + 50) )) + S2=$(( $RANDOM % 20 + 50 )) +else + S2=$(( -1*($RANDOM % 20 + 50) )) + S1=$(( $RANDOM % 20 + 50 )) +fi + +convert -size 140x60 xc:white \ + -pointsize 30 -draw "text 20,30 '$1'" \ + -roll -$R2+$R1 -swirl $S1 \ + -roll +$R2-$R1 -swirl $S2 \ + +repage -resize 120x60 \ + -quality 90 -depth 8 png:- From 43a3fef7bbe75ae9331959ec3c0d2ebd0f46e12f Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 26 May 2009 17:20:50 +0000 Subject: [PATCH 320/582] Document how to setup CAPTCHA. Install example captcha.sh (EJAB-895) SVN Revision: 2103 --- doc/guide.html | 310 ++++++++++++++++++++++----------------- doc/guide.tex | 52 ++++++- src/Makefile.in | 1 + src/ejabberd.cfg.example | 17 ++- 4 files changed, 240 insertions(+), 140 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 09176d608..5188669ce 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -123,95 +123,96 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;} </LI><LI CLASS="li-toc"><A HREF="#htoc25">3.1.5  Access Rules</A> </LI><LI CLASS="li-toc"><A HREF="#htoc26">3.1.6  Shapers</A> </LI><LI CLASS="li-toc"><A HREF="#htoc27">3.1.7  Default Language</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc28">3.1.8  Include Additional Configuration Files</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc29">3.1.9  Option Macros in Configuration File</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc28">3.1.8  CAPTCHA</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc29">3.1.9  Include Additional Configuration Files</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc30">3.1.10  Option Macros in Configuration File</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc30">3.2  Database and LDAP Configuration</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc31">3.2  Database and LDAP Configuration</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc31">3.2.1  MySQL</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc32">3.2.2  Microsoft SQL Server</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc33">3.2.3  PostgreSQL</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc34">3.2.4  ODBC Compatible</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc35">3.2.5  LDAP</A> +<A HREF="#htoc32">3.2.1  MySQL</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc33">3.2.2  Microsoft SQL Server</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc34">3.2.3  PostgreSQL</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc35">3.2.4  ODBC Compatible</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc36">3.2.5  LDAP</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc36">3.3  Modules Configuration</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc37">3.3  Modules Configuration</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc37">3.3.1  Modules Overview</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc38">3.3.2  Common Options</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc39">3.3.3  <TT>mod_announce</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc40">3.3.4  <TT>mod_disco</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc41">3.3.5  <TT>mod_echo</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc42">3.3.6  <TT>mod_irc</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc43">3.3.7  <TT>mod_last</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc44">3.3.8  <TT>mod_muc</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc45">3.3.9  <TT>mod_muc_log</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc46">3.3.10  <TT>mod_offline</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc47">3.3.11  <TT>mod_privacy</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc48">3.3.12  <TT>mod_private</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc49">3.3.13  <TT>mod_proxy65</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc50">3.3.14  <TT>mod_pubsub</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc51">3.3.15  <TT>mod_register</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc52">3.3.16  <TT>mod_roster</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc53">3.3.17  <TT>mod_service_log</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc54">3.3.18  <TT>mod_shared_roster</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc55">3.3.19  <TT>mod_stats</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc56">3.3.20  <TT>mod_time</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc57">3.3.21  <TT>mod_vcard</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc58">3.3.22  <TT>mod_vcard_ldap</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc59">3.3.23  <TT>mod_version</TT></A> +<A HREF="#htoc38">3.3.1  Modules Overview</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc39">3.3.2  Common Options</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc40">3.3.3  <TT>mod_announce</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc41">3.3.4  <TT>mod_disco</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc42">3.3.5  <TT>mod_echo</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc43">3.3.6  <TT>mod_irc</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc44">3.3.7  <TT>mod_last</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc45">3.3.8  <TT>mod_muc</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc46">3.3.9  <TT>mod_muc_log</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc47">3.3.10  <TT>mod_offline</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc48">3.3.11  <TT>mod_privacy</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc49">3.3.12  <TT>mod_private</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc50">3.3.13  <TT>mod_proxy65</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc51">3.3.14  <TT>mod_pubsub</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc52">3.3.15  <TT>mod_register</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc53">3.3.16  <TT>mod_roster</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc54">3.3.17  <TT>mod_service_log</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc55">3.3.18  <TT>mod_shared_roster</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc56">3.3.19  <TT>mod_stats</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc57">3.3.20  <TT>mod_time</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc58">3.3.21  <TT>mod_vcard</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc59">3.3.22  <TT>mod_vcard_ldap</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc60">3.3.23  <TT>mod_version</TT></A> </LI></UL> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc60">Chapter 4  Managing an <TT>ejabberd</TT> Server</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc61">Chapter 4  Managing an <TT>ejabberd</TT> Server</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc61">4.1  <TT>ejabberdctl</TT></A> +<A HREF="#htoc62">4.1  <TT>ejabberdctl</TT></A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc62">4.1.1  ejabberdctl Commands</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc63">4.1.2  Erlang Runtime System</A> +<A HREF="#htoc63">4.1.1  ejabberdctl Commands</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc64">4.1.2  Erlang Runtime System</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc64">4.2  <TT>ejabberd</TT> Commands</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc65">4.2  <TT>ejabberd</TT> Commands</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc65">4.2.1  List of ejabberd Commands</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc66">4.2.2  Restrict Execution with AccessCommands</A> +<A HREF="#htoc66">4.2.1  List of ejabberd Commands</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc67">4.2.2  Restrict Execution with AccessCommands</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc67">4.3  Web Admin</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc68">4.4  Ad-hoc Commands</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc69">4.5  Change Computer Hostname</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc68">4.3  Web Admin</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc69">4.4  Ad-hoc Commands</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc70">4.5  Change Computer Hostname</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc70">Chapter 5  Securing <TT>ejabberd</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc71">Chapter 5  Securing <TT>ejabberd</TT></A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc71">5.1  Firewall Settings</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc72">5.2  epmd</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc73">5.3  Erlang Cookie</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc74">5.4  Erlang Node Name</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc75">5.5  Securing Sensible Files</A> +<A HREF="#htoc72">5.1  Firewall Settings</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc73">5.2  epmd</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc74">5.3  Erlang Cookie</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc75">5.4  Erlang Node Name</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc76">5.5  Securing Sensible Files</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc76">Chapter 6  Clustering</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc77">Chapter 6  Clustering</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc77">6.1  How it Works</A> +<A HREF="#htoc78">6.1  How it Works</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc78">6.1.1  Router</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc79">6.1.2  Local Router</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc80">6.1.3  Session Manager</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc81">6.1.4  s2s Manager</A> +<A HREF="#htoc79">6.1.1  Router</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc80">6.1.2  Local Router</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc81">6.1.3  Session Manager</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc82">6.1.4  s2s Manager</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc82">6.2  Clustering Setup</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc83">6.3  Service Load-Balancing</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc83">6.2  Clustering Setup</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc84">6.3  Service Load-Balancing</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc84">6.3.1  Components Load-Balancing</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc85">6.3.2  Domain Load-Balancing Algorithm</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc86">6.3.3  Load-Balancing Buckets</A> +<A HREF="#htoc85">6.3.1  Components Load-Balancing</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc86">6.3.2  Domain Load-Balancing Algorithm</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc87">6.3.3  Load-Balancing Buckets</A> </LI></UL> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc87">Chapter 7  Debugging</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc88">Chapter 7  Debugging</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc88">7.1  Log Files</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc89">7.2  Debug Console</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc90">7.3  Watchdog Alerts</A> +<A HREF="#htoc89">7.1  Log Files</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc90">7.2  Debug Console</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc91">7.3  Watchdog Alerts</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc91">Appendix A  Internationalization and Localization</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc92">Appendix B  Release Notes</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc93">Appendix C  Acknowledgements</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc94">Appendix D  Copyright Information</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc92">Appendix A  Internationalization and Localization</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc93">Appendix B  Release Notes</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc94">Appendix C  Acknowledgements</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc95">Appendix D  Copyright Information</A> </LI></UL><!--TOC chapter Introduction--> <H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc1">Chapter 1</A>  Introduction</H1><!--SEC END --><P> <A NAME="intro"></A></P><P><TT>ejabberd</TT> is a free and open source instant messaging server written in <A HREF="http://www.erlang.org/">Erlang</A>.</P><P><TT>ejabberd</TT> is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.</P><P><TT>ejabberd</TT> is designed to be a rock-solid and feature rich XMPP server.</P><P><TT>ejabberd</TT> is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.</P><!--TOC section Key Features--> @@ -342,6 +343,7 @@ GNU Make </LI><LI CLASS="li-itemize">Erlang pgsql library. Optional. For PostgreSQL authentication or storage. See section <A HREF="#compilepgsql">3.2.3</A>. </LI><LI CLASS="li-itemize">PAM library. Optional. For Pluggable Authentication Modules (PAM). See section <A HREF="#pam">3.1.4</A>. </LI><LI CLASS="li-itemize">GNU Iconv 1.8 or higher, for the IRC Transport (mod_irc). Optional. Not needed on systems with GNU Libc. See section <A HREF="#modirc">3.3.6</A>. +</LI><LI CLASS="li-itemize">ImageMagick’s Convert program. Optional. For CAPTCHA challenges. See section <A HREF="#captcha">3.1.8</A>. </LI></UL><P> <A NAME="download"></A> </P><!--TOC subsection Download Source Code--> <H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc10">2.4.2</A>  <A HREF="#download">Download Source Code</A></H3><!--SEC END --><P> <A NAME="download"></A> </P><P>Released versions of <TT>ejabberd</TT> are available in the ProcessOne <TT>ejabberd</TT> downloads page: @@ -396,7 +398,7 @@ to install <TT>ejabberd</TT>.</P><P>The files and directories created are, by de </DD><DT CLASS="dt-description"><B><TT>include/</TT></B></DT><DD CLASS="dd-description"> Erlang header files (*.hrl) </DD><DT CLASS="dt-description"><B><TT>priv/</TT></B></DT><DD CLASS="dd-description"> Additional files required at runtime <DL CLASS="description"><DT CLASS="dt-description"> - <B><TT>bin/</TT></B></DT><DD CLASS="dd-description"> Binary C programs + <B><TT>bin/</TT></B></DT><DD CLASS="dd-description"> Executable programs </DD><DT CLASS="dt-description"><B><TT>lib/</TT></B></DT><DD CLASS="dd-description"> Binary system libraries (*.so) </DD><DT CLASS="dt-description"><B><TT>msgs/</TT></B></DT><DD CLASS="dd-description"> Translation files (*.msgs) </DD></DL> @@ -676,7 +678,7 @@ Interacts with an <A HREF="http://www.ejabberd.im/tutorials-transports">external <TT>shaper</TT>, <TT>service_check_from</TT> </DD><DT CLASS="dt-description"><B><TT>ejabberd_http</TT></B></DT><DD CLASS="dd-description"> Handles incoming HTTP connections.<BR> - Options: <TT>certfile</TT>, <TT>http_bind</TT>, <TT>http_poll</TT>, + Options: <TT>captcha</TT>, <TT>certfile</TT>, <TT>http_bind</TT>, <TT>http_poll</TT>, <TT>request_handlers</TT>, <TT>tls</TT>, <TT>web_admin</TT><BR> </DD></DL><P> <A NAME="listened-options"></A> </P><!--TOC subsubsection Options--> <H4 CLASS="subsubsection"><!--SEC ANCHOR --><A HREF="#listened-options">Options</A></H4><!--SEC END --><P> <A NAME="listened-options"></A> </P><P>This is a detailed description of each option allowed by the listening modules: @@ -699,6 +701,8 @@ when attempt to connect to ejabberd: <TT>{password, Secret}</TT>. Note that you cannot define in a single <TT>ejabberd_service</TT> components of different services: add an <TT>ejabberd_service</TT> for each service, as seen in an example below. +</DD><DT CLASS="dt-description"><B><TT>captcha</TT></B></DT><DD CLASS="dd-description"> +Simple web page that allows a user to fill a CAPTCHA challenge (see section <A HREF="#captcha">3.1.8</A>). </DD><DT CLASS="dt-description"><B><TT>http_bind</TT></B></DT><DD CLASS="dd-description"> This option enables HTTP Binding (<A HREF="http://www.xmpp.org/extensions/xep-0124.html">XEP-0124</A> and <A HREF="http://www.xmpp.org/extensions/xep-0206.html">XEP-0206</A>) support. HTTP Bind enables access via HTTP requests to <TT>ejabberd</TT> from behind firewalls which @@ -1203,8 +1207,40 @@ can be seen by Jabber clients. If a Jabber client does not support <TT>en</TT>. In order to take effect there must be a translation file <TT><language>.msg</TT> in <TT>ejabberd</TT>’s <TT>msgs</TT> directory.</P><P>For example, to set Russian as default language: </P><PRE CLASS="verbatim">{language, "ru"}. -</PRE><P>Appendix <A HREF="#i18ni10n">A</A> provides more details about internationalization and localization.</P><P> <A NAME="includeconfigfile"></A> </P><!--TOC subsection Include Additional Configuration Files--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc28">3.1.8</A>  <A HREF="#includeconfigfile">Include Additional Configuration Files</A></H3><!--SEC END --><P> <A NAME="includeconfigfile"></A> +</PRE><P>Appendix <A HREF="#i18ni10n">A</A> provides more details about internationalization and localization.</P><P> <A NAME="captcha"></A> </P><!--TOC subsection CAPTCHA--> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc28">3.1.8</A>  <A HREF="#captcha">CAPTCHA</A></H3><!--SEC END --><P> <A NAME="captcha"></A> +</P><P>Some <TT>ejabberd</TT> modules can be configured to require a CAPTCHA challenge on certain actions. +If the client does not support CAPTCHA Forms (<A HREF="http://www.xmpp.org/extensions/xep-0158.html">XEP-0158</A>), +a web link is provided so the user can fill the challenge in a web browser.</P><P>An example script is provided that generates the image +using ImageMagick’s Convert program.</P><P>The configurable options are: +</P><DL CLASS="description"><DT CLASS="dt-description"> +<B><TT>{captcha_cmd, Path}</TT></B></DT><DD CLASS="dd-description"> +Full path to a script that generates the image. +The default value is an empty string: <TT>""</TT> +</DD><DT CLASS="dt-description"><B><TT>{captcha_host, Host}</TT></B></DT><DD CLASS="dd-description"> +Host part of the URL sent to the user. +You can include the port number. +The URL sent to the user is formed by: <TT>http://Host/captcha/</TT> +The default value is the first hostname configured. +</DD></DL><P>Additionally, an <TT>ejabberd_http</TT> listener must be enabled with the <TT>captcha</TT> option. +See section <A HREF="#listened-module">3.1.3</A>.</P><P>Example configuration: +</P><PRE CLASS="verbatim">{hosts, ["example.org"]}. + +{captcha_cmd, "/lib/ejabberd/priv/bin/captcha.sh"}. +{captcha_host, "example.org:5280"}. + +{listen, + [ + ... + {5280, ejabberd_http, [ + captcha, + ... + ] + } + +]}. +</PRE><P> <A NAME="includeconfigfile"></A> </P><!--TOC subsection Include Additional Configuration Files--> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc29">3.1.9</A>  <A HREF="#includeconfigfile">Include Additional Configuration Files</A></H3><!--SEC END --><P> <A NAME="includeconfigfile"></A> </P><P>The option <TT>include_config_file</TT> in a configuration file instructs <TT>ejabberd</TT> to include other configuration files immediately.</P><P>The basic usage is: </P><PRE CLASS="verbatim">{include_config_file, <filename>}. </PRE><P>It is also possible to specify suboptions: @@ -1235,7 +1271,7 @@ and later includes another file with additional rules: </P><PRE CLASS="verbatim">{acl, admin, {user, "bob", "localhost"}}. {acl, admin, {user, "jan", "localhost"}}. </PRE><P> <A NAME="optionmacros"></A> </P><!--TOC subsection Option Macros in Configuration File--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc29">3.1.9</A>  <A HREF="#optionmacros">Option Macros in Configuration File</A></H3><!--SEC END --><P> <A NAME="optionmacros"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc30">3.1.10</A>  <A HREF="#optionmacros">Option Macros in Configuration File</A></H3><!--SEC END --><P> <A NAME="optionmacros"></A> </P><P>In the <TT>ejabberd</TT> configuration file, it is possible to define a macro for a value and later use this macro when defining an option.</P><P>A macro is defined with this syntax: @@ -1284,7 +1320,7 @@ This usage behaves as if it were defined and used this way: ] }. </PRE><P> <A NAME="database"></A> </P><!--TOC section Database and LDAP Configuration--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc30">3.2</A>  <A HREF="#database">Database and LDAP Configuration</A></H2><!--SEC END --><P> <A NAME="database"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc31">3.2</A>  <A HREF="#database">Database and LDAP Configuration</A></H2><!--SEC END --><P> <A NAME="database"></A> </P><P><TT>ejabberd</TT> uses its internal Mnesia database by default. However, it is possible to use a relational database or an LDAP server to store persistent, @@ -1317,7 +1353,7 @@ For example: {auth_method, [odbc]} ]}. </PRE><P> <A NAME="mysql"></A> </P><!--TOC subsection MySQL--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc31">3.2.1</A>  <A HREF="#mysql">MySQL</A></H3><!--SEC END --><P> <A NAME="mysql"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc32">3.2.1</A>  <A HREF="#mysql">MySQL</A></H3><!--SEC END --><P> <A NAME="mysql"></A> </P><P>Although this section will describe <TT>ejabberd</TT>’s configuration when you want to use the native MySQL driver, it does not describe MySQL’s installation and database creation. Check the MySQL documentation and the tutorial <A HREF="http://support.process-one.net/doc/display/MESSENGER/Using+ejabberd+with+MySQL+native+driver">Using ejabberd with MySQL native driver</A> for information regarding these topics. @@ -1378,7 +1414,7 @@ relational databases like MySQL. To enable storage to your database, just make sure that your database is running well (see previous sections), and replace the suffix-less or ldap module variant with the odbc module variant. Keep in mind that you cannot have several variants of the same module loaded!</P><P> <A NAME="mssql"></A> </P><!--TOC subsection Microsoft SQL Server--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc32">3.2.2</A>  <A HREF="#mssql">Microsoft SQL Server</A></H3><!--SEC END --><P> <A NAME="mssql"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc33">3.2.2</A>  <A HREF="#mssql">Microsoft SQL Server</A></H3><!--SEC END --><P> <A NAME="mssql"></A> </P><P>Although this section will describe <TT>ejabberd</TT>’s configuration when you want to use Microsoft SQL Server, it does not describe Microsoft SQL Server’s installation and database creation. Check the MySQL documentation and the @@ -1416,7 +1452,7 @@ database, just make sure that your database is running well (see previous sections), and replace the suffix-less or ldap module variant with the odbc module variant. Keep in mind that you cannot have several variants of the same module loaded!</P><P> <A NAME="pgsql"></A> </P><!--TOC subsection PostgreSQL--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc33">3.2.3</A>  <A HREF="#pgsql">PostgreSQL</A></H3><!--SEC END --><P> <A NAME="pgsql"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc34">3.2.3</A>  <A HREF="#pgsql">PostgreSQL</A></H3><!--SEC END --><P> <A NAME="pgsql"></A> </P><P>Although this section will describe <TT>ejabberd</TT>’s configuration when you want to use the native PostgreSQL driver, it does not describe PostgreSQL’s installation and database creation. Check the PostgreSQL documentation and the tutorial <A HREF="http://support.process-one.net/doc/display/MESSENGER/Using+ejabberd+with+MySQL+native+driver">Using ejabberd with MySQL native driver</A> for information regarding these topics. @@ -1477,7 +1513,7 @@ relational databases like PostgreSQL. To enable storage to your database, just make sure that your database is running well (see previous sections), and replace the suffix-less or ldap module variant with the odbc module variant. Keep in mind that you cannot have several variants of the same module loaded!</P><P> <A NAME="odbc"></A> </P><!--TOC subsection ODBC Compatible--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc34">3.2.4</A>  <A HREF="#odbc">ODBC Compatible</A></H3><!--SEC END --><P> <A NAME="odbc"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc35">3.2.4</A>  <A HREF="#odbc">ODBC Compatible</A></H3><!--SEC END --><P> <A NAME="odbc"></A> </P><P>Although this section will describe <TT>ejabberd</TT>’s configuration when you want to use the ODBC driver, it does not describe the installation and database creation of your database. Check the documentation of your database. The tutorial <A HREF="http://support.process-one.net/doc/display/MESSENGER/Using+ejabberd+with+MySQL+native+driver">Using ejabberd with MySQL native driver</A> also can help you. Note that the tutorial @@ -1522,7 +1558,7 @@ database, just make sure that your database is running well (see previous sections), and replace the suffix-less or ldap module variant with the odbc module variant. Keep in mind that you cannot have several variants of the same module loaded!</P><P> <A NAME="ldap"></A> </P><!--TOC subsection LDAP--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc35">3.2.5</A>  <A HREF="#ldap">LDAP</A></H3><!--SEC END --><P> <A NAME="ldap"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc36">3.2.5</A>  <A HREF="#ldap">LDAP</A></H3><!--SEC END --><P> <A NAME="ldap"></A> </P><P><TT>ejabberd</TT> has built-in LDAP support. You can authenticate users against LDAP server and use LDAP directory as vCard storage. Shared rosters are not supported yet.</P><P>Note that <TT>ejabberd</TT> treats LDAP as a read-only storage: @@ -1708,7 +1744,7 @@ configuration is shown below:</P><PRE CLASS="verbatim">{auth_method, ldap}. ... ]}. </PRE><P> <A NAME="modules"></A> </P><!--TOC section Modules Configuration--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc36">3.3</A>  <A HREF="#modules">Modules Configuration</A></H2><!--SEC END --><P> <A NAME="modules"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc37">3.3</A>  <A HREF="#modules">Modules Configuration</A></H2><!--SEC END --><P> <A NAME="modules"></A> </P><P>The option <TT>modules</TT> defines the list of modules that will be loaded after <TT>ejabberd</TT>’s startup. Each entry in the list is a tuple in which the first element is the name of a module and the second is a list of options for that @@ -1730,7 +1766,7 @@ all entries end with a comma: {mod_version, []} ]}. </PRE></LI></UL><P> <A NAME="modoverview"></A> </P><!--TOC subsection Modules Overview--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc37">3.3.1</A>  <A HREF="#modoverview">Modules Overview</A></H3><!--SEC END --><P> <A NAME="modoverview"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc38">3.3.1</A>  <A HREF="#modoverview">Modules Overview</A></H3><!--SEC END --><P> <A NAME="modoverview"></A> </P><P>The following table lists all modules included in <TT>ejabberd</TT>.</P><BLOCKQUOTE CLASS="table"><DIV CLASS="center"><DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV> <TABLE BORDER=1 CELLSPACING=0 CELLPADDING=1><TR><TD ALIGN=left NOWRAP><B>Module</B></TD><TD ALIGN=left NOWRAP><B>Feature</B></TD><TD ALIGN=left NOWRAP><B>Dependencies</B></TD></TR> <TR><TD ALIGN=left NOWRAP><TT>mod_adhoc</TT></TD><TD ALIGN=left NOWRAP>Ad-Hoc Commands (<A HREF="http://www.xmpp.org/extensions/xep-0050.html">XEP-0050</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR> @@ -1792,7 +1828,7 @@ Last connection date and time: Use <TT>mod_last_odbc</TT> instead of <TT>ejabberd</TT> website. Please remember that these contributions might not work or that they can contain severe bugs and security leaks. Therefore, use them at your own risk!</P><P> <A NAME="modcommonoptions"></A> </P><!--TOC subsection Common Options--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc38">3.3.2</A>  <A HREF="#modcommonoptions">Common Options</A></H3><!--SEC END --><P> <A NAME="modcommonoptions"></A> </P><P>The following options are used by many modules. Therefore, they are described in +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc39">3.3.2</A>  <A HREF="#modcommonoptions">Common Options</A></H3><!--SEC END --><P> <A NAME="modcommonoptions"></A> </P><P>The following options are used by many modules. Therefore, they are described in this separate section.</P><P> <A NAME="modiqdiscoption"></A> </P><!--TOC subsubsection <TT>iqdisc</TT>--> <H4 CLASS="subsubsection"><!--SEC ANCHOR --><A HREF="#modiqdiscoption"><TT>iqdisc</TT></A></H4><!--SEC END --><P> <A NAME="modiqdiscoption"></A> </P><P>Many modules define handlers for processing IQ queries of different namespaces @@ -1844,7 +1880,7 @@ the "@HOST@" keyword must be used: ... ]}. </PRE><P> <A NAME="modannounce"></A> </P><!--TOC subsection <TT>mod_announce</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc39">3.3.3</A>  <A HREF="#modannounce"><TT>mod_announce</TT></A></H3><!--SEC END --><P> <A NAME="modannounce"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc40">3.3.3</A>  <A HREF="#modannounce"><TT>mod_announce</TT></A></H3><!--SEC END --><P> <A NAME="modannounce"></A> </P><P>This module enables configured users to broadcast announcements and to set the message of the day (MOTD). Configured users can perform these actions with a @@ -1908,7 +1944,7 @@ Only administrators can send announcements: </PRE></LI></UL><P>Note that <TT>mod_announce</TT> can be resource intensive on large deployments as it can broadcast lot of messages. This module should be disabled for instances of <TT>ejabberd</TT> with hundreds of thousands users.</P><P> <A NAME="moddisco"></A> </P><!--TOC subsection <TT>mod_disco</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc40">3.3.4</A>  <A HREF="#moddisco"><TT>mod_disco</TT></A></H3><!--SEC END --><P> <A NAME="moddisco"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc41">3.3.4</A>  <A HREF="#moddisco"><TT>mod_disco</TT></A></H3><!--SEC END --><P> <A NAME="moddisco"></A> @@ -1951,7 +1987,7 @@ To serve a link to the Jabber User Directory on <TT>jabber.org</TT>: ... ]}. </PRE></LI></UL><P> <A NAME="modecho"></A> </P><!--TOC subsection <TT>mod_echo</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc41">3.3.5</A>  <A HREF="#modecho"><TT>mod_echo</TT></A></H3><!--SEC END --><P> <A NAME="modecho"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc42">3.3.5</A>  <A HREF="#modecho"><TT>mod_echo</TT></A></H3><!--SEC END --><P> <A NAME="modecho"></A> </P><P>This module simply echoes any Jabber packet back to the sender. This mirror can be of interest for <TT>ejabberd</TT> and Jabber client debugging.</P><P>Options: @@ -1971,7 +2007,7 @@ of them all? ... ]}. </PRE><P> <A NAME="modirc"></A> </P><!--TOC subsection <TT>mod_irc</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc42">3.3.6</A>  <A HREF="#modirc"><TT>mod_irc</TT></A></H3><!--SEC END --><P> <A NAME="modirc"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc43">3.3.6</A>  <A HREF="#modirc"><TT>mod_irc</TT></A></H3><!--SEC END --><P> <A NAME="modirc"></A> </P><P>This module is an IRC transport that can be used to join channels on IRC servers.</P><P>End user information: @@ -2029,7 +2065,7 @@ of <TT>example.org</TT>, and any user of <TT>example.com</TT>: ... ]}. </PRE></LI></UL><P> <A NAME="modlast"></A> </P><!--TOC subsection <TT>mod_last</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc43">3.3.7</A>  <A HREF="#modlast"><TT>mod_last</TT></A></H3><!--SEC END --><P> <A NAME="modlast"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc44">3.3.7</A>  <A HREF="#modlast"><TT>mod_last</TT></A></H3><!--SEC END --><P> <A NAME="modlast"></A> </P><P>This module adds support for Last Activity (<A HREF="http://www.xmpp.org/extensions/xep-0012.html">XEP-0012</A>). It can be used to discover when a disconnected user last accessed the server, to know when a connected user was last active on the server, or to query the uptime of the @@ -2038,7 +2074,7 @@ connected user was last active on the server, or to query the uptime of the <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Last activity (<TT>jabber:iq:last</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modmuc"></A> </P><!--TOC subsection <TT>mod_muc</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc44">3.3.8</A>  <A HREF="#modmuc"><TT>mod_muc</TT></A></H3><!--SEC END --><P> <A NAME="modmuc"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc45">3.3.8</A>  <A HREF="#modmuc"><TT>mod_muc</TT></A></H3><!--SEC END --><P> <A NAME="modmuc"></A> </P><P>This module provides a Multi-User Chat (<A HREF="http://www.xmpp.org/extensions/xep-0045.html">XEP-0045</A>) service. Users can discover existing rooms, join or create them. Occupants of a room can chat in public or have private chats.</P><P>Some of the features of Multi-User Chat: @@ -2261,7 +2297,7 @@ the newly created rooms have by default those options. ... ]}. </PRE></LI></UL><P> <A NAME="modmuclog"></A> </P><!--TOC subsection <TT>mod_muc_log</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc45">3.3.9</A>  <A HREF="#modmuclog"><TT>mod_muc_log</TT></A></H3><!--SEC END --><P> <A NAME="modmuclog"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc46">3.3.9</A>  <A HREF="#modmuclog"><TT>mod_muc_log</TT></A></H3><!--SEC END --><P> <A NAME="modmuclog"></A> </P><P>This module enables optional logging of Multi-User Chat (MUC) public conversations to HTML. Once you enable this module, users can join a room using a MUC capable Jabber client, and if they have enough privileges, they can request the @@ -2381,7 +2417,7 @@ top link will be the default <CODE><a href="/">Home</a></CODE>. ... ]}. </PRE></LI></UL><P> <A NAME="modoffline"></A> </P><!--TOC subsection <TT>mod_offline</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc46">3.3.10</A>  <A HREF="#modoffline"><TT>mod_offline</TT></A></H3><!--SEC END --><P> <A NAME="modoffline"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc47">3.3.10</A>  <A HREF="#modoffline"><TT>mod_offline</TT></A></H3><!--SEC END --><P> <A NAME="modoffline"></A> </P><P>This module implements offline message storage. This means that all messages sent to an offline user will be stored on the server until that user comes online again. Thus it is very similar to how email works. Note that @@ -2392,7 +2428,7 @@ is use to set a max number of offline messages per user (quota). Its value can be either <TT>infinity</TT> or a strictly positive integer. The default value is <TT>infinity</TT>. </DD></DL><P> <A NAME="modprivacy"></A> </P><!--TOC subsection <TT>mod_privacy</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc47">3.3.11</A>  <A HREF="#modprivacy"><TT>mod_privacy</TT></A></H3><!--SEC END --><P> <A NAME="modprivacy"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc48">3.3.11</A>  <A HREF="#modprivacy"><TT>mod_privacy</TT></A></H3><!--SEC END --><P> <A NAME="modprivacy"></A> </P><P>This module implements Blocking Communication (also known as Privacy Rules) as defined in section 10 from XMPP IM. If end users have support for it in their Jabber client, they will be able to: @@ -2420,7 +2456,7 @@ subscription type (or globally). <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Blocking Communication (<TT>jabber:iq:privacy</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modprivate"></A> </P><!--TOC subsection <TT>mod_private</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc48">3.3.12</A>  <A HREF="#modprivate"><TT>mod_private</TT></A></H3><!--SEC END --><P> <A NAME="modprivate"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc49">3.3.12</A>  <A HREF="#modprivate"><TT>mod_private</TT></A></H3><!--SEC END --><P> <A NAME="modprivate"></A> </P><P>This module adds support for Private XML Storage (<A HREF="http://www.xmpp.org/extensions/xep-0049.html">XEP-0049</A>): </P><BLOCKQUOTE CLASS="quote"> Using this method, Jabber entities can store private data on the server and @@ -2432,7 +2468,7 @@ of client-specific preferences; another is Bookmark Storage (<A HREF="http://www <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Private XML Storage (<TT>jabber:iq:private</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modproxy"></A> </P><!--TOC subsection <TT>mod_proxy65</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc49">3.3.13</A>  <A HREF="#modproxy"><TT>mod_proxy65</TT></A></H3><!--SEC END --><P> <A NAME="modproxy"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc50">3.3.13</A>  <A HREF="#modproxy"><TT>mod_proxy65</TT></A></H3><!--SEC END --><P> <A NAME="modproxy"></A> </P><P>This module implements SOCKS5 Bytestreams (<A HREF="http://www.xmpp.org/extensions/xep-0065.html">XEP-0065</A>). It allows <TT>ejabberd</TT> to act as a file transfer proxy between two XMPP clients.</P><P>Options: @@ -2487,7 +2523,7 @@ The simpliest configuration of the module: ... ]}. </PRE></LI></UL><P> <A NAME="modpubsub"></A> </P><!--TOC subsection <TT>mod_pubsub</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc50">3.3.14</A>  <A HREF="#modpubsub"><TT>mod_pubsub</TT></A></H3><!--SEC END --><P> <A NAME="modpubsub"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc51">3.3.14</A>  <A HREF="#modpubsub"><TT>mod_pubsub</TT></A></H3><!--SEC END --><P> <A NAME="modpubsub"></A> </P><P>This module offers a Publish-Subscribe Service (<A HREF="http://www.xmpp.org/extensions/xep-0060.html">XEP-0060</A>). The functionality in <TT>mod_pubsub</TT> can be extended using plugins. The plugin that implements PEP (Personal Eventing via Pubsub) (<A HREF="http://www.xmpp.org/extensions/xep-0163.html">XEP-0163</A>) @@ -2518,7 +2554,7 @@ and is shared by all node plugins. ... ]}. </PRE><P> <A NAME="modregister"></A> </P><!--TOC subsection <TT>mod_register</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc51">3.3.15</A>  <A HREF="#modregister"><TT>mod_register</TT></A></H3><!--SEC END --><P> <A NAME="modregister"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc52">3.3.15</A>  <A HREF="#modregister"><TT>mod_register</TT></A></H3><!--SEC END --><P> <A NAME="modregister"></A> </P><P>This module adds support for In-Band Registration (<A HREF="http://www.xmpp.org/extensions/xep-0077.html">XEP-0077</A>). This protocol enables end users to use a Jabber client to: </P><UL CLASS="itemize"><LI CLASS="li-itemize"> @@ -2591,13 +2627,13 @@ Also define a registration timeout of one hour: ... ]}. </PRE></LI></UL><P> <A NAME="modroster"></A> </P><!--TOC subsection <TT>mod_roster</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc52">3.3.16</A>  <A HREF="#modroster"><TT>mod_roster</TT></A></H3><!--SEC END --><P> <A NAME="modroster"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc53">3.3.16</A>  <A HREF="#modroster"><TT>mod_roster</TT></A></H3><!--SEC END --><P> <A NAME="modroster"></A> </P><P>This module implements roster management as defined in <A HREF="http://www.xmpp.org/specs/rfc3921.html#roster">RFC 3921: XMPP IM</A>.</P><P>Options: </P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Roster Management (<TT>jabber:iq:roster</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modservicelog"></A> </P><!--TOC subsection <TT>mod_service_log</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc53">3.3.17</A>  <A HREF="#modservicelog"><TT>mod_service_log</TT></A></H3><!--SEC END --><P> <A NAME="modservicelog"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc54">3.3.17</A>  <A HREF="#modservicelog"><TT>mod_service_log</TT></A></H3><!--SEC END --><P> <A NAME="modservicelog"></A> </P><P>This module adds support for logging end user packets via a Jabber message auditing service such as <A HREF="http://www.funkypenguin.info/project/bandersnatch/">Bandersnatch</A>. All user @@ -2627,7 +2663,7 @@ To log all end user packets to the Bandersnatch service running on ... ]}. </PRE></LI></UL><P> <A NAME="modsharedroster"></A> </P><!--TOC subsection <TT>mod_shared_roster</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc54">3.3.18</A>  <A HREF="#modsharedroster"><TT>mod_shared_roster</TT></A></H3><!--SEC END --><P> <A NAME="modsharedroster"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc55">3.3.18</A>  <A HREF="#modsharedroster"><TT>mod_shared_roster</TT></A></H3><!--SEC END --><P> <A NAME="modsharedroster"></A> </P><P>This module enables you to create shared roster groups. This means that you can create groups of people that can see members from (other) groups in their rosters. The big advantages of this feature are that end users do not need to @@ -2702,7 +2738,7 @@ roster groups as shown in the following table: </TABLE> <DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV></DIV></BLOCKQUOTE> </LI></UL><P> <A NAME="modstats"></A> </P><!--TOC subsection <TT>mod_stats</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc55">3.3.19</A>  <A HREF="#modstats"><TT>mod_stats</TT></A></H3><!--SEC END --><P> <A NAME="modstats"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc56">3.3.19</A>  <A HREF="#modstats"><TT>mod_stats</TT></A></H3><!--SEC END --><P> <A NAME="modstats"></A> </P><P>This module adds support for Statistics Gathering (<A HREF="http://www.xmpp.org/extensions/xep-0039.html">XEP-0039</A>). This protocol allows you to retrieve next statistics from your <TT>ejabberd</TT> deployment: </P><UL CLASS="itemize"><LI CLASS="li-itemize"> @@ -2734,14 +2770,14 @@ by sending: </query> </iq> </PRE></LI></UL><P> <A NAME="modtime"></A> </P><!--TOC subsection <TT>mod_time</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc56">3.3.20</A>  <A HREF="#modtime"><TT>mod_time</TT></A></H3><!--SEC END --><P> <A NAME="modtime"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc57">3.3.20</A>  <A HREF="#modtime"><TT>mod_time</TT></A></H3><!--SEC END --><P> <A NAME="modtime"></A> </P><P>This module features support for Entity Time (<A HREF="http://www.xmpp.org/extensions/xep-0090.html">XEP-0090</A>). By using this XEP, you are able to discover the time at another entity’s location.</P><P>Options: </P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Entity Time (<TT>jabber:iq:time</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modvcard"></A> </P><!--TOC subsection <TT>mod_vcard</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc57">3.3.21</A>  <A HREF="#modvcard"><TT>mod_vcard</TT></A></H3><!--SEC END --><P> <A NAME="modvcard"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc58">3.3.21</A>  <A HREF="#modvcard"><TT>mod_vcard</TT></A></H3><!--SEC END --><P> <A NAME="modvcard"></A> </P><P>This module allows end users to store and retrieve their vCard, and to retrieve other users vCards, as defined in vcard-temp (<A HREF="http://www.xmpp.org/extensions/xep-0054.html">XEP-0054</A>). The module also implements an uncomplicated Jabber User Directory based on the vCards of @@ -2796,7 +2832,7 @@ and that all virtual hosts will be searched instead of only the current one: ... ]}. </PRE></LI></UL><P> <A NAME="modvcardldap"></A> </P><!--TOC subsection <TT>mod_vcard_ldap</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc58">3.3.22</A>  <A HREF="#modvcardldap"><TT>mod_vcard_ldap</TT></A></H3><!--SEC END --><P> <A NAME="modvcardldap"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc59">3.3.22</A>  <A HREF="#modvcardldap"><TT>mod_vcard_ldap</TT></A></H3><!--SEC END --><P> <A NAME="modvcardldap"></A> </P><P><TT>ejabberd</TT> can map LDAP attributes to vCard fields. This behaviour is implemented in the <TT>mod_vcard_ldap</TT> module. This module does not depend on the authentication method (see <A HREF="#ldapauth">3.2.5</A>).</P><P>Note that <TT>ejabberd</TT> treats LDAP as a read-only storage: @@ -2972,7 +3008,7 @@ searching his info in LDAP.</P></LI><LI CLASS="li-itemize"><TT>ldap_vcard_map</T {"Nickname", "NICKNAME"} ]}, </PRE></LI></UL><P> <A NAME="modversion"></A> </P><!--TOC subsection <TT>mod_version</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc59">3.3.23</A>  <A HREF="#modversion"><TT>mod_version</TT></A></H3><!--SEC END --><P> <A NAME="modversion"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc60">3.3.23</A>  <A HREF="#modversion"><TT>mod_version</TT></A></H3><!--SEC END --><P> <A NAME="modversion"></A> </P><P>This module implements Software Version (<A HREF="http://www.xmpp.org/extensions/xep-0092.html">XEP-0092</A>). Consequently, it answers <TT>ejabberd</TT>’s version when queried.</P><P>Options: </P><DL CLASS="description"><DT CLASS="dt-description"> @@ -2981,8 +3017,8 @@ The default value is <TT>true</TT>. </DD><DT CLASS="dt-description"><B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Software Version (<TT>jabber:iq:version</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="manage"></A> </P><!--TOC chapter Managing an <TT>ejabberd</TT> Server--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc60">Chapter 4</A>  <A HREF="#manage">Managing an <TT>ejabberd</TT> Server</A></H1><!--SEC END --><P> <A NAME="manage"></A> </P><P> <A NAME="ejabberdctl"></A> </P><!--TOC section <TT>ejabberdctl</TT>--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc61">4.1</A>  <A HREF="#ejabberdctl"><TT>ejabberdctl</TT></A></H2><!--SEC END --><P> <A NAME="ejabberdctl"></A> </P><P>With the <TT>ejabberdctl</TT> command line administration script +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc61">Chapter 4</A>  <A HREF="#manage">Managing an <TT>ejabberd</TT> Server</A></H1><!--SEC END --><P> <A NAME="manage"></A> </P><P> <A NAME="ejabberdctl"></A> </P><!--TOC section <TT>ejabberdctl</TT>--> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc62">4.1</A>  <A HREF="#ejabberdctl"><TT>ejabberdctl</TT></A></H2><!--SEC END --><P> <A NAME="ejabberdctl"></A> </P><P>With the <TT>ejabberdctl</TT> command line administration script you can execute <TT>ejabberdctl commands</TT> (described in the next section, <A HREF="#ectl-commands">4.1.1</A>) and also many general <TT>ejabberd commands</TT> (described in section <A HREF="#eja-commands">4.2</A>). This means you can start, stop and perform many other administrative tasks @@ -2994,7 +3030,7 @@ and other codes may be used for specific results. This can be used by other scripts to determine automatically if a command succeeded or failed, for example using: <TT>echo $?</TT></P><P> <A NAME="ectl-commands"></A> </P><!--TOC subsection ejabberdctl Commands--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc62">4.1.1</A>  <A HREF="#ectl-commands">ejabberdctl Commands</A></H3><!--SEC END --><P> <A NAME="ectl-commands"></A> </P><P>When <TT>ejabberdctl</TT> is executed without any parameter, +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc63">4.1.1</A>  <A HREF="#ectl-commands">ejabberdctl Commands</A></H3><!--SEC END --><P> <A NAME="ectl-commands"></A> </P><P>When <TT>ejabberdctl</TT> is executed without any parameter, it displays the available options. If there isn’t an <TT>ejabberd</TT> server running, the available parameters are: </P><DL CLASS="description"><DT CLASS="dt-description"> @@ -3030,7 +3066,7 @@ robot1 testuser1 testuser2 </PRE><P> <A NAME="erlangconfiguration"></A> </P><!--TOC subsection Erlang Runtime System--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc63">4.1.2</A>  <A HREF="#erlangconfiguration">Erlang Runtime System</A></H3><!--SEC END --><P> <A NAME="erlangconfiguration"></A> </P><P><TT>ejabberd</TT> is an Erlang/OTP application that runs inside an Erlang runtime system. +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc64">4.1.2</A>  <A HREF="#erlangconfiguration">Erlang Runtime System</A></H3><!--SEC END --><P> <A NAME="erlangconfiguration"></A> </P><P><TT>ejabberd</TT> is an Erlang/OTP application that runs inside an Erlang runtime system. This system is configured using environment variables and command line parameters. The <TT>ejabberdctl</TT> administration script uses many of those possibilities. You can configure some of them with the file <TT>ejabberdctl.cfg</TT>, @@ -3099,7 +3135,7 @@ Starts the Erlang system detached from the system console. </DD></DL><P> Note that some characters need to be escaped when used in shell scripts, for instance <CODE>"</CODE> and <CODE>{}</CODE>. You can find other options in the Erlang manual page (<TT>erl -man erl</TT>).</P><P> <A NAME="eja-commands"></A> </P><!--TOC section <TT>ejabberd</TT> Commands--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc64">4.2</A>  <A HREF="#eja-commands"><TT>ejabberd</TT> Commands</A></H2><!--SEC END --><P> <A NAME="eja-commands"></A> </P><P>An <TT>ejabberd command</TT> is an abstract function identified by a name, +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc65">4.2</A>  <A HREF="#eja-commands"><TT>ejabberd</TT> Commands</A></H2><!--SEC END --><P> <A NAME="eja-commands"></A> </P><P>An <TT>ejabberd command</TT> is an abstract function identified by a name, with a defined number and type of calling arguments and type of result that is registered in the <TT>ejabberd_commands</TT> service. Those commands can be defined in any Erlang module and executed using any valid frontend.</P><P><TT>ejabberd</TT> includes a frontend to execute <TT>ejabberd commands</TT>: the script <TT>ejabberdctl</TT>. @@ -3107,7 +3143,7 @@ Other known frontends that can be installed to execute ejabberd commands in diff <TT>ejabberd_xmlrpc</TT> (XML-RPC service), <TT>mod_rest</TT> (HTTP POST service), <TT>mod_shcommands</TT> (ejabberd WebAdmin page).</P><P> <A NAME="list-eja-commands"></A> </P><!--TOC subsection List of ejabberd Commands--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc65">4.2.1</A>  <A HREF="#list-eja-commands">List of ejabberd Commands</A></H3><!--SEC END --><P> <A NAME="list-eja-commands"></A> </P><P><TT>ejabberd</TT> includes a few ejabberd Commands by default. +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc66">4.2.1</A>  <A HREF="#list-eja-commands">List of ejabberd Commands</A></H3><!--SEC END --><P> <A NAME="list-eja-commands"></A> </P><P><TT>ejabberd</TT> includes a few ejabberd Commands by default. When more modules are installed, new commands may be available in the frontends.</P><P>The easiest way to get a list of the available commands, and get help for them is to use the ejabberdctl script: </P><PRE CLASS="verbatim">$ ejabberdctl help @@ -3147,7 +3183,7 @@ exist tutorials to <A HREF="http://www.ejabberd.im/migrate-to-ejabberd">migrate in offline storage. This might be useful when the number of offline messages is very high. </DD></DL><P> <A NAME="accesscommands"></A> </P><!--TOC subsection Restrict Execution with AccessCommands--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc66">4.2.2</A>  <A HREF="#accesscommands">Restrict Execution with AccessCommands</A></H3><!--SEC END --><P> <A NAME="accesscommands"></A> </P><P>The frontends can be configured to restrict access to certain commands. +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc67">4.2.2</A>  <A HREF="#accesscommands">Restrict Execution with AccessCommands</A></H3><!--SEC END --><P> <A NAME="accesscommands"></A> </P><P>The frontends can be configured to restrict access to certain commands. In that case, authentication information must be provided. In each frontend the <TT>AccessCommands</TT> option is defined in a different place. But in all cases the option syntax is the same: @@ -3193,7 +3229,7 @@ and the provided arguments do not contradict Arguments.</P><P>As an example to u {_bot_reg_test, [register, unregister], [{host, "test.org"}]} ] </PRE><P> <A NAME="webadmin"></A> </P><!--TOC section Web Admin--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc67">4.3</A>  <A HREF="#webadmin">Web Admin</A></H2><!--SEC END --><P> <A NAME="webadmin"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc68">4.3</A>  <A HREF="#webadmin">Web Admin</A></H2><!--SEC END --><P> <A NAME="webadmin"></A> </P><P>The <TT>ejabberd</TT> Web Admin allows to administer most of <TT>ejabberd</TT> using a web browser.</P><P>This feature is enabled by default: a <TT>ejabberd_http</TT> listener with the option <TT>web_admin</TT> (see section <A HREF="#listened">3.1.3</A>) is included in the listening ports. Then you can open @@ -3265,13 +3301,13 @@ The file is searched by default in The directory of the documentation can be specified in the environment variable <TT>EJABBERD_DOC_PATH</TT>. See section <A HREF="#erlangconfiguration">4.1.2</A>.</P><P> <A NAME="adhoccommands"></A> </P><!--TOC section Ad-hoc Commands--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc68">4.4</A>  <A HREF="#adhoccommands">Ad-hoc Commands</A></H2><!--SEC END --><P> <A NAME="adhoccommands"></A> </P><P>If you enable <TT>mod_configure</TT> and <TT>mod_adhoc</TT>, +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc69">4.4</A>  <A HREF="#adhoccommands">Ad-hoc Commands</A></H2><!--SEC END --><P> <A NAME="adhoccommands"></A> </P><P>If you enable <TT>mod_configure</TT> and <TT>mod_adhoc</TT>, you can perform several administrative tasks in <TT>ejabberd</TT> with a Jabber client. The client must support Ad-Hoc Commands (<A HREF="http://www.xmpp.org/extensions/xep-0050.html">XEP-0050</A>), and you must login in the Jabber server with an account with proper privileges.</P><P> <A NAME="changeerlangnodename"></A> </P><!--TOC section Change Computer Hostname--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc69">4.5</A>  <A HREF="#changeerlangnodename">Change Computer Hostname</A></H2><!--SEC END --><P> <A NAME="changeerlangnodename"></A> </P><P><TT>ejabberd</TT> uses the distributed Mnesia database. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc70">4.5</A>  <A HREF="#changeerlangnodename">Change Computer Hostname</A></H2><!--SEC END --><P> <A NAME="changeerlangnodename"></A> </P><P><TT>ejabberd</TT> uses the distributed Mnesia database. Being distributed, Mnesia enforces consistency of its file, so it stores the name of the Erlang node in it (see section <A HREF="#nodename">5.4</A>). The name of an Erlang node includes the hostname of the computer. @@ -3308,8 +3344,8 @@ mv /var/lib/ejabberd/*.* /var/lib/ejabberd/oldfiles/ </PRE></LI><LI CLASS="li-enumerate">Check that the information of the old database is available: accounts, rosters... After you finish, remember to delete the temporary backup files from public directories. </LI></OL><P> <A NAME="secure"></A> </P><!--TOC chapter Securing <TT>ejabberd</TT>--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc70">Chapter 5</A>  <A HREF="#secure">Securing <TT>ejabberd</TT></A></H1><!--SEC END --><P> <A NAME="secure"></A> </P><P> <A NAME="firewall"></A> </P><!--TOC section Firewall Settings--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc71">5.1</A>  <A HREF="#firewall">Firewall Settings</A></H2><!--SEC END --><P> <A NAME="firewall"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc71">Chapter 5</A>  <A HREF="#secure">Securing <TT>ejabberd</TT></A></H1><!--SEC END --><P> <A NAME="secure"></A> </P><P> <A NAME="firewall"></A> </P><!--TOC section Firewall Settings--> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc72">5.1</A>  <A HREF="#firewall">Firewall Settings</A></H2><!--SEC END --><P> <A NAME="firewall"></A> </P><P>You need to take the following TCP ports in mind when configuring your firewall: </P><BLOCKQUOTE CLASS="table"><DIV CLASS="center"><DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV> <TABLE BORDER=1 CELLSPACING=0 CELLPADDING=1><TR><TD ALIGN=left NOWRAP><B>Port</B></TD><TD ALIGN=left NOWRAP><B>Description</B></TD></TR> @@ -3320,7 +3356,7 @@ After you finish, remember to delete the temporary backup files from public dire <TR><TD ALIGN=left NOWRAP>port range</TD><TD ALIGN=left NOWRAP>Used for connections between Erlang nodes. This range is configurable (see section <A HREF="#epmd">5.2</A>).</TD></TR> </TABLE> <DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV></DIV></BLOCKQUOTE><P> <A NAME="epmd"></A> </P><!--TOC section epmd--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc72">5.2</A>  <A HREF="#epmd">epmd</A></H2><!--SEC END --><P> <A NAME="epmd"></A> </P><P><A HREF="http://www.erlang.org/doc/man/epmd.html">epmd (Erlang Port Mapper Daemon)</A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc73">5.2</A>  <A HREF="#epmd">epmd</A></H2><!--SEC END --><P> <A NAME="epmd"></A> </P><P><A HREF="http://www.erlang.org/doc/man/epmd.html">epmd (Erlang Port Mapper Daemon)</A> is a small name server included in Erlang/OTP and used by Erlang programs when establishing distributed Erlang communications. <TT>ejabberd</TT> needs <TT>epmd</TT> to use <TT>ejabberdctl</TT> and also when clustering <TT>ejabberd</TT> nodes. @@ -3345,7 +3381,7 @@ but can be configured in the file <TT>ejabberdctl.cfg</TT>. The Erlang command-line parameter used internally is, for example: </P><PRE CLASS="verbatim">erl ... -kernel inet_dist_listen_min 4370 inet_dist_listen_max 4375 </PRE><P> <A NAME="cookie"></A> </P><!--TOC section Erlang Cookie--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc73">5.3</A>  <A HREF="#cookie">Erlang Cookie</A></H2><!--SEC END --><P> <A NAME="cookie"></A> </P><P>The Erlang cookie is a string with numbers and letters. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc74">5.3</A>  <A HREF="#cookie">Erlang Cookie</A></H2><!--SEC END --><P> <A NAME="cookie"></A> </P><P>The Erlang cookie is a string with numbers and letters. An Erlang node reads the cookie at startup from the command-line parameter <TT>-setcookie</TT>. If not indicated, the cookie is read from the cookie file <TT>$HOME/.erlang.cookie</TT>. If this file does not exist, it is created immediately with a random cookie. @@ -3359,7 +3395,7 @@ to prevent unauthorized access or intrusion to an Erlang node. The communication between Erlang nodes are not encrypted, so the cookie could be read sniffing the traffic on the network. The recommended way to secure the Erlang node is to block the port 4369.</P><P> <A NAME="nodename"></A> </P><!--TOC section Erlang Node Name--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc74">5.4</A>  <A HREF="#nodename">Erlang Node Name</A></H2><!--SEC END --><P> <A NAME="nodename"></A> </P><P>An Erlang node may have a node name. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc75">5.4</A>  <A HREF="#nodename">Erlang Node Name</A></H2><!--SEC END --><P> <A NAME="nodename"></A> </P><P>An Erlang node may have a node name. The name can be short (if indicated with the command-line parameter <TT>-sname</TT>) or long (if indicated with the parameter <TT>-name</TT>). Starting an Erlang node with -sname limits the communication between Erlang nodes to the LAN.</P><P>Using the option <TT>-sname</TT> instead of <TT>-name</TT> is a simple method @@ -3368,7 +3404,7 @@ However, it is not ultimately effective to prevent access to the Erlang node, because it may be possible to fake the fact that you are on another network using a modified version of Erlang <TT>epmd</TT>. The recommended way to secure the Erlang node is to block the port 4369.</P><P> <A NAME="secure-files"></A> </P><!--TOC section Securing Sensible Files--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc75">5.5</A>  <A HREF="#secure-files">Securing Sensible Files</A></H2><!--SEC END --><P> <A NAME="secure-files"></A> </P><P><TT>ejabberd</TT> stores sensible data in the file system either in plain text or binary files. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc76">5.5</A>  <A HREF="#secure-files">Securing Sensible Files</A></H2><!--SEC END --><P> <A NAME="secure-files"></A> </P><P><TT>ejabberd</TT> stores sensible data in the file system either in plain text or binary files. The file system permissions should be set to only allow the proper user to read, write and execute those files and directories.</P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>ejabberd configuration file: /etc/ejabberd/ejabberd.cfg</TT></B></DT><DD CLASS="dd-description"> @@ -3388,9 +3424,9 @@ so it is preferable to secure the whole <TT>/var/lib/ejabberd/</TT> directory. </DD><DT CLASS="dt-description"><B><TT>Erlang cookie file: /var/lib/ejabberd/.erlang.cookie</TT></B></DT><DD CLASS="dd-description"> See section <A HREF="#cookie">5.3</A>. </DD></DL><P> <A NAME="clustering"></A> </P><!--TOC chapter Clustering--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc76">Chapter 6</A>  <A HREF="#clustering">Clustering</A></H1><!--SEC END --><P> <A NAME="clustering"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc77">Chapter 6</A>  <A HREF="#clustering">Clustering</A></H1><!--SEC END --><P> <A NAME="clustering"></A> </P><P> <A NAME="howitworks"></A> </P><!--TOC section How it Works--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc77">6.1</A>  <A HREF="#howitworks">How it Works</A></H2><!--SEC END --><P> <A NAME="howitworks"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc78">6.1</A>  <A HREF="#howitworks">How it Works</A></H2><!--SEC END --><P> <A NAME="howitworks"></A> </P><P>A Jabber domain is served by one or more <TT>ejabberd</TT> nodes. These nodes can be run on different machines that are connected via a network. They all must have the ability to connect to port 4369 of all another nodes, and must @@ -3404,29 +3440,29 @@ router, </LI><LI CLASS="li-itemize">session manager, </LI><LI CLASS="li-itemize">s2s manager. </LI></UL><P> <A NAME="router"></A> </P><!--TOC subsection Router--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc78">6.1.1</A>  <A HREF="#router">Router</A></H3><!--SEC END --><P> <A NAME="router"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc79">6.1.1</A>  <A HREF="#router">Router</A></H3><!--SEC END --><P> <A NAME="router"></A> </P><P>This module is the main router of Jabber packets on each node. It routes them based on their destination’s domains. It uses a global routing table. The domain of the packet’s destination is searched in the routing table, and if it is found, the packet is routed to the appropriate process. If not, it is sent to the s2s manager.</P><P> <A NAME="localrouter"></A> </P><!--TOC subsection Local Router--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc79">6.1.2</A>  <A HREF="#localrouter">Local Router</A></H3><!--SEC END --><P> <A NAME="localrouter"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc80">6.1.2</A>  <A HREF="#localrouter">Local Router</A></H3><!--SEC END --><P> <A NAME="localrouter"></A> </P><P>This module routes packets which have a destination domain equal to one of this server’s host names. If the destination JID has a non-empty user part, it is routed to the session manager, otherwise it is processed depending on its content.</P><P> <A NAME="sessionmanager"></A> </P><!--TOC subsection Session Manager--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc80">6.1.3</A>  <A HREF="#sessionmanager">Session Manager</A></H3><!--SEC END --><P> <A NAME="sessionmanager"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc81">6.1.3</A>  <A HREF="#sessionmanager">Session Manager</A></H3><!--SEC END --><P> <A NAME="sessionmanager"></A> </P><P>This module routes packets to local users. It looks up to which user resource a packet must be sent via a presence table. Then the packet is either routed to the appropriate c2s process, or stored in offline storage, or bounced back.</P><P> <A NAME="s2smanager"></A> </P><!--TOC subsection s2s Manager--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc81">6.1.4</A>  <A HREF="#s2smanager">s2s Manager</A></H3><!--SEC END --><P> <A NAME="s2smanager"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc82">6.1.4</A>  <A HREF="#s2smanager">s2s Manager</A></H3><!--SEC END --><P> <A NAME="s2smanager"></A> </P><P>This module routes packets to other Jabber servers. First, it checks if an opened s2s connection from the domain of the packet’s source to the domain of the packet’s destination exists. If that is the case, the s2s manager routes the packet to the process serving this connection, otherwise a new connection is opened.</P><P> <A NAME="cluster"></A> </P><!--TOC section Clustering Setup--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc82">6.2</A>  <A HREF="#cluster">Clustering Setup</A></H2><!--SEC END --><P> <A NAME="cluster"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc83">6.2</A>  <A HREF="#cluster">Clustering Setup</A></H2><!--SEC END --><P> <A NAME="cluster"></A> </P><P>Suppose you already configured <TT>ejabberd</TT> on one machine named (<TT>first</TT>), and you need to setup another one to make an <TT>ejabberd</TT> cluster. Then do following steps:</P><OL CLASS="enumerate" type=1><LI CLASS="li-enumerate"> @@ -3464,10 +3500,10 @@ and ‘<CODE>access</CODE>’ options because they will be taken from enabled only on one machine in the cluster. </LI></OL><P>You can repeat these steps for other machines supposed to serve this domain.</P><P> <A NAME="servicelb"></A> </P><!--TOC section Service Load-Balancing--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc83">6.3</A>  <A HREF="#servicelb">Service Load-Balancing</A></H2><!--SEC END --><P> <A NAME="servicelb"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc84">6.3</A>  <A HREF="#servicelb">Service Load-Balancing</A></H2><!--SEC END --><P> <A NAME="servicelb"></A> </P><P> <A NAME="componentlb"></A> </P><!--TOC subsection Components Load-Balancing--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc84">6.3.1</A>  <A HREF="#componentlb">Components Load-Balancing</A></H3><!--SEC END --><P> <A NAME="componentlb"></A> </P><P> <A NAME="domainlb"></A> </P><!--TOC subsection Domain Load-Balancing Algorithm--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc85">6.3.2</A>  <A HREF="#domainlb">Domain Load-Balancing Algorithm</A></H3><!--SEC END --><P> <A NAME="domainlb"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc85">6.3.1</A>  <A HREF="#componentlb">Components Load-Balancing</A></H3><!--SEC END --><P> <A NAME="componentlb"></A> </P><P> <A NAME="domainlb"></A> </P><!--TOC subsection Domain Load-Balancing Algorithm--> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc86">6.3.2</A>  <A HREF="#domainlb">Domain Load-Balancing Algorithm</A></H3><!--SEC END --><P> <A NAME="domainlb"></A> </P><P><TT>ejabberd</TT> includes an algorithm to load balance the components that are plugged on an <TT>ejabberd</TT> cluster. It means that you can plug one or several instances of the same component on each <TT>ejabberd</TT> cluster and that the traffic will be automatically distributed.</P><P>The default distribution algorithm try to deliver to a local instance of a component. If several local instances are available, one instance is chosen randomly. If no instance is available locally, one instance is chosen randomly among the remote component instances.</P><P>If you need a different behaviour, you can change the load balancing behaviour with the option <TT>domain_balancing</TT>. The syntax of the option is the following:</P><PRE CLASS="verbatim">{domain_balancing, "component.example.com", <balancing_criterium>}. </PRE><P>Several balancing criteria are available: </P><UL CLASS="itemize"><LI CLASS="li-itemize"> @@ -3476,13 +3512,13 @@ domain.</P><P> <A NAME="servicelb"></A> </P><!--TOC section Service Load-Balanci </LI><LI CLASS="li-itemize"><TT>bare_destination</TT>: the bare JID (without resource) of the packet <TT>to</TT> attribute is used. </LI><LI CLASS="li-itemize"><TT>bare_source</TT>: the bare JID (without resource) of the packet <TT>from</TT> attribute is used. </LI></UL><P>If the value corresponding to the criteria is the same, the same component instance in the cluster will be used.</P><P> <A NAME="lbbuckets"></A> </P><!--TOC subsection Load-Balancing Buckets--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc86">6.3.3</A>  <A HREF="#lbbuckets">Load-Balancing Buckets</A></H3><!--SEC END --><P> <A NAME="lbbuckets"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc87">6.3.3</A>  <A HREF="#lbbuckets">Load-Balancing Buckets</A></H3><!--SEC END --><P> <A NAME="lbbuckets"></A> </P><P>When there is a risk of failure for a given component, domain balancing can cause service trouble. If one component is failing the service will not work correctly unless the sessions are rebalanced.</P><P>In this case, it is best to limit the problem to the sessions handled by the failing component. This is what the <TT>domain_balancing_component_number</TT> option does, making the load balancing algorithm not dynamic, but sticky on a fix number of component instances.</P><P>The syntax is the following: </P><PRE CLASS="verbatim">{domain_balancing_component_number, "component.example.com", N} </PRE><P> <A NAME="debugging"></A> </P><!--TOC chapter Debugging--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc87">Chapter 7</A>  <A HREF="#debugging">Debugging</A></H1><!--SEC END --><P> <A NAME="debugging"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc88">Chapter 7</A>  <A HREF="#debugging">Debugging</A></H1><!--SEC END --><P> <A NAME="debugging"></A> </P><P> <A NAME="logfiles"></A> </P><!--TOC section Log Files--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc88">7.1</A>  <A HREF="#logfiles">Log Files</A></H2><!--SEC END --><P> <A NAME="logfiles"></A> </P><P>An <TT>ejabberd</TT> node writes two log files: +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc89">7.1</A>  <A HREF="#logfiles">Log Files</A></H2><!--SEC END --><P> <A NAME="logfiles"></A> </P><P>An <TT>ejabberd</TT> node writes two log files: </P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>ejabberd.log</TT></B></DT><DD CLASS="dd-description"> is the ejabberd service log, with the messages reported by <TT>ejabberd</TT> code </DD><DT CLASS="dt-description"><B><TT>sasl.log</TT></B></DT><DD CLASS="dd-description"> is the Erlang/OTP system log, with the messages reported by Erlang/OTP using SASL (System Architecture Support Libraries) @@ -3504,12 +3540,12 @@ The ejabberdctl command <TT>reopen-log</TT> (please refer to section <A HREF="#ectl-commands">4.1.1</A>) reopens the log files, and also renames the old ones if you didn’t rename them.</P><P> <A NAME="debugconsole"></A> </P><!--TOC section Debug Console--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc89">7.2</A>  <A HREF="#debugconsole">Debug Console</A></H2><!--SEC END --><P> <A NAME="debugconsole"></A> </P><P>The Debug Console is an Erlang shell attached to an already running <TT>ejabberd</TT> server. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc90">7.2</A>  <A HREF="#debugconsole">Debug Console</A></H2><!--SEC END --><P> <A NAME="debugconsole"></A> </P><P>The Debug Console is an Erlang shell attached to an already running <TT>ejabberd</TT> server. With this Erlang shell, an experienced administrator can perform complex tasks.</P><P>This shell gives complete control over the <TT>ejabberd</TT> server, so it is important to use it with extremely care. There are some simple and safe examples in the article <A HREF="http://www.ejabberd.im/interconnect-erl-nodes">Interconnecting Erlang Nodes</A></P><P>To exit the shell, close the window or press the keys: control+c control+c.</P><P> <A NAME="watchdog"></A> </P><!--TOC section Watchdog Alerts--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc90">7.3</A>  <A HREF="#watchdog">Watchdog Alerts</A></H2><!--SEC END --><P> <A NAME="watchdog"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc91">7.3</A>  <A HREF="#watchdog">Watchdog Alerts</A></H2><!--SEC END --><P> <A NAME="watchdog"></A> </P><P><TT>ejabberd</TT> includes a watchdog mechanism that may be useful to developers when troubleshooting a problem related to memory usage. If a process in the <TT>ejabberd</TT> server consumes more memory than the configured threshold, @@ -3527,7 +3563,7 @@ or in a conversation with the watchdog alert bot.</P><P>Example configuration: To remove all watchdog admins, set the option with an empty list: </P><PRE CLASS="verbatim">{watchdog_admins, []}. </PRE><P> <A NAME="i18ni10n"></A> </P><!--TOC chapter Internationalization and Localization--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc91">Appendix A</A>  <A HREF="#i18ni10n">Internationalization and Localization</A></H1><!--SEC END --><P> <A NAME="i18ni10n"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc92">Appendix A</A>  <A HREF="#i18ni10n">Internationalization and Localization</A></H1><!--SEC END --><P> <A NAME="i18ni10n"></A> </P><P>The source code of <TT>ejabberd</TT> supports localization. The translators can edit the <A HREF="http://www.gnu.org/software/gettext/">gettext</A> .po files @@ -3562,9 +3598,9 @@ HTTP header ‘Accept-Language: ru’</TD></TR> </TABLE></DIV> <A NAME="fig:webadmmainru"></A> <DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV></DIV></BLOCKQUOTE><P> <A NAME="releasenotes"></A> </P><!--TOC chapter Release Notes--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc92">Appendix B</A>  <A HREF="#releasenotes">Release Notes</A></H1><!--SEC END --><P> <A NAME="releasenotes"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc93">Appendix B</A>  <A HREF="#releasenotes">Release Notes</A></H1><!--SEC END --><P> <A NAME="releasenotes"></A> </P><P>Release notes are available from <A HREF="http://www.process-one.net/en/ejabberd/release_notes/">ejabberd Home Page</A></P><P> <A NAME="acknowledgements"></A> </P><!--TOC chapter Acknowledgements--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc93">Appendix C</A>  <A HREF="#acknowledgements">Acknowledgements</A></H1><!--SEC END --><P> <A NAME="acknowledgements"></A> </P><P>Thanks to all people who contributed to this guide: +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc94">Appendix C</A>  <A HREF="#acknowledgements">Acknowledgements</A></H1><!--SEC END --><P> <A NAME="acknowledgements"></A> </P><P>Thanks to all people who contributed to this guide: </P><UL CLASS="itemize"><LI CLASS="li-itemize"> Alexey Shchepin (<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A>) </LI><LI CLASS="li-itemize">Badlop (<A HREF="xmpp:badlop@jabberes.org"><TT>xmpp:badlop@jabberes.org</TT></A>) @@ -3576,7 +3612,7 @@ Alexey Shchepin (<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT </LI><LI CLASS="li-itemize">Sergei Golovan (<A HREF="xmpp:sgolovan@nes.ru"><TT>xmpp:sgolovan@nes.ru</TT></A>) </LI><LI CLASS="li-itemize">Vsevolod Pelipas (<A HREF="xmpp:vsevoload@jabber.ru"><TT>xmpp:vsevoload@jabber.ru</TT></A>) </LI></UL><P> <A NAME="copyright"></A> </P><!--TOC chapter Copyright Information--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc94">Appendix D</A>  <A HREF="#copyright">Copyright Information</A></H1><!--SEC END --><P> <A NAME="copyright"></A> </P><P>Ejabberd Installation and Operation Guide.<BR> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc95">Appendix D</A>  <A HREF="#copyright">Copyright Information</A></H1><!--SEC END --><P> <A NAME="copyright"></A> </P><P>Ejabberd Installation and Operation Guide.<BR> Copyright © 2003 — 2009 ProcessOne</P><P>This document 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 diff --git a/doc/guide.tex b/doc/guide.tex index 195fb875e..b5a36f123 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -305,6 +305,7 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need: \item Erlang pgsql library. Optional. For PostgreSQL authentication or storage. See section \ref{compilepgsql}. \item PAM library. Optional. For Pluggable Authentication Modules (PAM). See section \ref{pam}. \item GNU Iconv 1.8 or higher, for the IRC Transport (mod\_irc). Optional. Not needed on systems with GNU Libc. See section \ref{modirc}. +\item ImageMagick's Convert program. Optional. For CAPTCHA challenges. See section \ref{captcha}. \end{itemize} \makesubsection{download}{Download Source Code} @@ -393,7 +394,7 @@ The files and directories created are, by default: \titem{include/} Erlang header files (*.hrl) \titem{priv/} Additional files required at runtime \begin{description} - \titem{bin/} Binary C programs + \titem{bin/} Executable programs \titem{lib/} Binary system libraries (*.so) \titem{msgs/} Translation files (*.msgs) \end{description} @@ -799,7 +800,7 @@ The available modules, their purpose and the options allowed by each one are: \texttt{shaper}, \texttt{service\_check\_from} \titem{\texttt{ejabberd\_http}} Handles incoming HTTP connections.\\ - Options: \texttt{certfile}, \texttt{http\_bind}, \texttt{http\_poll}, + Options: \texttt{captcha}, \texttt{certfile}, \texttt{http\_bind}, \texttt{http\_poll}, \texttt{request\_handlers}, \texttt{tls}, \texttt{web\_admin}\\ \end{description} @@ -826,6 +827,8 @@ This is a detailed description of each option allowed by the listening modules: Note that you cannot define in a single \term{ejabberd\_service} components of different services: add an \term{ejabberd\_service} for each service, as seen in an example below. + \titem{captcha} \ind{options!http-captcha} + Simple web page that allows a user to fill a CAPTCHA challenge (see section \ref{captcha}). \titem{http\_bind} \ind{options!http\_bind}\ind{protocols!XEP-0206: HTTP Binding}\ind{JWChat}\ind{web-based Jabber client} This option enables HTTP Binding (\xepref{0124} and \xepref{0206}) support. HTTP Bind enables access via HTTP requests to \ejabberd{} from behind firewalls which @@ -1498,6 +1501,51 @@ For example, to set Russian as default language: Appendix \ref{i18ni10n} provides more details about internationalization and localization. +\makesubsection{captcha}{CAPTCHA} +\ind{options!captcha}\ind{captcha} + +Some \ejabberd{} modules can be configured to require a CAPTCHA challenge on certain actions. +If the client does not support CAPTCHA Forms (\xepref{0158}), +a web link is provided so the user can fill the challenge in a web browser. + +An example script is provided that generates the image +using ImageMagick's Convert program. + +The configurable options are: +\begin{description} + \titem{\{captcha\_cmd, Path\}} + Full path to a script that generates the image. + The default value is an empty string: \term{""} + \titem{\{captcha\_host, Host\}} + Host part of the URL sent to the user. + You can include the port number. + The URL sent to the user is formed by: \term{http://Host/captcha/} + The default value is the first hostname configured. +\end{description} + +Additionally, an \term{ejabberd\_http} listener must be enabled with the \term{captcha} option. +See section \ref{listened-module}. + +Example configuration: +\begin{verbatim} +{hosts, ["example.org"]}. + +{captcha_cmd, "/lib/ejabberd/priv/bin/captcha.sh"}. +{captcha_host, "example.org:5280"}. + +{listen, + [ + ... + {5280, ejabberd_http, [ + captcha, + ... + ] + } + +]}. +\end{verbatim} + + \makesubsection{includeconfigfile}{Include Additional Configuration Files} \ind{options!includeconfigfile}\ind{includeconfigfile} diff --git a/src/Makefile.in b/src/Makefile.in index a311081f1..8ba622d54 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -208,6 +208,7 @@ install: all # # Binary C programs install -d $(PBINDIR) + install -m 750 $(O_USER) ../tools/captcha.sh $(PBINDIR) $(INSTALL_EPAM) # # Binary system libraries diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index 7161e5e34..783775bb7 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -150,7 +150,8 @@ %% ]}, {5280, ejabberd_http, [ - http_poll, + captcha, + http_poll, web_admin ]} @@ -426,6 +427,20 @@ %%}. +%%%. ======= +%%%' CAPTCHA + +%% +%% Full path to a script that generates the image. +%% +%%{captcha_cmd, "/lib/ejabberd/priv/bin/captcha.sh"}. + +%% +%% Host part of the URL sent to the user. +%% +%%{captcha_host, "example.org:5280"}. + + %%%. ================ %%%' DEFAULT LANGUAGE From aa210166c4066ab03a35ca5e83322c908c11d969 Mon Sep 17 00:00:00 2001 From: Christophe Romain <christophe.romain@process-one.net> Date: Tue, 26 May 2009 21:50:13 +0000 Subject: [PATCH 321/582] improve get_entity_* to work regardless of nodetree (EJAB-937) SVN Revision: 2104 --- src/mod_pubsub/gen_pubsub_nodetree.erl | 1 + src/mod_pubsub/mod_pubsub.erl | 8 ++++--- src/mod_pubsub/node_default.erl | 30 +++++++++++------------- src/mod_pubsub/node_pep.erl | 32 ++++++++++++++++++-------- src/mod_pubsub/nodetree_default.erl | 7 ++++++ src/mod_pubsub/nodetree_virtual.erl | 5 +++- 6 files changed, 53 insertions(+), 30 deletions(-) diff --git a/src/mod_pubsub/gen_pubsub_nodetree.erl b/src/mod_pubsub/gen_pubsub_nodetree.erl index 941748e68..f012b3d0b 100644 --- a/src/mod_pubsub/gen_pubsub_nodetree.erl +++ b/src/mod_pubsub/gen_pubsub_nodetree.erl @@ -44,6 +44,7 @@ behaviour_info(callbacks) -> {set_node, 1}, {get_node, 3}, {get_node, 2}, + {get_node, 1}, {get_nodes, 2}, {get_nodes, 1}, {get_subnodes, 3}, diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index ca614bd92..43cf49f76 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -167,12 +167,12 @@ init([ServerHost, Opts]) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), ServerHostB = list_to_binary(ServerHost), pubsub_index:init(Host, ServerHost, Opts), + ets:new(gen_mod:get_module_proc(Host, pubsub_state), [set, named_table]), + ets:new(gen_mod:get_module_proc(ServerHost, pubsub_state), [set, named_table]), {Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts), mod_disco:register_feature(ServerHost, ?NS_PUBSUB_s), - ets:new(gen_mod:get_module_proc(Host, pubsub_state), [set, named_table]), ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {nodetree, NodeTree}), ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {plugins, Plugins}), - ets:new(gen_mod:get_module_proc(ServerHost, pubsub_state), [set, named_table]), ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {nodetree, NodeTree}), ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {plugins, Plugins}), ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {pep_mapping, PepMapping}), @@ -3018,6 +3018,7 @@ tree_call(Host, Function, Args) -> end, catch apply(Module, Function, Args). tree_action(Host, Function, Args) -> + ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), Fun = fun() -> tree_call(Host, Function, Args) end, catch mnesia:sync_dirty(Fun). @@ -3037,7 +3038,8 @@ node_call(Type, Function, Args) -> Result -> {result, Result} %% any other return value is forced as result end. -node_action(_Host, Type, Function, Args) -> +node_action(Host, Type, Function, Args) -> + ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), transaction(fun() -> node_call(Type, Function, Args) end, sync_dirty). diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index bd972b550..013b5c211 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -552,15 +552,14 @@ purge_node(NodeId, Owner) -> get_entity_affiliations(Host, Owner) -> GenKey = jlib:short_prepd_bare_jid(Owner), States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'}), + NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, pubsub_state), nodetree) of + [{nodetree, N}] -> N; + _ -> nodetree_default + end, Reply = lists:foldl(fun(#pubsub_state{stateid = {_, N}, affiliation = A}, Acc) -> - case mnesia:index_read(pubsub_node, N, #pubsub_node.id) of - [#pubsub_node{nodeid = {H, _}} = Node] -> - case H of - Host -> [{Node, A}|Acc]; - _ -> Acc - end; - _ -> - Acc + case NodeTree:get_node(N) of + #pubsub_node{nodeid = {Host, _}} = Node -> [{Node, A}|Acc]; + _ -> Acc end end, [], States), {result, Reply}. @@ -608,15 +607,14 @@ get_entity_subscriptions(Host, Owner) -> ++ mnesia:match_object( #pubsub_state{stateid = {SubKey, '_'}, _ = '_'}) end, + NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, pubsub_state), nodetree) of + [{nodetree, N}] -> N; + _ -> nodetree_default + end, Reply = lists:foldl(fun(#pubsub_state{stateid = {J, N}, subscription = S}, Acc) -> - case mnesia:index_read(pubsub_node, N, #pubsub_node.id) of - [#pubsub_node{nodeid = {H, _}} = Node] -> - case H of - Host -> [{Node, S, J}|Acc]; - _ -> Acc - end; - _ -> - Acc + case NodeTree:get_node(N) of + #pubsub_node{nodeid = {Host, _}} = Node -> [{Node, S, J}|Acc]; + _ -> Acc end end, [], States), {result, Reply}. diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index 01523a087..868370eb8 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -170,8 +170,21 @@ purge_node(NodeId, Owner) -> node_default:purge_node(NodeId, Owner). get_entity_affiliations(_Host, Owner) -> - OwnerKey = jlib:short_prepd_bare_jid(Owner), - node_default:get_entity_affiliations(OwnerKey, Owner). + {_, D, _} = SubKey = jlib:jid_tolower(Owner), + SubKey = jlib:jid_tolower(Owner), + GenKey = jlib:jid_remove_resource(SubKey), + States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'}), + NodeTree = case ets:lookup(gen_mod:get_module_proc(D, pubsub_state), nodetree) of + [{nodetree, N}] -> N; + _ -> nodetree_default + end, + Reply = lists:foldl(fun(#pubsub_state{stateid = {_, N}, affiliation = A}, Acc) -> + case NodeTree:get_node(N) of + #pubsub_node{nodeid = {{_, D, _}, _}} = Node -> [{Node, A}|Acc]; + _ -> Acc + end + end, [], States), + {result, Reply}. get_node_affiliations(NodeId) -> node_default:get_node_affiliations(NodeId). @@ -193,15 +206,14 @@ get_entity_subscriptions(_Host, Owner) -> ++ mnesia:match_object( #pubsub_state{stateid = {SubKey, '_'}, _ = '_'}) end, + NodeTree = case ets:lookup(gen_mod:get_module_proc(D, pubsub_state), nodetree) of + [{nodetree, N}] -> N; + _ -> nodetree_default + end, Reply = lists:foldl(fun(#pubsub_state{stateid = {J, N}, subscription = S}, Acc) -> - case mnesia:index_read(pubsub_node, N, #pubsub_node.id) of - [#pubsub_node{nodeid = {H, _}} = Node] -> - case H of - {_, D, _} -> [{Node, S, J}|Acc]; - _ -> Acc - end; - _ -> - Acc + case NodeTree:get_node(N) of + #pubsub_node{nodeid = {{_, D, _}, _}} = Node -> [{Node, S, J}|Acc]; + _ -> Acc end end, [], States), {result, Reply}. diff --git a/src/mod_pubsub/nodetree_default.erl b/src/mod_pubsub/nodetree_default.erl index dd5b3391f..eb5759f9a 100644 --- a/src/mod_pubsub/nodetree_default.erl +++ b/src/mod_pubsub/nodetree_default.erl @@ -48,6 +48,7 @@ set_node/1, get_node/3, get_node/2, + get_node/1, get_nodes/2, get_nodes/1, get_subnodes/3, @@ -110,6 +111,12 @@ get_node(Host, Node) -> [] -> {error, 'item-not-found'}; Error -> Error end. +get_node(NodeId) -> + case catch mnesia:index_read(pubsub_node, NodeId, #pubsub_node.id) of + [Record] when is_record(Record, pubsub_node) -> Record; + [] -> {error, 'item-not-found'}; + Error -> Error + end. %% @spec (Host) -> [pubsubNode()] | {error, Reason} %% Host = mod_pubsub:host() | mod_pubsub:jid() diff --git a/src/mod_pubsub/nodetree_virtual.erl b/src/mod_pubsub/nodetree_virtual.erl index 1083e5581..fd6887431 100644 --- a/src/mod_pubsub/nodetree_virtual.erl +++ b/src/mod_pubsub/nodetree_virtual.erl @@ -45,6 +45,7 @@ set_node/1, get_node/3, get_node/2, + get_node/1, get_nodes/2, get_nodes/1, get_subnodes/3, @@ -91,7 +92,9 @@ set_node(_NodeRecord) -> get_node(Host, Node, _From) -> get_node(Host, Node). get_node(Host, Node) -> - #pubsub_node{nodeid = {Host, Node}}. + #pubsub_node{nodeid = {Host, Node}, id = {Host, Node}}. +get_node(NodeId) -> + #pubsub_node{nodeid = NodeId, id = NodeId}. %% @spec (Host) -> [pubsubNode()] %% Host = mod_pubsub:host() | mod_pubsub:jid() From 45a8a0fb53562d815fc43b18dd871d16030128bc Mon Sep 17 00:00:00 2001 From: Christophe Romain <christophe.romain@process-one.net> Date: Tue, 26 May 2009 22:50:11 +0000 Subject: [PATCH 322/582] make get_items able to sort items in publish order (EJAB-824) SVN Revision: 2105 --- src/mod_pubsub/mod_pubsub.erl | 23 ++++------------------- src/mod_pubsub/node_default.erl | 5 ++--- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 43cf49f76..615f1d3fa 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -445,8 +445,6 @@ send_loop(State) -> send_loop(State); {presence, User, Server, Resources, JID} -> %% get resources caps and check if processing is needed - %% get_caps may be blocked few seconds, get_caps as well - %% so we spawn the whole process not to block other queries spawn(fun() -> {HasCaps, ResourcesCaps} = lists:foldl(fun(Resource, {R, L}) -> case mod_caps:get_caps({User, Server, Resource}) of @@ -1985,29 +1983,16 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> %% Number = last | integer() %% @doc <p>Resend the items of a node to the user.</p> %% @todo use cache-last-item feature +send_items(Host, Node, NodeId, Type, LJID, last) -> + send_items(Host, Node, NodeId, Type, LJID, 1); send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of {result, []} -> []; {result, Items} -> case Number of - last -> - %%% [lists:last(Items)] does not work on clustered table - [First|Tail] = Items, - [lists:foldl( - fun(CurItem, LastItem) -> - {LTimeStamp, _} = LastItem#pubsub_item.creation, - {CTimeStamp, _} = CurItem#pubsub_item.creation, - if - CTimeStamp > LTimeStamp -> CurItem; - true -> LastItem - end - end, First, Tail)]; - N when N > 0 -> - %%% This case is buggy on clustered table due to lack of order - lists:nthtail(length(Items)-N, Items); - _ -> - Items + N when N > 0 -> lists:sublist(Items, N); + _ -> Items end; _ -> [] diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl index 013b5c211..663a508c2 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_default.erl @@ -699,9 +699,8 @@ del_state(NodeId, JID) -> %% ```get_items(NodeId, From) -> %% node_default:get_items(NodeId, From).'''</p> get_items(NodeId, _From) -> - Items = mnesia:match_object( - #pubsub_item{itemid = {'_', NodeId}, _ = '_'}), - {result, Items}. + Items = mnesia:match_object(#pubsub_item{itemid = {'_', NodeId}, _ = '_'}), + {result, lists:reverse(lists:keysort(#pubsub_item.modification, Items))}. get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> GenKey = jlib:short_prepd_bare_jid(JID), GenState = get_state(NodeId, GenKey), From dc613df3b1bfc52ff9412e3d6d3f5ca5c84dcc4d Mon Sep 17 00:00:00 2001 From: Pablo Polvorin <pablo.polvorin@process-one.net> Date: Wed, 27 May 2009 15:02:44 +0000 Subject: [PATCH 323/582] Do not indent the resulting html. Indentation in exmpp is buggy, and there isn't a real adventage on indenting the generated html SVN Revision: 2106 --- src/web/ejabberd_http.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/ejabberd_http.erl b/src/web/ejabberd_http.erl index 0310737b5..facfcef4b 100644 --- a/src/web/ejabberd_http.erl +++ b/src/web/ejabberd_http.erl @@ -472,10 +472,10 @@ make_xhtml_output(State, Status, Headers, XHTML) -> Data = case lists:member(html, Headers) of true -> list_to_binary([?HTML_DOCTYPE, - exmpp_xml:document_to_list(exmpp_xml:indent_document(XHTML, <<>>))]); + exmpp_xml:document_to_list(XHTML)]); _ -> list_to_binary([?XHTML_DOCTYPE, - exmpp_xml:document_to_list(exmpp_xml:indent_document(XHTML, <<>>))]) + exmpp_xml:document_to_list(XHTML)]) end, Headers1 = case lists:keysearch("Content-Type", 1, Headers) of {value, _} -> From a1fe76fb5ba506f23382a1c219e9dab1fd88f68a Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Wed, 27 May 2009 17:29:43 +0000 Subject: [PATCH 324/582] Support to select what modules to update. Split large function in smaller ones. SVN Revision: 2109 --- src/ejabberd_update.erl | 111 +++++++++++++++++++++++---------- src/web/ejabberd_web_admin.erl | 71 +++++++++++++++++++-- 2 files changed, 145 insertions(+), 37 deletions(-) diff --git a/src/ejabberd_update.erl b/src/ejabberd_update.erl index 7d5ae36c9..de2333558 100644 --- a/src/ejabberd_update.erl +++ b/src/ejabberd_update.erl @@ -28,13 +28,15 @@ -author('alexey@process-one.net'). %% API --export([update/0, update_info/0]). +-export([update/0, update/1, update_info/0]). -include("ejabberd.hrl"). %%==================================================================== %% API %%==================================================================== + +%% Update all the modified modules update() -> case update_info() of {ok, Dir, _UpdatedBeams, _Script, LowLevelScript, _Check} -> @@ -48,48 +50,91 @@ update() -> {error, Reason} end. -update_info() -> - Dir = filename:dirname(code:which(ejabberd)), - case file:list_dir(Dir) of - {ok, Files} -> - Beams = [list_to_atom(filename:rootname(FN)) || - FN <- Files, lists:suffix(".beam", FN)], - UpdatedBeams = - lists:filter( - fun(Module) -> - {ok, {Module, NewVsn}} = - beam_lib:version(code:which(Module)), - case code:is_loaded(Module) of - {file, _} -> - Attrs = Module:module_info(attributes), - {value, {vsn, CurVsn}} = - lists:keysearch(vsn, 1, Attrs), - NewVsn /= CurVsn; - false -> - false - end - end, Beams), - ?INFO_MSG("beam files: ~p~n", [UpdatedBeams]), - Script = make_script(UpdatedBeams), - ?INFO_MSG("script: ~p~n", [Script]), - LowLevelScript = make_low_level_script(UpdatedBeams, Script), - ?INFO_MSG("low level script: ~p~n", [LowLevelScript]), - Check = - release_handler_1:check_script( - LowLevelScript, +%% Update only the specified modules +update(ModulesToUpdate) -> + case update_info() of + {ok, Dir, UpdatedBeamsAll, _Script, _LowLevelScript, _Check} -> + UpdatedBeamsNow = + [A || A <- UpdatedBeamsAll, B <- ModulesToUpdate, A == B], + {_, LowLevelScript, _} = build_script(Dir, UpdatedBeamsNow), + Eval = + release_handler_1:eval_script( + LowLevelScript, [], [{ejabberd, "", filename:join(Dir, "..")}]), - ?INFO_MSG("check: ~p~n", [Check]), - {ok, Dir, UpdatedBeams, Script, LowLevelScript, Check}; + ?INFO_MSG("eval: ~p~n", [Eval]), + Eval; {error, Reason} -> {error, Reason} end. +%% Get information about the modified modules +update_info() -> + Dir = filename:dirname(code:which(ejabberd)), + case file:list_dir(Dir) of + {ok, Files} -> + update_info(Dir, Files); + {error, Reason} -> + {error, Reason} + end. %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- -%% From systools.hrl +update_info(Dir, Files) -> + Beams = lists:sort(get_beams(Files)), + UpdatedBeams = get_updated_beams(Beams), + ?INFO_MSG("beam files: ~p~n", [UpdatedBeams]), + {Script, LowLevelScript, Check} = build_script(Dir, UpdatedBeams), + {ok, Dir, UpdatedBeams, Script, LowLevelScript, Check}. + +get_beams(Files) -> + [list_to_atom(filename:rootname(FN)) + || FN <- Files, lists:suffix(".beam", FN)]. + +%% Return only the beams that have different version +get_updated_beams(Beams) -> + lists:filter( + fun(Module) -> + NewVsn = get_new_version(Module), + case code:is_loaded(Module) of + {file, _} -> + CurVsn = get_current_version(Module), + (NewVsn /= CurVsn + andalso NewVsn /= unknown_version); + false -> + false + end + end, Beams). + +get_new_version(Module) -> + Path = code:which(Module), + VersionRes = beam_lib:version(Path), + case VersionRes of + {ok, {Module, NewVsn}} -> NewVsn; + %% If a m1.erl has -module("m2"): + _ -> unknown_version + end. + +get_current_version(Module) -> + Attrs = Module:module_info(attributes), + {value, {vsn, CurVsn}} = lists:keysearch(vsn, 1, Attrs), + CurVsn. + +%% @spec(Dir::string(), UpdatedBeams::[atom()]) -> {Script,LowLevelScript,Check} +build_script(Dir, UpdatedBeams) -> + Script = make_script(UpdatedBeams), + ?INFO_MSG("script: ~p~n", [Script]), + LowLevelScript = make_low_level_script(UpdatedBeams, Script), + ?INFO_MSG("low level script: ~p~n", [LowLevelScript]), + Check = + release_handler_1:check_script( + LowLevelScript, + [{ejabberd, "", filename:join(Dir, "..")}]), + ?INFO_MSG("check: ~p~n", [Check]), + {Script, LowLevelScript, Check}. + +%% Copied from Erlang/OTP file: lib/sasl/src/systools.hrl -record(application, {name, %% Name of the application, atom(). type = permanent, %% Application start type, atom(). diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 484c9b393..77b69b933 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -39,6 +39,12 @@ -include("ejabberd_http.hrl"). -include("ejabberd_web_admin.hrl"). +-define(INPUTATTRS(Type, Name, Value, Attrs), + ?XA("input", Attrs ++ + [?XMLATTR('type', Type), + ?XMLATTR('name', Name), + ?XMLATTR('value', Value)])). + process(["doc", LocalFile], _Request) -> DocPath = case os:getenv("EJABBERD_DOC_PATH") of @@ -149,6 +155,12 @@ make_xhtml(Els, Host, Node, Lang) -> #xmlel{ns = ?NS_XHTML, name = 'meta', attrs = [ ?XMLATTR('http-equiv', <<"Content-Type">>), ?XMLATTR('content', <<"text/html; charset=utf-8">>)]}, + #xmlel{ns = ?NS_XHTML, name = 'script', + %% This children is to ensure exmpp puts: <script ...></script> + children = [?C(".")], + attrs = [ + ?XMLATTR('src', Base ++ "additions.js"), + ?XMLATTR('type', <<"text/javascript">>)]}, #xmlel{ns = ?NS_XHTML, name = 'link', attrs = [ ?XMLATTR('href', Base ++ "favicon.ico"), ?XMLATTR('type', <<"image/x-icon">>), @@ -190,6 +202,24 @@ get_base_path(Host, cluster) -> "/admin/server/" ++ Host ++ "/"; get_base_path(global, Node) -> "/admin/node/" ++ atom_to_list(Node) ++ "/"; get_base_path(Host, Node) -> "/admin/server/" ++ Host ++ "/node/" ++ atom_to_list(Node) ++ "/". +additions_js() -> +" +function selectAll() { + for(i=0;i<document.forms[0].elements.length;i++) + { var e = document.forms[0].elements[i]; + if(e.type == 'checkbox') + { e.checked = true; } + } +} +function unSelectAll() { + for(i=0;i<document.forms[0].elements.length;i++) + { var e = document.forms[0].elements[i]; + if(e.type == 'checkbox') + { e.checked = false; } + } +} +". + css(Host) -> Base = get_base_path(Host, cluster), " @@ -525,6 +555,10 @@ h3 { padding-left: 10px; } +#content ul.noliststyle > li { + list-style-type: none; +} + #content li.big { font-size: 10pt; } @@ -646,6 +680,9 @@ process_admin(_Host, #request{path = ["logo.png"]}) -> process_admin(_Host, #request{path = ["logo-fill.png"]}) -> {200, [{"Content-Type", "image/png"}, last_modified(), cache_control_public()], logo_fill()}; +process_admin(_Host, #request{path = ["additions.js"]}) -> + {200, [{"Content-Type", "text/javascript"}, last_modified(), cache_control_public()], additions_js()}; + process_admin(Host, #request{path = ["acls-raw"], q = Query, @@ -1953,9 +1990,32 @@ get_node(global, Node, ["update"], Query, Lang) -> [] -> ?CT("None"); _ -> - ?XE('ul', - [?LI([?C(atom_to_list(Beam))]) || - Beam <- UpdatedBeams]) + BeamsLis = + lists:map( + fun(Beam) -> + BeamString = atom_to_list(Beam), + ?LI([ + ?INPUT("checkbox", "selected", BeamString), + %% If we want checkboxes selected by default: + %%?XA("input", [{"checked", ""}, + %% {"type", "checkbox"}, + %% {"name", "selected"}, + %% {"value", BeamString}]), + ?C(BeamString)]) + end, + UpdatedBeams), + SelectButtons = + [?BR, + ?INPUTATTRS(<<"button">>, <<"selectall">>, + <<"Select All">>, + [?XMLATTR('onClick', <<"selectAll()">>)]), + ?C(" "), + ?INPUTATTRS(<<"button">>, <<"unselectall">>, + <<"Unselect All">>, + [?XMLATTR('onClick', <<"unSelectAll()">>)])], + %%?XE("ul", BeamsLis) + ?XAE('ul', [?XMLATTR('class', <<"noliststyle">>)], + BeamsLis ++ SelectButtons) end, FmtScript = ?XC('pre', io_lib:format("~p", [Script])), FmtLowLevelScript = ?XC('pre', io_lib:format("~p", [LowLevelScript])), @@ -1972,6 +2032,7 @@ get_node(global, Node, ["update"], Query, Lang) -> ?XCT('h3', "Update script"), FmtScript, ?XCT('h3', "Low level update script"), FmtLowLevelScript, ?XCT('h3', "Script check"), ?XC("pre", atom_to_list(Check)), + ?BR, ?INPUTT("submit", "update", "Update") ]) ]; @@ -2294,7 +2355,9 @@ node_modules_parse_query(Host, Node, Modules, Query) -> node_update_parse_query(Node, Query) -> case lists:keysearch("update", 1, Query) of {value, _} -> - case rpc:call(Node, ejabberd_update, update, []) of + ModulesToUpdateStrings = proplists:get_all_values("selected",Query), + ModulesToUpdate = [list_to_atom(M) || M <- ModulesToUpdateStrings], + case rpc:call(Node, ejabberd_update, update, [ModulesToUpdate]) of {ok, _} -> ok; {error, Error} -> From 9bcba6c8b8b713c33fd013b8cb37c83af8aafd59 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Wed, 27 May 2009 17:29:50 +0000 Subject: [PATCH 325/582] Update CSS of WebAdmin menu SVN Revision: 2110 --- src/web/ejabberd_web_admin.erl | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 77b69b933..8690006c8 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -309,7 +309,7 @@ html>body #container { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 8pt; font-weight: bold; - background: #d47911; + border-top: 1px solid #d47911; width: 17em; } @@ -325,7 +325,8 @@ html>body #container { display: block; padding: 3px 6px 3px 9px; border-left: 1em solid #ffc78c; - border-top: 1px solid #d47911; + border-right: 1px solid #d47911; + border-bottom: 1px solid #d47911; background: #ffe3c9; text-decoration: none; } @@ -346,19 +347,19 @@ html>body #container { ul li #navhead a, ul li #navheadsub a, ul li #navheadsubsub a { text-align: center; - border-top: 2px solid #d47911; - border-bottom: 1px solid #d47911; + border-top: 1px solid #d47911; + border-bottom: 2px solid #d47911; background: #FED6A6; } #navheadsub, #navitemsub { border-left: 7px solid white; - margin-left: 2px solid #d47911; + margin-left: 2px; } #navheadsubsub, #navitemsubsub { border-left: 14px solid white; - margin-left: 4px solid #d47911; + margin-left: 4px; } #lastactivity li { From 0bbbf468f013eb1714b8ec0a119ccf91ada95397 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Wed, 27 May 2009 17:29:58 +0000 Subject: [PATCH 326/582] Fix crashes when browsing some WebAdmin pages (EJAB-821) SVN Revision: 2111 --- src/mod_offline.erl | 14 +++++++------- src/mod_offline_odbc.erl | 8 ++++---- src/mod_roster.erl | 16 ++++++++-------- src/mod_roster_odbc.erl | 16 ++++++++-------- src/mod_shared_roster.erl | 14 +++++++------- src/web/ejabberd_web_admin.erl | 10 +++++----- 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 8ef6507a0..b4fcd4d37 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -574,11 +574,11 @@ user_queue(User, Server, Query, Lang) -> exmpp_xml:indent_document(Packet1, <<" ">>), [?DEFAULT_NS], ?PREFIXED_NS), ?XE("tr", - [?XAE("td", [{"class", "valign"}], [?INPUT("checkbox", "selected", ID)]), - ?XAC("td", [{"class", "valign"}], Time), - ?XAC("td", [{"class", "valign"}], SFrom), - ?XAC("td", [{"class", "valign"}], STo), - ?XAE("td", [{"class", "valign"}], [?XC("pre", FPacket)])] + [?XAE("td", [?XMLATTR('class', <<"valign">>)], [?INPUT("checkbox", "selected", ID)]), + ?XAC("td", [?XMLATTR('class', <<"valign">>)], Time), + ?XAC("td", [?XMLATTR('class', <<"valign">>)], SFrom), + ?XAC("td", [?XMLATTR('class', <<"valign">>)], STo), + ?XAE("td", [?XMLATTR('class', <<"valign">>)], [?XC("pre", FPacket)])] ) end, Msgs), [?XC("h1", io_lib:format(?T("~s's Offline Messages Queue"), @@ -587,7 +587,7 @@ user_queue(User, Server, Query, Lang) -> ok -> [?XREST("Submitted")]; nothing -> [] end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], + [?XAE("form", [?XMLATTR('action', <<"">>), ?XMLATTR('method', <<"post">>)], [?XE("table", [?XE("thead", [?XE("tr", @@ -601,7 +601,7 @@ user_queue(User, Server, Query, Lang) -> if FMsgs == [] -> [?XE("tr", - [?XAC("td", [{"colspan", "4"}], " ")] + [?XAC("td", [?XMLATTR('colspan', <<"4">>)], " ")] )]; true -> FMsgs diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index e0a35b7dd..b997f6a07 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -360,8 +360,8 @@ user_queue(User, Server, Query, Lang) -> exmpp_xml:indent_document(Packet, <<" ">>), [?DEFAULT_NS], ?PREFIXED_NS), ?XE("tr", - [?XAE("td", [{"class", "valign"}], [?INPUT("checkbox", "selected", ID)]), - ?XAE("td", [{"class", "valign"}], [?XC("pre", FPacket)])] + [?XAE("td", [?XMLATTR('class', <<"valign">>)], [?INPUT("checkbox", "selected", ID)]), + ?XAE("td", [?XMLATTR('class', <<"valign">>)], [?XC("pre", FPacket)])] ) end, Msgs), [?XC("h1", io_lib:format(?T("~s's Offline Messages Queue"), @@ -370,7 +370,7 @@ user_queue(User, Server, Query, Lang) -> ok -> [?XREST("Submitted")]; nothing -> [] end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], + [?XAE("form", [?XMLATTR('action', <<"">>), ?XMLATTR('method', <<"post">>)], [?XE("table", [?XE("thead", [?XE("tr", @@ -381,7 +381,7 @@ user_queue(User, Server, Query, Lang) -> if FMsgs == [] -> [?XE("tr", - [?XAC("td", [{"colspan", "4"}], " ")] + [?XAC("td", [?XMLATTR('colspan', <<"4">>)], " ")] )]; true -> FMsgs diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 38c6ffb05..5d4e4c889 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -1131,16 +1131,16 @@ user_roster(User, Server, Query, Lang) -> TDJID = build_contact_jid_td(R#roster.jid), ?XE("tr", [TDJID, - ?XAC("td", [{"class", "valign"}], + ?XAC("td", [?XMLATTR('class', <<"valign">>)], binary_to_list(R#roster.name)), - ?XAC("td", [{"class", "valign"}], + ?XAC("td", [?XMLATTR('class', <<"valign">>)], atom_to_list(R#roster.subscription)), - ?XAC("td", [{"class", "valign"}], + ?XAC("td", [?XMLATTR('class', <<"valign">>)], atom_to_list(Pending)), - ?XAE("td", [{"class", "valign"}], Groups), + ?XAE("td", [?XMLATTR('class', <<"valign">>)], Groups), if Pending == in -> - ?XAE("td", [{"class", "valign"}], + ?XAE("td", [?XMLATTR('class', <<"valign">>)], [?INPUTT("submit", "validate" ++ ejabberd_web_admin:term_to_id(R#roster.jid), @@ -1148,7 +1148,7 @@ user_roster(User, Server, Query, Lang) -> true -> ?X("td") end, - ?XAE("td", [{"class", "valign"}], + ?XAE("td", [?XMLATTR('class', <<"valign">>)], [?INPUTT("submit", "remove" ++ ejabberd_web_admin:term_to_id(R#roster.jid), @@ -1161,7 +1161,7 @@ user_roster(User, Server, Query, Lang) -> error -> [?XREST("Bad format")]; nothing -> [] end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], + [?XAE("form", [?XMLATTR('action', <<"">>), ?XMLATTR('method', <<"post">>)], FItems ++ [?P, ?INPUT("text", "newjid", ""), ?C(" "), @@ -1171,7 +1171,7 @@ user_roster(User, Server, Query, Lang) -> _ -> [?XC("h1", ?T("Roster of ") ++ us_to_list({User, Server}))] ++ [?CT("Bad format"), ?P] ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], + [?XAE("form", [?XMLATTR('action', <<"">>), ?XMLATTR('method', <<"post">>)], [?P, ?INPUT("text", "newjid", ""), ?C(" "), ?INPUTT("submit", "addjid", "Add Jabber ID") diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 8f5a8405b..01edcd3c4 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -970,16 +970,16 @@ user_roster(User, Server, Query, Lang) -> TDJID = build_contact_jid_td(R#roster.jid), ?XE("tr", [TDJID, - ?XAC("td", [{"class", "valign"}], + ?XAC("td", [?XMLATTR('class', <<"valign">>)], binary_to_list(R#roster.name)), - ?XAC("td", [{"class", "valign"}], + ?XAC("td", [?XMLATTR('class', <<"valign">>)], atom_to_list(R#roster.subscription)), - ?XAC("td", [{"class", "valign"}], + ?XAC("td", [?XMLATTR('class', <<"valign">>)], atom_to_list(Pending)), - ?XAE("td", [{"class", "valign"}], Groups), + ?XAE("td", [?XMLATTR('class', <<"valign">>)], Groups), if Pending == in -> - ?XAE("td", [{"class", "valign"}], + ?XAE("td", [?XMLATTR('class', <<"valign">>)], [?INPUTT("submit", "validate" ++ ejabberd_web_admin:term_to_id(R#roster.jid), @@ -987,7 +987,7 @@ user_roster(User, Server, Query, Lang) -> true -> ?X("td") end, - ?XAE("td", [{"class", "valign"}], + ?XAE("td", [?XMLATTR('class', <<"valign">>)], [?INPUTT("submit", "remove" ++ ejabberd_web_admin:term_to_id(R#roster.jid), @@ -1000,7 +1000,7 @@ user_roster(User, Server, Query, Lang) -> error -> [?XREST("Bad format")]; nothing -> [] end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], + [?XAE("form", [?XMLATTR('action', <<"">>), ?XMLATTR('method', <<"post">>)], FItems ++ [?P, ?INPUT("text", "newjid", ""), ?C(" "), @@ -1010,7 +1010,7 @@ user_roster(User, Server, Query, Lang) -> _ -> [?XC("h1", ?T("Roster of ") ++ us_to_list({User, Server}))] ++ [?CT("Bad format"), ?P] ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], + [?XAE("form", [?XMLATTR('action', <<"">>), ?XMLATTR('method', <<"post">>)], [?P, ?INPUT("text", "newjid", ""), ?C(" "), ?INPUTT("submit", "addjid", "Add Jabber ID") diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 81adde1d8..3892b7098 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -199,12 +199,12 @@ process_item(RosterItem, Host) -> %% Remove pending out subscription Mod:out_subscription(UserTo, ServerTo, - jlib:make_jid(UserFrom, ServerFrom, ""), + exmpp_jid:make_jid(UserFrom, ServerFrom), unsubscribe), %% Remove pending in subscription Mod:in_subscription(aaaa, UserFrom, ServerFrom, - jlib:make_jid(UserTo, ServerTo, ""), + exmpp_jid:make_jid(UserTo, ServerTo), unsubscribe, ""), %% But we're still subscribed, so respond as such. @@ -334,7 +334,7 @@ out_subscription(UserFrom, ServerFrom, JIDTo, unsubscribed) -> %% Remove pending out subscription {UserTo, ServerTo, _} = jlib:short_prepd_bare_jid(JIDTo), - JIDFrom = jlib:make_jid(UserFrom, UserTo, ""), + JIDFrom = exmpp_jid:make_jid(UserFrom, UserTo), Mod:out_subscription(UserTo, ServerTo, JIDFrom, unsubscribe), %% Remove pending in subscription @@ -707,7 +707,7 @@ push_roster_item(User, Server, ContactU, ContactS, GroupName, Subscription) -> subscription = Subscription, ask = none, groups = [GroupName]}, - push_item(User, Server, jlib:make_jid("", Server, ""), Item). + push_item(User, Server, exmpp_jid:make_jid(Server), Item). item_to_xml(Item) -> {U, S, R} = Item#roster.jid, @@ -796,7 +796,7 @@ list_shared_roster_groups(Host, Query, Lang) -> error -> [?XREST("Bad format")]; nothing -> [] end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], + [?XAE("form", [?XMLATTR('action', <<"">>), ?XMLATTR('method', <<"post">>)], [FGroups, ?BR, ?INPUTT("submit", "delete", "Delete Selected") @@ -858,7 +858,7 @@ shared_roster_group(Host, Group, Query, Lang) -> FDisplayedGroups = [[DG, $\n] || DG <- DisplayedGroups], DescNL = length(element(2, regexp:split(Description, "\n"))), FGroup = - ?XAE("table", [{"class", "withtextareas"}], + ?XAE("table", [?XMLATTR('class', <<"withtextareas">>)], [?XE("tbody", [?XE("tr", [?XCT("td", "Name:"), @@ -897,7 +897,7 @@ shared_roster_group(Host, Group, Query, Lang) -> error -> [?XREST("Bad format")]; nothing -> [] end ++ - [?XAE("form", [{"action", ""}, {"method", "post"}], + [?XAE("form", [?XMLATTR('action', <<"">>), ?XMLATTR('method', <<"post">>)], [FGroup, ?BR, ?INPUTT("submit", "submit", "Submit") diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 8690006c8..934369878 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -1228,13 +1228,13 @@ access_rules_to_xhtml(AccessRules, Lang) -> fun({access, Name, Rules} = Access) -> SName = atom_to_list(Name), ID = term_to_id(Access), - ?XE('trr', + ?XE('tr', [?XE('td', [?INPUT("checkbox", "selected", ID)]), ?XE('td', [?AC(SName ++ "/", SName)]), ?XC('td', term_to_string(Rules)) ] ) - end, AccessRules) ++ + end, lists:sort(AccessRules)) ++ [?XE('tr', [?X('td'), ?XE('td', [?INPUT("text", "namenew", "")]), @@ -1293,9 +1293,9 @@ access_rule_to_xhtml(Rules) -> SACL = atom_to_list(ACL), SAccess ++ "\s\t" ++ SACL ++ "\n" end, Rules), - ?XAC('textarea', [{"name", "rules"}, - {"rows", "16"}, - {"cols", "80"}], + ?XAC('textarea', [?XMLATTR('name', <<"rules">>), + ?XMLATTR('rows', <<"16">>), + ?XMLATTR('cols', <<"80">>)], Text). parse_access_rule(Text) -> From a16230c9ca5cf085db76aeb44831c71ba76bdbb3 Mon Sep 17 00:00:00 2001 From: Christophe Romain <christophe.romain@process-one.net> Date: Thu, 28 May 2009 23:21:50 +0000 Subject: [PATCH 327/582] pubsub: added configuration option in guide.tex, added last item cache, use default node type if given type is not configured, make node_flat the default node plugin. caps: improve cache handling SVN Revision: 2114 --- doc/guide.tex | 23 ++- src/ejabberd.cfg.example | 6 +- src/mod_caps.erl | 23 ++- src/mod_pubsub/mod_pubsub.erl | 132 ++++++++++++++---- src/mod_pubsub/node.template | 56 ++++---- src/mod_pubsub/node_buddy.erl | 60 ++++---- src/mod_pubsub/node_club.erl | 58 ++++---- src/mod_pubsub/node_dispatch.erl | 36 ++--- src/mod_pubsub/node_flat.erl | 58 ++++---- .../{node_default.erl => node_hometree.erl} | 4 +- src/mod_pubsub/node_mb.erl | 10 +- src/mod_pubsub/node_pep.erl | 50 +++---- src/mod_pubsub/node_private.erl | 62 ++++---- src/mod_pubsub/node_public.erl | 62 ++++---- ...nodetree_default.erl => nodetree_tree.erl} | 4 +- 15 files changed, 383 insertions(+), 261 deletions(-) rename src/mod_pubsub/{node_default.erl => node_hometree.erl} (99%) rename src/mod_pubsub/{nodetree_default.erl => nodetree_tree.erl} (98%) diff --git a/doc/guide.tex b/doc/guide.tex index b5a36f123..b1801a8a3 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -3268,11 +3268,28 @@ Options: \titem{access\_createnode} \ind{options!access\_createnode} This option restricts which users are allowed to create pubsub nodes using ACL and ACCESS. The default value is \term{pubsub\_createnode}. % Not clear enough + do not use abbreviations. -\titem{plugins} To specify which pubsub node plugins to use. If not defined, the default +\titem{plugins} \ind{options!plugins} + To specify which pubsub node plugins to use. If not defined, the default pubsub plugin is always used. -\titem{nodetree} To specify which nodetree to use. If not defined, the default pubsub - nodetree is used. Nodetrees are default and virtual. Only one nodetree can be used +\titem{nodetree} \ind{options!nodetree} + To specify which nodetree to use. If not defined, the default pubsub + nodetree is used. Only one nodetree can be used per host, and is shared by all node plugins. +\titem{pep\_sendlast\_offline} \ind{options!pep\_sendlast\_offline} + To specify whether or not we should get last published PEP items + from users in our roster which are offline when we connect. Value is true or false. + If not defined, pubsub assumes false so we only get last items of online contacts. +\titem{last\_item\_cache} \ind{options!last\_item\_cache} + To specify whether or not pubsub should cache last items. Value is true + or false. If not defined, pubsub do not cache last items. On systems with not so many nodes, + caching last items speeds up pubsub and allows to raise user connection rate. The cost is memory + usage, as every item is stored in memory. +\titem{pep\_mapping} \ind{pep\_mapping} + This allow to define a Key-Value list to choose defined node plugins on given PEP namespace. + The following example will use node\_tune instead of node\_pep for every PEP node with tune namespace: +\begin{verbatim} + {mod_pubsub, [{pep_mapping, [{"http://jabber.org/protocol/tune", "tune"}]}]} +\end{verbatim} %\titem{served\_hosts} \ind{options!served\_hosts} % This option allows to create additional pubsub virtual hosts in a single module instance. \end{description} diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index 783775bb7..2d406c2ed 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -485,9 +485,11 @@ {mod_privacy, []}, {mod_private, []}, %%{mod_proxy65,[]}, - {mod_pubsub, [ % requires mod_caps + {mod_pubsub, [ {access_createnode, pubsub_createnode}, - {plugins, ["default", "pep"]} + {pep_sendlast_offline, false}, + {last_item_cache, false}, + {plugins, ["flat", "pep"]} % pep requires mod_caps ]}, {mod_register, [ %% diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 1a6691cc0..f9441f1ee 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -59,7 +59,8 @@ %% hook handlers -export([receive_packet/3, receive_packet/4, - presence_probe/3]). + presence_probe/3, + remove_connection/3]). -include("ejabberd.hrl"). @@ -202,7 +203,20 @@ receive_packet(From, To, Packet) when ?IS_PRESENCE(Packet) -> 'unsubscribed' -> ok; 'unavailable' -> - clear_caps(From); + {_, S1, _} = jlib:short_prepd_jid(From), + case jlib:short_prepd_jid(To) of + {_, S1, _} -> ok; + _ -> clear_caps(From) + end; + %% TODO: probe client, and clean only if no answers + %% as far as protocol does not allow inter-server communication to + %% let remote server handle it's own caps to decide which user is to be + %% notified, we must keep a cache of online status of external contacts + %% this is absolutely not scallable, but we have no choice for now + %% we can only use unavailable presence, but if remote user just remove a local user + %% from its roster, then it's considered as offline, so he does not receive local PEP + %% anymore until he login again. + %% This is tracked in EJAB-943 _ -> ServerString = exmpp_jid:ldomain_as_list(To), Els = Packet#xmlel.children, @@ -218,6 +232,9 @@ presence_probe(From, To, _) -> ServerString = exmpp_jid:ldomain_as_list(To), wait_caps(ServerString, From). +remove_connection(_SID, JID, _Info) -> + clear_caps(JID). + caps_to_binary(#caps{node = Node, version = Version, exts = Exts}) -> BExts = [list_to_binary(Ext) || Ext <- Exts], #caps{node = list_to_binary(Node), version = list_to_binary(Version), exts = BExts}. @@ -249,6 +266,7 @@ init([Host, _Opts]) -> ejabberd_hooks:add(user_receive_packet, Host, ?MODULE, receive_packet, 30), ejabberd_hooks:add(s2s_receive_packet, Host, ?MODULE, receive_packet, 30), ejabberd_hooks:add(presence_probe_hook, Host, ?MODULE, presence_probe, 20), + ejabberd_hooks:add(sm_remove_connection_hook, Host, ?MODULE, remove_connection, 20), {ok, #state{host = Host}}. maybe_get_features(#caps{node = Node, version = Version, exts = Exts}) -> @@ -418,6 +436,7 @@ terminate(_Reason, State) -> ejabberd_hooks:delete(user_receive_packet, Host, ?MODULE, receive_packet, 30), ejabberd_hooks:delete(s2s_receive_packet, Host, ?MODULE, receive_packet, 30), ejabberd_hooks:delete(presence_probe_hook, Host, ?MODULE, presence_probe, 20), + ejabberd_hooks:delete(sm_remove_connection_hook, Host, ?MODULE, remove_connection, 20), ok. code_change(_OldVsn, State, _Extra) -> diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 615f1d3fa..43ca80b34 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -39,7 +39,7 @@ -module(mod_pubsub). -author('christophe.romain@process-one.net'). --version('1.12-05'). +-version('1.12-06'). -behaviour(gen_server). -behaviour(gen_mod). @@ -49,8 +49,8 @@ -include("ejabberd.hrl"). -include("pubsub.hrl"). --define(STDTREE, "default"). --define(STDNODE, "default"). +-define(STDTREE, "tree"). +-define(STDNODE, "flat"). -define(PEPNODE, "pep"). %% exports for hooks @@ -78,6 +78,9 @@ publish_item/6, delete_item/4, send_items/6, + get_items/2, + get_item/3, + get_cached_item/2, broadcast_stanza/7, get_configure/5, set_configure/5, @@ -120,7 +123,8 @@ host, access, pep_mapping = [], - pep_sendlast_offline, + pep_sendlast_offline = false, + last_item_cache = false, nodetree = ?STDTREE, plugins = [?STDNODE], send_loop}). @@ -165,17 +169,21 @@ init([ServerHost, Opts]) -> Access = gen_mod:get_opt(access_createnode, Opts, all), PepOffline = gen_mod:get_opt(pep_sendlast_offline, Opts, false), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), + LastItemCache = gen_mod:get_opt(last_item_cache, Opts, false), ServerHostB = list_to_binary(ServerHost), pubsub_index:init(Host, ServerHost, Opts), - ets:new(gen_mod:get_module_proc(Host, pubsub_state), [set, named_table]), - ets:new(gen_mod:get_module_proc(ServerHost, pubsub_state), [set, named_table]), + ets:new(gen_mod:get_module_proc(Host, config), [set, named_table]), + ets:new(gen_mod:get_module_proc(ServerHostB, config), [set, named_table]), + ets:new(gen_mod:get_module_proc(Host, last_items), [set, named_table]), + ets:new(gen_mod:get_module_proc(ServerHostB, last_items), [set, named_table]), {Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts), mod_disco:register_feature(ServerHost, ?NS_PUBSUB_s), - ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {nodetree, NodeTree}), - ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {plugins, Plugins}), - ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {nodetree, NodeTree}), - ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {plugins, Plugins}), - ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {pep_mapping, PepMapping}), + ets:insert(gen_mod:get_module_proc(Host, config), {nodetree, NodeTree}), + ets:insert(gen_mod:get_module_proc(Host, config), {plugins, Plugins}), + ets:insert(gen_mod:get_module_proc(Host, config), {last_item_cache, LastItemCache}), + ets:insert(gen_mod:get_module_proc(ServerHostB, config), {nodetree, NodeTree}), + ets:insert(gen_mod:get_module_proc(ServerHostB, config), {plugins, Plugins}), + ets:insert(gen_mod:get_module_proc(ServerHostB, config), {pep_mapping, PepMapping}), ejabberd_hooks:add(disco_sm_identity, ServerHostB, ?MODULE, disco_sm_identity, 75), ejabberd_hooks:add(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), ejabberd_hooks:add(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75), @@ -204,6 +212,7 @@ init([ServerHost, Opts]) -> access = Access, pep_mapping = PepMapping, pep_sendlast_offline = PepOffline, + last_item_cache = LastItemCache, nodetree = NodeTree, plugins = Plugins}, SendLoop = spawn(?MODULE, send_loop, [State]), @@ -641,8 +650,8 @@ out_subscription(User, Server, JID, subscribed) -> gen_server:cast(Proc, {presence, U, S, Rs, Owner}); out_subscription(_, _, _, _) -> ok. -in_subscription(_, User, Server, Subscriber, unsubscribed, _) -> - Owner = exmpp_jid:make_jid(User, Server, ""), +in_subscription(_, User, Server, Owner, unsubscribed, _) -> + Subscriber = exmpp_jid:make_jid(User, Server, ""), Proc = gen_mod:get_module_proc(Server, ?PROCNAME), gen_server:cast(Proc, {unsubscribe, Subscriber, Owner}); in_subscription(_, _, _, _, _, _) -> @@ -1534,7 +1543,8 @@ delete_node(Host, Node, Owner) -> NodeId = RNode#pubsub_node.id, Type = RNode#pubsub_node.type, Options = RNode#pubsub_node.options, - broadcast_removed_node(RH, RN, NodeId, Type, Options, RSubscriptions) + broadcast_removed_node(RH, RN, NodeId, Type, Options, RSubscriptions), + unset_cached_item(RH, NodeId) end, Removed), case Result of default -> {result, Reply}; @@ -1756,6 +1766,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> Type = TNode#pubsub_node.type, Options = TNode#pubsub_node.options, broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, jlib:short_prepd_jid(Publisher), Payload), + set_cached_item(Host, NodeId, ItemId, Payload), case Result of default -> {result, Reply}; _ -> {result, Result} @@ -1765,12 +1776,14 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> Type = TNode#pubsub_node.type, Options = TNode#pubsub_node.options, broadcast_retract_items(Host, Node, NodeId, Type, Options, Removed), + set_cached_item(Host, NodeId, ItemId, Payload), {result, Reply}; {result, {TNode, {Result, Removed}}} -> NodeId = TNode#pubsub_node.id, Type = TNode#pubsub_node.type, Options = TNode#pubsub_node.options, broadcast_retract_items(Host, Node, NodeId, Type, Options, Removed), + set_cached_item(Host, NodeId, ItemId, Payload), {result, Result}; {result, {_, default}} -> {result, Reply}; @@ -1842,6 +1855,10 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> Type = TNode#pubsub_node.type, Options = TNode#pubsub_node.options, broadcast_retract_items(Host, Node, NodeId, Type, Options, [ItemId], ForceNotify), + case get_cached_item(Host, NodeId) of + #pubsub_item{itemid = {ItemId, NodeId}, _ = '_'} -> unset_cached_item(Host, NodeId); + _ -> ok + end, case Result of default -> {result, Reply}; _ -> {result, Result} @@ -1895,6 +1912,7 @@ purge_node(Host, Node, Owner) -> Type = TNode#pubsub_node.type, Options = TNode#pubsub_node.options, broadcast_purge_node(Host, Node, NodeId, Type, Options), + unset_cached_item(Host, NodeId), case Result of default -> {result, Reply}; _ -> {result, Result} @@ -1973,6 +1991,22 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> Error end end. +get_items(Host, Node) -> + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + node_call(Type, get_items, [NodeId, service_jid(Host)]) + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Items}} -> Items; + Error -> Error + end. +get_item(Host, Node, ItemId) -> + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + node_call(Type, get_item, [NodeId, ItemId]) + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Items}} -> Items; + Error -> Error + end. %% @spec (Host, Node, NodeId, Type, LJID, Number) -> any() %% Host = host() @@ -1984,7 +2018,15 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> %% @doc <p>Resend the items of a node to the user.</p> %% @todo use cache-last-item feature send_items(Host, Node, NodeId, Type, LJID, last) -> - send_items(Host, Node, NodeId, Type, LJID, 1); + case get_cached_item(Host, NodeId) of + undefined -> + send_items(Host, Node, NodeId, Type, LJID, 1); + LastItem -> + Stanza = event_stanza( + [{xmlelement, "items", nodeAttr(Node), + itemsEls([LastItem])}]), + ejabberd_router ! {route, service_jid(Host), jlib:make_jid(LJID), Stanza} + end; send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of {result, []} -> @@ -2909,25 +2951,67 @@ set_xoption([_ | Opts], NewOpts) -> % skip unknown field set_xoption(Opts, NewOpts). +%%%% last item cache handling + +set_cached_item({_, ServerHost, _}, NodeId, ItemId, Payload) -> + set_cached_item(ServerHost, NodeId, ItemId, Payload); +set_cached_item(Host, NodeId, ItemId, Payload) -> + case ets:lookup(gen_mod:get_module_proc(Host, config), last_item_cache) of + [{last_item_cache, true}] -> + ets:insert(gen_mod:get_module_proc(Host, last_items), {NodeId, {ItemId, Payload}}); + _ -> + ok + end. +unset_cached_item({_, ServerHost, _}, NodeId) -> + unset_cached_item(ServerHost, NodeId); +unset_cached_item(Host, NodeId) -> + case ets:lookup(gen_mod:get_module_proc(Host, config), last_item_cache) of + [{last_item_cache, true}] -> + ets:delete(gen_mod:get_module_proc(Host, last_items), NodeId); + _ -> + ok + end. +get_cached_item({_, ServerHost, _}, NodeId) -> + get_cached_item(ServerHost, NodeId); +get_cached_item(Host, NodeId) -> + case ets:lookup(gen_mod:get_module_proc(Host, config), last_item_cache) of + [{last_item_cache, true}] -> + case ets:lookup(gen_mod:get_module_proc(Host, last_items), NodeId) of + [{NodeId, {ItemId, Payload}}] -> + #pubsub_item{itemid = {ItemId, NodeId}, payload = Payload}; + _ -> + undefined + end; + _ -> + undefined + end. + %%%% plugin handling plugins(Host) -> - case ets:lookup(gen_mod:get_module_proc(Host, pubsub_state), plugins) of + case ets:lookup(gen_mod:get_module_proc(Host, config), plugins) of + [{plugins, []}] -> [?STDNODE]; [{plugins, PL}] -> PL; _ -> [?STDNODE] end. -select_type(ServerHost, Host, Node, Type)-> - ?DEBUG("SELECT_TYPE : ~p~n", [[ServerHost, Host, Node, Type]]), - case Host of +select_type(ServerHost, Host, Node, Type) when is_list(ServerHost) -> + select_type(list_to_binary(ServerHost), Host, Node, Type); +select_type(ServerHost, Host, Node, Type) -> + SelectedType = case Host of {_User, _Server, _Resource} -> - case ets:lookup(gen_mod:get_module_proc(ServerHost, pubsub_state), pep_mapping) of - [{pep_mapping, PM}] -> ?DEBUG("SELECT_TYPE : ~p~n", [PM]), proplists:get_value(Node, PM, ?PEPNODE); - R -> ?DEBUG("SELECT_TYPE why ?: ~p~n", [R]), ?PEPNODE + case ets:lookup(gen_mod:get_module_proc(ServerHost, config), pep_mapping) of + [{pep_mapping, PM}] -> proplists:get_value(Node, PM, ?PEPNODE); + _ -> ?PEPNODE end; _ -> Type + end, + ConfiguredTypes = plugins(ServerHost), + case lists:member(SelectedType, ConfiguredTypes) of + true -> SelectedType; + false -> hd(ConfiguredTypes) end. -select_type(ServerHost, Host, Node) -> +select_type(ServerHost, Host, Node) -> select_type(ServerHost, Host, Node, hd(plugins(ServerHost))). features() -> @@ -2997,7 +3081,7 @@ tree_call({_User, Server, _Resource}, Function, Args) -> tree_call(Server, Function, Args); tree_call(Host, Function, Args) -> ?DEBUG("tree_call ~p ~p ~p",[Host, Function, Args]), - Module = case ets:lookup(gen_mod:get_module_proc(Host, pubsub_state), nodetree) of + Module = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of [{nodetree, N}] -> N; _ -> list_to_atom(?TREE_PREFIX ++ ?STDTREE) end, diff --git a/src/mod_pubsub/node.template b/src/mod_pubsub/node.template index 3151877f5..ff3cc2209 100644 --- a/src/mod_pubsub/node.template +++ b/src/mod_pubsub/node.template @@ -34,7 +34,7 @@ %% it's possible not to define some function at all %% in that case, warning will be generated at compilation %% and function call will fail, -%% then mod_pubsub will call function from node_default +%% then mod_pubsub will call function from node_hometree %% (this makes code cleaner, but execution a little bit longer) %% API definition @@ -69,10 +69,10 @@ init(Host, ServerHost, Opts) -> - node_default:init(Host, ServerHost, Opts). + node_hometree:init(Host, ServerHost, Opts). terminate(Host, ServerHost) -> - node_default:terminate(Host, ServerHost). + node_hometree:terminate(Host, ServerHost). options() -> [{node_type, __TO_BE_DEFINED__}, @@ -109,76 +109,76 @@ features() -> ]. create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> - node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). + node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). create_node(NodeId, Owner) -> - node_default:create_node(NodeId, Owner). + node_hometree:create_node(NodeId, Owner). delete_node(Removed) -> - node_default:delete_node(Removed). + node_hometree:delete_node(Removed). subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). + node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> - node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID). + node_hometree:unsubscribe_node(NodeId, Sender, Subscriber, SubID). publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> - node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). + node_hometree:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). remove_extra_items(NodeId, MaxItems, ItemIds) -> - node_default:remove_extra_items(NodeId, MaxItems, ItemIds). + node_hometree:remove_extra_items(NodeId, MaxItems, ItemIds). delete_item(NodeId, Publisher, PublishModel, ItemId) -> - node_default:delete_item(NodeId, Publisher, PublishModel, ItemId). + node_hometree:delete_item(NodeId, Publisher, PublishModel, ItemId). purge_node(NodeId, Owner) -> - node_default:purge_node(NodeId, Owner). + node_hometree:purge_node(NodeId, Owner). get_entity_affiliations(Host, Owner) -> - node_default:get_entity_affiliations(Host, Owner). + node_hometree:get_entity_affiliations(Host, Owner). get_node_affiliations(NodeId) -> - node_default:get_node_affiliations(NodeId). + node_hometree:get_node_affiliations(NodeId). get_affiliation(NodeId, Owner) -> - node_default:get_affiliation(NodeId, Owner). + node_hometree:get_affiliation(NodeId, Owner). set_affiliation(NodeId, Owner, Affiliation) -> - node_default:set_affiliation(NodeId, Owner, Affiliation). + node_hometree:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(Host, Owner) -> - node_default:get_entity_subscriptions(Host, Owner). + node_hometree:get_entity_subscriptions(Host, Owner). get_node_subscriptions(NodeId) -> - node_default:get_node_subscriptions(NodeId). + node_hometree:get_node_subscriptions(NodeId). get_subscription(NodeId, Owner) -> - node_default:get_subscription(NodeId, Owner). + node_hometree:get_subscription(NodeId, Owner). set_subscription(NodeId, Owner, Subscription) -> - node_default:set_subscription(NodeId, Owner, Subscription). + node_hometree:set_subscription(NodeId, Owner, Subscription). get_states(NodeId) -> - node_default:get_states(NodeId). + node_hometree:get_states(NodeId). get_state(NodeId, JID) -> - node_default:get_state(NodeId, JID). + node_hometree:get_state(NodeId, JID). set_state(State) -> - node_default:set_state(State). + node_hometree:set_state(State). get_items(NodeId, From) -> - node_default:get_items(NodeId, From). + node_hometree:get_items(NodeId, From). get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) - node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + node_hometree:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). get_item(NodeId, ItemId) -> - node_default:get_item(NodeId, ItemId). + node_hometree:get_item(NodeId, ItemId). get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + node_hometree:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). set_item(Item) -> - node_default:set_item(Item). + node_hometree:set_item(Item). diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl index d52121c9c..11d17e78a 100644 --- a/src/mod_pubsub/node_buddy.erl +++ b/src/mod_pubsub/node_buddy.erl @@ -37,7 +37,7 @@ %% it's possible not to define some function at all %% in that case, warning will be generated at compilation %% and function call will fail, -%% then mod_pubsub will call function from node_default +%% then mod_pubsub will call function from node_hometree %% (this makes code cleaner, but execution a little bit longer) %% API definition @@ -73,10 +73,10 @@ init(Host, ServerHost, Opts) -> - node_default:init(Host, ServerHost, Opts). + node_hometree:init(Host, ServerHost, Opts). terminate(Host, ServerHost) -> - node_default:terminate(Host, ServerHost). + node_hometree:terminate(Host, ServerHost). options() -> [{node_type, buddy}, @@ -114,79 +114,79 @@ features() -> ]. create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> - node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). + node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). create_node(NodeId, Owner) -> - node_default:create_node(NodeId, Owner). + node_hometree:create_node(NodeId, Owner). delete_node(Removed) -> - node_default:delete_node(Removed). + node_hometree:delete_node(Removed). subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). + node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> - node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID). + node_hometree:unsubscribe_node(NodeId, Sender, Subscriber, SubID). publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> - node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). + node_hometree:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). remove_extra_items(NodeId, MaxItems, ItemIds) -> - node_default:remove_extra_items(NodeId, MaxItems, ItemIds). + node_hometree:remove_extra_items(NodeId, MaxItems, ItemIds). delete_item(NodeId, Publisher, PublishModel, ItemId) -> - node_default:delete_item(NodeId, Publisher, PublishModel, ItemId). + node_hometree:delete_item(NodeId, Publisher, PublishModel, ItemId). purge_node(NodeId, Owner) -> - node_default:purge_node(NodeId, Owner). + node_hometree:purge_node(NodeId, Owner). get_entity_affiliations(Host, Owner) -> - node_default:get_entity_affiliations(Host, Owner). + node_hometree:get_entity_affiliations(Host, Owner). get_node_affiliations(NodeId) -> - node_default:get_node_affiliations(NodeId). + node_hometree:get_node_affiliations(NodeId). get_affiliation(NodeId, Owner) -> - node_default:get_affiliation(NodeId, Owner). + node_hometree:get_affiliation(NodeId, Owner). set_affiliation(NodeId, Owner, Affiliation) -> - node_default:set_affiliation(NodeId, Owner, Affiliation). + node_hometree:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(Host, Owner) -> - node_default:get_entity_subscriptions(Host, Owner). + node_hometree:get_entity_subscriptions(Host, Owner). get_node_subscriptions(NodeId) -> - node_default:get_node_subscriptions(NodeId). + node_hometree:get_node_subscriptions(NodeId). get_subscription(NodeId, Owner) -> - node_default:get_subscription(NodeId, Owner). + node_hometree:get_subscription(NodeId, Owner). set_subscription(NodeId, Owner, Subscription) -> - node_default:set_subscription(NodeId, Owner, Subscription). + node_hometree:set_subscription(NodeId, Owner, Subscription). get_states(NodeId) -> - node_default:get_states(NodeId). + node_hometree:get_states(NodeId). get_state(NodeId, JID) -> - node_default:get_state(NodeId, JID). + node_hometree:get_state(NodeId, JID). set_state(State) -> - node_default:set_state(State). + node_hometree:set_state(State). get_items(NodeId, From) -> - node_default:get_items(NodeId, From). + node_hometree:get_items(NodeId, From). get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). - + node_hometree:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + get_item(NodeId, ItemId) -> - node_default:get_item(NodeId, ItemId). + node_hometree:get_item(NodeId, ItemId). get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + node_hometree:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). set_item(Item) -> - node_default:set_item(Item). + node_hometree:set_item(Item). get_item_name(Host, Node, Id) -> - node_default:get_item_name(Host, Node, Id). + node_hometree:get_item_name(Host, Node, Id). diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl index 49d7a99fd..9d92365ee 100644 --- a/src/mod_pubsub/node_club.erl +++ b/src/mod_pubsub/node_club.erl @@ -37,7 +37,7 @@ %% it's possible not to define some function at all %% in that case, warning will be generated at compilation %% and function call will fail, -%% then mod_pubsub will call function from node_default +%% then mod_pubsub will call function from node_hometree %% (this makes code cleaner, but execution a little bit longer) %% API definition @@ -73,10 +73,10 @@ init(Host, ServerHost, Opts) -> - node_default:init(Host, ServerHost, Opts). + node_hometree:init(Host, ServerHost, Opts). terminate(Host, ServerHost) -> - node_default:terminate(Host, ServerHost). + node_hometree:terminate(Host, ServerHost). options() -> [{node_type, club}, @@ -113,79 +113,79 @@ features() -> ]. create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> - node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). + node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). create_node(NodeId, Owner) -> - node_default:create_node(NodeId, Owner). + node_hometree:create_node(NodeId, Owner). delete_node(Removed) -> - node_default:delete_node(Removed). + node_hometree:delete_node(Removed). subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). + node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> - node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID). + node_hometree:unsubscribe_node(NodeId, Sender, Subscriber, SubID). publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> - node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). + node_hometree:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). remove_extra_items(NodeId, MaxItems, ItemIds) -> - node_default:remove_extra_items(NodeId, MaxItems, ItemIds). + node_hometree:remove_extra_items(NodeId, MaxItems, ItemIds). delete_item(NodeId, Publisher, PublishModel, ItemId) -> - node_default:delete_item(NodeId, Publisher, PublishModel, ItemId). + node_hometree:delete_item(NodeId, Publisher, PublishModel, ItemId). purge_node(NodeId, Owner) -> - node_default:purge_node(NodeId, Owner). + node_hometree:purge_node(NodeId, Owner). get_entity_affiliations(Host, Owner) -> - node_default:get_entity_affiliations(Host, Owner). + node_hometree:get_entity_affiliations(Host, Owner). get_node_affiliations(NodeId) -> - node_default:get_node_affiliations(NodeId). + node_hometree:get_node_affiliations(NodeId). get_affiliation(NodeId, Owner) -> - node_default:get_affiliation(NodeId, Owner). + node_hometree:get_affiliation(NodeId, Owner). set_affiliation(NodeId, Owner, Affiliation) -> - node_default:set_affiliation(NodeId, Owner, Affiliation). + node_hometree:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(Host, Owner) -> - node_default:get_entity_subscriptions(Host, Owner). + node_hometree:get_entity_subscriptions(Host, Owner). get_node_subscriptions(NodeId) -> - node_default:get_node_subscriptions(NodeId). + node_hometree:get_node_subscriptions(NodeId). get_subscription(NodeId, Owner) -> - node_default:get_subscription(NodeId, Owner). + node_hometree:get_subscription(NodeId, Owner). set_subscription(NodeId, Owner, Subscription) -> - node_default:set_subscription(NodeId, Owner, Subscription). + node_hometree:set_subscription(NodeId, Owner, Subscription). get_states(NodeId) -> - node_default:get_states(NodeId). + node_hometree:get_states(NodeId). get_state(NodeId, JID) -> - node_default:get_state(NodeId, JID). + node_hometree:get_state(NodeId, JID). set_state(State) -> - node_default:set_state(State). + node_hometree:set_state(State). get_items(NodeId, From) -> - node_default:get_items(NodeId, From). + node_hometree:get_items(NodeId, From). get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + node_hometree:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). get_item(NodeId, ItemId) -> - node_default:get_item(NodeId, ItemId). + node_hometree:get_item(NodeId, ItemId). get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + node_hometree:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). set_item(Item) -> - node_default:set_item(Item). + node_hometree:set_item(Item). get_item_name(Host, Node, Id) -> - node_default:get_item_name(Host, Node, Id). + node_hometree:get_item_name(Host, Node, Id). diff --git a/src/mod_pubsub/node_dispatch.erl b/src/mod_pubsub/node_dispatch.erl index f1d356fdd..4de366a0d 100644 --- a/src/mod_pubsub/node_dispatch.erl +++ b/src/mod_pubsub/node_dispatch.erl @@ -71,10 +71,10 @@ init(Host, ServerHost, Opts) -> - node_default:init(Host, ServerHost, Opts). + node_hometree:init(Host, ServerHost, Opts). terminate(Host, ServerHost) -> - node_default:terminate(Host, ServerHost). + node_hometree:terminate(Host, ServerHost). options() -> [{node_type, dispatch}, @@ -110,13 +110,13 @@ features() -> ]. create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> - node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). + node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). create_node(NodeId, Owner) -> - node_default:create_node(NodeId, Owner). + node_hometree:create_node(NodeId, Owner). delete_node(Removed) -> - node_default:delete_node(Removed). + node_hometree:delete_node(Removed). subscribe_node(_NodeId, _Sender, _Subscriber, _AccessModel, _SendLast, _PresenceSubscription, _RosterGroup) -> @@ -127,7 +127,7 @@ unsubscribe_node(_NodeId, _Sender, _Subscriber, _SubID) -> publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> lists:foreach(fun(SubNode) -> - node_default:publish_item( + node_hometree:publish_item( SubNode#pubsub_node.id, Publisher, Model, MaxItems, ItemId, Payload) end, nodetree_default:get_subnodes(NodeId, Publisher)). @@ -151,7 +151,7 @@ get_affiliation(_NodeId, _Owner) -> {result, []}. set_affiliation(NodeId, Owner, Affiliation) -> - node_default:set_affiliation(NodeId, Owner, Affiliation). + node_hometree:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(_Host, _Owner) -> {result, []}. @@ -159,37 +159,37 @@ get_entity_subscriptions(_Host, _Owner) -> get_node_subscriptions(NodeId) -> %% note: get_node_subscriptions is used for broadcasting %% DO NOT REMOVE - node_default:get_node_subscriptions(NodeId). + node_hometree:get_node_subscriptions(NodeId). get_subscription(_NodeId, _Owner) -> {result, []}. set_subscription(NodeId, Owner, Subscription) -> - node_default:set_subscription(NodeId, Owner, Subscription). + node_hometree:set_subscription(NodeId, Owner, Subscription). get_states(NodeId) -> - node_default:get_states(NodeId). + node_hometree:get_states(NodeId). get_state(NodeId, JID) -> - node_default:get_state(NodeId, JID). + node_hometree:get_state(NodeId, JID). set_state(State) -> - node_default:set_state(State). + node_hometree:set_state(State). get_items(NodeId, From) -> - node_default:get_items(NodeId, From). + node_hometree:get_items(NodeId, From). get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + node_hometree:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). get_item(NodeId, ItemId) -> - node_default:get_item(NodeId, ItemId). + node_hometree:get_item(NodeId, ItemId). get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + node_hometree:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). set_item(Item) -> - node_default:set_item(Item). + node_hometree:set_item(Item). get_item_name(Host, Node, Id) -> - node_default:get_item_name(Host, Node, Id). + node_hometree:get_item_name(Host, Node, Id). diff --git a/src/mod_pubsub/node_flat.erl b/src/mod_pubsub/node_flat.erl index 8120f3787..95275ee66 100644 --- a/src/mod_pubsub/node_flat.erl +++ b/src/mod_pubsub/node_flat.erl @@ -64,10 +64,10 @@ init(Host, ServerHost, Opts) -> - node_default:init(Host, ServerHost, Opts). + node_hometree:init(Host, ServerHost, Opts). terminate(Host, ServerHost) -> - node_default:terminate(Host, ServerHost). + node_hometree:terminate(Host, ServerHost). options() -> [{node_type, flat}, @@ -87,9 +87,9 @@ options() -> {presence_based_delivery, false}]. features() -> - node_default:features(). + node_hometree:features(). -%% use same code as node_default, but do not limite node to +%% use same code as node_hometree, but do not limite node to %% the home/localhost/user/... hierarchy %% any node is allowed create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> @@ -104,76 +104,76 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> {result, Allowed}. create_node(NodeId, Owner) -> - node_default:create_node(NodeId, Owner). + node_hometree:create_node(NodeId, Owner). delete_node(Removed) -> - node_default:delete_node(Removed). + node_hometree:delete_node(Removed). subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). + node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> - node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID). + node_hometree:unsubscribe_node(NodeId, Sender, Subscriber, SubID). publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> - node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). + node_hometree:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). remove_extra_items(NodeId, MaxItems, ItemIds) -> - node_default:remove_extra_items(NodeId, MaxItems, ItemIds). + node_hometree:remove_extra_items(NodeId, MaxItems, ItemIds). delete_item(NodeId, Publisher, PublishModel, ItemId) -> - node_default:delete_item(NodeId, Publisher, PublishModel, ItemId). + node_hometree:delete_item(NodeId, Publisher, PublishModel, ItemId). purge_node(NodeId, Owner) -> - node_default:purge_node(NodeId, Owner). + node_hometree:purge_node(NodeId, Owner). get_entity_affiliations(Host, Owner) -> - node_default:get_entity_affiliations(Host, Owner). + node_hometree:get_entity_affiliations(Host, Owner). get_node_affiliations(NodeId) -> - node_default:get_node_affiliations(NodeId). + node_hometree:get_node_affiliations(NodeId). get_affiliation(NodeId, Owner) -> - node_default:get_affiliation(NodeId, Owner). + node_hometree:get_affiliation(NodeId, Owner). set_affiliation(NodeId, Owner, Affiliation) -> - node_default:set_affiliation(NodeId, Owner, Affiliation). + node_hometree:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(Host, Owner) -> - node_default:get_entity_subscriptions(Host, Owner). + node_hometree:get_entity_subscriptions(Host, Owner). get_node_subscriptions(NodeId) -> - node_default:get_node_subscriptions(NodeId). + node_hometree:get_node_subscriptions(NodeId). get_subscription(NodeId, Owner) -> - node_default:get_subscription(NodeId, Owner). + node_hometree:get_subscription(NodeId, Owner). set_subscription(NodeId, Owner, Subscription) -> - node_default:set_subscription(NodeId, Owner, Subscription). + node_hometree:set_subscription(NodeId, Owner, Subscription). get_states(NodeId) -> - node_default:get_states(NodeId). + node_hometree:get_states(NodeId). get_state(NodeId, JID) -> - node_default:get_state(NodeId, JID). + node_hometree:get_state(NodeId, JID). set_state(State) -> - node_default:set_state(State). + node_hometree:set_state(State). get_items(NodeId, From) -> - node_default:get_items(NodeId, From). + node_hometree:get_items(NodeId, From). get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + node_hometree:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). get_item(NodeId, ItemId) -> - node_default:get_item(NodeId, ItemId). + node_hometree:get_item(NodeId, ItemId). get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + node_hometree:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). set_item(Item) -> - node_default:set_item(Item). + node_hometree:set_item(Item). get_item_name(Host, Node, Id) -> - node_default:get_item_name(Host, Node, Id). + node_hometree:get_item_name(Host, Node, Id). diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_hometree.erl similarity index 99% rename from src/mod_pubsub/node_default.erl rename to src/mod_pubsub/node_hometree.erl index 663a508c2..2f08a7be2 100644 --- a/src/mod_pubsub/node_default.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -38,7 +38,7 @@ %%% useable and useful as is. Please, send us comments, feedback and %%% improvements.</p> --module(node_default). +-module(node_hometree). -author('christophe.romain@process-one.net'). -include_lib("exmpp/include/exmpp.hrl"). @@ -804,7 +804,7 @@ del_items(NodeId, ItemIds) -> %% @doc <p>Return the name of the node if known: Default is to return %% node id.</p> -get_item_name(_host, _Node, Id) -> +get_item_name(_Host, _Node, Id) -> Id. %% @spec (Affiliation, Subscription) -> true | false diff --git a/src/mod_pubsub/node_mb.erl b/src/mod_pubsub/node_mb.erl index fa0e93401..2dc785cfc 100644 --- a/src/mod_pubsub/node_mb.erl +++ b/src/mod_pubsub/node_mb.erl @@ -119,10 +119,10 @@ features() -> create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> node_pep:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). - + create_node(NodeId, Owner) -> - node_pep:create_node(NodeId, Owner). - + node_pep:create_node(NodeId, Owner). + delete_node(Removed) -> node_pep:delete_node(Removed). @@ -151,13 +151,13 @@ get_entity_affiliations(Host, Owner) -> node_pep:get_entity_affiliations(Host, Owner). get_node_affiliations(NodeId) -> - node_pep:get_node_affiliations(NodeId). + node_pep:get_node_affiliations(NodeId). get_affiliation(NodeId, Owner) -> node_pep:get_affiliation(NodeId, Owner). set_affiliation(NodeId, Owner, Affiliation) -> - node_pep:set_affiliation(NodeId, Owner, Affiliation). + node_pep:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(Host, Owner) -> node_pep:get_entity_subscriptions(Host, Owner). diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index 868370eb8..4259b296c 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -68,12 +68,12 @@ ]). init(Host, ServerHost, Opts) -> - node_default:init(Host, ServerHost, Opts), + node_hometree:init(Host, ServerHost, Opts), complain_if_modcaps_disabled(ServerHost), ok. terminate(Host, ServerHost) -> - node_default:terminate(Host, ServerHost), + node_hometree:terminate(Host, ServerHost), ok. options() -> @@ -134,40 +134,40 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> {result, Allowed}. create_node(NodeId, Owner) -> - case node_default:create_node(NodeId, Owner) of + case node_hometree:create_node(NodeId, Owner) of {result, _} -> {result, []}; Error -> Error end. delete_node(Removed) -> - case node_default:delete_node(Removed) of + case node_hometree:delete_node(Removed) of {result, {_, _, Removed}} -> {result, {[], Removed}}; Error -> Error end. subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_default:subscribe_node( + node_hometree:subscribe_node( NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> - case node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID) of + case node_hometree:unsubscribe_node(NodeId, Sender, Subscriber, SubID) of {error, Error} -> {error, Error}; {result, _} -> {result, []} end. publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> - node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). + node_hometree:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). remove_extra_items(NodeId, MaxItems, ItemIds) -> - node_default:remove_extra_items(NodeId, MaxItems, ItemIds). + node_hometree:remove_extra_items(NodeId, MaxItems, ItemIds). delete_item(NodeId, Publisher, PublishModel, ItemId) -> - node_default:delete_item(NodeId, Publisher, PublishModel, ItemId). + node_hometree:delete_item(NodeId, Publisher, PublishModel, ItemId). purge_node(NodeId, Owner) -> - node_default:purge_node(NodeId, Owner). + node_hometree:purge_node(NodeId, Owner). get_entity_affiliations(_Host, Owner) -> {_, D, _} = SubKey = jlib:jid_tolower(Owner), @@ -187,13 +187,13 @@ get_entity_affiliations(_Host, Owner) -> {result, Reply}. get_node_affiliations(NodeId) -> - node_default:get_node_affiliations(NodeId). + node_hometree:get_node_affiliations(NodeId). get_affiliation(NodeId, Owner) -> - node_default:get_affiliation(NodeId, Owner). + node_hometree:get_affiliation(NodeId, Owner). set_affiliation(NodeId, Owner, Affiliation) -> - node_default:set_affiliation(NodeId, Owner, Affiliation). + node_hometree:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(_Host, Owner) -> {U, D, _} = SubKey = jlib:jid_tolower(Owner), @@ -224,40 +224,40 @@ get_node_subscriptions(NodeId) -> %% but that call returns also all subscription to none %% and this is required for broadcast to occurs %% DO NOT REMOVE - node_default:get_node_subscriptions(NodeId). + node_hometree:get_node_subscriptions(NodeId). get_subscription(NodeId, Owner) -> - node_default:get_subscription(NodeId, Owner). + node_hometree:get_subscription(NodeId, Owner). set_subscription(NodeId, Owner, Subscription) -> - node_default:set_subscription(NodeId, Owner, Subscription). + node_hometree:set_subscription(NodeId, Owner, Subscription). get_states(NodeId) -> - node_default:get_states(NodeId). + node_hometree:get_states(NodeId). get_state(NodeId, JID) -> - node_default:get_state(NodeId, JID). + node_hometree:get_state(NodeId, JID). set_state(State) -> - node_default:set_state(State). + node_hometree:set_state(State). get_items(NodeId, From) -> - node_default:get_items(NodeId, From). + node_hometree:get_items(NodeId, From). get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + node_hometree:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). get_item(NodeId, ItemId) -> - node_default:get_item(NodeId, ItemId). + node_hometree:get_item(NodeId, ItemId). get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + node_hometree:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). set_item(Item) -> - node_default:set_item(Item). + node_hometree:set_item(Item). get_item_name(Host, Node, Id) -> - node_default:get_item_name(Host, Node, Id). + node_hometree:get_item_name(Host, Node, Id). %%% diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl index ba0a987fa..d04cff38f 100644 --- a/src/mod_pubsub/node_private.erl +++ b/src/mod_pubsub/node_private.erl @@ -37,7 +37,7 @@ %% it's possible not to define some function at all %% in that case, warning will be generated at compilation %% and function call will fail, -%% then mod_pubsub will call function from node_default +%% then mod_pubsub will call function from node_hometree %% (this makes code cleaner, but execution a little bit longer) %% API definition @@ -73,10 +73,10 @@ init(Host, ServerHost, Opts) -> - node_default:init(Host, ServerHost, Opts). + node_hometree:init(Host, ServerHost, Opts). terminate(Host, ServerHost) -> - node_default:terminate(Host, ServerHost). + node_hometree:terminate(Host, ServerHost). options() -> [{node_type, private}, @@ -113,82 +113,82 @@ features() -> ]. create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> - node_default:create_node_permission(Host, ServerHost, Node, ParentNode, + node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). create_node(NodeId, Owner) -> - node_default:create_node(NodeId, Owner). + node_hometree:create_node(NodeId, Owner). delete_node(Removed) -> - node_default:delete_node(Removed). + node_hometree:delete_node(Removed). subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, + node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> - node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID). + node_hometree:unsubscribe_node(NodeId, Sender, Subscriber, SubID). publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> - node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). + node_hometree:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). remove_extra_items(NodeId, MaxItems, ItemIds) -> - node_default:remove_extra_items(NodeId, MaxItems, ItemIds). + node_hometree:remove_extra_items(NodeId, MaxItems, ItemIds). delete_item(NodeId, Publisher, PublishModel, ItemId) -> - node_default:delete_item(NodeId, Publisher, PublishModel, ItemId). + node_hometree:delete_item(NodeId, Publisher, PublishModel, ItemId). purge_node(NodeId, Owner) -> - node_default:purge_node(NodeId, Owner). + node_hometree:purge_node(NodeId, Owner). get_entity_affiliations(Host, Owner) -> - node_default:get_entity_affiliations(Host, Owner). + node_hometree:get_entity_affiliations(Host, Owner). get_node_affiliations(NodeId) -> - node_default:get_node_affiliations(NodeId). + node_hometree:get_node_affiliations(NodeId). get_affiliation(NodeId, Owner) -> - node_default:get_affiliation(NodeId, Owner). + node_hometree:get_affiliation(NodeId, Owner). set_affiliation(NodeId, Owner, Affiliation) -> - node_default:set_affiliation(NodeId, Owner, Affiliation). + node_hometree:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(Host, Owner) -> - node_default:get_entity_subscriptions(Host, Owner). + node_hometree:get_entity_subscriptions(Host, Owner). get_node_subscriptions(NodeId) -> - node_default:get_node_subscriptions(NodeId). + node_hometree:get_node_subscriptions(NodeId). get_subscription(NodeId, Owner) -> - node_default:get_subscription(NodeId, Owner). + node_hometree:get_subscription(NodeId, Owner). set_subscription(NodeId, Owner, Subscription) -> - node_default:set_subscription(NodeId, Owner, Subscription). + node_hometree:set_subscription(NodeId, Owner, Subscription). get_states(NodeId) -> - node_default:get_states(NodeId). + node_hometree:get_states(NodeId). get_state(NodeId, JID) -> - node_default:get_state(NodeId, JID). + node_hometree:get_state(NodeId, JID). set_state(State) -> - node_default:set_state(State). + node_hometree:set_state(State). get_items(NodeId, From) -> - node_default:get_items(NodeId, From). + node_hometree:get_items(NodeId, From). get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). - + node_hometree:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + get_item(NodeId, ItemId) -> - node_default:get_item(NodeId, ItemId). + node_hometree:get_item(NodeId, ItemId). get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). - + node_hometree:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + set_item(Item) -> - node_default:set_item(Item). + node_hometree:set_item(Item). get_item_name(Host, Node, Id) -> - node_default:get_item_name(Host, Node, Id). + node_hometree:get_item_name(Host, Node, Id). diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl index a5a619fdc..c75ba803b 100644 --- a/src/mod_pubsub/node_public.erl +++ b/src/mod_pubsub/node_public.erl @@ -37,7 +37,7 @@ %% it's possible not to define some function at all %% in that case, warning will be generated at compilation %% and function call will fail, -%% then mod_pubsub will call function from node_default +%% then mod_pubsub will call function from node_hometree %% (this makes code cleaner, but execution a little bit longer) %% API definition @@ -73,10 +73,10 @@ init(Host, ServerHost, Opts) -> - node_default:init(Host, ServerHost, Opts). + node_hometree:init(Host, ServerHost, Opts). terminate(Host, ServerHost) -> - node_default:terminate(Host, ServerHost). + node_hometree:terminate(Host, ServerHost). options() -> [{node_type, public}, @@ -113,81 +113,81 @@ features() -> ]. create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> - node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). + node_hometree:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access). create_node(NodeId, Owner) -> - node_default:create_node(NodeId, Owner). + node_hometree:create_node(NodeId, Owner). delete_node(Removed) -> - node_default:delete_node(Removed). + node_hometree:delete_node(Removed). subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). + node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> - node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID). + node_hometree:unsubscribe_node(NodeId, Sender, Subscriber, SubID). publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> - node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). + node_hometree:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). remove_extra_items(NodeId, MaxItems, ItemIds) -> - node_default:remove_extra_items(NodeId, MaxItems, ItemIds). + node_hometree:remove_extra_items(NodeId, MaxItems, ItemIds). delete_item(NodeId, Publisher, PublishModel, ItemId) -> - node_default:delete_item(NodeId, Publisher, PublishModel, ItemId). + node_hometree:delete_item(NodeId, Publisher, PublishModel, ItemId). purge_node(NodeId, Owner) -> - node_default:purge_node(NodeId, Owner). + node_hometree:purge_node(NodeId, Owner). get_entity_affiliations(Host, Owner) -> - node_default:get_entity_affiliations(Host, Owner). + node_hometree:get_entity_affiliations(Host, Owner). get_node_affiliations(NodeId) -> - node_default:get_node_affiliations(NodeId). + node_hometree:get_node_affiliations(NodeId). get_affiliation(NodeId, Owner) -> - node_default:get_affiliation(NodeId, Owner). + node_hometree:get_affiliation(NodeId, Owner). set_affiliation(NodeId, Owner, Affiliation) -> - node_default:set_affiliation(NodeId, Owner, Affiliation). + node_hometree:set_affiliation(NodeId, Owner, Affiliation). get_entity_subscriptions(Host, Owner) -> - node_default:get_entity_subscriptions(Host, Owner). + node_hometree:get_entity_subscriptions(Host, Owner). get_node_subscriptions(NodeId) -> - node_default:get_node_subscriptions(NodeId). + node_hometree:get_node_subscriptions(NodeId). get_subscription(NodeId, Owner) -> - node_default:get_subscription(NodeId, Owner). + node_hometree:get_subscription(NodeId, Owner). set_subscription(NodeId, Owner, Subscription) -> - node_default:set_subscription(NodeId, Owner, Subscription). + node_hometree:set_subscription(NodeId, Owner, Subscription). get_states(NodeId) -> - node_default:get_states(NodeId). + node_hometree:get_states(NodeId). get_state(NodeId, JID) -> - node_default:get_state(NodeId, JID). + node_hometree:get_state(NodeId, JID). set_state(State) -> - node_default:set_state(State). + node_hometree:set_state(State). get_items(NodeId, From) -> - node_default:get_items(NodeId, From). + node_hometree:get_items(NodeId, From). get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). - + node_hometree:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + get_item(NodeId, ItemId) -> - node_default:get_item(NodeId, ItemId). + node_hometree:get_item(NodeId, ItemId). get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> - node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). - + node_hometree:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + set_item(Item) -> - node_default:set_item(Item). + node_hometree:set_item(Item). %% @doc <p>Return the name of the node if known: Default is to return %% node id.</p> get_item_name(Host, Node, Id) -> - node_default:get_item_name(Host, Node, Id). + node_hometree:get_item_name(Host, Node, Id). diff --git a/src/mod_pubsub/nodetree_default.erl b/src/mod_pubsub/nodetree_tree.erl similarity index 98% rename from src/mod_pubsub/nodetree_default.erl rename to src/mod_pubsub/nodetree_tree.erl index eb5759f9a..7600bfed3 100644 --- a/src/mod_pubsub/nodetree_default.erl +++ b/src/mod_pubsub/nodetree_tree.erl @@ -33,7 +33,7 @@ %%% useable and useful as is. Please, send us comments, feedback and %%% improvements.</p> --module(nodetree_default). +-module(nodetree_tree). -author('christophe.romain@process-one.net'). -include_lib("exmpp/include/exmpp.hrl"). @@ -141,7 +141,7 @@ get_subnodes(Host, Node) -> get_subnodes_tree(Host, Node, _From) -> get_subnodes_tree(Host, Node). get_subnodes_tree(Host, Node) -> - mnesia:foldl(fun(#pubsub_node{nodeid = {H, N} = R}, Acc) -> + mnesia:foldl(fun(#pubsub_node{nodeid = {H, N}} = R, Acc) -> case lists:prefix(Node, N) and (H == Host) of true -> [R | Acc]; _ -> Acc From db6a8c2e059e3a25205df0ba0bd9fe09b88bafcc Mon Sep 17 00:00:00 2001 From: Christophe Romain <christophe.romain@process-one.net> Date: Fri, 29 May 2009 00:13:21 +0000 Subject: [PATCH 328/582] fix ets table name change SVN Revision: 2115 --- src/mod_pubsub/node_hometree.erl | 4 ++-- src/mod_pubsub/node_pep.erl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index 2f08a7be2..8b920f3cb 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -552,7 +552,7 @@ purge_node(NodeId, Owner) -> get_entity_affiliations(Host, Owner) -> GenKey = jlib:short_prepd_bare_jid(Owner), States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'}), - NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, pubsub_state), nodetree) of + NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of [{nodetree, N}] -> N; _ -> nodetree_default end, @@ -607,7 +607,7 @@ get_entity_subscriptions(Host, Owner) -> ++ mnesia:match_object( #pubsub_state{stateid = {SubKey, '_'}, _ = '_'}) end, - NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, pubsub_state), nodetree) of + NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of [{nodetree, N}] -> N; _ -> nodetree_default end, diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index 4259b296c..a49b6b9c1 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -174,7 +174,7 @@ get_entity_affiliations(_Host, Owner) -> SubKey = jlib:jid_tolower(Owner), GenKey = jlib:jid_remove_resource(SubKey), States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'}), - NodeTree = case ets:lookup(gen_mod:get_module_proc(D, pubsub_state), nodetree) of + NodeTree = case ets:lookup(gen_mod:get_module_proc(D, config), nodetree) of [{nodetree, N}] -> N; _ -> nodetree_default end, @@ -206,7 +206,7 @@ get_entity_subscriptions(_Host, Owner) -> ++ mnesia:match_object( #pubsub_state{stateid = {SubKey, '_'}, _ = '_'}) end, - NodeTree = case ets:lookup(gen_mod:get_module_proc(D, pubsub_state), nodetree) of + NodeTree = case ets:lookup(gen_mod:get_module_proc(D, config), nodetree) of [{nodetree, N}] -> N; _ -> nodetree_default end, From 497d4d26bbc69e797fdcc52856d57d81d957d8a4 Mon Sep 17 00:00:00 2001 From: Christophe Romain <christophe.romain@process-one.net> Date: Fri, 29 May 2009 00:27:26 +0000 Subject: [PATCH 329/582] make flat the default node plugin SVN Revision: 2116 --- src/mod_pubsub/mod_pubsub.erl | 6 +++--- src/mod_pubsub/pubsub.hrl | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 43ca80b34..d826f551e 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -230,7 +230,7 @@ init([ServerHost, Opts]) -> %% <em>node_plugin</em>. The 'node_' prefix is mandatory.</p> %% <p>The modules are initialized in alphetical order and the list is checked %% and sorted to ensure that each module is initialized only once.</p> -%% <p>See {@link node_default:init/1} for an example implementation.</p> +%% <p>See {@link node_hometree:init/1} for an example implementation.</p> init_plugins(Host, ServerHost, Opts) -> TreePlugin = list_to_atom(?TREE_PREFIX ++ gen_mod:get_opt(nodetree, Opts, ?STDTREE)), @@ -1570,7 +1570,7 @@ delete_node(Host, Node, Owner) -> %% Node = pubsubNode() %% From = jid() %% JID = jid() -%% @see node_default:subscribe_node/5 +%% @see node_hometree:subscribe_node/5 %% @doc <p>Accepts or rejects subcription requests on a PubSub node.</p> %%<p>There are several reasons why the subscription request might fail:</p> %%<ul> @@ -3017,7 +3017,7 @@ select_type(ServerHost, Host, Node) -> features() -> [ %TODO "access-authorize", % OPTIONAL - "access-open", % OPTIONAL this relates to access_model option in node_default + "access-open", % OPTIONAL this relates to access_model option in node_hometree "access-presence", % OPTIONAL this relates to access_model option in node_pep %TODO "access-roster", % OPTIONAL "access-whitelist", % OPTIONAL diff --git a/src/mod_pubsub/pubsub.hrl b/src/mod_pubsub/pubsub.hrl index dc95e3378..b896d4614 100644 --- a/src/mod_pubsub/pubsub.hrl +++ b/src/mod_pubsub/pubsub.hrl @@ -62,7 +62,7 @@ %%% @type nodeType() = string(). %%% <p>The <tt>nodeType</tt> is a string containing the name of the PubSub %%% plugin to use to manage a given node. For example, it can be -%%% <tt>"default"</tt>, <tt>"collection"</tt> or <tt>"blog"</tt>.</p> +%%% <tt>"flat"</tt>, <tt>"hometree"</tt> or <tt>"blog"</tt>.</p> %%% @type jid() = #jid{ %%% user = string(), @@ -92,7 +92,7 @@ -record(pubsub_node, {nodeid, id, parent, - type = "default", + type = "flat", owners = [], options = [] }). From 7c45f8f05342b0b266a4fabc71dbd219f0bc29d9 Mon Sep 17 00:00:00 2001 From: Christophe Romain <christophe.romain@process-one.net> Date: Fri, 29 May 2009 00:44:07 +0000 Subject: [PATCH 330/582] fix nodetree virtual to allow node subscription SVN Revision: 2117 --- src/mod_pubsub/nodetree_virtual.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mod_pubsub/nodetree_virtual.erl b/src/mod_pubsub/nodetree_virtual.erl index fd6887431..c67968d05 100644 --- a/src/mod_pubsub/nodetree_virtual.erl +++ b/src/mod_pubsub/nodetree_virtual.erl @@ -92,9 +92,9 @@ set_node(_NodeRecord) -> get_node(Host, Node, _From) -> get_node(Host, Node). get_node(Host, Node) -> - #pubsub_node{nodeid = {Host, Node}, id = {Host, Node}}. -get_node(NodeId) -> - #pubsub_node{nodeid = NodeId, id = NodeId}. + #pubsub_node{nodeid = {Host, Node}, id = {Host, Node}, owners = [{undefined, list_to_binary(Host), undefined}]}. +get_node({Host, _} = NodeId) -> + #pubsub_node{nodeid = NodeId, id = NodeId, owners = [{undefined, list_to_binary(Host), undefined}]}. %% @spec (Host) -> [pubsubNode()] %% Host = mod_pubsub:host() | mod_pubsub:jid() From 447d3818f51ef719289488d87763653442065607 Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 16:26:00 +0000 Subject: [PATCH 331/582] API renaming : make_jid -> make SVN Revision: 2119 --- src/ejabberd_c2s.erl | 20 ++++++------- src/ejabberd_s2s.erl | 4 +-- src/ejabberd_s2s_in.erl | 2 +- src/ejabberd_sm.erl | 4 +-- src/ejabberd_system_monitor.erl | 2 +- src/jd2ejd.erl | 10 +++---- src/jlib.erl | 2 +- src/mod_announce.erl | 14 ++++----- src/mod_caps.erl | 2 +- src/mod_configure.erl | 2 +- src/mod_irc/mod_irc_connection.erl | 48 +++++++++++++++--------------- src/mod_muc/mod_muc_room.erl | 8 ++--- src/mod_privacy.erl | 8 ++--- src/mod_privacy_odbc.erl | 8 ++--- src/mod_pubsub/mod_pubsub.erl | 16 +++++----- src/mod_pubsub/node_flat.erl | 2 +- src/mod_pubsub/node_hometree.erl | 2 +- src/mod_pubsub/node_pep.erl | 2 +- src/mod_register.erl | 14 ++++----- src/mod_roster.erl | 26 ++++++++-------- src/mod_roster_odbc.erl | 26 ++++++++-------- src/mod_service_log.erl | 4 +-- src/mod_shared_roster.erl | 20 ++++++------- src/web/ejabberd_http_poll.erl | 4 +-- src/web/ejabberd_web_admin.erl | 4 +-- 25 files changed, 127 insertions(+), 127 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 6183af374..477aeffc0 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -241,7 +241,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> true -> Lang = exmpp_stream:get_lang(Opening), change_shaper(StateData, - exmpp_jid:make_jid(ServerB)), + exmpp_jid:make(ServerB)), case exmpp_stream:get_version(Opening) of {1, 0} -> send_element(StateData, Header), @@ -401,7 +401,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> fsm_next_state(wait_for_auth, StateData); {auth, _ID, set, {U, P, D, R}} -> try - JID = exmpp_jid:make_jid(U, StateData#state.server, R), + JID = exmpp_jid:make(U, StateData#state.server, R), UBinary = exmpp_jid:lnode(JID), case acl:match_rule(ServerString, StateData#state.access, JID) of @@ -421,7 +421,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> Info = [{ip, StateData#state.ip}, {conn, Conn}, {auth_module, AuthModule}], ejabberd_sm:open_session( - SID, exmpp_jid:make_jid(U, StateData#state.server, R), Info), + SID, exmpp_jid:make(U, StateData#state.server, R), Info), Res = exmpp_server_legacy_auth:success(El), send_element(StateData, Res), change_shaper(StateData, JID), @@ -692,7 +692,7 @@ wait_for_bind({xmlstreamelement, El}, StateData) -> Resource -> Resource end, - JID = exmpp_jid:make_jid(StateData#state.user, StateData#state.server, R), + JID = exmpp_jid:make(StateData#state.user, StateData#state.server, R), Res = exmpp_server_binding:bind(El, JID), send_element(StateData, Res), fsm_next_state(wait_for_session, @@ -1107,7 +1107,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> ?DEBUG("broadcast~n~p~n", [Packet#xmlel.children]), case Packet#xmlel.children of [{item, {U, S, R} = _IJIDShort, ISubscription}] -> - IJID = exmpp_jid:make_jid(U, + IJID = exmpp_jid:make(U, S, R), {false, Attrs, @@ -1586,7 +1586,7 @@ is_privacy_allow(From, To, Packet, PrivacyList) -> presence_broadcast(StateData, From, JIDSet, Packet) -> lists:foreach(fun({U, S, R}) -> - FJID = exmpp_jid:make_jid(U, S, R), + FJID = exmpp_jid:make(U, S, R), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, @@ -1607,7 +1607,7 @@ presence_broadcast_to_trusted(StateData, From, T, A, Packet) -> fun({U, S, R} = JID) -> case ?SETS:is_element(JID, T) of true -> - FJID = exmpp_jid:make_jid(U, S, R), + FJID = exmpp_jid:make(U, S, R), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, @@ -1630,7 +1630,7 @@ presence_broadcast_to_trusted(StateData, From, T, A, Packet) -> presence_broadcast_first(From, StateData, Packet) -> Probe = exmpp_presence:probe(), ?SETS:fold(fun({U, S, R}, X) -> - FJID = exmpp_jid:make_jid(U, S, R), + FJID = exmpp_jid:make(U, S, R), ejabberd_router:route( From, FJID, @@ -1645,7 +1645,7 @@ presence_broadcast_first(From, StateData, Packet) -> true -> As = ?SETS:fold( fun({U, S, R} = JID, A) -> - FJID = exmpp_jid:make_jid(U, S, R), + FJID = exmpp_jid:make(U, S, R), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, @@ -1869,7 +1869,7 @@ process_unauthenticated_stanza(StateData, El) when ?IS_IQ(El) -> ResIQ = exmpp_iq:error_without_original(El, 'service-unavailable'), Res1 = exmpp_stanza:set_sender(ResIQ, - exmpp_jid:make_jid(StateData#state.server)), + exmpp_jid:make(StateData#state.server)), Res2 = exmpp_stanza:remove_recipient(Res1), send_element(StateData, Res2); _ -> diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index 835f4db4a..e21511fcb 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -408,14 +408,14 @@ new_connection(MyServer, Server, From, FromTo, max_s2s_connections_number({From, To}) -> case acl:match_rule( - From, max_s2s_connections, exmpp_jid:make_jid(To)) of + From, max_s2s_connections, exmpp_jid:make(To)) of Max when is_integer(Max) -> Max; _ -> ?DEFAULT_MAX_S2S_CONNECTIONS_NUMBER end. max_s2s_connections_number_per_node({From, To}) -> case acl:match_rule( - From, max_s2s_connections_per_node, exmpp_jid:make_jid(To)) of + From, max_s2s_connections_per_node, exmpp_jid:make(To)) of Max when is_integer(Max) -> Max; _ -> ?DEFAULT_MAX_S2S_CONNECTIONS_NUMBER_PER_NODE end. diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 0676abbcc..0a0a9e46a 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -346,7 +346,7 @@ stream_established({xmlstreamelement, El}, StateData) -> Conns = ?DICT:store({LFrom, LTo}, wait_for_verification, StateData#state.connections), change_shaper(StateData, LTo, - exmpp_jid:make_jid(LFrom)), + exmpp_jid:make(LFrom)), {next_state, stream_established, StateData#state{connections = Conns, diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index d2f415d66..6cc7c20c5 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -142,8 +142,8 @@ bounce_offline_message(From, To, Packet) -> stop. disconnect_removed_user(User, Server) -> - ejabberd_sm:route(exmpp_jid:make_jid(), - exmpp_jid:make_jid(User, + ejabberd_sm:route(exmpp_jid:make(), + exmpp_jid:make(User, Server), #xmlel{name = 'broadcast', children = [{exit, "User removed"}]}). diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl index 6d5a03b81..cfd8c381b 100644 --- a/src/ejabberd_system_monitor.erl +++ b/src/ejabberd_system_monitor.erl @@ -190,7 +190,7 @@ process_large_heap(Pid, Info) -> "(~w) The process ~w is consuming too much memory:~n~p~n" "~s", [node(), Pid, Info, DetailedInfo]), - From = exmpp_jid:make_jid(undefined, Host, <<"watchdog">>), + From = exmpp_jid:make(undefined, Host, <<"watchdog">>), lists:foreach( fun(S) -> try diff --git a/src/jd2ejd.erl b/src/jd2ejd.erl index 4ee7577f4..9151f45be 100644 --- a/src/jd2ejd.erl +++ b/src/jd2ejd.erl @@ -115,7 +115,7 @@ process_xdb(_User, _Server, _El) -> xdb_data(_User, _Server, #xmlcdata{}) -> ok; xdb_data(User, Server, #xmlel{ns = NS} = El) -> - From = exmpp_jid:make_jid(User, Server), + From = exmpp_jid:make(User, Server), LServer = exmpp_stringprep:nameprep(Server), case NS of ?NS_LEGACY_AUTH -> @@ -156,12 +156,12 @@ xdb_data(User, Server, #xmlel{ns = NS} = El) -> true -> catch mod_vcard_odbc:process_sm_iq( From, - exmpp_jid:make_jid(Server), + exmpp_jid:make(Server), #iq{kind = request, type = set, ns = ?NS_VCARD, payload = El, iq_ns = ?NS_JABBER_CLIENT}); false -> catch mod_vcard:process_sm_iq( From, - exmpp_jid:make_jid(Server), + exmpp_jid:make(Server), #iq{kind = request, type = set, ns = ?NS_VCARD, payload = El, iq_ns = ?NS_JABBER_CLIENT}) end, ok; @@ -173,7 +173,7 @@ xdb_data(User, Server, #xmlel{ns = NS} = El) -> "1" -> catch mod_private:process_sm_iq( From, - exmpp_jid:make_jid(Server), + exmpp_jid:make(Server), #iq{kind = request, type = set, ns = ?NS_PRIVATE, iq_ns = ?NS_JABBER_CLIENT, payload = #xmlel{name = 'query', children = @@ -192,7 +192,7 @@ process_offline(Server, To, #xmlel{children = Els}) -> FromS = exmpp_stanza:get_sender(El), From = case FromS of undefined -> - exmpp_jid:make_jid(Server); + exmpp_jid:make(Server); _ -> try exmpp_jid:parse_jid(FromS) diff --git a/src/jlib.erl b/src/jlib.erl index 898e20a8b..3b1e8f914 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -372,7 +372,7 @@ from_old_jid(JID) -> Node = exmpp_jid:node(JID), Resource = exmpp_jid:resource(JID), Domain = exmpp_jid:domain(JID), - exmpp_jid:make_jid(Node,Domain,Resource). + exmpp_jid:make(Node,Domain,Resource). short_jid(JID) -> diff --git a/src/mod_announce.erl b/src/mod_announce.erl index b6a2ea188..abaef4b05 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -671,10 +671,10 @@ announce_all(From, To, Packet) -> Err = exmpp_stanza:reply_with_error(Packet, 'forbidden'), ejabberd_router:route(To, From, Err); allow -> - Local = exmpp_jid:make_jid(exmpp_jid:domain(To)), + Local = exmpp_jid:make(exmpp_jid:domain(To)), lists:foreach( fun({User, Server}) -> - Dest = exmpp_jid:make_jid(User, Server), + Dest = exmpp_jid:make(User, Server), ejabberd_router:route(Local, Dest, Packet) end, ejabberd_auth:get_vh_registered_users(Host)) end. @@ -686,10 +686,10 @@ announce_all_hosts_all(From, To, Packet) -> Err = exmpp_stanza:reply_with_error(Packet, 'forbidden'), ejabberd_router:route(To, From, Err); allow -> - Local = exmpp_jid:make_jid(exmpp_jid:domain(To)), + Local = exmpp_jid:make(exmpp_jid:domain(To)), lists:foreach( fun({User, Server}) -> - Dest = exmpp_jid:make_jid(User, Server), + Dest = exmpp_jid:make(User, Server), ejabberd_router:route(Local, Dest, Packet) end, ejabberd_auth:dirty_get_registered_users()) end. @@ -720,10 +720,10 @@ announce_all_hosts_online(From, To, Packet) -> end. announce_online1(Sessions, Server, Packet) -> - Local = exmpp_jid:make_jid(Server), + Local = exmpp_jid:make(Server), lists:foreach( fun({U, S, R}) -> - Dest = exmpp_jid:make_jid(U, S, R), + Dest = exmpp_jid:make(U, S, R), ejabberd_router:route(Local, Dest, Packet) end, Sessions). @@ -837,7 +837,7 @@ send_motd(JID) -> [#motd_users{}] -> ok; _ -> - Local = exmpp_jid:make_jid(exmpp_jid:ldomain(JID)), + Local = exmpp_jid:make(exmpp_jid:ldomain(JID)), ejabberd_router:route(Local, JID, Packet), F = fun() -> mnesia:write(#motd_users{us = US}) diff --git a/src/mod_caps.erl b/src/mod_caps.erl index f9441f1ee..b7d740379 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -352,7 +352,7 @@ handle_cast({note_caps, From, Stanza = exmpp_iq:get(?NS_JABBER_CLIENT, Query, ID), ejabberd_local:register_iq_response_handler (list_to_binary(Host), ID, ?MODULE, handle_disco_response), - ejabberd_router:route(exmpp_jid:make_jid(Host), + ejabberd_router:route(exmpp_jid:make(Host), From, Stanza), timer:send_after(?CAPS_QUERY_TIMEOUT, self(), {disco_timeout, ID}), ?DICT:store(ID, node_to_binary(Node, SubNode), Dict) diff --git a/src/mod_configure.erl b/src/mod_configure.erl index ce6062310..9dc25ffc8 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -1743,7 +1743,7 @@ stop_node(From, Host, ENode, Action, XData) -> [?XMLATTR('type', <<"submit">>)], children = SubEls}] }, - To = exmpp_jid:make_jid(Host), + To = exmpp_jid:make(Host), mod_announce:announce_commands(empty, From, To, Request) end, Time = timer:seconds(Delay), diff --git a/src/mod_irc/mod_irc_connection.erl b/src/mod_irc/mod_irc_connection.erl index 03f3fae64..b9eef8223 100644 --- a/src/mod_irc/mod_irc_connection.erl +++ b/src/mod_irc/mod_irc_connection.erl @@ -252,7 +252,7 @@ handle_info({route_chan, Channel, Resource, case exmpp_message:get_subject(El) of undefined -> ejabberd_router:route( - exmpp_jid:make_jid( + exmpp_jid:make( lists:concat( [Channel, "%", StateData#state.server]), StateData#state.host, StateData#state.nick), @@ -369,7 +369,7 @@ handle_info({route_chan, Channel, Resource, El}, StateName, StateData) when ?IS_IQ(El) -> From = StateData#state.user, - To = exmpp_jid:make_jid(lists:concat([Channel, "%", StateData#state.server]), + To = exmpp_jid:make(lists:concat([Channel, "%", StateData#state.server]), StateData#state.host, StateData#state.nick), _ = case exmpp_iq:xmlel_to_iq(El) of #iq{kind = request, ns = ?NS_MUC_ADMIN} = IQ_Rec -> @@ -586,7 +586,7 @@ terminate(_Reason, _StateName, StateData) -> lists:foreach( fun(Chan) -> ejabberd_router:route( - exmpp_jid:make_jid( + exmpp_jid:make( lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, StateData#state.nick), StateData#state.user, @@ -686,7 +686,7 @@ process_channel_list_user(StateData, Chan, User) -> _ -> {User1, <<"member">>, <<"participant">>} end, ejabberd_router:route( - exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, User2), StateData#state.user, #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = @@ -709,7 +709,7 @@ process_channel_topic(StateData, Chan, String) -> {ok, Msg, _} = regexp:sub(String, ".*332[^:]*:", ""), Msg1 = filter_message(Msg), ejabberd_router:route( - exmpp_jid:make_jid( + exmpp_jid:make( lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, ""), StateData#state.user, @@ -734,7 +734,7 @@ process_channel_topic_who(StateData, Chan, String) -> Msg2 = filter_message(Msg1), ejabberd_router:route( - exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, ""), StateData#state.user, exmpp_message:groupchat(Msg2)). @@ -743,7 +743,7 @@ process_channel_topic_who(StateData, Chan, String) -> process_endofwhois(StateData, _String, Nick) -> ejabberd_router:route( - exmpp_jid:make_jid(lists:concat([Nick, "!", StateData#state.server]), + exmpp_jid:make(lists:concat([Nick, "!", StateData#state.server]), StateData#state.host, ""), StateData#state.user, exmpp_message:chat("End of WHOIS")). @@ -751,7 +751,7 @@ process_endofwhois(StateData, _String, Nick) -> process_whois311(StateData, String, Nick, Ident, Irchost) -> {ok, Fullname, _} = regexp:sub(String, ".*311[^:]*:", ""), ejabberd_router:route( - exmpp_jid:make_jid(lists:concat([Nick, "!", StateData#state.server]), + exmpp_jid:make(lists:concat([Nick, "!", StateData#state.server]), StateData#state.host, ""), StateData#state.user, exmpp_message:chat(lists:concat( @@ -761,7 +761,7 @@ process_whois311(StateData, String, Nick, Ident, Irchost) -> process_whois312(StateData, String, Nick, Ircserver) -> {ok, Ircserverdesc, _} = regexp:sub(String, ".*312[^:]*:", ""), ejabberd_router:route( - exmpp_jid:make_jid(lists:concat([Nick, "!", StateData#state.server]), + exmpp_jid:make(lists:concat([Nick, "!", StateData#state.server]), StateData#state.host, ""), StateData#state.user, exmpp_message:chat(lists:concat(["WHOIS: ", Nick, " use ", @@ -770,7 +770,7 @@ process_whois312(StateData, String, Nick, Ircserver) -> process_whois319(StateData, String, Nick) -> {ok, Chanlist, _} = regexp:sub(String, ".*319[^:]*:", ""), ejabberd_router:route( - exmpp_jid:make_jid(lists:concat([Nick, "!", StateData#state.server]), + exmpp_jid:make(lists:concat([Nick, "!", StateData#state.server]), StateData#state.host, ""), StateData#state.user, exmpp_message:chat(lists:concat(["WHOIS: ", Nick, " is on ", @@ -789,7 +789,7 @@ process_chanprivmsg(StateData, Chan, From, String) -> end, Msg2 = filter_message(Msg1), ejabberd_router:route( - exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, exmpp_message:groupchat(Msg2)). @@ -807,7 +807,7 @@ process_channotice(StateData, Chan, From, String) -> end, Msg2 = filter_message(Msg1), ejabberd_router:route( - exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, exmpp_message:groupchat(Msg2)). @@ -826,7 +826,7 @@ process_privmsg(StateData, _Nick, From, String) -> end, Msg2 = filter_message(Msg1), ejabberd_router:route( - exmpp_jid:make_jid(lists:concat([FromUser, "!", StateData#state.server]), + exmpp_jid:make(lists:concat([FromUser, "!", StateData#state.server]), StateData#state.host, undefined), StateData#state.user, exmpp_message:chat(Msg2)). @@ -843,7 +843,7 @@ process_notice(StateData, _Nick, From, String) -> end, Msg2 = filter_message(Msg1), ejabberd_router:route( - exmpp_jid:make_jid(lists:concat([FromUser, "!", StateData#state.server]), + exmpp_jid:make(lists:concat([FromUser, "!", StateData#state.server]), StateData#state.host, undefined), StateData#state.user, exmpp_message:chat(Msg2)). @@ -879,7 +879,7 @@ process_topic(StateData, Chan, From, String) -> {ok, Msg, _} = regexp:sub(String, ".*TOPIC[^:]*:", ""), Msg1 = filter_message(Msg), ejabberd_router:route( - exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, exmpp_message:groupchat(Msg1, @@ -890,7 +890,7 @@ process_part(StateData, Chan, From, String) -> {ok, Msg, _} = regexp:sub(String, ".*PART[^:]*:", ""), Msg1 = filter_message(Msg), ejabberd_router:route( - exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [?XMLATTR('type', <<"unavailable">>)], children = @@ -923,7 +923,7 @@ process_quit(StateData, From, String) -> case ?SETS:is_member(FromUser, Ps) of true -> ejabberd_router:route( - exmpp_jid:make_jid( + exmpp_jid:make( lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, @@ -947,7 +947,7 @@ process_join(StateData, Channel, From, _String) -> [FromUser | FromIdent] = string:tokens(From, "!"), Chan = lists:subtract(Channel, ":#"), ejabberd_router:route( - exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = @@ -973,7 +973,7 @@ process_join(StateData, Channel, From, _String) -> process_mode_o(StateData, Chan, _From, Nick, Affiliation, Role) -> %Msg = lists:last(string:tokens(String, ":")), ejabberd_router:route( - exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, Nick), StateData#state.user, #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = @@ -986,12 +986,12 @@ process_kick(StateData, Chan, From, Nick, String) -> Msg = lists:last(string:tokens(String, ":")), Msg2 = Nick ++ " kicked by " ++ From ++ " (" ++ filter_message(Msg) ++ ")", ejabberd_router:route( - exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, undefined), StateData#state.user, exmpp_message:groupchat(Msg2)), ejabberd_router:route( - exmpp_jid:make_jid(lists:concat([Chan, "%", StateData#state.server]), + exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, Nick), StateData#state.user, #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [?XMLATTR('type', <<"unavailable">>)], children = @@ -1011,7 +1011,7 @@ process_nick(StateData, From, NewNick) -> case ?SETS:is_member(FromUser, Ps) of true -> ejabberd_router:route( - exmpp_jid:make_jid( + exmpp_jid:make( lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, FromUser), StateData#state.user, @@ -1024,7 +1024,7 @@ process_nick(StateData, From, NewNick) -> #xmlel{ns = ?NS_MUC_USER, name = 'status', attrs = [?XMLATTR('code', <<"303">>)]} ]}]}), ejabberd_router:route( - exmpp_jid:make_jid( + exmpp_jid:make( lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, Nick), StateData#state.user, @@ -1047,7 +1047,7 @@ process_error(StateData, String) -> lists:foreach( fun(Chan) -> ejabberd_router:route( - exmpp_jid:make_jid( + exmpp_jid:make( lists:concat([Chan, "%", StateData#state.server]), StateData#state.host, StateData#state.nick), StateData#state.user, diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 6c76008e5..c0f44a8fa 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -127,7 +127,7 @@ init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Creator, _Nick, D access = Access, room = Room, history = lqueue_new(HistorySize), - jid = exmpp_jid:make_jid(Room, Host), + jid = exmpp_jid:make(Room, Host), just_created = true, room_shaper = Shaper}), State1 = set_opts(DefRoomOpts, State), @@ -142,7 +142,7 @@ init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts]) -> access = Access, room = Room, history = lqueue_new(HistorySize), - jid = exmpp_jid:make_jid(Room, Host), + jid = exmpp_jid:make(Room, Host), room_shaper = Shaper}), {ok, normal_state, State}. @@ -1882,7 +1882,7 @@ send_existing_presences(ToJID, StateData) -> ok; _ -> {N,D,R} = LJID, - FromAffiliation = get_affiliation(exmpp_jid:make_jid(N,D,R), + FromAffiliation = get_affiliation(exmpp_jid:make(N,D,R), StateData), ItemAttrs = case (Role == moderator) orelse @@ -2632,7 +2632,7 @@ send_kickban_presence1(UJID, Reason, Code, StateData) -> {ok, #user{jid = _RealJID, nick = Nick}} = ?DICT:find(UJID, StateData#state.users), {N,D,R} = UJID, - Affiliation = get_affiliation(exmpp_jid:make_jid(N,D,R), StateData), + Affiliation = get_affiliation(exmpp_jid:make(N,D,R), StateData), SAffiliation = affiliation_to_binary(Affiliation), lists:foreach( fun({_LJID, Info}) -> diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 03f042aa3..820a8aba5 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -363,8 +363,8 @@ process_list_set(LUser, LServer, Name, Els) -> Error; {atomic, {result, _} = Res} -> ejabberd_router:route( - exmpp_jid:make_jid(LUser, LServer), - exmpp_jid:make_jid(LUser, LServer), + exmpp_jid:make(LUser, LServer), + exmpp_jid:make(LUser, LServer), #xmlel{name = 'broadcast', children=[{privacy_list, #userlist{name = Name, list = []}, @@ -394,8 +394,8 @@ process_list_set(LUser, LServer, Name, Els) -> Error; {atomic, {result, _} = Res} -> ejabberd_router:route( - exmpp_jid:make_jid(LUser, LServer), - exmpp_jid:make_jid(LUser, LServer), + exmpp_jid:make(LUser, LServer), + exmpp_jid:make(LUser, LServer), #xmlel{name = 'broadcast', children=[{privacy_list, #userlist{name = Name, list = List}, diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 42e84e520..6f373d49f 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -363,8 +363,8 @@ process_list_set(LUser, LServer, Name, Els) -> Error; {atomic, {result, _} = Res} -> ejabberd_router:route( - exmpp_jid:make_jid(LUser, LServer), - exmpp_jid:make_jid(LUser, LServer), + exmpp_jid:make(LUser, LServer), + exmpp_jid:make(LUser, LServer), #xmlel{name = 'broadcast', children=[{privacy_list, #userlist{name = Name, list = []}, @@ -395,8 +395,8 @@ process_list_set(LUser, LServer, Name, Els) -> Error; {atomic, {result, _} = Res} -> ejabberd_router:route( - exmpp_jid:make_jid(LUser, LServer), - exmpp_jid:make_jid(LUser, LServer), + exmpp_jid:make(LUser, LServer), + exmpp_jid:make(LUser, LServer), #xmlel{name = 'broadcast', children=[{privacy_list, #userlist{name = Name, list = List}, diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index d826f551e..0d5b8aeef 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -640,7 +640,7 @@ presence_probe(Peer, JID, _Pid) -> %% out_subscription(User, Server, JID, subscribed) -> - Owner = exmpp_jid:make_jid(User, Server, ""), + Owner = exmpp_jid:make(User, Server, ""), {U, S, R} = jlib:short_prepd_jid(JID), Rs = case R of [] -> user_resources(U, S); @@ -651,7 +651,7 @@ out_subscription(User, Server, JID, subscribed) -> out_subscription(_, _, _, _) -> ok. in_subscription(_, User, Server, Owner, unsubscribed, _) -> - Subscriber = exmpp_jid:make_jid(User, Server, ""), + Subscriber = exmpp_jid:make(User, Server, ""), Proc = gen_mod:get_module_proc(Server, ?PROCNAME), gen_server:cast(Proc, {unsubscribe, Subscriber, Owner}); in_subscription(_, _, _, _, _, _) -> @@ -706,7 +706,7 @@ handle_cast({presence, User, Server, Resources, JID}, State) -> handle_cast({remove_user, LUser, LServer}, State) -> Host = State#state.host, - Owner = exmpp_jid:make_jid(LUser, LServer), + Owner = exmpp_jid:make(LUser, LServer), %% remove user's subscriptions lists:foreach(fun(PType) -> {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Owner]), @@ -2042,7 +2042,7 @@ send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = itemsEls(ToSend)}]), - ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(LU, LS, LR), Stanza}. + ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(LU, LS, LR), Stanza}. %% @spec (Host, JID, Plugins) -> {error, Reason} | {result, Response} %% Host = host() @@ -2411,8 +2411,8 @@ string_to_node(SNode) -> %% @doc <p>Generate pubsub service JID.</p> service_jid(Host) -> case Host of - {U,S,_} -> exmpp_jid:make_jid(U, S); - _ -> exmpp_jid:make_jid(Host) + {U,S,_} -> exmpp_jid:make(U, S); + _ -> exmpp_jid:make(Host) end. %% @spec (LJID, Subscription, PresenceDelivery) -> boolean() @@ -2629,7 +2629,7 @@ broadcast_stanza(Host, Node, _NodeId, _Type, Options, Subscriptions, Stanza) -> %% set the from address on the notification to the bare JID of the account owner %% Also, add "replyto" if entity has presence subscription to the account owner %% See XEP-0163 1.1 section 4.3.1 - Sender = exmpp_jid:make_jid(LUser, LServer), + Sender = exmpp_jid:make(LUser, LServer), %%ReplyTo = jlib:make_jid(LUser, LServer, SenderResource), % This has to be used case catch ejabberd_c2s:get_subscribed(C2SPid) of Contacts when is_list(Contacts) -> @@ -2642,7 +2642,7 @@ broadcast_stanza(Host, Node, _NodeId, _Type, Options, Subscriptions, Stanza) -> end end, [], user_resources(U, S)), lists:foreach(fun(R) -> - ejabberd_router ! {route, Sender, exmpp_jid:make_jid(U, S, R), Stanza} + ejabberd_router ! {route, Sender, exmpp_jid:make(U, S, R), Stanza} end, Rs) end) end, Contacts); diff --git a/src/mod_pubsub/node_flat.erl b/src/mod_pubsub/node_flat.erl index 95275ee66..acab96119 100644 --- a/src/mod_pubsub/node_flat.erl +++ b/src/mod_pubsub/node_flat.erl @@ -99,7 +99,7 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> true; % pubsub service always allowed _ -> {LU, LS, LR} = LOwner, - acl:match_rule(ServerHost, Access, exmpp_jid:make_jid(LU, LS, LR)) =:= allow + acl:match_rule(ServerHost, Access, exmpp_jid:make(LU, LS, LR)) =:= allow end, {result, Allowed}. diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index 8b920f3cb..ab6f2c1b5 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -203,7 +203,7 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) -> true; % pubsub service always allowed _ -> {LU, LS, LR} = LOwner, - case acl:match_rule(ServerHost, Access, exmpp_jid:make_jid(LU, LS, LR)) of + case acl:match_rule(ServerHost, Access, exmpp_jid:make(LU, LS, LR)) of allow -> case Node of ["home", Server, User | _] -> true; diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index a49b6b9c1..c486ac2ac 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -119,7 +119,7 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> {undefined, Host, undefined} -> true; % pubsub service always allowed _ -> - JID = exmpp_jid:make_jid(User, Server, Resource), + JID = exmpp_jid:make(User, Server, Resource), case acl:match_rule(ServerHost, Access, JID) of allow -> case Host of diff --git a/src/mod_register.erl b/src/mod_register.erl index 5e895d6f2..c45a47cca 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -76,8 +76,8 @@ unauthenticated_iq_register(_Acc, {A, _Port} -> A; _ -> undefined end, - BareJID = exmpp_jid:make_jid(Server), - ResIQ = process_iq(exmpp_jid:make_jid(), + BareJID = exmpp_jid:make(Server), + ResIQ = process_iq(exmpp_jid:make(), BareJID, IQ_Rec, Address), @@ -143,10 +143,10 @@ process_iq(From, To, {User, Server, Resource} -> ResIQ = exmpp_iq:result(IQ_Rec, SubEl), ejabberd_router:route( - exmpp_jid:make_jid(User, + exmpp_jid:make(User, Server, Resource), - exmpp_jid:make_jid(User, + exmpp_jid:make(User, Server, Resource), exmpp_iq:iq_to_xmlel(ResIQ)), @@ -204,7 +204,7 @@ try_register(User, Server, Password, Source, Lang) -> false -> {error, 'bad-request'}; _ -> - JID = exmpp_jid:make_jid(User, + JID = exmpp_jid:make(User, Server), Access = gen_mod:get_module_opt(Server, ?MODULE, access, all), case acl:match_rule(Server, Access, JID) of @@ -247,7 +247,7 @@ send_welcome_message(JID) -> ok; {Subj, Body} -> ejabberd_router:route( - exmpp_jid:make_jid(Host), + exmpp_jid:make(Host), JID, exmpp_message:normal(Subj, Body)); _ -> @@ -268,7 +268,7 @@ send_registration_notifications(UJID) -> try JID = exmpp_jid:parse_jid(S), ejabberd_router:route( - exmpp_jid:make_jid(Host), + exmpp_jid:make(Host), JID, exmpp_message:chat(Body)) catch diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 5d4e4c889..7ae405284 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -301,14 +301,14 @@ process_item_set(From, To, #xmlel{} = El) -> if IsTo -> ejabberd_router:route( exmpp_jid:jid_to_bare_jid(From), - exmpp_jid:make_jid(U, S, R), + exmpp_jid:make(U, S, R), exmpp_presence:unsubscribe()); true -> ok end, if IsFrom -> ejabberd_router:route( exmpp_jid:jid_to_bare_jid(From), - exmpp_jid:make_jid(U, S, R), + exmpp_jid:make(U, S, R), exmpp_presence:unsubscribed()); true -> ok end, @@ -384,8 +384,8 @@ process_item_els(Item, []) -> push_item(User, Server, From, Item) when is_binary(User), is_binary(Server), ?IS_JID(From) -> - ejabberd_sm:route(exmpp_jid:make_jid(), - exmpp_jid:make_jid(User, Server), + ejabberd_sm:route(exmpp_jid:make(), + exmpp_jid:make(User, Server), #xmlel{name = 'broadcast', children = [{item, Item#roster.jid, @@ -411,7 +411,7 @@ push_item(User, Server, Resource, From, Item) "push" ++ randoms:get_string()), ejabberd_router:route( From, - exmpp_jid:make_jid(User, Server, Resource), + exmpp_jid:make(User, Server, Resource), ResIQ). %% @spec (Ignored, User, Server) -> Subscription_Lists @@ -559,7 +559,7 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) ok; _ -> ejabberd_router:route( - exmpp_jid:make_jid(User, Server), JID1, + exmpp_jid:make(User, Server), JID1, exmpp_presence:AutoReply()) end, case Push of @@ -570,7 +570,7 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) ok; true -> push_item(User, Server, - exmpp_jid:make_jid(User, Server), Item) + exmpp_jid:make(User, Server), Item) end, true; none -> @@ -843,7 +843,7 @@ process_item_attrs_ws(Item, []) -> get_in_pending_subscriptions(Ls, User, Server) when is_binary(User), is_binary(Server) -> - JID = exmpp_jid:make_jid(User, Server), + JID = exmpp_jid:make(User, Server), US = {exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID)}, case mnesia:dirty_index_read(roster, US, #roster.us) of Result when is_list(Result) -> @@ -1184,7 +1184,7 @@ user_roster(User, Server, Query, Lang) -> build_contact_jid_td({U, S, R}) -> %% Convert {U, S, R} into {jid, U, S, R, U, S, R}: - ContactJID = exmpp_jid:make_jid(U, S, R), + ContactJID = exmpp_jid:make(U, S, R), JIDURI = case {exmpp_jid:lnode(ContactJID), exmpp_jid:ldomain(ContactJID)} of {undefined, _} -> ""; {CUser, CServer} -> @@ -1245,7 +1245,7 @@ user_roster_parse_query(User, Server, Items, Query) -> user_roster_subscribe_jid(User, Server, JID) -> out_subscription(User, Server, JID, subscribe), - UJID = exmpp_jid:make_jid(User, Server), + UJID = exmpp_jid:make(User, Server), ejabberd_router:route( UJID, JID, exmpp_presence:subscribe()). @@ -1263,10 +1263,10 @@ user_roster_item_parse_query(User, Server, Items, Query) -> "validate" ++ ejabberd_web_admin:term_to_id(JID), 1, Query) of {value, _} -> {U, S, R} = JID, - JID1 = exmpp_jid:make_jid(U, S, R), + JID1 = exmpp_jid:make(U, S, R), out_subscription( User, Server, JID1, subscribed), - UJID = exmpp_jid:make_jid(User, Server), + UJID = exmpp_jid:make(User, Server), ejabberd_router:route( UJID, JID1, exmpp_presence:subscribed()), throw(submitted); @@ -1275,7 +1275,7 @@ user_roster_item_parse_query(User, Server, Items, Query) -> "remove" ++ ejabberd_web_admin:term_to_id(JID), 1, Query) of {value, _} -> {U, S, R} = JID, - UJID = exmpp_jid:make_jid(User, Server), + UJID = exmpp_jid:make(User, Server), Attrs1 = exmpp_xml:set_attribute_in_list([], 'jid', exmpp_jid:jid_to_list(U, S, R)), Attrs2 = exmpp_xml:set_attribute_in_list(Attrs1, diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 01edcd3c4..590f036e4 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -285,14 +285,14 @@ process_item_set(From, To, #xmlel{} = El) -> if IsTo -> ejabberd_router:route( exmpp_jid:jid_to_bare_jid(From), - exmpp_jid:make_jid(U, S, R), + exmpp_jid:make(U, S, R), exmpp_presence:unsubscribe()); true -> ok end, if IsFrom -> ejabberd_router:route( exmpp_jid:jid_to_bare_jid(From), - exmpp_jid:make_jid(U, S, R), + exmpp_jid:make(U, S, R), exmpp_presence:unsubscribed()); true -> ok end, @@ -347,8 +347,8 @@ process_item_els(Item, []) -> push_item(User, Server, From, Item) when is_binary(User), is_binary(Server) -> - ejabberd_sm:route(exmpp_jid:make_jid(), - exmpp_jid:make_jid(User, Server), + ejabberd_sm:route(exmpp_jid:make(), + exmpp_jid:make(User, Server), #xmlel{name = 'broadcast', children = [{item, Item#roster.jid, @@ -365,7 +365,7 @@ push_item(User, Server, Resource, From, Item) -> "push" ++ randoms:get_string()), ejabberd_router:route( From, - exmpp_jid:make_jid(User, Server, Resource), + exmpp_jid:make(User, Server, Resource), ResIQ). get_subscription_lists(_, User, Server) @@ -503,7 +503,7 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) ok; _ -> ejabberd_router:route( - exmpp_jid:make_jid(User, Server), JID1, + exmpp_jid:make(User, Server), JID1, exmpp_presence:AutoReply()) end, case Push of @@ -514,7 +514,7 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) ok; true -> push_item(User, Server, - exmpp_jid:make_jid(User, Server), Item) + exmpp_jid:make(User, Server), Item) end, true; none -> @@ -754,7 +754,7 @@ process_item_attrs_ws(Item, []) -> get_in_pending_subscriptions(Ls, User, Server) when is_binary(User), is_binary(Server) -> - JID = exmpp_jid:make_jid(User, Server), + JID = exmpp_jid:make(User, Server), LUser = exmpp_jid:lnode(JID), LServer = exmpp_jid:ldomain_as_list(JID), Username = ejabberd_odbc:escape(LUser), @@ -1019,7 +1019,7 @@ user_roster(User, Server, Query, Lang) -> build_contact_jid_td({U, S, R}) -> %% Convert {U, S, R} into {jid, U, S, R, U, S, R}: - ContactJID = exmpp_jid:make_jid(U, S, R), + ContactJID = exmpp_jid:make(U, S, R), JIDURI = case {exmpp_jid:lnode(ContactJID), exmpp_jid:ldomain(ContactJID)} of {undefined, _} -> ""; {CUser, CServer} -> @@ -1070,7 +1070,7 @@ user_roster_parse_query(User, Server, Items, Query) -> user_roster_subscribe_jid(User, Server, JID) -> out_subscription(User, Server, JID, subscribe), - UJID = exmpp_jid:make_jid(User, Server), + UJID = exmpp_jid:make(User, Server), ejabberd_router:route( UJID, JID, exmpp_presence:subscribe()). @@ -1082,10 +1082,10 @@ user_roster_item_parse_query(User, Server, Items, Query) -> "validate" ++ ejabberd_web_admin:term_to_id(JID), 1, Query) of {value, _} -> {U, S, R} = JID, - JID1 = exmpp_jid:make_jid(U, S, R), + JID1 = exmpp_jid:make(U, S, R), out_subscription( User, Server, JID1, subscribed), - UJID = exmpp_jid:make_jid(User, Server), + UJID = exmpp_jid:make(User, Server), ejabberd_router:route( UJID, JID1, exmpp_presence:subscribed()), throw(submitted); @@ -1093,7 +1093,7 @@ user_roster_item_parse_query(User, Server, Items, Query) -> case lists:keysearch( "remove" ++ ejabberd_web_admin:term_to_id(JID), 1, Query) of {value, _} -> - UJID = exmpp_jid:make_jid(User, Server), + UJID = exmpp_jid:make(User, Server), Attrs1 = exmpp_xml:set_attribute_in_list([], 'jid', exmpp_jid:jid_to_list(JID)), Attrs2 = exmpp_xml:set_attribute_in_list(Attrs1, diff --git a/src/mod_service_log.erl b/src/mod_service_log.erl index 499f96e70..725f69010 100644 --- a/src/mod_service_log.erl +++ b/src/mod_service_log.erl @@ -63,13 +63,13 @@ log_user_receive(_JID, From, To, Packet) -> log_packet(From, To, Packet, Host) -> Loggers = gen_mod:get_module_opt(Host, ?MODULE, loggers, []), - ServerJID = exmpp_jid:make_jid(Host), + ServerJID = exmpp_jid:make(Host), FixedPacket = exmpp_stanza:set_jids(Packet, From, To), lists:foreach( fun(Logger) -> ejabberd_router:route( ServerJID, - exmpp_jid:make_jid(Logger), + exmpp_jid:make(Logger), #xmlel{name = 'route', children = [FixedPacket]}) end, Loggers). diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 3892b7098..b8df4d19c 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -199,12 +199,12 @@ process_item(RosterItem, Host) -> %% Remove pending out subscription Mod:out_subscription(UserTo, ServerTo, - exmpp_jid:make_jid(UserFrom, ServerFrom), + exmpp_jid:make(UserFrom, ServerFrom), unsubscribe), %% Remove pending in subscription Mod:in_subscription(aaaa, UserFrom, ServerFrom, - exmpp_jid:make_jid(UserTo, ServerTo), + exmpp_jid:make(UserTo, ServerTo), unsubscribe, ""), %% But we're still subscribed, so respond as such. @@ -237,9 +237,9 @@ set_new_rosteritems(UserFrom, ServerFrom, RIFrom = build_roster_record(UserFrom, ServerFrom, UserTo, ServerTo, NameTo, GroupsFrom), set_item(UserFrom, ServerFrom, ResourceTo, RIFrom), - JIDTo = exmpp_jid:make_jid(UserTo, ServerTo), + JIDTo = exmpp_jid:make(UserTo, ServerTo), - JIDFrom = exmpp_jid:make_jid(UserFrom, ServerFrom), + JIDFrom = exmpp_jid:make(UserFrom, ServerFrom), RITo = build_roster_record(UserTo, ServerTo, UserFrom, ServerFrom, UserFrom,[]), set_item(UserTo, ServerTo, undefined, RITo), @@ -268,8 +268,8 @@ set_item(User, Server, Resource, Item) -> ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request, "push" ++ randoms:get_string()), ejabberd_router:route( - exmpp_jid:make_jid(User, Server, Resource), - exmpp_jid:make_jid(Server), + exmpp_jid:make(User, Server, Resource), + exmpp_jid:make(Server), ResIQ). @@ -334,7 +334,7 @@ out_subscription(UserFrom, ServerFrom, JIDTo, unsubscribed) -> %% Remove pending out subscription {UserTo, ServerTo, _} = jlib:short_prepd_bare_jid(JIDTo), - JIDFrom = exmpp_jid:make_jid(UserFrom, UserTo), + JIDFrom = exmpp_jid:make(UserFrom, UserTo), Mod:out_subscription(UserTo, ServerTo, JIDFrom, unsubscribe), %% Remove pending in subscription @@ -684,7 +684,7 @@ push_item(User, Server, From, Item) -> %% ejabberd_sm:route(jlib:make_jid("", "", ""), %% jlib:make_jid(User, Server, "") %% why? - ejabberd_sm:route(From, exmpp_jid:make_jid(User, Server), + ejabberd_sm:route(From, exmpp_jid:make(User, Server), #xmlel{name = 'broadcast', children = [{item, Item#roster.jid, @@ -695,7 +695,7 @@ push_item(User, Server, From, Item) -> "push" ++ randoms:get_string()), lists:foreach( fun(Resource) -> - JID = exmpp_jid:make_jid(User, Server, Resource), + JID = exmpp_jid:make(User, Server, Resource), ejabberd_router:route(JID, JID, Stanza) end, ejabberd_sm:get_user_resources(list_to_binary(User), list_to_binary(Server))). @@ -707,7 +707,7 @@ push_roster_item(User, Server, ContactU, ContactS, GroupName, Subscription) -> subscription = Subscription, ask = none, groups = [GroupName]}, - push_item(User, Server, exmpp_jid:make_jid(Server), Item). + push_item(User, Server, exmpp_jid:make(Server), Item). item_to_xml(Item) -> {U, S, R} = Item#roster.jid, diff --git a/src/web/ejabberd_http_poll.erl b/src/web/ejabberd_http_poll.erl index d4ecaf549..9b521c34a 100644 --- a/src/web/ejabberd_http_poll.erl +++ b/src/web/ejabberd_http_poll.erl @@ -423,14 +423,14 @@ resend_message(Packet) -> get_jid("from", ParsedPacket) -> case exmpp_stanza:get_sender(ParsedPacket) of undefined -> - exmpp_jid:make_jid(); + exmpp_jid:make(); From -> exmpp_jid:parse_jid(From) end; get_jid("to", ParsedPacket) -> case exmpp_stanza:get_recipient(ParsedPacket) of undefined -> - exmpp_jid:make_jid(); + exmpp_jid:make(); From -> exmpp_jid:parse_jid(From) end. diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 934369878..b2d689dea 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -77,7 +77,7 @@ process(["server", SHost | RPath], #request{auth = Auth} = Request) -> case get_auth(Auth) of {User, Server} -> case acl:match_rule( - Host, configure, exmpp_jid:make_jid(User, Server)) of + Host, configure, exmpp_jid:make(User, Server)) of deny -> ejabberd_web:error(not_allowed); allow -> @@ -99,7 +99,7 @@ process(RPath, #request{auth = Auth} = Request) -> case get_auth(Auth) of {User, Server} -> case acl:match_rule( - global, configure, exmpp_jid:make_jid(User, Server)) of + global, configure, exmpp_jid:make(User, Server)) of deny -> ejabberd_web:error(not_allowed); allow -> From 5dbc4f99545179c5535924a727913e62a8b42da4 Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 16:30:15 +0000 Subject: [PATCH 332/582] API renaming : jid_to_bare_jid > bare SVN Revision: 2120 --- src/ejabberd_c2s.erl | 10 +++++----- src/ejabberd_s2s.erl | 2 +- src/ejabberd_sm.erl | 2 +- src/jlib.erl | 4 ++-- src/mod_muc/mod_muc_room.erl | 2 +- src/mod_roster.erl | 4 ++-- src/mod_roster_odbc.erl | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 477aeffc0..0fdc23c36 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -838,7 +838,7 @@ session_established2(El, StateData) -> To = exmpp_stanza:get_recipient(El), ToJID = case To of undefined -> - exmpp_jid:jid_to_bare_jid(StateData#state.jid); + exmpp_jid:bare(StateData#state.jid); _ -> exmpp_jid:parse_jid(To) end, @@ -1518,28 +1518,28 @@ presence_track(From, To, Packet, StateData) -> ejabberd_hooks:run(roster_out_subscription, StateData#state.server, [StateData#state.user, StateData#state.server, To, subscribe]), - check_privacy_route(From, StateData, exmpp_jid:jid_to_bare_jid(From), + check_privacy_route(From, StateData, exmpp_jid:bare(From), To, Packet), StateData; 'subscribed' -> ejabberd_hooks:run(roster_out_subscription, StateData#state.server, [StateData#state.user, StateData#state.server, To, subscribed]), - check_privacy_route(From, StateData, exmpp_jid:jid_to_bare_jid(From), + check_privacy_route(From, StateData, exmpp_jid:bare(From), To, Packet), StateData; 'unsubscribe' -> ejabberd_hooks:run(roster_out_subscription, StateData#state.server, [StateData#state.user, StateData#state.server, To, unsubscribe]), - check_privacy_route(From, StateData, exmpp_jid:jid_to_bare_jid(From), + check_privacy_route(From, StateData, exmpp_jid:bare(From), To, Packet), StateData; 'unsubscribed' -> ejabberd_hooks:run(roster_out_subscription, StateData#state.server, [StateData#state.user, StateData#state.server, To, unsubscribed]), - check_privacy_route(From, StateData, exmpp_jid:jid_to_bare_jid(From), + check_privacy_route(From, StateData, exmpp_jid:bare(From), To, Packet), StateData; 'error' -> diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index e21511fcb..0c68c694c 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -357,7 +357,7 @@ choose_pid(From, Pids) -> % Use sticky connections based on the JID of the sender (whithout % the resource to ensure that a muc room always uses the same % connection) - Pid = lists:nth(erlang:phash(exmpp_jid:jid_to_bare_jid(From), length(Pids1)), + Pid = lists:nth(erlang:phash(exmpp_jid:bare(From), length(Pids1)), Pids1), ?DEBUG("Using ejabberd_s2s_out ~p~n", [Pid]), Pid. diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 6cc7c20c5..7bb0cf35a 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -678,7 +678,7 @@ check_max_sessions(JID) -> %% Defaults to infinity get_max_user_sessions(JID) -> case acl:match_rule( - exmpp_jid:ldomain_as_list(JID), max_user_sessions, exmpp_jid:jid_to_bare_jid(JID)) of + exmpp_jid:ldomain_as_list(JID), max_user_sessions, exmpp_jid:bare(JID)) of Max when is_integer(Max) -> Max; infinity -> infinity; _ -> ?MAX_USER_SESSIONS diff --git a/src/jlib.erl b/src/jlib.erl index 3b1e8f914..d914bf73f 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -379,7 +379,7 @@ short_jid(JID) -> {exmpp_jid:node(JID), exmpp_jid:domain(JID), exmpp_jid:resource(JID)}. short_bare_jid(JID) -> - short_jid(exmpp_jid:jid_to_bare_jid(JID)). + short_jid(exmpp_jid:bare(JID)). short_prepd_jid(JID) -> {exmpp_jid:lnode(JID), @@ -387,6 +387,6 @@ short_prepd_jid(JID) -> exmpp_jid:lresource(JID)}. short_prepd_bare_jid(JID) -> - short_prepd_jid(exmpp_jid:jid_to_bare_jid(JID)). + short_prepd_jid(exmpp_jid:bare(JID)). diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index c0f44a8fa..d16e09020 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -2379,7 +2379,7 @@ find_changed_items(UJID, UAffiliation, URole, UJID, UAffiliation, URole, Items, Lang, StateData, - [{exmpp_jid:jid_to_bare_jid(JID), + [{exmpp_jid:bare(JID), affiliation, SAffiliation, exmpp_xml:get_path( diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 7ae405284..4afb0df88 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -300,14 +300,14 @@ process_item_set(From, To, #xmlel{} = El) -> {U, S, R} = OldItem#roster.jid, if IsTo -> ejabberd_router:route( - exmpp_jid:jid_to_bare_jid(From), + exmpp_jid:bare(From), exmpp_jid:make(U, S, R), exmpp_presence:unsubscribe()); true -> ok end, if IsFrom -> ejabberd_router:route( - exmpp_jid:jid_to_bare_jid(From), + exmpp_jid:bare(From), exmpp_jid:make(U, S, R), exmpp_presence:unsubscribed()); true -> ok diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 590f036e4..c4ea93cf0 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -284,14 +284,14 @@ process_item_set(From, To, #xmlel{} = El) -> {U, S, R} = OldItem#roster.jid, if IsTo -> ejabberd_router:route( - exmpp_jid:jid_to_bare_jid(From), + exmpp_jid:bare(From), exmpp_jid:make(U, S, R), exmpp_presence:unsubscribe()); true -> ok end, if IsFrom -> ejabberd_router:route( - exmpp_jid:jid_to_bare_jid(From), + exmpp_jid:bare(From), exmpp_jid:make(U, S, R), exmpp_presence:unsubscribed()); true -> ok From a136192db2bedce9e088ab55710461b5af22d2cd Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 16:34:38 +0000 Subject: [PATCH 333/582] API renaming : bare_jid_to_jid -> full SVN Revision: 2121 --- src/ejabberd_sm.erl | 4 ++-- src/mod_configure.erl | 4 ++-- src/mod_disco.erl | 2 +- src/mod_echo.erl | 2 +- src/mod_muc/mod_muc_room.erl | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 7bb0cf35a..b5c8270e9 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -465,7 +465,7 @@ do_route(From, To, Packet) -> fun({_, R}) -> do_route( From, - exmpp_jid:bare_jid_to_jid(To, R), + exmpp_jid:full(To, R), Packet) end, PResources); true -> @@ -479,7 +479,7 @@ do_route(From, To, Packet) -> lists:foreach( fun(R) -> do_route(From, - exmpp_jid:bare_jid_to_jid(To, R), + exmpp_jid:full(To, R), Packet) end, get_user_resources(exmpp_jid:lnode(To), exmpp_jid:ldomain(To))); diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 9dc25ffc8..838ce0ddb 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -304,7 +304,7 @@ get_user_resources(BareJID) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', exmpp_jid:jid_to_binary( - exmpp_jid:bare_jid_to_jid(BareJID, R))), + exmpp_jid:full(BareJID, R))), ?XMLATTR('name', exmpp_jid:lnode(BareJID))]} end, lists:sort(Rs)). @@ -1677,7 +1677,7 @@ set_form(From, Host, ?NS_ADMINL("user-stats"), Lang, XData) -> Resources = ejabberd_sm:get_user_resources(exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID)), - IPs1 = [ejabberd_sm:get_user_ip(exmpp_jid:bare_jid_to_jid(JID,Resource)) + IPs1 = [ejabberd_sm:get_user_ip(exmpp_jid:full(JID,Resource)) || Resource <- Resources], IPs = [inet_parse:ntoa(IP)++":"++integer_to_list(Port) || {IP, Port} <- IPs1], diff --git a/src/mod_disco.erl b/src/mod_disco.erl index b548464eb..a75b173f4 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -397,7 +397,7 @@ get_user_resources(JID) -> lists:map(fun(R) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [ ?XMLATTR('jid', - exmpp_jid:jid_to_binary(exmpp_jid:bare_jid_to_jid(JID, R))), + exmpp_jid:jid_to_binary(exmpp_jid:full(JID, R))), ?XMLATTR('name', exmpp_jid:lnode(JID)) ]} end, lists:sort(Rs)). diff --git a/src/mod_echo.erl b/src/mod_echo.erl index a1df48723..27a2850a5 100644 --- a/src/mod_echo.erl +++ b/src/mod_echo.erl @@ -174,7 +174,7 @@ do_client_version(disabled, _From, _To) -> do_client_version(enabled, From, To) -> %% It is important to identify this process and packet Random_resource = integer_to_list(random:uniform(100000)), - From2 = exmpp_jid:bare_jid_to_jid(From,Random_resource), + From2 = exmpp_jid:full(From,Random_resource), %% Build an iq:query request Request = #xmlel{ns = ?NS_SOFT_VERSION, name = 'query'}, diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index d16e09020..3dc9b1577 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -3533,7 +3533,7 @@ tab_count_user(JID) -> jid_replace_resource(JID, Resource) -> - exmpp_jid:bare_jid_to_jid(JID, Resource). + exmpp_jid:full(JID, Resource). From 526dc54173aba2a5dac5bf40daa908dc576ef552 Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 16:35:55 +0000 Subject: [PATCH 334/582] API renaming : parse_jid -> parse SVN Revision: 2122 --- src/ejabberd_c2s.erl | 4 ++-- src/ejabberd_s2s_in.erl | 10 +++++----- src/ejabberd_s2s_out.erl | 4 ++-- src/ejabberd_service.erl | 6 +++--- src/ejabberd_system_monitor.erl | 4 ++-- src/jd2ejd.erl | 2 +- src/mod_configure.erl | 14 +++++++------- src/mod_irc/mod_irc_connection.erl | 4 ++-- src/mod_muc/mod_muc_log.erl | 2 +- src/mod_muc/mod_muc_room.erl | 6 +++--- src/mod_offline_odbc.erl | 4 ++-- src/mod_privacy.erl | 2 +- src/mod_privacy_odbc.erl | 4 ++-- src/mod_proxy65/mod_proxy65_service.erl | 2 +- src/mod_pubsub/mod_pubsub.erl | 10 +++++----- src/mod_register.erl | 2 +- src/mod_roster.erl | 6 +++--- src/mod_roster_odbc.erl | 8 ++++---- src/mod_shared_roster.erl | 2 +- src/web/ejabberd_http_poll.erl | 4 ++-- src/web/ejabberd_web_admin.erl | 10 +++++----- 21 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 0fdc23c36..4054d9eb2 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -840,7 +840,7 @@ session_established2(El, StateData) -> undefined -> exmpp_jid:bare(StateData#state.jid); _ -> - exmpp_jid:parse_jid(To) + exmpp_jid:parse(To) end, NewEl = case exmpp_stanza:get_lang(El) of undefined -> @@ -1919,7 +1919,7 @@ check_from(El, FromJID) -> El; {value, SJID} -> try - JIDEl = exmpp_jid:parse_jid(SJID), + JIDEl = exmpp_jid:parse(SJID), case exmpp_jid:lresource(JIDEl) of undefined -> %% Matching JID: The stanza is ok diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 0a0a9e46a..d4fc78152 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -371,7 +371,7 @@ stream_established({xmlstreamelement, El}, StateData) -> error; F -> try - exmpp_jid:parse_jid(F) + exmpp_jid:parse(F) catch _Exception1 -> error end @@ -381,7 +381,7 @@ stream_established({xmlstreamelement, El}, StateData) -> error; T -> try - exmpp_jid:parse_jid(T) + exmpp_jid:parse(T) catch _Exception2 -> error end @@ -641,7 +641,7 @@ get_cert_domains(Cert) -> end, if D /= error -> - JID = exmpp_jid:parse_jid(D), + JID = exmpp_jid:parse(D), case {exmpp_jid:lnode_as_list(JID), exmpp_jid:ldomain_as_list(JID), exmpp_jid:lresource_as_list(JID)} of @@ -677,7 +677,7 @@ get_cert_domains(Cert) -> case 'XmppAddr':decode( 'XmppAddr', XmppAddr) of {ok, D} when is_binary(D) -> - JID2 = exmpp_jid:parse_jid(binary_to_list(D)), + JID2 = exmpp_jid:parse(binary_to_list(D)), case {exmpp_jid:lnode_as_list(JID2), exmpp_jid:ldomain_as_list(JID2), exmpp_jid:lresource_as_list(JID2)} of @@ -695,7 +695,7 @@ get_cert_domains(Cert) -> [] end; ({dNSName, D}) when is_list(D) -> - JID3 = exmpp_jid:parse_jid(D), + JID3 = exmpp_jid:parse(D), case {exmpp_jid:lnode_as_list(JID3), exmpp_jid:ldomain_as_list(JID3), exmpp_jid:lresource_as_list(JID3)} of diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 9641e5c11..2ee8ddeb9 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -855,8 +855,8 @@ bounce_element(El, Condition) -> <<"result">> -> ok; _ -> Err = exmpp_stanza:reply_with_error(El, Condition), - From = exmpp_jid:parse_jid(exmpp_stanza:get_sender(El)), - To = exmpp_jid:parse_jid(exmpp_stanza:get_recipient(El)), + From = exmpp_jid:parse(exmpp_stanza:get_sender(El)), + To = exmpp_jid:parse(exmpp_stanza:get_recipient(El)), % No namespace conversion (:server <-> :client) is done. % This is handled by C2S and S2S send_element functions. ejabberd_router:route(To, From, Err) diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 0f2472467..e786a4d4d 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -227,10 +227,10 @@ stream_established({xmlstreamelement, El}, StateData) -> %% when accept packets from any address. %% In this case, the component can send packet of %% behalf of the server users. - false -> exmpp_jid:parse_jid(From); + false -> exmpp_jid:parse(From); %% The default is the standard behaviour in XEP-0114 _ -> - FromJID1 = exmpp_jid:parse_jid(From), + FromJID1 = exmpp_jid:parse(From), Server = exmpp_jid:ldomain(FromJID1), case lists:member(Server, StateData#state.hosts) of true -> FromJID1; @@ -240,7 +240,7 @@ stream_established({xmlstreamelement, El}, StateData) -> To = exmpp_stanza:get_recipient(El), ToJID = case To of undefined -> error; - _ -> exmpp_jid:parse_jid(To) + _ -> exmpp_jid:parse(To) end, if ((El#xmlel.name == 'iq') or (El#xmlel.name == 'message') or diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl index cfd8c381b..aea38787a 100644 --- a/src/ejabberd_system_monitor.erl +++ b/src/ejabberd_system_monitor.erl @@ -194,7 +194,7 @@ process_large_heap(Pid, Info) -> lists:foreach( fun(S) -> try - JID = exmpp_jid:parse_jid(S), + JID = exmpp_jid:parse(S), send_message(From, JID, Body) catch _ -> @@ -216,7 +216,7 @@ get_admin_jids() -> lists:flatmap( fun(S) -> try - JID = exmpp_jid:parse_jid(S), + JID = exmpp_jid:parse(S), [{exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID), exmpp_jid:lresource(JID)}] diff --git a/src/jd2ejd.erl b/src/jd2ejd.erl index 9151f45be..633e3195b 100644 --- a/src/jd2ejd.erl +++ b/src/jd2ejd.erl @@ -195,7 +195,7 @@ process_offline(Server, To, #xmlel{children = Els}) -> exmpp_jid:make(Server); _ -> try - exmpp_jid:parse_jid(FromS) + exmpp_jid:parse(FromS) catch _ -> error diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 838ce0ddb..b33c6366f 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -1562,7 +1562,7 @@ set_form(From, Host, ?NS_ADMINL("add-user"), _Lang, XData) -> AccountString = get_value("accountjid", XData), Password = get_value("password", XData), Password = get_value("password-verify", XData), - AccountJID = exmpp_jid:parse_jid(AccountString), + AccountJID = exmpp_jid:parse(AccountString), User = exmpp_jid:lnode_as_list(AccountJID), Server = exmpp_jid:ldomain_as_list(AccountJID), true = lists:member(Server, ?MYHOSTS), @@ -1575,7 +1575,7 @@ set_form(From, Host, ?NS_ADMINL("delete-user"), _Lang, XData) -> [_|_] = AccountStringList, ASL2 = lists:map( fun(AccountString) -> - JID = exmpp_jid:parse_jid(AccountString), + JID = exmpp_jid:parse(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), Server = exmpp_jid:ldomain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), @@ -1588,7 +1588,7 @@ set_form(From, Host, ?NS_ADMINL("delete-user"), _Lang, XData) -> set_form(From, Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> AccountString = get_value("accountjid", XData), - JID = exmpp_jid:parse_jid(AccountString), + JID = exmpp_jid:parse(AccountString), LUser = [_|_] = exmpp_jid:lnode_as_list(JID), LServer = exmpp_jid:ldomain_as_list(JID), true = (LServer == Host) orelse (get_permission_level(From) == global), @@ -1607,7 +1607,7 @@ set_form(From, Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> set_form(From, Host, ?NS_ADMINL("get-user-password"), Lang, XData) -> AccountString = get_value("accountjid", XData), - JID = exmpp_jid:parse_jid(AccountString), + JID = exmpp_jid:parse(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), Server = exmpp_jid:ldomain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), @@ -1622,7 +1622,7 @@ set_form(From, Host, ?NS_ADMINL("get-user-password"), Lang, XData) -> set_form(From, Host, ?NS_ADMINL("change-user-password"), _Lang, XData) -> AccountString = get_value("accountjid", XData), Password = get_value("password", XData), - JID = exmpp_jid:parse_jid(AccountString), + JID = exmpp_jid:parse(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), Server = exmpp_jid:ldomain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), @@ -1632,7 +1632,7 @@ set_form(From, Host, ?NS_ADMINL("change-user-password"), _Lang, XData) -> set_form(From, Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> AccountString = get_value("accountjid", XData), - JID = exmpp_jid:parse_jid(AccountString), + JID = exmpp_jid:parse(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), Server = exmpp_jid:ldomain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), @@ -1670,7 +1670,7 @@ set_form(From, Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> set_form(From, Host, ?NS_ADMINL("user-stats"), Lang, XData) -> AccountString = get_value("accountjid", XData), - JID = exmpp_jid:parse_jid(AccountString), + JID = exmpp_jid:parse(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), Server = exmpp_jid:ldomain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), diff --git a/src/mod_irc/mod_irc_connection.erl b/src/mod_irc/mod_irc_connection.erl index b9eef8223..79d492ef6 100644 --- a/src/mod_irc/mod_irc_connection.erl +++ b/src/mod_irc/mod_irc_connection.erl @@ -632,8 +632,8 @@ bounce_messages(Reason) -> attrs = [?XMLATTR('code', <<"502">>)], children = [#xmlcdata{cdata = Reason}]}, Err = exmpp_stanza:reply_with_error(El, Error), - From = exmpp_jid:parse_jid(exmpp_stanza:get_sender(El)), - To = exmpp_jid:parse_jid(exmpp_stanza:get_recipient(El)), + From = exmpp_jid:parse(exmpp_stanza:get_sender(El)), + To = exmpp_jid:parse(exmpp_stanza:get_recipient(El)), ejabberd_router:route(To, From, Err) end, bounce_messages(Reason) diff --git a/src/mod_muc/mod_muc_log.erl b/src/mod_muc/mod_muc_log.erl index e531de96e..7a582e739 100644 --- a/src/mod_muc/mod_muc_log.erl +++ b/src/mod_muc/mod_muc_log.erl @@ -271,7 +271,7 @@ build_filename_string(TimeStamp, OutDir, RoomJID, DirType, DirName, FileFormat) {Fd, Fn, Fnrel}. get_room_name(RoomJID) -> - JID = exmpp_jid:parse_jid(RoomJID), + JID = exmpp_jid:parse(RoomJID), exmpp_jid:node_as_list(JID). %% calculate day before diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 3dc9b1577..c9c69d078 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -2294,7 +2294,7 @@ find_changed_items(UJID, UAffiliation, URole, Lang, StateData, Res) -> TJID = case exmpp_xml:get_attribute_as_binary(Item, 'jid',false) of S when S =/= false -> - try exmpp_jid:parse_jid(S) of + try exmpp_jid:parse(S) of J -> {value, J} catch @@ -3344,7 +3344,7 @@ check_invitation(From, Els, Lang, StateData) -> _ -> throw({error, 'bad-request'}) end, - JID = try exmpp_jid:parse_jid(exmpp_xml:get_attribute_as_binary(InviteEl, + JID = try exmpp_jid:parse(exmpp_xml:get_attribute_as_binary(InviteEl, 'to', false)) of JID1 -> JID1 @@ -3447,7 +3447,7 @@ check_decline_invitation(Packet) -> #xmlel{ns = ?NS_MUC_USER} = XEl = exmpp_xml:get_element(Packet, 'x'), DEl = exmpp_xml:get_element(XEl, 'decline'), ToString = exmpp_xml:get_attribute_as_binary(DEl, 'to', false), - ToJID = exmpp_jid:parse_jid(ToString), + ToJID = exmpp_jid:parse(ToString), {true, {Packet, XEl, DEl, ToJID}}. %% Send the decline to the inviter user. diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index b997f6a07..7eaa9669c 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -257,9 +257,9 @@ pop_offline_messages(Ls, User, Server) [El] = exmpp_xml:parse_document(XML, [names_as_atom, {check_elems, xmpp}, {check_nss,xmpp}, {check_attrs,xmpp}]), - To = exmpp_jid:parse_jid( + To = exmpp_jid:parse( exmpp_stanza:get_recipient(El)), - From = exmpp_jid:parse_jid( + From = exmpp_jid:parse( exmpp_stanza:get_sender(El)), [{route, From, To, El}] catch diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 820a8aba5..7fbc8443b 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -444,7 +444,7 @@ parse_items([El = #xmlel{name = item} | Els], Res) -> case T of "jid" -> try - JID = exmpp_jid:parse_jid(V), + JID = exmpp_jid:parse(V), I1#listitem{ type = jid, value = jlib:short_prepd_jid(JID)} diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 6f373d49f..b94b1a649 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -445,7 +445,7 @@ parse_items([El = #xmlel{name = item} | Els], Res) -> case T of "jid" -> try - JID = exmpp_jid:parse_jid(V), + JID = exmpp_jid:parse(V), I1#listitem{ type = jid, value = jlib:short_prepd_jid(JID)} @@ -693,7 +693,7 @@ raw_to_item({SType, SValue, SAction, SOrder, SMatchAll, SMatchIQ, "n" -> {none, none}; "j" -> - JID = exmpp_jid:parse_jid(SValue), + JID = exmpp_jid:parse(SValue), {jid, jlib:short_prepd_jid(JID)}; "g" -> {group, SValue}; diff --git a/src/mod_proxy65/mod_proxy65_service.erl b/src/mod_proxy65/mod_proxy65_service.erl index 372e2d7a9..ba1c43176 100644 --- a/src/mod_proxy65/mod_proxy65_service.erl +++ b/src/mod_proxy65/mod_proxy65_service.erl @@ -160,7 +160,7 @@ process_iq(InitiatorJID, #iq{type = set, payload = SubEl, ns = ?NS_BYTESTREAMS} allow -> ActivateEl = exmpp_xml:get_path(SubEl, [{element, 'activate'}]), SID = exmpp_xml:get_attribute_as_list(SubEl, 'sid', ""), - case catch exmpp_jid:parse_jid(exmpp_xml:get_cdata_as_string(ActivateEl)) of + case catch exmpp_jid:parse(exmpp_xml:get_cdata_as_string(ActivateEl)) of TargetJID when ?IS_JID(TargetJID), SID /= "", length(SID) =< 128, TargetJID /= InitiatorJID -> Target = exmpp_jid:prepd_jid_to_list(TargetJID), diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 0d5b8aeef..8508e5d85 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -1310,7 +1310,7 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> {_, _, _} -> [SNode]; _ -> string:tokens(SNode, "/") end, - Subscriber = exmpp_jid:parse_jid(SSubscriber), + Subscriber = exmpp_jid:parse(SSubscriber), Allow = case SAllow of "1" -> true; "true" -> true; @@ -1587,7 +1587,7 @@ delete_node(Host, Node, Owner) -> %%</ul> subscribe_node(Host, Node, From, JID) -> Subscriber = try - jlib:short_prepd_jid(exmpp_jid:parse_jid(JID)) + jlib:short_prepd_jid(exmpp_jid:parse(JID)) catch _:_ -> {undefined, undefined, undefined} @@ -1684,7 +1684,7 @@ subscribe_node(Host, Node, From, JID) -> %%<li>The request specifies a subscription ID that is not valid or current.</li> %%</ul> unsubscribe_node(Host, Node, From, JID, SubId) when is_list(JID) -> - Subscriber = try jlib:short_prepd_jid(exmpp_jid:parse_jid(JID)) + Subscriber = try jlib:short_prepd_jid(exmpp_jid:parse(JID)) catch _:_ -> {undefined, undefined, undefined} @@ -2126,7 +2126,7 @@ set_affiliations(Host, Node, From, EntitiesEls) -> case El of #xmlel{name = 'affiliation', attrs = Attrs} -> JID = try - exmpp_jid:parse_jid( + exmpp_jid:parse( exmpp_xml:get_attribute_from_list_as_list(Attrs, 'jid', "")) catch _:_ -> error @@ -2297,7 +2297,7 @@ set_subscriptions(Host, Node, From, EntitiesEls) -> case El of #xmlel{name = 'subscription', attrs = Attrs} -> JID = try - exmpp_jid:parse_jid( + exmpp_jid:parse( exmpp_xml:get_attribute_from_list_as_list(Attrs, 'jid', "")) catch _:_ -> diff --git a/src/mod_register.erl b/src/mod_register.erl index c45a47cca..3b6ce57cd 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -266,7 +266,7 @@ send_registration_notifications(UJID) -> lists:foreach( fun(S) -> try - JID = exmpp_jid:parse_jid(S), + JID = exmpp_jid:parse(S), ejabberd_router:route( exmpp_jid:make(Host), JID, diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 4afb0df88..6b5559bcb 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -248,7 +248,7 @@ process_iq_set(From, To, #iq{payload = Request} = IQ_Rec) -> process_item_set(From, To, #xmlel{} = El) -> try - JID1 = exmpp_jid:parse_jid(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), + JID1 = exmpp_jid:parse(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), User = exmpp_jid:node(From), LUser = exmpp_jid:lnode(From), LServer = exmpp_jid:ldomain(From), @@ -777,7 +777,7 @@ set_items(User, Server, #xmlel{children = Els}) process_item_set_t(LUser, LServer, #xmlel{} = El) -> try - JID1 = exmpp_jid:parse_jid(exmpp_xml:get_attribute_as_list(El, 'jid', <<>>)), + JID1 = exmpp_jid:parse(exmpp_xml:get_attribute_as_list(El, 'jid', <<>>)), JID = jlib:short_jid(JID1), LJID = jlib:short_prepd_jid(JID1), Item = #roster{usj = {LUser, LServer, LJID}, @@ -1216,7 +1216,7 @@ user_roster_parse_query(User, Server, Items, Query) -> error; {value, {_, SJID}} -> try - JID = exmpp_jid:parse_jid(SJID), + JID = exmpp_jid:parse(SJID), user_roster_subscribe_jid(User, Server, JID), ok catch diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index c4ea93cf0..4024aae2c 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -216,7 +216,7 @@ process_iq_set(From, To, #iq{payload = Request} = IQ_Rec) -> process_item_set(From, To, #xmlel{} = El) -> try - JID1 = exmpp_jid:parse_jid(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), + JID1 = exmpp_jid:parse(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), User = exmpp_jid:lnode(From), Server = exmpp_jid:ldomain(From), LServer = binary_to_list(Server), @@ -696,7 +696,7 @@ set_items(User, Server, #xmlel{children = Els}) when is_binary(User), is_binary( process_item_set_t(LUser, LServer, #xmlel{} = El) -> try - JID1 = exmpp_jid:parse_jid(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), + JID1 = exmpp_jid:parse(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), {U0, S0, R0} = LJID = jlib:short_prepd_jid(JID1), Username = ejabberd_odbc:escape(LUser), SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_binary(U0, S0, R0)), @@ -854,7 +854,7 @@ get_jid_info(_, User, Server, JID) when is_binary(User), is_binary(Server) -> raw_to_record(LServer, {User, SJID, Nick, SSubscription, SAsk, SAskMessage, _SServer, _SSubscribe, _SType}) when is_binary(LServer) -> try - JID = exmpp_jid:parse_jid(SJID), + JID = exmpp_jid:parse(SJID), LJID = jlib:short_prepd_jid(JID), Subscription = case SSubscription of "B" -> both; @@ -1045,7 +1045,7 @@ user_roster_parse_query(User, Server, Items, Query) -> error; {value, {_, SJID}} -> try - JID = exmpp_jid:parse_jid(SJID), + JID = exmpp_jid:parse(SJID), user_roster_subscribe_jid(User, Server, JID), ok catch diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index b8df4d19c..25cdb9a24 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -940,7 +940,7 @@ shared_roster_group_parse_query(Host, Group, Query) -> USs; _ -> try - JID = exmpp_jid:parse_jid(SJID), + JID = exmpp_jid:parse(SJID), [{exmpp_jid:lnode_as_list(JID), exmpp_jid:ldomain_as_list(JID)} | USs] catch _ -> diff --git a/src/web/ejabberd_http_poll.erl b/src/web/ejabberd_http_poll.erl index 9b521c34a..e340d0e35 100644 --- a/src/web/ejabberd_http_poll.erl +++ b/src/web/ejabberd_http_poll.erl @@ -425,12 +425,12 @@ get_jid("from", ParsedPacket) -> undefined -> exmpp_jid:make(); From -> - exmpp_jid:parse_jid(From) + exmpp_jid:parse(From) end; get_jid("to", ParsedPacket) -> case exmpp_stanza:get_recipient(ParsedPacket) of undefined -> exmpp_jid:make(); From -> - exmpp_jid:parse_jid(From) + exmpp_jid:parse(From) end. diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index b2d689dea..75f30f2aa 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -120,7 +120,7 @@ get_auth(Auth) -> case Auth of {SJID, P} -> try - JID = exmpp_jid:parse_jid(SJID), + JID = exmpp_jid:parse(SJID), U = exmpp_jid:node_as_list(JID), S = exmpp_jid:domain_as_list(JID), case ejabberd_auth:check_password(U, S, P) of @@ -1176,7 +1176,7 @@ string_to_spec("user_regexp", Val) -> string_to_spec("server_regexp", Val) -> {server_regexp, Val}; string_to_spec("node_regexp", Val) -> - JID = exmpp_jid:parse_jid(Val), + JID = exmpp_jid:parse(Val), U = exmpp_jid:lnode_as_list(JID), S = exmpp_jid:ldomain_as_list(JID), undefined = exmpp_jid:resource(JID), @@ -1186,7 +1186,7 @@ string_to_spec("user_glob", Val) -> string_to_spec("server_glob", Val) -> {server_glob, Val}; string_to_spec("node_glob", Val) -> - JID = exmpp_jid:parse_jid(Val), + JID = exmpp_jid:parse(Val), U = exmpp_jid:lnode_as_list(JID), S = exmpp_jid:ldomain_as_list(JID), undefined = exmpp_jid:resource(JID), @@ -1199,7 +1199,7 @@ string_to_spec("raw", Val) -> NewSpec. string_to_spec2(ACLName, Val) -> - JID = exmpp_jid:parse_jid(Val), + JID = exmpp_jid:parse(Val), U = exmpp_jid:lnode_as_list(JID), S = exmpp_jid:ldomain_as_list(JID), undefined = exmpp_jid:resource(JID), @@ -1402,7 +1402,7 @@ list_users_parse_query(Query, Host) -> {value, {_, Password}} = lists:keysearch("newuserpassword", 1, Query), try - JID = exmpp_jid:parse_jid(Username++"@"++Host), + JID = exmpp_jid:parse(Username++"@"++Host), User = exmpp_jid:node_as_list(JID), Server = exmpp_jid:domain_as_list(JID), case ejabberd_auth:try_register(User, Server, Password) of From 19d7d79229fafd64801dcf2491d6abe565ea1fbe Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 16:37:15 +0000 Subject: [PATCH 335/582] API renaming : ldomain -> prep_domain SVN Revision: 2123 --- src/ejabberd_auth_anonymous.erl | 4 +-- src/ejabberd_c2s.erl | 2 +- src/ejabberd_local.erl | 4 +-- src/ejabberd_router.erl | 2 +- src/ejabberd_s2s.erl | 2 +- src/ejabberd_s2s_in.erl | 4 +-- src/ejabberd_service.erl | 2 +- src/ejabberd_sm.erl | 60 ++++++++++++++++----------------- src/ejabberd_system_monitor.erl | 2 +- src/jlib.erl | 2 +- src/mod_adhoc.erl | 6 ++-- src/mod_announce.erl | 4 +-- src/mod_caps.erl | 2 +- src/mod_configure.erl | 8 ++--- src/mod_disco.erl | 14 ++++---- src/mod_last.erl | 14 ++++---- src/mod_last_odbc.erl | 12 +++---- src/mod_muc/mod_muc.erl | 6 ++-- src/mod_muc/mod_muc_room.erl | 6 ++-- src/mod_privacy.erl | 2 +- src/mod_privacy_odbc.erl | 2 +- src/mod_private.erl | 4 +-- src/mod_roster.erl | 12 +++---- src/mod_roster_odbc.erl | 16 ++++----- 24 files changed, 96 insertions(+), 96 deletions(-) diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index 0a9361180..2808bcc70 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -180,7 +180,7 @@ remove_connection(SID, LUser, LServer) when is_list(LUser), is_list(LServer) -> register_connection(SID, JID, Info) when ?IS_JID(JID) -> LUser = exmpp_jid:lnode(JID), - LServer = exmpp_jid:ldomain(JID), + LServer = exmpp_jid:prep_domain(JID), case proplists:get_value(auth_module, Info) of undefined -> ok; @@ -201,7 +201,7 @@ register_connection(SID, JID, Info) when ?IS_JID(JID) -> unregister_connection(SID, JID, _) when ?IS_JID(JID) -> LUser = exmpp_jid:lnode(JID), - LServer = exmpp_jid:ldomain(JID), + LServer = exmpp_jid:prep_domain(JID), purge_hook(anonymous_user_exist(LUser, LServer), LUser, LServer), remove_connection(SID, LUser, LServer). diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 4054d9eb2..147f48109 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1574,7 +1574,7 @@ check_privacy_route(From, StateData, FromRoute, To, Packet) -> %% Check if privacy rules allow this delivery is_privacy_allow(From, To, Packet, PrivacyList) -> User = exmpp_jid:lnode(To), - Server = exmpp_jid:ldomain(To), + Server = exmpp_jid:prep_domain(To), allow == ejabberd_hooks:run_fold( privacy_check_packet, Server, allow, diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 78d67784d..74005ad59 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -76,7 +76,7 @@ start_link() -> process_iq(From, To, Packet) -> case exmpp_iq:xmlel_to_iq(Packet) of #iq{kind = request, ns = XMLNS} = IQ_Rec -> - Host = exmpp_jid:ldomain(To), + Host = exmpp_jid:prep_domain(To), case ets:lookup(?IQTABLE, {XMLNS, Host}) of [{_, Module, Function}] -> ResIQ = Module:Function(From, To, IQ_Rec), @@ -325,7 +325,7 @@ do_route(From, To, Packet) -> <<"result">> -> ok; _ -> ejabberd_hooks:run(local_send_to_resource_hook, - exmpp_jid:ldomain(To), + exmpp_jid:prep_domain(To), [From, To, Packet]) end end. diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index 915f4379a..5f60932b7 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -332,7 +332,7 @@ do_route(OrigFrom, OrigTo, OrigPacket) -> case ejabberd_hooks:run_fold(filter_packet, {OrigFrom, OrigTo, OrigPacket}, []) of {From, To, Packet} -> - LDomain = exmpp_jid:ldomain(To), + LDomain = exmpp_jid:prep_domain(To), case mnesia:dirty_read(route, LDomain) of [] -> ejabberd_s2s:route(From, To, Packet); diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index 0c68c694c..c13d8beaa 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -283,7 +283,7 @@ do_route(From, To, Packet) -> ?DEBUG("sending to process ~p~n", [Pid]), NewPacket1 = exmpp_stanza:set_sender(Packet, From), NewPacket = exmpp_stanza:set_recipient(NewPacket1, To), - MyServer = exmpp_jid:ldomain(From), + MyServer = exmpp_jid:prep_domain(From), ejabberd_hooks:run( s2s_send_packet, MyServer, diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index d4fc78152..82eab82ce 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -406,7 +406,7 @@ stream_established({xmlstreamelement, El}, StateData) -> (Name == 'presence')) -> ejabberd_hooks:run( s2s_receive_packet, - exmpp_jid:ldomain(From), + exmpp_jid:prep_domain(From), [From, To, El]), ejabberd_router:route( From, To, El); @@ -426,7 +426,7 @@ stream_established({xmlstreamelement, El}, StateData) -> (Name == 'presence')) -> ejabberd_hooks:run( s2s_receive_packet, - exmpp_jid:ldomain(From), + exmpp_jid:prep_domain(From), [From, To, El]), ejabberd_router:route( From, To, El); diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index e786a4d4d..1fe22afae 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -231,7 +231,7 @@ stream_established({xmlstreamelement, El}, StateData) -> %% The default is the standard behaviour in XEP-0114 _ -> FromJID1 = exmpp_jid:parse(From), - Server = exmpp_jid:ldomain(FromJID1), + Server = exmpp_jid:prep_domain(FromJID1), case lists:member(Server, StateData#state.hosts) of true -> FromJID1; false -> error diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index b5c8270e9..b3b301887 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -112,7 +112,7 @@ route(From, To, Packet) -> open_session(SID, JID, Info) when ?IS_JID(JID) -> set_session(SID, JID, undefined, Info), check_for_sessions_to_replace(JID), - ejabberd_hooks:run(sm_register_connection_hook, exmpp_jid:ldomain(JID), + ejabberd_hooks:run(sm_register_connection_hook, exmpp_jid:prep_domain(JID), [SID, JID, Info]). close_session(SID, JID ) when ?IS_JID(JID)-> @@ -124,7 +124,7 @@ close_session(SID, JID ) when ?IS_JID(JID)-> mnesia:delete({session, SID}) end, mnesia:sync_dirty(F), - ejabberd_hooks:run(sm_remove_connection_hook, exmpp_jid:ldomain(JID), + ejabberd_hooks:run(sm_remove_connection_hook, exmpp_jid:prep_domain(JID), [SID, JID, Info]). check_in_subscription(Acc, User, Server, _JID, _Type, _Reason) @@ -160,7 +160,7 @@ get_user_resources(User, Server) get_user_ip(JID) when ?IS_JID(JID) -> USR = {exmpp_jid:lnode(JID), - exmpp_jid:ldomain(JID), + exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID)}, case mnesia:dirty_index_read(session, USR, #session.usr) of [] -> @@ -194,33 +194,33 @@ get_user_info(User, Server, Resource) set_presence(SID, JID, Priority, Presence, Info) when ?IS_JID(JID) -> set_session(SID, JID, Priority, Info), ejabberd_hooks:run(set_presence_hook, - exmpp_jid:ldomain(JID), + exmpp_jid:prep_domain(JID), [exmpp_jid:lnode(JID), - exmpp_jid:ldomain(JID), + exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID), Presence]). unset_presence(SID, JID, Status, Info) when ?IS_JID(JID)-> set_session(SID, JID, undefined, Info), ejabberd_hooks:run(unset_presence_hook, - exmpp_jid:ldomain(JID), + exmpp_jid:prep_domain(JID), [exmpp_jid:lnode(JID), - exmpp_jid:ldomain(JID), + exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID), Status]). close_session_unset_presence(SID, JID, Status) when ?IS_JID(JID) -> close_session(SID, JID), ejabberd_hooks:run(unset_presence_hook, - exmpp_jid:ldomain(JID), + exmpp_jid:prep_domain(JID), [exmpp_jid:lnode(JID), - exmpp_jid:ldomain(JID), + exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID), Status]). get_session_pid(JID) when ?IS_JID(JID) -> USR = {exmpp_jid:lnode(JID), - exmpp_jid:ldomain(JID), + exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID)}, case catch mnesia:dirty_index_read(session, USR, #session.usr) of [#session{sid = {_, Pid}}] -> Pid; @@ -385,9 +385,9 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- set_session(SID, JID, Priority, Info) -> - US = {exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID)}, + US = {exmpp_jid:lnode(JID), exmpp_jid:prep_domain(JID)}, USR = {exmpp_jid:lnode(JID), - exmpp_jid:ldomain(JID), + exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID)}, F = fun() -> mnesia:write(#session{sid = SID, @@ -427,40 +427,40 @@ do_route(From, To, Packet) -> {is_privacy_allow(From, To, Packet) andalso ejabberd_hooks:run_fold( roster_in_subscription, - exmpp_jid:ldomain(To), + exmpp_jid:prep_domain(To), false, - [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, subscribe, Reason]), + [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To), From, subscribe, Reason]), true}; 'subscribed' -> {is_privacy_allow(From, To, Packet) andalso ejabberd_hooks:run_fold( roster_in_subscription, - exmpp_jid:ldomain(To), + exmpp_jid:prep_domain(To), false, - [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, subscribed, <<>>]), + [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To), From, subscribed, <<>>]), true}; 'unsubscribe' -> {is_privacy_allow(From, To, Packet) andalso ejabberd_hooks:run_fold( roster_in_subscription, - exmpp_jid:ldomain(To), + exmpp_jid:prep_domain(To), false, - [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, unsubscribe, <<>>]), + [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To), From, unsubscribe, <<>>]), true}; 'unsubscribed' -> {is_privacy_allow(From, To, Packet) andalso ejabberd_hooks:run_fold( roster_in_subscription, - exmpp_jid:ldomain(To), + exmpp_jid:prep_domain(To), false, - [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From, unsubscribed, <<>>]), + [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To), From, unsubscribed, <<>>]), true}; _ -> {true, false} end, if Pass -> PResources = get_user_present_resources( - exmpp_jid:lnode(To), exmpp_jid:ldomain(To)), + exmpp_jid:lnode(To), exmpp_jid:prep_domain(To)), lists:foreach( fun({_, R}) -> do_route( @@ -482,13 +482,13 @@ do_route(From, To, Packet) -> exmpp_jid:full(To, R), Packet) end, get_user_resources(exmpp_jid:lnode(To), - exmpp_jid:ldomain(To))); + exmpp_jid:prep_domain(To))); _ -> ok end; _ -> USR = {exmpp_jid:lnode(To), - exmpp_jid:ldomain(To), + exmpp_jid:prep_domain(To), exmpp_jid:lresource(To)}, case mnesia:dirty_index_read(session, USR, #session.usr) of [] -> @@ -522,7 +522,7 @@ do_route(From, To, Packet) -> %% or if there are no current sessions for the user. is_privacy_allow(From, To, Packet) -> User = exmpp_jid:lnode(To), - Server = exmpp_jid:ldomain(To), + Server = exmpp_jid:prep_domain(To), PrivacyList = ejabberd_hooks:run_fold(privacy_get_user_list, Server, #userlist{}, [User, Server]), is_privacy_allow(From, To, Packet, PrivacyList). @@ -531,7 +531,7 @@ is_privacy_allow(From, To, Packet) -> %% Function copied from ejabberd_c2s.erl is_privacy_allow(From, To, Packet, PrivacyList) -> User = exmpp_jid:lnode(To), - Server = exmpp_jid:ldomain(To), + Server = exmpp_jid:prep_domain(To), allow == ejabberd_hooks:run_fold( privacy_check_packet, Server, allow, @@ -543,7 +543,7 @@ is_privacy_allow(From, To, Packet, PrivacyList) -> route_message(From, To, Packet) -> LUser = exmpp_jid:lnode(To), - LServer = exmpp_jid:ldomain(To), + LServer = exmpp_jid:prep_domain(To), PrioRes = get_user_present_resources(LUser, LServer), case catch lists:max(PrioRes) of {Priority, _R} when is_integer(Priority), Priority >= 0 -> @@ -579,7 +579,7 @@ route_message(From, To, Packet) -> exmpp_jid:ldomain_as_list(To)) of true -> ejabberd_hooks:run(offline_message_hook, - exmpp_jid:ldomain(To), + exmpp_jid:prep_domain(To), [From, To, Packet]); _ -> Err = exmpp_stanza:reply_with_error( @@ -636,7 +636,7 @@ check_for_sessions_to_replace(JID) -> check_existing_resources(JID) -> USR = {exmpp_jid:lnode(JID), - exmpp_jid:ldomain(JID), + exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID)}, %% A connection exist with the same resource. We replace it: SIDs = mnesia:dirty_select( @@ -659,7 +659,7 @@ check_max_sessions(JID) -> SIDs = mnesia:dirty_select( session, [{#session{sid = '$1', - us = {exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID)}, + us = {exmpp_jid:lnode(JID), exmpp_jid:prep_domain(JID)}, _ = '_'}, [], ['$1']}]), MaxSessions = get_max_user_sessions(JID), @@ -690,7 +690,7 @@ get_max_user_sessions(JID) -> process_iq(From, To, Packet) -> case exmpp_iq:xmlel_to_iq(Packet) of #iq{kind = request, ns = XMLNS} = IQ_Rec -> - LServer = exmpp_jid:ldomain(To), + LServer = exmpp_jid:prep_domain(To), case ets:lookup(sm_iqtable, {XMLNS, LServer}) of [{_, Module, Function}] -> ResIQ = Module:Function(From, To, IQ_Rec), diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl index aea38787a..0911e94b2 100644 --- a/src/ejabberd_system_monitor.erl +++ b/src/ejabberd_system_monitor.erl @@ -218,7 +218,7 @@ get_admin_jids() -> try JID = exmpp_jid:parse(S), [{exmpp_jid:lnode(JID), - exmpp_jid:ldomain(JID), + exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID)}] catch _ -> diff --git a/src/jlib.erl b/src/jlib.erl index d914bf73f..53941eee8 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -383,7 +383,7 @@ short_bare_jid(JID) -> short_prepd_jid(JID) -> {exmpp_jid:lnode(JID), - exmpp_jid:ldomain(JID), + exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID)}. short_prepd_bare_jid(JID) -> diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl index 19dfcd9d8..ab169d1b9 100644 --- a/src/mod_adhoc.erl +++ b/src/mod_adhoc.erl @@ -103,7 +103,7 @@ get_local_commands(Acc, _From, To, <<>>, Lang) -> end; get_local_commands(_Acc, From, To, ?NS_ADHOC_b, Lang) -> - ejabberd_hooks:run_fold(adhoc_local_items, exmpp_jid:ldomain(To), {result, []}, [From, To, Lang]); + ejabberd_hooks:run_fold(adhoc_local_items, exmpp_jid:prep_domain(To), {result, []}, [From, To, Lang]); get_local_commands(_Acc, _From, _To, <<"ping">>, _Lang) -> {result, []}; @@ -134,7 +134,7 @@ get_sm_commands(Acc, _From, To, <<>>, Lang) -> end; get_sm_commands(_Acc, From, To, ?NS_ADHOC_b, Lang) -> - ejabberd_hooks:run_fold(adhoc_sm_items, exmpp_jid:ldomain(To), {result, []}, [From, To, Lang]); + ejabberd_hooks:run_fold(adhoc_sm_items, exmpp_jid:prep_domain(To), {result, []}, [From, To, Lang]); get_sm_commands(Acc, _From, _To, _Node, _Lang) -> Acc. @@ -221,7 +221,7 @@ process_adhoc_request(From, To, IQ_Rec, Hook) -> {error, Error} -> exmpp_iq:error(IQ_Rec, Error); #adhoc_request{} = AdhocRequest -> - case ejabberd_hooks:run_fold(Hook, exmpp_jid:ldomain(To), empty, + case ejabberd_hooks:run_fold(Hook, exmpp_jid:prep_domain(To), empty, [From, To, AdhocRequest]) of ignore -> ignore; diff --git a/src/mod_announce.erl b/src/mod_announce.erl index abaef4b05..bdf702d39 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -702,7 +702,7 @@ announce_online(From, To, Packet) -> Err = exmpp_stanza:reply_with_error(Packet, 'forbidden'), ejabberd_router:route(To, From, Err); allow -> - announce_online1(ejabberd_sm:get_vh_session_list(exmpp_jid:ldomain(To)), + announce_online1(ejabberd_sm:get_vh_session_list(exmpp_jid:prep_domain(To)), exmpp_jid:domain_as_list(To), Packet) end. @@ -837,7 +837,7 @@ send_motd(JID) -> [#motd_users{}] -> ok; _ -> - Local = exmpp_jid:make(exmpp_jid:ldomain(JID)), + Local = exmpp_jid:make(exmpp_jid:prep_domain(JID)), ejabberd_router:route(Local, JID, Packet), F = fun() -> mnesia:write(#motd_users{us = US}) diff --git a/src/mod_caps.erl b/src/mod_caps.erl index b7d740379..67bc804ef 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -315,7 +315,7 @@ handle_cast({note_caps, From, %% lots of caps disco requests. %#jid{node = U, domain = S, resource = R} = From, U = exmpp_jid:lnode(From), - S = exmpp_jid:ldomain(From), + S = exmpp_jid:prep_domain(From), R = exmpp_jid:resource(From), BJID = exmpp_jid:jid_to_binary(From), mnesia:transaction(fun() -> diff --git a/src/mod_configure.erl b/src/mod_configure.erl index b33c6366f..83cb1df83 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -299,7 +299,7 @@ get_sm_items(Acc, From, To, Node, Lang) -> get_user_resources(BareJID) -> Rs = ejabberd_sm:get_user_resources(exmpp_jid:lnode(BareJID), - exmpp_jid:ldomain(BareJID)), + exmpp_jid:prep_domain(BareJID)), lists:map(fun(R) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', @@ -1641,7 +1641,7 @@ set_form(From, Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> %% TODO: Update time format to XEP-0202: Entity Time FLast = case ejabberd_sm:get_user_resources(exmpp_jid:lnode(User), - exmpp_jid:ldomain(Server)) of + exmpp_jid:prep_domain(Server)) of [] -> _US = {User, Server}, case get_last_info(User, Server) of @@ -1676,13 +1676,13 @@ set_form(From, Host, ?NS_ADMINL("user-stats"), Lang, XData) -> true = (Server == Host) orelse (get_permission_level(From) == global), Resources = ejabberd_sm:get_user_resources(exmpp_jid:lnode(JID), - exmpp_jid:ldomain(JID)), + exmpp_jid:prep_domain(JID)), IPs1 = [ejabberd_sm:get_user_ip(exmpp_jid:full(JID,Resource)) || Resource <- Resources], IPs = [inet_parse:ntoa(IP)++":"++integer_to_list(Port) || {IP, Port} <- IPs1], Items = ejabberd_hooks:run_fold(roster_get, - exmpp_jid:ldomain(JID), + exmpp_jid:prep_domain(JID), [], [{list_to_binary(User), list_to_binary(Server)}]), Rostersize = integer_to_list(erlang:length(Items)), diff --git a/src/mod_disco.erl b/src/mod_disco.erl index a75b173f4..13288a01a 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -133,7 +133,7 @@ process_local_iq_items(From, To, #iq{type = get, payload = SubEl, Node = exmpp_xml:get_attribute_as_binary(SubEl, 'node', <<>>), case ejabberd_hooks:run_fold(disco_local_items, - exmpp_jid:ldomain(To), + exmpp_jid:prep_domain(To), empty, [From, To, Node, Lang]) of {result, Items} -> @@ -155,11 +155,11 @@ process_local_iq_info(From, To, #iq{type = get, payload = SubEl, lang = Lang} = IQ_Rec) -> Node = exmpp_xml:get_attribute_as_binary(SubEl, 'node', <<>>), Identity = ejabberd_hooks:run_fold(disco_local_identity, - exmpp_jid:ldomain(To), + exmpp_jid:prep_domain(To), [], [From, To, Node, Lang]), case ejabberd_hooks:run_fold(disco_local_features, - exmpp_jid:ldomain(To), + exmpp_jid:prep_domain(To), empty, [From, To, Node, Lang]) of {result, Features} -> @@ -274,7 +274,7 @@ process_sm_iq_items(From, To, #iq{type = get, payload = SubEl, lang = Lang} = IQ_Rec) -> Node = exmpp_xml:get_attribute_as_binary(SubEl, 'node', <<>>), case ejabberd_hooks:run_fold(disco_sm_items, - exmpp_jid:ldomain(To), + exmpp_jid:prep_domain(To), empty, [From, To, Node, Lang]) of {result, Items} -> @@ -348,11 +348,11 @@ process_sm_iq_info(From, To, #iq{type = get, payload = SubEl, lang = Lang} = IQ_Rec) -> Node = exmpp_xml:get_attribute_as_binary(SubEl, 'node', <<>>), Identity = ejabberd_hooks:run_fold(disco_sm_identity, - exmpp_jid:ldomain(To), + exmpp_jid:prep_domain(To), [], [From, To, Node, Lang]), case ejabberd_hooks:run_fold(disco_sm_features, - exmpp_jid:ldomain(To), + exmpp_jid:prep_domain(To), empty, [From, To, Node, Lang]) of {result, Features} -> @@ -393,7 +393,7 @@ get_sm_features(Acc, _From, _To, _Node, _Lang) -> get_user_resources(JID) -> Rs = ejabberd_sm:get_user_resources(exmpp_jid:lnode(JID), - exmpp_jid:ldomain(JID)), + exmpp_jid:prep_domain(JID)), lists:map(fun(R) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [ ?XMLATTR('jid', diff --git a/src/mod_last.erl b/src/mod_last.erl index 321ef8327..5f8cb4d08 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -105,23 +105,23 @@ now_to_seconds({MegaSecs, Secs, _MicroSecs}) -> process_sm_iq(From, To, #iq{type = get} = IQ_Rec) -> {Subscription, _Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, exmpp_jid:ldomain(To), - {none, []}, [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From]), + roster_get_jid_info, exmpp_jid:prep_domain(To), + {none, []}, [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To), From]), if (Subscription == both) or (Subscription == from) -> UserListRecord = ejabberd_hooks:run_fold( - privacy_get_user_list, exmpp_jid:ldomain(To), + privacy_get_user_list, exmpp_jid:prep_domain(To), #userlist{}, - [exmpp_jid:lnode(To), exmpp_jid:ldomain(To)]), + [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To)]), case ejabberd_hooks:run_fold( - privacy_check_packet, exmpp_jid:ldomain(To), + privacy_check_packet, exmpp_jid:prep_domain(To), allow, - [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), UserListRecord, + [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To), UserListRecord, {From, To, exmpp_presence:available()}, out]) of allow -> - get_last(IQ_Rec, exmpp_jid:lnode(To), exmpp_jid:ldomain(To)); + get_last(IQ_Rec, exmpp_jid:lnode(To), exmpp_jid:prep_domain(To)); deny -> exmpp_iq:error(IQ_Rec, 'not-allowed') end; diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 961a20329..09943751e 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -99,18 +99,18 @@ process_sm_iq(From, To, #iq{type = get} = IQ_Rec) -> Server = exmpp_jid:ldomain_as_list(To), {Subscription, _Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, exmpp_jid:ldomain(To), - {none, []}, [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), From]), + roster_get_jid_info, exmpp_jid:prep_domain(To), + {none, []}, [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To), From]), if (Subscription == both) or (Subscription == from) -> UserListRecord = ejabberd_hooks:run_fold( - privacy_get_user_list, exmpp_jid:ldomain(To), + privacy_get_user_list, exmpp_jid:prep_domain(To), #userlist{}, - [exmpp_jid:lnode(To), exmpp_jid:ldomain(To)]), + [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To)]), case ejabberd_hooks:run_fold( - privacy_check_packet, exmpp_jid:ldomain(To), + privacy_check_packet, exmpp_jid:prep_domain(To), allow, - [exmpp_jid:lnode(To), exmpp_jid:ldomain(To), UserListRecord, + [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To), UserListRecord, {From, To, exmpp_presence:available()}, out]) of diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index 69d6fce1a..624c771df 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -146,7 +146,7 @@ process_iq_disco_items(Host, From, To, #iq{lang = Lang} = IQ) when is_binary(Hos can_use_nick(_Host, _JID, <<>>) -> false; can_use_nick(Host, JID, Nick) when is_binary(Host), is_binary(Nick) -> - LUS = {exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID)}, + LUS = {exmpp_jid:lnode(JID), exmpp_jid:prep_domain(JID)}, case catch mnesia:dirty_select( muc_registered, [{#muc_registered{us_host = '$1', @@ -662,7 +662,7 @@ flush() -> iq_get_register_info(Host, From, Lang) -> LUser = exmpp_jid:lnode(From), - LServer = exmpp_jid:ldomain(From), + LServer = exmpp_jid:prep_domain(From), LUS = {LUser, LServer}, {Nick, Registered} = case catch mnesia:dirty_read(muc_registered, {LUS, Host}) of @@ -692,7 +692,7 @@ iq_get_register_info(Host, From, Lang) -> iq_set_register_info(Host, From, Nick, Lang) when is_binary(Host), is_binary(Nick) -> LUser = exmpp_jid:lnode(From), - LServer = exmpp_jid:ldomain(From), + LServer = exmpp_jid:prep_domain(From), LUS = {LUser, LServer}, F = fun() -> case Nick of diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index c9c69d078..d64b78930 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -3495,7 +3495,7 @@ add_to_log(Type, Data, StateData) -> tab_add_online_user(JID, StateData) -> LUser = exmpp_jid:lnode(JID), - LServer = exmpp_jid:ldomain(JID), + LServer = exmpp_jid:prep_domain(JID), US = {LUser, LServer}, Room = StateData#state.room, Host = StateData#state.host, @@ -3507,7 +3507,7 @@ tab_add_online_user(JID, StateData) -> tab_remove_online_user(JID, StateData) when ?IS_JID(JID) -> LUser = exmpp_jid:lnode(JID), - LServer = exmpp_jid:ldomain(JID), + LServer = exmpp_jid:prep_domain(JID), tab_remove_online_user({LUser, LServer, none},StateData); tab_remove_online_user({LUser, LServer,_}, StateData) -> @@ -3520,7 +3520,7 @@ tab_remove_online_user({LUser, LServer,_}, StateData) -> tab_count_user(JID) -> LUser = exmpp_jid:lnode(JID), - LServer = exmpp_jid:ldomain(JID), + LServer = exmpp_jid:prep_domain(JID), US = {LUser, LServer}, case catch ets:select( muc_online_users, diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 7fbc8443b..3989bba39 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -661,7 +661,7 @@ is_type_match(Type, Value, JID, Subscription, Groups) -> jid -> {User, Server, Resource} = Value, ((User == undefined) orelse (User == []) orelse (User == exmpp_jid:lnode(JID))) - andalso ((Server == undefined) orelse (Server == []) orelse (Server == exmpp_jid:ldomain(JID))) + andalso ((Server == undefined) orelse (Server == []) orelse (Server == exmpp_jid:prep_domain(JID))) andalso ((Resource == undefined) orelse (Resource == []) orelse (Resource == exmpp_jid:lresource(JID))); subscription -> Value == Subscription; diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index b94b1a649..42f96157a 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -660,7 +660,7 @@ is_type_match(Type, Value, JID, Subscription, Groups) -> jid -> {User, Server, Resource} = Value, ((User == undefined) orelse (User == []) orelse (User == exmpp_jid:lnode(JID))) - andalso ((Server == undefined) orelse (Server == []) orelse (Server == exmpp_jid:ldomain(JID))) + andalso ((Server == undefined) orelse (Server == []) orelse (Server == exmpp_jid:prep_domain(JID))) andalso ((Resource == undefined) orelse (Resource == []) orelse (Resource == exmpp_jid:lresource(JID))); subscription -> Value == Subscription; diff --git a/src/mod_private.erl b/src/mod_private.erl index 7edf4d433..313a312f0 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -74,7 +74,7 @@ process_sm_iq(From, To, #iq{type = Type} = IQ_Rec) -> process_iq_get(From, _To, #iq{payload = SubEl} = IQ_Rec) -> LUser = exmpp_jid:lnode(From), - LServer = exmpp_jid:ldomain(From), + LServer = exmpp_jid:prep_domain(From), case catch get_data(LUser, LServer, exmpp_xml:get_child_elements(SubEl)) of @@ -89,7 +89,7 @@ process_iq_get(From, _To, #iq{payload = SubEl} = IQ_Rec) -> process_iq_set(From, _To, #iq{payload = SubEl} = IQ_Rec) -> LUser = exmpp_jid:lnode(From), - LServer = exmpp_jid:ldomain(From), + LServer = exmpp_jid:prep_domain(From), F = fun() -> lists:foreach( fun(El) -> diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 6b5559bcb..a817bbad9 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -163,8 +163,8 @@ process_local_iq(From, To, #iq{type = set} = IQ_Rec) %% IQ_Result = exmpp_iq:iq() process_iq_get(From, To, IQ_Rec) -> - US = {exmpp_jid:lnode(From), exmpp_jid:ldomain(From)}, - case catch ejabberd_hooks:run_fold(roster_get, exmpp_jid:ldomain(To), [], [US]) of + US = {exmpp_jid:lnode(From), exmpp_jid:prep_domain(From)}, + case catch ejabberd_hooks:run_fold(roster_get, exmpp_jid:prep_domain(To), [], [US]) of Items when is_list(Items) -> XItems = lists:map(fun item_to_xml/1, Items), Result = #xmlel{ns = ?NS_ROSTER, name = 'query', @@ -251,7 +251,7 @@ process_item_set(From, To, #xmlel{} = El) -> JID1 = exmpp_jid:parse(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), User = exmpp_jid:node(From), LUser = exmpp_jid:lnode(From), - LServer = exmpp_jid:ldomain(From), + LServer = exmpp_jid:prep_domain(From), JID = jlib:short_jid(JID1), LJID = jlib:short_prepd_jid(JID1), F = fun() -> @@ -279,7 +279,7 @@ process_item_set(From, To, #xmlel{} = El) -> %% If the item exist in shared roster, take the %% subscription information from there: Item3 = ejabberd_hooks:run_fold(roster_process_item, - exmpp_jid:ldomain(From), Item2, [exmpp_jid:ldomain(From)]), + exmpp_jid:prep_domain(From), Item2, [exmpp_jid:prep_domain(From)]), {Item, Item3} end, case mnesia:transaction(F) of @@ -844,7 +844,7 @@ process_item_attrs_ws(Item, []) -> get_in_pending_subscriptions(Ls, User, Server) when is_binary(User), is_binary(Server) -> JID = exmpp_jid:make(User, Server), - US = {exmpp_jid:lnode(JID), exmpp_jid:ldomain(JID)}, + US = {exmpp_jid:lnode(JID), exmpp_jid:prep_domain(JID)}, case mnesia:dirty_index_read(roster, US, #roster.us) of Result when is_list(Result) -> Ls ++ lists:map( @@ -1185,7 +1185,7 @@ user_roster(User, Server, Query, Lang) -> build_contact_jid_td({U, S, R}) -> %% Convert {U, S, R} into {jid, U, S, R, U, S, R}: ContactJID = exmpp_jid:make(U, S, R), - JIDURI = case {exmpp_jid:lnode(ContactJID), exmpp_jid:ldomain(ContactJID)} of + JIDURI = case {exmpp_jid:lnode(ContactJID), exmpp_jid:prep_domain(ContactJID)} of {undefined, _} -> ""; {CUser, CServer} -> CUser_S = binary_to_list(CUser), diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 4024aae2c..65666206d 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -119,8 +119,8 @@ process_local_iq(From, To, #iq{type = set} = IQ_Rec) -> process_iq_get(From, To, IQ_Rec) -> - US = {exmpp_jid:lnode(From), exmpp_jid:ldomain(From)}, - case catch ejabberd_hooks:run_fold(roster_get, exmpp_jid:ldomain(To), [], [US]) of + US = {exmpp_jid:lnode(From), exmpp_jid:prep_domain(From)}, + case catch ejabberd_hooks:run_fold(roster_get, exmpp_jid:prep_domain(To), [], [US]) of Items when is_list(Items) -> XItems = lists:map(fun item_to_xml/1, Items), Result = #xmlel{ns = ?NS_ROSTER, name = 'query', @@ -218,7 +218,7 @@ process_item_set(From, To, #xmlel{} = El) -> try JID1 = exmpp_jid:parse(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), User = exmpp_jid:lnode(From), - Server = exmpp_jid:ldomain(From), + Server = exmpp_jid:prep_domain(From), LServer = binary_to_list(Server), {U0, S0, R0} = LJID = jlib:short_prepd_jid(JID1), Username = ejabberd_odbc:escape(User), @@ -234,7 +234,7 @@ process_item_set(From, To, #xmlel{} = El) -> us = {User, Server}, jid = LJID}; [I] -> - R = raw_to_record(exmpp_jid:ldomain(From), I), + R = raw_to_record(exmpp_jid:prep_domain(From), I), case R of %% Bad JID in database: error -> @@ -263,12 +263,12 @@ process_item_set(From, To, #xmlel{} = El) -> %% If the item exist in shared roster, take the %% subscription information from there: Item3 = ejabberd_hooks:run_fold(roster_process_item, - exmpp_jid:ldomain(From), Item2, [exmpp_jid:ldomain(From)]), + exmpp_jid:prep_domain(From), Item2, [exmpp_jid:prep_domain(From)]), {Item, Item3} end, case odbc_queries:sql_transaction(LServer, F) of {atomic, {OldItem, Item}} -> - push_item(exmpp_jid:node(From), exmpp_jid:ldomain(From), To, Item), + push_item(exmpp_jid:node(From), exmpp_jid:prep_domain(From), To, Item), case Item#roster.subscription of remove -> IsTo = case OldItem#roster.subscription of @@ -774,7 +774,7 @@ get_in_pending_subscriptions(Ls, User, Server) end, lists:flatmap( fun(I) -> - case raw_to_record(exmpp_jid:ldomain(JID), I) of + case raw_to_record(exmpp_jid:prep_domain(JID), I) of %% Bad JID in database: error -> []; @@ -1020,7 +1020,7 @@ user_roster(User, Server, Query, Lang) -> build_contact_jid_td({U, S, R}) -> %% Convert {U, S, R} into {jid, U, S, R, U, S, R}: ContactJID = exmpp_jid:make(U, S, R), - JIDURI = case {exmpp_jid:lnode(ContactJID), exmpp_jid:ldomain(ContactJID)} of + JIDURI = case {exmpp_jid:lnode(ContactJID), exmpp_jid:prep_domain(ContactJID)} of {undefined, _} -> ""; {CUser, CServer} -> CUser_S = binary_to_list(CUser), From 7eb395b87d2db8c1666abf752b5a8baab0300dad Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 16:38:28 +0000 Subject: [PATCH 336/582] API renaming : ldomain_as_list -> prep_domain_as_list SVN Revision: 2124 --- src/acl.erl | 2 +- src/ejabberd_router.erl | 2 +- src/ejabberd_s2s.erl | 8 +++---- src/ejabberd_s2s_in.erl | 10 ++++----- src/ejabberd_sm.erl | 4 ++-- src/mod_adhoc.erl | 4 ++-- src/mod_announce.erl | 32 +++++++++++++-------------- src/mod_caps.erl | 6 ++--- src/mod_configure.erl | 34 ++++++++++++++--------------- src/mod_configure2.erl | 2 +- src/mod_disco.erl | 24 ++++++++++---------- src/mod_irc/mod_irc.erl | 6 ++--- src/mod_last_odbc.erl | 2 +- src/mod_offline.erl | 2 +- src/mod_offline_odbc.erl | 2 +- src/mod_privacy.erl | 4 ++-- src/mod_privacy_odbc.erl | 4 ++-- src/mod_private.erl | 2 +- src/mod_private_odbc.erl | 6 ++--- src/mod_pubsub/mod_pubsub.erl | 22 +++++++++---------- src/mod_pubsub/nodetree_virtual.erl | 2 +- src/mod_register.erl | 14 ++++++------ src/mod_roster.erl | 2 +- src/mod_roster_odbc.erl | 4 ++-- src/mod_service_log.erl | 4 ++-- src/mod_shared_roster.erl | 2 +- src/mod_vcard.erl | 4 ++-- src/mod_vcard_ldap.erl | 2 +- src/mod_vcard_odbc.erl | 4 ++-- src/web/ejabberd_web_admin.erl | 6 ++--- 30 files changed, 111 insertions(+), 111 deletions(-) diff --git a/src/acl.erl b/src/acl.erl index 976d70a84..08061ab67 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -232,7 +232,7 @@ match_acl(ACLName, JID, Host) -> none -> false; _ -> User = exmpp_jid:lnode_as_list(JID), - Server = exmpp_jid:ldomain_as_list(JID), + Server = exmpp_jid:prep_domain_as_list(JID), Resource = exmpp_jid:lresource_as_list(JID), lists:any(fun(#acl{aclspec = Spec}) -> case Spec of diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index 5f60932b7..696a55970 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -352,7 +352,7 @@ do_route(OrigFrom, OrigTo, OrigPacket) -> drop end; Rs -> - LDstDomain = exmpp_jid:ldomain_as_list(To), + LDstDomain = exmpp_jid:prep_domain_as_list(To), Value = case ejabberd_config:get_local_option( {domain_balancing, LDstDomain}) of undefined -> now(); diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl index c13d8beaa..33af46f76 100644 --- a/src/ejabberd_s2s.erl +++ b/src/ejabberd_s2s.erl @@ -303,8 +303,8 @@ do_route(From, To, Packet) -> end. find_connection(From, To) -> - MyServer = exmpp_jid:ldomain_as_list(From), - Server = exmpp_jid:ldomain_as_list(To), + MyServer = exmpp_jid:prep_domain_as_list(From), + Server = exmpp_jid:prep_domain_as_list(To), FromTo = {MyServer, Server}, MaxS2SConnectionsNumber = max_s2s_connections_number(FromTo), MaxS2SConnectionsNumberPerNode = @@ -432,12 +432,12 @@ needed_connections_number(Ls, MaxS2SConnectionsNumber, %% service. %% -------------------------------------------------------------------- is_service(From, To) -> - LFromDomain = exmpp_jid:ldomain_as_list(From), + LFromDomain = exmpp_jid:prep_domain_as_list(From), case ejabberd_config:get_local_option({route_subdomains, LFromDomain}) of s2s -> % bypass RFC 3920 10.3 false; _ -> - LDstDomain = exmpp_jid:ldomain_as_list(To), + LDstDomain = exmpp_jid:prep_domain_as_list(To), P = fun(Domain) -> is_subdomain(LDstDomain, Domain) end, lists:any(P, ?MYHOSTS) end. diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 82eab82ce..f1e3bff37 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -390,8 +390,8 @@ stream_established({xmlstreamelement, El}, StateData) -> % This is handled by C2S and S2S send_element functions. if (To /= error) and (From /= error) -> - LFrom = exmpp_jid:ldomain_as_list(From), - LTo = exmpp_jid:ldomain_as_list(To), + LFrom = exmpp_jid:prep_domain_as_list(From), + LTo = exmpp_jid:prep_domain_as_list(To), if StateData#state.authenticated -> case (LFrom == StateData#state.auth_domain) @@ -643,7 +643,7 @@ get_cert_domains(Cert) -> D /= error -> JID = exmpp_jid:parse(D), case {exmpp_jid:lnode_as_list(JID), - exmpp_jid:ldomain_as_list(JID), + exmpp_jid:prep_domain_as_list(JID), exmpp_jid:lresource_as_list(JID)} of {undefined, LD, undefined} -> [LD]; @@ -679,7 +679,7 @@ get_cert_domains(Cert) -> {ok, D} when is_binary(D) -> JID2 = exmpp_jid:parse(binary_to_list(D)), case {exmpp_jid:lnode_as_list(JID2), - exmpp_jid:ldomain_as_list(JID2), + exmpp_jid:prep_domain_as_list(JID2), exmpp_jid:lresource_as_list(JID2)} of { undefined, LD, undefined} -> case idna:domain_utf8_to_ascii(LD) of @@ -697,7 +697,7 @@ get_cert_domains(Cert) -> ({dNSName, D}) when is_list(D) -> JID3 = exmpp_jid:parse(D), case {exmpp_jid:lnode_as_list(JID3), - exmpp_jid:ldomain_as_list(JID3), + exmpp_jid:prep_domain_as_list(JID3), exmpp_jid:lresource_as_list(JID3)} of {undefined, LD, undefined} -> [LD]; diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index b3b301887..eb71b2416 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -576,7 +576,7 @@ route_message(From, To, Packet) -> bounce_offline_message(From, To, Packet); _ -> case ejabberd_auth:is_user_exists(exmpp_jid:lnode_as_list(To), - exmpp_jid:ldomain_as_list(To)) of + exmpp_jid:prep_domain_as_list(To)) of true -> ejabberd_hooks:run(offline_message_hook, exmpp_jid:prep_domain(To), @@ -678,7 +678,7 @@ check_max_sessions(JID) -> %% Defaults to infinity get_max_user_sessions(JID) -> case acl:match_rule( - exmpp_jid:ldomain_as_list(JID), max_user_sessions, exmpp_jid:bare(JID)) of + exmpp_jid:prep_domain_as_list(JID), max_user_sessions, exmpp_jid:bare(JID)) of Max when is_integer(Max) -> Max; infinity -> infinity; _ -> ?MAX_USER_SESSIONS diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl index ab169d1b9..d71f5b2d9 100644 --- a/src/mod_adhoc.erl +++ b/src/mod_adhoc.erl @@ -83,7 +83,7 @@ stop(Host) -> get_local_commands(Acc, _From, To, <<>>, Lang) -> Server = exmpp_jid:domain(To), - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), Display = gen_mod:get_module_opt(LServer, ?MODULE, report_commands_node, false), case Display of false -> @@ -114,7 +114,7 @@ get_local_commands(Acc, _From, _To, _Node, _Lang) -> %------------------------------------------------------------------------- get_sm_commands(Acc, _From, To, <<>>, Lang) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), Display = gen_mod:get_module_opt(LServer, ?MODULE, report_commands_node, false), case Display of false -> diff --git a/src/mod_announce.erl b/src/mod_announce.erl index bdf702d39..0b0d649fb 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -136,7 +136,7 @@ announce(From, To, Packet) -> case {exmpp_jid:lnode(To), exmpp_jid:lresource(To)} of {undefined, Res} -> Name = Packet#xmlel.name, - Proc = gen_mod:get_module_proc(exmpp_jid:ldomain_as_list(To), ?PROCNAME), + Proc = gen_mod:get_module_proc(exmpp_jid:prep_domain_as_list(To), ?PROCNAME), case {Res, Name} of {<<"announce/all">>, 'message'} -> Proc ! {announce_all, From, To, Packet}, @@ -221,7 +221,7 @@ disco_identity(Acc, _From, _To, Node, Lang) -> end). disco_features(Acc, From, To, <<"announce">>, _Lang) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -238,7 +238,7 @@ disco_features(Acc, From, To, <<"announce">>, _Lang) -> end; disco_features(Acc, From, To, Node, _Lang) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -290,7 +290,7 @@ disco_features(Acc, From, To, Node, _Lang) -> end). disco_items(Acc, From, To, <<>>, Lang) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), Server = exmpp_jid:domain(To), case gen_mod:is_loaded(LServer, mod_adhoc) of @@ -314,7 +314,7 @@ disco_items(Acc, From, To, <<>>, Lang) -> end; disco_items(Acc, From, To, <<"announce">>, Lang) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -323,7 +323,7 @@ disco_items(Acc, From, To, <<"announce">>, Lang) -> end; disco_items(Acc, From, To, Node, _Lang) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -361,7 +361,7 @@ disco_items(Acc, From, To, Node, _Lang) -> %%------------------------------------------------------------------------- announce_items(Acc, From, To, Lang) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), Server = exmpp_jid:domain(To), Access1 = gen_mod:get_module_opt(LServer, ?MODULE, access, none), Nodes1 = case acl:match_rule(LServer, Access1, From) of @@ -408,7 +408,7 @@ commands_result(Allow, From, To, Request) -> announce_commands(Acc, From, To, #adhoc_request{ node = Node} = Request) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), LNode = tokenize(Node), F = fun() -> Access = gen_mod:get_module_opt(global, ?MODULE, access, none), @@ -463,7 +463,7 @@ announce_commands(From, To, #adhoc_response{status = canceled}); XData == false, ActionIsExecute -> %% User requests form - Elements = generate_adhoc_form(Lang, Node, exmpp_jid:ldomain_as_list(To)), + Elements = generate_adhoc_form(Lang, Node, exmpp_jid:prep_domain_as_list(To)), adhoc:produce_response( Request, #adhoc_response{status = executing, @@ -542,7 +542,7 @@ handle_adhoc_form(From, To, node = Node, sessionid = SessionID}, Fields) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), Confirm = case lists:keysearch("confirm", 1, Fields) of {value, {"confirm", ["true"]}} -> true; @@ -664,7 +664,7 @@ get_title(Lang, <<?NS_ADMIN_s , "#delete-motd-allhosts">>) -> %%------------------------------------------------------------------------- announce_all(From, To, Packet) -> - Host = exmpp_jid:ldomain_as_list(To), + Host = exmpp_jid:prep_domain_as_list(To), Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), case acl:match_rule(Host, Access, From) of deny -> @@ -695,7 +695,7 @@ announce_all_hosts_all(From, To, Packet) -> end. announce_online(From, To, Packet) -> - Host = exmpp_jid:ldomain_as_list(To), + Host = exmpp_jid:prep_domain_as_list(To), Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), case acl:match_rule(Host, Access, From) of deny -> @@ -728,7 +728,7 @@ announce_online1(Sessions, Server, Packet) -> end, Sessions). announce_motd(From, To, Packet) -> - Host = exmpp_jid:ldomain_as_list(To), + Host = exmpp_jid:prep_domain_as_list(To), Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), case acl:match_rule(Host, Access, From) of deny -> @@ -762,7 +762,7 @@ announce_motd(Host, Packet) -> mnesia:transaction(F). announce_motd_update(From, To, Packet) -> - Host = exmpp_jid:ldomain_as_list(To), + Host = exmpp_jid:prep_domain_as_list(To), Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), case acl:match_rule(Host, Access, From) of deny -> @@ -791,7 +791,7 @@ announce_motd_update(LServer, Packet) -> mnesia:transaction(F). announce_motd_delete(From, To, Packet) -> - Host = exmpp_jid:ldomain_as_list(To), + Host = exmpp_jid:prep_domain_as_list(To), Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), case acl:match_rule(Host, Access, From) of deny -> @@ -828,7 +828,7 @@ announce_motd_delete(LServer) -> mnesia:transaction(F). send_motd(JID) -> - LServer = exmpp_jid:ldomain_as_list(JID), + LServer = exmpp_jid:prep_domain_as_list(JID), LUser = exmpp_jid:lnode_as_list(JID), case catch mnesia:dirty_read({motd, LServer}) of [#motd{packet = Packet}] -> diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 67bc804ef..576f1f21e 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -218,7 +218,7 @@ receive_packet(From, To, Packet) when ?IS_PRESENCE(Packet) -> %% anymore until he login again. %% This is tracked in EJAB-943 _ -> - ServerString = exmpp_jid:ldomain_as_list(To), + ServerString = exmpp_jid:prep_domain_as_list(To), Els = Packet#xmlel.children, note_caps(ServerString, From, read_caps(Els)) end; @@ -229,7 +229,7 @@ receive_packet(_JID, From, To, Packet) -> receive_packet(From, To, Packet). presence_probe(From, To, _) -> - ServerString = exmpp_jid:ldomain_as_list(To), + ServerString = exmpp_jid:prep_domain_as_list(To), wait_caps(ServerString, From). remove_connection(_SID, JID, _Info) -> @@ -424,7 +424,7 @@ handle_cast(visit_feature_queries, #state{feature_queries = FeatureQueries} = St {noreply, State#state{feature_queries = NewFeatureQueries}}. handle_disco_response(From, To, IQ_Rec) -> - Host = exmpp_jid:ldomain_as_list(To), + Host = exmpp_jid:prep_domain_as_list(To), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), gen_server:cast(Proc, {disco_response, From, To, IQ_Rec}). diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 83cb1df83..18841b916 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -184,7 +184,7 @@ get_local_identity(Acc, _From, _To, Node, Lang) -> end). get_sm_features(Acc, From, To, Node, _Lang) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -199,7 +199,7 @@ get_sm_features(Acc, From, To, Node, _Lang) -> end. get_local_features(Acc, From, To, Node, _Lang) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -255,7 +255,7 @@ get_local_features(Acc, From, To, Node, _Lang) -> %%%----------------------------------------------------------------------- adhoc_sm_items(Acc, From, To, Lang) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), case acl:match_rule(LServer, configure, From) of allow -> Items = case Acc of @@ -274,7 +274,7 @@ adhoc_sm_items(Acc, From, To, Lang) -> %%%----------------------------------------------------------------------- get_sm_items(Acc, From, To, Node, Lang) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -312,7 +312,7 @@ get_user_resources(BareJID) -> %%%----------------------------------------------------------------------- adhoc_local_items(Acc, From, To, Lang) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), case acl:match_rule(LServer, configure, From) of allow -> Items = case Acc of @@ -391,7 +391,7 @@ get_permission_level(JID) -> end). get_local_items(Acc, From, To, <<>>, Lang) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -417,7 +417,7 @@ get_local_items(Acc, From, To, <<>>, Lang) -> end; get_local_items(Acc, From, To, Node, Lang) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -744,7 +744,7 @@ get_stopped_nodes(_Lang) -> end). adhoc_local_commands(Acc, From, To, #adhoc_request{node = Node} = Request) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), LNode = tokenize(Node), case LNode of ["running nodes", _ENode, "DB"] -> @@ -773,7 +773,7 @@ adhoc_local_commands(From, To, sessionid = SessionID, action = Action, xdata = XData} = Request) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), LNode = tokenize(Node), %% If the "action" attribute is not present, it is %% understood as "execute". If there was no <actions/> @@ -1564,7 +1564,7 @@ set_form(From, Host, ?NS_ADMINL("add-user"), _Lang, XData) -> Password = get_value("password-verify", XData), AccountJID = exmpp_jid:parse(AccountString), User = exmpp_jid:lnode_as_list(AccountJID), - Server = exmpp_jid:ldomain_as_list(AccountJID), + Server = exmpp_jid:prep_domain_as_list(AccountJID), true = lists:member(Server, ?MYHOSTS), true = (Server == Host) orelse (get_permission_level(From) == global), ejabberd_auth:try_register(User, Server, Password), @@ -1577,7 +1577,7 @@ set_form(From, Host, ?NS_ADMINL("delete-user"), _Lang, XData) -> fun(AccountString) -> JID = exmpp_jid:parse(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), - Server = exmpp_jid:ldomain_as_list(JID), + Server = exmpp_jid:prep_domain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), true = ejabberd_auth:is_user_exists(User, Server), {User, Server} @@ -1590,7 +1590,7 @@ set_form(From, Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> AccountString = get_value("accountjid", XData), JID = exmpp_jid:parse(AccountString), LUser = [_|_] = exmpp_jid:lnode_as_list(JID), - LServer = exmpp_jid:ldomain_as_list(JID), + LServer = exmpp_jid:prep_domain_as_list(JID), true = (LServer == Host) orelse (get_permission_level(From) == global), %% Code copied from ejabberd_sm.erl case exmpp_jid:lresource_as_list(JID) of @@ -1609,7 +1609,7 @@ set_form(From, Host, ?NS_ADMINL("get-user-password"), Lang, XData) -> AccountString = get_value("accountjid", XData), JID = exmpp_jid:parse(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), - Server = exmpp_jid:ldomain_as_list(JID), + Server = exmpp_jid:prep_domain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), Password = ejabberd_auth:get_password(User, Server), true = is_list(Password), @@ -1624,7 +1624,7 @@ set_form(From, Host, ?NS_ADMINL("change-user-password"), _Lang, XData) -> Password = get_value("password", XData), JID = exmpp_jid:parse(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), - Server = exmpp_jid:ldomain_as_list(JID), + Server = exmpp_jid:prep_domain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), true = ejabberd_auth:is_user_exists(User, Server), ejabberd_auth:set_password(User, Server, Password), @@ -1634,7 +1634,7 @@ set_form(From, Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> AccountString = get_value("accountjid", XData), JID = exmpp_jid:parse(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), - Server = exmpp_jid:ldomain_as_list(JID), + Server = exmpp_jid:prep_domain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), %% Code copied from web/ejabberd_web_admin.erl @@ -1672,7 +1672,7 @@ set_form(From, Host, ?NS_ADMINL("user-stats"), Lang, XData) -> AccountString = get_value("accountjid", XData), JID = exmpp_jid:parse(AccountString), User = [_|_] = exmpp_jid:lnode_as_list(JID), - Server = exmpp_jid:ldomain_as_list(JID), + Server = exmpp_jid:prep_domain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), Resources = ejabberd_sm:get_user_resources(exmpp_jid:lnode(JID), @@ -1771,7 +1771,7 @@ adhoc_sm_commands(_Acc, From, To, xdata = XData} = Request) -> User = exmpp_jid:node_as_list(To), Server = exmpp_jid:domain_as_list(To), - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), case acl:match_rule(LServer, configure, From) of deny -> {error, 'forbidden'}; diff --git a/src/mod_configure2.erl b/src/mod_configure2.erl index 33c698ab9..b54b67d2b 100644 --- a/src/mod_configure2.erl +++ b/src/mod_configure2.erl @@ -71,7 +71,7 @@ stop(Host) -> process_local_iq(From, To, #iq{type = Type, payload = Request} = IQ_Rec) -> - case acl:match_rule(exmpp_jid:ldomain_as_list(To), configure, From) of + case acl:match_rule(exmpp_jid:prep_domain_as_list(To), configure, From) of deny -> exmpp_iq:error(IQ_Rec, 'not-allowed'); allow -> diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 13288a01a..6a227052d 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -196,7 +196,7 @@ get_local_features(Acc, _From, To, <<>>, _Lang) -> {result, Features} -> Features; empty -> [] end, - Host = exmpp_jid:ldomain_as_list(To), + Host = exmpp_jid:prep_domain_as_list(To), {result, ets:select(disco_features, [{{{'_', Host}}, [], ['$_']}]) ++ Feats}; @@ -239,7 +239,7 @@ get_local_services(Acc, _From, To, <<>>, _Lang) -> {result, Its} -> Its; empty -> [] end, - Host = exmpp_jid:ldomain_as_list(To), + Host = exmpp_jid:prep_domain_as_list(To), {result, lists:usort( lists:map(fun domain_to_xml/1, @@ -290,9 +290,9 @@ process_sm_iq_items(From, To, #iq{type = get, payload = SubEl, end; process_sm_iq_items(From, To, #iq{type = set, payload = SubEl} = IQ_Rec) -> LTo = exmpp_jid:lnode_as_list(To), - ToServer = exmpp_jid:ldomain_as_list(To), + ToServer = exmpp_jid:prep_domain_as_list(To), LFrom = exmpp_jid:lnode_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), + LServer = exmpp_jid:prep_domain_as_list(From), Self = (LTo == LFrom) andalso (ToServer == LServer), Node = exmpp_xml:get_attribute_as_list(SubEl, 'node', ""), if @@ -315,9 +315,9 @@ get_sm_items({error, _Error} = Acc, _From, _To, _Node, _Lang) -> get_sm_items(Acc, From, To, <<>>, _Lang) -> LFrom = exmpp_jid:lnode_as_list(From), - LSFrom = exmpp_jid:ldomain_as_list(From), + LSFrom = exmpp_jid:prep_domain_as_list(From), LTo = exmpp_jid:lnode_as_list(To), - LSTo = exmpp_jid:ldomain_as_list(To), + LSTo = exmpp_jid:prep_domain_as_list(To), Items = case Acc of {result, Its} -> Its; @@ -334,9 +334,9 @@ get_sm_items({result, _} = Acc, _From, _To, _Node, _Lang) -> get_sm_items(empty, From, To, _Node, _Lang) -> LFrom = exmpp_jid:lnode_as_list(From), - LSFrom = exmpp_jid:ldomain_as_list(From), + LSFrom = exmpp_jid:prep_domain_as_list(From), LTo = exmpp_jid:lnode_as_list(To), - LSTo = exmpp_jid:ldomain_as_list(To), + LSTo = exmpp_jid:prep_domain_as_list(To), case {LFrom, LSFrom} of {LTo, LSTo} -> {error, 'item-not-found'}; @@ -376,9 +376,9 @@ get_sm_identity(Acc, _From, _To, _Node, _Lang) -> get_sm_features(empty, From, To, _Node, _Lang) -> LFrom = exmpp_jid:lnode_as_list(From), - LSFrom = exmpp_jid:ldomain_as_list(From), + LSFrom = exmpp_jid:prep_domain_as_list(From), LTo = exmpp_jid:lnode_as_list(To), - LSTo = exmpp_jid:ldomain_as_list(To), + LSTo = exmpp_jid:prep_domain_as_list(To), case {LFrom, LSFrom} of {LTo, LSTo} -> {error, 'item-not-found'}; @@ -405,9 +405,9 @@ get_user_resources(JID) -> get_publish_items(empty, From, To, Node, _Lang) -> LFrom = exmpp_jid:lnode_as_list(From), - LSFrom = exmpp_jid:ldomain_as_list(From), + LSFrom = exmpp_jid:prep_domain_as_list(From), LTo = exmpp_jid:lnode_as_list(To), - LSTo = exmpp_jid:ldomain_as_list(To), + LSTo = exmpp_jid:prep_domain_as_list(To), if (LFrom == LTo) and (LSFrom == LSTo) -> retrieve_disco_publish({LTo, LSTo}, binary_to_list(Node)); diff --git a/src/mod_irc/mod_irc.erl b/src/mod_irc/mod_irc.erl index eb4d5fa7f..31810489a 100644 --- a/src/mod_irc/mod_irc.erl +++ b/src/mod_irc/mod_irc.erl @@ -404,7 +404,7 @@ get_form(Host, From, [], Lang, DefEnc) -> User = exmpp_jid:node_as_list(From), Server = exmpp_jid:domain_as_list(From), LUser = exmpp_jid:lnode_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), + LServer = exmpp_jid:prep_domain_as_list(From), US = {LUser, LServer}, Customs = case catch mnesia:dirty_read({irc_custom, {US, Host}}) of @@ -489,7 +489,7 @@ get_form(_Host, _, _, _Lang, _) -> set_form(Host, From, [], _Lang, XData) -> LUser = exmpp_jid:lnode_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), + LServer = exmpp_jid:prep_domain_as_list(From), US = {LUser, LServer}, case {lists:keysearch("username", 1, XData), lists:keysearch("encodings", 1, XData)} of @@ -535,7 +535,7 @@ set_form(_Host, _, _, _Lang, _XData) -> get_user_and_encoding(Host, From, IRCServer, DefEnc) -> User = exmpp_jid:node_as_list(From), LUser = exmpp_jid:lnode_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), + LServer = exmpp_jid:prep_domain_as_list(From), US = {LUser, LServer}, case catch mnesia:dirty_read({irc_custom, {US, Host}}) of {'EXIT', _Reason} -> diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 09943751e..75ab454dd 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -96,7 +96,7 @@ now_to_seconds({MegaSecs, Secs, _MicroSecs}) -> %%% process_sm_iq(From, To, #iq{type = get} = IQ_Rec) -> User = exmpp_jid:lnode_as_list(To), - Server = exmpp_jid:ldomain_as_list(To), + Server = exmpp_jid:prep_domain_as_list(To), {Subscription, _Groups} = ejabberd_hooks:run_fold( roster_get_jid_info, exmpp_jid:prep_domain(To), diff --git a/src/mod_offline.erl b/src/mod_offline.erl index b4fcd4d37..7f59a5ea9 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -162,7 +162,7 @@ store_packet(From, To, Packet) -> case check_event(From, To, Packet) of true -> LUser = exmpp_jid:lnode_as_list(To), - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), TimeStamp = now(), Expire = find_x_expire(TimeStamp, Packet#xmlel.children), gen_mod:get_module_proc(LServer, ?PROCNAME) ! diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index 7eaa9669c..7e6fb3a29 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -172,7 +172,7 @@ store_packet(From, To, Packet) -> LUser = exmpp_jid:lnode_as_list(To), TimeStamp = now(), Expire = find_x_expire(TimeStamp, Packet#xmlel.children), - gen_mod:get_module_proc(exmpp_jid:ldomain_as_list(To), ?PROCNAME) ! + gen_mod:get_module_proc(exmpp_jid:prep_domain_as_list(To), ?PROCNAME) ! #offline_msg{user = LUser, timestamp = TimeStamp, expire = Expire, diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 3989bba39..db5b2774e 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -88,7 +88,7 @@ process_iq(_From, _To, IQ_Rec) -> process_iq_get(_, From, _To, #iq{payload = SubEl}, #userlist{name = Active}) -> LUser = exmpp_jid:lnode_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), + LServer = exmpp_jid:prep_domain_as_list(From), case exmpp_xml:get_child_elements(SubEl) of [] -> process_lists_get(LUser, LServer, Active); @@ -247,7 +247,7 @@ list_to_action(S) -> process_iq_set(_, From, _To, #iq{payload = SubEl}) -> LUser = exmpp_jid:lnode_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), + LServer = exmpp_jid:prep_domain_as_list(From), case exmpp_xml:get_child_elements(SubEl) of [#xmlel{name = Name} = Child] -> ListName = exmpp_xml:get_attribute_as_list(Child, 'name', false), diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 42f96157a..90c1a7c4c 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -84,7 +84,7 @@ process_iq(_From, _To, IQ_Rec) -> process_iq_get(_, From, _To, #iq{payload = SubEl}, #userlist{name = Active}) -> LUser = exmpp_jid:lnode_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), + LServer = exmpp_jid:prep_domain_as_list(From), case exmpp_xml:get_child_elements(SubEl) of [] -> process_lists_get(LUser, LServer, Active); @@ -253,7 +253,7 @@ list_to_action(S) -> process_iq_set(_, From, _To, #iq{payload = SubEl}) -> LUser = exmpp_jid:lnode_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), + LServer = exmpp_jid:prep_domain_as_list(From), case exmpp_xml:get_child_elements(SubEl) of [#xmlel{name = Name} = Child] -> ListName = exmpp_xml:get_attribute_as_list(Child, 'name', false), diff --git a/src/mod_private.erl b/src/mod_private.erl index 313a312f0..3d25fa4db 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -113,7 +113,7 @@ check_packet(From, To, IQ_Rec, [F | R]) -> end. check_domain(From, _To, _IQ_Rec) -> - LServer = exmpp_jid:ldomain_as_list(From), + LServer = exmpp_jid:prep_domain_as_list(From), case lists:member(LServer, ?MYHOSTS) of true -> ok; false -> {error, 'not-allowed'} diff --git a/src/mod_private_odbc.erl b/src/mod_private_odbc.erl index 84deae535..75bfc1841 100644 --- a/src/mod_private_odbc.erl +++ b/src/mod_private_odbc.erl @@ -68,7 +68,7 @@ process_sm_iq(From, To, #iq{type = Type} = IQ_Rec) -> process_iq_get(From, _To, #iq{payload = SubEl} = IQ_Rec) -> LUser = exmpp_jid:lnode_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), + LServer = exmpp_jid:prep_domain_as_list(From), case catch get_data(LUser, LServer, exmpp_xml:get_child_elements(SubEl)) of @@ -83,7 +83,7 @@ process_iq_get(From, _To, #iq{payload = SubEl} = IQ_Rec) -> process_iq_set(From, _To, #iq{payload = SubEl} = IQ_Rec) -> LUser = exmpp_jid:lnode_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), + LServer = exmpp_jid:prep_domain_as_list(From), F = fun() -> lists:foreach( fun(El) -> @@ -107,7 +107,7 @@ check_packet(From, To, IQ_Rec, [F | R]) -> end. check_domain(From, _To, _IQ_Rec) -> - LServer = exmpp_jid:ldomain_as_list(From), + LServer = exmpp_jid:prep_domain_as_list(From), case lists:member(LServer, ?MYHOSTS) of true -> ok; false -> {error, 'not-allowed'} diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 8508e5d85..574e0b8e9 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -521,12 +521,12 @@ identity(Host) -> #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = Identity}. disco_local_identity(Acc, _From, To, <<>>, _Lang) -> - Acc ++ [identity(exmpp_jid:ldomain_as_list(To))]; + Acc ++ [identity(exmpp_jid:prep_domain_as_list(To))]; disco_local_identity(Acc, _From, _To, _Node, _Lang) -> Acc. disco_local_features(Acc, _From, To, <<>>, _Lang) -> - Host = exmpp_jid:ldomain_as_list(To), + Host = exmpp_jid:prep_domain_as_list(To), Feats = case Acc of {result, I} -> I; _ -> [] @@ -543,7 +543,7 @@ disco_local_items(Acc, _From, _To, _Node, _Lang) -> Acc. disco_sm_identity(Acc, _From, To, <<>>, _Lang) -> - Acc ++ [identity(exmpp_jid:ldomain_as_list(To))]; + Acc ++ [identity(exmpp_jid:prep_domain_as_list(To))]; disco_sm_identity(Acc, From, To, Node, _Lang) -> LOwner = jlib:short_prepd_bare_jid(To), Acc ++ case node_disco_identity(LOwner, From, Node) of @@ -567,7 +567,7 @@ disco_sm_features(Acc, From, To, Node, _Lang) -> disco_sm_items(Acc, From, To, <<>>, _Lang) -> %% TODO, use iq_disco_items(Host, [], From) - Host = exmpp_jid:ldomain_as_list(To), + Host = exmpp_jid:prep_domain_as_list(To), LJID = jlib:short_prepd_bare_jid(To), case tree_action(Host, get_subnodes, [Host, [], From]) of [] -> @@ -589,7 +589,7 @@ disco_sm_items(Acc, From, To, <<>>, _Lang) -> disco_sm_items(Acc, From, To, NodeB, _Lang) -> Node = binary_to_list(NodeB), %% TODO, use iq_disco_items(Host, Node, From) - Host = exmpp_jid:ldomain_as_list(To), + Host = exmpp_jid:prep_domain_as_list(To), LJID = jlib:short_prepd_bare_jid(To), Action = fun(#pubsub_node{type = Type, id = NodeId}) -> case node_call(Type, get_items, [NodeId, From]) of @@ -625,13 +625,13 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) -> presence_probe(JID, JID, Pid) -> {U, S, R} = jlib:short_prepd_jid(JID), - Host = S, % exmpp_jid:ldomain_as_list(JID), + Host = S, % exmpp_jid:prep_domain_as_list(JID), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), gen_server:cast(Proc, {presence, JID, Pid}), gen_server:cast(Proc, {presence, U, S, [R], JID}); presence_probe(Peer, JID, _Pid) -> {U, S, R} = jlib:short_prepd_jid(Peer), - Host = exmpp_jid:ldomain_as_list(JID), + Host = exmpp_jid:prep_domain_as_list(JID), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), gen_server:cast(Proc, {presence, U, S, [R], JID}). @@ -765,7 +765,7 @@ handle_info({route, From, To, Packet}, #state{server_host = ServerHost, access = Access, plugins = Plugins} = State) -> - case catch do_route(ServerHost, Access, Plugins, exmpp_jid:ldomain_as_list(To), From, To, Packet) of + case catch do_route(ServerHost, Access, Plugins, exmpp_jid:prep_domain_as_list(To), From, To, Packet) of {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); _ -> ok end, @@ -1048,8 +1048,8 @@ iq_disco_items(Host, Item, From) -> end. iq_local(From, To, #iq{type = Type, payload = SubEl, ns = XMLNS, lang = Lang} = IQ_Rec) -> - ServerHost = exmpp_jid:ldomain_as_list(To), - FromHost = exmpp_jid:ldomain_as_list(To), + ServerHost = exmpp_jid:prep_domain_as_list(To), + FromHost = exmpp_jid:prep_domain_as_list(To), %% Accept IQs to server only from our own users. if FromHost /= ServerHost -> @@ -1068,7 +1068,7 @@ iq_local(From, To, #iq{type = Type, payload = SubEl, ns = XMLNS, lang = Lang} = end. iq_sm(From, To, #iq{type = Type, payload = SubEl, ns = XMLNS, lang = Lang} = IQ_Rec) -> - ServerHost = exmpp_jid:ldomain_as_list(To), + ServerHost = exmpp_jid:prep_domain_as_list(To), LOwner = jlib:short_prepd_bare_jid(To), Res = case XMLNS of ?NS_PUBSUB -> iq_pubsub(LOwner, ServerHost, From, Type, SubEl, Lang); diff --git a/src/mod_pubsub/nodetree_virtual.erl b/src/mod_pubsub/nodetree_virtual.erl index c67968d05..00ea68cc4 100644 --- a/src/mod_pubsub/nodetree_virtual.erl +++ b/src/mod_pubsub/nodetree_virtual.erl @@ -135,7 +135,7 @@ get_subnodes_tree(_Host, _Node) -> %% <p>default allowed nodes: /home/host/user/any/node/name</p> create_node(Host, Node, _Type, Owner, _Options) -> UserName = exmpp_jid:lnode_as_list(Owner), - UserHost = exmpp_jid:ldomain_as_list(Owner), + UserHost = exmpp_jid:prep_domain_as_list(Owner), case Node of ["home", UserHost, UserName | _] -> {error, {virtual, {Host, Node}}}; _ -> {error, 'not-allowed'} diff --git a/src/mod_register.erl b/src/mod_register.erl index 3b6ce57cd..a84e8f184 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -88,7 +88,7 @@ unauthenticated_iq_register(Acc, _Server, _IQ, _IP) -> process_iq(From, To, IQ) -> process_iq(From, To, IQ, {exmpp_jid:lnode_as_list(From), - exmpp_jid:ldomain_as_list(From), + exmpp_jid:prep_domain_as_list(From), exmpp_jid:lresource_as_list(From)}). process_iq(From, To, @@ -99,11 +99,11 @@ process_iq(From, To, UTag = exmpp_xml:get_element(SubEl, 'username'), PTag = exmpp_xml:get_element(SubEl, 'password'), RTag = exmpp_xml:get_element(SubEl, 'remove'), - Server = exmpp_jid:ldomain_as_list(To), + Server = exmpp_jid:prep_domain_as_list(To), if (UTag /= undefined) and (RTag /= undefined) -> User = exmpp_xml:get_cdata_as_list(UTag), - case {exmpp_jid:node_as_list(From), exmpp_jid:ldomain_as_list(From)} of + case {exmpp_jid:node_as_list(From), exmpp_jid:prep_domain_as_list(From)} of {User, Server} -> ejabberd_auth:remove_user(User, Server), exmpp_iq:result(IQ_Rec, SubEl); @@ -138,7 +138,7 @@ process_iq(From, To, end; (UTag == undefined) and (RTag /= undefined) -> case {exmpp_jid:node_as_list(From), - exmpp_jid:ldomain_as_list(From), + exmpp_jid:prep_domain_as_list(From), exmpp_jid:resource_as_list(From)}of {User, Server, Resource} -> ResIQ = exmpp_iq:result(IQ_Rec, SubEl), @@ -158,7 +158,7 @@ process_iq(From, To, (UTag /= undefined) and (PTag /= undefined) -> User = exmpp_xml:get_cdata_as_list(UTag), Password = exmpp_xml:get_cdata_as_list(PTag), - case {exmpp_jid:node_as_list(From), exmpp_jid:ldomain_as_list(From)} of + case {exmpp_jid:node_as_list(From), exmpp_jid:prep_domain_as_list(From)} of {User, Server} -> try_set_password(User, Server, Password, IQ_Rec, SubEl); _ -> @@ -241,7 +241,7 @@ try_register(User, Server, Password, Source, Lang) -> send_welcome_message(JID) -> - Host = exmpp_jid:ldomain_as_list(JID), + Host = exmpp_jid:prep_domain_as_list(JID), case gen_mod:get_module_opt(Host, ?MODULE, welcome_message, {"", ""}) of {"", ""} -> ok; @@ -255,7 +255,7 @@ send_welcome_message(JID) -> end. send_registration_notifications(UJID) -> - Host = exmpp_jid:ldomain_as_list(UJID), + Host = exmpp_jid:prep_domain_as_list(UJID), case gen_mod:get_module_opt(Host, ?MODULE, registration_watchers, []) of [] -> ok; JIDs when is_list(JIDs) -> diff --git a/src/mod_roster.erl b/src/mod_roster.erl index a817bbad9..1b227ba7c 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -135,7 +135,7 @@ stop(Host) when is_list(Host) -> process_iq(From, To, IQ_Rec) when ?IS_JID(From), ?IS_JID(To), ?IS_IQ_RECORD(IQ_Rec) -> - LServer = exmpp_jid:ldomain_as_list(From), + LServer = exmpp_jid:prep_domain_as_list(From), case lists:member(LServer, ?MYHOSTS) of true -> process_local_iq(From, To, IQ_Rec); diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 65666206d..408ac1411 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -103,7 +103,7 @@ stop(Host) -> process_iq(From, To, IQ_Rec) -> - LServer = exmpp_jid:ldomain_as_list(From), + LServer = exmpp_jid:prep_domain_as_list(From), case lists:member(LServer, ?MYHOSTS) of true -> process_local_iq(From, To, IQ_Rec); @@ -756,7 +756,7 @@ get_in_pending_subscriptions(Ls, User, Server) when is_binary(User), is_binary(Server) -> JID = exmpp_jid:make(User, Server), LUser = exmpp_jid:lnode(JID), - LServer = exmpp_jid:ldomain_as_list(JID), + LServer = exmpp_jid:prep_domain_as_list(JID), Username = ejabberd_odbc:escape(LUser), case catch odbc_queries:get_roster(LServer, Username) of {selected, ["username", "jid", "nick", "subscription", "ask", diff --git a/src/mod_service_log.erl b/src/mod_service_log.erl index 725f69010..66d2599b9 100644 --- a/src/mod_service_log.erl +++ b/src/mod_service_log.erl @@ -55,10 +55,10 @@ stop(Host) -> ok. log_user_send(From, To, Packet) -> - log_packet(From, To, Packet, exmpp_jid:ldomain_as_list(From)). + log_packet(From, To, Packet, exmpp_jid:prep_domain_as_list(From)). log_user_receive(_JID, From, To, Packet) -> - log_packet(From, To, Packet, exmpp_jid:ldomain_as_list(To)). + log_packet(From, To, Packet, exmpp_jid:prep_domain_as_list(To)). log_packet(From, To, Packet, Host) -> diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 25cdb9a24..aa132cba4 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -941,7 +941,7 @@ shared_roster_group_parse_query(Host, Group, Query) -> _ -> try JID = exmpp_jid:parse(SJID), - [{exmpp_jid:lnode_as_list(JID), exmpp_jid:ldomain_as_list(JID)} | USs] + [{exmpp_jid:lnode_as_list(JID), exmpp_jid:prep_domain_as_list(JID)} | USs] catch _ -> error diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index c98802b80..820cee5f0 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -170,7 +170,7 @@ process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> LUser = exmpp_jid:lnode_as_list(To), - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), US = {LUser, LServer}, F = fun() -> mnesia:read({vcard, US}) @@ -191,7 +191,7 @@ process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> end; process_sm_iq(From, _To, #iq{type = set, payload = Request} = IQ_Rec) -> User = exmpp_jid:node_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), + LServer = exmpp_jid:prep_domain_as_list(From), case lists:member(LServer, ?MYHOSTS) of true -> set_vcard(User, LServer, Request), diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index 148d6b0af..ef746903b 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -240,7 +240,7 @@ process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> exmpp_iq:error(IQ_Rec, 'not-allowed'). process_sm_iq(_From, To, #iq{} = IQ_Rec) -> - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), case catch process_vcard_ldap(To, IQ_Rec, LServer) of {'EXIT', _} -> exmpp_iq:error(IQ_Rec, 'internal-server-error'); diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl index 45531bd95..f7ca4a9dd 100644 --- a/src/mod_vcard_odbc.erl +++ b/src/mod_vcard_odbc.erl @@ -132,7 +132,7 @@ process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> LUser = exmpp_jid:lnode_as_list(To), - LServer = exmpp_jid:ldomain_as_list(To), + LServer = exmpp_jid:prep_domain_as_list(To), Username = ejabberd_odbc:escape(LUser), case catch odbc_queries:get_vcard(LServer, Username) of {selected, ["vcard"], [{SVCARD}]} -> @@ -153,7 +153,7 @@ process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> end; process_sm_iq(From, _To, #iq{type = set, payload = Request} = IQ_Rec) -> User = exmpp_jid:node_as_list(From), - LServer = exmpp_jid:ldomain_as_list(From), + LServer = exmpp_jid:prep_domain_as_list(From), case lists:member(LServer, ?MYHOSTS) of true -> set_vcard(User, LServer, Request), diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 75f30f2aa..ee5b1d5f1 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -1178,7 +1178,7 @@ string_to_spec("server_regexp", Val) -> string_to_spec("node_regexp", Val) -> JID = exmpp_jid:parse(Val), U = exmpp_jid:lnode_as_list(JID), - S = exmpp_jid:ldomain_as_list(JID), + S = exmpp_jid:prep_domain_as_list(JID), undefined = exmpp_jid:resource(JID), {node_regexp, U, S}; string_to_spec("user_glob", Val) -> @@ -1188,7 +1188,7 @@ string_to_spec("server_glob", Val) -> string_to_spec("node_glob", Val) -> JID = exmpp_jid:parse(Val), U = exmpp_jid:lnode_as_list(JID), - S = exmpp_jid:ldomain_as_list(JID), + S = exmpp_jid:prep_domain_as_list(JID), undefined = exmpp_jid:resource(JID), {node_glob, U, S}; string_to_spec("all", _) -> @@ -1201,7 +1201,7 @@ string_to_spec("raw", Val) -> string_to_spec2(ACLName, Val) -> JID = exmpp_jid:parse(Val), U = exmpp_jid:lnode_as_list(JID), - S = exmpp_jid:ldomain_as_list(JID), + S = exmpp_jid:prep_domain_as_list(JID), undefined = exmpp_jid:resource(JID), case U of undefined -> From d5f2c41f262852617ec4cd1f851d79bb1e26d4bf Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 16:39:36 +0000 Subject: [PATCH 337/582] API renaming : lnode -> prep_node SVN Revision: 2125 --- src/ejabberd_auth_anonymous.erl | 4 ++-- src/ejabberd_c2s.erl | 4 ++-- src/ejabberd_local.erl | 2 +- src/ejabberd_sm.erl | 38 ++++++++++++++++----------------- src/ejabberd_system_monitor.erl | 4 ++-- src/jlib.erl | 2 +- src/mod_announce.erl | 2 +- src/mod_caps.erl | 2 +- src/mod_configure.erl | 8 +++---- src/mod_disco.erl | 4 ++-- src/mod_last.erl | 8 +++---- src/mod_last_odbc.erl | 6 +++--- src/mod_muc/mod_muc.erl | 8 +++---- src/mod_muc/mod_muc_room.erl | 8 +++---- src/mod_privacy.erl | 2 +- src/mod_privacy_odbc.erl | 2 +- src/mod_private.erl | 4 ++-- src/mod_pubsub/mod_pubsub.erl | 2 +- src/mod_roster.erl | 8 +++---- src/mod_roster_odbc.erl | 8 +++---- 20 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index 2808bcc70..ac63cc720 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -179,7 +179,7 @@ remove_connection(SID, LUser, LServer) when is_list(LUser), is_list(LServer) -> %% @doc Register connection. register_connection(SID, JID, Info) when ?IS_JID(JID) -> - LUser = exmpp_jid:lnode(JID), + LUser = exmpp_jid:prep_node(JID), LServer = exmpp_jid:prep_domain(JID), case proplists:get_value(auth_module, Info) of undefined -> @@ -200,7 +200,7 @@ register_connection(SID, JID, Info) when ?IS_JID(JID) -> %% @doc Remove an anonymous user from the anonymous users table. unregister_connection(SID, JID, _) when ?IS_JID(JID) -> - LUser = exmpp_jid:lnode(JID), + LUser = exmpp_jid:prep_node(JID), LServer = exmpp_jid:prep_domain(JID), purge_hook(anonymous_user_exist(LUser, LServer), LUser, LServer), diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 147f48109..ca69cbdfc 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -402,7 +402,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> {auth, _ID, set, {U, P, D, R}} -> try JID = exmpp_jid:make(U, StateData#state.server, R), - UBinary = exmpp_jid:lnode(JID), + UBinary = exmpp_jid:prep_node(JID), case acl:match_rule(ServerString, StateData#state.access, JID) of allow -> @@ -1573,7 +1573,7 @@ check_privacy_route(From, StateData, FromRoute, To, Packet) -> %% Check if privacy rules allow this delivery is_privacy_allow(From, To, Packet, PrivacyList) -> - User = exmpp_jid:lnode(To), + User = exmpp_jid:prep_node(To), Server = exmpp_jid:prep_domain(To), allow == ejabberd_hooks:run_fold( privacy_check_packet, Server, diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 74005ad59..9c93b1238 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -303,7 +303,7 @@ do_route(From, To, Packet) -> ?DEBUG("local route~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n", [From, To, Packet, 8]), - LNode = exmpp_jid:lnode(To), + LNode = exmpp_jid:prep_node(To), LResource = exmpp_jid:lresource(To), if LNode /= undefined -> diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index eb71b2416..3ae27a1ca 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -159,7 +159,7 @@ get_user_resources(User, Server) end. get_user_ip(JID) when ?IS_JID(JID) -> - USR = {exmpp_jid:lnode(JID), + USR = {exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID)}, case mnesia:dirty_index_read(session, USR, #session.usr) of @@ -195,7 +195,7 @@ set_presence(SID, JID, Priority, Presence, Info) when ?IS_JID(JID) -> set_session(SID, JID, Priority, Info), ejabberd_hooks:run(set_presence_hook, exmpp_jid:prep_domain(JID), - [exmpp_jid:lnode(JID), + [exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID), Presence]). @@ -204,7 +204,7 @@ unset_presence(SID, JID, Status, Info) when ?IS_JID(JID)-> set_session(SID, JID, undefined, Info), ejabberd_hooks:run(unset_presence_hook, exmpp_jid:prep_domain(JID), - [exmpp_jid:lnode(JID), + [exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID), Status]). @@ -213,13 +213,13 @@ close_session_unset_presence(SID, JID, Status) when ?IS_JID(JID) -> close_session(SID, JID), ejabberd_hooks:run(unset_presence_hook, exmpp_jid:prep_domain(JID), - [exmpp_jid:lnode(JID), + [exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID), Status]). get_session_pid(JID) when ?IS_JID(JID) -> - USR = {exmpp_jid:lnode(JID), + USR = {exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID)}, case catch mnesia:dirty_index_read(session, USR, #session.usr) of @@ -385,8 +385,8 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- set_session(SID, JID, Priority, Info) -> - US = {exmpp_jid:lnode(JID), exmpp_jid:prep_domain(JID)}, - USR = {exmpp_jid:lnode(JID), + US = {exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID)}, + USR = {exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID)}, F = fun() -> @@ -429,7 +429,7 @@ do_route(From, To, Packet) -> roster_in_subscription, exmpp_jid:prep_domain(To), false, - [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To), From, subscribe, Reason]), + [exmpp_jid:prep_node(To), exmpp_jid:prep_domain(To), From, subscribe, Reason]), true}; 'subscribed' -> {is_privacy_allow(From, To, Packet) andalso @@ -437,7 +437,7 @@ do_route(From, To, Packet) -> roster_in_subscription, exmpp_jid:prep_domain(To), false, - [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To), From, subscribed, <<>>]), + [exmpp_jid:prep_node(To), exmpp_jid:prep_domain(To), From, subscribed, <<>>]), true}; 'unsubscribe' -> {is_privacy_allow(From, To, Packet) andalso @@ -445,7 +445,7 @@ do_route(From, To, Packet) -> roster_in_subscription, exmpp_jid:prep_domain(To), false, - [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To), From, unsubscribe, <<>>]), + [exmpp_jid:prep_node(To), exmpp_jid:prep_domain(To), From, unsubscribe, <<>>]), true}; 'unsubscribed' -> {is_privacy_allow(From, To, Packet) andalso @@ -453,14 +453,14 @@ do_route(From, To, Packet) -> roster_in_subscription, exmpp_jid:prep_domain(To), false, - [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To), From, unsubscribed, <<>>]), + [exmpp_jid:prep_node(To), exmpp_jid:prep_domain(To), From, unsubscribed, <<>>]), true}; _ -> {true, false} end, if Pass -> PResources = get_user_present_resources( - exmpp_jid:lnode(To), exmpp_jid:prep_domain(To)), + exmpp_jid:prep_node(To), exmpp_jid:prep_domain(To)), lists:foreach( fun({_, R}) -> do_route( @@ -481,13 +481,13 @@ do_route(From, To, Packet) -> do_route(From, exmpp_jid:full(To, R), Packet) - end, get_user_resources(exmpp_jid:lnode(To), + end, get_user_resources(exmpp_jid:prep_node(To), exmpp_jid:prep_domain(To))); _ -> ok end; _ -> - USR = {exmpp_jid:lnode(To), + USR = {exmpp_jid:prep_node(To), exmpp_jid:prep_domain(To), exmpp_jid:lresource(To)}, case mnesia:dirty_index_read(session, USR, #session.usr) of @@ -521,7 +521,7 @@ do_route(From, To, Packet) -> %% for the target session/resource to which a stanza is addressed, %% or if there are no current sessions for the user. is_privacy_allow(From, To, Packet) -> - User = exmpp_jid:lnode(To), + User = exmpp_jid:prep_node(To), Server = exmpp_jid:prep_domain(To), PrivacyList = ejabberd_hooks:run_fold(privacy_get_user_list, Server, #userlist{}, [User, Server]), @@ -530,7 +530,7 @@ is_privacy_allow(From, To, Packet) -> %% Check if privacy rules allow this delivery %% Function copied from ejabberd_c2s.erl is_privacy_allow(From, To, Packet, PrivacyList) -> - User = exmpp_jid:lnode(To), + User = exmpp_jid:prep_node(To), Server = exmpp_jid:prep_domain(To), allow == ejabberd_hooks:run_fold( privacy_check_packet, Server, @@ -542,7 +542,7 @@ is_privacy_allow(From, To, Packet, PrivacyList) -> in]). route_message(From, To, Packet) -> - LUser = exmpp_jid:lnode(To), + LUser = exmpp_jid:prep_node(To), LServer = exmpp_jid:prep_domain(To), PrioRes = get_user_present_resources(LUser, LServer), case catch lists:max(PrioRes) of @@ -635,7 +635,7 @@ check_for_sessions_to_replace(JID) -> check_max_sessions(JID). check_existing_resources(JID) -> - USR = {exmpp_jid:lnode(JID), + USR = {exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID)}, %% A connection exist with the same resource. We replace it: @@ -659,7 +659,7 @@ check_max_sessions(JID) -> SIDs = mnesia:dirty_select( session, [{#session{sid = '$1', - us = {exmpp_jid:lnode(JID), exmpp_jid:prep_domain(JID)}, + us = {exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID)}, _ = '_'}, [], ['$1']}]), MaxSessions = get_max_user_sessions(JID), diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl index 0911e94b2..fd9a6b58e 100644 --- a/src/ejabberd_system_monitor.erl +++ b/src/ejabberd_system_monitor.erl @@ -60,7 +60,7 @@ end, gen_server:start_link({local, ?MODULE}, ?MODULE, Opts, []). process_command(From, To, Packet) -> - case {exmpp_jid:lnode(To), exmpp_jid:lresource(To) } of + case {exmpp_jid:prep_node(To), exmpp_jid:lresource(To) } of {undefined, <<"watchdog">>} -> case Packet#xmlel.name of 'message' -> @@ -217,7 +217,7 @@ get_admin_jids() -> fun(S) -> try JID = exmpp_jid:parse(S), - [{exmpp_jid:lnode(JID), + [{exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID)}] catch diff --git a/src/jlib.erl b/src/jlib.erl index 53941eee8..7133c3ed2 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -382,7 +382,7 @@ short_bare_jid(JID) -> short_jid(exmpp_jid:bare(JID)). short_prepd_jid(JID) -> - {exmpp_jid:lnode(JID), + {exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), exmpp_jid:lresource(JID)}. diff --git a/src/mod_announce.erl b/src/mod_announce.erl index 0b0d649fb..1efd6d8cd 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -133,7 +133,7 @@ stop(Host) -> %% Announcing via messages to a custom resource announce(From, To, Packet) -> - case {exmpp_jid:lnode(To), exmpp_jid:lresource(To)} of + case {exmpp_jid:prep_node(To), exmpp_jid:lresource(To)} of {undefined, Res} -> Name = Packet#xmlel.name, Proc = gen_mod:get_module_proc(exmpp_jid:prep_domain_as_list(To), ?PROCNAME), diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 576f1f21e..3158363c3 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -314,7 +314,7 @@ handle_cast({note_caps, From, %% XXX: this leads to race conditions where ejabberd will send %% lots of caps disco requests. %#jid{node = U, domain = S, resource = R} = From, - U = exmpp_jid:lnode(From), + U = exmpp_jid:prep_node(From), S = exmpp_jid:prep_domain(From), R = exmpp_jid:resource(From), BJID = exmpp_jid:jid_to_binary(From), diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 18841b916..2c701971d 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -298,7 +298,7 @@ get_sm_items(Acc, From, To, Node, Lang) -> end. get_user_resources(BareJID) -> - Rs = ejabberd_sm:get_user_resources(exmpp_jid:lnode(BareJID), + Rs = ejabberd_sm:get_user_resources(exmpp_jid:prep_node(BareJID), exmpp_jid:prep_domain(BareJID)), lists:map(fun(R) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = @@ -306,7 +306,7 @@ get_user_resources(BareJID) -> exmpp_jid:jid_to_binary( exmpp_jid:full(BareJID, R))), ?XMLATTR('name', - exmpp_jid:lnode(BareJID))]} + exmpp_jid:prep_node(BareJID))]} end, lists:sort(Rs)). %%%----------------------------------------------------------------------- @@ -1640,7 +1640,7 @@ set_form(From, Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> %% Code copied from web/ejabberd_web_admin.erl %% TODO: Update time format to XEP-0202: Entity Time FLast = - case ejabberd_sm:get_user_resources(exmpp_jid:lnode(User), + case ejabberd_sm:get_user_resources(exmpp_jid:prep_node(User), exmpp_jid:prep_domain(Server)) of [] -> _US = {User, Server}, @@ -1675,7 +1675,7 @@ set_form(From, Host, ?NS_ADMINL("user-stats"), Lang, XData) -> Server = exmpp_jid:prep_domain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), - Resources = ejabberd_sm:get_user_resources(exmpp_jid:lnode(JID), + Resources = ejabberd_sm:get_user_resources(exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID)), IPs1 = [ejabberd_sm:get_user_ip(exmpp_jid:full(JID,Resource)) || Resource <- Resources], diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 6a227052d..9b2357b64 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -392,13 +392,13 @@ get_sm_features(Acc, _From, _To, _Node, _Lang) -> get_user_resources(JID) -> - Rs = ejabberd_sm:get_user_resources(exmpp_jid:lnode(JID), + Rs = ejabberd_sm:get_user_resources(exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID)), lists:map(fun(R) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [ ?XMLATTR('jid', exmpp_jid:jid_to_binary(exmpp_jid:full(JID, R))), - ?XMLATTR('name', exmpp_jid:lnode(JID)) + ?XMLATTR('name', exmpp_jid:prep_node(JID)) ]} end, lists:sort(Rs)). diff --git a/src/mod_last.erl b/src/mod_last.erl index 5f8cb4d08..02615e704 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -106,22 +106,22 @@ process_sm_iq(From, To, #iq{type = get} = IQ_Rec) -> {Subscription, _Groups} = ejabberd_hooks:run_fold( roster_get_jid_info, exmpp_jid:prep_domain(To), - {none, []}, [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To), From]), + {none, []}, [exmpp_jid:prep_node(To), exmpp_jid:prep_domain(To), From]), if (Subscription == both) or (Subscription == from) -> UserListRecord = ejabberd_hooks:run_fold( privacy_get_user_list, exmpp_jid:prep_domain(To), #userlist{}, - [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To)]), + [exmpp_jid:prep_node(To), exmpp_jid:prep_domain(To)]), case ejabberd_hooks:run_fold( privacy_check_packet, exmpp_jid:prep_domain(To), allow, - [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To), UserListRecord, + [exmpp_jid:prep_node(To), exmpp_jid:prep_domain(To), UserListRecord, {From, To, exmpp_presence:available()}, out]) of allow -> - get_last(IQ_Rec, exmpp_jid:lnode(To), exmpp_jid:prep_domain(To)); + get_last(IQ_Rec, exmpp_jid:prep_node(To), exmpp_jid:prep_domain(To)); deny -> exmpp_iq:error(IQ_Rec, 'not-allowed') end; diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 75ab454dd..738013b69 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -100,17 +100,17 @@ process_sm_iq(From, To, #iq{type = get} = IQ_Rec) -> {Subscription, _Groups} = ejabberd_hooks:run_fold( roster_get_jid_info, exmpp_jid:prep_domain(To), - {none, []}, [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To), From]), + {none, []}, [exmpp_jid:prep_node(To), exmpp_jid:prep_domain(To), From]), if (Subscription == both) or (Subscription == from) -> UserListRecord = ejabberd_hooks:run_fold( privacy_get_user_list, exmpp_jid:prep_domain(To), #userlist{}, - [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To)]), + [exmpp_jid:prep_node(To), exmpp_jid:prep_domain(To)]), case ejabberd_hooks:run_fold( privacy_check_packet, exmpp_jid:prep_domain(To), allow, - [exmpp_jid:lnode(To), exmpp_jid:prep_domain(To), UserListRecord, + [exmpp_jid:prep_node(To), exmpp_jid:prep_domain(To), UserListRecord, {From, To, exmpp_presence:available()}, out]) of diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index 624c771df..dcf30fc58 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -146,7 +146,7 @@ process_iq_disco_items(Host, From, To, #iq{lang = Lang} = IQ) when is_binary(Hos can_use_nick(_Host, _JID, <<>>) -> false; can_use_nick(Host, JID, Nick) when is_binary(Host), is_binary(Nick) -> - LUS = {exmpp_jid:lnode(JID), exmpp_jid:prep_domain(JID)}, + LUS = {exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID)}, case catch mnesia:dirty_select( muc_registered, [{#muc_registered{us_host = '$1', @@ -344,7 +344,7 @@ do_route(Host, ServerHost, Access, HistorySize, RoomShaper, do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, From, To, Packet, DefRoomOpts) -> {_AccessRoute, AccessCreate, AccessAdmin, _AccessPersistent} = Access, - Room = exmpp_jid:lnode(To), + Room = exmpp_jid:prep_node(To), Nick = exmpp_jid:lresource(To), #xmlel{name = Name} = Packet, case Room of @@ -661,7 +661,7 @@ flush() -> children = [#xmlcdata{cdata = Val}]}]}). iq_get_register_info(Host, From, Lang) -> - LUser = exmpp_jid:lnode(From), + LUser = exmpp_jid:prep_node(From), LServer = exmpp_jid:prep_domain(From), LUS = {LUser, LServer}, {Nick, Registered} = @@ -691,7 +691,7 @@ iq_get_register_info(Host, From, Lang) -> iq_set_register_info(Host, From, Nick, Lang) when is_binary(Host), is_binary(Nick) -> - LUser = exmpp_jid:lnode(From), + LUser = exmpp_jid:prep_node(From), LServer = exmpp_jid:prep_domain(From), LUS = {LUser, LServer}, F = fun() -> diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index d64b78930..a50f08cdd 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -2208,7 +2208,7 @@ process_admin_items_set(UJID, Items, Lang, StateData) -> case catch ( case E of {JID, affiliation, owner, _} -> - case exmpp_jid:lnode(JID) of + case exmpp_jid:prep_node(JID) of <<>> -> SD; %% TODO: <<>> or 'undefined' ? @@ -3494,7 +3494,7 @@ add_to_log(Type, Data, StateData) -> %% Users number checking tab_add_online_user(JID, StateData) -> - LUser = exmpp_jid:lnode(JID), + LUser = exmpp_jid:prep_node(JID), LServer = exmpp_jid:prep_domain(JID), US = {LUser, LServer}, Room = StateData#state.room, @@ -3506,7 +3506,7 @@ tab_add_online_user(JID, StateData) -> tab_remove_online_user(JID, StateData) when ?IS_JID(JID) -> - LUser = exmpp_jid:lnode(JID), + LUser = exmpp_jid:prep_node(JID), LServer = exmpp_jid:prep_domain(JID), tab_remove_online_user({LUser, LServer, none},StateData); @@ -3519,7 +3519,7 @@ tab_remove_online_user({LUser, LServer,_}, StateData) -> #muc_online_users{us = US, room = Room, host = Host}). tab_count_user(JID) -> - LUser = exmpp_jid:lnode(JID), + LUser = exmpp_jid:prep_node(JID), LServer = exmpp_jid:prep_domain(JID), US = {LUser, LServer}, case catch ets:select( diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index db5b2774e..2d8bb6d66 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -660,7 +660,7 @@ is_type_match(Type, Value, JID, Subscription, Groups) -> case Type of jid -> {User, Server, Resource} = Value, - ((User == undefined) orelse (User == []) orelse (User == exmpp_jid:lnode(JID))) + ((User == undefined) orelse (User == []) orelse (User == exmpp_jid:prep_node(JID))) andalso ((Server == undefined) orelse (Server == []) orelse (Server == exmpp_jid:prep_domain(JID))) andalso ((Resource == undefined) orelse (Resource == []) orelse (Resource == exmpp_jid:lresource(JID))); subscription -> diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 90c1a7c4c..06b39111c 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -659,7 +659,7 @@ is_type_match(Type, Value, JID, Subscription, Groups) -> case Type of jid -> {User, Server, Resource} = Value, - ((User == undefined) orelse (User == []) orelse (User == exmpp_jid:lnode(JID))) + ((User == undefined) orelse (User == []) orelse (User == exmpp_jid:prep_node(JID))) andalso ((Server == undefined) orelse (Server == []) orelse (Server == exmpp_jid:prep_domain(JID))) andalso ((Resource == undefined) orelse (Resource == []) orelse (Resource == exmpp_jid:lresource(JID))); subscription -> diff --git a/src/mod_private.erl b/src/mod_private.erl index 3d25fa4db..275c693fc 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -73,7 +73,7 @@ process_sm_iq(From, To, #iq{type = Type} = IQ_Rec) -> end. process_iq_get(From, _To, #iq{payload = SubEl} = IQ_Rec) -> - LUser = exmpp_jid:lnode(From), + LUser = exmpp_jid:prep_node(From), LServer = exmpp_jid:prep_domain(From), case catch get_data(LUser, LServer, @@ -88,7 +88,7 @@ process_iq_get(From, _To, #iq{payload = SubEl} = IQ_Rec) -> process_iq_set(From, _To, #iq{payload = SubEl} = IQ_Rec) -> - LUser = exmpp_jid:lnode(From), + LUser = exmpp_jid:prep_node(From), LServer = exmpp_jid:prep_domain(From), F = fun() -> lists:foreach( diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 574e0b8e9..fd6e5647d 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -828,7 +828,7 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- do_route(ServerHost, Access, Plugins, Host, From, To, Packet) -> #xmlel{name = Name} = Packet, - LNode = exmpp_jid:lnode(To), + LNode = exmpp_jid:prep_node(To), LRes = exmpp_jid:lresource(To), case {LNode, LRes} of {undefined, undefined} -> diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 1b227ba7c..d320ce64e 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -163,7 +163,7 @@ process_local_iq(From, To, #iq{type = set} = IQ_Rec) %% IQ_Result = exmpp_iq:iq() process_iq_get(From, To, IQ_Rec) -> - US = {exmpp_jid:lnode(From), exmpp_jid:prep_domain(From)}, + US = {exmpp_jid:prep_node(From), exmpp_jid:prep_domain(From)}, case catch ejabberd_hooks:run_fold(roster_get, exmpp_jid:prep_domain(To), [], [US]) of Items when is_list(Items) -> XItems = lists:map(fun item_to_xml/1, Items), @@ -250,7 +250,7 @@ process_item_set(From, To, #xmlel{} = El) -> try JID1 = exmpp_jid:parse(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), User = exmpp_jid:node(From), - LUser = exmpp_jid:lnode(From), + LUser = exmpp_jid:prep_node(From), LServer = exmpp_jid:prep_domain(From), JID = jlib:short_jid(JID1), LJID = jlib:short_prepd_jid(JID1), @@ -844,7 +844,7 @@ process_item_attrs_ws(Item, []) -> get_in_pending_subscriptions(Ls, User, Server) when is_binary(User), is_binary(Server) -> JID = exmpp_jid:make(User, Server), - US = {exmpp_jid:lnode(JID), exmpp_jid:prep_domain(JID)}, + US = {exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID)}, case mnesia:dirty_index_read(roster, US, #roster.us) of Result when is_list(Result) -> Ls ++ lists:map( @@ -1185,7 +1185,7 @@ user_roster(User, Server, Query, Lang) -> build_contact_jid_td({U, S, R}) -> %% Convert {U, S, R} into {jid, U, S, R, U, S, R}: ContactJID = exmpp_jid:make(U, S, R), - JIDURI = case {exmpp_jid:lnode(ContactJID), exmpp_jid:prep_domain(ContactJID)} of + JIDURI = case {exmpp_jid:prep_node(ContactJID), exmpp_jid:prep_domain(ContactJID)} of {undefined, _} -> ""; {CUser, CServer} -> CUser_S = binary_to_list(CUser), diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 408ac1411..7ed173705 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -119,7 +119,7 @@ process_local_iq(From, To, #iq{type = set} = IQ_Rec) -> process_iq_get(From, To, IQ_Rec) -> - US = {exmpp_jid:lnode(From), exmpp_jid:prep_domain(From)}, + US = {exmpp_jid:prep_node(From), exmpp_jid:prep_domain(From)}, case catch ejabberd_hooks:run_fold(roster_get, exmpp_jid:prep_domain(To), [], [US]) of Items when is_list(Items) -> XItems = lists:map(fun item_to_xml/1, Items), @@ -217,7 +217,7 @@ process_iq_set(From, To, #iq{payload = Request} = IQ_Rec) -> process_item_set(From, To, #xmlel{} = El) -> try JID1 = exmpp_jid:parse(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), - User = exmpp_jid:lnode(From), + User = exmpp_jid:prep_node(From), Server = exmpp_jid:prep_domain(From), LServer = binary_to_list(Server), {U0, S0, R0} = LJID = jlib:short_prepd_jid(JID1), @@ -755,7 +755,7 @@ process_item_attrs_ws(Item, []) -> get_in_pending_subscriptions(Ls, User, Server) when is_binary(User), is_binary(Server) -> JID = exmpp_jid:make(User, Server), - LUser = exmpp_jid:lnode(JID), + LUser = exmpp_jid:prep_node(JID), LServer = exmpp_jid:prep_domain_as_list(JID), Username = ejabberd_odbc:escape(LUser), case catch odbc_queries:get_roster(LServer, Username) of @@ -1020,7 +1020,7 @@ user_roster(User, Server, Query, Lang) -> build_contact_jid_td({U, S, R}) -> %% Convert {U, S, R} into {jid, U, S, R, U, S, R}: ContactJID = exmpp_jid:make(U, S, R), - JIDURI = case {exmpp_jid:lnode(ContactJID), exmpp_jid:prep_domain(ContactJID)} of + JIDURI = case {exmpp_jid:prep_node(ContactJID), exmpp_jid:prep_domain(ContactJID)} of {undefined, _} -> ""; {CUser, CServer} -> CUser_S = binary_to_list(CUser), From d51d9e9fffd8907bc6137815f56f36cc461e6f70 Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 16:40:51 +0000 Subject: [PATCH 338/582] API renaming : lnode_as_list -> prep_node_as_list SVN Revision: 2126 --- src/acl.erl | 2 +- src/ejabberd_s2s_in.erl | 6 +++--- src/ejabberd_sm.erl | 2 +- src/mod_announce.erl | 2 +- src/mod_configure.erl | 14 +++++++------- src/mod_disco.erl | 20 ++++++++++---------- src/mod_irc/mod_irc.erl | 6 +++--- src/mod_last_odbc.erl | 2 +- src/mod_offline.erl | 2 +- src/mod_offline_odbc.erl | 4 ++-- src/mod_privacy.erl | 4 ++-- src/mod_privacy_odbc.erl | 4 ++-- src/mod_private_odbc.erl | 4 ++-- src/mod_pubsub/nodetree_virtual.erl | 2 +- src/mod_register.erl | 2 +- src/mod_shared_roster.erl | 2 +- src/mod_vcard.erl | 2 +- src/mod_vcard_ldap.erl | 2 +- src/mod_vcard_odbc.erl | 2 +- src/web/ejabberd_web_admin.erl | 6 +++--- 20 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/acl.erl b/src/acl.erl index 08061ab67..012918f14 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -231,7 +231,7 @@ match_acl(ACLName, JID, Host) -> all -> true; none -> false; _ -> - User = exmpp_jid:lnode_as_list(JID), + User = exmpp_jid:prep_node_as_list(JID), Server = exmpp_jid:prep_domain_as_list(JID), Resource = exmpp_jid:lresource_as_list(JID), lists:any(fun(#acl{aclspec = Spec}) -> diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index f1e3bff37..024708d9d 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -642,7 +642,7 @@ get_cert_domains(Cert) -> if D /= error -> JID = exmpp_jid:parse(D), - case {exmpp_jid:lnode_as_list(JID), + case {exmpp_jid:prep_node_as_list(JID), exmpp_jid:prep_domain_as_list(JID), exmpp_jid:lresource_as_list(JID)} of {undefined, LD, undefined} -> @@ -678,7 +678,7 @@ get_cert_domains(Cert) -> 'XmppAddr', XmppAddr) of {ok, D} when is_binary(D) -> JID2 = exmpp_jid:parse(binary_to_list(D)), - case {exmpp_jid:lnode_as_list(JID2), + case {exmpp_jid:prep_node_as_list(JID2), exmpp_jid:prep_domain_as_list(JID2), exmpp_jid:lresource_as_list(JID2)} of { undefined, LD, undefined} -> @@ -696,7 +696,7 @@ get_cert_domains(Cert) -> end; ({dNSName, D}) when is_list(D) -> JID3 = exmpp_jid:parse(D), - case {exmpp_jid:lnode_as_list(JID3), + case {exmpp_jid:prep_node_as_list(JID3), exmpp_jid:prep_domain_as_list(JID3), exmpp_jid:lresource_as_list(JID3)} of {undefined, LD, undefined} -> diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 3ae27a1ca..941413cb3 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -575,7 +575,7 @@ route_message(From, To, Packet) -> 'headline' -> bounce_offline_message(From, To, Packet); _ -> - case ejabberd_auth:is_user_exists(exmpp_jid:lnode_as_list(To), + case ejabberd_auth:is_user_exists(exmpp_jid:prep_node_as_list(To), exmpp_jid:prep_domain_as_list(To)) of true -> ejabberd_hooks:run(offline_message_hook, diff --git a/src/mod_announce.erl b/src/mod_announce.erl index 1efd6d8cd..bf9699add 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -829,7 +829,7 @@ announce_motd_delete(LServer) -> send_motd(JID) -> LServer = exmpp_jid:prep_domain_as_list(JID), - LUser = exmpp_jid:lnode_as_list(JID), + LUser = exmpp_jid:prep_node_as_list(JID), case catch mnesia:dirty_read({motd, LServer}) of [#motd{packet = Packet}] -> US = {LUser, LServer}, diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 2c701971d..4f16a2a46 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -1563,7 +1563,7 @@ set_form(From, Host, ?NS_ADMINL("add-user"), _Lang, XData) -> Password = get_value("password", XData), Password = get_value("password-verify", XData), AccountJID = exmpp_jid:parse(AccountString), - User = exmpp_jid:lnode_as_list(AccountJID), + User = exmpp_jid:prep_node_as_list(AccountJID), Server = exmpp_jid:prep_domain_as_list(AccountJID), true = lists:member(Server, ?MYHOSTS), true = (Server == Host) orelse (get_permission_level(From) == global), @@ -1576,7 +1576,7 @@ set_form(From, Host, ?NS_ADMINL("delete-user"), _Lang, XData) -> ASL2 = lists:map( fun(AccountString) -> JID = exmpp_jid:parse(AccountString), - User = [_|_] = exmpp_jid:lnode_as_list(JID), + User = [_|_] = exmpp_jid:prep_node_as_list(JID), Server = exmpp_jid:prep_domain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), true = ejabberd_auth:is_user_exists(User, Server), @@ -1589,7 +1589,7 @@ set_form(From, Host, ?NS_ADMINL("delete-user"), _Lang, XData) -> set_form(From, Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> AccountString = get_value("accountjid", XData), JID = exmpp_jid:parse(AccountString), - LUser = [_|_] = exmpp_jid:lnode_as_list(JID), + LUser = [_|_] = exmpp_jid:prep_node_as_list(JID), LServer = exmpp_jid:prep_domain_as_list(JID), true = (LServer == Host) orelse (get_permission_level(From) == global), %% Code copied from ejabberd_sm.erl @@ -1608,7 +1608,7 @@ set_form(From, Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> set_form(From, Host, ?NS_ADMINL("get-user-password"), Lang, XData) -> AccountString = get_value("accountjid", XData), JID = exmpp_jid:parse(AccountString), - User = [_|_] = exmpp_jid:lnode_as_list(JID), + User = [_|_] = exmpp_jid:prep_node_as_list(JID), Server = exmpp_jid:prep_domain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), Password = ejabberd_auth:get_password(User, Server), @@ -1623,7 +1623,7 @@ set_form(From, Host, ?NS_ADMINL("change-user-password"), _Lang, XData) -> AccountString = get_value("accountjid", XData), Password = get_value("password", XData), JID = exmpp_jid:parse(AccountString), - User = [_|_] = exmpp_jid:lnode_as_list(JID), + User = [_|_] = exmpp_jid:prep_node_as_list(JID), Server = exmpp_jid:prep_domain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), true = ejabberd_auth:is_user_exists(User, Server), @@ -1633,7 +1633,7 @@ set_form(From, Host, ?NS_ADMINL("change-user-password"), _Lang, XData) -> set_form(From, Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> AccountString = get_value("accountjid", XData), JID = exmpp_jid:parse(AccountString), - User = [_|_] = exmpp_jid:lnode_as_list(JID), + User = [_|_] = exmpp_jid:prep_node_as_list(JID), Server = exmpp_jid:prep_domain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), @@ -1671,7 +1671,7 @@ set_form(From, Host, ?NS_ADMINL("get-user-lastlogin"), Lang, XData) -> set_form(From, Host, ?NS_ADMINL("user-stats"), Lang, XData) -> AccountString = get_value("accountjid", XData), JID = exmpp_jid:parse(AccountString), - User = [_|_] = exmpp_jid:lnode_as_list(JID), + User = [_|_] = exmpp_jid:prep_node_as_list(JID), Server = exmpp_jid:prep_domain_as_list(JID), true = (Server == Host) orelse (get_permission_level(From) == global), diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 9b2357b64..f8dd45e71 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -289,9 +289,9 @@ process_sm_iq_items(From, To, #iq{type = get, payload = SubEl, exmpp_iq:error(IQ_Rec, Error) end; process_sm_iq_items(From, To, #iq{type = set, payload = SubEl} = IQ_Rec) -> - LTo = exmpp_jid:lnode_as_list(To), + LTo = exmpp_jid:prep_node_as_list(To), ToServer = exmpp_jid:prep_domain_as_list(To), - LFrom = exmpp_jid:lnode_as_list(From), + LFrom = exmpp_jid:prep_node_as_list(From), LServer = exmpp_jid:prep_domain_as_list(From), Self = (LTo == LFrom) andalso (ToServer == LServer), Node = exmpp_xml:get_attribute_as_list(SubEl, 'node', ""), @@ -314,9 +314,9 @@ get_sm_items({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; get_sm_items(Acc, From, To, <<>>, _Lang) -> - LFrom = exmpp_jid:lnode_as_list(From), + LFrom = exmpp_jid:prep_node_as_list(From), LSFrom = exmpp_jid:prep_domain_as_list(From), - LTo = exmpp_jid:lnode_as_list(To), + LTo = exmpp_jid:prep_node_as_list(To), LSTo = exmpp_jid:prep_domain_as_list(To), Items = case Acc of @@ -333,9 +333,9 @@ get_sm_items({result, _} = Acc, _From, _To, _Node, _Lang) -> Acc; get_sm_items(empty, From, To, _Node, _Lang) -> - LFrom = exmpp_jid:lnode_as_list(From), + LFrom = exmpp_jid:prep_node_as_list(From), LSFrom = exmpp_jid:prep_domain_as_list(From), - LTo = exmpp_jid:lnode_as_list(To), + LTo = exmpp_jid:prep_node_as_list(To), LSTo = exmpp_jid:prep_domain_as_list(To), case {LFrom, LSFrom} of {LTo, LSTo} -> @@ -375,9 +375,9 @@ get_sm_identity(Acc, _From, _To, _Node, _Lang) -> Acc. get_sm_features(empty, From, To, _Node, _Lang) -> - LFrom = exmpp_jid:lnode_as_list(From), + LFrom = exmpp_jid:prep_node_as_list(From), LSFrom = exmpp_jid:prep_domain_as_list(From), - LTo = exmpp_jid:lnode_as_list(To), + LTo = exmpp_jid:prep_node_as_list(To), LSTo = exmpp_jid:prep_domain_as_list(To), case {LFrom, LSFrom} of {LTo, LSTo} -> @@ -404,9 +404,9 @@ get_user_resources(JID) -> get_publish_items(empty, From, To, Node, _Lang) -> - LFrom = exmpp_jid:lnode_as_list(From), + LFrom = exmpp_jid:prep_node_as_list(From), LSFrom = exmpp_jid:prep_domain_as_list(From), - LTo = exmpp_jid:lnode_as_list(To), + LTo = exmpp_jid:prep_node_as_list(To), LSTo = exmpp_jid:prep_domain_as_list(To), if (LFrom == LTo) and (LSFrom == LSTo) -> diff --git a/src/mod_irc/mod_irc.erl b/src/mod_irc/mod_irc.erl index 31810489a..a12853d33 100644 --- a/src/mod_irc/mod_irc.erl +++ b/src/mod_irc/mod_irc.erl @@ -403,7 +403,7 @@ process_irc_register(Host, From, _To, _DefEnc, get_form(Host, From, [], Lang, DefEnc) -> User = exmpp_jid:node_as_list(From), Server = exmpp_jid:domain_as_list(From), - LUser = exmpp_jid:lnode_as_list(From), + LUser = exmpp_jid:prep_node_as_list(From), LServer = exmpp_jid:prep_domain_as_list(From), US = {LUser, LServer}, Customs = @@ -488,7 +488,7 @@ get_form(_Host, _, _, _Lang, _) -> set_form(Host, From, [], _Lang, XData) -> - LUser = exmpp_jid:lnode_as_list(From), + LUser = exmpp_jid:prep_node_as_list(From), LServer = exmpp_jid:prep_domain_as_list(From), US = {LUser, LServer}, case {lists:keysearch("username", 1, XData), @@ -534,7 +534,7 @@ set_form(_Host, _, _, _Lang, _XData) -> get_user_and_encoding(Host, From, IRCServer, DefEnc) -> User = exmpp_jid:node_as_list(From), - LUser = exmpp_jid:lnode_as_list(From), + LUser = exmpp_jid:prep_node_as_list(From), LServer = exmpp_jid:prep_domain_as_list(From), US = {LUser, LServer}, case catch mnesia:dirty_read({irc_custom, {US, Host}}) of diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 738013b69..7bc552d8b 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -95,7 +95,7 @@ now_to_seconds({MegaSecs, Secs, _MicroSecs}) -> %%% Serve queries about user last online %%% process_sm_iq(From, To, #iq{type = get} = IQ_Rec) -> - User = exmpp_jid:lnode_as_list(To), + User = exmpp_jid:prep_node_as_list(To), Server = exmpp_jid:prep_domain_as_list(To), {Subscription, _Groups} = ejabberd_hooks:run_fold( diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 7f59a5ea9..03217aede 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -161,7 +161,7 @@ store_packet(From, To, Packet) -> (Type /= <<"headline">>) -> case check_event(From, To, Packet) of true -> - LUser = exmpp_jid:lnode_as_list(To), + LUser = exmpp_jid:prep_node_as_list(To), LServer = exmpp_jid:prep_domain_as_list(To), TimeStamp = now(), Expire = find_x_expire(TimeStamp, Packet#xmlel.children), diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index 7e6fb3a29..d71b3d726 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -103,7 +103,7 @@ loop(Host, MaxOfflineMsgs) -> fun(M) -> Username = ejabberd_odbc:escape( - exmpp_jid:lnode_as_list(M#offline_msg.to)), + exmpp_jid:prep_node_as_list(M#offline_msg.to)), From = M#offline_msg.from, To = M#offline_msg.to, Packet0 = exmpp_stanza:set_jids( @@ -169,7 +169,7 @@ store_packet(From, To, Packet) -> (Type /= <<"headline">>) -> case check_event(From, To, Packet) of true -> - LUser = exmpp_jid:lnode_as_list(To), + LUser = exmpp_jid:prep_node_as_list(To), TimeStamp = now(), Expire = find_x_expire(TimeStamp, Packet#xmlel.children), gen_mod:get_module_proc(exmpp_jid:prep_domain_as_list(To), ?PROCNAME) ! diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 2d8bb6d66..8ff718cfc 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -87,7 +87,7 @@ process_iq(_From, _To, IQ_Rec) -> process_iq_get(_, From, _To, #iq{payload = SubEl}, #userlist{name = Active}) -> - LUser = exmpp_jid:lnode_as_list(From), + LUser = exmpp_jid:prep_node_as_list(From), LServer = exmpp_jid:prep_domain_as_list(From), case exmpp_xml:get_child_elements(SubEl) of [] -> @@ -246,7 +246,7 @@ list_to_action(S) -> process_iq_set(_, From, _To, #iq{payload = SubEl}) -> - LUser = exmpp_jid:lnode_as_list(From), + LUser = exmpp_jid:prep_node_as_list(From), LServer = exmpp_jid:prep_domain_as_list(From), case exmpp_xml:get_child_elements(SubEl) of [#xmlel{name = Name} = Child] -> diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 06b39111c..7d3b5316a 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -83,7 +83,7 @@ process_iq(_From, _To, IQ_Rec) -> process_iq_get(_, From, _To, #iq{payload = SubEl}, #userlist{name = Active}) -> - LUser = exmpp_jid:lnode_as_list(From), + LUser = exmpp_jid:prep_node_as_list(From), LServer = exmpp_jid:prep_domain_as_list(From), case exmpp_xml:get_child_elements(SubEl) of [] -> @@ -252,7 +252,7 @@ list_to_action(S) -> process_iq_set(_, From, _To, #iq{payload = SubEl}) -> - LUser = exmpp_jid:lnode_as_list(From), + LUser = exmpp_jid:prep_node_as_list(From), LServer = exmpp_jid:prep_domain_as_list(From), case exmpp_xml:get_child_elements(SubEl) of [#xmlel{name = Name} = Child] -> diff --git a/src/mod_private_odbc.erl b/src/mod_private_odbc.erl index 75bfc1841..3c16b5c79 100644 --- a/src/mod_private_odbc.erl +++ b/src/mod_private_odbc.erl @@ -67,7 +67,7 @@ process_sm_iq(From, To, #iq{type = Type} = IQ_Rec) -> end. process_iq_get(From, _To, #iq{payload = SubEl} = IQ_Rec) -> - LUser = exmpp_jid:lnode_as_list(From), + LUser = exmpp_jid:prep_node_as_list(From), LServer = exmpp_jid:prep_domain_as_list(From), case catch get_data(LUser, LServer, @@ -82,7 +82,7 @@ process_iq_get(From, _To, #iq{payload = SubEl} = IQ_Rec) -> process_iq_set(From, _To, #iq{payload = SubEl} = IQ_Rec) -> - LUser = exmpp_jid:lnode_as_list(From), + LUser = exmpp_jid:prep_node_as_list(From), LServer = exmpp_jid:prep_domain_as_list(From), F = fun() -> lists:foreach( diff --git a/src/mod_pubsub/nodetree_virtual.erl b/src/mod_pubsub/nodetree_virtual.erl index 00ea68cc4..bd9b74713 100644 --- a/src/mod_pubsub/nodetree_virtual.erl +++ b/src/mod_pubsub/nodetree_virtual.erl @@ -134,7 +134,7 @@ get_subnodes_tree(_Host, _Node) -> %% is considered as already created.</p> %% <p>default allowed nodes: /home/host/user/any/node/name</p> create_node(Host, Node, _Type, Owner, _Options) -> - UserName = exmpp_jid:lnode_as_list(Owner), + UserName = exmpp_jid:prep_node_as_list(Owner), UserHost = exmpp_jid:prep_domain_as_list(Owner), case Node of ["home", UserHost, UserName | _] -> {error, {virtual, {Host, Node}}}; diff --git a/src/mod_register.erl b/src/mod_register.erl index a84e8f184..f1dfa3bcf 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -87,7 +87,7 @@ unauthenticated_iq_register(Acc, _Server, _IQ, _IP) -> Acc. process_iq(From, To, IQ) -> - process_iq(From, To, IQ, {exmpp_jid:lnode_as_list(From), + process_iq(From, To, IQ, {exmpp_jid:prep_node_as_list(From), exmpp_jid:prep_domain_as_list(From), exmpp_jid:lresource_as_list(From)}). diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index aa132cba4..65c87711c 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -941,7 +941,7 @@ shared_roster_group_parse_query(Host, Group, Query) -> _ -> try JID = exmpp_jid:parse(SJID), - [{exmpp_jid:lnode_as_list(JID), exmpp_jid:prep_domain_as_list(JID)} | USs] + [{exmpp_jid:prep_node_as_list(JID), exmpp_jid:prep_domain_as_list(JID)} | USs] catch _ -> error diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index 820cee5f0..23eaf66f7 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -169,7 +169,7 @@ process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> - LUser = exmpp_jid:lnode_as_list(To), + LUser = exmpp_jid:prep_node_as_list(To), LServer = exmpp_jid:prep_domain_as_list(To), US = {LUser, LServer}, F = fun() -> diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index ef746903b..4ee43b84e 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -254,7 +254,7 @@ process_vcard_ldap(To, IQ_Rec, Server) -> set -> exmpp_iq:error(IQ_Rec, 'not-allowed'); get -> - LUser = exmpp_jid:lnode_as_list(To), + LUser = exmpp_jid:prep_node_as_list(To), LServer = State#state.serverhost, case ejabberd_auth:is_user_exists(LUser, LServer) of true -> diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl index f7ca4a9dd..e92f164db 100644 --- a/src/mod_vcard_odbc.erl +++ b/src/mod_vcard_odbc.erl @@ -131,7 +131,7 @@ process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) -> - LUser = exmpp_jid:lnode_as_list(To), + LUser = exmpp_jid:prep_node_as_list(To), LServer = exmpp_jid:prep_domain_as_list(To), Username = ejabberd_odbc:escape(LUser), case catch odbc_queries:get_vcard(LServer, Username) of diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index ee5b1d5f1..0fda60468 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -1177,7 +1177,7 @@ string_to_spec("server_regexp", Val) -> {server_regexp, Val}; string_to_spec("node_regexp", Val) -> JID = exmpp_jid:parse(Val), - U = exmpp_jid:lnode_as_list(JID), + U = exmpp_jid:prep_node_as_list(JID), S = exmpp_jid:prep_domain_as_list(JID), undefined = exmpp_jid:resource(JID), {node_regexp, U, S}; @@ -1187,7 +1187,7 @@ string_to_spec("server_glob", Val) -> {server_glob, Val}; string_to_spec("node_glob", Val) -> JID = exmpp_jid:parse(Val), - U = exmpp_jid:lnode_as_list(JID), + U = exmpp_jid:prep_node_as_list(JID), S = exmpp_jid:prep_domain_as_list(JID), undefined = exmpp_jid:resource(JID), {node_glob, U, S}; @@ -1200,7 +1200,7 @@ string_to_spec("raw", Val) -> string_to_spec2(ACLName, Val) -> JID = exmpp_jid:parse(Val), - U = exmpp_jid:lnode_as_list(JID), + U = exmpp_jid:prep_node_as_list(JID), S = exmpp_jid:prep_domain_as_list(JID), undefined = exmpp_jid:resource(JID), case U of From 29c0e17ca242ef1428f5fe51817e4806116dea7f Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 16:42:07 +0000 Subject: [PATCH 339/582] API renaming : lresource -> prep_resource SVN Revision: 2127 --- src/ejabberd_c2s.erl | 2 +- src/ejabberd_local.erl | 2 +- src/ejabberd_sm.erl | 18 +++++++++--------- src/ejabberd_system_monitor.erl | 4 ++-- src/jlib.erl | 2 +- src/mod_announce.erl | 2 +- src/mod_caps.erl | 2 +- src/mod_muc/mod_muc.erl | 2 +- src/mod_privacy.erl | 2 +- src/mod_privacy_odbc.erl | 2 +- src/mod_pubsub/mod_pubsub.erl | 2 +- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index ca69cbdfc..a1d1ea2fb 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1920,7 +1920,7 @@ check_from(El, FromJID) -> {value, SJID} -> try JIDEl = exmpp_jid:parse(SJID), - case exmpp_jid:lresource(JIDEl) of + case exmpp_jid:prep_resource(JIDEl) of undefined -> %% Matching JID: The stanza is ok case exmpp_jid:compare_bare_jids(JIDEl, FromJID) of diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 9c93b1238..275449deb 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -304,7 +304,7 @@ do_route(From, To, Packet) -> [From, To, Packet, 8]), LNode = exmpp_jid:prep_node(To), - LResource = exmpp_jid:lresource(To), + LResource = exmpp_jid:prep_resource(To), if LNode /= undefined -> ejabberd_sm:route(From, To, Packet); diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 941413cb3..511f7ec5e 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -161,7 +161,7 @@ get_user_resources(User, Server) get_user_ip(JID) when ?IS_JID(JID) -> USR = {exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), - exmpp_jid:lresource(JID)}, + exmpp_jid:prep_resource(JID)}, case mnesia:dirty_index_read(session, USR, #session.usr) of [] -> undefined; @@ -197,7 +197,7 @@ set_presence(SID, JID, Priority, Presence, Info) when ?IS_JID(JID) -> exmpp_jid:prep_domain(JID), [exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), - exmpp_jid:lresource(JID), + exmpp_jid:prep_resource(JID), Presence]). unset_presence(SID, JID, Status, Info) when ?IS_JID(JID)-> @@ -206,7 +206,7 @@ unset_presence(SID, JID, Status, Info) when ?IS_JID(JID)-> exmpp_jid:prep_domain(JID), [exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), - exmpp_jid:lresource(JID), + exmpp_jid:prep_resource(JID), Status]). close_session_unset_presence(SID, JID, Status) when ?IS_JID(JID) -> @@ -215,13 +215,13 @@ close_session_unset_presence(SID, JID, Status) when ?IS_JID(JID) -> exmpp_jid:prep_domain(JID), [exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), - exmpp_jid:lresource(JID), + exmpp_jid:prep_resource(JID), Status]). get_session_pid(JID) when ?IS_JID(JID) -> USR = {exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), - exmpp_jid:lresource(JID)}, + exmpp_jid:prep_resource(JID)}, case catch mnesia:dirty_index_read(session, USR, #session.usr) of [#session{sid = {_, Pid}}] -> Pid; _ -> none @@ -388,7 +388,7 @@ set_session(SID, JID, Priority, Info) -> US = {exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID)}, USR = {exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), - exmpp_jid:lresource(JID)}, + exmpp_jid:prep_resource(JID)}, F = fun() -> mnesia:write(#session{sid = SID, usr = USR, @@ -416,7 +416,7 @@ clean_table_from_bad_node(Node) -> do_route(From, To, Packet) -> ?DEBUG("session manager~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n", [From, To, Packet, 8]), - case exmpp_jid:lresource(To) of + case exmpp_jid:prep_resource(To) of undefined -> case Packet of _ when ?IS_PRESENCE(Packet) -> @@ -489,7 +489,7 @@ do_route(From, To, Packet) -> _ -> USR = {exmpp_jid:prep_node(To), exmpp_jid:prep_domain(To), - exmpp_jid:lresource(To)}, + exmpp_jid:prep_resource(To)}, case mnesia:dirty_index_read(session, USR, #session.usr) of [] -> case Packet of @@ -637,7 +637,7 @@ check_for_sessions_to_replace(JID) -> check_existing_resources(JID) -> USR = {exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), - exmpp_jid:lresource(JID)}, + exmpp_jid:prep_resource(JID)}, %% A connection exist with the same resource. We replace it: SIDs = mnesia:dirty_select( session, diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl index fd9a6b58e..15a786c7c 100644 --- a/src/ejabberd_system_monitor.erl +++ b/src/ejabberd_system_monitor.erl @@ -60,7 +60,7 @@ end, gen_server:start_link({local, ?MODULE}, ?MODULE, Opts, []). process_command(From, To, Packet) -> - case {exmpp_jid:prep_node(To), exmpp_jid:lresource(To) } of + case {exmpp_jid:prep_node(To), exmpp_jid:prep_resource(To) } of {undefined, <<"watchdog">>} -> case Packet#xmlel.name of 'message' -> @@ -219,7 +219,7 @@ get_admin_jids() -> JID = exmpp_jid:parse(S), [{exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), - exmpp_jid:lresource(JID)}] + exmpp_jid:prep_resource(JID)}] catch _ -> [] diff --git a/src/jlib.erl b/src/jlib.erl index 7133c3ed2..cf3dc5e8d 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -384,7 +384,7 @@ short_bare_jid(JID) -> short_prepd_jid(JID) -> {exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID), - exmpp_jid:lresource(JID)}. + exmpp_jid:prep_resource(JID)}. short_prepd_bare_jid(JID) -> short_prepd_jid(exmpp_jid:bare(JID)). diff --git a/src/mod_announce.erl b/src/mod_announce.erl index bf9699add..b12000067 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -133,7 +133,7 @@ stop(Host) -> %% Announcing via messages to a custom resource announce(From, To, Packet) -> - case {exmpp_jid:prep_node(To), exmpp_jid:lresource(To)} of + case {exmpp_jid:prep_node(To), exmpp_jid:prep_resource(To)} of {undefined, Res} -> Name = Packet#xmlel.name, Proc = gen_mod:get_module_proc(exmpp_jid:prep_domain_as_list(To), ?PROCNAME), diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 3158363c3..1c90dc2e8 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -119,7 +119,7 @@ get_caps({U, S, R}, Retry) -> %% clear_caps removes user caps from database clear_caps(JID) -> - R = exmpp_jid:lresource(JID), + R = exmpp_jid:prep_resource(JID), BJID = exmpp_jid:jid_to_binary(JID), BUID = exmpp_jid:bare_jid_to_binary(JID), catch mnesia:dirty_delete({user_caps, BJID}), diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index dcf30fc58..3ccb7e3ac 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -345,7 +345,7 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, From, To, Packet, DefRoomOpts) -> {_AccessRoute, AccessCreate, AccessAdmin, _AccessPersistent} = Access, Room = exmpp_jid:prep_node(To), - Nick = exmpp_jid:lresource(To), + Nick = exmpp_jid:prep_resource(To), #xmlel{name = Name} = Packet, case Room of 'undefined' -> diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 8ff718cfc..3b53a2bf1 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -662,7 +662,7 @@ is_type_match(Type, Value, JID, Subscription, Groups) -> {User, Server, Resource} = Value, ((User == undefined) orelse (User == []) orelse (User == exmpp_jid:prep_node(JID))) andalso ((Server == undefined) orelse (Server == []) orelse (Server == exmpp_jid:prep_domain(JID))) - andalso ((Resource == undefined) orelse (Resource == []) orelse (Resource == exmpp_jid:lresource(JID))); + andalso ((Resource == undefined) orelse (Resource == []) orelse (Resource == exmpp_jid:prep_resource(JID))); subscription -> Value == Subscription; group -> diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 7d3b5316a..aa1c0fedb 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -661,7 +661,7 @@ is_type_match(Type, Value, JID, Subscription, Groups) -> {User, Server, Resource} = Value, ((User == undefined) orelse (User == []) orelse (User == exmpp_jid:prep_node(JID))) andalso ((Server == undefined) orelse (Server == []) orelse (Server == exmpp_jid:prep_domain(JID))) - andalso ((Resource == undefined) orelse (Resource == []) orelse (Resource == exmpp_jid:lresource(JID))); + andalso ((Resource == undefined) orelse (Resource == []) orelse (Resource == exmpp_jid:prep_resource(JID))); subscription -> Value == Subscription; group -> diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index fd6e5647d..b22501295 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -829,7 +829,7 @@ code_change(_OldVsn, State, _Extra) -> do_route(ServerHost, Access, Plugins, Host, From, To, Packet) -> #xmlel{name = Name} = Packet, LNode = exmpp_jid:prep_node(To), - LRes = exmpp_jid:lresource(To), + LRes = exmpp_jid:prep_resource(To), case {LNode, LRes} of {undefined, undefined} -> case Name of From 4258b99b2ba4ae9c892ec87c1c3c01be776b39d8 Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 16:43:15 +0000 Subject: [PATCH 340/582] API renaming : lresource_as_list -> prep_resource_as_list SVN Revision: 2128 --- src/acl.erl | 2 +- src/ejabberd_s2s_in.erl | 6 +++--- src/mod_configure.erl | 2 +- src/mod_register.erl | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/acl.erl b/src/acl.erl index 012918f14..8ab703514 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -233,7 +233,7 @@ match_acl(ACLName, JID, Host) -> _ -> User = exmpp_jid:prep_node_as_list(JID), Server = exmpp_jid:prep_domain_as_list(JID), - Resource = exmpp_jid:lresource_as_list(JID), + Resource = exmpp_jid:prep_resource_as_list(JID), lists:any(fun(#acl{aclspec = Spec}) -> case Spec of all -> diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 024708d9d..973107a16 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -644,7 +644,7 @@ get_cert_domains(Cert) -> JID = exmpp_jid:parse(D), case {exmpp_jid:prep_node_as_list(JID), exmpp_jid:prep_domain_as_list(JID), - exmpp_jid:lresource_as_list(JID)} of + exmpp_jid:prep_resource_as_list(JID)} of {undefined, LD, undefined} -> [LD]; _ -> @@ -680,7 +680,7 @@ get_cert_domains(Cert) -> JID2 = exmpp_jid:parse(binary_to_list(D)), case {exmpp_jid:prep_node_as_list(JID2), exmpp_jid:prep_domain_as_list(JID2), - exmpp_jid:lresource_as_list(JID2)} of + exmpp_jid:prep_resource_as_list(JID2)} of { undefined, LD, undefined} -> case idna:domain_utf8_to_ascii(LD) of false -> @@ -698,7 +698,7 @@ get_cert_domains(Cert) -> JID3 = exmpp_jid:parse(D), case {exmpp_jid:prep_node_as_list(JID3), exmpp_jid:prep_domain_as_list(JID3), - exmpp_jid:lresource_as_list(JID3)} of + exmpp_jid:prep_resource_as_list(JID3)} of {undefined, LD, undefined} -> [LD]; _ -> diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 4f16a2a46..7b1e909bf 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -1593,7 +1593,7 @@ set_form(From, Host, ?NS_ADMINL("end-user-session"), _Lang, XData) -> LServer = exmpp_jid:prep_domain_as_list(JID), true = (LServer == Host) orelse (get_permission_level(From) == global), %% Code copied from ejabberd_sm.erl - case exmpp_jid:lresource_as_list(JID) of + case exmpp_jid:prep_resource_as_list(JID) of undefined -> SIDs = mnesia:dirty_select(session, [{#session{sid = '$1', usr = {LUser, LServer, '_'}, _ = '_'}, [], ['$1']}]), diff --git a/src/mod_register.erl b/src/mod_register.erl index f1dfa3bcf..218abdad5 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -89,7 +89,7 @@ unauthenticated_iq_register(Acc, _Server, _IQ, _IP) -> process_iq(From, To, IQ) -> process_iq(From, To, IQ, {exmpp_jid:prep_node_as_list(From), exmpp_jid:prep_domain_as_list(From), - exmpp_jid:lresource_as_list(From)}). + exmpp_jid:prep_resource_as_list(From)}). process_iq(From, To, #iq{type = Type, lang = Lang, payload = SubEl} = IQ_Rec, From c31f99937f420a6e8e33c8a21a1b5a45f5761c0a Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 16:49:00 +0000 Subject: [PATCH 341/582] API renaming : compare_jids -> compare SVN Revision: 2129 --- src/ejabberd_c2s.erl | 2 +- src/ejabberd_system_monitor.erl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index a1d1ea2fb..c3f2a5e60 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1931,7 +1931,7 @@ check_from(El, FromJID) -> end; _ -> %% Matching JID: The stanza is ok - case exmpp_jid:compare_jids(JIDEl, FromJID) of + case exmpp_jid:compare(JIDEl, FromJID) of true -> El; false -> diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl index 15a786c7c..583340184 100644 --- a/src/ejabberd_system_monitor.erl +++ b/src/ejabberd_system_monitor.erl @@ -65,7 +65,7 @@ process_command(From, To, Packet) -> case Packet#xmlel.name of 'message' -> case lists:any(fun(J) -> - exmpp_jid:compare_jids(J,From) + exmpp_jid:compare(J,From) end, get_admin_jids()) of true -> Body = exmpp_xml:get_path( From 1b94c7a8b3487c20db6afd09c8466df2f4f0b758 Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 16:50:36 +0000 Subject: [PATCH 342/582] API renaming : compare_bare_jids -> bare_compare SVN Revision: 2130 --- src/ejabberd_c2s.erl | 2 +- src/mod_private.erl | 2 +- src/mod_private_odbc.erl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index c3f2a5e60..8874c441f 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1923,7 +1923,7 @@ check_from(El, FromJID) -> case exmpp_jid:prep_resource(JIDEl) of undefined -> %% Matching JID: The stanza is ok - case exmpp_jid:compare_bare_jids(JIDEl, FromJID) of + case exmpp_jid:bare_compare(JIDEl, FromJID) of true -> El; false -> diff --git a/src/mod_private.erl b/src/mod_private.erl index 275c693fc..2e62669e3 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -121,7 +121,7 @@ check_domain(From, _To, _IQ_Rec) -> % the iq can't be directed to another jid check_user(From, To, _IQ_Rec) -> - case exmpp_jid:compare_bare_jids(From, To) of + case exmpp_jid:bare_compare(From, To) of true -> ok; false -> {error, 'forbidden'} end. diff --git a/src/mod_private_odbc.erl b/src/mod_private_odbc.erl index 3c16b5c79..ecd2a4050 100644 --- a/src/mod_private_odbc.erl +++ b/src/mod_private_odbc.erl @@ -115,7 +115,7 @@ check_domain(From, _To, _IQ_Rec) -> % the iq can't be directed to another jid check_user(From, To, _IQ_Rec) -> - case exmpp_jid:compare_bare_jids(From, To) of + case exmpp_jid:bare_compare(From, To) of true -> ok; false -> {error, 'forbidden'} end. From 15bc238297684d4b32fdde4ac8155c7f67083f7e Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 16:52:14 +0000 Subject: [PATCH 343/582] API renaming : jid_to_list -> to_list SVN Revision: 2131 --- src/ejabberd_captcha.erl | 4 ++-- src/ejd2odbc.erl | 10 +++++----- src/mod_caps.erl | 2 +- src/mod_irc/mod_irc_connection.erl | 2 +- src/mod_muc/mod_muc_log.erl | 2 +- src/mod_muc/mod_muc_room.erl | 2 +- src/mod_offline.erl | 6 +++--- src/mod_offline_odbc.erl | 2 +- src/mod_privacy_odbc.erl | 2 +- src/mod_proxy65/mod_proxy65_stream.erl | 4 ++-- src/mod_pubsub/mod_pubsub.erl | 4 ++-- src/mod_register.erl | 2 +- src/mod_roster.erl | 6 +++--- src/mod_roster_odbc.erl | 6 +++--- src/mod_shared_roster.erl | 2 +- src/mod_vcard.erl | 4 ++-- src/mod_vcard_ldap.erl | 4 ++-- src/mod_vcard_odbc.erl | 4 ++-- src/web/ejabberd_web_admin.erl | 4 ++-- 19 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/ejabberd_captcha.erl b/src/ejabberd_captcha.erl index 8813d82d2..68c91fe69 100644 --- a/src/ejabberd_captcha.erl +++ b/src/ejabberd_captcha.erl @@ -59,7 +59,7 @@ create_captcha(Id, SID, From, To, Lang, Args) case create_image() of {ok, Type, Key, Image} -> B64Image = jlib:encode_base64(binary_to_list(Image)), - JID = exmpp_jid:jid_to_list(From), + JID = exmpp_jid:to_list(From), CID = "sha1+" ++ sha:sha(Image) ++ "@bob.xmpp.org", Data = {xmlelement, "data", [{"xmlns", ?NS_BOB}, {"cid", CID}, @@ -70,7 +70,7 @@ create_captcha(Id, SID, From, To, Lang, Args) %% ?NS_DATA_FORMS is 'jabber:x:data' [{xmlelement, "x", [{"xmlns", "jabber:x:data"}, {"type", "form"}], [?VFIELD("hidden", "FORM_TYPE", {xmlcdata, ?NS_CAPTCHA}), - ?VFIELD("hidden", "from", {xmlcdata, exmpp_jid:jid_to_list(To)}), + ?VFIELD("hidden", "from", {xmlcdata, exmpp_jid:to_list(To)}), ?VFIELD("hidden", "challenge", {xmlcdata, Id}), ?VFIELD("hidden", "sid", {xmlcdata, SID}), {xmlelement, "field", [{"var", "ocr"}, {"label", ?CAPTCHA_TEXT(Lang)}], diff --git a/src/ejd2odbc.erl b/src/ejd2odbc.erl index 86850a49d..f46b45eba 100644 --- a/src/ejd2odbc.erl +++ b/src/ejd2odbc.erl @@ -92,7 +92,7 @@ export_roster(Server, Output) -> fun(Host, #roster{usj = {LUser, LServer, {N, D, Res} = _LJID}} = R) when LServer == Host -> Username = ejabberd_odbc:escape(LUser), - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(N, D, Res)), + SJID = ejabberd_odbc:escape(exmpp_jid:to_list(N, D, Res)), ItemVals = record_to_string(R), ItemGroups = groups_to_string(R), ["delete from rosterusers " @@ -125,8 +125,8 @@ export_offline(Server, Output) -> when LServer == Host -> Username = ejabberd_odbc:escape(LUser), Packet0 = exmpp_stanza:set_jids(Packet, - exmpp_jid:jid_to_list(From), - exmpp_jid:jid_to_list(To)), + exmpp_jid:to_list(From), + exmpp_jid:to_list(To)), Packet1 = exmpp_xml:append_child(Packet0, jlib:timestamp_to_xml( calendar:now_to_universal_time(TimeStamp))), @@ -313,7 +313,7 @@ record_to_string(#roster{usj = {User, _Server, {N, D, R} = _JID}, ask = Ask, askmessage = AskMessage}) -> Username = ejabberd_odbc:escape(User), - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(N, D, R)), + SJID = ejabberd_odbc:escape(exmpp_jid:to_list(N, D, R)), Nick = ejabberd_odbc:escape(Name), SSubscription = case Subscription of both -> "B"; @@ -349,7 +349,7 @@ record_to_string(#roster{usj = {User, _Server, {N, D, R} = _JID}, groups_to_string(#roster{usj = {User, _Server, {N, D, R} = _JID}, groups = Groups}) -> Username = ejabberd_odbc:escape(User), - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_list(N, D, R)), + SJID = ejabberd_odbc:escape(exmpp_jid:to_list(N, D, R)), [["(" "'", Username, "'," "'", SJID, "'," diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 1c90dc2e8..fa872ec3f 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -390,7 +390,7 @@ handle_cast({disco_response, From, _To, #iq{id = ID, type = Type, payload = Payl ?DEBUG("ID '~s' matches no query", [ID]) end; %gen_server:cast(self(), visit_feature_queries), - %?DEBUG("Error IQ reponse from ~s:~n~p", [exmpp_jid:jid_to_list(From), SubEls]); + %?DEBUG("Error IQ reponse from ~s:~n~p", [exmpp_jid:to_list(From), SubEls]); {result, Payload} -> ?DEBUG("Invalid IQ contents from ~s:~n~p", [exmpp_jid:jid_to_binary(From), Payload]); _ -> diff --git a/src/mod_irc/mod_irc_connection.erl b/src/mod_irc/mod_irc_connection.erl index 79d492ef6..afcb91aa4 100644 --- a/src/mod_irc/mod_irc_connection.erl +++ b/src/mod_irc/mod_irc_connection.erl @@ -871,7 +871,7 @@ process_userinfo(StateData, _Nick, From) -> "xmpp:~s" "\001\r\n", [FromUser, - exmpp_jid:jid_to_list(StateData#state.user)])). + exmpp_jid:to_list(StateData#state.user)])). process_topic(StateData, Chan, From, String) -> diff --git a/src/mod_muc/mod_muc_log.erl b/src/mod_muc/mod_muc_log.erl index 7a582e739..f6d1d2ace 100644 --- a/src/mod_muc/mod_muc_log.erl +++ b/src/mod_muc/mod_muc_log.erl @@ -795,7 +795,7 @@ get_room_info(RoomJID, Opts) -> {value, {_, SA}} -> SA; false -> "" end, - #room{jid = exmpp_jid:jid_to_list(RoomJID), + #room{jid = exmpp_jid:to_list(RoomJID), title = Title, subject = Subject, subject_author = SubjectAuthor, diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index a50f08cdd..8d1fdbfdc 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -2825,7 +2825,7 @@ get_config(Lang, StateData, From) -> Res = [#xmlel{name = 'title', children = [ #xmlcdata{cdata = io_lib:format(translate:translate(Lang, "Configuration of room ~s"), - [exmpp_jid:jid_to_list(StateData#state.jid)]) + [exmpp_jid:to_list(StateData#state.jid)]) }]}, #xmlel{name = 'field', attrs = [?XMLATTR('type', <<"hidden">>), ?XMLATTR('var', <<"FORM_TYPE">>)], diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 03217aede..bb9ce561a 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -567,8 +567,8 @@ user_queue(User, Server, Query, Lang) -> io_lib:format( "~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", [Year, Month, Day, Hour, Minute, Second])), - SFrom = exmpp_jid:jid_to_list(From), - STo = exmpp_jid:jid_to_list(To), + SFrom = exmpp_jid:to_list(From), + STo = exmpp_jid:to_list(To), Packet1 = exmpp_stanza:set_jids(Packet, SFrom, STo), FPacket = exmpp_xml:node_to_list( exmpp_xml:indent_document(Packet1, <<" ">>), @@ -636,7 +636,7 @@ user_queue_parse_query(US, Query) -> end. us_to_list({User, Server}) -> - exmpp_jid:jid_to_list(User, Server). + exmpp_jid:to_list(User, Server). webadmin_user(Acc, User, Server, Lang) -> FQueueLen = try diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index d71b3d726..7b3603f01 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -440,7 +440,7 @@ user_queue_parse_query(Username, LServer, Query) -> end. us_to_list({User, Server}) -> - exmpp_jid:jid_to_list(User, Server). + exmpp_jid:to_list(User, Server). webadmin_user(Acc, User, Server, Lang) -> FQueueLen = try diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index aa1c0fedb..3e86dc794 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -747,7 +747,7 @@ item_to_raw(#listitem{type = Type, {"n", ""}; jid -> {N0, D0, R0} = Value, - {"j", exmpp_jid:jid_to_list(N0, D0, R0)}; + {"j", exmpp_jid:to_list(N0, D0, R0)}; group -> {"g", Value}; subscription -> diff --git a/src/mod_proxy65/mod_proxy65_stream.erl b/src/mod_proxy65/mod_proxy65_stream.erl index 29f55c188..f8b421bbf 100644 --- a/src/mod_proxy65/mod_proxy65_stream.erl +++ b/src/mod_proxy65/mod_proxy65_stream.erl @@ -123,8 +123,8 @@ activate({P1, J1}, {P2, J2}) -> {S1, S2} when is_port(S1), is_port(S2) -> P1 ! {activate, P2, S2, J1, J2}, P2 ! {activate, P1, S1, J1, J2}, - JID1 = exmpp_jid:jid_to_list(J1), - JID2 = exmpp_jid:jid_to_list(J2), + JID1 = exmpp_jid:to_list(J1), + JID2 = exmpp_jid:to_list(J2), ?INFO_MSG("(~w:~w) Activated bytestream for ~s -> ~s", [P1, P2, JID1, JID2]), ok; _ -> diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index b22501295..9cae8b368 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -2777,8 +2777,8 @@ max_items(Options) -> -define(JLIST_CONFIG_FIELD(Label, Var, Opts), ?LISTXFIELD(Label, "pubsub#" ++ atom_to_list(Var), - exmpp_jid:jid_to_list(get_option(Options, Var)), - [exmpp_jid:jid_to_list(O) || O <- Opts])). + exmpp_jid:to_list(get_option(Options, Var)), + [exmpp_jid:to_list(O) || O <- Opts])). -define(ALIST_CONFIG_FIELD(Label, Var, Opts), ?LISTXFIELD(Label, "pubsub#" ++ atom_to_list(Var), diff --git a/src/mod_register.erl b/src/mod_register.erl index 218abdad5..d521369bd 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -262,7 +262,7 @@ send_registration_notifications(UJID) -> Body = lists:flatten( io_lib:format( "The user '~s' was just created on node ~w.", - [exmpp_jid:jid_to_list(UJID), node()])), + [exmpp_jid:to_list(UJID), node()])), lists:foreach( fun(S) -> try diff --git a/src/mod_roster.erl b/src/mod_roster.erl index d320ce64e..e73a557b5 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -1197,9 +1197,9 @@ build_contact_jid_td({U, S, R}) -> end, case JIDURI of [] -> - ?XAC('td', [?XMLATTR('class', <<"valign">>)], exmpp_jid:jid_to_list(ContactJID)); + ?XAC('td', [?XMLATTR('class', <<"valign">>)], exmpp_jid:to_list(ContactJID)); URI when is_list(URI) -> - ?XAE('td', [?XMLATTR('class', <<"valign">>)], [?AC(JIDURI, exmpp_jid:jid_to_list(ContactJID))]) + ?XAE('td', [?XMLATTR('class', <<"valign">>)], [?AC(JIDURI, exmpp_jid:to_list(ContactJID))]) end. %% @spec (User, Server, Items, Query) -> ok | nothing | error @@ -1277,7 +1277,7 @@ user_roster_item_parse_query(User, Server, Items, Query) -> {U, S, R} = JID, UJID = exmpp_jid:make(User, Server), Attrs1 = exmpp_xml:set_attribute_in_list([], - 'jid', exmpp_jid:jid_to_list(U, S, R)), + 'jid', exmpp_jid:to_list(U, S, R)), Attrs2 = exmpp_xml:set_attribute_in_list(Attrs1, 'subscription', "remove"), Item = #xmlel{ns = ?NS_ROSTER, name = 'item', diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 7ed173705..f23c04821 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -1032,9 +1032,9 @@ build_contact_jid_td({U, S, R}) -> end, case JIDURI of [] -> - ?XAC('td', [?XMLATTR('class', <<"valign">>)], exmpp_jid:jid_to_list(ContactJID)); + ?XAC('td', [?XMLATTR('class', <<"valign">>)], exmpp_jid:to_list(ContactJID)); URI when is_list(URI) -> - ?XAE('td', [?XMLATTR('class', <<"valign">>)], [?AC(JIDURI, exmpp_jid:jid_to_list(ContactJID))]) + ?XAE('td', [?XMLATTR('class', <<"valign">>)], [?AC(JIDURI, exmpp_jid:to_list(ContactJID))]) end. user_roster_parse_query(User, Server, Items, Query) -> @@ -1095,7 +1095,7 @@ user_roster_item_parse_query(User, Server, Items, Query) -> {value, _} -> UJID = exmpp_jid:make(User, Server), Attrs1 = exmpp_xml:set_attribute_in_list([], - 'jid', exmpp_jid:jid_to_list(JID)), + 'jid', exmpp_jid:to_list(JID)), Attrs2 = exmpp_xml:set_attribute_in_list(Attrs1, 'subscription', "remove"), Item = #xmlel{ns = ?NS_ROSTER, name = 'item', diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 65c87711c..60e0e5234 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -712,7 +712,7 @@ push_roster_item(User, Server, ContactU, ContactS, GroupName, Subscription) -> item_to_xml(Item) -> {U, S, R} = Item#roster.jid, Attrs1 = exmpp_xml:set_attribute_in_list([], - 'jid', exmpp_jid:jid_to_list(U, S, R)), + 'jid', exmpp_jid:to_list(U, S, R)), Attrs2 = case Item#roster.name of "" -> Attrs1; diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index 23eaf66f7..156c88660 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -286,7 +286,7 @@ set_vcard(User, LServer, VCARD) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = - [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ exmpp_jid:jid_to_list(JID))}]}, + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ exmpp_jid:to_list(JID))}]}, #xmlel{ns = ?NS_SEARCH, name = 'instructions', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Fill in the form to search " @@ -441,7 +441,7 @@ search_result(Lang, JID, ServerHost, Data) -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary( translate:translate(Lang, "Search Results for ") ++ - exmpp_jid:jid_to_list(JID))}]}, + exmpp_jid:to_list(JID))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'reported', children = [?TLFIELD(<<"text-single">>, "Jabber ID", <<"jid">>), ?TLFIELD(<<"text-single">>, "Full Name", <<"fn">>), diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index 4ee43b84e..401ad0daf 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -398,7 +398,7 @@ ldap_attribute_to_vcard(_, _) -> [?XMLATTR('type', <<"form">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ - exmpp_jid:jid_to_list(JID))}]}, + exmpp_jid:to_list(JID))}]}, #xmlel{ns = ?NS_SEARCH, name = 'instructions', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Fill in fields to search " "for any matching Jabber User"))}]} @@ -525,7 +525,7 @@ search_result(Lang, JID, State, Data) -> SearchReported = State#state.search_reported, Header = [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search Results for ") ++ - exmpp_jid:jid_to_list(JID))}]}, + exmpp_jid:to_list(JID))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'reported', children = [?TLFIELD(<<"text-single">>, "Jabber ID", <<"jid">>)] ++ lists:map( diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl index e92f164db..6f3cb96d7 100644 --- a/src/mod_vcard_odbc.erl +++ b/src/mod_vcard_odbc.erl @@ -260,7 +260,7 @@ set_vcard(User, LServer, VCARD) -> #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = - [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ exmpp_jid:jid_to_list(JID))}]}, + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ exmpp_jid:to_list(JID))}]}, #xmlel{ns = ?NS_SEARCH, name = 'instructions', children = [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Fill in the form to search " @@ -405,7 +405,7 @@ search_result(Lang, JID, ServerHost, Data) -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = [#xmlcdata{cdata = list_to_binary( translate:translate(Lang, "Search Results for ") ++ - exmpp_jid:jid_to_list(JID))}]}, + exmpp_jid:to_list(JID))}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'reported', children = [?TLFIELD(<<"text-single">>, "Jabber ID", <<"jid">>), ?TLFIELD(<<"text-single">>, "Full Name", <<"fn">>), diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 0fda60468..21892def6 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -1483,10 +1483,10 @@ list_given_users(Users, Prefix, Lang, URLFunc) -> )]). us_to_list({User, Server}) -> - exmpp_jid:jid_to_list(User, Server, undefined). + exmpp_jid:to_list(User, Server, undefined). su_to_list({Server, User}) -> - exmpp_jid:jid_to_list(User, Server, undefined). + exmpp_jid:to_list(User, Server, undefined). get_stats(global, Lang) -> From 0ace8bda8cbddfa1491dfd41cfee4f4531d64eeb Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 16:53:48 +0000 Subject: [PATCH 344/582] API renaming : prepd_jid_to_list -> prep_to_list SVN Revision: 2132 --- src/mod_proxy65/mod_proxy65_service.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod_proxy65/mod_proxy65_service.erl b/src/mod_proxy65/mod_proxy65_service.erl index ba1c43176..c3b4a8766 100644 --- a/src/mod_proxy65/mod_proxy65_service.erl +++ b/src/mod_proxy65/mod_proxy65_service.erl @@ -163,8 +163,8 @@ process_iq(InitiatorJID, #iq{type = set, payload = SubEl, ns = ?NS_BYTESTREAMS} case catch exmpp_jid:parse(exmpp_xml:get_cdata_as_string(ActivateEl)) of TargetJID when ?IS_JID(TargetJID), SID /= "", length(SID) =< 128, TargetJID /= InitiatorJID -> - Target = exmpp_jid:prepd_jid_to_list(TargetJID), - Initiator = exmpp_jid:prepd_jid_to_list(InitiatorJID), + Target = exmpp_jid:prep_to_list(TargetJID), + Initiator = exmpp_jid:prep_to_list(InitiatorJID), SHA1 = sha:sha(SID ++ Initiator ++ Target), case mod_proxy65_sm:activate_stream(SHA1, InitiatorJID, TargetJID, ServerHost) of ok -> From 7a884ced32d53866213f669b4f03486f3a49614c Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 16:54:33 +0000 Subject: [PATCH 345/582] API renaming : bare_jid_to_list -> bare_to_list SVN Revision: 2133 --- src/mod_roster.erl | 2 +- src/mod_roster_odbc.erl | 2 +- src/mod_shared_roster.erl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mod_roster.erl b/src/mod_roster.erl index e73a557b5..7b8bb3ea1 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -1303,7 +1303,7 @@ user_roster_item_parse_query(User, Server, Items, Query) -> %% Server = binary() us_to_list({User, Server}) -> - exmpp_jid:bare_jid_to_list(User, Server). + exmpp_jid:bare_to_list(User, Server). %% @spec (Acc, User, Server, Lang) -> New_Acc %% Acc = [ejabberd_web:html()] diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index f23c04821..9c0548669 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -1117,7 +1117,7 @@ user_roster_item_parse_query(User, Server, Items, Query) -> nothing. us_to_list({User, Server}) -> - exmpp_jid:bare_jid_to_list(User, Server). + exmpp_jid:bare_to_list(User, Server). webadmin_user(Acc, _User, _Server, Lang) -> Acc ++ [?XE("h3", [?ACT("roster/", "Roster")])]. diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 60e0e5234..da7b72357 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -996,4 +996,4 @@ get_opt(Opts, Opt, Default) -> end. us_to_list({User, Server}) -> - exmpp_jid:bare_jid_to_list(User, Server). + exmpp_jid:bare_to_list(User, Server). From 9abe47f35032a609d3df8e277af6d6de8fffc316 Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 16:59:08 +0000 Subject: [PATCH 346/582] API renaming : jid_to_binary -> to_binary SVN Revision: 2134 --- src/ejabberd_c2s.erl | 14 ++++++------ src/mod_adhoc.erl | 2 +- src/mod_caps.erl | 10 ++++----- src/mod_configure.erl | 22 +++++++++---------- src/mod_disco.erl | 2 +- src/mod_echo.erl | 2 +- src/mod_muc/mod_muc.erl | 2 +- src/mod_muc/mod_muc_room.erl | 40 +++++++++++++++++------------------ src/mod_privacy.erl | 2 +- src/mod_privacy_odbc.erl | 2 +- src/mod_pubsub/mod_pubsub.erl | 20 +++++++++--------- src/mod_roster.erl | 6 +++--- src/mod_roster_odbc.erl | 22 +++++++++---------- 13 files changed, 73 insertions(+), 73 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 8874c441f..8569fcea9 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -415,7 +415,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> ?INFO_MSG( "(~w) Accepted legacy authentication for ~s by ~s", [StateData#state.socket, - exmpp_jid:jid_to_binary(JID), AuthModule]), + exmpp_jid:to_binary(JID), AuthModule]), SID = {now(), self()}, Conn = get_conn_type(StateData), Info = [{ip, StateData#state.ip}, {conn, Conn}, @@ -454,7 +454,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> ?INFO_MSG( "(~w) Failed legacy authentication for ~s", [StateData#state.socket, - exmpp_jid:jid_to_binary(JID)]), + exmpp_jid:to_binary(JID)]), Res = exmpp_iq:error_without_original(El, 'not-authorized'), send_element(StateData, Res), @@ -464,7 +464,7 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> ?INFO_MSG( "(~w) Forbidden legacy authentication for ~s", [StateData#state.socket, - exmpp_jid:jid_to_binary(JID)]), + exmpp_jid:to_binary(JID)]), Res = exmpp_iq:error_without_original(El, 'not-allowed'), send_element(StateData, Res), @@ -733,7 +733,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> allow -> ?INFO_MSG("(~w) Opened session for ~s", [StateData#state.socket, - exmpp_jid:jid_to_binary(JID)]), + exmpp_jid:to_binary(JID)]), SID = {now(), self()}, Conn = get_conn_type(StateData), Info = [{ip, StateData#state.ip}, {conn, Conn}, @@ -770,7 +770,7 @@ wait_for_session({xmlstreamelement, El}, StateData) -> StateData#state.server, [JID]), ?INFO_MSG("(~w) Forbidden session for ~s", [StateData#state.socket, - exmpp_jid:jid_to_binary(JID)]), + exmpp_jid:to_binary(JID)]), Err = exmpp_server_session:error(El, 'not-allowed'), send_element(StateData, Err), fsm_next_state(wait_for_session, StateData) @@ -1222,7 +1222,7 @@ terminate(_Reason, StateName, StateData) -> replaced -> ?INFO_MSG("(~w) Replaced session for ~s", [StateData#state.socket, - exmpp_jid:jid_to_binary(StateData#state.jid)]), + exmpp_jid:to_binary(StateData#state.jid)]), From = StateData#state.jid, Packet = exmpp_presence:unavailable(), Packet1 = exmpp_presence:set_status(Packet, @@ -1238,7 +1238,7 @@ terminate(_Reason, StateName, StateData) -> _ -> ?INFO_MSG("(~w) Close session for ~s", [StateData#state.socket, - exmpp_jid:jid_to_binary(StateData#state.jid)]), + exmpp_jid:to_binary(StateData#state.jid)]), EmptySet = ?SETS:new(), case StateData of diff --git a/src/mod_adhoc.erl b/src/mod_adhoc.erl index d71f5b2d9..782465a30 100644 --- a/src/mod_adhoc.erl +++ b/src/mod_adhoc.erl @@ -126,7 +126,7 @@ get_sm_commands(Acc, _From, To, <<>>, Lang) -> end, Nodes = [#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [?XMLATTR('jid', exmpp_jid:jid_to_binary(To)), + [?XMLATTR('jid', exmpp_jid:to_binary(To)), ?XMLATTR('node', ?NS_ADHOC_s), ?XMLATTR('name', translate:translate(Lang, "Commands"))] }], diff --git a/src/mod_caps.erl b/src/mod_caps.erl index fa872ec3f..bc567b669 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -106,7 +106,7 @@ get_caps(LJID) -> get_caps(_, 0) -> nothing; get_caps({U, S, R}, Retry) -> - BJID = exmpp_jid:jid_to_binary(U, S, R), + BJID = exmpp_jid:to_binary(U, S, R), case catch mnesia:dirty_read({user_caps, BJID}) of [#user_caps{caps=waiting}] -> timer:sleep(2000), @@ -120,7 +120,7 @@ get_caps({U, S, R}, Retry) -> %% clear_caps removes user caps from database clear_caps(JID) -> R = exmpp_jid:prep_resource(JID), - BJID = exmpp_jid:jid_to_binary(JID), + BJID = exmpp_jid:to_binary(JID), BUID = exmpp_jid:bare_jid_to_binary(JID), catch mnesia:dirty_delete({user_caps, BJID}), catch mnesia:dirty_delete_object(#user_caps_resources{uid = BUID, resource = list_to_binary(R)}), @@ -317,7 +317,7 @@ handle_cast({note_caps, From, U = exmpp_jid:prep_node(From), S = exmpp_jid:prep_domain(From), R = exmpp_jid:resource(From), - BJID = exmpp_jid:jid_to_binary(From), + BJID = exmpp_jid:to_binary(From), mnesia:transaction(fun() -> mnesia:dirty_write(#user_caps{jid = BJID, caps = caps_to_binary(Caps)}), case ejabberd_sm:get_user_resources(U, S) of @@ -360,7 +360,7 @@ handle_cast({note_caps, From, {noreply, State#state{disco_requests = NewRequests}} end; handle_cast({wait_caps, From}, State) -> - BJID = exmpp_jid:jid_to_binary(From), + BJID = exmpp_jid:to_binary(From), mnesia:dirty_write(#user_caps{jid = BJID, caps = waiting}), {noreply, State}; handle_cast({disco_response, From, _To, #iq{id = ID, type = Type, payload = Payload}}, @@ -392,7 +392,7 @@ handle_cast({disco_response, From, _To, #iq{id = ID, type = Type, payload = Payl %gen_server:cast(self(), visit_feature_queries), %?DEBUG("Error IQ reponse from ~s:~n~p", [exmpp_jid:to_list(From), SubEls]); {result, Payload} -> - ?DEBUG("Invalid IQ contents from ~s:~n~p", [exmpp_jid:jid_to_binary(From), Payload]); + ?DEBUG("Invalid IQ contents from ~s:~n~p", [exmpp_jid:to_binary(From), Payload]); _ -> %% Can't do anything about errors ok diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 7b1e909bf..b947e7424 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -100,7 +100,7 @@ stop(Host) -> -define(NODEJID(To, Name, Node), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [?XMLATTR('jid', exmpp_jid:jid_to_binary(To)), + [?XMLATTR('jid', exmpp_jid:to_binary(To)), ?XMLATTR('name', ?T(Lang, Name)), ?XMLATTR('node', Node)]}). @@ -263,7 +263,7 @@ adhoc_sm_items(Acc, From, To, Lang) -> empty -> [] end, Nodes = [#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [?XMLATTR('jid', exmpp_jid:jid_to_binary(To)), + [?XMLATTR('jid', exmpp_jid:to_binary(To)), ?XMLATTR('name', ?T(Lang, "Configuration")), ?XMLATTR('node', <<"config">>)]}], {result, Items ++ Nodes}; @@ -303,7 +303,7 @@ get_user_resources(BareJID) -> lists:map(fun(R) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', - exmpp_jid:jid_to_binary( + exmpp_jid:to_binary( exmpp_jid:full(BareJID, R))), ?XMLATTR('name', exmpp_jid:prep_node(BareJID))]} @@ -382,7 +382,7 @@ get_permission_level(JID) -> allow -> PermLev = get_permission_level(From), case get_local_items({PermLev, LServer}, LNode, - exmpp_jid:jid_to_binary(To), Lang) of + exmpp_jid:to_binary(To), Lang) of {result, Res} -> {result, Res}; {error, Error} -> @@ -407,7 +407,7 @@ get_local_items(Acc, From, To, <<>>, Lang) -> allow -> PermLev = get_permission_level(From), case get_local_items({PermLev, LServer}, [], - exmpp_jid:jid_to_binary(To), Lang) of + exmpp_jid:to_binary(To), Lang) of {result, Res} -> {result, Items ++ Res}; {error, _Error} -> @@ -530,8 +530,8 @@ get_local_items({_, Host}, ["all users", [$@ | Diap]], _Server, _Lang) -> Sub = lists:sublist(SUsers, N1, N2 - N1 + 1), lists:map(fun({S, U}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [?XMLATTR('jid', exmpp_jid:jid_to_binary(U, S)), - ?XMLATTR('name', exmpp_jid:jid_to_binary(U, S))]} + [?XMLATTR('jid', exmpp_jid:to_binary(U, S)), + ?XMLATTR('name', exmpp_jid:to_binary(U, S))]} end, Sub) end of {'EXIT', _Reason} -> @@ -623,8 +623,8 @@ get_online_vh_users(Host) -> SURs = lists:sort([{S, U, R} || {U, S, R} <- USRs]), lists:map(fun({S, U, R}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [?XMLATTR('jid', exmpp_jid:jid_to_binary(U, S, R)), - ?XMLATTR('name', exmpp_jid:jid_to_binary(U, S))]} + [?XMLATTR('jid', exmpp_jid:to_binary(U, S, R)), + ?XMLATTR('name', exmpp_jid:to_binary(U, S))]} end, SURs) end. @@ -638,8 +638,8 @@ get_all_vh_users(Host) -> N when N =< 100 -> lists:map(fun({S, U}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [?XMLATTR('jid', exmpp_jid:jid_to_binary(U, S)), - ?XMLATTR('name', exmpp_jid:jid_to_binary(U, S))]} + [?XMLATTR('jid', exmpp_jid:to_binary(U, S)), + ?XMLATTR('name', exmpp_jid:to_binary(U, S))]} end, SUsers); N -> NParts = trunc(math:sqrt(N * 0.618)) + 1, diff --git a/src/mod_disco.erl b/src/mod_disco.erl index f8dd45e71..2a47ac993 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -397,7 +397,7 @@ get_user_resources(JID) -> lists:map(fun(R) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [ ?XMLATTR('jid', - exmpp_jid:jid_to_binary(exmpp_jid:full(JID, R))), + exmpp_jid:to_binary(exmpp_jid:full(JID, R))), ?XMLATTR('name', exmpp_jid:prep_node(JID)) ]} end, lists:sort(Rs)). diff --git a/src/mod_echo.erl b/src/mod_echo.erl index 27a2850a5..9927b24b8 100644 --- a/src/mod_echo.erl +++ b/src/mod_echo.erl @@ -199,5 +199,5 @@ do_client_version(enabled, From, To) -> %% Print in log Values_string1 = [io_lib:format("~n~s: ~p", [N, V]) || {N, V} <- Values], Values_string2 = lists:concat(Values_string1), - ?INFO_MSG("Information of the client: ~s~s", [exmpp_jid:jid_to_binary(To), Values_string2]). + ?INFO_MSG("Information of the client: ~s~s", [exmpp_jid:to_binary(To), Values_string2]). diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index 3ccb7e3ac..15c924d1c 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -569,7 +569,7 @@ iq_disco_items(Host, From, Lang, none) when is_binary(Host) -> {true, #xmlel{name = 'item', attrs = [?XMLATTR('jid', - exmpp_jid:jid_to_binary(Name, + exmpp_jid:to_binary(Name, Host)), ?XMLATTR('name', Desc)]}}; diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 8d1fdbfdc..b68878ee3 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -132,7 +132,7 @@ init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Creator, _Nick, D room_shaper = Shaper}), State1 = set_opts(DefRoomOpts, State), ?INFO_MSG("Created MUC room ~s@~s by ~s", - [Room, Host, exmpp_jid:jid_to_binary(Creator)]), + [Room, Host, exmpp_jid:to_binary(Creator)]), {ok, normal_state, State1}; init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts]) -> process_flag(trap_exit, true), @@ -585,11 +585,11 @@ handle_event({destroy, Reason}, _StateName, StateData) -> end}, StateData), ?INFO_MSG("Destroyed MUC room ~s with reason: ~p", - [exmpp_jid:jid_to_binary(StateData#state.jid), Reason]), + [exmpp_jid:to_binary(StateData#state.jid), Reason]), {stop, normal, StateData}; handle_event(destroy, StateName, StateData) -> ?INFO_MSG("Destroyed MUC room ~s", - [exmpp_jid:jid_to_binary(StateData#state.jid)]), + [exmpp_jid:to_binary(StateData#state.jid)]), handle_event({destroy, none}, StateName, StateData); handle_event({set_affiliations, Affiliations}, StateName, StateData) -> @@ -984,7 +984,7 @@ process_presence(From, Nick, #xmlel{name = 'presence'} = Packet, (?DICT:to_list(StateData1#state.users) == []) of true -> ?INFO_MSG("Destroyed MUC room ~s because it's temporary and empty", - [exmpp_jid:jid_to_binary(StateData#state.jid)]), + [exmpp_jid:to_binary(StateData#state.jid)]), {stop, normal, StateData1}; _ -> {next_state, normal_state, StateData1} @@ -1036,7 +1036,7 @@ decide_fate_message(error, Packet, From, StateData) -> %% If this is an error stanza and its condition matches a criteria true -> Reason = io_lib:format("This participant is considered a ghost and is expulsed: ~s", - [exmpp_jid:jid_to_binary(From)]), + [exmpp_jid:to_binary(From)]), {expulse_sender, Reason}; false -> continue_delivery @@ -1833,7 +1833,7 @@ send_new_presence(NJID, Reason, StateData) -> case (Info#user.role == moderator) orelse ((StateData#state.config)#config.anonymous == false) of true -> - [?XMLATTR('jid', exmpp_jid:jid_to_binary(RealJID)), + [?XMLATTR('jid', exmpp_jid:to_binary(RealJID)), ?XMLATTR('affiliation', SAffiliation), ?XMLATTR('role', SRole)]; _ -> @@ -1889,7 +1889,7 @@ send_existing_presences(ToJID, StateData) -> ((StateData#state.config)#config.anonymous == false) of true -> - [?XMLATTR('jid', exmpp_jid:jid_to_binary(FromJID)), + [?XMLATTR('jid', exmpp_jid:to_binary(FromJID)), ?XMLATTR('affiliation', affiliation_to_binary(FromAffiliation)), ?XMLATTR('role', role_to_binary(FromRole))]; @@ -1946,7 +1946,7 @@ send_nick_changing(JID, OldNick, StateData) -> case (Info#user.role == moderator) orelse ((StateData#state.config)#config.anonymous == false) of true -> - [?XMLATTR('jid', exmpp_jid:jid_to_binary(RealJID)), + [?XMLATTR('jid', exmpp_jid:to_binary(RealJID)), ?XMLATTR('affiliation', SAffiliation), ?XMLATTR('role', SRole), ?XMLATTR('nick', Nick)]; @@ -1959,7 +1959,7 @@ send_nick_changing(JID, OldNick, StateData) -> case (Info#user.role == moderator) orelse ((StateData#state.config)#config.anonymous == false) of true -> - [?XMLATTR('jid', exmpp_jid:jid_to_binary(RealJID)), + [?XMLATTR('jid', exmpp_jid:to_binary(RealJID)), ?XMLATTR('affiliation', SAffiliation), ?XMLATTR('role', SRole)]; _ -> @@ -2151,7 +2151,7 @@ items_with_affiliation(SAffiliation, StateData) -> attrs = [?XMLATTR('affiliation', affiliation_to_binary(Affiliation)), ?XMLATTR('jid', - exmpp_jid:jid_to_binary(N, D, R))], + exmpp_jid:to_binary(N, D, R))], children = [ #xmlel{name = 'reason', children = [#xmlcdata{cdata = Reason}]}]}; @@ -2161,7 +2161,7 @@ items_with_affiliation(SAffiliation, StateData) -> attrs = [?XMLATTR('affiliation', affiliation_to_binary(Affiliation)), ?XMLATTR('jid', - exmpp_jid:jid_to_binary(N, D, R))]} + exmpp_jid:to_binary(N, D, R))]} end, search_affiliation(SAffiliation, StateData)). user_to_item(#user{role = Role, @@ -2174,7 +2174,7 @@ user_to_item(#user{role = Role, ?XMLATTR('role', role_to_binary(Role)), ?XMLATTR('affiliation', affiliation_to_binary(Affiliation)), ?XMLATTR('nick', Nick), - ?XMLATTR('jid', exmpp_jid:jid_to_binary(JID))] + ?XMLATTR('jid', exmpp_jid:to_binary(JID))] }. search_role(Role, StateData) -> @@ -2201,7 +2201,7 @@ process_admin_items_set(UJID, Items, Lang, StateData) -> case find_changed_items(UJID, UAffiliation, URole, Items, Lang, StateData, []) of {result, Res} -> ?INFO_MSG("Processing MUC admin query from ~s in room ~s:~n ~p", - [exmpp_jid:jid_to_binary(UJID), exmpp_jid:jid_to_binary(StateData#state.jid), Res]), + [exmpp_jid:to_binary(UJID), exmpp_jid:to_binary(StateData#state.jid), Res]), NSD = lists:foldl( fun(E, SD) -> @@ -2693,7 +2693,7 @@ process_iq_owner(From, set, Lang, SubEl, StateData) -> end; [#xmlel{name = 'destroy'} = SubEl1] -> ?INFO_MSG("Destroyed MUC room ~s by the owner ~s", - [exmpp_jid:jid_to_binary(StateData#state.jid), exmpp_jid:jid_to_binary(From)]), + [exmpp_jid:to_binary(StateData#state.jid), exmpp_jid:to_binary(From)]), destroy_room(SubEl1, StateData); Items -> process_admin_items_set(From, Items, Lang, StateData) @@ -3289,7 +3289,7 @@ process_iq_disco_items(From, get, _Lang, StateData) -> fun({_LJID, Info}) -> Nick = Info#user.nick, #xmlel{name = 'item', attrs = [?XMLATTR('jid', - exmpp_jid:jid_to_binary( + exmpp_jid:to_binary( StateData#state.room, StateData#state.host, Nick)), @@ -3371,7 +3371,7 @@ check_invitation(From, Els, Lang, StateData) -> [#xmlel{ns = ?NS_MUC_USER, name = 'invite', attrs = [?XMLATTR('from', - exmpp_jid:jid_to_binary(From))], + exmpp_jid:to_binary(From))], children = [#xmlel{ns =?NS_MUC_USER, name = 'reason', children = [#xmlcdata{cdata = Reason} ]}] ++ ContinueEl}], @@ -3391,8 +3391,8 @@ check_invitation(From, Els, Lang, StateData) -> io_lib:format( translate:translate(Lang, "~s invites you to the room ~s"), - [exmpp_jid:jid_to_binary(From), - exmpp_jid:jid_to_binary(StateData#state.room, + [exmpp_jid:to_binary(From), + exmpp_jid:to_binary(StateData#state.room, StateData#state.host) ]), case (StateData#state.config)#config.password_protected of @@ -3417,7 +3417,7 @@ check_invitation(From, Els, Lang, StateData) -> children = IEl ++ PasswdEl}, #xmlel{ns = 'jabber:x:conference', name = 'x', attrs = [?XMLATTR('jid', - exmpp_jid:jid_to_binary( + exmpp_jid:to_binary( StateData#state.room, StateData#state.host) )], @@ -3454,7 +3454,7 @@ check_decline_invitation(Packet) -> %% The original stanza must be slightly modified. send_decline_invitation({Packet, XEl, DEl = #xmlel{name='decline'}, ToJID}, RoomJID, FromJID) -> - FromString = exmpp_jid:jid_to_binary(FromJID), + FromString = exmpp_jid:to_binary(FromJID), DEl1 = exmpp_xml:remove_attribute(DEl, 'to'), DEl2 = exmpp_xml:set_attribute(DEl1, 'from',FromString), diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 3b53a2bf1..ca6ec8f68 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -224,7 +224,7 @@ value_to_binary(Type, Val) -> case Type of jid -> {N, D, R} = Val, - exmpp_jid:jid_to_binary(N, D, R); + exmpp_jid:to_binary(N, D, R); group -> Val; subscription -> case Val of diff --git a/src/mod_privacy_odbc.erl b/src/mod_privacy_odbc.erl index 3e86dc794..e38b4734b 100644 --- a/src/mod_privacy_odbc.erl +++ b/src/mod_privacy_odbc.erl @@ -230,7 +230,7 @@ value_to_binary(Type, Val) -> case Type of jid -> {N, D, R} = Val, - exmpp_jid:jid_to_binary(N, D, R); + exmpp_jid:to_binary(N, D, R); group -> Val; subscription -> case Val of diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 9cae8b368..7ce313d3d 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -580,7 +580,7 @@ disco_sm_items(Acc, From, To, <<>>, _Lang) -> NodeItems = lists:map( fun(#pubsub_node{nodeid = {_, Node}}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [?XMLATTR('jid', exmpp_jid:jid_to_binary(LJID)), + [?XMLATTR('jid', exmpp_jid:to_binary(LJID)), ?XMLATTR('node', node_to_string(Node))]} end, Nodes), {result, NodeItems ++ Items} @@ -606,7 +606,7 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) -> %% "node" is forbidden by XEP-0060. {result, Name} = node_action(Host, Node, get_item_name, [NodeId, Id]), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [?XMLATTR('jid', exmpp_jid:jid_to_binary(LJID)), + [?XMLATTR('jid', exmpp_jid:to_binary(LJID)), ?XMLATTR('name', Name)]} end, AllItems), {result, NodeItems ++ Items}; @@ -1250,7 +1250,7 @@ send_authorization_request(#pubsub_node{owners = Owners, nodeid = {Host, Node}}, ?XMLATTR('type', <<"jid-single">>), ?XMLATTR('label', translate:translate(Lang, "Subscriber Address"))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = - [#xmlcdata{cdata = exmpp_jid:jid_to_binary(U, S, R)}]}]}, + [#xmlcdata{cdata = exmpp_jid:to_binary(U, S, R)}]}]}, #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('var', <<"pubsub#allow">>), ?XMLATTR('type', <<"boolean">>), @@ -1296,7 +1296,7 @@ send_authorization_approval(Host, JID, SNode, Subscription) -> Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'subscription', attrs = [?XMLATTR('node', SNode), - ?XMLATTR('jid', exmpp_jid:jid_to_binary(JID)), + ?XMLATTR('jid', exmpp_jid:to_binary(JID)), ?XMLATTR('subscription', subscription_to_string(Subscription))]}]), ejabberd_router ! {route, service_jid(Host), JID, Stanza}. @@ -1633,7 +1633,7 @@ subscribe_node(Host, Node, From, JID) -> %% TODO, this is subscription-notification, should depends on node features Fields = [?XMLATTR('node', node_to_string(Node)), - ?XMLATTR('jid', exmpp_jid:jid_to_binary(Subscriber)), + ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), ?XMLATTR('subscription', subscription_to_string(Subscription))], [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = @@ -2104,7 +2104,7 @@ get_affiliations(Host, Node, JID) -> fun({_, none}) -> []; ({{AU, AS, AR}, Affiliation}) -> [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'affiliation', attrs = - [?XMLATTR('jid', exmpp_jid:jid_to_binary(AU, AS, AR)), + [?XMLATTR('jid', exmpp_jid:to_binary(AU, AS, AR)), ?XMLATTR('affiliation', affiliation_to_string(Affiliation))]}] end, Affiliations), {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = @@ -2230,11 +2230,11 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> [] -> [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = [?XMLATTR('node', node_to_string(SubsNode)), - ?XMLATTR('jid', exmpp_jid:jid_to_binary(SubJID)), + ?XMLATTR('jid', exmpp_jid:to_binary(SubJID)), ?XMLATTR('subscription', subscription_to_string(Subscription))]}]; SubsNode -> [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = - [?XMLATTR('jid', exmpp_jid:jid_to_binary(SubJID)), + [?XMLATTR('jid', exmpp_jid:to_binary(SubJID)), ?XMLATTR('subscription', subscription_to_string(Subscription))]}]; _ -> [] @@ -2270,11 +2270,11 @@ get_subscriptions(Host, Node, JID) -> fun({_, none}) -> []; ({{AU, AS, AR}, Subscription}) -> [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscription', attrs = - [?XMLATTR('jid', exmpp_jid:jid_to_binary(AU, AS, AR)), + [?XMLATTR('jid', exmpp_jid:to_binary(AU, AS, AR)), ?XMLATTR('subscription', subscription_to_string(Subscription))]}]; ({{AU, AS, AR}, Subscription, SubId}) -> [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscription', attrs = - [?XMLATTR('jid', exmpp_jid:jid_to_binary(AU, AS, AR)), + [?XMLATTR('jid', exmpp_jid:to_binary(AU, AS, AR)), ?XMLATTR('subscription', subscription_to_string(Subscription)), ?XMLATTR('subid', SubId)]}] end, Subscriptions), diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 7b8bb3ea1..709174c69 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -200,7 +200,7 @@ get_user_roster(Acc, {U, S} = US) when is_binary(U), is_binary(S) -> item_to_xml(Item) -> {U, S, R} = Item#roster.jid, Attrs1 = exmpp_xml:set_attribute_in_list([], - 'jid', exmpp_jid:jid_to_binary(U, S, R)), + 'jid', exmpp_jid:to_binary(U, S, R)), Attrs2 = case Item#roster.name of <<>> -> Attrs1; @@ -853,8 +853,8 @@ get_in_pending_subscriptions(Ls, User, Server) {U0, S0, R0} = R#roster.jid, Pres1 = exmpp_presence:subscribe(), Pres2 = exmpp_stanza:set_jids(Pres1, - exmpp_jid:jid_to_binary(U0, S0, R0), - exmpp_jid:jid_to_binary(JID)), + exmpp_jid:to_binary(U0, S0, R0), + exmpp_jid:to_binary(JID)), exmpp_presence:set_status(Pres2, Message) end, lists:filter( diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 9c0548669..64e125e4a 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -160,7 +160,7 @@ get_roster(LUser, LServer) when is_binary(LUser), is_binary(LServer)-> []; R -> {U2, S2, R2} = R#roster.jid, - SJID = exmpp_jid:jid_to_binary(U2, S2, R2), + SJID = exmpp_jid:to_binary(U2, S2, R2), Groups = lists:flatmap( fun({S, G}) when S == SJID -> [G]; @@ -179,7 +179,7 @@ get_roster(LUser, LServer) when is_binary(LUser), is_binary(LServer)-> item_to_xml(Item) -> {U, S, R} = Item#roster.jid, Attrs1 = exmpp_xml:set_attribute_in_list([], - 'jid', exmpp_jid:jid_to_binary(U, S, R)), + 'jid', exmpp_jid:to_binary(U, S, R)), Attrs2 = case Item#roster.name of <<>> -> Attrs1; @@ -222,7 +222,7 @@ process_item_set(From, To, #xmlel{} = El) -> LServer = binary_to_list(Server), {U0, S0, R0} = LJID = jlib:short_prepd_jid(JID1), Username = ejabberd_odbc:escape(User), - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_binary(U0, S0, R0)), + SJID = ejabberd_odbc:escape(exmpp_jid:to_binary(U0, S0, R0)), F = fun() -> {selected, ["username", "jid", "nick", "subscription", @@ -426,7 +426,7 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) LServer = binary_to_list(Server), {N0,D0,R0} = LJID = jlib:short_prepd_jid(JID1), Username = ejabberd_odbc:escape(User), - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_binary(N0,D0,R0)), + SJID = ejabberd_odbc:escape(exmpp_jid:to_binary(N0,D0,R0)), F = fun() -> Item = case odbc_queries:get_roster_by_jid(LServer, Username, SJID) of @@ -699,7 +699,7 @@ process_item_set_t(LUser, LServer, #xmlel{} = El) -> JID1 = exmpp_jid:parse(exmpp_xml:get_attribute_as_binary(El, 'jid', <<>>)), {U0, S0, R0} = LJID = jlib:short_prepd_jid(JID1), Username = ejabberd_odbc:escape(LUser), - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_binary(U0, S0, R0)), + SJID = ejabberd_odbc:escape(exmpp_jid:to_binary(U0, S0, R0)), Item = #roster{usj = {LUser, LServer, LJID}, us = {LUser, LServer}, jid = LJID}, @@ -768,8 +768,8 @@ get_in_pending_subscriptions(Ls, User, Server) {U0, S0, R0} = R#roster.jid, Pres1 = exmpp_presence:subscribe(), Pres2 = exmpp_stanza:set_jids(Pres1, - exmpp_jid:jid_to_binary(U0, S0, R0), - exmpp_jid:jid_to_binary(JID)), + exmpp_jid:to_binary(U0, S0, R0), + exmpp_jid:to_binary(JID)), exmpp_presence:set_status(Pres2, Message) end, lists:flatmap( @@ -800,7 +800,7 @@ get_jid_info(_, User, Server, JID) when is_binary(User), is_binary(Server) -> LServer = binary_to_list(Server), LJID = {N, D, R} = jlib:short_prepd_jid(JID), Username = ejabberd_odbc:escape(User), - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_binary(N, D, R)), + SJID = ejabberd_odbc:escape(exmpp_jid:to_binary(N, D, R)), case catch odbc_queries:get_subscription(LServer, Username, SJID) of {selected, ["subscription"], [{SSubscription}]} -> Subscription = case SSubscription of @@ -823,7 +823,7 @@ get_jid_info(_, User, Server, JID) when is_binary(User), is_binary(Server) -> {none, []}; true -> {LR_N, LR_D, LR_R} = LRJID, - SRJID = ejabberd_odbc:escape(exmpp_jid:jid_to_binary(LR_N, LR_D, LR_R)), + SRJID = ejabberd_odbc:escape(exmpp_jid:to_binary(LR_N, LR_D, LR_R)), case catch odbc_queries:get_subscription(LServer, Username, SRJID) of {selected, ["subscription"], [{SSubscription}]} -> Subscription = case SSubscription of @@ -891,7 +891,7 @@ record_to_string(#roster{us = {User, _Server}, askmessage = AskMessage}) -> Username = ejabberd_odbc:escape(User), {U, S, R} = JID, - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_binary(U, S, R)), + SJID = ejabberd_odbc:escape(exmpp_jid:to_binary(U, S, R)), Nick = ejabberd_odbc:escape(Name), SSubscription = case Subscription of both -> "B"; @@ -915,7 +915,7 @@ groups_to_string(#roster{us = {User, _Server}, groups = Groups}) -> Username = ejabberd_odbc:escape(User), {U, S, R} = JID, - SJID = ejabberd_odbc:escape(exmpp_jid:jid_to_binary(U, S, R)), + SJID = ejabberd_odbc:escape(exmpp_jid:to_binary(U, S, R)), %% Empty groups do not need to be converted to string to be inserted in %% the database From 437c9d07f55811d75ca624ac18c6dc30c86e90ce Mon Sep 17 00:00:00 2001 From: Karim Gemayel <kgemayel@process-one.net> Date: Mon, 1 Jun 2009 17:00:44 +0000 Subject: [PATCH 347/582] API renaming : bare_jid_to_binary -> bare_to_binary SVN Revision: 2135 --- src/mod_caps.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mod_caps.erl b/src/mod_caps.erl index bc567b669..218d3ba1a 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -121,14 +121,14 @@ get_caps({U, S, R}, Retry) -> clear_caps(JID) -> R = exmpp_jid:prep_resource(JID), BJID = exmpp_jid:to_binary(JID), - BUID = exmpp_jid:bare_jid_to_binary(JID), + BUID = exmpp_jid:bare_to_binary(JID), catch mnesia:dirty_delete({user_caps, BJID}), catch mnesia:dirty_delete_object(#user_caps_resources{uid = BUID, resource = list_to_binary(R)}), ok. %% give default user resource get_user_resources(U, S) -> - BUID = exmpp_jid:bare_jid_to_binary(U, S), + BUID = exmpp_jid:bare_to_binary(U, S), case catch mnesia:dirty_read({user_caps_resources, BUID}) of {'EXIT', _} -> []; @@ -323,7 +323,7 @@ handle_cast({note_caps, From, case ejabberd_sm:get_user_resources(U, S) of [] -> % only store resource of caps aware external contacts - BUID = exmpp_jid:bare_jid_to_binary(From), + BUID = exmpp_jid:bare_to_binary(From), mnesia:dirty_write(#user_caps_resources{uid = BUID, resource = list_to_binary(R)}); _ -> ok From ff3fd0211553f436e2b33f0f6cc5abd38cf833ea Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Mon, 1 Jun 2009 21:04:11 +0000 Subject: [PATCH 348/582] Fix Access check: the rule can be defined in a vhost or global. SVN Revision: 2137 --- src/ejabberd_commands.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl index 19b5e5967..3a94712fe 100644 --- a/src/ejabberd_commands.erl +++ b/src/ejabberd_commands.erl @@ -394,7 +394,7 @@ get_md5(AccountPass) -> check_access(Access, User, Server) -> %% Check this user has access permission - case acl:match_rule(global, Access, jlib:make_jid(User, Server, "")) of + case acl:match_rule(Server, Access, jlib:make_jid(User, Server, "")) of allow -> true; deny -> false end. From 332de67fe266be09767d6c80e87e732368538885 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Mon, 1 Jun 2009 21:04:16 +0000 Subject: [PATCH 349/582] Fix some calls to exmpp SVN Revision: 2138 --- src/ejabberd_c2s.erl | 4 ++-- src/mod_muc/mod_muc_room.erl | 2 +- src/mod_pubsub/mod_pubsub.erl | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 8569fcea9..9fd4a3767 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -333,7 +333,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> send_element(StateData, exmpp_xml:append_child(Header, exmpp_stream:error('policy-violation', - "en", "Use of STARTTLS required"))), + {"en", "Use of STARTTLS required"}))), {stop, normal, StateData}; true -> send_element(StateData, Header), @@ -598,7 +598,7 @@ wait_for_feature_request({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, if (SockMod == gen_tcp) and TLSRequired -> send_element(StateData, exmpp_stream:error( - 'policy-violation', "en", "Use of STARTTLS required")), + 'policy-violation', {"en", "Use of STARTTLS required"})), send_element(StateData, exmpp_stream:closing()), {stop, normal, StateData}; true -> diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index b68878ee3..11d029ed2 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -2213,7 +2213,7 @@ process_admin_items_set(UJID, Items, Lang, StateData) -> SD; %% TODO: <<>> or 'undefined' ? %% TODO: double case on the E var, because - %% exmpp_jid:lnode/1 can't be used in guards + %% exmpp_jid:prep_node/1 can't be used in guards %% If the provided JID does not have username, %% forget the affiliation completely _ -> case E of diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 7ce313d3d..36d03f689 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -433,7 +433,7 @@ send_loop(State) -> ServerHost -> %% local contacts case ejabberd_sm:get_user_resources(U, S) of [] -> %% offline - PeerJID = exmpp_jlib:make_jid(U, S, R), + PeerJID = exmpp_jid:make(U, S, R), self() ! {presence, User, Server, [Resource], PeerJID}; _ -> %% online % this is already handled by presence probe From 2b6f45e4c13f3299cf09f0faf2ae179b268725d0 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Mon, 1 Jun 2009 23:44:55 +0000 Subject: [PATCH 350/582] Update some calls from jlib:make_jid to exmpp_jid:make SVN Revision: 2139 --- src/ejabberd_commands.erl | 2 +- src/mod_roster.erl | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl index 3a94712fe..67096fb9d 100644 --- a/src/ejabberd_commands.erl +++ b/src/ejabberd_commands.erl @@ -394,7 +394,7 @@ get_md5(AccountPass) -> check_access(Access, User, Server) -> %% Check this user has access permission - case acl:match_rule(Server, Access, jlib:make_jid(User, Server, "")) of + case acl:match_rule(Server, Access, exmpp_jid:make(User, Server, "")) of allow -> true; deny -> false end. diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 709174c69..9d18dd071 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -707,7 +707,7 @@ remove_user(User, Server) %% Both or To, send a "unsubscribe" presence stanza. send_unsubscription_to_rosteritems(LUser, LServer) -> RosterItems = get_user_roster([], {LUser, LServer}), - From = jlib:make_jid({LUser, LServer, ""}), + From = exmpp_jid:make(LUser, LServer, ""), lists:foreach(fun(RosterItem) -> send_unsubscribing_presence(From, RosterItem) end, @@ -725,16 +725,18 @@ send_unsubscribing_presence(From, Item) -> from -> true; _ -> false end, + {INode, IDom, IRes} = Item#roster.jid, + SendToJID = exmpp_jid:make(INode, IDom, IRes), if IsTo -> send_presence_type( jlib:jid_remove_resource(From), - jlib:make_jid(Item#roster.jid), "unsubscribe"); + SendToJID, "unsubscribe"); true -> ok end, if IsFrom -> send_presence_type( jlib:jid_remove_resource(From), - jlib:make_jid(Item#roster.jid), "unsubscribed"); + SendToJID, "unsubscribed"); true -> ok end, ok. From a45e6da3d019d66cde042efdd9d2eee161e14f31 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 2 Jun 2009 18:09:01 +0000 Subject: [PATCH 351/582] Remove support of deprecated Disco Publish XEP-0030 (EJAB-904) SVN Revision: 2141 --- src/mod_disco.erl | 139 +--------------------------------------------- 1 file changed, 2 insertions(+), 137 deletions(-) diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 2a47ac993..60c7a26b0 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -41,7 +41,6 @@ get_sm_identity/5, get_sm_features/5, get_sm_items/5, - get_publish_items/5, register_feature/2, unregister_feature/2, register_extra_domain/2, @@ -51,15 +50,8 @@ -include("ejabberd.hrl"). --record(disco_publish, {owner_node, jid, name, node}). - start(Host, Opts) -> HostB = list_to_binary(Host), - mnesia:create_table(disco_publish, - [{disc_only_copies, [node()]}, - {attributes, record_info(fields, disco_publish)}, - {type, bag}]), - mnesia:add_table_index(disco_publish, owner_node), ejabberd_local:refresh_iq_handlers(), @@ -77,7 +69,6 @@ start(Host, Opts) -> register_feature(Host, "iq"), register_feature(Host, "presence"), register_feature(Host, "presence-invisible"), - register_feature(Host, "http://jabber.org/protocol/disco#publish"), catch ets:new(disco_extra_domains, [named_table, ordered_set, public]), ExtraDomains = gen_mod:get_opt(extra_domains, Opts, []), @@ -91,12 +82,10 @@ start(Host, Opts) -> ejabberd_hooks:add(disco_sm_items, HostB, ?MODULE, get_sm_items, 100), ejabberd_hooks:add(disco_sm_features, HostB, ?MODULE, get_sm_features, 100), ejabberd_hooks:add(disco_sm_identity, HostB, ?MODULE, get_sm_identity, 100), - ejabberd_hooks:add(disco_sm_items, HostB, ?MODULE, get_publish_items, 75), ok. stop(Host) -> HostB = list_to_binary(Host), - ejabberd_hooks:delete(disco_sm_items, HostB, ?MODULE, get_publish_items, 75), ejabberd_hooks:delete(disco_sm_identity, HostB, ?MODULE, get_sm_identity, 100), ejabberd_hooks:delete(disco_sm_features, HostB, ?MODULE, get_sm_features, 100), ejabberd_hooks:delete(disco_sm_items, HostB, ?MODULE, get_sm_items, 100), @@ -288,27 +277,8 @@ process_sm_iq_items(From, To, #iq{type = get, payload = SubEl, {error, Error} -> exmpp_iq:error(IQ_Rec, Error) end; -process_sm_iq_items(From, To, #iq{type = set, payload = SubEl} = IQ_Rec) -> - LTo = exmpp_jid:prep_node_as_list(To), - ToServer = exmpp_jid:prep_domain_as_list(To), - LFrom = exmpp_jid:prep_node_as_list(From), - LServer = exmpp_jid:prep_domain_as_list(From), - Self = (LTo == LFrom) andalso (ToServer == LServer), - Node = exmpp_xml:get_attribute_as_list(SubEl, 'node', ""), - if - Self, Node /= [] -> - %% Here, we treat disco publish attempts to your own JID. - Items = SubEl#xmlel.children, - case process_disco_publish({LFrom, LServer}, Node, Items) of - ok -> - exmpp_iq:result(IQ_Rec); - {error, Err} -> - exmpp_iq:error(IQ_Rec, Err) - end; - - true -> - exmpp_iq:error(IQ_Rec, 'not-allowed') - end. +process_sm_iq_items(_From, _To, #iq{type = set, payload = _SubEl} = IQ_Rec) -> + exmpp_iq:error(IQ_Rec, 'not-allowed'). get_sm_items({error, _Error} = Acc, _From, _To, _Node, _Lang) -> Acc; @@ -389,8 +359,6 @@ get_sm_features(empty, From, To, _Node, _Lang) -> get_sm_features(Acc, _From, _To, _Node, _Lang) -> Acc. - - get_user_resources(JID) -> Rs = ejabberd_sm:get_user_resources(exmpp_jid:prep_node(JID), exmpp_jid:prep_domain(JID)), @@ -401,106 +369,3 @@ get_user_resources(JID) -> ?XMLATTR('name', exmpp_jid:prep_node(JID)) ]} end, lists:sort(Rs)). - - -get_publish_items(empty, From, To, Node, _Lang) -> - LFrom = exmpp_jid:prep_node_as_list(From), - LSFrom = exmpp_jid:prep_domain_as_list(From), - LTo = exmpp_jid:prep_node_as_list(To), - LSTo = exmpp_jid:prep_domain_as_list(To), - if - (LFrom == LTo) and (LSFrom == LSTo) -> - retrieve_disco_publish({LTo, LSTo}, binary_to_list(Node)); - true -> - empty - end; -get_publish_items(Acc, _From, _To, _Node, _Lang) -> - Acc. - -process_disco_publish(User, Node, Items) -> - F = fun() -> - lists:foreach( - fun(#xmlel{} = Item) -> - Action = exmpp_xml:get_attribute_as_list(Item, 'action', ""), - Jid = exmpp_xml:get_attribute_as_list(Item, 'jid', ""), - PNode = exmpp_xml:get_attribute_as_list(Item, 'node', ""), - Name = exmpp_xml:get_attribute_as_list(Item, 'name', ""), - ?INFO_MSG("Disco publish: ~p ~p ~p ~p ~p ~p~n", - [User, Action, Node, Jid, PNode, Name]), - - %% The disco_publish table isn't strictly a "bag" table, as - %% entries with same jid and node combination are considered - %% the same, even if they have different names. Therefore, - %% we find a list of items to supersede. - SupersededItems = mnesia:match_object( - #disco_publish{owner_node = {User, Node}, - jid = Jid, - node = PNode, - _ = '_'}), - case Action of - "update" -> - lists:map( - fun(O) -> - mnesia:delete_object(O) - end, SupersededItems), - mnesia:write( - #disco_publish{owner_node = {User, Node}, - jid = Jid, - name = Name, - node = PNode}); - "remove" -> - case SupersededItems of - [] -> - mnesia:abort({error, 'item-not-found'}); - _ -> - lists:map( - fun(O) -> - mnesia:delete_object(O) - end, SupersededItems) - end; - _ -> - %% invalid "action" attribute - return an error - mnesia:abort({error, 'bad-request'}) - end; - (#xmlcdata{}) -> - ok - end, Items) - end, - case mnesia:transaction(F) of - {aborted, {error, _} = Error} -> - Error; - {atomic, _} -> - ok; - _ -> - {error, 'internal-server-error'} - end. - -retrieve_disco_publish(User, Node) -> - case catch mnesia:dirty_read({disco_publish, {User, Node}}) of - {'EXIT', _Reason} -> - {error, 'internal-server-error'}; - [] -> - empty; - Items -> - {result, - lists:map( - fun(#disco_publish{jid = Jid, - name = Name, - node = PNode}) -> - #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - lists:append([[?XMLATTR('jid', Jid)], - case Name of - "" -> - []; - _ -> - [?XMLATTR('name', Name)] - end, - case PNode of - "" -> - []; - _ -> - [?XMLATTR('node', PNode)] - end])} - end, Items)} - end. - From dd101c99e58ff8e2d5e10ec47ee64d9dbd0ae746 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 9 Jun 2009 09:39:07 +0000 Subject: [PATCH 352/582] Malformed CAPTCHA response may crash a room. This is now fixed. (thanks to Evgeniy Khramtsov) SVN Revision: 2150 --- src/ejabberd_captcha.erl | 42 +++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/ejabberd_captcha.erl b/src/ejabberd_captcha.erl index 68c91fe69..b31ec8bab 100644 --- a/src/ejabberd_captcha.erl +++ b/src/ejabberd_captcha.erl @@ -150,30 +150,36 @@ check_captcha(Id, ProvidedKey) -> process_reply(El) -> case {exmpp_xml:element_matches(El, captcha), - exmpp_xml:get_element(El, x)} of + exmpp_xml:get_element(El, x)} of {false, _} -> {error, malformed}; {_, undefined} -> {error, malformed}; {true, Xdata} -> Fields = jlib:parse_xdata_submit(Xdata), - [Id | _] = proplists:get_value("challenge", Fields, [none]), - [OCR | _] = proplists:get_value("ocr", Fields, [none]), - ?T(case mnesia:read(captcha, Id, write) of - [#captcha{pid=Pid, args=Args, key=Key, tref=Tref}] -> - mnesia:delete({captcha, Id}), - erlang:cancel_timer(Tref), - if OCR == Key -> - Pid ! {captcha_succeed, Args}, - ok; - true -> - Pid ! {captcha_failed, Args}, - {error, bad_match} - end; - _ -> - {error, not_found} - end) - end. + case {proplists:get_value("challenge", Fields), + proplists:get_value("ocr", Fields)} of + {[Id|_], [OCR|_]} -> + ?T(case mnesia:read(captcha, Id, write) of + [#captcha{pid=Pid, args=Args, key=Key, tref=Tref}] -> + mnesia:delete({captcha, Id}), + erlang:cancel_timer(Tref), + if OCR == Key -> + Pid ! {captcha_succeed, Args}, + ok; + true -> + Pid ! {captcha_failed, Args}, + {error, bad_match} + end; + _ -> + {error, not_found} + end); + _ -> + {error, malformed} + end + end; +process_reply(_) -> + {error, malformed}. process(_Handlers, #request{method='GET', lang=Lang, path=[_, Id]}) -> From 60f52b2cd83d2ba45572b5af8b8329505a80fde9 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 9 Jun 2009 10:56:49 +0000 Subject: [PATCH 353/582] Add forgotten copyright and license notices. Fix blackspaces. SVN Revision: 2152 --- src/cyrsasl_digest.erl | 20 +++++++++++++++++++- src/ejabberd_captcha.erl | 23 +++++++++++++++++++++-- src/ejabberd_zlib/ejabberd_zlib_drv.c | 2 +- src/expat_erl.c | 21 ++++++++++++++++++++- src/mod_irc/iconv_erl.c | 2 +- src/odbc/mssql2000.sql | 2 +- src/pam/epam.c | 2 +- src/stringprep/stringprep_drv.c | 2 +- src/tls/tls_drv.c | 2 +- 9 files changed, 66 insertions(+), 10 deletions(-) diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl index 0eb8f8df1..b6174935c 100644 --- a/src/cyrsasl_digest.erl +++ b/src/cyrsasl_digest.erl @@ -3,7 +3,25 @@ %%% Author : Alexey Shchepin <alexey@sevcom.net> %%% Purpose : DIGEST-MD5 SASL mechanism %%% Created : 11 Mar 2003 by Alexey Shchepin <alexey@sevcom.net> -%%% Id : $Id$ +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% %%%---------------------------------------------------------------------- -module(cyrsasl_digest). diff --git a/src/ejabberd_captcha.erl b/src/ejabberd_captcha.erl index b31ec8bab..a9657b4b2 100644 --- a/src/ejabberd_captcha.erl +++ b/src/ejabberd_captcha.erl @@ -1,10 +1,29 @@ %%%------------------------------------------------------------------- %%% File : ejabberd_captcha.erl %%% Author : Evgeniy Khramtsov <xramtsov@gmail.com> -%%% Description : CAPTCHA processing. -%%% +%%% Purpose : CAPTCHA processing. %%% Created : 26 Apr 2008 by Evgeniy Khramtsov <xramtsov@gmail.com> +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% %%%------------------------------------------------------------------- + -module(ejabberd_captcha). -behaviour(gen_server). diff --git a/src/ejabberd_zlib/ejabberd_zlib_drv.c b/src/ejabberd_zlib/ejabberd_zlib_drv.c index 39039aa4f..f86d33edb 100644 --- a/src/ejabberd_zlib/ejabberd_zlib_drv.c +++ b/src/ejabberd_zlib/ejabberd_zlib_drv.c @@ -10,7 +10,7 @@ * 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/expat_erl.c b/src/expat_erl.c index 65c17fd08..19653f61b 100644 --- a/src/expat_erl.c +++ b/src/expat_erl.c @@ -1,4 +1,23 @@ -/* $Id$ */ +/* + * ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + */ + #include <stdio.h> #include <string.h> diff --git a/src/mod_irc/iconv_erl.c b/src/mod_irc/iconv_erl.c index c9ce801ff..e845635b3 100644 --- a/src/mod_irc/iconv_erl.c +++ b/src/mod_irc/iconv_erl.c @@ -10,7 +10,7 @@ * 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/odbc/mssql2000.sql b/src/odbc/mssql2000.sql index d305784fb..1bb93d783 100644 --- a/src/odbc/mssql2000.sql +++ b/src/odbc/mssql2000.sql @@ -10,7 +10,7 @@ * 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/pam/epam.c b/src/pam/epam.c index 3a24d7ce2..db82c825a 100644 --- a/src/pam/epam.c +++ b/src/pam/epam.c @@ -10,7 +10,7 @@ * 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/stringprep/stringprep_drv.c b/src/stringprep/stringprep_drv.c index 2d31020c5..8007fb5f8 100644 --- a/src/stringprep/stringprep_drv.c +++ b/src/stringprep/stringprep_drv.c @@ -10,7 +10,7 @@ * 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., 59 Temple Place, Suite 330, Boston, MA diff --git a/src/tls/tls_drv.c b/src/tls/tls_drv.c index 8380ea751..811293406 100644 --- a/src/tls/tls_drv.c +++ b/src/tls/tls_drv.c @@ -10,7 +10,7 @@ * 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., 59 Temple Place, Suite 330, Boston, MA From 8de03275c3cb23f06ee88dbdc7392d1b9dbc49b3 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 9 Jun 2009 12:10:24 +0000 Subject: [PATCH 354/582] When client is closed, include the Reason in the stream trailer stanza. SVN Revision: 2154 --- src/ejabberd_c2s.erl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 9fd4a3767..412a26816 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1186,6 +1186,9 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> end, if Pass == exit -> + %% When Pass==exit, NewState contains a string instead of a #state{} + Lang = StateData#state.lang, + catch send_element(StateData, exmpp_stream:error('undefined-condition', {Lang, NewState})), catch send_element(StateData, exmpp_stream:closing()), {stop, normal, StateData}; Pass -> From 2f3963417fc5b387049f382acc3041dc8ee00ccf Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Thu, 11 Jun 2009 18:57:03 +0000 Subject: [PATCH 355/582] Prevent process crash if the IP and port of a connection is unknown. SVN Revision: 2156 --- src/ejabberd_c2s.erl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 412a26816..744a24933 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1911,6 +1911,8 @@ fsm_reply(Reply, StateName, StateData) -> {reply, Reply, StateName, StateData, ?C2S_OPEN_TIMEOUT}. %% Used by c2s blacklist plugins +is_ip_blacklisted(undefined) -> + false; is_ip_blacklisted({IP,_Port}) -> ejabberd_hooks:run_fold(check_bl_c2s, false, [IP]). From b4a1b4c8fbb91582ee6913b5d5d48d0492dacea9 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Mon, 15 Jun 2009 17:27:06 +0000 Subject: [PATCH 356/582] Replace TYPE/1 with is_TYPE/1 (EJAB-922) SVN Revision: 2160 --- src/ejabberd_debug.erl | 2 +- src/eldap/eldap.erl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ejabberd_debug.erl b/src/ejabberd_debug.erl index f2152d851..84581eb38 100644 --- a/src/ejabberd_debug.erl +++ b/src/ejabberd_debug.erl @@ -46,7 +46,7 @@ pids() -> lists:zf( fun(Pid) -> case process_info(Pid) of - ProcessInfo when list(ProcessInfo) -> + ProcessInfo when is_list(ProcessInfo) -> CurrentFunction = current_function(ProcessInfo), InitialCall = initial_call(ProcessInfo), RegisteredName = registered_name(ProcessInfo), diff --git a/src/eldap/eldap.erl b/src/eldap/eldap.erl index 3c3e736ae..f77ea8296 100644 --- a/src/eldap/eldap.erl +++ b/src/eldap/eldap.erl @@ -699,7 +699,7 @@ recvd_packet(Pkt, S) -> Answer = case {Name, Op} of {searchRequest, {searchResEntry, R}} when - record(R,'SearchResultEntry') -> + is_record(R,'SearchResultEntry') -> New_dict = dict:append(Id, R, Dict), {ok, S#eldap{dict = New_dict}}; {searchRequest, {searchResDone, Result}} -> @@ -1059,7 +1059,7 @@ get_list(Key, List) -> get_atom(Key, List) -> case lists:keysearch(Key, 1, List) of - {value, {Key, Value}} when atom(Value) -> + {value, {Key, Value}} when is_atom(Value) -> Value; {value, {Key, _Value}} -> throw({error, "Bad Value in Config for " ++ atom_to_list(Key)}); From 2f6cea2be319b1c3cfc037fb6ddd75a695a46478 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Mon, 15 Jun 2009 17:27:11 +0000 Subject: [PATCH 357/582] Fix warning about a case already covered. SVN Revision: 2161 --- src/ejabberd_captcha.erl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ejabberd_captcha.erl b/src/ejabberd_captcha.erl index a9657b4b2..3406cabaf 100644 --- a/src/ejabberd_captcha.erl +++ b/src/ejabberd_captcha.erl @@ -196,9 +196,7 @@ process_reply(El) -> _ -> {error, malformed} end - end; -process_reply(_) -> - {error, malformed}. + end. process(_Handlers, #request{method='GET', lang=Lang, path=[_, Id]}) -> From 88fd7b226a46f8074b3cf851a9554754063e519a Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Mon, 15 Jun 2009 17:44:04 +0000 Subject: [PATCH 358/582] Add option to restrict max offline messages by Access and ACL (EJAB-951) New option for mod_offline: access_max_user_messages. The old option user_max_messages is no longer supported. SVN Revision: 2163 --- doc/guide.html | 53 +++++++++++++++++++++++++++++++++------- doc/guide.tex | 31 ++++++++++++++++++++--- src/ejabberd.cfg.example | 5 +++- src/mod_offline.erl | 34 ++++++++++++++++---------- src/mod_offline_odbc.erl | 33 +++++++++++++++---------- 5 files changed, 116 insertions(+), 40 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 5188669ce..f64da433a 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -2423,11 +2423,31 @@ sent to an offline user will be stored on the server until that user comes online again. Thus it is very similar to how email works. Note that <TT>ejabberdctl</TT> has a command to delete expired messages (see section <A HREF="#ejabberdctl">4.1</A>).</P><DL CLASS="description"><DT CLASS="dt-description"> -<B><TT>user_max_messages</TT></B></DT><DD CLASS="dd-description">This option -is use to set a max number of offline messages per user (quota). Its -value can be either <TT>infinity</TT> or a strictly positive -integer. The default value is <TT>infinity</TT>. -</DD></DL><P> <A NAME="modprivacy"></A> </P><!--TOC subsection <TT>mod_privacy</TT>--> +<B><TT>access_max_user_messages</TT></B></DT><DD CLASS="dd-description"> +This option defines which access rule will be enforced to limit +the maximum number of offline messages that a user can have (quota). +When a user has too many offline messages, any new messages that he receive are discarded, +and a resource-constraint error is returned to the sender. +The default value is <TT>max_user_offline_messages</TT>. +Then you can define an access rule with a syntax similar to +<TT>max_user_sessions</TT> (see <A HREF="#configmaxsessions">3.1.5</A>). +</DD></DL><P>This example allows power users to have as much as 5000 offline messages, +administrators up to 2000, +and all the other users up to 100. +</P><PRE CLASS="verbatim">{acl, admin, {user, "admin1", "localhost"}}. +{acl, admin, {user, "admin2", "example.org"}}. +{acl, poweruser, {user, "bob", "example.org"}}. +{acl, poweruser, {user, "jane", "example.org"}}. + +{access, max_user_offline_messages, [ {5000, poweruser}, {2000, admin}, {100, all} ]}. + +{modules, + [ + ... + {mod_offline, [ {access_max_user_messages, max_user_offline_messages} ]}, + ... + ]}. +</PRE><P> <A NAME="modprivacy"></A> </P><!--TOC subsection <TT>mod_privacy</TT>--> <H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc48">3.3.11</A>  <A HREF="#modprivacy"><TT>mod_privacy</TT></A></H3><!--SEC END --><P> <A NAME="modprivacy"></A> </P><P>This module implements Blocking Communication (also known as Privacy Rules) as defined in section 10 from XMPP IM. If end users have support for it in @@ -2538,12 +2558,27 @@ is replaced at start time with the real virtual host name. </DD><DT CLASS="dt-description"><B><TT>access_createnode</TT></B></DT><DD CLASS="dd-description"> This option restricts which users are allowed to create pubsub nodes using -ACL and ACCESS. The default value is <TT>pubsub_createnode</TT>. </DD><DT CLASS="dt-description"><B><TT>plugins</TT></B></DT><DD CLASS="dd-description"> To specify which pubsub node plugins to use. If not defined, the default +ACL and ACCESS. The default value is <TT>pubsub_createnode</TT>. </DD><DT CLASS="dt-description"><B><TT>plugins</TT></B></DT><DD CLASS="dd-description"> +To specify which pubsub node plugins to use. If not defined, the default pubsub plugin is always used. -</DD><DT CLASS="dt-description"><B><TT>nodetree</TT></B></DT><DD CLASS="dd-description"> To specify which nodetree to use. If not defined, the default pubsub -nodetree is used. Nodetrees are default and virtual. Only one nodetree can be used +</DD><DT CLASS="dt-description"><B><TT>nodetree</TT></B></DT><DD CLASS="dd-description"> +To specify which nodetree to use. If not defined, the default pubsub +nodetree is used. Only one nodetree can be used per host, and is shared by all node plugins. -</DD></DL><P>Example: +</DD><DT CLASS="dt-description"><B><TT>pep_sendlast_offline</TT></B></DT><DD CLASS="dd-description"> +To specify whether or not we should get last published PEP items +from users in our roster which are offline when we connect. Value is true or false. +If not defined, pubsub assumes false so we only get last items of online contacts. +</DD><DT CLASS="dt-description"><B><TT>last_item_cache</TT></B></DT><DD CLASS="dd-description"> +To specify whether or not pubsub should cache last items. Value is true +or false. If not defined, pubsub do not cache last items. On systems with not so many nodes, +caching last items speeds up pubsub and allows to raise user connection rate. The cost is memory +usage, as every item is stored in memory. +</DD><DT CLASS="dt-description"><B><TT>pep_mapping</TT></B></DT><DD CLASS="dd-description"> +This allow to define a Key-Value list to choose defined node plugins on given PEP namespace. +The following example will use node_tune instead of node_pep for every PEP node with tune namespace: +<PRE CLASS="verbatim"> {mod_pubsub, [{pep_mapping, [{"http://jabber.org/protocol/tune", "tune"}]}]} +</PRE></DD></DL><P>Example: </P><PRE CLASS="verbatim">{modules, [ ... diff --git a/doc/guide.tex b/doc/guide.tex index b1801a8a3..a0bb82eb1 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -3132,12 +3132,35 @@ online again. Thus it is very similar to how email works. Note that (see section~\ref{ejabberdctl}). \begin{description} - \titem{user\_max\_messages}\ind{options!user\_max\_messages}This option - is use to set a max number of offline messages per user (quota). Its - value can be either \term{infinity} or a strictly positive - integer. The default value is \term{infinity}. + \titem{access\_max\_user\_messages}\ind{options!access\_max\_user\_messages} + This option defines which access rule will be enforced to limit + the maximum number of offline messages that a user can have (quota). + When a user has too many offline messages, any new messages that he receive are discarded, + and a resource-constraint error is returned to the sender. + The default value is \term{max\_user\_offline\_messages}. + Then you can define an access rule with a syntax similar to + \term{max\_user\_sessions} (see \ref{configmaxsessions}). \end{description} +This example allows power users to have as much as 5000 offline messages, +administrators up to 2000, +and all the other users up to 100. +\begin{verbatim} +{acl, admin, {user, "admin1", "localhost"}}. +{acl, admin, {user, "admin2", "example.org"}}. +{acl, poweruser, {user, "bob", "example.org"}}. +{acl, poweruser, {user, "jane", "example.org"}}. + +{access, max_user_offline_messages, [ {5000, poweruser}, {2000, admin}, {100, all} ]}. + +{modules, + [ + ... + {mod_offline, [ {access_max_user_messages, max_user_offline_messages} ]}, + ... + ]}. +\end{verbatim} + \makesubsection{modprivacy}{\modprivacy{}} \ind{modules!\modprivacy{}}\ind{Blocking Communication}\ind{Privacy Rules}\ind{protocols!RFC 3921: XMPP IM} diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index 2d406c2ed..33e90789c 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -379,6 +379,9 @@ %% Maximum number of simultaneous sessions allowed for a single user: {access, max_user_sessions, [{10, all}]}. +%% Maximum number of offline messages that users can have: +{access, max_user_offline_messages, [{5000, admin}, {100, all}]}, + %% This rule allows access only for local users: {access, local, [{allow, local}]}. @@ -481,7 +484,7 @@ {access_admin, muc_admin} ]}, %%{mod_muc_log,[]}, - {mod_offline, []}, + {mod_offline, [{access_max_user_messages, max_user_offline_messages}]}, {mod_privacy, []}, {mod_private, []}, %%{mod_proxy65,[]}, diff --git a/src/mod_offline.erl b/src/mod_offline.erl index bb9ce561a..8b785bd03 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -30,7 +30,7 @@ -behaviour(gen_mod). -export([start/2, - init/1, + loop/1, stop/1, store_packet/3, resend_offline_messages/2, @@ -58,6 +58,9 @@ -define(DEFAULT_NS, ?NS_JABBER_CLIENT). -define(PREFIXED_NS, [{?NS_XMPP, ?NS_XMPP_pfx}]). +%% default value for the maximum number of user messages +-define(MAX_USER_MESSAGES, infinity). + start(Host, Opts) -> HostB = list_to_binary(Host), mnesia:create_table(offline_msg, @@ -79,22 +82,18 @@ start(Host, Opts) -> ?MODULE, webadmin_user, 50), ejabberd_hooks:add(webadmin_user_parse_query, HostB, ?MODULE, webadmin_user_parse_query, 50), - MaxOfflineMsgs = gen_mod:get_opt(user_max_messages, Opts, infinity), + AccessMaxOfflineMsgs = gen_mod:get_opt(access_max_user_messages, Opts, max_user_offline_messages), register(gen_mod:get_module_proc(Host, ?PROCNAME), - spawn(?MODULE, init, [MaxOfflineMsgs])). + spawn(?MODULE, loop, [AccessMaxOfflineMsgs])). -%% MaxOfflineMsgs is either infinity of integer > 0 -init(infinity) -> - loop(infinity); -init(MaxOfflineMsgs) - when is_integer(MaxOfflineMsgs), MaxOfflineMsgs > 0 -> - loop(MaxOfflineMsgs). - -loop(MaxOfflineMsgs) -> +loop(AccessMaxOfflineMsgs) -> receive #offline_msg{us=US} = Msg -> Msgs = receive_all(US, [Msg]), Len = length(Msgs), + {User, Host} = US, + MaxOfflineMsgs = get_max_user_messages(AccessMaxOfflineMsgs, + User, Host), F = fun() -> %% Only count messages if needed: Count = if MaxOfflineMsgs =/= infinity -> @@ -120,9 +119,18 @@ loop(MaxOfflineMsgs) -> end end, mnesia:transaction(F), - loop(MaxOfflineMsgs); + loop(AccessMaxOfflineMsgs); _ -> - loop(MaxOfflineMsgs) + loop(AccessMaxOfflineMsgs) + end. + +%% Function copied from ejabberd_sm.erl: +get_max_user_messages(AccessRule, LUser, Host) -> + case acl:match_rule( + Host, AccessRule, jlib:make_jid(LUser, Host, "")) of + Max when is_integer(Max) -> Max; + infinity -> infinity; + _ -> ?MAX_USER_MESSAGES end. receive_all(US, Msgs) -> diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index 7b3603f01..2d4cd787a 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -32,7 +32,7 @@ -export([count_offline_messages/2]). -export([start/2, - init/2, + loop/2, stop/1, store_packet/3, pop_offline_messages/3, @@ -57,6 +57,9 @@ -define(DEFAULT_NS, ?NS_JABBER_CLIENT). -define(PREFIXED_NS, [{?NS_XMPP, ?NS_XMPP_pfx}]). +%% default value for the maximum number of user messages +-define(MAX_USER_MESSAGES, infinity). + start(Host, Opts) -> HostB = list_to_binary(Host), ejabberd_hooks:add(offline_message_hook, HostB, @@ -73,22 +76,17 @@ start(Host, Opts) -> ?MODULE, webadmin_user, 50), ejabberd_hooks:add(webadmin_user_parse_query, HostB, ?MODULE, webadmin_user_parse_query, 50), - MaxOfflineMsgs = gen_mod:get_opt(user_max_messages, Opts, infinity), + AccessMaxOfflineMsgs = gen_mod:get_opt(access_max_user_messages, Opts, max_user_offline_messages), register(gen_mod:get_module_proc(Host, ?PROCNAME), - spawn(?MODULE, init, [Host, MaxOfflineMsgs])). + spawn(?MODULE, loop, [Host, AccessMaxOfflineMsgs])). -%% MaxOfflineMsgs is either infinity of integer > 0 -init(Host, infinity) -> - loop(Host, infinity); -init(Host, MaxOfflineMsgs) - when is_integer(MaxOfflineMsgs), MaxOfflineMsgs > 0 -> - loop(Host, MaxOfflineMsgs). - -loop(Host, MaxOfflineMsgs) -> +loop(Host, AccessMaxOfflineMsgs) -> receive #offline_msg{user = User} = Msg -> Msgs = receive_all(User, [Msg]), Len = length(Msgs), + MaxOfflineMsgs = get_max_user_messages(AccessMaxOfflineMsgs, + User, Host), %% Only count existing messages if needed: Count = if MaxOfflineMsgs =/= infinity -> @@ -128,9 +126,18 @@ loop(Host, MaxOfflineMsgs) -> ok end end, - loop(Host, MaxOfflineMsgs); + loop(Host, AccessMaxOfflineMsgs); _ -> - loop(Host, MaxOfflineMsgs) + loop(Host, AccessMaxOfflineMsgs) + end. + +%% Function copied from ejabberd_sm.erl: +get_max_user_messages(AccessRule, LUser, Host) -> + case acl:match_rule( + Host, AccessRule, jlib:make_jid(LUser, Host, "")) of + Max when is_integer(Max) -> Max; + infinity -> infinity; + _ -> ?MAX_USER_MESSAGES end. receive_all(Username, Msgs) -> From 940f5be35ed3408490432c301d969dcb335301a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20R=C3=A9mond?= <mickael.remond@process-one.net> Date: Tue, 16 Jun 2009 00:49:09 +0000 Subject: [PATCH 359/582] Fix syntax error in config file SVN Revision: 2166 --- src/ejabberd.cfg.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index 33e90789c..cb07c89e1 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -380,7 +380,7 @@ {access, max_user_sessions, [{10, all}]}. %% Maximum number of offline messages that users can have: -{access, max_user_offline_messages, [{5000, admin}, {100, all}]}, +{access, max_user_offline_messages, [{5000, admin}, {100, all}]}. %% This rule allows access only for local users: {access, local, [{allow, local}]}. From 818a70bdd7f814fbf5a59dc9833cb906dc35830f Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 11:27:33 +0000 Subject: [PATCH 360/582] Do not include mod_irc, it can be found in ejabberd-modules SVN. Iconv not required. (EJAB-954) SVN Revision: 2167 --- README | 2 - doc/guide.html | 293 +++---- doc/guide.tex | 91 +-- doc/introduction.tex | 1 - examples/mtr/ejabberd-netbsd.sh | 2 +- src/Makefile.in | 2 +- src/Makefile.win32 | 7 - src/aclocal.m4 | 90 --- src/configure | 307 +------- src/configure.ac | 4 - src/configure.erl | 6 - src/ejabberd.app | 4 - src/ejabberd.cfg.example | 1 - src/mod_irc/Makefile.in | 60 -- src/mod_irc/Makefile.win32 | 42 - src/mod_irc/iconv.erl | 94 --- src/mod_irc/iconv_erl.c | 139 ---- src/mod_irc/mod_irc.erl | 593 -------------- src/mod_irc/mod_irc_connection.erl | 1177 ---------------------------- src/win32/ejabberd.cfg | 1 - 20 files changed, 122 insertions(+), 2794 deletions(-) delete mode 100644 src/mod_irc/Makefile.in delete mode 100644 src/mod_irc/Makefile.win32 delete mode 100644 src/mod_irc/iconv.erl delete mode 100644 src/mod_irc/iconv_erl.c delete mode 100644 src/mod_irc/mod_irc.erl delete mode 100644 src/mod_irc/mod_irc_connection.erl diff --git a/README b/README index 09a4ef40f..ac5986191 100644 --- a/README +++ b/README @@ -17,8 +17,6 @@ To compile ejabberd you need: - Erlang mysql library. Optional. MySQL authentication/storage. - Erlang pgsql library. Optional. PostgreSQL authentication/storage. - PAM library. Optional. For Pluggable Authentication Modules (PAM). - - GNU Iconv 1.8 or higher, for the IRC Transport - (mod_irc). Optional. Not needed on systems with GNU Libc. 1. Compile and install on *nix systems diff --git a/doc/guide.html b/doc/guide.html index f64da433a..464f60eec 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -142,77 +142,76 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;} </LI><LI CLASS="li-toc"><A HREF="#htoc40">3.3.3  <TT>mod_announce</TT></A> </LI><LI CLASS="li-toc"><A HREF="#htoc41">3.3.4  <TT>mod_disco</TT></A> </LI><LI CLASS="li-toc"><A HREF="#htoc42">3.3.5  <TT>mod_echo</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc43">3.3.6  <TT>mod_irc</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc44">3.3.7  <TT>mod_last</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc45">3.3.8  <TT>mod_muc</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc46">3.3.9  <TT>mod_muc_log</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc47">3.3.10  <TT>mod_offline</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc48">3.3.11  <TT>mod_privacy</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc49">3.3.12  <TT>mod_private</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc50">3.3.13  <TT>mod_proxy65</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc51">3.3.14  <TT>mod_pubsub</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc52">3.3.15  <TT>mod_register</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc53">3.3.16  <TT>mod_roster</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc54">3.3.17  <TT>mod_service_log</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc55">3.3.18  <TT>mod_shared_roster</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc56">3.3.19  <TT>mod_stats</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc57">3.3.20  <TT>mod_time</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc58">3.3.21  <TT>mod_vcard</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc59">3.3.22  <TT>mod_vcard_ldap</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc60">3.3.23  <TT>mod_version</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc43">3.3.6  <TT>mod_last</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc44">3.3.7  <TT>mod_muc</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc45">3.3.8  <TT>mod_muc_log</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc46">3.3.9  <TT>mod_offline</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc47">3.3.10  <TT>mod_privacy</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc48">3.3.11  <TT>mod_private</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc49">3.3.12  <TT>mod_proxy65</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc50">3.3.13  <TT>mod_pubsub</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc51">3.3.14  <TT>mod_register</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc52">3.3.15  <TT>mod_roster</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc53">3.3.16  <TT>mod_service_log</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc54">3.3.17  <TT>mod_shared_roster</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc55">3.3.18  <TT>mod_stats</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc56">3.3.19  <TT>mod_time</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc57">3.3.20  <TT>mod_vcard</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc58">3.3.21  <TT>mod_vcard_ldap</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc59">3.3.22  <TT>mod_version</TT></A> </LI></UL> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc61">Chapter 4  Managing an <TT>ejabberd</TT> Server</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc60">Chapter 4  Managing an <TT>ejabberd</TT> Server</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc62">4.1  <TT>ejabberdctl</TT></A> +<A HREF="#htoc61">4.1  <TT>ejabberdctl</TT></A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc63">4.1.1  ejabberdctl Commands</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc64">4.1.2  Erlang Runtime System</A> +<A HREF="#htoc62">4.1.1  ejabberdctl Commands</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc63">4.1.2  Erlang Runtime System</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc65">4.2  <TT>ejabberd</TT> Commands</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc64">4.2  <TT>ejabberd</TT> Commands</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc66">4.2.1  List of ejabberd Commands</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc67">4.2.2  Restrict Execution with AccessCommands</A> +<A HREF="#htoc65">4.2.1  List of ejabberd Commands</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc66">4.2.2  Restrict Execution with AccessCommands</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc68">4.3  Web Admin</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc69">4.4  Ad-hoc Commands</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc70">4.5  Change Computer Hostname</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc67">4.3  Web Admin</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc68">4.4  Ad-hoc Commands</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc69">4.5  Change Computer Hostname</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc71">Chapter 5  Securing <TT>ejabberd</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc70">Chapter 5  Securing <TT>ejabberd</TT></A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc72">5.1  Firewall Settings</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc73">5.2  epmd</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc74">5.3  Erlang Cookie</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc75">5.4  Erlang Node Name</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc76">5.5  Securing Sensible Files</A> +<A HREF="#htoc71">5.1  Firewall Settings</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc72">5.2  epmd</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc73">5.3  Erlang Cookie</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc74">5.4  Erlang Node Name</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc75">5.5  Securing Sensible Files</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc77">Chapter 6  Clustering</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc76">Chapter 6  Clustering</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc78">6.1  How it Works</A> +<A HREF="#htoc77">6.1  How it Works</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc79">6.1.1  Router</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc80">6.1.2  Local Router</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc81">6.1.3  Session Manager</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc82">6.1.4  s2s Manager</A> +<A HREF="#htoc78">6.1.1  Router</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc79">6.1.2  Local Router</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc80">6.1.3  Session Manager</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc81">6.1.4  s2s Manager</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc83">6.2  Clustering Setup</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc84">6.3  Service Load-Balancing</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc82">6.2  Clustering Setup</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc83">6.3  Service Load-Balancing</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc85">6.3.1  Components Load-Balancing</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc86">6.3.2  Domain Load-Balancing Algorithm</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc87">6.3.3  Load-Balancing Buckets</A> +<A HREF="#htoc84">6.3.1  Components Load-Balancing</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc85">6.3.2  Domain Load-Balancing Algorithm</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc86">6.3.3  Load-Balancing Buckets</A> </LI></UL> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc88">Chapter 7  Debugging</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc87">Chapter 7  Debugging</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc89">7.1  Log Files</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc90">7.2  Debug Console</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc91">7.3  Watchdog Alerts</A> +<A HREF="#htoc88">7.1  Log Files</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc89">7.2  Debug Console</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc90">7.3  Watchdog Alerts</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc92">Appendix A  Internationalization and Localization</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc93">Appendix B  Release Notes</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc94">Appendix C  Acknowledgements</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc95">Appendix D  Copyright Information</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc91">Appendix A  Internationalization and Localization</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc92">Appendix B  Release Notes</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc93">Appendix C  Acknowledgements</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc94">Appendix D  Copyright Information</A> </LI></UL><!--TOC chapter Introduction--> <H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc1">Chapter 1</A>  Introduction</H1><!--SEC END --><P> <A NAME="intro"></A></P><P><TT>ejabberd</TT> is a free and open source instant messaging server written in <A HREF="http://www.erlang.org/">Erlang</A>.</P><P><TT>ejabberd</TT> is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.</P><P><TT>ejabberd</TT> is designed to be a rock-solid and feature rich XMPP server.</P><P><TT>ejabberd</TT> is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.</P><!--TOC section Key Features--> @@ -272,7 +271,6 @@ Support for virtual hosting. </LI><LI CLASS="li-itemize"><A HREF="http://www.xmpp.org/extensions/xep-0045.html">Multi-User Chat</A> module with support for clustering and HTML logging. </LI><LI CLASS="li-itemize">Users Directory based on users vCards. </LI><LI CLASS="li-itemize"><A HREF="http://www.xmpp.org/extensions/xep-0060.html">Publish-Subscribe</A> component with support for <A HREF="http://www.xmpp.org/extensions/xep-0163.html">Personal Eventing via Pubsub</A>. </LI><LI CLASS="li-itemize">Support for web clients: <A HREF="http://www.xmpp.org/extensions/xep-0025.html">HTTP Polling</A> and <A HREF="http://www.xmpp.org/extensions/xep-0206.html">HTTP Binding (BOSH)</A> services. -</LI><LI CLASS="li-itemize">IRC transport. </LI><LI CLASS="li-itemize">Component support: interface with networks such as AIM, ICQ and MSN installing special tranports. </LI></UL> </LI></UL><P> <A NAME="installing"></A> </P><!--TOC chapter Installing <TT>ejabberd</TT>--> @@ -342,7 +340,6 @@ GNU Make </LI><LI CLASS="li-itemize">Erlang mysql library. Optional. For MySQL authentication or storage. See section <A HREF="#compilemysql">3.2.1</A>. </LI><LI CLASS="li-itemize">Erlang pgsql library. Optional. For PostgreSQL authentication or storage. See section <A HREF="#compilepgsql">3.2.3</A>. </LI><LI CLASS="li-itemize">PAM library. Optional. For Pluggable Authentication Modules (PAM). See section <A HREF="#pam">3.1.4</A>. -</LI><LI CLASS="li-itemize">GNU Iconv 1.8 or higher, for the IRC Transport (mod_irc). Optional. Not needed on systems with GNU Libc. See section <A HREF="#modirc">3.3.6</A>. </LI><LI CLASS="li-itemize">ImageMagick’s Convert program. Optional. For CAPTCHA challenges. See section <A HREF="#captcha">3.1.8</A>. </LI></UL><P> <A NAME="download"></A> </P><!--TOC subsection Download Source Code--> <H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc10">2.4.2</A>  <A HREF="#download">Download Source Code</A></H3><!--SEC END --><P> <A NAME="download"></A> @@ -460,8 +457,6 @@ for example: MS Visual C++ 6.0 Compiler </LI><LI CLASS="li-itemize"><A HREF="http://www.erlang.org/download.html">Erlang/OTP R11B-5</A> </LI><LI CLASS="li-itemize"><A HREF="http://sourceforge.net/project/showfiles.php?group_id=10127&package_id=11277">Expat 2.0.0 or higher</A> -</LI><LI CLASS="li-itemize"><A HREF="http://www.gnu.org/software/libiconv/">GNU Iconv 1.9.2</A> -(optional) </LI><LI CLASS="li-itemize"><A HREF="http://www.slproweb.com/products/Win32OpenSSL.html">Shining Light OpenSSL 0.9.8d or higher</A> (to enable SSL connections) </LI><LI CLASS="li-itemize"><A HREF="http://www.zlib.net/">Zlib 1.2.3 or higher</A> @@ -472,17 +467,12 @@ Install Erlang emulator (for example, into <CODE>C:\sdk\erl5.5.5</CODE>). directory.<P>Copy file <CODE>C:\sdk\Expat-2.0.0\Libs\libexpat.dll</CODE> to your Windows system directory (for example, <CODE>C:\WINNT</CODE> or <CODE>C:\WINNT\System32</CODE>) -</P></LI><LI CLASS="li-enumerate">Build and install the Iconv library into the directory -<CODE>C:\sdk\GnuWin32</CODE>.<P>Copy file <CODE>C:\sdk\GnuWin32\bin\lib*.dll</CODE> to your -Windows system directory (more installation instructions can be found in the -file README.woe32 in the iconv distribution).</P><P>Note: instead of copying libexpat.dll and iconv.dll to the Windows -directory, you can add the directories -<CODE>C:\sdk\Expat-2.0.0\Libs</CODE> and -<CODE>C:\sdk\GnuWin32\bin</CODE> to the <CODE>PATH</CODE> environment -variable. +Note: instead of copying libexpat.dll to the Windows +directory, you can add the directory <CODE>C:\sdk\Expat-2.0.0\Libs</CODE> +to the <CODE>PATH</CODE> environment variable. </P></LI><LI CLASS="li-enumerate">Install OpenSSL in <CODE>C:\sdk\OpenSSL</CODE> and add <CODE>C:\sdk\OpenSSL\lib\VC</CODE> to your path or copy the binaries to your system directory. </LI><LI CLASS="li-enumerate">Install ZLib in <CODE>C:\sdk\gnuWin32</CODE>. Copy -<CODE>C:\sdk\GnuWin32\bin\zlib1.dll</CODE> to your system directory. If you change your path it should already be set after libiconv install. +<CODE>C:\sdk\GnuWin32\bin\zlib1.dll</CODE> to your system directory. </LI><LI CLASS="li-enumerate">Make sure the you can access Erlang binaries from your path. For example: <CODE>set PATH=%PATH%;"C:\sdk\erl5.6.5\bin"</CODE> </LI><LI CLASS="li-enumerate">Depending on how you end up actually installing the library you might need to check and tweak the paths in the file configure.erl. </LI><LI CLASS="li-enumerate">While in the directory <CODE>ejabberd\src</CODE> run: @@ -499,7 +489,7 @@ There are two ways to register a Jabber account: <OL CLASS="enumerate" type=a><LI CLASS="li-enumerate"> Using <TT>ejabberdctl</TT> (see section <A HREF="#ejabberdctl">4.1</A>): <PRE CLASS="verbatim">ejabberdctl register admin1 example.org FgT5bk3 -</PRE></LI><LI CLASS="li-enumerate">Using a Jabber client and In-Band Registration (see section <A HREF="#modregister">3.3.15</A>). +</PRE></LI><LI CLASS="li-enumerate">Using a Jabber client and In-Band Registration (see section <A HREF="#modregister">3.3.14</A>). </LI></OL> </LI><LI CLASS="li-enumerate">Edit the <TT>ejabberd</TT> configuration file to give administration rights to the Jabber account you created: <PRE CLASS="verbatim">{acl, admins, {user, "admin1", "example.org"}}. @@ -1775,7 +1765,6 @@ all entries end with a comma: <TR><TD ALIGN=left NOWRAP><TT>mod_configure</TT></TD><TD ALIGN=left NOWRAP>Server configuration using Ad-Hoc</TD><TD ALIGN=left NOWRAP><TT>mod_adhoc</TT></TD></TR> <TR><TD ALIGN=left NOWRAP><A HREF="#moddisco"><TT>mod_disco</TT></A></TD><TD ALIGN=left NOWRAP>Service Discovery (<A HREF="http://www.xmpp.org/extensions/xep-0030.html">XEP-0030</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR> <TR><TD ALIGN=left NOWRAP><A HREF="#modecho"><TT>mod_echo</TT></A></TD><TD ALIGN=left NOWRAP>Echoes Jabber packets</TD><TD ALIGN=left NOWRAP> </TD></TR> -<TR><TD ALIGN=left NOWRAP><A HREF="#modirc"><TT>mod_irc</TT></A></TD><TD ALIGN=left NOWRAP>IRC transport</TD><TD ALIGN=left NOWRAP> </TD></TR> <TR><TD ALIGN=left NOWRAP><A HREF="#modlast"><TT>mod_last</TT></A></TD><TD ALIGN=left NOWRAP>Last Activity (<A HREF="http://www.xmpp.org/extensions/xep-0012.html">XEP-0012</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR> <TR><TD ALIGN=left NOWRAP><A HREF="#modlast"><TT>mod_last_odbc</TT></A></TD><TD ALIGN=left NOWRAP>Last Activity (<A HREF="http://www.xmpp.org/extensions/xep-0012.html">XEP-0012</A>)</TD><TD ALIGN=left NOWRAP>supported DB (*)</TD></TR> <TR><TD ALIGN=left NOWRAP><A HREF="#modmuc"><TT>mod_muc</TT></A></TD><TD ALIGN=left NOWRAP>Multi-User Chat (<A HREF="http://www.xmpp.org/extensions/xep-0045.html">XEP-0045</A>)</TD><TD ALIGN=left NOWRAP> </TD></TR> @@ -1896,7 +1885,7 @@ message is sent to all registered users. If the user is online and connected to several resources, only the resource with the highest priority will receive the message. If the registered user is not connected, the message will be stored offline in assumption that offline storage -(see section <A HREF="#modoffline">3.3.10</A>) is enabled. +(see section <A HREF="#modoffline">3.3.9</A>) is enabled. </DD><DT CLASS="dt-description"><B><TT>example.org/announce/online (example.org/announce/all-hosts/online)</TT></B></DT><DD CLASS="dd-description">The message is sent to all connected users. If the user is online and connected to several resources, all resources will receive the message. @@ -2006,66 +1995,8 @@ of them all? {mod_echo, [{host, "mirror.example.org"}]}, ... ]}. -</PRE><P> <A NAME="modirc"></A> </P><!--TOC subsection <TT>mod_irc</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc43">3.3.6</A>  <A HREF="#modirc"><TT>mod_irc</TT></A></H3><!--SEC END --><P> <A NAME="modirc"></A> -</P><P>This module is an IRC transport that can be used to join channels on IRC -servers.</P><P>End user information: - -</P><UL CLASS="itemize"><LI CLASS="li-itemize"> -A Jabber client with ‘groupchat 1.0’ support or Multi-User -Chat support (<A HREF="http://www.xmpp.org/extensions/xep-0045.html">XEP-0045</A>) is necessary to join IRC channels. -</LI><LI CLASS="li-itemize">An IRC channel can be joined in nearly the same way as joining a -Jabber Multi-User Chat room. The difference is that the room name will -be ‘channel%<TT>irc.example.org</TT>’ in case <TT>irc.example.org</TT> is -the IRC server hosting ‘channel’. And of course the host should point -to the IRC transport instead of the Multi-User Chat service. -</LI><LI CLASS="li-itemize">You can register your nickame by sending ‘IDENTIFY password’ to<BR> - <TT>nickserver!irc.example.org@irc.jabberserver.org</TT>. -</LI><LI CLASS="li-itemize">Entering your password is possible by sending ‘LOGIN nick password’<BR> - to <TT>nickserver!irc.example.org@irc.jabberserver.org</TT>. -</LI><LI CLASS="li-itemize">When using a popular Jabber server, it can occur that no -connection can be achieved with some IRC servers because they limit the -number of conections from one IP. -</LI></UL><P>Options: -</P><DL CLASS="description"><DT CLASS="dt-description"> - -<B><TT>host</TT></B></DT><DD CLASS="dd-description"> This option defines the Jabber ID of the -service. If the <TT>host</TT> option is not specified, the Jabber ID will be the -hostname of the virtual host with the prefix ‘<TT>irc.</TT>’. The keyword "@HOST@" -is replaced at start time with the real virtual host name. - -</DD><DT CLASS="dt-description"><B><TT>access</TT></B></DT><DD CLASS="dd-description"> This option can be used to specify who -may use the IRC transport (default value: <TT>all</TT>). -</DD><DT CLASS="dt-description"><B><TT>default_encoding</TT></B></DT><DD CLASS="dd-description"> Set the default IRC encoding (default value: <TT>"koi8-r"</TT>). -</DD></DL><P>Examples: -</P><UL CLASS="itemize"><LI CLASS="li-itemize"> -In the first example, the IRC transport is available on (all) your -virtual host(s) with the prefix ‘<TT>irc.</TT>’. Furthermore, anyone is -able to use the transport. The default encoding is set to "iso8859-15". -<PRE CLASS="verbatim">{modules, - [ - ... - {mod_irc, [{access, all}, {default_encoding, "iso8859-15"}]}, - ... - ]}. -</PRE></LI><LI CLASS="li-itemize">In next example the IRC transport is available with JIDs with prefix <TT>irc-t.net</TT>. -Moreover, the transport is only accessible to two users -of <TT>example.org</TT>, and any user of <TT>example.com</TT>: -<PRE CLASS="verbatim">{acl, paying_customers, {user, "customer1", "example.org"}}. -{acl, paying_customers, {user, "customer2", "example.org"}}. -{acl, paying_customers, {server, "example.com"}}. - -{access, irc_users, [{allow, paying_customers}, {deny, all}]}. - -{modules, - [ - ... - {mod_irc, [{access, irc_users}, - {host, "irc.example.net"}]}, - ... - ]}. -</PRE></LI></UL><P> <A NAME="modlast"></A> </P><!--TOC subsection <TT>mod_last</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc44">3.3.7</A>  <A HREF="#modlast"><TT>mod_last</TT></A></H3><!--SEC END --><P> <A NAME="modlast"></A> +</PRE><P> <A NAME="modlast"></A> </P><!--TOC subsection <TT>mod_last</TT>--> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc43">3.3.6</A>  <A HREF="#modlast"><TT>mod_last</TT></A></H3><!--SEC END --><P> <A NAME="modlast"></A> </P><P>This module adds support for Last Activity (<A HREF="http://www.xmpp.org/extensions/xep-0012.html">XEP-0012</A>). It can be used to discover when a disconnected user last accessed the server, to know when a connected user was last active on the server, or to query the uptime of the @@ -2074,7 +2005,7 @@ connected user was last active on the server, or to query the uptime of the <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Last activity (<TT>jabber:iq:last</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modmuc"></A> </P><!--TOC subsection <TT>mod_muc</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc45">3.3.8</A>  <A HREF="#modmuc"><TT>mod_muc</TT></A></H3><!--SEC END --><P> <A NAME="modmuc"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc44">3.3.7</A>  <A HREF="#modmuc"><TT>mod_muc</TT></A></H3><!--SEC END --><P> <A NAME="modmuc"></A> </P><P>This module provides a Multi-User Chat (<A HREF="http://www.xmpp.org/extensions/xep-0045.html">XEP-0045</A>) service. Users can discover existing rooms, join or create them. Occupants of a room can chat in public or have private chats.</P><P>Some of the features of Multi-User Chat: @@ -2297,7 +2228,7 @@ the newly created rooms have by default those options. ... ]}. </PRE></LI></UL><P> <A NAME="modmuclog"></A> </P><!--TOC subsection <TT>mod_muc_log</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc46">3.3.9</A>  <A HREF="#modmuclog"><TT>mod_muc_log</TT></A></H3><!--SEC END --><P> <A NAME="modmuclog"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc45">3.3.8</A>  <A HREF="#modmuclog"><TT>mod_muc_log</TT></A></H3><!--SEC END --><P> <A NAME="modmuclog"></A> </P><P>This module enables optional logging of Multi-User Chat (MUC) public conversations to HTML. Once you enable this module, users can join a room using a MUC capable Jabber client, and if they have enough privileges, they can request the @@ -2417,7 +2348,7 @@ top link will be the default <CODE><a href="/">Home</a></CODE>. ... ]}. </PRE></LI></UL><P> <A NAME="modoffline"></A> </P><!--TOC subsection <TT>mod_offline</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc47">3.3.10</A>  <A HREF="#modoffline"><TT>mod_offline</TT></A></H3><!--SEC END --><P> <A NAME="modoffline"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc46">3.3.9</A>  <A HREF="#modoffline"><TT>mod_offline</TT></A></H3><!--SEC END --><P> <A NAME="modoffline"></A> </P><P>This module implements offline message storage. This means that all messages sent to an offline user will be stored on the server until that user comes online again. Thus it is very similar to how email works. Note that @@ -2448,7 +2379,7 @@ and all the other users up to 100. ... ]}. </PRE><P> <A NAME="modprivacy"></A> </P><!--TOC subsection <TT>mod_privacy</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc48">3.3.11</A>  <A HREF="#modprivacy"><TT>mod_privacy</TT></A></H3><!--SEC END --><P> <A NAME="modprivacy"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc47">3.3.10</A>  <A HREF="#modprivacy"><TT>mod_privacy</TT></A></H3><!--SEC END --><P> <A NAME="modprivacy"></A> </P><P>This module implements Blocking Communication (also known as Privacy Rules) as defined in section 10 from XMPP IM. If end users have support for it in their Jabber client, they will be able to: @@ -2476,7 +2407,7 @@ subscription type (or globally). <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Blocking Communication (<TT>jabber:iq:privacy</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modprivate"></A> </P><!--TOC subsection <TT>mod_private</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc49">3.3.12</A>  <A HREF="#modprivate"><TT>mod_private</TT></A></H3><!--SEC END --><P> <A NAME="modprivate"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc48">3.3.11</A>  <A HREF="#modprivate"><TT>mod_private</TT></A></H3><!--SEC END --><P> <A NAME="modprivate"></A> </P><P>This module adds support for Private XML Storage (<A HREF="http://www.xmpp.org/extensions/xep-0049.html">XEP-0049</A>): </P><BLOCKQUOTE CLASS="quote"> Using this method, Jabber entities can store private data on the server and @@ -2488,7 +2419,7 @@ of client-specific preferences; another is Bookmark Storage (<A HREF="http://www <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Private XML Storage (<TT>jabber:iq:private</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modproxy"></A> </P><!--TOC subsection <TT>mod_proxy65</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc50">3.3.13</A>  <A HREF="#modproxy"><TT>mod_proxy65</TT></A></H3><!--SEC END --><P> <A NAME="modproxy"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc49">3.3.12</A>  <A HREF="#modproxy"><TT>mod_proxy65</TT></A></H3><!--SEC END --><P> <A NAME="modproxy"></A> </P><P>This module implements SOCKS5 Bytestreams (<A HREF="http://www.xmpp.org/extensions/xep-0065.html">XEP-0065</A>). It allows <TT>ejabberd</TT> to act as a file transfer proxy between two XMPP clients.</P><P>Options: @@ -2543,7 +2474,7 @@ The simpliest configuration of the module: ... ]}. </PRE></LI></UL><P> <A NAME="modpubsub"></A> </P><!--TOC subsection <TT>mod_pubsub</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc51">3.3.14</A>  <A HREF="#modpubsub"><TT>mod_pubsub</TT></A></H3><!--SEC END --><P> <A NAME="modpubsub"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc50">3.3.13</A>  <A HREF="#modpubsub"><TT>mod_pubsub</TT></A></H3><!--SEC END --><P> <A NAME="modpubsub"></A> </P><P>This module offers a Publish-Subscribe Service (<A HREF="http://www.xmpp.org/extensions/xep-0060.html">XEP-0060</A>). The functionality in <TT>mod_pubsub</TT> can be extended using plugins. The plugin that implements PEP (Personal Eventing via Pubsub) (<A HREF="http://www.xmpp.org/extensions/xep-0163.html">XEP-0163</A>) @@ -2589,7 +2520,7 @@ The following example will use node_tune instead of node_pep for every PEP node ... ]}. </PRE><P> <A NAME="modregister"></A> </P><!--TOC subsection <TT>mod_register</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc52">3.3.15</A>  <A HREF="#modregister"><TT>mod_register</TT></A></H3><!--SEC END --><P> <A NAME="modregister"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc51">3.3.14</A>  <A HREF="#modregister"><TT>mod_register</TT></A></H3><!--SEC END --><P> <A NAME="modregister"></A> </P><P>This module adds support for In-Band Registration (<A HREF="http://www.xmpp.org/extensions/xep-0077.html">XEP-0077</A>). This protocol enables end users to use a Jabber client to: </P><UL CLASS="itemize"><LI CLASS="li-itemize"> @@ -2662,13 +2593,13 @@ Also define a registration timeout of one hour: ... ]}. </PRE></LI></UL><P> <A NAME="modroster"></A> </P><!--TOC subsection <TT>mod_roster</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc53">3.3.16</A>  <A HREF="#modroster"><TT>mod_roster</TT></A></H3><!--SEC END --><P> <A NAME="modroster"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc52">3.3.15</A>  <A HREF="#modroster"><TT>mod_roster</TT></A></H3><!--SEC END --><P> <A NAME="modroster"></A> </P><P>This module implements roster management as defined in <A HREF="http://www.xmpp.org/specs/rfc3921.html#roster">RFC 3921: XMPP IM</A>.</P><P>Options: </P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Roster Management (<TT>jabber:iq:roster</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modservicelog"></A> </P><!--TOC subsection <TT>mod_service_log</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc54">3.3.17</A>  <A HREF="#modservicelog"><TT>mod_service_log</TT></A></H3><!--SEC END --><P> <A NAME="modservicelog"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc53">3.3.16</A>  <A HREF="#modservicelog"><TT>mod_service_log</TT></A></H3><!--SEC END --><P> <A NAME="modservicelog"></A> </P><P>This module adds support for logging end user packets via a Jabber message auditing service such as <A HREF="http://www.funkypenguin.info/project/bandersnatch/">Bandersnatch</A>. All user @@ -2698,7 +2629,7 @@ To log all end user packets to the Bandersnatch service running on ... ]}. </PRE></LI></UL><P> <A NAME="modsharedroster"></A> </P><!--TOC subsection <TT>mod_shared_roster</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc55">3.3.18</A>  <A HREF="#modsharedroster"><TT>mod_shared_roster</TT></A></H3><!--SEC END --><P> <A NAME="modsharedroster"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc54">3.3.17</A>  <A HREF="#modsharedroster"><TT>mod_shared_roster</TT></A></H3><!--SEC END --><P> <A NAME="modsharedroster"></A> </P><P>This module enables you to create shared roster groups. This means that you can create groups of people that can see members from (other) groups in their rosters. The big advantages of this feature are that end users do not need to @@ -2773,7 +2704,7 @@ roster groups as shown in the following table: </TABLE> <DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV></DIV></BLOCKQUOTE> </LI></UL><P> <A NAME="modstats"></A> </P><!--TOC subsection <TT>mod_stats</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc56">3.3.19</A>  <A HREF="#modstats"><TT>mod_stats</TT></A></H3><!--SEC END --><P> <A NAME="modstats"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc55">3.3.18</A>  <A HREF="#modstats"><TT>mod_stats</TT></A></H3><!--SEC END --><P> <A NAME="modstats"></A> </P><P>This module adds support for Statistics Gathering (<A HREF="http://www.xmpp.org/extensions/xep-0039.html">XEP-0039</A>). This protocol allows you to retrieve next statistics from your <TT>ejabberd</TT> deployment: </P><UL CLASS="itemize"><LI CLASS="li-itemize"> @@ -2805,14 +2736,14 @@ by sending: </query> </iq> </PRE></LI></UL><P> <A NAME="modtime"></A> </P><!--TOC subsection <TT>mod_time</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc57">3.3.20</A>  <A HREF="#modtime"><TT>mod_time</TT></A></H3><!--SEC END --><P> <A NAME="modtime"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc56">3.3.19</A>  <A HREF="#modtime"><TT>mod_time</TT></A></H3><!--SEC END --><P> <A NAME="modtime"></A> </P><P>This module features support for Entity Time (<A HREF="http://www.xmpp.org/extensions/xep-0090.html">XEP-0090</A>). By using this XEP, you are able to discover the time at another entity’s location.</P><P>Options: </P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Entity Time (<TT>jabber:iq:time</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modvcard"></A> </P><!--TOC subsection <TT>mod_vcard</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc58">3.3.21</A>  <A HREF="#modvcard"><TT>mod_vcard</TT></A></H3><!--SEC END --><P> <A NAME="modvcard"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc57">3.3.20</A>  <A HREF="#modvcard"><TT>mod_vcard</TT></A></H3><!--SEC END --><P> <A NAME="modvcard"></A> </P><P>This module allows end users to store and retrieve their vCard, and to retrieve other users vCards, as defined in vcard-temp (<A HREF="http://www.xmpp.org/extensions/xep-0054.html">XEP-0054</A>). The module also implements an uncomplicated Jabber User Directory based on the vCards of @@ -2867,7 +2798,7 @@ and that all virtual hosts will be searched instead of only the current one: ... ]}. </PRE></LI></UL><P> <A NAME="modvcardldap"></A> </P><!--TOC subsection <TT>mod_vcard_ldap</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc59">3.3.22</A>  <A HREF="#modvcardldap"><TT>mod_vcard_ldap</TT></A></H3><!--SEC END --><P> <A NAME="modvcardldap"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc58">3.3.21</A>  <A HREF="#modvcardldap"><TT>mod_vcard_ldap</TT></A></H3><!--SEC END --><P> <A NAME="modvcardldap"></A> </P><P><TT>ejabberd</TT> can map LDAP attributes to vCard fields. This behaviour is implemented in the <TT>mod_vcard_ldap</TT> module. This module does not depend on the authentication method (see <A HREF="#ldapauth">3.2.5</A>).</P><P>Note that <TT>ejabberd</TT> treats LDAP as a read-only storage: @@ -3043,7 +2974,7 @@ searching his info in LDAP.</P></LI><LI CLASS="li-itemize"><TT>ldap_vcard_map</T {"Nickname", "NICKNAME"} ]}, </PRE></LI></UL><P> <A NAME="modversion"></A> </P><!--TOC subsection <TT>mod_version</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc60">3.3.23</A>  <A HREF="#modversion"><TT>mod_version</TT></A></H3><!--SEC END --><P> <A NAME="modversion"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc59">3.3.22</A>  <A HREF="#modversion"><TT>mod_version</TT></A></H3><!--SEC END --><P> <A NAME="modversion"></A> </P><P>This module implements Software Version (<A HREF="http://www.xmpp.org/extensions/xep-0092.html">XEP-0092</A>). Consequently, it answers <TT>ejabberd</TT>’s version when queried.</P><P>Options: </P><DL CLASS="description"><DT CLASS="dt-description"> @@ -3052,8 +2983,8 @@ The default value is <TT>true</TT>. </DD><DT CLASS="dt-description"><B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Software Version (<TT>jabber:iq:version</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="manage"></A> </P><!--TOC chapter Managing an <TT>ejabberd</TT> Server--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc61">Chapter 4</A>  <A HREF="#manage">Managing an <TT>ejabberd</TT> Server</A></H1><!--SEC END --><P> <A NAME="manage"></A> </P><P> <A NAME="ejabberdctl"></A> </P><!--TOC section <TT>ejabberdctl</TT>--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc62">4.1</A>  <A HREF="#ejabberdctl"><TT>ejabberdctl</TT></A></H2><!--SEC END --><P> <A NAME="ejabberdctl"></A> </P><P>With the <TT>ejabberdctl</TT> command line administration script +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc60">Chapter 4</A>  <A HREF="#manage">Managing an <TT>ejabberd</TT> Server</A></H1><!--SEC END --><P> <A NAME="manage"></A> </P><P> <A NAME="ejabberdctl"></A> </P><!--TOC section <TT>ejabberdctl</TT>--> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc61">4.1</A>  <A HREF="#ejabberdctl"><TT>ejabberdctl</TT></A></H2><!--SEC END --><P> <A NAME="ejabberdctl"></A> </P><P>With the <TT>ejabberdctl</TT> command line administration script you can execute <TT>ejabberdctl commands</TT> (described in the next section, <A HREF="#ectl-commands">4.1.1</A>) and also many general <TT>ejabberd commands</TT> (described in section <A HREF="#eja-commands">4.2</A>). This means you can start, stop and perform many other administrative tasks @@ -3065,7 +2996,7 @@ and other codes may be used for specific results. This can be used by other scripts to determine automatically if a command succeeded or failed, for example using: <TT>echo $?</TT></P><P> <A NAME="ectl-commands"></A> </P><!--TOC subsection ejabberdctl Commands--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc63">4.1.1</A>  <A HREF="#ectl-commands">ejabberdctl Commands</A></H3><!--SEC END --><P> <A NAME="ectl-commands"></A> </P><P>When <TT>ejabberdctl</TT> is executed without any parameter, +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc62">4.1.1</A>  <A HREF="#ectl-commands">ejabberdctl Commands</A></H3><!--SEC END --><P> <A NAME="ectl-commands"></A> </P><P>When <TT>ejabberdctl</TT> is executed without any parameter, it displays the available options. If there isn’t an <TT>ejabberd</TT> server running, the available parameters are: </P><DL CLASS="description"><DT CLASS="dt-description"> @@ -3101,7 +3032,7 @@ robot1 testuser1 testuser2 </PRE><P> <A NAME="erlangconfiguration"></A> </P><!--TOC subsection Erlang Runtime System--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc64">4.1.2</A>  <A HREF="#erlangconfiguration">Erlang Runtime System</A></H3><!--SEC END --><P> <A NAME="erlangconfiguration"></A> </P><P><TT>ejabberd</TT> is an Erlang/OTP application that runs inside an Erlang runtime system. +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc63">4.1.2</A>  <A HREF="#erlangconfiguration">Erlang Runtime System</A></H3><!--SEC END --><P> <A NAME="erlangconfiguration"></A> </P><P><TT>ejabberd</TT> is an Erlang/OTP application that runs inside an Erlang runtime system. This system is configured using environment variables and command line parameters. The <TT>ejabberdctl</TT> administration script uses many of those possibilities. You can configure some of them with the file <TT>ejabberdctl.cfg</TT>, @@ -3170,7 +3101,7 @@ Starts the Erlang system detached from the system console. </DD></DL><P> Note that some characters need to be escaped when used in shell scripts, for instance <CODE>"</CODE> and <CODE>{}</CODE>. You can find other options in the Erlang manual page (<TT>erl -man erl</TT>).</P><P> <A NAME="eja-commands"></A> </P><!--TOC section <TT>ejabberd</TT> Commands--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc65">4.2</A>  <A HREF="#eja-commands"><TT>ejabberd</TT> Commands</A></H2><!--SEC END --><P> <A NAME="eja-commands"></A> </P><P>An <TT>ejabberd command</TT> is an abstract function identified by a name, +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc64">4.2</A>  <A HREF="#eja-commands"><TT>ejabberd</TT> Commands</A></H2><!--SEC END --><P> <A NAME="eja-commands"></A> </P><P>An <TT>ejabberd command</TT> is an abstract function identified by a name, with a defined number and type of calling arguments and type of result that is registered in the <TT>ejabberd_commands</TT> service. Those commands can be defined in any Erlang module and executed using any valid frontend.</P><P><TT>ejabberd</TT> includes a frontend to execute <TT>ejabberd commands</TT>: the script <TT>ejabberdctl</TT>. @@ -3178,7 +3109,7 @@ Other known frontends that can be installed to execute ejabberd commands in diff <TT>ejabberd_xmlrpc</TT> (XML-RPC service), <TT>mod_rest</TT> (HTTP POST service), <TT>mod_shcommands</TT> (ejabberd WebAdmin page).</P><P> <A NAME="list-eja-commands"></A> </P><!--TOC subsection List of ejabberd Commands--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc66">4.2.1</A>  <A HREF="#list-eja-commands">List of ejabberd Commands</A></H3><!--SEC END --><P> <A NAME="list-eja-commands"></A> </P><P><TT>ejabberd</TT> includes a few ejabberd Commands by default. +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc65">4.2.1</A>  <A HREF="#list-eja-commands">List of ejabberd Commands</A></H3><!--SEC END --><P> <A NAME="list-eja-commands"></A> </P><P><TT>ejabberd</TT> includes a few ejabberd Commands by default. When more modules are installed, new commands may be available in the frontends.</P><P>The easiest way to get a list of the available commands, and get help for them is to use the ejabberdctl script: </P><PRE CLASS="verbatim">$ ejabberdctl help @@ -3218,7 +3149,7 @@ exist tutorials to <A HREF="http://www.ejabberd.im/migrate-to-ejabberd">migrate in offline storage. This might be useful when the number of offline messages is very high. </DD></DL><P> <A NAME="accesscommands"></A> </P><!--TOC subsection Restrict Execution with AccessCommands--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc67">4.2.2</A>  <A HREF="#accesscommands">Restrict Execution with AccessCommands</A></H3><!--SEC END --><P> <A NAME="accesscommands"></A> </P><P>The frontends can be configured to restrict access to certain commands. +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc66">4.2.2</A>  <A HREF="#accesscommands">Restrict Execution with AccessCommands</A></H3><!--SEC END --><P> <A NAME="accesscommands"></A> </P><P>The frontends can be configured to restrict access to certain commands. In that case, authentication information must be provided. In each frontend the <TT>AccessCommands</TT> option is defined in a different place. But in all cases the option syntax is the same: @@ -3264,7 +3195,7 @@ and the provided arguments do not contradict Arguments.</P><P>As an example to u {_bot_reg_test, [register, unregister], [{host, "test.org"}]} ] </PRE><P> <A NAME="webadmin"></A> </P><!--TOC section Web Admin--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc68">4.3</A>  <A HREF="#webadmin">Web Admin</A></H2><!--SEC END --><P> <A NAME="webadmin"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc67">4.3</A>  <A HREF="#webadmin">Web Admin</A></H2><!--SEC END --><P> <A NAME="webadmin"></A> </P><P>The <TT>ejabberd</TT> Web Admin allows to administer most of <TT>ejabberd</TT> using a web browser.</P><P>This feature is enabled by default: a <TT>ejabberd_http</TT> listener with the option <TT>web_admin</TT> (see section <A HREF="#listened">3.1.3</A>) is included in the listening ports. Then you can open @@ -3336,13 +3267,13 @@ The file is searched by default in The directory of the documentation can be specified in the environment variable <TT>EJABBERD_DOC_PATH</TT>. See section <A HREF="#erlangconfiguration">4.1.2</A>.</P><P> <A NAME="adhoccommands"></A> </P><!--TOC section Ad-hoc Commands--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc69">4.4</A>  <A HREF="#adhoccommands">Ad-hoc Commands</A></H2><!--SEC END --><P> <A NAME="adhoccommands"></A> </P><P>If you enable <TT>mod_configure</TT> and <TT>mod_adhoc</TT>, +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc68">4.4</A>  <A HREF="#adhoccommands">Ad-hoc Commands</A></H2><!--SEC END --><P> <A NAME="adhoccommands"></A> </P><P>If you enable <TT>mod_configure</TT> and <TT>mod_adhoc</TT>, you can perform several administrative tasks in <TT>ejabberd</TT> with a Jabber client. The client must support Ad-Hoc Commands (<A HREF="http://www.xmpp.org/extensions/xep-0050.html">XEP-0050</A>), and you must login in the Jabber server with an account with proper privileges.</P><P> <A NAME="changeerlangnodename"></A> </P><!--TOC section Change Computer Hostname--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc70">4.5</A>  <A HREF="#changeerlangnodename">Change Computer Hostname</A></H2><!--SEC END --><P> <A NAME="changeerlangnodename"></A> </P><P><TT>ejabberd</TT> uses the distributed Mnesia database. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc69">4.5</A>  <A HREF="#changeerlangnodename">Change Computer Hostname</A></H2><!--SEC END --><P> <A NAME="changeerlangnodename"></A> </P><P><TT>ejabberd</TT> uses the distributed Mnesia database. Being distributed, Mnesia enforces consistency of its file, so it stores the name of the Erlang node in it (see section <A HREF="#nodename">5.4</A>). The name of an Erlang node includes the hostname of the computer. @@ -3379,8 +3310,8 @@ mv /var/lib/ejabberd/*.* /var/lib/ejabberd/oldfiles/ </PRE></LI><LI CLASS="li-enumerate">Check that the information of the old database is available: accounts, rosters... After you finish, remember to delete the temporary backup files from public directories. </LI></OL><P> <A NAME="secure"></A> </P><!--TOC chapter Securing <TT>ejabberd</TT>--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc71">Chapter 5</A>  <A HREF="#secure">Securing <TT>ejabberd</TT></A></H1><!--SEC END --><P> <A NAME="secure"></A> </P><P> <A NAME="firewall"></A> </P><!--TOC section Firewall Settings--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc72">5.1</A>  <A HREF="#firewall">Firewall Settings</A></H2><!--SEC END --><P> <A NAME="firewall"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc70">Chapter 5</A>  <A HREF="#secure">Securing <TT>ejabberd</TT></A></H1><!--SEC END --><P> <A NAME="secure"></A> </P><P> <A NAME="firewall"></A> </P><!--TOC section Firewall Settings--> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc71">5.1</A>  <A HREF="#firewall">Firewall Settings</A></H2><!--SEC END --><P> <A NAME="firewall"></A> </P><P>You need to take the following TCP ports in mind when configuring your firewall: </P><BLOCKQUOTE CLASS="table"><DIV CLASS="center"><DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV> <TABLE BORDER=1 CELLSPACING=0 CELLPADDING=1><TR><TD ALIGN=left NOWRAP><B>Port</B></TD><TD ALIGN=left NOWRAP><B>Description</B></TD></TR> @@ -3391,7 +3322,7 @@ After you finish, remember to delete the temporary backup files from public dire <TR><TD ALIGN=left NOWRAP>port range</TD><TD ALIGN=left NOWRAP>Used for connections between Erlang nodes. This range is configurable (see section <A HREF="#epmd">5.2</A>).</TD></TR> </TABLE> <DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV></DIV></BLOCKQUOTE><P> <A NAME="epmd"></A> </P><!--TOC section epmd--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc73">5.2</A>  <A HREF="#epmd">epmd</A></H2><!--SEC END --><P> <A NAME="epmd"></A> </P><P><A HREF="http://www.erlang.org/doc/man/epmd.html">epmd (Erlang Port Mapper Daemon)</A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc72">5.2</A>  <A HREF="#epmd">epmd</A></H2><!--SEC END --><P> <A NAME="epmd"></A> </P><P><A HREF="http://www.erlang.org/doc/man/epmd.html">epmd (Erlang Port Mapper Daemon)</A> is a small name server included in Erlang/OTP and used by Erlang programs when establishing distributed Erlang communications. <TT>ejabberd</TT> needs <TT>epmd</TT> to use <TT>ejabberdctl</TT> and also when clustering <TT>ejabberd</TT> nodes. @@ -3416,7 +3347,7 @@ but can be configured in the file <TT>ejabberdctl.cfg</TT>. The Erlang command-line parameter used internally is, for example: </P><PRE CLASS="verbatim">erl ... -kernel inet_dist_listen_min 4370 inet_dist_listen_max 4375 </PRE><P> <A NAME="cookie"></A> </P><!--TOC section Erlang Cookie--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc74">5.3</A>  <A HREF="#cookie">Erlang Cookie</A></H2><!--SEC END --><P> <A NAME="cookie"></A> </P><P>The Erlang cookie is a string with numbers and letters. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc73">5.3</A>  <A HREF="#cookie">Erlang Cookie</A></H2><!--SEC END --><P> <A NAME="cookie"></A> </P><P>The Erlang cookie is a string with numbers and letters. An Erlang node reads the cookie at startup from the command-line parameter <TT>-setcookie</TT>. If not indicated, the cookie is read from the cookie file <TT>$HOME/.erlang.cookie</TT>. If this file does not exist, it is created immediately with a random cookie. @@ -3430,7 +3361,7 @@ to prevent unauthorized access or intrusion to an Erlang node. The communication between Erlang nodes are not encrypted, so the cookie could be read sniffing the traffic on the network. The recommended way to secure the Erlang node is to block the port 4369.</P><P> <A NAME="nodename"></A> </P><!--TOC section Erlang Node Name--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc75">5.4</A>  <A HREF="#nodename">Erlang Node Name</A></H2><!--SEC END --><P> <A NAME="nodename"></A> </P><P>An Erlang node may have a node name. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc74">5.4</A>  <A HREF="#nodename">Erlang Node Name</A></H2><!--SEC END --><P> <A NAME="nodename"></A> </P><P>An Erlang node may have a node name. The name can be short (if indicated with the command-line parameter <TT>-sname</TT>) or long (if indicated with the parameter <TT>-name</TT>). Starting an Erlang node with -sname limits the communication between Erlang nodes to the LAN.</P><P>Using the option <TT>-sname</TT> instead of <TT>-name</TT> is a simple method @@ -3439,7 +3370,7 @@ However, it is not ultimately effective to prevent access to the Erlang node, because it may be possible to fake the fact that you are on another network using a modified version of Erlang <TT>epmd</TT>. The recommended way to secure the Erlang node is to block the port 4369.</P><P> <A NAME="secure-files"></A> </P><!--TOC section Securing Sensible Files--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc76">5.5</A>  <A HREF="#secure-files">Securing Sensible Files</A></H2><!--SEC END --><P> <A NAME="secure-files"></A> </P><P><TT>ejabberd</TT> stores sensible data in the file system either in plain text or binary files. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc75">5.5</A>  <A HREF="#secure-files">Securing Sensible Files</A></H2><!--SEC END --><P> <A NAME="secure-files"></A> </P><P><TT>ejabberd</TT> stores sensible data in the file system either in plain text or binary files. The file system permissions should be set to only allow the proper user to read, write and execute those files and directories.</P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>ejabberd configuration file: /etc/ejabberd/ejabberd.cfg</TT></B></DT><DD CLASS="dd-description"> @@ -3459,9 +3390,9 @@ so it is preferable to secure the whole <TT>/var/lib/ejabberd/</TT> directory. </DD><DT CLASS="dt-description"><B><TT>Erlang cookie file: /var/lib/ejabberd/.erlang.cookie</TT></B></DT><DD CLASS="dd-description"> See section <A HREF="#cookie">5.3</A>. </DD></DL><P> <A NAME="clustering"></A> </P><!--TOC chapter Clustering--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc77">Chapter 6</A>  <A HREF="#clustering">Clustering</A></H1><!--SEC END --><P> <A NAME="clustering"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc76">Chapter 6</A>  <A HREF="#clustering">Clustering</A></H1><!--SEC END --><P> <A NAME="clustering"></A> </P><P> <A NAME="howitworks"></A> </P><!--TOC section How it Works--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc78">6.1</A>  <A HREF="#howitworks">How it Works</A></H2><!--SEC END --><P> <A NAME="howitworks"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc77">6.1</A>  <A HREF="#howitworks">How it Works</A></H2><!--SEC END --><P> <A NAME="howitworks"></A> </P><P>A Jabber domain is served by one or more <TT>ejabberd</TT> nodes. These nodes can be run on different machines that are connected via a network. They all must have the ability to connect to port 4369 of all another nodes, and must @@ -3475,29 +3406,29 @@ router, </LI><LI CLASS="li-itemize">session manager, </LI><LI CLASS="li-itemize">s2s manager. </LI></UL><P> <A NAME="router"></A> </P><!--TOC subsection Router--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc79">6.1.1</A>  <A HREF="#router">Router</A></H3><!--SEC END --><P> <A NAME="router"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc78">6.1.1</A>  <A HREF="#router">Router</A></H3><!--SEC END --><P> <A NAME="router"></A> </P><P>This module is the main router of Jabber packets on each node. It routes them based on their destination’s domains. It uses a global routing table. The domain of the packet’s destination is searched in the routing table, and if it is found, the packet is routed to the appropriate process. If not, it is sent to the s2s manager.</P><P> <A NAME="localrouter"></A> </P><!--TOC subsection Local Router--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc80">6.1.2</A>  <A HREF="#localrouter">Local Router</A></H3><!--SEC END --><P> <A NAME="localrouter"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc79">6.1.2</A>  <A HREF="#localrouter">Local Router</A></H3><!--SEC END --><P> <A NAME="localrouter"></A> </P><P>This module routes packets which have a destination domain equal to one of this server’s host names. If the destination JID has a non-empty user part, it is routed to the session manager, otherwise it is processed depending on its content.</P><P> <A NAME="sessionmanager"></A> </P><!--TOC subsection Session Manager--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc81">6.1.3</A>  <A HREF="#sessionmanager">Session Manager</A></H3><!--SEC END --><P> <A NAME="sessionmanager"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc80">6.1.3</A>  <A HREF="#sessionmanager">Session Manager</A></H3><!--SEC END --><P> <A NAME="sessionmanager"></A> </P><P>This module routes packets to local users. It looks up to which user resource a packet must be sent via a presence table. Then the packet is either routed to the appropriate c2s process, or stored in offline storage, or bounced back.</P><P> <A NAME="s2smanager"></A> </P><!--TOC subsection s2s Manager--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc82">6.1.4</A>  <A HREF="#s2smanager">s2s Manager</A></H3><!--SEC END --><P> <A NAME="s2smanager"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc81">6.1.4</A>  <A HREF="#s2smanager">s2s Manager</A></H3><!--SEC END --><P> <A NAME="s2smanager"></A> </P><P>This module routes packets to other Jabber servers. First, it checks if an opened s2s connection from the domain of the packet’s source to the domain of the packet’s destination exists. If that is the case, the s2s manager routes the packet to the process serving this connection, otherwise a new connection is opened.</P><P> <A NAME="cluster"></A> </P><!--TOC section Clustering Setup--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc83">6.2</A>  <A HREF="#cluster">Clustering Setup</A></H2><!--SEC END --><P> <A NAME="cluster"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc82">6.2</A>  <A HREF="#cluster">Clustering Setup</A></H2><!--SEC END --><P> <A NAME="cluster"></A> </P><P>Suppose you already configured <TT>ejabberd</TT> on one machine named (<TT>first</TT>), and you need to setup another one to make an <TT>ejabberd</TT> cluster. Then do following steps:</P><OL CLASS="enumerate" type=1><LI CLASS="li-enumerate"> @@ -3531,14 +3462,14 @@ the Erlang shell. This probably can take some time if Mnesia has not yet transfered and processed all data it needed from <TT>first</TT>.</LI><LI CLASS="li-enumerate">Now run <TT>ejabberd</TT> on <TT>second</TT> with a configuration similar as on <TT>first</TT>: you probably do not need to duplicate ‘<CODE>acl</CODE>’ and ‘<CODE>access</CODE>’ options because they will be taken from -<TT>first</TT>; and <CODE>mod_irc</CODE> should be +<TT>first</TT>. If you installed <CODE>mod_irc</CODE>, notice that it should be enabled only on one machine in the cluster. </LI></OL><P>You can repeat these steps for other machines supposed to serve this domain.</P><P> <A NAME="servicelb"></A> </P><!--TOC section Service Load-Balancing--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc84">6.3</A>  <A HREF="#servicelb">Service Load-Balancing</A></H2><!--SEC END --><P> <A NAME="servicelb"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc83">6.3</A>  <A HREF="#servicelb">Service Load-Balancing</A></H2><!--SEC END --><P> <A NAME="servicelb"></A> </P><P> <A NAME="componentlb"></A> </P><!--TOC subsection Components Load-Balancing--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc85">6.3.1</A>  <A HREF="#componentlb">Components Load-Balancing</A></H3><!--SEC END --><P> <A NAME="componentlb"></A> </P><P> <A NAME="domainlb"></A> </P><!--TOC subsection Domain Load-Balancing Algorithm--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc86">6.3.2</A>  <A HREF="#domainlb">Domain Load-Balancing Algorithm</A></H3><!--SEC END --><P> <A NAME="domainlb"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc84">6.3.1</A>  <A HREF="#componentlb">Components Load-Balancing</A></H3><!--SEC END --><P> <A NAME="componentlb"></A> </P><P> <A NAME="domainlb"></A> </P><!--TOC subsection Domain Load-Balancing Algorithm--> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc85">6.3.2</A>  <A HREF="#domainlb">Domain Load-Balancing Algorithm</A></H3><!--SEC END --><P> <A NAME="domainlb"></A> </P><P><TT>ejabberd</TT> includes an algorithm to load balance the components that are plugged on an <TT>ejabberd</TT> cluster. It means that you can plug one or several instances of the same component on each <TT>ejabberd</TT> cluster and that the traffic will be automatically distributed.</P><P>The default distribution algorithm try to deliver to a local instance of a component. If several local instances are available, one instance is chosen randomly. If no instance is available locally, one instance is chosen randomly among the remote component instances.</P><P>If you need a different behaviour, you can change the load balancing behaviour with the option <TT>domain_balancing</TT>. The syntax of the option is the following:</P><PRE CLASS="verbatim">{domain_balancing, "component.example.com", <balancing_criterium>}. </PRE><P>Several balancing criteria are available: </P><UL CLASS="itemize"><LI CLASS="li-itemize"> @@ -3547,13 +3478,13 @@ domain.</P><P> <A NAME="servicelb"></A> </P><!--TOC section Service Load-Balanci </LI><LI CLASS="li-itemize"><TT>bare_destination</TT>: the bare JID (without resource) of the packet <TT>to</TT> attribute is used. </LI><LI CLASS="li-itemize"><TT>bare_source</TT>: the bare JID (without resource) of the packet <TT>from</TT> attribute is used. </LI></UL><P>If the value corresponding to the criteria is the same, the same component instance in the cluster will be used.</P><P> <A NAME="lbbuckets"></A> </P><!--TOC subsection Load-Balancing Buckets--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc87">6.3.3</A>  <A HREF="#lbbuckets">Load-Balancing Buckets</A></H3><!--SEC END --><P> <A NAME="lbbuckets"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc86">6.3.3</A>  <A HREF="#lbbuckets">Load-Balancing Buckets</A></H3><!--SEC END --><P> <A NAME="lbbuckets"></A> </P><P>When there is a risk of failure for a given component, domain balancing can cause service trouble. If one component is failing the service will not work correctly unless the sessions are rebalanced.</P><P>In this case, it is best to limit the problem to the sessions handled by the failing component. This is what the <TT>domain_balancing_component_number</TT> option does, making the load balancing algorithm not dynamic, but sticky on a fix number of component instances.</P><P>The syntax is the following: </P><PRE CLASS="verbatim">{domain_balancing_component_number, "component.example.com", N} </PRE><P> <A NAME="debugging"></A> </P><!--TOC chapter Debugging--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc88">Chapter 7</A>  <A HREF="#debugging">Debugging</A></H1><!--SEC END --><P> <A NAME="debugging"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc87">Chapter 7</A>  <A HREF="#debugging">Debugging</A></H1><!--SEC END --><P> <A NAME="debugging"></A> </P><P> <A NAME="logfiles"></A> </P><!--TOC section Log Files--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc89">7.1</A>  <A HREF="#logfiles">Log Files</A></H2><!--SEC END --><P> <A NAME="logfiles"></A> </P><P>An <TT>ejabberd</TT> node writes two log files: +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc88">7.1</A>  <A HREF="#logfiles">Log Files</A></H2><!--SEC END --><P> <A NAME="logfiles"></A> </P><P>An <TT>ejabberd</TT> node writes two log files: </P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>ejabberd.log</TT></B></DT><DD CLASS="dd-description"> is the ejabberd service log, with the messages reported by <TT>ejabberd</TT> code </DD><DT CLASS="dt-description"><B><TT>sasl.log</TT></B></DT><DD CLASS="dd-description"> is the Erlang/OTP system log, with the messages reported by Erlang/OTP using SASL (System Architecture Support Libraries) @@ -3575,12 +3506,12 @@ The ejabberdctl command <TT>reopen-log</TT> (please refer to section <A HREF="#ectl-commands">4.1.1</A>) reopens the log files, and also renames the old ones if you didn’t rename them.</P><P> <A NAME="debugconsole"></A> </P><!--TOC section Debug Console--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc90">7.2</A>  <A HREF="#debugconsole">Debug Console</A></H2><!--SEC END --><P> <A NAME="debugconsole"></A> </P><P>The Debug Console is an Erlang shell attached to an already running <TT>ejabberd</TT> server. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc89">7.2</A>  <A HREF="#debugconsole">Debug Console</A></H2><!--SEC END --><P> <A NAME="debugconsole"></A> </P><P>The Debug Console is an Erlang shell attached to an already running <TT>ejabberd</TT> server. With this Erlang shell, an experienced administrator can perform complex tasks.</P><P>This shell gives complete control over the <TT>ejabberd</TT> server, so it is important to use it with extremely care. There are some simple and safe examples in the article <A HREF="http://www.ejabberd.im/interconnect-erl-nodes">Interconnecting Erlang Nodes</A></P><P>To exit the shell, close the window or press the keys: control+c control+c.</P><P> <A NAME="watchdog"></A> </P><!--TOC section Watchdog Alerts--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc91">7.3</A>  <A HREF="#watchdog">Watchdog Alerts</A></H2><!--SEC END --><P> <A NAME="watchdog"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc90">7.3</A>  <A HREF="#watchdog">Watchdog Alerts</A></H2><!--SEC END --><P> <A NAME="watchdog"></A> </P><P><TT>ejabberd</TT> includes a watchdog mechanism that may be useful to developers when troubleshooting a problem related to memory usage. If a process in the <TT>ejabberd</TT> server consumes more memory than the configured threshold, @@ -3598,7 +3529,7 @@ or in a conversation with the watchdog alert bot.</P><P>Example configuration: To remove all watchdog admins, set the option with an empty list: </P><PRE CLASS="verbatim">{watchdog_admins, []}. </PRE><P> <A NAME="i18ni10n"></A> </P><!--TOC chapter Internationalization and Localization--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc92">Appendix A</A>  <A HREF="#i18ni10n">Internationalization and Localization</A></H1><!--SEC END --><P> <A NAME="i18ni10n"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc91">Appendix A</A>  <A HREF="#i18ni10n">Internationalization and Localization</A></H1><!--SEC END --><P> <A NAME="i18ni10n"></A> </P><P>The source code of <TT>ejabberd</TT> supports localization. The translators can edit the <A HREF="http://www.gnu.org/software/gettext/">gettext</A> .po files @@ -3633,9 +3564,9 @@ HTTP header ‘Accept-Language: ru’</TD></TR> </TABLE></DIV> <A NAME="fig:webadmmainru"></A> <DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV></DIV></BLOCKQUOTE><P> <A NAME="releasenotes"></A> </P><!--TOC chapter Release Notes--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc93">Appendix B</A>  <A HREF="#releasenotes">Release Notes</A></H1><!--SEC END --><P> <A NAME="releasenotes"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc92">Appendix B</A>  <A HREF="#releasenotes">Release Notes</A></H1><!--SEC END --><P> <A NAME="releasenotes"></A> </P><P>Release notes are available from <A HREF="http://www.process-one.net/en/ejabberd/release_notes/">ejabberd Home Page</A></P><P> <A NAME="acknowledgements"></A> </P><!--TOC chapter Acknowledgements--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc94">Appendix C</A>  <A HREF="#acknowledgements">Acknowledgements</A></H1><!--SEC END --><P> <A NAME="acknowledgements"></A> </P><P>Thanks to all people who contributed to this guide: +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc93">Appendix C</A>  <A HREF="#acknowledgements">Acknowledgements</A></H1><!--SEC END --><P> <A NAME="acknowledgements"></A> </P><P>Thanks to all people who contributed to this guide: </P><UL CLASS="itemize"><LI CLASS="li-itemize"> Alexey Shchepin (<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A>) </LI><LI CLASS="li-itemize">Badlop (<A HREF="xmpp:badlop@jabberes.org"><TT>xmpp:badlop@jabberes.org</TT></A>) @@ -3647,7 +3578,7 @@ Alexey Shchepin (<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT </LI><LI CLASS="li-itemize">Sergei Golovan (<A HREF="xmpp:sgolovan@nes.ru"><TT>xmpp:sgolovan@nes.ru</TT></A>) </LI><LI CLASS="li-itemize">Vsevolod Pelipas (<A HREF="xmpp:vsevoload@jabber.ru"><TT>xmpp:vsevoload@jabber.ru</TT></A>) </LI></UL><P> <A NAME="copyright"></A> </P><!--TOC chapter Copyright Information--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc95">Appendix D</A>  <A HREF="#copyright">Copyright Information</A></H1><!--SEC END --><P> <A NAME="copyright"></A> </P><P>Ejabberd Installation and Operation Guide.<BR> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc94">Appendix D</A>  <A HREF="#copyright">Copyright Information</A></H1><!--SEC END --><P> <A NAME="copyright"></A> </P><P>Ejabberd Installation and Operation Guide.<BR> Copyright © 2003 — 2009 ProcessOne</P><P>This document 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 diff --git a/doc/guide.tex b/doc/guide.tex index a0bb82eb1..3901db633 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -68,7 +68,6 @@ \newcommand{\modconfigure}{\module{mod\_configure}} \newcommand{\moddisco}{\module{mod\_disco}} \newcommand{\modecho}{\module{mod\_echo}} -\newcommand{\modirc}{\module{mod\_irc}} \newcommand{\modlast}{\module{mod\_last}} \newcommand{\modlastodbc}{\module{mod\_last\_odbc}} \newcommand{\modmuc}{\module{mod\_muc}} @@ -304,7 +303,6 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need: \item Erlang mysql library. Optional. For MySQL authentication or storage. See section \ref{compilemysql}. \item Erlang pgsql library. Optional. For PostgreSQL authentication or storage. See section \ref{compilepgsql}. \item PAM library. Optional. For Pluggable Authentication Modules (PAM). See section \ref{pam}. -\item GNU Iconv 1.8 or higher, for the IRC Transport (mod\_irc). Optional. Not needed on systems with GNU Libc. See section \ref{modirc}. \item ImageMagick's Convert program. Optional. For CAPTCHA challenges. See section \ref{captcha}. \end{itemize} @@ -486,9 +484,6 @@ To compile \ejabberd{} on a Microsoft Windows system, you need: \item MS Visual C++ 6.0 Compiler \item \footahref{http://www.erlang.org/download.html}{Erlang/OTP R11B-5} \item \footahref{http://sourceforge.net/project/showfiles.php?group\_id=10127\&package\_id=11277}{Expat 2.0.0 or higher} -\item -\footahref{http://www.gnu.org/software/libiconv/}{GNU Iconv 1.9.2} -(optional) \item \footahref{http://www.slproweb.com/products/Win32OpenSSL.html}{Shining Light OpenSSL 0.9.8d or higher} (to enable SSL connections) \item \footahref{http://www.zlib.net/}{Zlib 1.2.3 or higher} @@ -507,21 +502,12 @@ We assume that we will try to put as much library as possible into \verb|C:\sdk\ Copy file \verb|C:\sdk\Expat-2.0.0\Libs\libexpat.dll| to your Windows system directory (for example, \verb|C:\WINNT| or \verb|C:\WINNT\System32|) -\item Build and install the Iconv library into the directory - \verb|C:\sdk\GnuWin32|. - - Copy file \verb|C:\sdk\GnuWin32\bin\lib*.dll| to your - Windows system directory (more installation instructions can be found in the - file README.woe32 in the iconv distribution). - - Note: instead of copying libexpat.dll and iconv.dll to the Windows - directory, you can add the directories - \verb|C:\sdk\Expat-2.0.0\Libs| and - \verb|C:\sdk\GnuWin32\bin| to the \verb|PATH| environment - variable. + Note: instead of copying libexpat.dll to the Windows + directory, you can add the directory \verb|C:\sdk\Expat-2.0.0\Libs| + to the \verb|PATH| environment variable. \item Install OpenSSL in \verb|C:\sdk\OpenSSL| and add \verb|C:\sdk\OpenSSL\lib\VC| to your path or copy the binaries to your system directory. \item Install ZLib in \verb|C:\sdk\gnuWin32|. Copy - \verb|C:\sdk\GnuWin32\bin\zlib1.dll| to your system directory. If you change your path it should already be set after libiconv install. + \verb|C:\sdk\GnuWin32\bin\zlib1.dll| to your system directory. \item Make sure the you can access Erlang binaries from your path. For example: \verb|set PATH=%PATH%;"C:\sdk\erl5.6.5\bin"| \item Depending on how you end up actually installing the library you might need to check and tweak the paths in the file configure.erl. \item While in the directory \verb|ejabberd\src| run: @@ -2367,7 +2353,6 @@ The following table lists all modules included in \ejabberd{}. \hline \modconfigure{} & Server configuration using Ad-Hoc & \modadhoc{} \\ \hline \ahrefloc{moddisco}{\moddisco{}} & Service Discovery (\xepref{0030}) & \\ \hline \ahrefloc{modecho}{\modecho{}} & Echoes Jabber packets & \\ - \hline \ahrefloc{modirc}{\modirc{}} & IRC transport & \\ \hline \ahrefloc{modlast}{\modlast{}} & Last Activity (\xepref{0012}) & \\ \hline \ahrefloc{modlast}{\modlastodbc{}} & Last Activity (\xepref{0012}) & supported DB (*) \\ \hline \ahrefloc{modmuc}{\modmuc{}} & Multi-User Chat (\xepref{0045}) & \\ @@ -2667,72 +2652,6 @@ Example: Mirror, mirror, on the wall, who is the most beautiful \ifthenelse{\boolean{modhttpfileserver}}{\input{mod_http_fileserver.tex}}{} -\makesubsection{modirc}{\modirc{}} -\ind{modules!\modirc{}}\ind{IRC} - -This module is an IRC transport that can be used to join channels on IRC -servers. - -End user information: -\ind{protocols!groupchat 1.0}\ind{protocols!XEP-0045: Multi-User Chat} -\begin{itemize} -\item A \Jabber{} client with `groupchat 1.0' support or Multi-User - Chat support (\xepref{0045}) is necessary to join IRC channels. -\item An IRC channel can be joined in nearly the same way as joining a - \Jabber{} Multi-User Chat room. The difference is that the room name will - be `channel\%\jid{irc.example.org}' in case \jid{irc.example.org} is - the IRC server hosting `channel'. And of course the host should point - to the IRC transport instead of the Multi-User Chat service. -\item You can register your nickame by sending `IDENTIFY password' to \\ - \jid{nickserver!irc.example.org@irc.jabberserver.org}. -\item Entering your password is possible by sending `LOGIN nick password' \\ - to \jid{nickserver!irc.example.org@irc.jabberserver.org}. -\item When using a popular \Jabber{} server, it can occur that no - connection can be achieved with some IRC servers because they limit the - number of conections from one IP. -\end{itemize} - -Options: -\begin{description} -\hostitem{irc} -\titem{access} \ind{options!access}This option can be used to specify who - may use the IRC transport (default value: \term{all}). -\titem{default\_encoding} \ind{options!defaultencoding}Set the default IRC encoding (default value: \term{"koi8-r"}). -\end{description} - -Examples: -\begin{itemize} -\item In the first example, the IRC transport is available on (all) your - virtual host(s) with the prefix `\jid{irc.}'. Furthermore, anyone is - able to use the transport. The default encoding is set to "iso8859-15". -\begin{verbatim} -{modules, - [ - ... - {mod_irc, [{access, all}, {default_encoding, "iso8859-15"}]}, - ... - ]}. -\end{verbatim} -\item In next example the IRC transport is available with JIDs with prefix \jid{irc-t.net}. - Moreover, the transport is only accessible to two users - of \term{example.org}, and any user of \term{example.com}: -\begin{verbatim} -{acl, paying_customers, {user, "customer1", "example.org"}}. -{acl, paying_customers, {user, "customer2", "example.org"}}. -{acl, paying_customers, {server, "example.com"}}. - -{access, irc_users, [{allow, paying_customers}, {deny, all}]}. - -{modules, - [ - ... - {mod_irc, [{access, irc_users}, - {host, "irc.example.net"}]}, - ... - ]}. -\end{verbatim} -\end{itemize} - \makesubsection{modlast}{\modlast{}} \ind{modules!\modlast{}}\ind{protocols!XEP-0012: Last Activity} @@ -4612,7 +4531,7 @@ mnesia:change_table_copy_type(schema, node(), disc_copies). \item Now run \ejabberd{} on \term{second} with a configuration similar as on \term{first}: you probably do not need to duplicate `\verb|acl|' and `\verb|access|' options because they will be taken from - \term{first}; and \verb|mod_irc| should be + \term{first}. If you installed \verb|mod_irc|, notice that it should be enabled only on one machine in the cluster. \end{enumerate} diff --git a/doc/introduction.tex b/doc/introduction.tex index 1991c93ec..6cedbd161 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -127,7 +127,6 @@ Moreover, \ejabberd{} comes with a wide range of other state-of-the-art features \item Users Directory based on users vCards. \item \txepref{0060}{Publish-Subscribe} component with support for \txepref{0163}{Personal Eventing via Pubsub}. \item Support for web clients: \txepref{0025}{HTTP Polling} and \txepref{0206}{HTTP Binding (BOSH)} services. -\item IRC transport. \item Component support: interface with networks such as AIM, ICQ and MSN installing special tranports. \end{itemize} \end{itemize} diff --git a/examples/mtr/ejabberd-netbsd.sh b/examples/mtr/ejabberd-netbsd.sh index 9896c9bc4..31d01b6b8 100644 --- a/examples/mtr/ejabberd-netbsd.sh +++ b/examples/mtr/ejabberd-netbsd.sh @@ -70,7 +70,7 @@ done echo '7. compile ejabberd' gmake -for A in mod_irc mod_muc mod_pubsub; do +for A in mod_muc mod_pubsub; do (cd $A; gmake) done diff --git a/src/Makefile.in b/src/Makefile.in index 8ba622d54..24b12e301 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -63,7 +63,7 @@ endif prefix = @prefix@ exec_prefix = @exec_prefix@ -SUBDIRS = @mod_irc@ @mod_pubsub@ @mod_muc@ @mod_proxy65@ @eldap@ @pam@ @web@ stringprep @tls@ @odbc@ @ejabberd_zlib@ +SUBDIRS = @mod_pubsub@ @mod_muc@ @mod_proxy65@ @eldap@ @pam@ @web@ stringprep @tls@ @odbc@ @ejabberd_zlib@ ERLSHLIBS = expat_erl.so ERLBEHAVS = cyrsasl.erl gen_mod.erl p1_fsm.erl SOURCES_ALL = $(wildcard *.erl) diff --git a/src/Makefile.win32 b/src/Makefile.win32 index 9d21e896a..b866f11ff 100644 --- a/src/Makefile.win32 +++ b/src/Makefile.win32 @@ -52,9 +52,6 @@ release : build release_clean mkdir $(SRC_DIR)\eldap copy eldap\eldap.* $(SRC_DIR)\eldap copy eldap\ELDAPv3.asn $(SRC_DIR)\eldap - mkdir $(SRC_DIR)\mod_irc - copy mod_irc\*.erl $(SRC_DIR)\mod_irc - copy mod_irc\*.c $(SRC_DIR)\mod_irc mkdir $(SRC_DIR)\mod_muc copy mod_muc\*.erl $(SRC_DIR)\mod_muc mkdir $(SRC_DIR)\mod_pubsub @@ -91,8 +88,6 @@ build : $(DLL) compile-beam all-recursive all-recursive : cd eldap nmake -nologo -f Makefile.win32 - cd ..\mod_irc - nmake -nologo -f Makefile.win32 cd ..\mod_muc nmake -nologo -f Makefile.win32 cd ..\mod_pubsub @@ -132,8 +127,6 @@ clean-local : clean-recursive : cd eldap nmake -nologo -f Makefile.win32 clean - cd ..\mod_irc - nmake -nologo -f Makefile.win32 clean cd ..\mod_muc nmake -nologo -f Makefile.win32 clean cd ..\mod_pubsub diff --git a/src/aclocal.m4 b/src/aclocal.m4 index 5365443f0..c1f354bb9 100644 --- a/src/aclocal.m4 +++ b/src/aclocal.m4 @@ -226,96 +226,6 @@ AC_SUBST(make_$1) ]) - -dnl From Bruno Haible. - -AC_DEFUN([AM_ICONV], -[ - dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and - dnl those with the standalone portable GNU libiconv installed). - AC_ARG_WITH([libiconv-prefix], - [AC_HELP_STRING([--with-libiconv-prefix=PREFIX], [prefix where libiconv is installed])], [ - for dir in `echo "$withval" | tr : ' '`; do - if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi - if test -d $dir/include; then CFLAGS="$CFLAGS -I$dir/include"; fi - if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi - done - ]) - - AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [ - am_cv_func_iconv="no, consider installing GNU libiconv" - am_cv_lib_iconv=no - AC_TRY_LINK([#include <stdlib.h> -#include <iconv.h>], - [iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd);], - am_cv_func_iconv=yes) - if test "$am_cv_func_iconv" != yes; then - am_save_LIBS="$LIBS" - LIBS="$LIBS -liconv" - AC_TRY_LINK([#include <stdlib.h> -#include <iconv.h>], - [iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd);], - am_cv_lib_iconv=yes - am_cv_func_iconv=yes) - LIBS="$am_save_LIBS" - fi - dnl trying /usr/local - if test "$am_cv_func_iconv" != yes; then - am_save_LIBS="$LIBS" - am_save_CFLAGS="$CFLAGS" - am_save_LDFLAGS="$LDFLAGS" - LIBS="$LIBS -liconv" - LDFLAGS="$LDFLAGS -L/usr/local/lib" - CFLAGS="$CFLAGS -I/usr/local/include" - AC_TRY_LINK([#include <stdlib.h> -#include <iconv.h>], - [iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd);], - am_cv_lib_iconv=yes - am_cv_func_iconv=yes - CPPFLAGS="$CPPFLAGS -I/usr/local/include", - LDFLAGS="$am_save_LDFLAGS" - CFLAGS="$am_save_CFLAGS") - LIBS="$am_save_LIBS" - fi - - ]) - if test "$am_cv_func_iconv" = yes; then - AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) - AC_MSG_CHECKING([for iconv declaration]) - AC_CACHE_VAL(am_cv_proto_iconv, [ - AC_TRY_COMPILE([ -#include <stdlib.h> -#include <iconv.h> -extern -#ifdef __cplusplus -"C" -#endif -#if defined(__STDC__) || defined(__cplusplus) -size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); -#else -size_t iconv(); -#endif -], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const") - am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) - am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` - AC_MSG_RESULT([$]{ac_t:- - }[$]am_cv_proto_iconv) - AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, - [Define as const if the declaration of iconv() needs const.]) - fi - LIBICONV= - if test "$am_cv_lib_iconv" = yes; then - LIBICONV="-liconv" - fi - AC_SUBST(LIBICONV) -]) - dnl <openssl> AC_DEFUN(AM_WITH_OPENSSL, [ AC_ARG_WITH(openssl, diff --git a/src/configure b/src/configure index ec6bd6d91..468877f3b 100755 --- a/src/configure +++ b/src/configure @@ -666,15 +666,12 @@ ERLANG_CFLAGS ERLANG_LIBS ERLANG_SSL39 ERLANG_EXMPP -LIBICONV CPP GREP EGREP EXPAT_CFLAGS EXPAT_LIBS LIBOBJS -mod_irc -make_mod_irc mod_muc make_mod_muc mod_proxy65 @@ -1286,7 +1283,6 @@ if test -n "$ac_init_help"; then Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-mod_irc enable mod_irc (default: yes) --enable-mod_muc enable mod_muc (default: yes) --enable-mod_proxy65 enable mod_proxy65 (default: yes) --enable-mod_pubsub enable mod_pubsub (default: yes) @@ -1315,8 +1311,6 @@ Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-erlang=PREFIX path to erlc and erl - --with-libiconv-prefix=PREFIX - prefix where libiconv is installed --with-expat=PREFIX prefix where EXPAT is installed --with-zlib=PREFIX prefix where zlib is installed --with-pam=PREFIX prefix where PAM is installed @@ -3040,277 +3034,8 @@ echo "$as_me: error: erlang program was not properly executed, (conftest.out was -#locating iconv - - - -# Check whether --with-libiconv-prefix was given. -if test "${with_libiconv_prefix+set}" = set; then - withval=$with_libiconv_prefix; - for dir in `echo "$withval" | tr : ' '`; do - if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi - if test -d $dir/include; then CFLAGS="$CFLAGS -I$dir/include"; fi - if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi - done - -fi - - - { echo "$as_me:$LINENO: checking for iconv" >&5 -echo $ECHO_N "checking for iconv... $ECHO_C" >&6; } -if test "${am_cv_func_iconv+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - - am_cv_func_iconv="no, consider installing GNU libiconv" - am_cv_lib_iconv=no - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <stdlib.h> -#include <iconv.h> -int -main () -{ -iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - am_cv_func_iconv=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext - if test "$am_cv_func_iconv" != yes; then - am_save_LIBS="$LIBS" - LIBS="$LIBS -liconv" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <stdlib.h> -#include <iconv.h> -int -main () -{ -iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - am_cv_lib_iconv=yes - am_cv_func_iconv=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext - LIBS="$am_save_LIBS" - fi - if test "$am_cv_func_iconv" != yes; then - am_save_LIBS="$LIBS" - am_save_CFLAGS="$CFLAGS" - am_save_LDFLAGS="$LDFLAGS" - LIBS="$LIBS -liconv" - LDFLAGS="$LDFLAGS -L/usr/local/lib" - CFLAGS="$CFLAGS -I/usr/local/include" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <stdlib.h> -#include <iconv.h> -int -main () -{ -iconv_t cd = iconv_open("",""); - iconv(cd,NULL,NULL,NULL,NULL); - iconv_close(cd); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then - am_cv_lib_iconv=yes - am_cv_func_iconv=yes - CPPFLAGS="$CPPFLAGS -I/usr/local/include" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - LDFLAGS="$am_save_LDFLAGS" - CFLAGS="$am_save_CFLAGS" -fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext - LIBS="$am_save_LIBS" - fi - - -fi -{ echo "$as_me:$LINENO: result: $am_cv_func_iconv" >&5 -echo "${ECHO_T}$am_cv_func_iconv" >&6; } - if test "$am_cv_func_iconv" = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_ICONV 1 -_ACEOF - - { echo "$as_me:$LINENO: checking for iconv declaration" >&5 -echo $ECHO_N "checking for iconv declaration... $ECHO_C" >&6; } - if test "${am_cv_proto_iconv+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - -#include <stdlib.h> -#include <iconv.h> -extern -#ifdef __cplusplus -"C" -#endif -#if defined(__STDC__) || defined(__cplusplus) -size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); -#else -size_t iconv(); -#endif - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - am_cv_proto_iconv_arg1="" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - am_cv_proto_iconv_arg1="const" -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" -fi - - am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` - { echo "$as_me:$LINENO: result: ${ac_t:- - }$am_cv_proto_iconv" >&5 -echo "${ECHO_T}${ac_t:- - }$am_cv_proto_iconv" >&6; } - -cat >>confdefs.h <<_ACEOF -#define ICONV_CONST $am_cv_proto_iconv_arg1 -_ACEOF - - fi - LIBICONV= - if test "$am_cv_lib_iconv" = yes; then - LIBICONV="-liconv" - fi - - #locating libexpat + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -4723,28 +4448,6 @@ fi -mod_irc= -make_mod_irc= -{ echo "$as_me:$LINENO: checking whether build mod_irc" >&5 -echo $ECHO_N "checking whether build mod_irc... $ECHO_C" >&6; } -# Check whether --enable-mod_irc was given. -if test "${enable_mod_irc+set}" = set; then - enableval=$enable_mod_irc; mr_enable_mod_irc="$enableval" -else - mr_enable_mod_irc=yes -fi - -if test "$mr_enable_mod_irc" = "yes"; then -mod_irc=mod_irc -make_mod_irc=mod_irc/Makefile -fi -{ echo "$as_me:$LINENO: result: $mr_enable_mod_irc" >&5 -echo "${ECHO_T}$mr_enable_mod_irc" >&6; } - - - - - mod_muc= make_mod_muc= { echo "$as_me:$LINENO: checking whether build mod_muc" >&5 @@ -5523,7 +5226,7 @@ fi -ac_config_files="$ac_config_files Makefile $make_mod_irc $make_mod_muc $make_mod_pubsub $make_mod_proxy65 $make_eldap $make_pam $make_web stringprep/Makefile $make_tls $make_odbc $make_ejabberd_zlib" +ac_config_files="$ac_config_files Makefile $make_mod_muc $make_mod_pubsub $make_mod_proxy65 $make_eldap $make_pam $make_web stringprep/Makefile $make_tls $make_odbc $make_ejabberd_zlib" #openssl @@ -6510,7 +6213,6 @@ for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "$make_mod_irc") CONFIG_FILES="$CONFIG_FILES $make_mod_irc" ;; "$make_mod_muc") CONFIG_FILES="$CONFIG_FILES $make_mod_muc" ;; "$make_mod_pubsub") CONFIG_FILES="$CONFIG_FILES $make_mod_pubsub" ;; "$make_mod_proxy65") CONFIG_FILES="$CONFIG_FILES $make_mod_proxy65" ;; @@ -6632,15 +6334,12 @@ ERLANG_CFLAGS!$ERLANG_CFLAGS$ac_delim ERLANG_LIBS!$ERLANG_LIBS$ac_delim ERLANG_SSL39!$ERLANG_SSL39$ac_delim ERLANG_EXMPP!$ERLANG_EXMPP$ac_delim -LIBICONV!$LIBICONV$ac_delim CPP!$CPP$ac_delim GREP!$GREP$ac_delim EGREP!$EGREP$ac_delim EXPAT_CFLAGS!$EXPAT_CFLAGS$ac_delim EXPAT_LIBS!$EXPAT_LIBS$ac_delim LIBOBJS!$LIBOBJS$ac_delim -mod_irc!$mod_irc$ac_delim -make_mod_irc!$make_mod_irc$ac_delim mod_muc!$mod_muc$ac_delim make_mod_muc!$make_mod_muc$ac_delim mod_proxy65!$mod_proxy65$ac_delim @@ -6674,7 +6373,7 @@ INSTALLUSER!$INSTALLUSER$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 91; then + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 88; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 diff --git a/src/configure.ac b/src/configure.ac index c325c3f54..dc2359e47 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -14,8 +14,6 @@ fi #locating erlang AM_WITH_ERLANG -#locating iconv -AM_ICONV #locating libexpat AM_WITH_EXPAT @@ -32,7 +30,6 @@ AC_PREFIX_DEFAULT(/) AC_FUNC_MALLOC AC_HEADER_STDC -AC_MOD_ENABLE(mod_irc, yes) AC_MOD_ENABLE(mod_muc, yes) AC_MOD_ENABLE(mod_proxy65, yes) AC_MOD_ENABLE(mod_pubsub, yes) @@ -95,7 +92,6 @@ esac],[full_xml=false]) AC_SUBST(full_xml) AC_CONFIG_FILES([Makefile - $make_mod_irc $make_mod_muc $make_mod_pubsub $make_mod_proxy65 diff --git a/src/configure.erl b/src/configure.erl index cd7e48710..bd5e3e995 100644 --- a/src/configure.erl +++ b/src/configure.erl @@ -44,15 +44,11 @@ start() -> true -> ExpatLib = "EXPAT_LIB = $(EXPAT_DIR)\\StaticLibs\\libexpatMT.lib\n", ExpatFlag = "EXPAT_FLAG = -DXML_STATIC\n", - IconvDir = "ICONV_DIR = c:\\sdk\\GnuWin32\n", - IconvLib = "ICONV_LIB = $(ICONV_DIR)\\lib\\libiconv.lib\n", ZlibDir = "ZLIB_DIR = c:\\sdk\\GnuWin32\n", ZlibLib = "ZLIB_LIB = $(ZLIB_DIR)\\lib\\zlib.lib\n"; false -> ExpatLib = "EXPAT_LIB = $(EXPAT_DIR)\\Libs\\libexpat.lib\n", ExpatFlag = "", - IconvDir = "ICONV_DIR = c:\\sdk\\GnuWin32\n", - IconvLib = "ICONV_LIB = $(ICONV_DIR)\\lib\\libiconv.lib\n", ZlibDir = "ZLIB_DIR = c:\\sdk\\GnuWin32\n", ZlibLib = "ZLIB_LIB = $(ZLIB_DIR)\\lib\\zlib.lib\n" end, @@ -82,8 +78,6 @@ start() -> ExpatDir ++ ExpatLib ++ ExpatFlag ++ - IconvDir ++ - IconvLib ++ ZlibDir ++ ZlibLib)), halt(). diff --git a/src/ejabberd.app b/src/ejabberd.app index 7f0948f04..c80650df3 100644 --- a/src/ejabberd.app +++ b/src/ejabberd.app @@ -61,7 +61,6 @@ gen_mod, gen_pubsub_node, gen_pubsub_nodetree, - iconv, idna, jd2ejd, jlib, @@ -74,8 +73,6 @@ mod_echo, mod_http_bind, mod_http_fileserver, - mod_irc, - mod_irc_connection, mod_last, mod_last_odbc, mod_muc, @@ -142,7 +139,6 @@ ejabberd_mod_roster, ejabberd_mod_echo, ejabberd_mod_pubsub, - ejabberd_mod_irc, ejabberd_mod_muc, ejabberd_offline, random_generator diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index cb07c89e1..4b16b89b5 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -474,7 +474,6 @@ {mod_configure,[]}, % requires mod_adhoc {mod_disco, []}, %%{mod_echo, [{host, "echo.localhost"}]}, - {mod_irc, []}, {mod_last, []}, {mod_muc, [ %%{host, "conference.@HOST@"}, diff --git a/src/mod_irc/Makefile.in b/src/mod_irc/Makefile.in deleted file mode 100644 index 9dcf9f182..000000000 --- a/src/mod_irc/Makefile.in +++ /dev/null @@ -1,60 +0,0 @@ -# $Id$ - -CC = @CC@ -CFLAGS = @CFLAGS@ -CPPFLAGS = @CPPFLAGS@ -LDFLAGS = @LDFLAGS@ -LIBS = @LIBS@ @LIBICONV@ - -ERLANG_CFLAGS = @ERLANG_CFLAGS@ -ERLANG_LIBS = @ERLANG_LIBS@ - -# Assume Linux-style dynamic library flags -DYNAMIC_LIB_CFLAGS = -fpic -shared -ifeq ($(shell uname),Darwin) - DYNAMIC_LIB_CFLAGS = -fPIC -bundle -flat_namespace -undefined suppress -endif -ifeq ($(shell uname),SunOs) - DYNAMIC_LIB_CFLAGS = -KPIC -G -z text -endif - - -EFLAGS += -I .. -EFLAGS += -pz .. - -# make debug=true to compile Erlang module with debug informations. -ifdef debug - EFLAGS+=+debug_info -endif - -ERLSHLIBS = ../iconv_erl.so -OUTDIR = .. -SOURCES = $(wildcard *.erl) -BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam)) - -all: $(BEAMS) $(ERLSHLIBS) - -$(OUTDIR)/%.beam: %.erl - @ERLC@ -W $(EFLAGS) -o $(OUTDIR) $< - -#all: $(ERLSHLIBS) -# erl -s make all report "{outdir, \"..\"}" -noinput -s erlang halt - -$(ERLSHLIBS): ../%.so: %.c - $(CC) $(INCLUDES) $(CFLAGS) $(LDFLAGS) \ - $(subst ../,,$(subst .so,.c,$@)) \ - $(LIBS) \ - $(ERLANG_CFLAGS) \ - $(ERLANG_LIBS) \ - -o $@ \ - $(DYNAMIC_LIB_CFLAGS) - -clean: - rm -f $(BEAMS) $(ERLSHLIBS) - -distclean: clean - rm -f Makefile - -TAGS: - etags *.erl - diff --git a/src/mod_irc/Makefile.win32 b/src/mod_irc/Makefile.win32 deleted file mode 100644 index 9c22f43f1..000000000 --- a/src/mod_irc/Makefile.win32 +++ /dev/null @@ -1,42 +0,0 @@ - -include ..\Makefile.inc - -EFLAGS = -I .. -pz .. - -OUTDIR = .. -BEAMS = ..\iconv.beam ..\mod_irc.beam ..\mod_irc_connection.beam - -SOURCE = iconv_erl.c -OBJECT = iconv_erl.o -DLL = $(OUTDIR)\iconv_erl.dll - -ALL : $(DLL) $(BEAMS) - -CLEAN : - -@erase $(DLL) - -@erase $(OUTDIR)\iconv_erl.exp - -@erase $(OUTDIR)\iconv_erl.lib - -@erase $(OBJECT) - -@erase $(BEAMS) - -$(OUTDIR)\iconv.beam : iconv.erl - erlc -W $(EFLAGS) -o $(OUTDIR) iconv.erl - -$(OUTDIR)\mod_irc.beam : mod_irc.erl - erlc -W $(EFLAGS) -o $(OUTDIR) mod_irc.erl - -$(OUTDIR)\mod_irc_connection.beam : mod_irc_connection.erl - erlc -W $(EFLAGS) -o $(OUTDIR) mod_irc_connection.erl - -CC=cl.exe -CC_FLAGS=-nologo -D__WIN32__ -DWIN32 -DWINDOWS -D_WIN32 -DNT -MD -Ox -I"$(ERLANG_DIR)\usr\include" -I"$(EI_DIR)\include" -I"$(ICONV_DIR)\include" - -LD=link.exe -LD_FLAGS=-release -nologo -incremental:no -dll "$(EI_DIR)\lib\ei_md.lib" "$(EI_DIR)\lib\erl_interface_md.lib" "$(ICONV_LIB)" MSVCRT.LIB kernel32.lib advapi32.lib gdi32.lib user32.lib comctl32.lib comdlg32.lib shell32.lib - -$(DLL) : $(OBJECT) - $(LD) $(LD_FLAGS) -out:$(DLL) $(OBJECT) - -$(OBJECT) : $(SOURCE) - $(CC) $(CC_FLAGS) -c -Fo$(OBJECT) $(SOURCE) - diff --git a/src/mod_irc/iconv.erl b/src/mod_irc/iconv.erl deleted file mode 100644 index 8cccf2df8..000000000 --- a/src/mod_irc/iconv.erl +++ /dev/null @@ -1,94 +0,0 @@ -%%%---------------------------------------------------------------------- -%%% File : iconv.erl -%%% Author : Alexey Shchepin <alexey@process-one.net> -%%% Purpose : Interface to libiconv -%%% Created : 16 Feb 2003 by Alexey Shchepin <alexey@process-one.net> -%%% -%%% -%%% ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA -%%% 02111-1307 USA -%%% -%%%---------------------------------------------------------------------- - --module(iconv). --author('alexey@process-one.net'). - --behaviour(gen_server). - --export([start/0, start_link/0, convert/3]). - -%% Internal exports, call-back functions. --export([init/1, - handle_call/3, - handle_cast/2, - handle_info/2, - code_change/3, - terminate/2]). - - - -start() -> - gen_server:start({local, ?MODULE}, ?MODULE, [], []). - -start_link() -> - gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). - -init([]) -> - case erl_ddll:load_driver(ejabberd:get_so_path(), iconv_erl) of - ok -> ok; - {error, already_loaded} -> ok - end, - Port = open_port({spawn, iconv_erl}, []), - ets:new(iconv_table, [set, public, named_table]), - ets:insert(iconv_table, {port, Port}), - {ok, Port}. - - -%%% -------------------------------------------------------- -%%% The call-back functions. -%%% -------------------------------------------------------- - -handle_call(_, _, State) -> - {noreply, State}. - -handle_cast(_, State) -> - {noreply, State}. - -handle_info({'EXIT', Port, Reason}, Port) -> - {stop, {port_died, Reason}, Port}; -handle_info({'EXIT', _Pid, _Reason}, Port) -> - {noreply, Port}; -handle_info(_, State) -> - {noreply, State}. - -code_change(_OldVsn, State, _Extra) -> - {ok, State}. - -terminate(_Reason, Port) -> - Port ! {self, close}, - ok. - - - -convert(From, To, String) -> - [{port, Port} | _] = ets:lookup(iconv_table, port), - Bin = term_to_binary({From, To, String}), - BRes = port_control(Port, 1, Bin), - binary_to_list(BRes). - - - diff --git a/src/mod_irc/iconv_erl.c b/src/mod_irc/iconv_erl.c deleted file mode 100644 index e845635b3..000000000 --- a/src/mod_irc/iconv_erl.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - * - */ - -#include <stdio.h> -#include <string.h> -#include <erl_driver.h> -#include <ei.h> -#include <iconv.h> - -typedef struct { - ErlDrvPort port; - iconv_t cd; -} iconv_data; - - -static ErlDrvData iconv_erl_start(ErlDrvPort port, char *buff) -{ - iconv_data* d = (iconv_data*)driver_alloc(sizeof(iconv_data)); - d->port = port; - d->cd = NULL; - - set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY); - - return (ErlDrvData)d; -} - -static void iconv_erl_stop(ErlDrvData handle) -{ - driver_free((char*)handle); -} - -static int iconv_erl_control(ErlDrvData drv_data, - unsigned int command, - char *buf, int len, - char **rbuf, int rlen) -{ - int i; - int size; - int index = 0; - int avail; - size_t inleft, outleft; - ErlDrvBinary *b; - char *from, *to, *string, *stmp, *rstring, *rtmp; - iconv_t cd; - - ei_decode_version(buf, &index, &i); - ei_decode_tuple_header(buf, &index, &i); - ei_get_type(buf, &index, &i, &size); - from = malloc(size + 1); - ei_decode_string(buf, &index, from); - - ei_get_type(buf, &index, &i, &size); - to = malloc(size + 1); - ei_decode_string(buf, &index, to); - - ei_get_type(buf, &index, &i, &size); - stmp = string = malloc(size + 1); - ei_decode_string(buf, &index, string); - - cd = iconv_open(to, from); - - if (cd == (iconv_t) -1) { - cd = iconv_open("ascii", "ascii"); - if (cd == (iconv_t) -1) { - *rbuf = (char*)(b = driver_alloc_binary(size)); - memcpy(b->orig_bytes, string, size); - - free(from); - free(to); - free(string); - - return size; - } - } - - outleft = avail = 4*size; - inleft = size; - rtmp = rstring = malloc(avail); - while (inleft > 0) { - if (iconv(cd, &stmp, &inleft, &rtmp, &outleft) == (size_t) -1) { - stmp++; - inleft--; - } - } - - size = rtmp - rstring; - - *rbuf = (char*)(b = driver_alloc_binary(size)); - memcpy(b->orig_bytes, rstring, size); - - free(from); - free(to); - free(string); - free(rstring); - iconv_close(cd); - - return size; -} - - - -ErlDrvEntry iconv_driver_entry = { - NULL, /* F_PTR init, N/A */ - iconv_erl_start, /* L_PTR start, called when port is opened */ - iconv_erl_stop, /* F_PTR stop, called when port is closed */ - NULL, /* F_PTR output, called when erlang has sent */ - NULL, /* F_PTR ready_input, called when input descriptor ready */ - NULL, /* F_PTR ready_output, called when output descriptor ready */ - "iconv_erl", /* char *driver_name, the argument to open_port */ - NULL, /* F_PTR finish, called when unloaded */ - NULL, /* handle */ - iconv_erl_control, /* F_PTR control, port_command callback */ - NULL, /* F_PTR timeout, reserved */ - NULL /* F_PTR outputv, reserved */ -}; - -DRIVER_INIT(iconv_erl) /* must match name in driver_entry */ -{ - return &iconv_driver_entry; -} - - diff --git a/src/mod_irc/mod_irc.erl b/src/mod_irc/mod_irc.erl deleted file mode 100644 index a12853d33..000000000 --- a/src/mod_irc/mod_irc.erl +++ /dev/null @@ -1,593 +0,0 @@ -%%%---------------------------------------------------------------------- -%%% File : mod_irc.erl -%%% Author : Alexey Shchepin <alexey@process-one.net> -%%% Purpose : IRC transport -%%% Created : 15 Feb 2003 by Alexey Shchepin <alexey@process-one.net> -%%% -%%% -%%% ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA -%%% 02111-1307 USA -%%% -%%%---------------------------------------------------------------------- - --module(mod_irc). --author('alexey@process-one.net'). - --behaviour(gen_server). --behaviour(gen_mod). - -%% API --export([start_link/2, - start/2, - stop/1, - closed_connection/3]). - -%% gen_server callbacks --export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). - --include_lib("exmpp/include/exmpp.hrl"). - --include("ejabberd.hrl"). - --record(irc_connection, {jid_server_host, pid}). --record(irc_custom, {us_host, data}). - --record(state, {host, server_host, default_encoding, access}). - --define(PROCNAME, ejabberd_mod_irc). - -%%==================================================================== -%% API -%%==================================================================== -%%-------------------------------------------------------------------- -%% Function: start_link() -> {ok,Pid} | ignore | {error,Error} -%% Description: Starts the server -%%-------------------------------------------------------------------- -start_link(Host, Opts) -> - Proc = gen_mod:get_module_proc(Host, ?PROCNAME), - gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []). - -start(Host, Opts) -> - start_supervisor(Host), - Proc = gen_mod:get_module_proc(Host, ?PROCNAME), - ChildSpec = - {Proc, - {?MODULE, start_link, [Host, Opts]}, - temporary, - 1000, - worker, - [?MODULE]}, - supervisor:start_child(ejabberd_sup, ChildSpec). - -stop(Host) -> - stop_supervisor(Host), - Proc = gen_mod:get_module_proc(Host, ?PROCNAME), - gen_server:call(Proc, stop), - supervisor:delete_child(ejabberd_sup, Proc). - -%%==================================================================== -%% gen_server callbacks -%%==================================================================== - -%%-------------------------------------------------------------------- -%% Function: init(Args) -> {ok, State} | -%% {ok, State, Timeout} | -%% ignore | -%% {stop, Reason} -%% Description: Initiates the server -%%-------------------------------------------------------------------- -init([Host, Opts]) -> - iconv:start(), - mnesia:create_table(irc_custom, - [{disc_copies, [node()]}, - {attributes, record_info(fields, irc_custom)}]), - MyHost = gen_mod:get_opt_host(Host, Opts, "irc.@HOST@"), - update_table(MyHost), - Access = gen_mod:get_opt(access, Opts, all), - DefaultEncoding = gen_mod:get_opt(default_encoding, Opts, "koi8-r"), - catch ets:new(irc_connection, [named_table, - public, - {keypos, #irc_connection.jid_server_host}]), - ejabberd_router:register_route(MyHost), - {ok, #state{host = MyHost, - server_host = Host, - default_encoding = DefaultEncoding, - access = Access}}. - -%%-------------------------------------------------------------------- -%% 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) -> - {stop, normal, 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}. - -%%-------------------------------------------------------------------- -%% 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{host = Host, - server_host = ServerHost, - default_encoding = DefEnc, - access = Access} = State) -> - case catch do_route(Host, ServerHost, Access, From, To, Packet, DefEnc) of - {'EXIT', Reason} -> - ?ERROR_MSG("~p", [Reason]); - _ -> - ok - end, - {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) -> - ejabberd_router:unregister_route(State#state.host), - ok. - -%%-------------------------------------------------------------------- -%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState} -%% Description: Convert process state when code is changed -%%-------------------------------------------------------------------- -code_change(_OldVsn, State, _Extra) -> - {ok, State}. - -%%-------------------------------------------------------------------- -%%% Internal functions -%%-------------------------------------------------------------------- -start_supervisor(Host) -> - Proc = gen_mod:get_module_proc(Host, ejabberd_mod_irc_sup), - ChildSpec = - {Proc, - {ejabberd_tmp_sup, start_link, - [Proc, mod_irc_connection]}, - permanent, - infinity, - supervisor, - [ejabberd_tmp_sup]}, - supervisor:start_child(ejabberd_sup, ChildSpec). - -stop_supervisor(Host) -> - Proc = gen_mod:get_module_proc(Host, ejabberd_mod_irc_sup), - supervisor:terminate_child(ejabberd_sup, Proc), - supervisor:delete_child(ejabberd_sup, Proc). - -do_route(Host, ServerHost, Access, From, To, Packet, DefEnc) -> - case acl:match_rule(ServerHost, Access, From) of - allow -> - do_route1(Host, ServerHost, From, To, Packet, DefEnc); - _ -> - Lang = exmpp_stanza:get_lang(Packet), - ErrText = translate:translate(Lang, - "Access denied by service policy"), - Err = exmpp_stanza:reply_with_error(Packet, - exmpp_stanza:error(Packet#xmlel.ns, - 'forbidden', {Lang, ErrText})), - ejabberd_router:route(To, From, Err) - end. - -do_route1(Host, ServerHost, From, To, Packet, DefEnc) -> - ChanServ = exmpp_jid:node_as_list(To), - Resource = exmpp_jid:resource_as_list(To), - case ChanServ of - undefined -> - case Resource of - undefined -> - case exmpp_iq:xmlel_to_iq(Packet) of - #iq{type = get, ns = ?NS_DISCO_INFO = XMLNS, - lang = Lang} = IQ_Rec -> - Result = #xmlel{ns = XMLNS, name = 'query', - children = iq_disco(Lang)}, - Res = exmpp_iq:result(IQ_Rec, Result), - ejabberd_router:route(To, - From, - exmpp_iq:iq_to_xmlel(Res)); - #iq{type = get, ns = ?NS_DISCO_ITEMS = XMLNS} = IQ_Rec -> - Result = #xmlel{ns = XMLNS, name = 'query'}, - Res = exmpp_iq:result(IQ_Rec, Result), - ejabberd_router:route(To, - From, - exmpp_iq:iq_to_xmlel(Res)); - #iq{kind = request, ns = ?NS_INBAND_REGISTER} = IQ_Rec -> - process_register(Host, From, To, DefEnc, IQ_Rec); - #iq{type = get, ns = ?NS_VCARD = XMLNS, - lang = Lang} = IQ_Rec -> - Result = #xmlel{ns = XMLNS, name = 'vCard', - children = iq_get_vcard(Lang)}, - Res = exmpp_iq:result(IQ_Rec, Result), - ejabberd_router:route(To, - From, - exmpp_iq:iq_to_xmlel(Res)); - #iq{} = _IQ_Rec -> - Err = exmpp_iq:error( - Packet, 'feature-not-implemented'), - ejabberd_router:route(To, From, Err); - _ -> - ok - end; - _ -> - Err = exmpp_stanza:reply_with_error(Packet, 'bad-request'), - ejabberd_router:route(To, From, Err) - end; - _ -> - case string:tokens(ChanServ, "%") of - [[_ | _] = Channel, [_ | _] = Server] -> - case ets:lookup(irc_connection, {From, Server, Host}) of - [] -> - ?DEBUG("open new connection~n", []), - {Username, Encoding} = get_user_and_encoding( - Host, From, Server, DefEnc), - {ok, Pid} = mod_irc_connection:start( - From, Host, ServerHost, Server, - Username, Encoding), - ets:insert( - irc_connection, - #irc_connection{jid_server_host = {From, Server, Host}, - pid = Pid}), - mod_irc_connection:route_chan( - Pid, Channel, Resource, Packet), - ok; - [R] -> - Pid = R#irc_connection.pid, - ?DEBUG("send to process ~p~n", - [Pid]), - mod_irc_connection:route_chan( - Pid, Channel, Resource, Packet), - ok - end; - _ -> - case string:tokens(ChanServ, "!") of - [[_ | _] = Nick, [_ | _] = Server] -> - case ets:lookup(irc_connection, {From, Server, Host}) of - [] -> - Err = exmpp_stanza:reply_with_error( - Packet, 'service-unavailable'), - ejabberd_router:route(To, From, Err); - [R] -> - Pid = R#irc_connection.pid, - ?DEBUG("send to process ~p~n", - [Pid]), - mod_irc_connection:route_nick( - Pid, Nick, Packet), - ok - end; - _ -> - Err = exmpp_stanza:reply_with_error( - Packet, 'bad-request'), - ejabberd_router:route(To, From, Err) - end - end - end. - - -closed_connection(Host, From, Server) -> - ets:delete(irc_connection, {From, Server, Host}). - - -iq_disco(Lang) -> - [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = - [?XMLATTR('category', <<"conference">>), - ?XMLATTR('type', <<"irc">>), - ?XMLATTR('name', translate:translate(Lang, "IRC Transport"))]}, - #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [?XMLATTR('var', ?NS_DISCO_INFO_s)]}, - #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [?XMLATTR('var', ?NS_MUC_s)]}, - #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [?XMLATTR('var', ?NS_INBAND_REGISTER_s)]}, - #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = - [?XMLATTR('var', ?NS_VCARD_s)]}]. - -iq_get_vcard(Lang) -> - [#xmlel{ns = ?NS_VCARD, name = 'FN', children = - [#xmlcdata{cdata = <<"ejabberd/mod_irc">>}]}, - #xmlel{ns = ?NS_VCARD, name = 'URL', children = - [#xmlcdata{cdata = list_to_binary(?EJABBERD_URI)}]}, - #xmlel{ns = ?NS_VCARD, name = 'DESC', children = - [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "ejabberd IRC module") ++ - "\nCopyright (c) 2003-2009 Alexey Shchepin")}]}]. - -process_register(Host, From, To, DefEnc, #iq{} = IQ_Rec) -> - case catch process_irc_register(Host, From, To, DefEnc, IQ_Rec) of - {'EXIT', Reason} -> - ?ERROR_MSG("~p", [Reason]); - ResIQ -> - if - ResIQ /= ignore -> - ejabberd_router:route(To, From, - exmpp_iq:iq_to_xmlel(ResIQ)); - true -> - ok - end - end. - -find_xdata_el(#xmlel{children = SubEls}) -> - find_xdata_el1(SubEls). - -find_xdata_el1([]) -> - false; - -find_xdata_el1([#xmlel{ns = ?NS_DATA_FORMS} = El | _Els]) -> - El; - -find_xdata_el1([_ | Els]) -> - find_xdata_el1(Els). - -process_irc_register(Host, From, _To, DefEnc, - #iq{type = get, ns = XMLNS, - lang = Lang, payload = SubEl} = IQ_Rec) -> - Node = - string:tokens(exmpp_xml:get_attribute_as_list(SubEl, 'node', ""), "/"), - case get_form(Host, From, Node, Lang ,DefEnc) of - {result, Res} -> - Result = #xmlel{ns = XMLNS, name = 'query', children = Res}, - exmpp_iq:result(IQ_Rec, Result); - {error, Error} -> - exmpp_iq:error(IQ_Rec, Error) - end; -process_irc_register(Host, From, _To, _DefEnc, - #iq{type = set, ns = XMLNS, - lang = Lang, payload = SubEl} = IQ_Rec) -> - XDataEl = find_xdata_el(SubEl), - case XDataEl of - false -> - exmpp_iq:error(IQ_Rec, 'not-acceptable'); - _ -> - case exmpp_stanza:get_type(XDataEl) of - <<"cancel">> -> - Result = #xmlel{ns = XMLNS, name = 'query'}, - exmpp_iq:result(IQ_Rec, Result); - <<"submit">> -> - XData = jlib:parse_xdata_submit(XDataEl), - case XData of - invalid -> - exmpp_iq:error(IQ_Rec, 'bad-request'); - _ -> - Node = string:tokens( - exmpp_xml:get_attribute_as_list(SubEl, "node", ""), - "/"), - case set_form( - Host, From, Node, Lang, XData) of - {result, Res} -> - Result = #xmlel{ns = XMLNS, name = 'query', - children = Res}, - exmpp_iq:result(IQ_Rec, Result); - {error, Error} -> - exmpp_iq:error(IQ_Rec, Error) - end - end; - _ -> - exmpp_iq:error(IQ_Rec, 'bad-request') - end - end. - - - -get_form(Host, From, [], Lang, DefEnc) -> - User = exmpp_jid:node_as_list(From), - Server = exmpp_jid:domain_as_list(From), - LUser = exmpp_jid:prep_node_as_list(From), - LServer = exmpp_jid:prep_domain_as_list(From), - US = {LUser, LServer}, - Customs = - case catch mnesia:dirty_read({irc_custom, {US, Host}}) of - {'EXIT', _Reason} -> - {error, 'internal-server-error'}; - [] -> - {User, []}; - [#irc_custom{data = Data}] -> - {proplists:get_value(username, Data, ""), - proplists:get_value(encodings, Data, "")} - end, - case Customs of - {error, _Error} -> - Customs; - {Username, Encodings} -> - {result, - [#xmlel{ns = ?NS_INBAND_REGISTER, name = 'instructions', children = - [#xmlcdata{cdata = list_to_binary( - translate:translate( - Lang, - "You need an x:data capable client " - "to configure mod_irc settings"))}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = - [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = - [#xmlcdata{cdata = list_to_binary( - translate:translate( - Lang, - "Registration in mod_irc for ") ++ User ++ "@" ++ Server)}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = - [#xmlcdata{cdata = list_to_binary( - translate:translate( - Lang, - "Enter username and encodings you wish to use for " - "connecting to IRC servers"))}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', <<"text-single">>), - ?XMLATTR('label', - translate:translate( - Lang, "IRC Username")), - ?XMLATTR('var', <<"username">>)], children = - [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Username)}]}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', <<"fixed">>)], children = - [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = - [#xmlcdata{cdata = list_to_binary( - lists:flatten( - io_lib:format( - translate:translate( - Lang, - "If you want to specify different encodings " - "for IRC servers, fill this list with values " - "in format '{\"irc server\", \"encoding\"}'. " - "By default this service use \"~s\" encoding."), - [DefEnc])))}]}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', <<"fixed">>)], children = - [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = - [#xmlcdata{cdata = list_to_binary( - translate:translate( - Lang, - "Example: [{\"irc.lucky.net\", \"koi8-r\"}, " - "{\"vendetta.fef.net\", \"iso8859-1\"}]." - ))}]}]}, - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', <<"text-multi">>), - ?XMLATTR('label', - translate:translate(Lang, "Encodings")), - ?XMLATTR('var', <<"encodings">>)], children = - lists:map( - fun(S) -> - #xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(S)}]} - end, - string:tokens( - lists:flatten( - io_lib:format("~p.", [Encodings])), - "\n")) - } - ]}]} - end; - -get_form(_Host, _, _, _Lang, _) -> - {error, 'service-unavailable'}. - - - - -set_form(Host, From, [], _Lang, XData) -> - LUser = exmpp_jid:prep_node_as_list(From), - LServer = exmpp_jid:prep_domain_as_list(From), - US = {LUser, LServer}, - case {lists:keysearch("username", 1, XData), - lists:keysearch("encodings", 1, XData)} of - {{value, {_, [Username]}}, {value, {_, Strings}}} -> - EncString = lists:foldl(fun(S, Res) -> - Res ++ S ++ "\n" - end, "", Strings), - case erl_scan:string(EncString) of - {ok, Tokens, _} -> - case erl_parse:parse_term(Tokens) of - {ok, Encodings} -> - case mnesia:transaction( - fun() -> - mnesia:write( - #irc_custom{us_host = - {US, Host}, - data = - [{username, - Username}, - {encodings, - Encodings}]}) - end) of - {atomic, _} -> - {result, []}; - _ -> - {error, 'not-acceptable'} - end; - _ -> - {error, 'not-acceptable'} - end; - _ -> - {error, 'not-acceptable'} - end; - _ -> - {error, 'not-acceptable'} - end; - - -set_form(_Host, _, _, _Lang, _XData) -> - {error, 'service-unavailable'}. - - -get_user_and_encoding(Host, From, IRCServer, DefEnc) -> - User = exmpp_jid:node_as_list(From), - LUser = exmpp_jid:prep_node_as_list(From), - LServer = exmpp_jid:prep_domain_as_list(From), - US = {LUser, LServer}, - case catch mnesia:dirty_read({irc_custom, {US, Host}}) of - {'EXIT', _Reason} -> - {User, DefEnc}; - [] -> - {User, DefEnc}; - [#irc_custom{data = Data}] -> - {proplists:get_value(username, Data, ""), - case proplists:get_value(IRCServer, proplists:get_value(encodings, Data, ""), "") of - "" -> DefEnc; - E -> E - end} - end. - - -update_table(Host) -> - Fields = record_info(fields, irc_custom), - case mnesia:table_info(irc_custom, attributes) of - Fields -> - ok; - [userserver, data] -> - ?INFO_MSG("Converting irc_custom table from " - "{userserver, data} format", []), - {atomic, ok} = mnesia:create_table( - mod_irc_tmp_table, - [{disc_only_copies, [node()]}, - {type, bag}, - {local_content, true}, - {record_name, irc_custom}, - {attributes, record_info(fields, irc_custom)}]), - mnesia:transform_table(irc_custom, ignore, Fields), - F1 = fun() -> - mnesia:write_lock_table(mod_irc_tmp_table), - mnesia:foldl( - fun(#irc_custom{us_host = US} = R, _) -> - mnesia:dirty_write( - mod_irc_tmp_table, - R#irc_custom{us_host = {US, Host}}) - end, ok, irc_custom) - end, - mnesia:transaction(F1), - mnesia:clear_table(irc_custom), - F2 = fun() -> - mnesia:write_lock_table(irc_custom), - mnesia:foldl( - fun(R, _) -> - mnesia:dirty_write(R) - end, ok, mod_irc_tmp_table) - end, - mnesia:transaction(F2), - mnesia:delete_table(mod_irc_tmp_table); - _ -> - ?INFO_MSG("Recreating irc_custom table", []), - mnesia:transform_table(irc_custom, ignore, Fields) - end. diff --git a/src/mod_irc/mod_irc_connection.erl b/src/mod_irc/mod_irc_connection.erl deleted file mode 100644 index afcb91aa4..000000000 --- a/src/mod_irc/mod_irc_connection.erl +++ /dev/null @@ -1,1177 +0,0 @@ -%%%---------------------------------------------------------------------- -%%% File : mod_irc_connection.erl -%%% Author : Alexey Shchepin <alexey@process-one.net> -%%% Purpose : -%%% Created : 15 Feb 2003 by Alexey Shchepin <alexey@process-one.net> -%%% -%%% -%%% ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA -%%% 02111-1307 USA -%%% -%%%---------------------------------------------------------------------- - --module(mod_irc_connection). --author('alexey@process-one.net'). - --behaviour(gen_fsm). - -%% External exports --export([start_link/5, start/6, route_chan/4, route_nick/3]). - -%% gen_fsm callbacks --export([init/1, - open_socket/2, - wait_for_registration/2, - stream_established/2, - handle_event/3, - handle_sync_event/4, - handle_info/3, - terminate/3, - code_change/4]). - --include_lib("exmpp/include/exmpp.hrl"). - --include("ejabberd.hrl"). - --define(SETS, gb_sets). - --record(state, {socket, encoding, queue, - user, host, server, nick, - channels = dict:new(), - inbuf = "", outbuf = ""}). - -%-define(DBGFSM, true). - --ifdef(DBGFSM). --define(FSMOPTS, [{debug, [trace]}]). --else. --define(FSMOPTS, []). --endif. - -%%%---------------------------------------------------------------------- -%%% API -%%%---------------------------------------------------------------------- -start(From, Host, ServerHost, Server, Username, Encoding) -> - Supervisor = gen_mod:get_module_proc(ServerHost, ejabberd_mod_irc_sup), - supervisor:start_child( - Supervisor, [From, Host, Server, Username, Encoding]). - -start_link(From, Host, Server, Username, Encoding) -> - gen_fsm:start_link(?MODULE, [From, Host, Server, Username, Encoding], - ?FSMOPTS). - -%%%---------------------------------------------------------------------- -%%% Callback functions from gen_fsm -%%%---------------------------------------------------------------------- - -%%---------------------------------------------------------------------- -%% Func: init/1 -%% Returns: {ok, StateName, StateData} | -%% {ok, StateName, StateData, Timeout} | -%% ignore | -%% {stop, StopReason} -%%---------------------------------------------------------------------- -init([From, Host, Server, Username, Encoding]) -> - gen_fsm:send_event(self(), init), - {ok, open_socket, #state{queue = queue:new(), - encoding = Encoding, - user = From, - nick = Username, - host = Host, - server = Server}}. - -%%---------------------------------------------------------------------- -%% Func: StateName/2 -%% Returns: {next_state, NextStateName, NextStateData} | -%% {next_state, NextStateName, NextStateData, Timeout} | -%% {stop, Reason, NewStateData} -%%---------------------------------------------------------------------- -open_socket(init, StateData) -> - Addr = StateData#state.server, - Port = 6667, - ?DEBUG("connecting to ~s:~p~n", [Addr, Port]), - case gen_tcp:connect(Addr, Port, [binary, {packet, 0}]) of - {ok, Socket} -> - NewStateData = StateData#state{socket = Socket}, - send_text(NewStateData, - io_lib:format("NICK ~s\r\n", [StateData#state.nick])), - send_text(NewStateData, - io_lib:format( - "USER ~s ~s ~s :~s\r\n", - [StateData#state.nick, - StateData#state.nick, - StateData#state.host, - StateData#state.nick])), - send_text(NewStateData, - io_lib:format("CODEPAGE ~s\r\n", [StateData#state.encoding])), - {next_state, wait_for_registration, - NewStateData}; - {error, Reason} -> - ?DEBUG("connect return ~p~n", [Reason]), - Text = case Reason of - timeout -> <<"Server Connect Timeout">>; - _ -> <<"Server Connect Failed">> - end, - bounce_messages(Text), - {stop, normal, StateData} - end. - -wait_for_registration(closed, StateData) -> - {stop, normal, StateData}. - -stream_established({xmlstreamend, _Name}, StateData) -> - {stop, normal, StateData}; - -stream_established(timeout, StateData) -> - {stop, normal, StateData}; - -stream_established(closed, StateData) -> - {stop, normal, 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) -> - {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(_Event, _From, StateName, StateData) -> - Reply = ok, - {reply, Reply, StateName, StateData}. - -code_change(_OldVsn, StateName, StateData, _Extra) -> - {ok, StateName, StateData}. - --define(SEND(S), - if - StateName == stream_established -> - send_text(StateData, S), - StateData; - true -> - StateData#state{outbuf = StateData#state.outbuf ++ S} - end). - -%%---------------------------------------------------------------------- -%% Func: handle_info/3 -%% Returns: {next_state, NextStateName, NextStateData} | -%% {next_state, NextStateName, NextStateData, Timeout} | -%% {stop, Reason, NewStateData} -%%---------------------------------------------------------------------- -handle_info({route_chan, Channel, Resource, - El}, - StateName, StateData) when ?IS_PRESENCE(El) -> - NewStateData = - case exmpp_presence:get_type(El) of - 'unavailable' -> - S1 = ?SEND(io_lib:format("PART #~s\r\n", [Channel])), - S1#state{channels = - dict:erase(Channel, S1#state.channels)}; - 'subscribe' -> StateData; - 'subscribed' -> StateData; - 'unsubscribe' -> StateData; - 'unsubscribed' -> StateData; - 'error' -> stop; - _ -> - Nick = case Resource of - undefined -> - StateData#state.nick; - _ -> - Resource - end, - S1 = ?SEND(io_lib:format("NICK ~s\r\n" - "JOIN #~s\r\n", - [Nick, Channel])), - case dict:is_key(Channel, S1#state.channels) of - true -> - S1#state{nick = Nick}; - _ -> - S1#state{nick = Nick, - channels = - dict:store(Channel, ?SETS:new(), - S1#state.channels)} - end - end, - if - NewStateData == stop -> - {stop, normal, StateData}; - true -> - case length(dict:fetch_keys(NewStateData#state.channels)) of - 0 -> - {stop, normal, NewStateData}; - _ -> - {next_state, StateName, NewStateData} - end - end; - -handle_info({route_chan, Channel, Resource, - El}, - StateName, StateData) when ?IS_MESSAGE(El) -> - NewStateData = - case exmpp_message:get_type(El) of - 'groupchat' -> - case exmpp_message:get_subject(El) of - undefined -> - ejabberd_router:route( - exmpp_jid:make( - lists:concat( - [Channel, "%", StateData#state.server]), - StateData#state.host, StateData#state.nick), - StateData#state.user, El), - Body = binary_to_list(exmpp_message:get_body(El)), - case Body of - "/quote " ++ Rest -> - ?SEND(Rest ++ "\r\n"); - "/msg " ++ Rest -> - ?SEND("PRIVMSG " ++ Rest ++ "\r\n"); - "/me " ++ Rest -> - Strings = string:tokens(Rest, "\n"), - Res = lists:concat( - lists:map( - fun(S) -> - io_lib:format( - "PRIVMSG #~s :\001ACTION ~s\001\r\n", - [Channel, S]) - end, Strings)), - ?SEND(Res); - "/ctcp " ++ Rest -> - Words = string:tokens(Rest, " "), - case Words of - [CtcpDest | _] -> - CtcpCmd = - toupper( - string:substr( - Rest, - string:str(Rest, " ") + 1)), - Res = io_lib:format( - "PRIVMSG ~s :\001~s\001\r\n", - [CtcpDest, CtcpCmd]), - ?SEND(Res); - _ -> - ok - end; - _ -> - Strings = string:tokens(Body, "\n"), - Res = lists:concat( - lists:map( - fun(S) -> - io_lib:format( - "PRIVMSG #~s :~s\r\n", - [Channel, S]) - end, Strings)), - ?SEND(Res) - end; - Subject -> - Strings = string:tokens(Subject, "\n"), - Res = lists:concat( - lists:map( - fun(S) -> - io_lib:format("TOPIC #~s :~s\r\n", - [Channel, S]) - end, Strings)), - ?SEND(Res) - end; - Type when Type == 'chat'; Type == 'normal' -> - Body = binary_to_list(exmpp_message:get_body(El)), - case Body of - "/quote " ++ Rest -> - ?SEND(Rest ++ "\r\n"); - "/msg " ++ Rest -> - ?SEND("PRIVMSG " ++ Rest ++ "\r\n"); - "/me " ++ Rest -> - Strings = string:tokens(Rest, "\n"), - Res = lists:concat( - lists:map( - fun(S) -> - io_lib:format( - "PRIVMSG ~s :\001ACTION ~s\001\r\n", - [Resource, S]) - end, Strings)), - ?SEND(Res); - "/ctcp " ++ Rest -> - Words = string:tokens(Rest, " "), - case Words of - [CtcpDest | _ ] -> - CtcpCmd = - toupper( - string:substr( - Rest, string:str(Rest, " ") + 1)), - Res = io_lib:format( - "PRIVMSG ~s :~s\r\n", - [CtcpDest, "\001" ++ CtcpCmd ++ "\001"]), - ?SEND(Res); - _ -> - ok - end; - _ -> - Strings = string:tokens(Body, "\n"), - Res = lists:concat( - lists:map( - fun(S) -> - io_lib:format("PRIVMSG ~s :~s\r\n", - [Resource, S]) - end, Strings)), - ?SEND(Res) - end; - 'error' -> - stop; - _ -> - StateData - end, - if - NewStateData == stop -> - {stop, normal, StateData}; - true -> - {next_state, StateName, NewStateData} - end; - - -handle_info({route_chan, Channel, Resource, - El}, - StateName, StateData) when ?IS_IQ(El) -> - From = StateData#state.user, - To = exmpp_jid:make(lists:concat([Channel, "%", StateData#state.server]), - StateData#state.host, StateData#state.nick), - _ = case exmpp_iq:xmlel_to_iq(El) of - #iq{kind = request, ns = ?NS_MUC_ADMIN} = IQ_Rec -> - iq_admin(StateData, Channel, From, To, IQ_Rec); - #iq{kind = request, ns = ?NS_SOFT_VERSION} -> - Res = io_lib:format("PRIVMSG ~s :\001VERSION\001\r\n", - [Resource]), - _ = ?SEND(Res), - Err = exmpp_iq:error(El, 'feature-not-implemented'), - ejabberd_router:route(To, From, Err); - #iq{kind = request, ns = ?NS_TIME_OLD} -> - Res = io_lib:format("PRIVMSG ~s :\001TIME\001\r\n", - [Resource]), - _ = ?SEND(Res), - Err = exmpp_iq:error(El, 'feature-not-implemented'), - ejabberd_router:route(To, From, Err); - #iq{kind = request, ns = ?NS_VCARD} -> - Res = io_lib:format("WHOIS ~s \r\n", - [Resource]), - _ = ?SEND(Res), - Err = exmpp_iq:error(El, 'feature-not-implemented'), - ejabberd_router:route(To, From, Err); - #iq{} -> - Err = exmpp_iq:error(El, 'feature-not-implemented'), - ejabberd_router:route(To, From, Err); - _ -> - ok - end, - {next_state, StateName, StateData}; - -handle_info({route_chan, _Channel, _Resource, _Packet}, StateName, StateData) -> - {next_state, StateName, StateData}; - - -handle_info({route_nick, Nick, - El}, - StateName, StateData) when ?IS_MESSAGE(El) -> - NewStateData = - case exmpp_message:get_type(El) of - 'chat' -> - Body = binary_to_list(exmpp_message:get_body(El)), - case Body of - "/quote " ++ Rest -> - ?SEND(Rest ++ "\r\n"); - "/msg " ++ Rest -> - ?SEND("PRIVMSG " ++ Rest ++ "\r\n"); - "/me " ++ Rest -> - Strings = string:tokens(Rest, "\n"), - Res = lists:concat( - lists:map( - fun(S) -> - io_lib:format( - "PRIVMSG ~s :\001ACTION ~s\001\r\n", - [Nick, S]) - end, Strings)), - ?SEND(Res); - "/ctcp " ++ Rest -> - Words = string:tokens(Rest, " "), - case Words of - [CtcpDest | _ ] -> - CtcpCmd = toupper(string:substr(Rest, string:str(Rest, " ")+1 )), - Res = io_lib:format( - "PRIVMSG ~s :~s\r\n", - [CtcpDest, "\001" ++ CtcpCmd ++ "\001"]), - ?SEND(Res); - _ -> - ok - end; - _ -> - Strings = string:tokens(Body, "\n"), - Res = lists:concat( - lists:map( - fun(S) -> - io_lib:format("PRIVMSG ~s :~s\r\n", - [Nick, S]) - end, Strings)), - ?SEND(Res) - end; - 'error' -> - stop; - _ -> - StateData - end, - if - NewStateData == stop -> - {stop, normal, StateData}; - true -> - {next_state, StateName, NewStateData} - end; - -handle_info({route_nick, _Nick, _Packet}, StateName, StateData) -> - {next_state, StateName, StateData}; - - -handle_info({ircstring, [$P, $I, $N, $G, $ | ID]}, StateName, StateData) -> - send_text(StateData, "PONG " ++ ID ++ "\r\n"), - {next_state, StateName, StateData}; - -handle_info({ircstring, [$: | String]}, _StateName, StateData) -> - Words = string:tokens(String, " "), - NewStateData = - case Words of - [_, "353" | Items] -> - process_channel_list(StateData, Items); - [_, "332", _Nick, [$# | Chan] | _] -> - process_channel_topic(StateData, Chan, String), - StateData; - [_, "333", _Nick, [$# | Chan] | _] -> - process_channel_topic_who(StateData, Chan, String), - StateData; - [_, "318", _, Nick | _] -> - process_endofwhois(StateData, String, Nick), - StateData; - [_, "311", _, Nick, Ident, Irchost | _ ] -> - process_whois311(StateData, String, Nick, Ident, Irchost), - StateData; - [_, "312", _, Nick, Ircserver | _ ] -> - process_whois312(StateData, String, Nick, Ircserver), - StateData; - [_, "319", _, Nick | _ ] -> - process_whois319(StateData, String, Nick), - StateData; - [From, "PRIVMSG", [$# | Chan] | _] -> - process_chanprivmsg(StateData, Chan, From, String), - StateData; - [From, "NOTICE", [$# | Chan] | _] -> - process_channotice(StateData, Chan, From, String), - StateData; - [From, "PRIVMSG", Nick, ":\001VERSION\001" | _] -> - process_version(StateData, Nick, From), - StateData; - [From, "PRIVMSG", Nick, ":\001USERINFO\001" | _] -> - process_userinfo(StateData, Nick, From), - StateData; - [From, "PRIVMSG", Nick | _] -> - process_privmsg(StateData, Nick, From, String), - StateData; - [From, "NOTICE", Nick | _] -> - process_notice(StateData, Nick, From, String), - StateData; - [From, "TOPIC", [$# | Chan] | _] -> - process_topic(StateData, Chan, From, String), - StateData; - [From, "PART", [$# | Chan] | _] -> - process_part(StateData, Chan, From, String); - [From, "QUIT" | _] -> - process_quit(StateData, From, String); - [From, "JOIN", Chan | _] -> - process_join(StateData, Chan, From, String); - [From, "MODE", [$# | Chan], "+o", Nick | _] -> - process_mode_o(StateData, Chan, From, Nick, - "admin", "moderator"), - StateData; - [From, "MODE", [$# | Chan], "-o", Nick | _] -> - process_mode_o(StateData, Chan, From, Nick, - "member", "participant"), - StateData; - [From, "KICK", [$# | Chan], Nick | _] -> - process_kick(StateData, Chan, From, Nick, String), - StateData; - [From, "NICK", Nick | _] -> - process_nick(StateData, From, Nick); - _ -> - ?DEBUG("unknown irc command '~s'~n", [String]), - StateData - end, - NewStateData1 = - case StateData#state.outbuf of - "" -> - NewStateData; - Data -> - send_text(NewStateData, Data), - NewStateData#state{outbuf = ""} - end, - {next_state, stream_established, NewStateData1}; - -handle_info({ircstring, [$E, $R, $R, $O, $R | _] = String}, - StateName, StateData) -> - process_error(StateData, String), - {next_state, StateName, StateData}; - - -handle_info({ircstring, String}, StateName, StateData) -> - ?DEBUG("unknown irc command '~s'~n", [String]), - {next_state, StateName, StateData}; - - -handle_info({send_text, Text}, StateName, StateData) -> - send_text(StateData, Text), - {next_state, StateName, StateData}; -handle_info({tcp, _Socket, Data}, StateName, StateData) -> - Buf = StateData#state.inbuf ++ binary_to_list(Data), - {ok, Strings} = regexp:split([C || C <- Buf, C /= $\r], "\n"), - ?DEBUG("strings=~p~n", [Strings]), - NewBuf = process_lines(StateData#state.encoding, Strings), - {next_state, StateName, StateData#state{inbuf = NewBuf}}; -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}. - -%%---------------------------------------------------------------------- -%% Func: terminate/3 -%% Purpose: Shutdown the fsm -%% Returns: any -%%---------------------------------------------------------------------- -terminate(_Reason, _StateName, StateData) -> - mod_irc:closed_connection(StateData#state.host, - StateData#state.user, - StateData#state.server), - bounce_messages(<<"Server Connect Failed">>), - lists:foreach( - fun(Chan) -> - ejabberd_router:route( - exmpp_jid:make( - lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, StateData#state.nick), - StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [?XMLATTR('type', <<"error">>)], children = - [#xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', attrs = [?XMLATTR('code', <<"502">>)], children = - [#xmlcdata{cdata = <<"Server Connect Failed">>}]}]}) - end, dict:fetch_keys(StateData#state.channels)), - case StateData#state.socket of - undefined -> - ok; - Socket -> - gen_tcp:close(Socket) - end, - ok. - -%%%---------------------------------------------------------------------- -%%% Internal functions -%%%---------------------------------------------------------------------- - -send_text(#state{socket = Socket, encoding = Encoding}, Text) -> - CText = iconv:convert("utf-8", Encoding, lists:flatten(Text)), - %?DEBUG("IRC OUTu: ~s~nIRC OUTk: ~s~n", [Text, CText]), - gen_tcp:send(Socket, CText). - - -%send_queue(Socket, Q) -> -% case queue:out(Q) of -% {{value, El}, Q1} -> -% send_element(Socket, El), -% send_queue(Socket, Q1); -% {empty, Q1} -> -% ok -% end. - -bounce_messages(Reason) -> - receive - {send_element, El} -> - case exmpp_stanza:get_type(El) of - <<"error">> -> - ok; - _ -> - Error = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', - attrs = [?XMLATTR('code', <<"502">>)], - children = [#xmlcdata{cdata = Reason}]}, - Err = exmpp_stanza:reply_with_error(El, Error), - From = exmpp_jid:parse(exmpp_stanza:get_sender(El)), - To = exmpp_jid:parse(exmpp_stanza:get_recipient(El)), - ejabberd_router:route(To, From, Err) - end, - bounce_messages(Reason) - after 0 -> - ok - end. - - -route_chan(Pid, Channel, Resource, Packet) -> - Pid ! {route_chan, Channel, Resource, Packet}. - -route_nick(Pid, Nick, Packet) -> - Pid ! {route_nick, Nick, Packet}. - - -process_lines(_Encoding, [S]) -> - S; -process_lines(Encoding, [S | Ss]) -> - self() ! {ircstring, iconv:convert(Encoding, "utf-8", S)}, - process_lines(Encoding, Ss). - -process_channel_list(StateData, Items) -> - process_channel_list_find_chan(StateData, Items). - -process_channel_list_find_chan(StateData, []) -> - StateData; -process_channel_list_find_chan(StateData, [[$# | Chan] | Items]) -> - process_channel_list_users(StateData, Chan, Items); -process_channel_list_find_chan(StateData, [_ | Items]) -> - process_channel_list_find_chan(StateData, Items). - -process_channel_list_users(StateData, _Chan, []) -> - StateData; -process_channel_list_users(StateData, Chan, [User | Items]) -> - NewStateData = process_channel_list_user(StateData, Chan, User), - process_channel_list_users(NewStateData, Chan, Items). - -process_channel_list_user(StateData, Chan, User) -> - User1 = case User of - [$: | U1] -> U1; - _ -> User - end, - {User2, Affiliation, Role} = - case User1 of - [$@ | U2] -> {U2, <<"admin">>, <<"moderator">>}; - [$+ | U2] -> {U2, <<"member">>, <<"participant">>}; - [$\% | U2] -> {U2, <<"admin">>, <<"moderator">>}; - [$& | U2] -> {U2, <<"admin">>, <<"moderator">>}; - [$~ | U2] -> {U2, <<"admin">>, <<"moderator">>}; - _ -> {User1, <<"member">>, <<"participant">>} - end, - ejabberd_router:route( - exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, User2), - StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = - [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = - [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [?XMLATTR('affiliation', Affiliation), - ?XMLATTR('role', Role)]}]}]}), - case catch dict:update(Chan, - fun(Ps) -> - ?SETS:add_element(User2, Ps) - end, StateData#state.channels) of - {'EXIT', _} -> - StateData; - NS -> - StateData#state{channels = NS} - end. - - -process_channel_topic(StateData, Chan, String) -> - {ok, Msg, _} = regexp:sub(String, ".*332[^:]*:", ""), - Msg1 = filter_message(Msg), - ejabberd_router:route( - exmpp_jid:make( - lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, ""), - StateData#state.user, - exmpp_message:groupchat(Msg1, "Topic for #" ++ Chan ++ ": " ++ Msg1)). - -process_channel_topic_who(StateData, Chan, String) -> - Words = string:tokens(String, " "), - Msg1 = case Words of - [_, "333", _, _Chan, Whoset , Timeset] -> - case string:to_integer(Timeset) of - {Unixtimeset, _Rest} -> - "Topic for #" ++ Chan ++ " set by " ++ Whoset ++ - " at " ++ unixtime2string(Unixtimeset); - _-> - "Topic for #" ++ Chan ++ " set by " ++ Whoset - end; - [_, "333", _, _Chan, Whoset | _] -> - "Topic for #" ++ Chan ++ " set by " ++ Whoset; - _ -> - String - end, - Msg2 = filter_message(Msg1), - - ejabberd_router:route( - exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, ""), - StateData#state.user, - exmpp_message:groupchat(Msg2)). - - - -process_endofwhois(StateData, _String, Nick) -> - ejabberd_router:route( - exmpp_jid:make(lists:concat([Nick, "!", StateData#state.server]), - StateData#state.host, ""), - StateData#state.user, - exmpp_message:chat("End of WHOIS")). - -process_whois311(StateData, String, Nick, Ident, Irchost) -> - {ok, Fullname, _} = regexp:sub(String, ".*311[^:]*:", ""), - ejabberd_router:route( - exmpp_jid:make(lists:concat([Nick, "!", StateData#state.server]), - StateData#state.host, ""), - StateData#state.user, - exmpp_message:chat(lists:concat( - ["WHOIS: ", Nick, " is ", - Ident, "@" , Irchost, " : " , Fullname]))). - -process_whois312(StateData, String, Nick, Ircserver) -> - {ok, Ircserverdesc, _} = regexp:sub(String, ".*312[^:]*:", ""), - ejabberd_router:route( - exmpp_jid:make(lists:concat([Nick, "!", StateData#state.server]), - StateData#state.host, ""), - StateData#state.user, - exmpp_message:chat(lists:concat(["WHOIS: ", Nick, " use ", - Ircserver, " : ", Ircserverdesc]))). - -process_whois319(StateData, String, Nick) -> - {ok, Chanlist, _} = regexp:sub(String, ".*319[^:]*:", ""), - ejabberd_router:route( - exmpp_jid:make(lists:concat([Nick, "!", StateData#state.server]), - StateData#state.host, ""), - StateData#state.user, - exmpp_message:chat(lists:concat(["WHOIS: ", Nick, " is on ", - Chanlist]))). - - - -process_chanprivmsg(StateData, Chan, From, String) -> - [FromUser | _] = string:tokens(From, "!"), - {ok, Msg, _} = regexp:sub(String, ".*PRIVMSG[^:]*:", ""), - Msg1 = case Msg of - [1, $A, $C, $T, $I, $O, $N, $ | Rest] -> - "/me " ++ Rest; - _ -> - Msg - end, - Msg2 = filter_message(Msg1), - ejabberd_router:route( - exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, FromUser), - StateData#state.user, - exmpp_message:groupchat(Msg2)). - - - -process_channotice(StateData, Chan, From, String) -> - [FromUser | _] = string:tokens(From, "!"), - {ok, Msg, _} = regexp:sub(String, ".*NOTICE[^:]*:", ""), - Msg1 = case Msg of - [1, $A, $C, $T, $I, $O, $N, $ | Rest] -> - "/me " ++ Rest; - _ -> - "/me NOTICE: " ++ Msg - end, - Msg2 = filter_message(Msg1), - ejabberd_router:route( - exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, FromUser), - StateData#state.user, - exmpp_message:groupchat(Msg2)). - - - - -process_privmsg(StateData, _Nick, From, String) -> - [FromUser | _] = string:tokens(From, "!"), - {ok, Msg, _} = regexp:sub(String, ".*PRIVMSG[^:]*:", ""), - Msg1 = case Msg of - [1, $A, $C, $T, $I, $O, $N, $ | Rest] -> - "/me " ++ Rest; - _ -> - Msg - end, - Msg2 = filter_message(Msg1), - ejabberd_router:route( - exmpp_jid:make(lists:concat([FromUser, "!", StateData#state.server]), - StateData#state.host, undefined), - StateData#state.user, - exmpp_message:chat(Msg2)). - - -process_notice(StateData, _Nick, From, String) -> - [FromUser | _] = string:tokens(From, "!"), - {ok, Msg, _} = regexp:sub(String, ".*NOTICE[^:]*:", ""), - Msg1 = case Msg of - [1, $A, $C, $T, $I, $O, $N, $ | Rest] -> - "/me " ++ Rest; - _ -> - "/me NOTICE: " ++ Msg - end, - Msg2 = filter_message(Msg1), - ejabberd_router:route( - exmpp_jid:make(lists:concat([FromUser, "!", StateData#state.server]), - StateData#state.host, undefined), - StateData#state.user, - exmpp_message:chat(Msg2)). - - -process_version(StateData, _Nick, From) -> - [FromUser | _] = string:tokens(From, "!"), - send_text( - StateData, - io_lib:format("NOTICE ~s :\001VERSION " - "ejabberd IRC transport ~s (c) Alexey Shchepin" - "\001\r\n", - [FromUser, ?VERSION]) ++ - io_lib:format("NOTICE ~s :\001VERSION " - ?EJABBERD_URI - "\001\r\n", - [FromUser])). - - -process_userinfo(StateData, _Nick, From) -> - [FromUser | _] = string:tokens(From, "!"), - send_text( - StateData, - io_lib:format("NOTICE ~s :\001USERINFO " - "xmpp:~s" - "\001\r\n", - [FromUser, - exmpp_jid:to_list(StateData#state.user)])). - - -process_topic(StateData, Chan, From, String) -> - [FromUser | _] = string:tokens(From, "!"), - {ok, Msg, _} = regexp:sub(String, ".*TOPIC[^:]*:", ""), - Msg1 = filter_message(Msg), - ejabberd_router:route( - exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, FromUser), - StateData#state.user, - exmpp_message:groupchat(Msg1, - "/me has changed the subject to: " ++ Msg1)). - -process_part(StateData, Chan, From, String) -> - [FromUser | FromIdent] = string:tokens(From, "!"), - {ok, Msg, _} = regexp:sub(String, ".*PART[^:]*:", ""), - Msg1 = filter_message(Msg), - ejabberd_router:route( - exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, FromUser), - StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [?XMLATTR('type', <<"unavailable">>)], children = - [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = - [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [?XMLATTR('affiliation', <<"member">>), - ?XMLATTR('role', <<"none">>)]}]}, - #xmlel{ns = ?NS_MUC_USER, name = 'status', children = - [#xmlcdata{cdata = list_to_binary(Msg1 ++ " (" ++ FromIdent ++ ")")}]}] - }), - case catch dict:update(Chan, - fun(Ps) -> - remove_element(FromUser, Ps) - end, StateData#state.channels) of - {'EXIT', _} -> - StateData; - NS -> - StateData#state{channels = NS} - end. - - -process_quit(StateData, From, String) -> - [FromUser | FromIdent] = string:tokens(From, "!"), - - {ok, Msg, _} = regexp:sub(String, ".*QUIT[^:]*:", ""), - Msg1 = filter_message(Msg), - %%NewChans = - dict:map( - fun(Chan, Ps) -> - case ?SETS:is_member(FromUser, Ps) of - true -> - ejabberd_router:route( - exmpp_jid:make( - lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, FromUser), - StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [?XMLATTR('type', <<"unavailable">>)], children = - [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = - [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [?XMLATTR('affiliation', <<"member">>), - ?XMLATTR('role', <<"none">>)]}]}, - #xmlel{ns = ?NS_MUC_USER, name = 'status', children = - [#xmlcdata{cdata = list_to_binary(Msg1 ++ " (" ++ FromIdent ++ ")")}]} - ]}), - remove_element(FromUser, Ps); - _ -> - Ps - end - end, StateData#state.channels), - StateData. - - -process_join(StateData, Channel, From, _String) -> - [FromUser | FromIdent] = string:tokens(From, "!"), - Chan = lists:subtract(Channel, ":#"), - ejabberd_router:route( - exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, FromUser), - StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = - [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = - [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [?XMLATTR('affiliation', <<"member">>), - ?XMLATTR('role', <<"participant">>)]}]}, - #xmlel{ns = ?NS_MUC_USER, name = 'status', children = - [#xmlcdata{cdata = list_to_binary(FromIdent)}]}]}), - - case catch dict:update(Chan, - fun(Ps) -> - ?SETS:add_element(FromUser, Ps) - end, StateData#state.channels) of - {'EXIT', _} -> - StateData; - NS -> - StateData#state{channels = NS} - end. - - - -process_mode_o(StateData, Chan, _From, Nick, Affiliation, Role) -> - %Msg = lists:last(string:tokens(String, ":")), - ejabberd_router:route( - exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, Nick), - StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = - [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = - [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [?XMLATTR('affiliation', Affiliation), - ?XMLATTR('role', Role)]}]}]}). - -process_kick(StateData, Chan, From, Nick, String) -> - Msg = lists:last(string:tokens(String, ":")), - Msg2 = Nick ++ " kicked by " ++ From ++ " (" ++ filter_message(Msg) ++ ")", - ejabberd_router:route( - exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, undefined), - StateData#state.user, - exmpp_message:groupchat(Msg2)), - ejabberd_router:route( - exmpp_jid:make(lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, Nick), - StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [?XMLATTR('type', <<"unavailable">>)], children = - [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = - [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [?XMLATTR('affiliation', <<"none">>), - ?XMLATTR('role', <<"none">>)]}, - #xmlel{ns = ?NS_MUC_USER, name = 'status', attrs = [?XMLATTR('code', <<"307">>)]} - ]}]}). - -process_nick(StateData, From, NewNick) -> - [FromUser | _] = string:tokens(From, "!"), - Nick = lists:subtract(NewNick, ":"), - NewChans = - dict:map( - fun(Chan, Ps) -> - case ?SETS:is_member(FromUser, Ps) of - true -> - ejabberd_router:route( - exmpp_jid:make( - lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, FromUser), - StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [?XMLATTR('type', <<"unavailable">>)], children = - [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = - [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [?XMLATTR('affiliation', <<"member">>), - ?XMLATTR('role', <<"participant">>), - ?XMLATTR('nick', Nick)]}, - #xmlel{ns = ?NS_MUC_USER, name = 'status', attrs = [?XMLATTR('code', <<"303">>)]} - ]}]}), - ejabberd_router:route( - exmpp_jid:make( - lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, Nick), - StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', children = - [#xmlel{ns = ?NS_MUC_USER, name = 'x', children = - [#xmlel{ns = ?NS_MUC_USER, name = 'item', attrs = - [?XMLATTR('affiliation', <<"member">>), - ?XMLATTR('role', <<"participant">>)]} - ]}]}), - ?SETS:add_element(Nick, - remove_element(FromUser, Ps)); - _ -> - Ps - end - end, StateData#state.channels), - StateData#state{channels = NewChans}. - - -process_error(StateData, String) -> - lists:foreach( - fun(Chan) -> - ejabberd_router:route( - exmpp_jid:make( - lists:concat([Chan, "%", StateData#state.server]), - StateData#state.host, StateData#state.nick), - StateData#state.user, - #xmlel{ns = ?NS_JABBER_CLIENT, name = 'presence', attrs = [?XMLATTR('type', <<"error">>)], children = - [#xmlel{ns = ?NS_JABBER_CLIENT, name = 'error', attrs = [?XMLATTR('code', <<"502">>)], children = - [#xmlcdata{cdata = list_to_binary(String)}]}]}) - end, dict:fetch_keys(StateData#state.channels)). - - - - -remove_element(E, Set) -> - case ?SETS:is_element(E, Set) of - true -> - ?SETS:del_element(E, Set); - _ -> - Set - end. - - - -iq_admin(StateData, Channel, From, To, - #iq{type = Type, ns = XMLNS, payload = SubEl} = IQ_Rec) -> - case catch process_iq_admin(StateData, Channel, Type, SubEl) of - {'EXIT', Reason} -> - ?ERROR_MSG("~p", [Reason]); - Res -> - if - Res /= ignore -> - ResIQ = case Res of - {result, ResEls} -> - Result = #xmlel{ns = XMLNS, name = 'query', - children = ResEls}, - exmpp_iq:result(IQ_Rec, Result); - {error, Error} -> - exmpp_iq:error(IQ_Rec, Error) - end, - ejabberd_router:route(To, From, - exmpp_iq:iq_to_xmlel(ResIQ)); - true -> - ok - end - end. - - -process_iq_admin(StateData, Channel, set, SubEl) -> - case exmpp_xml:get_element(SubEl, 'item') of - false -> - {error, 'bad-request'}; - ItemEl -> - Nick = exmpp_xml:get_attribute_as_list(ItemEl, 'nick', ""), - Affiliation = exmpp_xml:get_attribute_as_list(ItemEl, 'affiliation', ""), - Role = exmpp_xml:get_attribute_as_list(ItemEl, 'role', ""), - Reason = exmpp_xml:get_path(ItemEl, [{element, 'reason'}, cdata_as_list]), - process_admin(StateData, Channel, Nick, Affiliation, Role, Reason) - end; -process_iq_admin(_StateData, _Channel, get, _SubEl) -> - {error, 'feature-not-implemented'}. - - - -process_admin(_StateData, _Channel, "", _Affiliation, _Role, _Reason) -> - {error, 'feature-not-implemented'}; - -process_admin(StateData, Channel, Nick, _Affiliation, "none", Reason) -> - case Reason of - "" -> - send_text(StateData, - io_lib:format("KICK #~s ~s\r\n", - [Channel, Nick])); - _ -> - send_text(StateData, - io_lib:format("KICK #~s ~s :~s\r\n", - [Channel, Nick, Reason])) - end, - {result, []}; - - - -process_admin(_StateData, _Channel, _Nick, _Affiliation, _Role, _Reason) -> - {error, 'feature-not-implemented'}. - - - -filter_message(Msg) -> - lists:filter( - fun(C) -> - if (C < 32) and - (C /= 9) and - (C /= 10) and - (C /= 13) -> - false; - true -> true - end - end, filter_mirc_colors(Msg)). - -filter_mirc_colors(Msg) -> - case regexp:gsub(Msg, "(\\003[0-9]+)(,[0-9]+)?", "") of - {ok, Msg2, _} -> - Msg2; - _ -> - Msg - end. - -unixtime2string(Unixtime) -> - Secs = Unixtime + calendar:datetime_to_gregorian_seconds( - {{1970, 1, 1}, {0,0,0}}), - case calendar:universal_time_to_local_time( - calendar:gregorian_seconds_to_datetime(Secs)) of - {{Year, Month, Day}, {Hour, Minute, Second}} -> - lists:flatten( - io_lib:format("~4..0w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w", - [Year, Month, Day, Hour, Minute, Second])); - _-> - "0000-00-00 00:00:00" - end. - -toupper([C | Cs]) -> - if - C >= $a, C =< $z -> - [C - 32 | toupper(Cs)]; - true -> - [C | toupper(Cs)] - end; -toupper([]) -> - []. - diff --git a/src/win32/ejabberd.cfg b/src/win32/ejabberd.cfg index 7ba191be0..a42b849d5 100644 --- a/src/win32/ejabberd.cfg +++ b/src/win32/ejabberd.cfg @@ -146,7 +146,6 @@ {mod_offline, []}, {mod_announce, [{access, announce}]}, {mod_private, []}, - {mod_irc, []}, % Default options for mod_muc: % host: "conference." ++ ?MYNAME % access: all From 487b80b9b06d6f75a5142e8d04b1ec8ea487fe3e Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 13:52:07 +0000 Subject: [PATCH 361/582] Initial commit of mod_http_fileserver (thanks to Massimiliano Mirra) SVN Revision: 2183 --- src/web/mod_http_fileserver.erl | 112 ++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 src/web/mod_http_fileserver.erl diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl new file mode 100644 index 000000000..248870c8e --- /dev/null +++ b/src/web/mod_http_fileserver.erl @@ -0,0 +1,112 @@ +%%%---------------------------------------------------------------------- +%%% File : mod_http_fileserver.erl +%%% Author : Massimiliano Mirra <mmirra [at] process-one [dot] net> +%%% Purpose : Simple file server plugin for embedded ejabberd web server +%%% Created : +%%% Id : +%%%---------------------------------------------------------------------- + +-module(mod_http_fileserver). +-author('mmirra@process-one.net'). +-vsn(''). +-define(ejabberd_debug, true). +-compile([export_all]). + +-behaviour(gen_mod). + +-export([ + start/2, + stop/1, + process/2 + ]). + +-include("ejabberd.hrl"). +-include("jlib.hrl"). +-include("ejabberd_http.hrl"). + +%%%---------------------------------------------------------------------- +%%% REQUEST HANDLERS +%%%---------------------------------------------------------------------- + +%%----------------------------------------------------------------------- +%% FUNCTION +%% +%% process/2 +%% +%% PURPOSE +%% +%% Handle an HTTP request. +%% +%% RETURNS +%% +%% Page to be sent back to the client and/or HTTP status code. +%% +%% ARGUMENTS +%% +%% - LocalPath: part of the requested URL path that is "local to the +%% module". +%% +%%----------------------------------------------------------------------- + +process(LocalPath, _Request) -> + ?DEBUG("Requested ~p", [LocalPath]), + [{docroot, DocRoot}] = ets:lookup(mod_http_fileserver, docroot), + FileName = filename:join(filename:split(DocRoot) ++ LocalPath), + case file:read_file(FileName) of + {ok, FileContents} -> + ?DEBUG("Delivering content.", []), + {200, + [{"Server", "ejabberd"}, + {"Content-type", content_type(FileName)}], + FileContents}; + {error, Error} -> + ?DEBUG("Delivering error: ~p", [Error]), + case Error of + eacces -> {403, [], "Forbidden"}; + enoent -> {404, [], "Not found"}; + _Else -> {404, [], atom_to_list(Error)} + end + end. + + +%%%---------------------------------------------------------------------- +%%% UTILITIES +%%%---------------------------------------------------------------------- + +content_type(Filename) -> + case httpd_util:to_lower(filename:extension(Filename)) of + ".jpg" -> "image/jpeg"; + ".jpeg" -> "image/jpeg"; + ".gif" -> "image/gif"; + ".png" -> "image/png"; + ".html" -> "text/html"; + ".css" -> "text/css"; + ".txt" -> "text/plain"; + ".xul" -> "application/vnd.mozilla.xul+xml"; + ".jar" -> "application/java-archive"; + ".xpi" -> "application/x-xpinstall"; + _Else -> "application/octet-stream" + end. + + +%%%---------------------------------------------------------------------- +%%% BEHAVIOUR CALLBACKS +%%%---------------------------------------------------------------------- + +start(_Host, Opts) -> + case gen_mod:get_opt(docroot, Opts, undefined) of + undefined -> + {'EXIT', {missing_document_root, ?MODULE}}; + DocRoot -> + case filelib:is_dir(DocRoot) of + true -> + ets:new(mod_http_fileserver, [named_table, bag]), + ets:insert(mod_http_fileserver, [{docroot, DocRoot}]), + ok; + _Else -> + {'EXIT', {unaccessible_document_root, ?MODULE}} + end + end. + +stop(_Host) -> + ok. From b57248e82216ffc152db8c6ed06e4e21ccb9a122 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 13:52:12 +0000 Subject: [PATCH 362/582] Added accesslog parameter to record requests log in a file similar to Apache (thanks to Jerome Sautret) SVN Revision: 2184 --- src/web/mod_http_fileserver.erl | 115 +++++++++++++++++++++++++++++--- 1 file changed, 106 insertions(+), 9 deletions(-) diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl index 248870c8e..f04cf113c 100644 --- a/src/web/mod_http_fileserver.erl +++ b/src/web/mod_http_fileserver.erl @@ -15,14 +15,16 @@ -behaviour(gen_mod). -export([ - start/2, - stop/1, - process/2 + start/2, + stop/1, + process/2, + ctl_process/2 ]). -include("ejabberd.hrl"). -include("jlib.hrl"). -include("ejabberd_http.hrl"). +-include("ejabberd_ctl.hrl"). %%%---------------------------------------------------------------------- %%% REQUEST HANDLERS @@ -30,7 +32,7 @@ %%----------------------------------------------------------------------- %% FUNCTION -%% +%% %% process/2 %% %% PURPOSE @@ -48,8 +50,21 @@ %% %%----------------------------------------------------------------------- -process(LocalPath, _Request) -> + +process(LocalPath, Request) -> ?DEBUG("Requested ~p", [LocalPath]), + + Result = serve(LocalPath), + case ets:lookup(mod_http_fileserver, accessfile) of + undefined -> + ok; + [{accessfile, AccessFile}] -> + {Code, _, _} = Result, + log(AccessFile, Code, Request) + end, + Result. + +serve(LocalPath) -> [{docroot, DocRoot}] = ets:lookup(mod_http_fileserver, docroot), FileName = filename:join(filename:split(DocRoot) ++ LocalPath), case file:read_file(FileName) of @@ -68,11 +83,40 @@ process(LocalPath, _Request) -> end end. +ctl_process(_Val, ["reopen-weblog"]) -> + mod_http_fileserver_server ! reopenlog, + ?STATUS_SUCCESS; +ctl_process(Val, _Args) -> + Val. %%%---------------------------------------------------------------------- %%% UTILITIES %%%---------------------------------------------------------------------- +join([], _) -> + ""; +join([E], _) -> + E; +join([H | T], Separator) -> + lists:foldl(fun(E, Acc) -> lists:concat([Acc, Separator, E]) end, H, T). + +log(File, Code, Request) -> + {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:local_time(), + IP = join(tuple_to_list(Request#request.ip), "."), + Path = join(Request#request.path, "/"), + Query = case join(lists:map(fun(E) -> lists:concat([element(1, E), "=", element(2, E)]) end, + Request#request.q), "&") of + []-> + ""; + String -> + [$? | String] + end, + % combined apache like log format : + % 127.0.0.1 - - [28/Mar/2007:18:41:55 +0200] "GET / HTTP/1.1" 302 303 "-" "tsung" + % XXX TODO some fields are harcoded/missing (reply size, user agent or referer for example) + io:format(File, "~p - - [~p/~p/~p:~p:~p:~p] \"~s /~s~s\" ~p -1 \"-\" \"-\"~n", + [IP, Day, Month, Year, Hour, Minute, Second, Request#request.method, Path, Query, Code]). + content_type(Filename) -> case httpd_util:to_lower(filename:extension(Filename)) of ".jpg" -> "image/jpeg"; @@ -88,25 +132,78 @@ content_type(Filename) -> _Else -> "application/octet-stream" end. +open_file(Filename) -> + case file:open(Filename, [append]) of + {ok, File} -> + ets:insert(mod_http_fileserver, {accessfile, File}), + ok; + {error, _Reason} -> + {'EXIT', {unaccessible_accessfile, ?MODULE}} + end. + +loop(Filename) -> + receive + reopenlog -> + case ets:lookup(mod_http_fileserver, accessfile) of + undefined -> + ok; + [{accessfile, AccessFile}] -> + file:close(AccessFile), + case open_file(Filename) of + ok -> + ok; + _ -> + error + end + end, + loop(Filename); + stop -> + ok + end. + %%%---------------------------------------------------------------------- %%% BEHAVIOUR CALLBACKS %%%---------------------------------------------------------------------- start(_Host, Opts) -> + ejabberd_ctl:register_commands([{"reopen-weblog", "reopen http fileserver log file"}], + ?MODULE, ctl_process), case gen_mod:get_opt(docroot, Opts, undefined) of undefined -> {'EXIT', {missing_document_root, ?MODULE}}; DocRoot -> case filelib:is_dir(DocRoot) of true -> - ets:new(mod_http_fileserver, [named_table, bag]), + % XXX WARNING, using a single ets table name will + % not work with virtual hosts + ets:new(mod_http_fileserver, [named_table, public]), ets:insert(mod_http_fileserver, [{docroot, DocRoot}]), - ok; + case gen_mod:get_opt(accesslog, Opts, undefined) of + undefined -> + ok; + Filename -> + % XXX same remark as above for proc name + register(mod_http_fileserver_server, spawn(?MODULE, loop, [Filename])), + open_file(Filename) + end; _Else -> {'EXIT', {unaccessible_document_root, ?MODULE}} - end + end end. stop(_Host) -> - ok. + case ets:info(mod_http_fileserver, name) of + undefined -> + ok; + _ -> + case ets:lookup(mod_http_fileserver, accessfile) of + undefined -> + ok; + [{accessfile, AccessFile}] -> + mod_http_fileserver_server ! stop, + file:close(AccessFile) + end, + ets:delete(mod_http_fileserver) + end, + ok. From 91193bf9289d6ba8a5f13d9274eca4a2bdbc9550 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 13:52:17 +0000 Subject: [PATCH 363/582] Small change in accesslog file format; fix bug when accesslog conf parameter wasn't present in the conf file (thanks to Jerome Sautret) SVN Revision: 2185 --- src/web/mod_http_fileserver.erl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl index f04cf113c..a0c14964f 100644 --- a/src/web/mod_http_fileserver.erl +++ b/src/web/mod_http_fileserver.erl @@ -56,7 +56,7 @@ process(LocalPath, Request) -> Result = serve(LocalPath), case ets:lookup(mod_http_fileserver, accessfile) of - undefined -> + [] -> ok; [{accessfile, AccessFile}] -> {Code, _, _} = Result, @@ -114,7 +114,7 @@ log(File, Code, Request) -> % combined apache like log format : % 127.0.0.1 - - [28/Mar/2007:18:41:55 +0200] "GET / HTTP/1.1" 302 303 "-" "tsung" % XXX TODO some fields are harcoded/missing (reply size, user agent or referer for example) - io:format(File, "~p - - [~p/~p/~p:~p:~p:~p] \"~s /~s~s\" ~p -1 \"-\" \"-\"~n", + io:format(File, "~s - - [~p/~p/~p:~p:~p:~p] \"~s /~s~s\" ~p -1 \"-\" \"-\"~n", [IP, Day, Month, Year, Hour, Minute, Second, Request#request.method, Path, Query, Code]). content_type(Filename) -> @@ -145,7 +145,7 @@ loop(Filename) -> receive reopenlog -> case ets:lookup(mod_http_fileserver, accessfile) of - undefined -> + [] -> ok; [{accessfile, AccessFile}] -> file:close(AccessFile), @@ -198,7 +198,7 @@ stop(_Host) -> ok; _ -> case ets:lookup(mod_http_fileserver, accessfile) of - undefined -> + [] -> ok; [{accessfile, AccessFile}] -> mod_http_fileserver_server ! stop, From 0d4155b902212a98a54b7eeb887230b504508c61 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 13:52:28 +0000 Subject: [PATCH 364/582] The Erlang/OTP function httpd_util:to_lower/1 is deprecated, and it's recommended to use string:to_lower/1 instead. SVN Revision: 2186 --- src/web/mod_http_fileserver.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl index a0c14964f..ff101755f 100644 --- a/src/web/mod_http_fileserver.erl +++ b/src/web/mod_http_fileserver.erl @@ -118,7 +118,7 @@ log(File, Code, Request) -> [IP, Day, Month, Year, Hour, Minute, Second, Request#request.method, Path, Query, Code]). content_type(Filename) -> - case httpd_util:to_lower(filename:extension(Filename)) of + case string:to_lower(filename:extension(Filename)) of ".jpg" -> "image/jpeg"; ".jpeg" -> "image/jpeg"; ".gif" -> "image/gif"; From 6af85aea18ca2cbe23902ec261e3c05b78e6e008 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 13:52:32 +0000 Subject: [PATCH 365/582] Remove Erlang module attribute 'vsn' because it doesn't provide any worth feature, and it difficults hot code update (EJAB-440) SVN Revision: 2187 --- src/web/mod_http_fileserver.erl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl index ff101755f..990bc5fe6 100644 --- a/src/web/mod_http_fileserver.erl +++ b/src/web/mod_http_fileserver.erl @@ -8,7 +8,6 @@ -module(mod_http_fileserver). -author('mmirra@process-one.net'). --vsn(''). -define(ejabberd_debug, true). -compile([export_all]). From 0864e8a24f58e5337a2a71e568820c1438ec01ad Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 13:52:37 +0000 Subject: [PATCH 366/582] Fix error creating ETS table if enabled in several vhosts (EJAB-551). Unregister the command when stopping the module. SVN Revision: 2188 --- src/web/mod_http_fileserver.erl | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl index 990bc5fe6..aa85de904 100644 --- a/src/web/mod_http_fileserver.erl +++ b/src/web/mod_http_fileserver.erl @@ -165,25 +165,38 @@ loop(Filename) -> %%% BEHAVIOUR CALLBACKS %%%---------------------------------------------------------------------- +%% TODO: Improve this module to allow each virtual host to have a different +%% options. See http://support.process-one.net/browse/EJAB-561 start(_Host, Opts) -> - ejabberd_ctl:register_commands([{"reopen-weblog", "reopen http fileserver log file"}], - ?MODULE, ctl_process), + case ets:info(mod_http_fileserver, name) of + undefined -> + start2(_Host, Opts); + _ -> + ok + end. + +start2(_Host, Opts) -> case gen_mod:get_opt(docroot, Opts, undefined) of undefined -> {'EXIT', {missing_document_root, ?MODULE}}; DocRoot -> case filelib:is_dir(DocRoot) of true -> - % XXX WARNING, using a single ets table name will - % not work with virtual hosts + %% XXX WARNING, using a single ets table name will + %% not work with virtual hosts ets:new(mod_http_fileserver, [named_table, public]), ets:insert(mod_http_fileserver, [{docroot, DocRoot}]), case gen_mod:get_opt(accesslog, Opts, undefined) of undefined -> ok; Filename -> - % XXX same remark as above for proc name - register(mod_http_fileserver_server, spawn(?MODULE, loop, [Filename])), + %% XXX same remark as above for proc name + ejabberd_ctl:register_commands( + [{"reopen-weblog", + "reopen http fileserver log file"}], + ?MODULE, ctl_process), + register(mod_http_fileserver_server, + spawn(?MODULE, loop, [Filename])), open_file(Filename) end; _Else -> @@ -200,6 +213,10 @@ stop(_Host) -> [] -> ok; [{accessfile, AccessFile}] -> + ejabberd_ctl:unregister_commands( + [{"reopen-weblog", + "reopen http fileserver log file"}], + ?MODULE, ctl_process), mod_http_fileserver_server ! stop, file:close(AccessFile) end, From 4fdc4a2e061291542b0ec7995922c50d0c85727d Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 13:52:42 +0000 Subject: [PATCH 367/582] Include Last-Modified HTTP header in responses to allow caching (EJAB-546) in mod_http_fileserver and mod_muc_log_http. SVN Revision: 2189 --- src/web/mod_http_fileserver.erl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl index aa85de904..1131030bf 100644 --- a/src/web/mod_http_fileserver.erl +++ b/src/web/mod_http_fileserver.erl @@ -8,8 +8,6 @@ -module(mod_http_fileserver). -author('mmirra@process-one.net'). --define(ejabberd_debug, true). --compile([export_all]). -behaviour(gen_mod). @@ -17,6 +15,7 @@ start/2, stop/1, process/2, + loop/1, ctl_process/2 ]). @@ -24,6 +23,7 @@ -include("jlib.hrl"). -include("ejabberd_http.hrl"). -include("ejabberd_ctl.hrl"). +-include_lib("kernel/include/file.hrl"). %%%---------------------------------------------------------------------- %%% REQUEST HANDLERS @@ -71,6 +71,7 @@ serve(LocalPath) -> ?DEBUG("Delivering content.", []), {200, [{"Server", "ejabberd"}, + {"Last-Modified", last_modified(FileName)}, {"Content-type", content_type(FileName)}], FileContents}; {error, Error} -> @@ -131,6 +132,11 @@ content_type(Filename) -> _Else -> "application/octet-stream" end. +last_modified(FileName) -> + {ok, FileInfo} = file:read_file_info(FileName), + Then = FileInfo#file_info.mtime, + httpd_util:rfc1123_date(Then). + open_file(Filename) -> case file:open(Filename, [append]) of {ok, File} -> From 14afea1a20cdd6b9d808d240636ea05fdda3ff40 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 13:52:47 +0000 Subject: [PATCH 368/582] Added JavaScript content type SVN Revision: 2190 --- src/web/mod_http_fileserver.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl index 1131030bf..d3c796257 100644 --- a/src/web/mod_http_fileserver.erl +++ b/src/web/mod_http_fileserver.erl @@ -129,6 +129,7 @@ content_type(Filename) -> ".xul" -> "application/vnd.mozilla.xul+xml"; ".jar" -> "application/java-archive"; ".xpi" -> "application/x-xpinstall"; + ".js" -> "application/x-javascript"; _Else -> "application/octet-stream" end. From fa831479261f9c490f603da74957e71d964c6519 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 13:52:52 +0000 Subject: [PATCH 369/582] Use httpd_util:to_lower when not compiling with Erlang R12 (EJAB-628) SVN Revision: 2191 --- src/web/mod_http_fileserver.erl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl index d3c796257..96fa27e0c 100644 --- a/src/web/mod_http_fileserver.erl +++ b/src/web/mod_http_fileserver.erl @@ -25,6 +25,12 @@ -include("ejabberd_ctl.hrl"). -include_lib("kernel/include/file.hrl"). +-ifdef(SSL39). +-define(STRING2LOWER, string). +-else. +-define(STRING2LOWER, httpd_util). +-endif. + %%%---------------------------------------------------------------------- %%% REQUEST HANDLERS %%%---------------------------------------------------------------------- @@ -118,7 +124,7 @@ log(File, Code, Request) -> [IP, Day, Month, Year, Hour, Minute, Second, Request#request.method, Path, Query, Code]). content_type(Filename) -> - case string:to_lower(filename:extension(Filename)) of + case ?STRING2LOWER:to_lower(filename:extension(Filename)) of ".jpg" -> "image/jpeg"; ".jpeg" -> "image/jpeg"; ".gif" -> "image/gif"; From b44a3c765031ed1d1b63318c1521c3d83a287452 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 13:52:57 +0000 Subject: [PATCH 370/582] Fix ip source to comply with new ip storage into ejabberd_http (thanks to Christophe Romain) SVN Revision: 2192 --- src/web/mod_http_fileserver.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl index 96fa27e0c..0590a7e57 100644 --- a/src/web/mod_http_fileserver.erl +++ b/src/web/mod_http_fileserver.erl @@ -108,7 +108,7 @@ join([H | T], Separator) -> log(File, Code, Request) -> {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:local_time(), - IP = join(tuple_to_list(Request#request.ip), "."), + IP = join(tuple_to_list(element(1, Request#request.ip)), "."), Path = join(Request#request.path, "/"), Query = case join(lists:map(fun(E) -> lists:concat([element(1, E), "=", element(2, E)]) end, Request#request.q), "&") of From 4956ed11f4ebc81144ec2c94e18b5ad1bccd566a Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 13:53:02 +0000 Subject: [PATCH 371/582] Converted to gen_server behaviour (EJAB-561). Use the general reopen_log_hook instead of ejabberdctl command. SVN Revision: 2193 --- src/web/mod_http_fileserver.erl | 438 ++++++++++++++++++++------------ 1 file changed, 273 insertions(+), 165 deletions(-) diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl index 0590a7e57..889188843 100644 --- a/src/web/mod_http_fileserver.erl +++ b/src/web/mod_http_fileserver.erl @@ -1,76 +1,242 @@ -%%%---------------------------------------------------------------------- +%%%------------------------------------------------------------------- %%% File : mod_http_fileserver.erl %%% Author : Massimiliano Mirra <mmirra [at] process-one [dot] net> %%% Purpose : Simple file server plugin for embedded ejabberd web server -%%% Created : -%%% Id : -%%%---------------------------------------------------------------------- - +%%% Created : 26 Sep 2008 by Badlop <badlop@process-one.net> +%%%------------------------------------------------------------------- -module(mod_http_fileserver). -author('mmirra@process-one.net'). -behaviour(gen_mod). +-behaviour(gen_server). --export([ - start/2, - stop/1, - process/2, - loop/1, - ctl_process/2 - ]). +%% gen_mod callbacks +-export([start/2, stop/1]). + +%% API +-export([start_link/2]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +%% request_handlers callbacks +-export([process/2]). + +%% ejabberd_hooks callbacks +-export([reopen_log/1]). -include("ejabberd.hrl"). -include("jlib.hrl"). --include("ejabberd_http.hrl"). --include("ejabberd_ctl.hrl"). -include_lib("kernel/include/file.hrl"). +%%-include("ejabberd_http.hrl"). +%% TODO: When ejabberd-modules SVN gets the new ejabberd_http.hrl, delete this code: +-record(request, {method, + path, + q = [], + us, + auth, + lang = "", + data = "", + ip, + host, % string() + port, % integer() + tp, % transfer protocol = http | https + headers + }). + -ifdef(SSL39). -define(STRING2LOWER, string). -else. -define(STRING2LOWER, httpd_util). -endif. -%%%---------------------------------------------------------------------- -%%% REQUEST HANDLERS -%%%---------------------------------------------------------------------- +-record(state, {host, docroot, accesslog, accesslogfd}). -%%----------------------------------------------------------------------- -%% FUNCTION -%% -%% process/2 -%% -%% PURPOSE -%% -%% Handle an HTTP request. -%% -%% RETURNS -%% -%% Page to be sent back to the client and/or HTTP status code. -%% -%% ARGUMENTS -%% -%% - LocalPath: part of the requested URL path that is "local to the -%% module". -%% -%%----------------------------------------------------------------------- +-define(PROCNAME, ejabberd_mod_http_fileserver). +%%==================================================================== +%% gen_mod callbacks +%%==================================================================== +start(Host, Opts) -> + Proc = get_proc_name(Host), + ChildSpec = + {Proc, + {?MODULE, start_link, [Host, Opts]}, + temporary, + 1000, + worker, + [?MODULE]}, + supervisor:start_child(ejabberd_sup, ChildSpec). + +stop(Host) -> + Proc = get_proc_name(Host), + gen_server:call(Proc, stop), + supervisor:terminate_child(ejabberd_sup, Proc), + supervisor:delete_child(ejabberd_sup, Proc). + +%%==================================================================== +%% API +%%==================================================================== +%%-------------------------------------------------------------------- +%% Function: start_link() -> {ok,Pid} | ignore | {error,Error} +%% Description: Starts the server +%%-------------------------------------------------------------------- +start_link(Host, Opts) -> + Proc = get_proc_name(Host), + gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []). + +%%==================================================================== +%% gen_server callbacks +%%==================================================================== +%%-------------------------------------------------------------------- +%% Function: init(Args) -> {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%-------------------------------------------------------------------- +init([Host, Opts]) -> + try initialize(Host, Opts) of + {DocRoot, AccessLog, AccessLogFD} -> + {ok, #state{host = Host, + accesslog = AccessLog, + accesslogfd = AccessLogFD, + docroot = DocRoot}} + catch + throw:Reason -> + {stop, Reason} + end. + +initialize(Host, Opts) -> + DocRoot = gen_mod:get_opt(docroot, Opts, undefined), + check_docroot_defined(DocRoot, Host), + DRInfo = check_docroot_exists(DocRoot), + check_docroot_is_dir(DRInfo, DocRoot), + check_docroot_is_readable(DRInfo, DocRoot), + AccessLog = gen_mod:get_opt(accesslog, Opts, undefined), + AccessLogFD = try_open_log(AccessLog, Host), + {DocRoot, AccessLog, AccessLogFD}. + +check_docroot_defined(DocRoot, Host) -> + case DocRoot of + undefined -> throw({undefined_docroot_option, Host}); + _ -> ok + end. + +check_docroot_exists(DocRoot) -> + case file:read_file_info(DocRoot) of + {error, Reason} -> throw({error_access_docroot, DocRoot, Reason}); + {ok, FI} -> FI + end. + +check_docroot_is_dir(DRInfo, DocRoot) -> + case DRInfo#file_info.type of + directory -> ok; + _ -> throw({docroot_not_directory, DocRoot}) + end. + +check_docroot_is_readable(DRInfo, DocRoot) -> + case DRInfo#file_info.access of + read -> ok; + read_write -> ok; + _ -> throw({docroot_not_readable, DocRoot}) + end. + +try_open_log(undefined, _Host) -> + undefined; +try_open_log(FN, Host) -> + FD = try open_log(FN) of + FD1 -> FD1 + catch + throw:{cannot_open_accesslog, FN, Reason} -> + ?ERROR_MSG("Cannot open access log file: ~p~nReason: ~p", [FN, Reason]), + undefined + end, + ejabberd_hooks:add(reopen_log_hook, Host, ?MODULE, reopen_log, 50), + FD. + +%%-------------------------------------------------------------------- +%% 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({serve, LocalPath}, _From, State) -> + Reply = serve(LocalPath, State#state.docroot), + {reply, Reply, State}; +handle_call(_Request, _From, State) -> + {reply, ok, State}. + +%%-------------------------------------------------------------------- +%% Function: handle_cast(Msg, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% Description: Handling cast messages +%%-------------------------------------------------------------------- +handle_cast({add_to_log, Code, Request}, State) -> + add_to_log(State#state.accesslogfd, Code, Request), + {noreply, State}; +handle_cast(reopen_log, State) -> + FD2 = reopen_log(State#state.accesslog, State#state.accesslogfd), + {noreply, State#state{accesslogfd = FD2}}; +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}. + +%%-------------------------------------------------------------------- +%% 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) -> + close_log(State#state.accesslogfd), + ejabberd_hooks:delete(reopen_log_hook, State#state.host, ?MODULE, reopen_log, 50), + ok. + +%%-------------------------------------------------------------------- +%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState} +%% Description: Convert process state when code is changed +%%-------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%==================================================================== +%% request_handlers callbacks +%%==================================================================== + +%% @spec (LocalPath, Request) -> {HTTPCode::integer(), [Header], Page::string()} +%% @doc Handle an HTTP request. +%% LocalPath is the part of the requested URL path that is "local to the module". +%% Returns the page to be sent back to the client and/or HTTP status code. process(LocalPath, Request) -> ?DEBUG("Requested ~p", [LocalPath]), - - Result = serve(LocalPath), - case ets:lookup(mod_http_fileserver, accessfile) of - [] -> - ok; - [{accessfile, AccessFile}] -> + try gen_server:call(get_proc_name(Request#request.host), {serve, LocalPath}) of + Result -> {Code, _, _} = Result, - log(AccessFile, Code, Request) - end, - Result. + add_to_log(Code, Request), + Result + catch + exit:{noproc, _} -> + ejabberd_web:error(not_found) + end. -serve(LocalPath) -> - [{docroot, DocRoot}] = ets:lookup(mod_http_fileserver, docroot), +serve(LocalPath, DocRoot) -> FileName = filename:join(filename:split(DocRoot) ++ LocalPath), case file:read_file(FileName) of {ok, FileContents} -> @@ -89,15 +255,67 @@ serve(LocalPath) -> end end. -ctl_process(_Val, ["reopen-weblog"]) -> - mod_http_fileserver_server ! reopenlog, - ?STATUS_SUCCESS; -ctl_process(Val, _Args) -> - Val. +%%---------------------------------------------------------------------- +%% Log file +%%---------------------------------------------------------------------- -%%%---------------------------------------------------------------------- -%%% UTILITIES -%%%---------------------------------------------------------------------- +open_log(FN) -> + case file:open(FN, [append]) of + {ok, FD} -> + FD; + {error, Reason} -> + throw({cannot_open_accesslog, FN, Reason}) + end. + +close_log(FD) -> + file:close(FD). + +reopen_log(undefined, undefined) -> + ok; +reopen_log(FN, FD) -> + close_log(FD), + open_log(FN). + +reopen_log(Host) -> + gen_server:cast(get_proc_name(Host), reopen_log). + +add_to_log(Code, Request) -> + gen_server:cast(get_proc_name(Request#request.host), + {add_to_log, Code, Request}). + +add_to_log(undefined, _Code, _Request) -> + ok; +add_to_log(File, Code, Request) -> + {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:local_time(), + %% TODO: This IP address conversion supports only IPv4, not IPv6 + IP = join(tuple_to_list(element(1, Request#request.ip)), "."), + Path = join(Request#request.path, "/"), + Query = case join(lists:map(fun(E) -> lists:concat([element(1, E), "=", element(2, E)]) end, + Request#request.q), "&") of + [] -> + ""; + String -> + [$? | String] + end, + %% Pseudo Combined Apache log format: + %% 127.0.0.1 - - [28/Mar/2007:18:41:55 +0200] "GET / HTTP/1.1" 302 303 "-" "tsung" + %% TODO some fields are harcoded/missing: + %% The date/time integers should have always 2 digits. For example day "7" should be "07" + %% Month should be 3*letter, not integer 1..12 + %% Missing time zone = (`+' | `-') 4*digit + %% Missing protocol version: HTTP/1.1 + %% Missing size of the object, not including response headers. If no content: "-" + %% Missing Referer HTTP request header + %% Missing User-Agent HTTP request header. + %% For reference: http://httpd.apache.org/docs/2.2/logs.html + io:format(File, "~s - - [~p/~p/~p:~p:~p:~p] \"~s /~s~s\" ~p -1 \"-\" \"-\"~n", + [IP, Day, Month, Year, Hour, Minute, Second, Request#request.method, Path, Query, Code]). + +%%---------------------------------------------------------------------- +%% Utilities +%%---------------------------------------------------------------------- + +get_proc_name(Host) -> gen_mod:get_module_proc(Host, ?PROCNAME). join([], _) -> ""; @@ -106,23 +324,6 @@ join([E], _) -> join([H | T], Separator) -> lists:foldl(fun(E, Acc) -> lists:concat([Acc, Separator, E]) end, H, T). -log(File, Code, Request) -> - {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:local_time(), - IP = join(tuple_to_list(element(1, Request#request.ip)), "."), - Path = join(Request#request.path, "/"), - Query = case join(lists:map(fun(E) -> lists:concat([element(1, E), "=", element(2, E)]) end, - Request#request.q), "&") of - []-> - ""; - String -> - [$? | String] - end, - % combined apache like log format : - % 127.0.0.1 - - [28/Mar/2007:18:41:55 +0200] "GET / HTTP/1.1" 302 303 "-" "tsung" - % XXX TODO some fields are harcoded/missing (reply size, user agent or referer for example) - io:format(File, "~s - - [~p/~p/~p:~p:~p:~p] \"~s /~s~s\" ~p -1 \"-\" \"-\"~n", - [IP, Day, Month, Year, Hour, Minute, Second, Request#request.method, Path, Query, Code]). - content_type(Filename) -> case ?STRING2LOWER:to_lower(filename:extension(Filename)) of ".jpg" -> "image/jpeg"; @@ -143,96 +344,3 @@ last_modified(FileName) -> {ok, FileInfo} = file:read_file_info(FileName), Then = FileInfo#file_info.mtime, httpd_util:rfc1123_date(Then). - -open_file(Filename) -> - case file:open(Filename, [append]) of - {ok, File} -> - ets:insert(mod_http_fileserver, {accessfile, File}), - ok; - {error, _Reason} -> - {'EXIT', {unaccessible_accessfile, ?MODULE}} - end. - -loop(Filename) -> - receive - reopenlog -> - case ets:lookup(mod_http_fileserver, accessfile) of - [] -> - ok; - [{accessfile, AccessFile}] -> - file:close(AccessFile), - case open_file(Filename) of - ok -> - ok; - _ -> - error - end - end, - loop(Filename); - stop -> - ok - end. - - -%%%---------------------------------------------------------------------- -%%% BEHAVIOUR CALLBACKS -%%%---------------------------------------------------------------------- - -%% TODO: Improve this module to allow each virtual host to have a different -%% options. See http://support.process-one.net/browse/EJAB-561 -start(_Host, Opts) -> - case ets:info(mod_http_fileserver, name) of - undefined -> - start2(_Host, Opts); - _ -> - ok - end. - -start2(_Host, Opts) -> - case gen_mod:get_opt(docroot, Opts, undefined) of - undefined -> - {'EXIT', {missing_document_root, ?MODULE}}; - DocRoot -> - case filelib:is_dir(DocRoot) of - true -> - %% XXX WARNING, using a single ets table name will - %% not work with virtual hosts - ets:new(mod_http_fileserver, [named_table, public]), - ets:insert(mod_http_fileserver, [{docroot, DocRoot}]), - case gen_mod:get_opt(accesslog, Opts, undefined) of - undefined -> - ok; - Filename -> - %% XXX same remark as above for proc name - ejabberd_ctl:register_commands( - [{"reopen-weblog", - "reopen http fileserver log file"}], - ?MODULE, ctl_process), - register(mod_http_fileserver_server, - spawn(?MODULE, loop, [Filename])), - open_file(Filename) - end; - _Else -> - {'EXIT', {unaccessible_document_root, ?MODULE}} - end - end. - -stop(_Host) -> - case ets:info(mod_http_fileserver, name) of - undefined -> - ok; - _ -> - case ets:lookup(mod_http_fileserver, accessfile) of - [] -> - ok; - [{accessfile, AccessFile}] -> - ejabberd_ctl:unregister_commands( - [{"reopen-weblog", - "reopen http fileserver log file"}], - ?MODULE, ctl_process), - mod_http_fileserver_server ! stop, - file:close(AccessFile) - end, - ets:delete(mod_http_fileserver) - end, - ok. From 226bcd136091b8a97aceabe5b62f5c98309730cd Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 13:53:07 +0000 Subject: [PATCH 372/582] Fix capitalization of HTTP headers (thanks to Brian Cully)(EJAB-892) SVN Revision: 2194 --- src/web/mod_http_fileserver.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl index 889188843..a8f8068dd 100644 --- a/src/web/mod_http_fileserver.erl +++ b/src/web/mod_http_fileserver.erl @@ -244,7 +244,7 @@ serve(LocalPath, DocRoot) -> {200, [{"Server", "ejabberd"}, {"Last-Modified", last_modified(FileName)}, - {"Content-type", content_type(FileName)}], + {"Content-Type", content_type(FileName)}], FileContents}; {error, Error} -> ?DEBUG("Delivering error: ~p", [Error]), From 249ee4b318a9e9dcc4a4c4d7d04f1e74611aa296 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 13:53:13 +0000 Subject: [PATCH 373/582] New option directory_indices, and improve logging (thanks to Brian Cully)(EJAB-932) SVN Revision: 2195 --- src/web/mod_http_fileserver.erl | 112 ++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 40 deletions(-) diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl index a8f8068dd..910b770ec 100644 --- a/src/web/mod_http_fileserver.erl +++ b/src/web/mod_http_fileserver.erl @@ -52,10 +52,16 @@ -define(STRING2LOWER, httpd_util). -endif. --record(state, {host, docroot, accesslog, accesslogfd}). +-record(state, {host, docroot, accesslog, accesslogfd, directory_indices}). -define(PROCNAME, ejabberd_mod_http_fileserver). +%% Response is {DataSize, Code, [{HeaderKey, HeaderValue}], Data} +-define(HTTP_ERR_FILE_NOT_FOUND, {-1, 404, [], "Not found"}). +-define(HTTP_ERR_FORBIDDEN, {-1, 403, [], "Forbidden"}). + +-compile(export_all). + %%==================================================================== %% gen_mod callbacks %%==================================================================== @@ -100,11 +106,12 @@ start_link(Host, Opts) -> %%-------------------------------------------------------------------- init([Host, Opts]) -> try initialize(Host, Opts) of - {DocRoot, AccessLog, AccessLogFD} -> + {DocRoot, AccessLog, AccessLogFD, DirectoryIndices} -> {ok, #state{host = Host, accesslog = AccessLog, accesslogfd = AccessLogFD, - docroot = DocRoot}} + docroot = DocRoot, + directory_indices = DirectoryIndices}} catch throw:Reason -> {stop, Reason} @@ -118,7 +125,8 @@ initialize(Host, Opts) -> check_docroot_is_readable(DRInfo, DocRoot), AccessLog = gen_mod:get_opt(accesslog, Opts, undefined), AccessLogFD = try_open_log(AccessLog, Host), - {DocRoot, AccessLog, AccessLogFD}. + DirectoryIndices = gen_mod:get_opt(directory_indices, Opts, []), + {DocRoot, AccessLog, AccessLogFD, DirectoryIndices}. check_docroot_defined(DocRoot, Host) -> case DocRoot of @@ -168,7 +176,7 @@ try_open_log(FN, Host) -> %% Description: Handling call messages %%-------------------------------------------------------------------- handle_call({serve, LocalPath}, _From, State) -> - Reply = serve(LocalPath, State#state.docroot), + Reply = serve(LocalPath, State#state.docroot, State#state.directory_indices), {reply, Reply, State}; handle_call(_Request, _From, State) -> {reply, ok, State}. @@ -179,8 +187,8 @@ handle_call(_Request, _From, State) -> %% {stop, Reason, State} %% Description: Handling cast messages %%-------------------------------------------------------------------- -handle_cast({add_to_log, Code, Request}, State) -> - add_to_log(State#state.accesslogfd, Code, Request), +handle_cast({add_to_log, FileSize, Code, Request}, State) -> + add_to_log(State#state.accesslogfd, FileSize, Code, Request), {noreply, State}; handle_cast(reopen_log, State) -> FD2 = reopen_log(State#state.accesslog, State#state.accesslogfd), @@ -227,34 +235,46 @@ code_change(_OldVsn, State, _Extra) -> process(LocalPath, Request) -> ?DEBUG("Requested ~p", [LocalPath]), try gen_server:call(get_proc_name(Request#request.host), {serve, LocalPath}) of - Result -> - {Code, _, _} = Result, - add_to_log(Code, Request), - Result + {FileSize, Code, Headers, Contents} -> + add_to_log(FileSize, Code, Request), + {Code, Headers, Contents} catch exit:{noproc, _} -> ejabberd_web:error(not_found) end. -serve(LocalPath, DocRoot) -> +serve(LocalPath, DocRoot, DirectoryIndices) -> FileName = filename:join(filename:split(DocRoot) ++ LocalPath), - case file:read_file(FileName) of - {ok, FileContents} -> - ?DEBUG("Delivering content.", []), - {200, - [{"Server", "ejabberd"}, - {"Last-Modified", last_modified(FileName)}, - {"Content-Type", content_type(FileName)}], - FileContents}; - {error, Error} -> - ?DEBUG("Delivering error: ~p", [Error]), - case Error of - eacces -> {403, [], "Forbidden"}; - enoent -> {404, [], "Not found"}; - _Else -> {404, [], atom_to_list(Error)} - end + case file:read_file_info(FileName) of + {error, enoent} -> ?HTTP_ERR_FILE_NOT_FOUND; + {error, eacces} -> ?HTTP_ERR_FORBIDDEN; + {ok, #file_info{type = directory}} -> serve_index(FileName, DirectoryIndices); + {ok, FileInfo} -> serve_file(FileInfo, FileName) end. +%% Troll through the directory indices attempting to find one which +%% works, if none can be found, return a 404. +serve_index(_FileName, []) -> + ?HTTP_ERR_FILE_NOT_FOUND; +serve_index(FileName, [Index | T]) -> + IndexFileName = filename:join([FileName] ++ [Index]), + case file:read_file_info(IndexFileName) of + {error, _Error} -> serve_index(FileName, T); + {ok, #file_info{type = directory}} -> serve_index(FileName, T); + {ok, FileInfo} -> serve_file(FileInfo, IndexFileName) + end. + +%% Assume the file exists if we got this far and attempt to read it in +%% and serve it up. +serve_file(FileInfo, FileName) -> + ?DEBUG("Delivering: ~s", [FileName]), + {ok, FileContents} = file:read_file(FileName), + {FileInfo#file_info.size, + 200, [{"Server", "ejabberd"}, + {"Last-Modified", last_modified(FileInfo)}, + {"Content-Type", content_type(FileName)}], + FileContents}. + %%---------------------------------------------------------------------- %% Log file %%---------------------------------------------------------------------- @@ -279,16 +299,15 @@ reopen_log(FN, FD) -> reopen_log(Host) -> gen_server:cast(get_proc_name(Host), reopen_log). -add_to_log(Code, Request) -> +add_to_log(FileSize, Code, Request) -> gen_server:cast(get_proc_name(Request#request.host), - {add_to_log, Code, Request}). + {add_to_log, FileSize, Code, Request}). -add_to_log(undefined, _Code, _Request) -> +add_to_log(undefined, _FileSize, _Code, _Request) -> ok; -add_to_log(File, Code, Request) -> +add_to_log(File, FileSize, Code, Request) -> {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:local_time(), - %% TODO: This IP address conversion supports only IPv4, not IPv6 - IP = join(tuple_to_list(element(1, Request#request.ip)), "."), + IP = ip_to_string(element(1, Request#request.ip)), Path = join(Request#request.path, "/"), Query = case join(lists:map(fun(E) -> lists:concat([element(1, E), "=", element(2, E)]) end, Request#request.q), "&") of @@ -297,6 +316,8 @@ add_to_log(File, Code, Request) -> String -> [$? | String] end, + UserAgent = find_header('User-Agent', Request#request.headers, "-"), + Referer = find_header('Referer', Request#request.headers, "-"), %% Pseudo Combined Apache log format: %% 127.0.0.1 - - [28/Mar/2007:18:41:55 +0200] "GET / HTTP/1.1" 302 303 "-" "tsung" %% TODO some fields are harcoded/missing: @@ -304,12 +325,16 @@ add_to_log(File, Code, Request) -> %% Month should be 3*letter, not integer 1..12 %% Missing time zone = (`+' | `-') 4*digit %% Missing protocol version: HTTP/1.1 - %% Missing size of the object, not including response headers. If no content: "-" - %% Missing Referer HTTP request header - %% Missing User-Agent HTTP request header. %% For reference: http://httpd.apache.org/docs/2.2/logs.html - io:format(File, "~s - - [~p/~p/~p:~p:~p:~p] \"~s /~s~s\" ~p -1 \"-\" \"-\"~n", - [IP, Day, Month, Year, Hour, Minute, Second, Request#request.method, Path, Query, Code]). + io:format(File, "~s - - [~p/~p/~p:~p:~p:~p] \"~s /~s~s\" ~p ~p ~p ~p~n", + [IP, Day, Month, Year, Hour, Minute, Second, Request#request.method, Path, Query, Code, + FileSize, Referer, UserAgent]). + +find_header(Header, Headers, Default) -> + case lists:keysearch(Header, 1, Headers) of + {value, {_, Value}} -> Value; + false -> Default + end. %%---------------------------------------------------------------------- %% Utilities @@ -340,7 +365,14 @@ content_type(Filename) -> _Else -> "application/octet-stream" end. -last_modified(FileName) -> - {ok, FileInfo} = file:read_file_info(FileName), +last_modified(FileInfo) -> Then = FileInfo#file_info.mtime, httpd_util:rfc1123_date(Then). + +%% Convert IP address tuple to string representation. Accepts either +%% IPv4 or IPv6 address tuples. +ip_to_string(Address) when size(Address) == 4 -> + join(tuple_to_list(Address), "."); +ip_to_string(Address) when size(Address) == 8 -> + Parts = lists:map(fun (Int) -> io_lib:format("~.16B", [Int]) end, tuple_to_list(Address)), + ?STRING2LOWER:to_lower(lists:flatten(join(Parts, ":"))). From 8e8b78a4c3f30220abe332fc0dd9d63388b8835f Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 13:53:18 +0000 Subject: [PATCH 374/582] Add forgotten copyright and license notices. SVN Revision: 2196 --- src/web/mod_http_fileserver.erl | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl index 910b770ec..5d5eebb7f 100644 --- a/src/web/mod_http_fileserver.erl +++ b/src/web/mod_http_fileserver.erl @@ -2,8 +2,28 @@ %%% File : mod_http_fileserver.erl %%% Author : Massimiliano Mirra <mmirra [at] process-one [dot] net> %%% Purpose : Simple file server plugin for embedded ejabberd web server -%%% Created : 26 Sep 2008 by Badlop <badlop@process-one.net> -%%%------------------------------------------------------------------- +%%% Created : +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%%---------------------------------------------------------------------- + -module(mod_http_fileserver). -author('mmirra@process-one.net'). From 77a62670d3f1687c9041b80beb5628fe3ec711f6 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 13:53:25 +0000 Subject: [PATCH 375/582] Add permanent section about mod_http_fileserver to the Guide. Example config. SVN Revision: 2197 --- doc/Makefile | 3 - doc/guide.html | 259 +++++++++++++++++++++++---------------- doc/guide.tex | 59 ++++++++- src/ejabberd.cfg.example | 12 +- 4 files changed, 219 insertions(+), 114 deletions(-) diff --git a/doc/Makefile b/doc/Makefile index 3cc89b059..aa1a71673 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -6,9 +6,6 @@ CONTRIBUTED_MODULES = "" ifeq ($(shell ls mod_http_bind.tex),mod_http_bind.tex) CONTRIBUTED_MODULES += "\\n\\setboolean{modhttpbind}{true}" endif -ifeq ($(shell ls mod_http_fileserver.tex),mod_http_fileserver.tex) - CONTRIBUTED_MODULES += "\\n\\setboolean{modhttpfileserver}{true}" -endif all: release pdf html diff --git a/doc/guide.html b/doc/guide.html index 464f60eec..fdfaf3baf 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -142,76 +142,77 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;} </LI><LI CLASS="li-toc"><A HREF="#htoc40">3.3.3  <TT>mod_announce</TT></A> </LI><LI CLASS="li-toc"><A HREF="#htoc41">3.3.4  <TT>mod_disco</TT></A> </LI><LI CLASS="li-toc"><A HREF="#htoc42">3.3.5  <TT>mod_echo</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc43">3.3.6  <TT>mod_last</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc44">3.3.7  <TT>mod_muc</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc45">3.3.8  <TT>mod_muc_log</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc46">3.3.9  <TT>mod_offline</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc47">3.3.10  <TT>mod_privacy</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc48">3.3.11  <TT>mod_private</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc49">3.3.12  <TT>mod_proxy65</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc50">3.3.13  <TT>mod_pubsub</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc51">3.3.14  <TT>mod_register</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc52">3.3.15  <TT>mod_roster</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc53">3.3.16  <TT>mod_service_log</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc54">3.3.17  <TT>mod_shared_roster</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc55">3.3.18  <TT>mod_stats</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc56">3.3.19  <TT>mod_time</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc57">3.3.20  <TT>mod_vcard</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc58">3.3.21  <TT>mod_vcard_ldap</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc59">3.3.22  <TT>mod_version</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc43">3.3.6  <TT>mod_http_fileserver</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc44">3.3.7  <TT>mod_last</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc45">3.3.8  <TT>mod_muc</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc46">3.3.9  <TT>mod_muc_log</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc47">3.3.10  <TT>mod_offline</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc48">3.3.11  <TT>mod_privacy</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc49">3.3.12  <TT>mod_private</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc50">3.3.13  <TT>mod_proxy65</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc51">3.3.14  <TT>mod_pubsub</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc52">3.3.15  <TT>mod_register</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc53">3.3.16  <TT>mod_roster</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc54">3.3.17  <TT>mod_service_log</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc55">3.3.18  <TT>mod_shared_roster</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc56">3.3.19  <TT>mod_stats</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc57">3.3.20  <TT>mod_time</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc58">3.3.21  <TT>mod_vcard</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc59">3.3.22  <TT>mod_vcard_ldap</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc60">3.3.23  <TT>mod_version</TT></A> </LI></UL> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc60">Chapter 4  Managing an <TT>ejabberd</TT> Server</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc61">Chapter 4  Managing an <TT>ejabberd</TT> Server</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc61">4.1  <TT>ejabberdctl</TT></A> +<A HREF="#htoc62">4.1  <TT>ejabberdctl</TT></A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc62">4.1.1  ejabberdctl Commands</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc63">4.1.2  Erlang Runtime System</A> +<A HREF="#htoc63">4.1.1  ejabberdctl Commands</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc64">4.1.2  Erlang Runtime System</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc64">4.2  <TT>ejabberd</TT> Commands</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc65">4.2  <TT>ejabberd</TT> Commands</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc65">4.2.1  List of ejabberd Commands</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc66">4.2.2  Restrict Execution with AccessCommands</A> +<A HREF="#htoc66">4.2.1  List of ejabberd Commands</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc67">4.2.2  Restrict Execution with AccessCommands</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc67">4.3  Web Admin</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc68">4.4  Ad-hoc Commands</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc69">4.5  Change Computer Hostname</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc68">4.3  Web Admin</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc69">4.4  Ad-hoc Commands</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc70">4.5  Change Computer Hostname</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc70">Chapter 5  Securing <TT>ejabberd</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc71">Chapter 5  Securing <TT>ejabberd</TT></A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc71">5.1  Firewall Settings</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc72">5.2  epmd</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc73">5.3  Erlang Cookie</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc74">5.4  Erlang Node Name</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc75">5.5  Securing Sensible Files</A> +<A HREF="#htoc72">5.1  Firewall Settings</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc73">5.2  epmd</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc74">5.3  Erlang Cookie</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc75">5.4  Erlang Node Name</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc76">5.5  Securing Sensible Files</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc76">Chapter 6  Clustering</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc77">Chapter 6  Clustering</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc77">6.1  How it Works</A> +<A HREF="#htoc78">6.1  How it Works</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc78">6.1.1  Router</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc79">6.1.2  Local Router</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc80">6.1.3  Session Manager</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc81">6.1.4  s2s Manager</A> +<A HREF="#htoc79">6.1.1  Router</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc80">6.1.2  Local Router</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc81">6.1.3  Session Manager</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc82">6.1.4  s2s Manager</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc82">6.2  Clustering Setup</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc83">6.3  Service Load-Balancing</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc83">6.2  Clustering Setup</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc84">6.3  Service Load-Balancing</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc84">6.3.1  Components Load-Balancing</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc85">6.3.2  Domain Load-Balancing Algorithm</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc86">6.3.3  Load-Balancing Buckets</A> +<A HREF="#htoc85">6.3.1  Components Load-Balancing</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc86">6.3.2  Domain Load-Balancing Algorithm</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc87">6.3.3  Load-Balancing Buckets</A> </LI></UL> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc87">Chapter 7  Debugging</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc88">Chapter 7  Debugging</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc88">7.1  Log Files</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc89">7.2  Debug Console</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc90">7.3  Watchdog Alerts</A> +<A HREF="#htoc89">7.1  Log Files</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc90">7.2  Debug Console</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc91">7.3  Watchdog Alerts</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc91">Appendix A  Internationalization and Localization</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc92">Appendix B  Release Notes</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc93">Appendix C  Acknowledgements</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc94">Appendix D  Copyright Information</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc92">Appendix A  Internationalization and Localization</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc93">Appendix B  Release Notes</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc94">Appendix C  Acknowledgements</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc95">Appendix D  Copyright Information</A> </LI></UL><!--TOC chapter Introduction--> <H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc1">Chapter 1</A>  Introduction</H1><!--SEC END --><P> <A NAME="intro"></A></P><P><TT>ejabberd</TT> is a free and open source instant messaging server written in <A HREF="http://www.erlang.org/">Erlang</A>.</P><P><TT>ejabberd</TT> is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.</P><P><TT>ejabberd</TT> is designed to be a rock-solid and feature rich XMPP server.</P><P><TT>ejabberd</TT> is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.</P><!--TOC section Key Features--> @@ -489,7 +490,7 @@ There are two ways to register a Jabber account: <OL CLASS="enumerate" type=a><LI CLASS="li-enumerate"> Using <TT>ejabberdctl</TT> (see section <A HREF="#ejabberdctl">4.1</A>): <PRE CLASS="verbatim">ejabberdctl register admin1 example.org FgT5bk3 -</PRE></LI><LI CLASS="li-enumerate">Using a Jabber client and In-Band Registration (see section <A HREF="#modregister">3.3.14</A>). +</PRE></LI><LI CLASS="li-enumerate">Using a Jabber client and In-Band Registration (see section <A HREF="#modregister">3.3.15</A>). </LI></OL> </LI><LI CLASS="li-enumerate">Edit the <TT>ejabberd</TT> configuration file to give administration rights to the Jabber account you created: <PRE CLASS="verbatim">{acl, admins, {user, "admin1", "example.org"}}. @@ -1885,7 +1886,7 @@ message is sent to all registered users. If the user is online and connected to several resources, only the resource with the highest priority will receive the message. If the registered user is not connected, the message will be stored offline in assumption that offline storage -(see section <A HREF="#modoffline">3.3.9</A>) is enabled. +(see section <A HREF="#modoffline">3.3.10</A>) is enabled. </DD><DT CLASS="dt-description"><B><TT>example.org/announce/online (example.org/announce/all-hosts/online)</TT></B></DT><DD CLASS="dd-description">The message is sent to all connected users. If the user is online and connected to several resources, all resources will receive the message. @@ -1995,8 +1996,54 @@ of them all? {mod_echo, [{host, "mirror.example.org"}]}, ... ]}. +</PRE><P> <A NAME="modhttpfileserver"></A> </P><!--TOC subsection <TT>mod_http_fileserver</TT>--> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc43">3.3.6</A>  <A HREF="#modhttpfileserver"><TT>mod_http_fileserver</TT></A></H3><!--SEC END --><P> <A NAME="modhttpfileserver"></A> +</P><P>This simple module serves files from the local disk over HTTP.</P><P>Options: +</P><DL CLASS="description"><DT CLASS="dt-description"> +<B><TT>docroot</TT></B></DT><DD CLASS="dd-description"> +Directory to serve the files. +</DD><DT CLASS="dt-description"><B><TT>accesslog</TT></B></DT><DD CLASS="dd-description"> +File to log accesses using an Apache-like format. +No log will be recorded if this option is not specified. +</DD><DT CLASS="dt-description"><B><TT>directory_indices</TT></B></DT><DD CLASS="dd-description"> +Indicate one or more directory index files, similarly to Apache’s +DirectoryIndex variable. When a web request hits a directory +instead of a regular file, those directory indices are looked in +order, and the first one found is returned. +</DD></DL><P>This example configuration will serve the files from +the local directory <CODE>/var/www</CODE> +in the address <CODE>http://example.org:5280/pub/archive/</CODE>. +To use this module you must enable it: +</P><PRE CLASS="verbatim">{modules, + [ + ... + {mod_http_fileserver, [ + {docroot, "/var/www"}, + {directory_indices, ["index.html", "main.htm"]}, + {accesslog, "/var/log/ejabberd/access.log"} + ] + }, + ... +]}. +</PRE><P>And define it as a handler in the HTTP service: +</P><PRE CLASS="verbatim">{listen, + [ + ... + {5280, ejabberd_http, [ + ... + {request_handlers, [ + ... + {["pub", "archive"], mod_http_fileserver}, + ... + ] + }, + ... + ] + }, + ... +]}. </PRE><P> <A NAME="modlast"></A> </P><!--TOC subsection <TT>mod_last</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc43">3.3.6</A>  <A HREF="#modlast"><TT>mod_last</TT></A></H3><!--SEC END --><P> <A NAME="modlast"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc44">3.3.7</A>  <A HREF="#modlast"><TT>mod_last</TT></A></H3><!--SEC END --><P> <A NAME="modlast"></A> </P><P>This module adds support for Last Activity (<A HREF="http://www.xmpp.org/extensions/xep-0012.html">XEP-0012</A>). It can be used to discover when a disconnected user last accessed the server, to know when a connected user was last active on the server, or to query the uptime of the @@ -2005,7 +2052,7 @@ connected user was last active on the server, or to query the uptime of the <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Last activity (<TT>jabber:iq:last</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modmuc"></A> </P><!--TOC subsection <TT>mod_muc</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc44">3.3.7</A>  <A HREF="#modmuc"><TT>mod_muc</TT></A></H3><!--SEC END --><P> <A NAME="modmuc"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc45">3.3.8</A>  <A HREF="#modmuc"><TT>mod_muc</TT></A></H3><!--SEC END --><P> <A NAME="modmuc"></A> </P><P>This module provides a Multi-User Chat (<A HREF="http://www.xmpp.org/extensions/xep-0045.html">XEP-0045</A>) service. Users can discover existing rooms, join or create them. Occupants of a room can chat in public or have private chats.</P><P>Some of the features of Multi-User Chat: @@ -2228,7 +2275,7 @@ the newly created rooms have by default those options. ... ]}. </PRE></LI></UL><P> <A NAME="modmuclog"></A> </P><!--TOC subsection <TT>mod_muc_log</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc45">3.3.8</A>  <A HREF="#modmuclog"><TT>mod_muc_log</TT></A></H3><!--SEC END --><P> <A NAME="modmuclog"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc46">3.3.9</A>  <A HREF="#modmuclog"><TT>mod_muc_log</TT></A></H3><!--SEC END --><P> <A NAME="modmuclog"></A> </P><P>This module enables optional logging of Multi-User Chat (MUC) public conversations to HTML. Once you enable this module, users can join a room using a MUC capable Jabber client, and if they have enough privileges, they can request the @@ -2348,7 +2395,7 @@ top link will be the default <CODE><a href="/">Home</a></CODE>. ... ]}. </PRE></LI></UL><P> <A NAME="modoffline"></A> </P><!--TOC subsection <TT>mod_offline</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc46">3.3.9</A>  <A HREF="#modoffline"><TT>mod_offline</TT></A></H3><!--SEC END --><P> <A NAME="modoffline"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc47">3.3.10</A>  <A HREF="#modoffline"><TT>mod_offline</TT></A></H3><!--SEC END --><P> <A NAME="modoffline"></A> </P><P>This module implements offline message storage. This means that all messages sent to an offline user will be stored on the server until that user comes online again. Thus it is very similar to how email works. Note that @@ -2379,7 +2426,7 @@ and all the other users up to 100. ... ]}. </PRE><P> <A NAME="modprivacy"></A> </P><!--TOC subsection <TT>mod_privacy</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc47">3.3.10</A>  <A HREF="#modprivacy"><TT>mod_privacy</TT></A></H3><!--SEC END --><P> <A NAME="modprivacy"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc48">3.3.11</A>  <A HREF="#modprivacy"><TT>mod_privacy</TT></A></H3><!--SEC END --><P> <A NAME="modprivacy"></A> </P><P>This module implements Blocking Communication (also known as Privacy Rules) as defined in section 10 from XMPP IM. If end users have support for it in their Jabber client, they will be able to: @@ -2407,7 +2454,7 @@ subscription type (or globally). <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Blocking Communication (<TT>jabber:iq:privacy</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modprivate"></A> </P><!--TOC subsection <TT>mod_private</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc48">3.3.11</A>  <A HREF="#modprivate"><TT>mod_private</TT></A></H3><!--SEC END --><P> <A NAME="modprivate"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc49">3.3.12</A>  <A HREF="#modprivate"><TT>mod_private</TT></A></H3><!--SEC END --><P> <A NAME="modprivate"></A> </P><P>This module adds support for Private XML Storage (<A HREF="http://www.xmpp.org/extensions/xep-0049.html">XEP-0049</A>): </P><BLOCKQUOTE CLASS="quote"> Using this method, Jabber entities can store private data on the server and @@ -2419,7 +2466,7 @@ of client-specific preferences; another is Bookmark Storage (<A HREF="http://www <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Private XML Storage (<TT>jabber:iq:private</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modproxy"></A> </P><!--TOC subsection <TT>mod_proxy65</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc49">3.3.12</A>  <A HREF="#modproxy"><TT>mod_proxy65</TT></A></H3><!--SEC END --><P> <A NAME="modproxy"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc50">3.3.13</A>  <A HREF="#modproxy"><TT>mod_proxy65</TT></A></H3><!--SEC END --><P> <A NAME="modproxy"></A> </P><P>This module implements SOCKS5 Bytestreams (<A HREF="http://www.xmpp.org/extensions/xep-0065.html">XEP-0065</A>). It allows <TT>ejabberd</TT> to act as a file transfer proxy between two XMPP clients.</P><P>Options: @@ -2474,7 +2521,7 @@ The simpliest configuration of the module: ... ]}. </PRE></LI></UL><P> <A NAME="modpubsub"></A> </P><!--TOC subsection <TT>mod_pubsub</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc50">3.3.13</A>  <A HREF="#modpubsub"><TT>mod_pubsub</TT></A></H3><!--SEC END --><P> <A NAME="modpubsub"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc51">3.3.14</A>  <A HREF="#modpubsub"><TT>mod_pubsub</TT></A></H3><!--SEC END --><P> <A NAME="modpubsub"></A> </P><P>This module offers a Publish-Subscribe Service (<A HREF="http://www.xmpp.org/extensions/xep-0060.html">XEP-0060</A>). The functionality in <TT>mod_pubsub</TT> can be extended using plugins. The plugin that implements PEP (Personal Eventing via Pubsub) (<A HREF="http://www.xmpp.org/extensions/xep-0163.html">XEP-0163</A>) @@ -2520,7 +2567,7 @@ The following example will use node_tune instead of node_pep for every PEP node ... ]}. </PRE><P> <A NAME="modregister"></A> </P><!--TOC subsection <TT>mod_register</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc51">3.3.14</A>  <A HREF="#modregister"><TT>mod_register</TT></A></H3><!--SEC END --><P> <A NAME="modregister"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc52">3.3.15</A>  <A HREF="#modregister"><TT>mod_register</TT></A></H3><!--SEC END --><P> <A NAME="modregister"></A> </P><P>This module adds support for In-Band Registration (<A HREF="http://www.xmpp.org/extensions/xep-0077.html">XEP-0077</A>). This protocol enables end users to use a Jabber client to: </P><UL CLASS="itemize"><LI CLASS="li-itemize"> @@ -2593,13 +2640,13 @@ Also define a registration timeout of one hour: ... ]}. </PRE></LI></UL><P> <A NAME="modroster"></A> </P><!--TOC subsection <TT>mod_roster</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc52">3.3.15</A>  <A HREF="#modroster"><TT>mod_roster</TT></A></H3><!--SEC END --><P> <A NAME="modroster"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc53">3.3.16</A>  <A HREF="#modroster"><TT>mod_roster</TT></A></H3><!--SEC END --><P> <A NAME="modroster"></A> </P><P>This module implements roster management as defined in <A HREF="http://www.xmpp.org/specs/rfc3921.html#roster">RFC 3921: XMPP IM</A>.</P><P>Options: </P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Roster Management (<TT>jabber:iq:roster</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modservicelog"></A> </P><!--TOC subsection <TT>mod_service_log</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc53">3.3.16</A>  <A HREF="#modservicelog"><TT>mod_service_log</TT></A></H3><!--SEC END --><P> <A NAME="modservicelog"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc54">3.3.17</A>  <A HREF="#modservicelog"><TT>mod_service_log</TT></A></H3><!--SEC END --><P> <A NAME="modservicelog"></A> </P><P>This module adds support for logging end user packets via a Jabber message auditing service such as <A HREF="http://www.funkypenguin.info/project/bandersnatch/">Bandersnatch</A>. All user @@ -2629,7 +2676,7 @@ To log all end user packets to the Bandersnatch service running on ... ]}. </PRE></LI></UL><P> <A NAME="modsharedroster"></A> </P><!--TOC subsection <TT>mod_shared_roster</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc54">3.3.17</A>  <A HREF="#modsharedroster"><TT>mod_shared_roster</TT></A></H3><!--SEC END --><P> <A NAME="modsharedroster"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc55">3.3.18</A>  <A HREF="#modsharedroster"><TT>mod_shared_roster</TT></A></H3><!--SEC END --><P> <A NAME="modsharedroster"></A> </P><P>This module enables you to create shared roster groups. This means that you can create groups of people that can see members from (other) groups in their rosters. The big advantages of this feature are that end users do not need to @@ -2704,7 +2751,7 @@ roster groups as shown in the following table: </TABLE> <DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV></DIV></BLOCKQUOTE> </LI></UL><P> <A NAME="modstats"></A> </P><!--TOC subsection <TT>mod_stats</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc55">3.3.18</A>  <A HREF="#modstats"><TT>mod_stats</TT></A></H3><!--SEC END --><P> <A NAME="modstats"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc56">3.3.19</A>  <A HREF="#modstats"><TT>mod_stats</TT></A></H3><!--SEC END --><P> <A NAME="modstats"></A> </P><P>This module adds support for Statistics Gathering (<A HREF="http://www.xmpp.org/extensions/xep-0039.html">XEP-0039</A>). This protocol allows you to retrieve next statistics from your <TT>ejabberd</TT> deployment: </P><UL CLASS="itemize"><LI CLASS="li-itemize"> @@ -2736,14 +2783,14 @@ by sending: </query> </iq> </PRE></LI></UL><P> <A NAME="modtime"></A> </P><!--TOC subsection <TT>mod_time</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc56">3.3.19</A>  <A HREF="#modtime"><TT>mod_time</TT></A></H3><!--SEC END --><P> <A NAME="modtime"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc57">3.3.20</A>  <A HREF="#modtime"><TT>mod_time</TT></A></H3><!--SEC END --><P> <A NAME="modtime"></A> </P><P>This module features support for Entity Time (<A HREF="http://www.xmpp.org/extensions/xep-0090.html">XEP-0090</A>). By using this XEP, you are able to discover the time at another entity’s location.</P><P>Options: </P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Entity Time (<TT>jabber:iq:time</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modvcard"></A> </P><!--TOC subsection <TT>mod_vcard</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc57">3.3.20</A>  <A HREF="#modvcard"><TT>mod_vcard</TT></A></H3><!--SEC END --><P> <A NAME="modvcard"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc58">3.3.21</A>  <A HREF="#modvcard"><TT>mod_vcard</TT></A></H3><!--SEC END --><P> <A NAME="modvcard"></A> </P><P>This module allows end users to store and retrieve their vCard, and to retrieve other users vCards, as defined in vcard-temp (<A HREF="http://www.xmpp.org/extensions/xep-0054.html">XEP-0054</A>). The module also implements an uncomplicated Jabber User Directory based on the vCards of @@ -2798,7 +2845,7 @@ and that all virtual hosts will be searched instead of only the current one: ... ]}. </PRE></LI></UL><P> <A NAME="modvcardldap"></A> </P><!--TOC subsection <TT>mod_vcard_ldap</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc58">3.3.21</A>  <A HREF="#modvcardldap"><TT>mod_vcard_ldap</TT></A></H3><!--SEC END --><P> <A NAME="modvcardldap"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc59">3.3.22</A>  <A HREF="#modvcardldap"><TT>mod_vcard_ldap</TT></A></H3><!--SEC END --><P> <A NAME="modvcardldap"></A> </P><P><TT>ejabberd</TT> can map LDAP attributes to vCard fields. This behaviour is implemented in the <TT>mod_vcard_ldap</TT> module. This module does not depend on the authentication method (see <A HREF="#ldapauth">3.2.5</A>).</P><P>Note that <TT>ejabberd</TT> treats LDAP as a read-only storage: @@ -2974,7 +3021,7 @@ searching his info in LDAP.</P></LI><LI CLASS="li-itemize"><TT>ldap_vcard_map</T {"Nickname", "NICKNAME"} ]}, </PRE></LI></UL><P> <A NAME="modversion"></A> </P><!--TOC subsection <TT>mod_version</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc59">3.3.22</A>  <A HREF="#modversion"><TT>mod_version</TT></A></H3><!--SEC END --><P> <A NAME="modversion"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc60">3.3.23</A>  <A HREF="#modversion"><TT>mod_version</TT></A></H3><!--SEC END --><P> <A NAME="modversion"></A> </P><P>This module implements Software Version (<A HREF="http://www.xmpp.org/extensions/xep-0092.html">XEP-0092</A>). Consequently, it answers <TT>ejabberd</TT>’s version when queried.</P><P>Options: </P><DL CLASS="description"><DT CLASS="dt-description"> @@ -2983,8 +3030,8 @@ The default value is <TT>true</TT>. </DD><DT CLASS="dt-description"><B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Software Version (<TT>jabber:iq:version</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="manage"></A> </P><!--TOC chapter Managing an <TT>ejabberd</TT> Server--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc60">Chapter 4</A>  <A HREF="#manage">Managing an <TT>ejabberd</TT> Server</A></H1><!--SEC END --><P> <A NAME="manage"></A> </P><P> <A NAME="ejabberdctl"></A> </P><!--TOC section <TT>ejabberdctl</TT>--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc61">4.1</A>  <A HREF="#ejabberdctl"><TT>ejabberdctl</TT></A></H2><!--SEC END --><P> <A NAME="ejabberdctl"></A> </P><P>With the <TT>ejabberdctl</TT> command line administration script +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc61">Chapter 4</A>  <A HREF="#manage">Managing an <TT>ejabberd</TT> Server</A></H1><!--SEC END --><P> <A NAME="manage"></A> </P><P> <A NAME="ejabberdctl"></A> </P><!--TOC section <TT>ejabberdctl</TT>--> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc62">4.1</A>  <A HREF="#ejabberdctl"><TT>ejabberdctl</TT></A></H2><!--SEC END --><P> <A NAME="ejabberdctl"></A> </P><P>With the <TT>ejabberdctl</TT> command line administration script you can execute <TT>ejabberdctl commands</TT> (described in the next section, <A HREF="#ectl-commands">4.1.1</A>) and also many general <TT>ejabberd commands</TT> (described in section <A HREF="#eja-commands">4.2</A>). This means you can start, stop and perform many other administrative tasks @@ -2996,7 +3043,7 @@ and other codes may be used for specific results. This can be used by other scripts to determine automatically if a command succeeded or failed, for example using: <TT>echo $?</TT></P><P> <A NAME="ectl-commands"></A> </P><!--TOC subsection ejabberdctl Commands--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc62">4.1.1</A>  <A HREF="#ectl-commands">ejabberdctl Commands</A></H3><!--SEC END --><P> <A NAME="ectl-commands"></A> </P><P>When <TT>ejabberdctl</TT> is executed without any parameter, +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc63">4.1.1</A>  <A HREF="#ectl-commands">ejabberdctl Commands</A></H3><!--SEC END --><P> <A NAME="ectl-commands"></A> </P><P>When <TT>ejabberdctl</TT> is executed without any parameter, it displays the available options. If there isn’t an <TT>ejabberd</TT> server running, the available parameters are: </P><DL CLASS="description"><DT CLASS="dt-description"> @@ -3032,7 +3079,7 @@ robot1 testuser1 testuser2 </PRE><P> <A NAME="erlangconfiguration"></A> </P><!--TOC subsection Erlang Runtime System--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc63">4.1.2</A>  <A HREF="#erlangconfiguration">Erlang Runtime System</A></H3><!--SEC END --><P> <A NAME="erlangconfiguration"></A> </P><P><TT>ejabberd</TT> is an Erlang/OTP application that runs inside an Erlang runtime system. +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc64">4.1.2</A>  <A HREF="#erlangconfiguration">Erlang Runtime System</A></H3><!--SEC END --><P> <A NAME="erlangconfiguration"></A> </P><P><TT>ejabberd</TT> is an Erlang/OTP application that runs inside an Erlang runtime system. This system is configured using environment variables and command line parameters. The <TT>ejabberdctl</TT> administration script uses many of those possibilities. You can configure some of them with the file <TT>ejabberdctl.cfg</TT>, @@ -3101,7 +3148,7 @@ Starts the Erlang system detached from the system console. </DD></DL><P> Note that some characters need to be escaped when used in shell scripts, for instance <CODE>"</CODE> and <CODE>{}</CODE>. You can find other options in the Erlang manual page (<TT>erl -man erl</TT>).</P><P> <A NAME="eja-commands"></A> </P><!--TOC section <TT>ejabberd</TT> Commands--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc64">4.2</A>  <A HREF="#eja-commands"><TT>ejabberd</TT> Commands</A></H2><!--SEC END --><P> <A NAME="eja-commands"></A> </P><P>An <TT>ejabberd command</TT> is an abstract function identified by a name, +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc65">4.2</A>  <A HREF="#eja-commands"><TT>ejabberd</TT> Commands</A></H2><!--SEC END --><P> <A NAME="eja-commands"></A> </P><P>An <TT>ejabberd command</TT> is an abstract function identified by a name, with a defined number and type of calling arguments and type of result that is registered in the <TT>ejabberd_commands</TT> service. Those commands can be defined in any Erlang module and executed using any valid frontend.</P><P><TT>ejabberd</TT> includes a frontend to execute <TT>ejabberd commands</TT>: the script <TT>ejabberdctl</TT>. @@ -3109,7 +3156,7 @@ Other known frontends that can be installed to execute ejabberd commands in diff <TT>ejabberd_xmlrpc</TT> (XML-RPC service), <TT>mod_rest</TT> (HTTP POST service), <TT>mod_shcommands</TT> (ejabberd WebAdmin page).</P><P> <A NAME="list-eja-commands"></A> </P><!--TOC subsection List of ejabberd Commands--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc65">4.2.1</A>  <A HREF="#list-eja-commands">List of ejabberd Commands</A></H3><!--SEC END --><P> <A NAME="list-eja-commands"></A> </P><P><TT>ejabberd</TT> includes a few ejabberd Commands by default. +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc66">4.2.1</A>  <A HREF="#list-eja-commands">List of ejabberd Commands</A></H3><!--SEC END --><P> <A NAME="list-eja-commands"></A> </P><P><TT>ejabberd</TT> includes a few ejabberd Commands by default. When more modules are installed, new commands may be available in the frontends.</P><P>The easiest way to get a list of the available commands, and get help for them is to use the ejabberdctl script: </P><PRE CLASS="verbatim">$ ejabberdctl help @@ -3149,7 +3196,7 @@ exist tutorials to <A HREF="http://www.ejabberd.im/migrate-to-ejabberd">migrate in offline storage. This might be useful when the number of offline messages is very high. </DD></DL><P> <A NAME="accesscommands"></A> </P><!--TOC subsection Restrict Execution with AccessCommands--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc66">4.2.2</A>  <A HREF="#accesscommands">Restrict Execution with AccessCommands</A></H3><!--SEC END --><P> <A NAME="accesscommands"></A> </P><P>The frontends can be configured to restrict access to certain commands. +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc67">4.2.2</A>  <A HREF="#accesscommands">Restrict Execution with AccessCommands</A></H3><!--SEC END --><P> <A NAME="accesscommands"></A> </P><P>The frontends can be configured to restrict access to certain commands. In that case, authentication information must be provided. In each frontend the <TT>AccessCommands</TT> option is defined in a different place. But in all cases the option syntax is the same: @@ -3195,7 +3242,7 @@ and the provided arguments do not contradict Arguments.</P><P>As an example to u {_bot_reg_test, [register, unregister], [{host, "test.org"}]} ] </PRE><P> <A NAME="webadmin"></A> </P><!--TOC section Web Admin--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc67">4.3</A>  <A HREF="#webadmin">Web Admin</A></H2><!--SEC END --><P> <A NAME="webadmin"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc68">4.3</A>  <A HREF="#webadmin">Web Admin</A></H2><!--SEC END --><P> <A NAME="webadmin"></A> </P><P>The <TT>ejabberd</TT> Web Admin allows to administer most of <TT>ejabberd</TT> using a web browser.</P><P>This feature is enabled by default: a <TT>ejabberd_http</TT> listener with the option <TT>web_admin</TT> (see section <A HREF="#listened">3.1.3</A>) is included in the listening ports. Then you can open @@ -3267,13 +3314,13 @@ The file is searched by default in The directory of the documentation can be specified in the environment variable <TT>EJABBERD_DOC_PATH</TT>. See section <A HREF="#erlangconfiguration">4.1.2</A>.</P><P> <A NAME="adhoccommands"></A> </P><!--TOC section Ad-hoc Commands--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc68">4.4</A>  <A HREF="#adhoccommands">Ad-hoc Commands</A></H2><!--SEC END --><P> <A NAME="adhoccommands"></A> </P><P>If you enable <TT>mod_configure</TT> and <TT>mod_adhoc</TT>, +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc69">4.4</A>  <A HREF="#adhoccommands">Ad-hoc Commands</A></H2><!--SEC END --><P> <A NAME="adhoccommands"></A> </P><P>If you enable <TT>mod_configure</TT> and <TT>mod_adhoc</TT>, you can perform several administrative tasks in <TT>ejabberd</TT> with a Jabber client. The client must support Ad-Hoc Commands (<A HREF="http://www.xmpp.org/extensions/xep-0050.html">XEP-0050</A>), and you must login in the Jabber server with an account with proper privileges.</P><P> <A NAME="changeerlangnodename"></A> </P><!--TOC section Change Computer Hostname--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc69">4.5</A>  <A HREF="#changeerlangnodename">Change Computer Hostname</A></H2><!--SEC END --><P> <A NAME="changeerlangnodename"></A> </P><P><TT>ejabberd</TT> uses the distributed Mnesia database. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc70">4.5</A>  <A HREF="#changeerlangnodename">Change Computer Hostname</A></H2><!--SEC END --><P> <A NAME="changeerlangnodename"></A> </P><P><TT>ejabberd</TT> uses the distributed Mnesia database. Being distributed, Mnesia enforces consistency of its file, so it stores the name of the Erlang node in it (see section <A HREF="#nodename">5.4</A>). The name of an Erlang node includes the hostname of the computer. @@ -3310,8 +3357,8 @@ mv /var/lib/ejabberd/*.* /var/lib/ejabberd/oldfiles/ </PRE></LI><LI CLASS="li-enumerate">Check that the information of the old database is available: accounts, rosters... After you finish, remember to delete the temporary backup files from public directories. </LI></OL><P> <A NAME="secure"></A> </P><!--TOC chapter Securing <TT>ejabberd</TT>--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc70">Chapter 5</A>  <A HREF="#secure">Securing <TT>ejabberd</TT></A></H1><!--SEC END --><P> <A NAME="secure"></A> </P><P> <A NAME="firewall"></A> </P><!--TOC section Firewall Settings--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc71">5.1</A>  <A HREF="#firewall">Firewall Settings</A></H2><!--SEC END --><P> <A NAME="firewall"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc71">Chapter 5</A>  <A HREF="#secure">Securing <TT>ejabberd</TT></A></H1><!--SEC END --><P> <A NAME="secure"></A> </P><P> <A NAME="firewall"></A> </P><!--TOC section Firewall Settings--> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc72">5.1</A>  <A HREF="#firewall">Firewall Settings</A></H2><!--SEC END --><P> <A NAME="firewall"></A> </P><P>You need to take the following TCP ports in mind when configuring your firewall: </P><BLOCKQUOTE CLASS="table"><DIV CLASS="center"><DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV> <TABLE BORDER=1 CELLSPACING=0 CELLPADDING=1><TR><TD ALIGN=left NOWRAP><B>Port</B></TD><TD ALIGN=left NOWRAP><B>Description</B></TD></TR> @@ -3322,7 +3369,7 @@ After you finish, remember to delete the temporary backup files from public dire <TR><TD ALIGN=left NOWRAP>port range</TD><TD ALIGN=left NOWRAP>Used for connections between Erlang nodes. This range is configurable (see section <A HREF="#epmd">5.2</A>).</TD></TR> </TABLE> <DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV></DIV></BLOCKQUOTE><P> <A NAME="epmd"></A> </P><!--TOC section epmd--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc72">5.2</A>  <A HREF="#epmd">epmd</A></H2><!--SEC END --><P> <A NAME="epmd"></A> </P><P><A HREF="http://www.erlang.org/doc/man/epmd.html">epmd (Erlang Port Mapper Daemon)</A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc73">5.2</A>  <A HREF="#epmd">epmd</A></H2><!--SEC END --><P> <A NAME="epmd"></A> </P><P><A HREF="http://www.erlang.org/doc/man/epmd.html">epmd (Erlang Port Mapper Daemon)</A> is a small name server included in Erlang/OTP and used by Erlang programs when establishing distributed Erlang communications. <TT>ejabberd</TT> needs <TT>epmd</TT> to use <TT>ejabberdctl</TT> and also when clustering <TT>ejabberd</TT> nodes. @@ -3347,7 +3394,7 @@ but can be configured in the file <TT>ejabberdctl.cfg</TT>. The Erlang command-line parameter used internally is, for example: </P><PRE CLASS="verbatim">erl ... -kernel inet_dist_listen_min 4370 inet_dist_listen_max 4375 </PRE><P> <A NAME="cookie"></A> </P><!--TOC section Erlang Cookie--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc73">5.3</A>  <A HREF="#cookie">Erlang Cookie</A></H2><!--SEC END --><P> <A NAME="cookie"></A> </P><P>The Erlang cookie is a string with numbers and letters. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc74">5.3</A>  <A HREF="#cookie">Erlang Cookie</A></H2><!--SEC END --><P> <A NAME="cookie"></A> </P><P>The Erlang cookie is a string with numbers and letters. An Erlang node reads the cookie at startup from the command-line parameter <TT>-setcookie</TT>. If not indicated, the cookie is read from the cookie file <TT>$HOME/.erlang.cookie</TT>. If this file does not exist, it is created immediately with a random cookie. @@ -3361,7 +3408,7 @@ to prevent unauthorized access or intrusion to an Erlang node. The communication between Erlang nodes are not encrypted, so the cookie could be read sniffing the traffic on the network. The recommended way to secure the Erlang node is to block the port 4369.</P><P> <A NAME="nodename"></A> </P><!--TOC section Erlang Node Name--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc74">5.4</A>  <A HREF="#nodename">Erlang Node Name</A></H2><!--SEC END --><P> <A NAME="nodename"></A> </P><P>An Erlang node may have a node name. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc75">5.4</A>  <A HREF="#nodename">Erlang Node Name</A></H2><!--SEC END --><P> <A NAME="nodename"></A> </P><P>An Erlang node may have a node name. The name can be short (if indicated with the command-line parameter <TT>-sname</TT>) or long (if indicated with the parameter <TT>-name</TT>). Starting an Erlang node with -sname limits the communication between Erlang nodes to the LAN.</P><P>Using the option <TT>-sname</TT> instead of <TT>-name</TT> is a simple method @@ -3370,7 +3417,7 @@ However, it is not ultimately effective to prevent access to the Erlang node, because it may be possible to fake the fact that you are on another network using a modified version of Erlang <TT>epmd</TT>. The recommended way to secure the Erlang node is to block the port 4369.</P><P> <A NAME="secure-files"></A> </P><!--TOC section Securing Sensible Files--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc75">5.5</A>  <A HREF="#secure-files">Securing Sensible Files</A></H2><!--SEC END --><P> <A NAME="secure-files"></A> </P><P><TT>ejabberd</TT> stores sensible data in the file system either in plain text or binary files. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc76">5.5</A>  <A HREF="#secure-files">Securing Sensible Files</A></H2><!--SEC END --><P> <A NAME="secure-files"></A> </P><P><TT>ejabberd</TT> stores sensible data in the file system either in plain text or binary files. The file system permissions should be set to only allow the proper user to read, write and execute those files and directories.</P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>ejabberd configuration file: /etc/ejabberd/ejabberd.cfg</TT></B></DT><DD CLASS="dd-description"> @@ -3390,9 +3437,9 @@ so it is preferable to secure the whole <TT>/var/lib/ejabberd/</TT> directory. </DD><DT CLASS="dt-description"><B><TT>Erlang cookie file: /var/lib/ejabberd/.erlang.cookie</TT></B></DT><DD CLASS="dd-description"> See section <A HREF="#cookie">5.3</A>. </DD></DL><P> <A NAME="clustering"></A> </P><!--TOC chapter Clustering--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc76">Chapter 6</A>  <A HREF="#clustering">Clustering</A></H1><!--SEC END --><P> <A NAME="clustering"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc77">Chapter 6</A>  <A HREF="#clustering">Clustering</A></H1><!--SEC END --><P> <A NAME="clustering"></A> </P><P> <A NAME="howitworks"></A> </P><!--TOC section How it Works--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc77">6.1</A>  <A HREF="#howitworks">How it Works</A></H2><!--SEC END --><P> <A NAME="howitworks"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc78">6.1</A>  <A HREF="#howitworks">How it Works</A></H2><!--SEC END --><P> <A NAME="howitworks"></A> </P><P>A Jabber domain is served by one or more <TT>ejabberd</TT> nodes. These nodes can be run on different machines that are connected via a network. They all must have the ability to connect to port 4369 of all another nodes, and must @@ -3406,29 +3453,29 @@ router, </LI><LI CLASS="li-itemize">session manager, </LI><LI CLASS="li-itemize">s2s manager. </LI></UL><P> <A NAME="router"></A> </P><!--TOC subsection Router--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc78">6.1.1</A>  <A HREF="#router">Router</A></H3><!--SEC END --><P> <A NAME="router"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc79">6.1.1</A>  <A HREF="#router">Router</A></H3><!--SEC END --><P> <A NAME="router"></A> </P><P>This module is the main router of Jabber packets on each node. It routes them based on their destination’s domains. It uses a global routing table. The domain of the packet’s destination is searched in the routing table, and if it is found, the packet is routed to the appropriate process. If not, it is sent to the s2s manager.</P><P> <A NAME="localrouter"></A> </P><!--TOC subsection Local Router--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc79">6.1.2</A>  <A HREF="#localrouter">Local Router</A></H3><!--SEC END --><P> <A NAME="localrouter"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc80">6.1.2</A>  <A HREF="#localrouter">Local Router</A></H3><!--SEC END --><P> <A NAME="localrouter"></A> </P><P>This module routes packets which have a destination domain equal to one of this server’s host names. If the destination JID has a non-empty user part, it is routed to the session manager, otherwise it is processed depending on its content.</P><P> <A NAME="sessionmanager"></A> </P><!--TOC subsection Session Manager--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc80">6.1.3</A>  <A HREF="#sessionmanager">Session Manager</A></H3><!--SEC END --><P> <A NAME="sessionmanager"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc81">6.1.3</A>  <A HREF="#sessionmanager">Session Manager</A></H3><!--SEC END --><P> <A NAME="sessionmanager"></A> </P><P>This module routes packets to local users. It looks up to which user resource a packet must be sent via a presence table. Then the packet is either routed to the appropriate c2s process, or stored in offline storage, or bounced back.</P><P> <A NAME="s2smanager"></A> </P><!--TOC subsection s2s Manager--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc81">6.1.4</A>  <A HREF="#s2smanager">s2s Manager</A></H3><!--SEC END --><P> <A NAME="s2smanager"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc82">6.1.4</A>  <A HREF="#s2smanager">s2s Manager</A></H3><!--SEC END --><P> <A NAME="s2smanager"></A> </P><P>This module routes packets to other Jabber servers. First, it checks if an opened s2s connection from the domain of the packet’s source to the domain of the packet’s destination exists. If that is the case, the s2s manager routes the packet to the process serving this connection, otherwise a new connection is opened.</P><P> <A NAME="cluster"></A> </P><!--TOC section Clustering Setup--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc82">6.2</A>  <A HREF="#cluster">Clustering Setup</A></H2><!--SEC END --><P> <A NAME="cluster"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc83">6.2</A>  <A HREF="#cluster">Clustering Setup</A></H2><!--SEC END --><P> <A NAME="cluster"></A> </P><P>Suppose you already configured <TT>ejabberd</TT> on one machine named (<TT>first</TT>), and you need to setup another one to make an <TT>ejabberd</TT> cluster. Then do following steps:</P><OL CLASS="enumerate" type=1><LI CLASS="li-enumerate"> @@ -3466,10 +3513,10 @@ and ‘<CODE>access</CODE>’ options because they will be taken from enabled only on one machine in the cluster. </LI></OL><P>You can repeat these steps for other machines supposed to serve this domain.</P><P> <A NAME="servicelb"></A> </P><!--TOC section Service Load-Balancing--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc83">6.3</A>  <A HREF="#servicelb">Service Load-Balancing</A></H2><!--SEC END --><P> <A NAME="servicelb"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc84">6.3</A>  <A HREF="#servicelb">Service Load-Balancing</A></H2><!--SEC END --><P> <A NAME="servicelb"></A> </P><P> <A NAME="componentlb"></A> </P><!--TOC subsection Components Load-Balancing--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc84">6.3.1</A>  <A HREF="#componentlb">Components Load-Balancing</A></H3><!--SEC END --><P> <A NAME="componentlb"></A> </P><P> <A NAME="domainlb"></A> </P><!--TOC subsection Domain Load-Balancing Algorithm--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc85">6.3.2</A>  <A HREF="#domainlb">Domain Load-Balancing Algorithm</A></H3><!--SEC END --><P> <A NAME="domainlb"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc85">6.3.1</A>  <A HREF="#componentlb">Components Load-Balancing</A></H3><!--SEC END --><P> <A NAME="componentlb"></A> </P><P> <A NAME="domainlb"></A> </P><!--TOC subsection Domain Load-Balancing Algorithm--> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc86">6.3.2</A>  <A HREF="#domainlb">Domain Load-Balancing Algorithm</A></H3><!--SEC END --><P> <A NAME="domainlb"></A> </P><P><TT>ejabberd</TT> includes an algorithm to load balance the components that are plugged on an <TT>ejabberd</TT> cluster. It means that you can plug one or several instances of the same component on each <TT>ejabberd</TT> cluster and that the traffic will be automatically distributed.</P><P>The default distribution algorithm try to deliver to a local instance of a component. If several local instances are available, one instance is chosen randomly. If no instance is available locally, one instance is chosen randomly among the remote component instances.</P><P>If you need a different behaviour, you can change the load balancing behaviour with the option <TT>domain_balancing</TT>. The syntax of the option is the following:</P><PRE CLASS="verbatim">{domain_balancing, "component.example.com", <balancing_criterium>}. </PRE><P>Several balancing criteria are available: </P><UL CLASS="itemize"><LI CLASS="li-itemize"> @@ -3478,13 +3525,13 @@ domain.</P><P> <A NAME="servicelb"></A> </P><!--TOC section Service Load-Balanci </LI><LI CLASS="li-itemize"><TT>bare_destination</TT>: the bare JID (without resource) of the packet <TT>to</TT> attribute is used. </LI><LI CLASS="li-itemize"><TT>bare_source</TT>: the bare JID (without resource) of the packet <TT>from</TT> attribute is used. </LI></UL><P>If the value corresponding to the criteria is the same, the same component instance in the cluster will be used.</P><P> <A NAME="lbbuckets"></A> </P><!--TOC subsection Load-Balancing Buckets--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc86">6.3.3</A>  <A HREF="#lbbuckets">Load-Balancing Buckets</A></H3><!--SEC END --><P> <A NAME="lbbuckets"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc87">6.3.3</A>  <A HREF="#lbbuckets">Load-Balancing Buckets</A></H3><!--SEC END --><P> <A NAME="lbbuckets"></A> </P><P>When there is a risk of failure for a given component, domain balancing can cause service trouble. If one component is failing the service will not work correctly unless the sessions are rebalanced.</P><P>In this case, it is best to limit the problem to the sessions handled by the failing component. This is what the <TT>domain_balancing_component_number</TT> option does, making the load balancing algorithm not dynamic, but sticky on a fix number of component instances.</P><P>The syntax is the following: </P><PRE CLASS="verbatim">{domain_balancing_component_number, "component.example.com", N} </PRE><P> <A NAME="debugging"></A> </P><!--TOC chapter Debugging--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc87">Chapter 7</A>  <A HREF="#debugging">Debugging</A></H1><!--SEC END --><P> <A NAME="debugging"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc88">Chapter 7</A>  <A HREF="#debugging">Debugging</A></H1><!--SEC END --><P> <A NAME="debugging"></A> </P><P> <A NAME="logfiles"></A> </P><!--TOC section Log Files--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc88">7.1</A>  <A HREF="#logfiles">Log Files</A></H2><!--SEC END --><P> <A NAME="logfiles"></A> </P><P>An <TT>ejabberd</TT> node writes two log files: +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc89">7.1</A>  <A HREF="#logfiles">Log Files</A></H2><!--SEC END --><P> <A NAME="logfiles"></A> </P><P>An <TT>ejabberd</TT> node writes two log files: </P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>ejabberd.log</TT></B></DT><DD CLASS="dd-description"> is the ejabberd service log, with the messages reported by <TT>ejabberd</TT> code </DD><DT CLASS="dt-description"><B><TT>sasl.log</TT></B></DT><DD CLASS="dd-description"> is the Erlang/OTP system log, with the messages reported by Erlang/OTP using SASL (System Architecture Support Libraries) @@ -3506,12 +3553,12 @@ The ejabberdctl command <TT>reopen-log</TT> (please refer to section <A HREF="#ectl-commands">4.1.1</A>) reopens the log files, and also renames the old ones if you didn’t rename them.</P><P> <A NAME="debugconsole"></A> </P><!--TOC section Debug Console--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc89">7.2</A>  <A HREF="#debugconsole">Debug Console</A></H2><!--SEC END --><P> <A NAME="debugconsole"></A> </P><P>The Debug Console is an Erlang shell attached to an already running <TT>ejabberd</TT> server. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc90">7.2</A>  <A HREF="#debugconsole">Debug Console</A></H2><!--SEC END --><P> <A NAME="debugconsole"></A> </P><P>The Debug Console is an Erlang shell attached to an already running <TT>ejabberd</TT> server. With this Erlang shell, an experienced administrator can perform complex tasks.</P><P>This shell gives complete control over the <TT>ejabberd</TT> server, so it is important to use it with extremely care. There are some simple and safe examples in the article <A HREF="http://www.ejabberd.im/interconnect-erl-nodes">Interconnecting Erlang Nodes</A></P><P>To exit the shell, close the window or press the keys: control+c control+c.</P><P> <A NAME="watchdog"></A> </P><!--TOC section Watchdog Alerts--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc90">7.3</A>  <A HREF="#watchdog">Watchdog Alerts</A></H2><!--SEC END --><P> <A NAME="watchdog"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc91">7.3</A>  <A HREF="#watchdog">Watchdog Alerts</A></H2><!--SEC END --><P> <A NAME="watchdog"></A> </P><P><TT>ejabberd</TT> includes a watchdog mechanism that may be useful to developers when troubleshooting a problem related to memory usage. If a process in the <TT>ejabberd</TT> server consumes more memory than the configured threshold, @@ -3529,7 +3576,7 @@ or in a conversation with the watchdog alert bot.</P><P>Example configuration: To remove all watchdog admins, set the option with an empty list: </P><PRE CLASS="verbatim">{watchdog_admins, []}. </PRE><P> <A NAME="i18ni10n"></A> </P><!--TOC chapter Internationalization and Localization--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc91">Appendix A</A>  <A HREF="#i18ni10n">Internationalization and Localization</A></H1><!--SEC END --><P> <A NAME="i18ni10n"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc92">Appendix A</A>  <A HREF="#i18ni10n">Internationalization and Localization</A></H1><!--SEC END --><P> <A NAME="i18ni10n"></A> </P><P>The source code of <TT>ejabberd</TT> supports localization. The translators can edit the <A HREF="http://www.gnu.org/software/gettext/">gettext</A> .po files @@ -3564,9 +3611,9 @@ HTTP header ‘Accept-Language: ru’</TD></TR> </TABLE></DIV> <A NAME="fig:webadmmainru"></A> <DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV></DIV></BLOCKQUOTE><P> <A NAME="releasenotes"></A> </P><!--TOC chapter Release Notes--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc92">Appendix B</A>  <A HREF="#releasenotes">Release Notes</A></H1><!--SEC END --><P> <A NAME="releasenotes"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc93">Appendix B</A>  <A HREF="#releasenotes">Release Notes</A></H1><!--SEC END --><P> <A NAME="releasenotes"></A> </P><P>Release notes are available from <A HREF="http://www.process-one.net/en/ejabberd/release_notes/">ejabberd Home Page</A></P><P> <A NAME="acknowledgements"></A> </P><!--TOC chapter Acknowledgements--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc93">Appendix C</A>  <A HREF="#acknowledgements">Acknowledgements</A></H1><!--SEC END --><P> <A NAME="acknowledgements"></A> </P><P>Thanks to all people who contributed to this guide: +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc94">Appendix C</A>  <A HREF="#acknowledgements">Acknowledgements</A></H1><!--SEC END --><P> <A NAME="acknowledgements"></A> </P><P>Thanks to all people who contributed to this guide: </P><UL CLASS="itemize"><LI CLASS="li-itemize"> Alexey Shchepin (<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A>) </LI><LI CLASS="li-itemize">Badlop (<A HREF="xmpp:badlop@jabberes.org"><TT>xmpp:badlop@jabberes.org</TT></A>) @@ -3578,7 +3625,7 @@ Alexey Shchepin (<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT </LI><LI CLASS="li-itemize">Sergei Golovan (<A HREF="xmpp:sgolovan@nes.ru"><TT>xmpp:sgolovan@nes.ru</TT></A>) </LI><LI CLASS="li-itemize">Vsevolod Pelipas (<A HREF="xmpp:vsevoload@jabber.ru"><TT>xmpp:vsevoload@jabber.ru</TT></A>) </LI></UL><P> <A NAME="copyright"></A> </P><!--TOC chapter Copyright Information--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc94">Appendix D</A>  <A HREF="#copyright">Copyright Information</A></H1><!--SEC END --><P> <A NAME="copyright"></A> </P><P>Ejabberd Installation and Operation Guide.<BR> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc95">Appendix D</A>  <A HREF="#copyright">Copyright Information</A></H1><!--SEC END --><P> <A NAME="copyright"></A> </P><P>Ejabberd Installation and Operation Guide.<BR> Copyright © 2003 — 2009 ProcessOne</P><P>This document 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 diff --git a/doc/guide.tex b/doc/guide.tex index 3901db633..e613106dd 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -68,6 +68,7 @@ \newcommand{\modconfigure}{\module{mod\_configure}} \newcommand{\moddisco}{\module{mod\_disco}} \newcommand{\modecho}{\module{mod\_echo}} +\newcommand{\modhttpfileserver}{\module{mod\_http\_fileserver}} \newcommand{\modlast}{\module{mod\_last}} \newcommand{\modlastodbc}{\module{mod\_last\_odbc}} \newcommand{\modmuc}{\module{mod\_muc}} @@ -96,8 +97,6 @@ \usepackage{ifthen} \newboolean{modhttpbind} \newcommand{\modhttpbind}{\module{mod\_http\_bind}} -\newboolean{modhttpfileserver} -\newcommand{\modhttpfileserver}{\module{mod\_http\_fileserver}} \include{contributed_modules} %% Common options @@ -2650,7 +2649,61 @@ Example: Mirror, mirror, on the wall, who is the most beautiful \ifthenelse{\boolean{modhttpbind}}{\input{mod_http_bind.tex}}{} -\ifthenelse{\boolean{modhttpfileserver}}{\input{mod_http_fileserver.tex}}{} +\makesubsection{modhttpfileserver}{\modhttpfileserver{}} +\ind{modules!\modhttpfileserver{}}\ind{modhttpfileserver} + +This simple module serves files from the local disk over HTTP. + +Options: +\begin{description} + \titem{docroot} \ind{options!docroot} + Directory to serve the files. + \titem{accesslog} \ind{options!accesslog} + File to log accesses using an Apache-like format. + No log will be recorded if this option is not specified. + \titem{directory\_indices} \ind{options!directoryindices} + Indicate one or more directory index files, similarly to Apache's + DirectoryIndex variable. When a web request hits a directory + instead of a regular file, those directory indices are looked in + order, and the first one found is returned. +\end{description} + +This example configuration will serve the files from +the local directory \verb|/var/www| +in the address \verb|http://example.org:5280/pub/archive/|. +To use this module you must enable it: +\begin{verbatim} +{modules, + [ + ... + {mod_http_fileserver, [ + {docroot, "/var/www"}, + {directory_indices, ["index.html", "main.htm"]}, + {accesslog, "/var/log/ejabberd/access.log"} + ] + }, + ... +]}. +\end{verbatim} +And define it as a handler in the HTTP service: +\begin{verbatim} +{listen, + [ + ... + {5280, ejabberd_http, [ + ... + {request_handlers, [ + ... + {["pub", "archive"], mod_http_fileserver}, + ... + ] + }, + ... + ] + }, + ... +]}. +\end{verbatim} \makesubsection{modlast}{\modlast{}} \ind{modules!\modlast{}}\ind{protocols!XEP-0012: Last Activity} diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index 4b16b89b5..8be6b1316 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -150,8 +150,12 @@ %% ]}, {5280, ejabberd_http, [ - captcha, - http_poll, + %%{request_handlers, + %% [ + %% {["pub", "archive"], mod_http_fileserver}, + %% ]}, + captcha, + http_poll, web_admin ]} @@ -474,6 +478,10 @@ {mod_configure,[]}, % requires mod_adhoc {mod_disco, []}, %%{mod_echo, [{host, "echo.localhost"}]}, + %%{mod_http_fileserver, [ + %% {docroot, "/var/www"}, + %% {accesslog, "/var/log/ejabberd/access.log"} + %% ]}, {mod_last, []}, {mod_muc, [ %%{host, "conference.@HOST@"}, From dd8e4c620bcb15e2bbe9f9a3133982431f851627 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:23:40 +0000 Subject: [PATCH 376/582] Initial commit of HTTP-Bind source code (thanks to Stefan Striegler) SVN Revision: 2261 --- src/web/ejabberd_http_bind.erl | 804 +++++++++++++++++++++++++++++++++ src/web/mod_http_bind.erl | 102 +++++ 2 files changed, 906 insertions(+) create mode 100644 src/web/ejabberd_http_bind.erl create mode 100644 src/web/mod_http_bind.erl diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl new file mode 100644 index 000000000..d462e0a0d --- /dev/null +++ b/src/web/ejabberd_http_bind.erl @@ -0,0 +1,804 @@ +%%%---------------------------------------------------------------------- +%%% File : ejabberd_http_bind.erl +%%% Author : Stefan Strigler <steve@zeank.in-berlin.de> +%%% Purpose : HTTP Binding support (JEP-0124) +%%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> +%%% Id : $Id: $ +%%%---------------------------------------------------------------------- + +-module(ejabberd_http_bind). +-author('steve@zeank.in-berlin.de'). +-vsn('Revision: 1.4'). + +-behaviour(gen_fsm). + +%% External exports +-export([start_link/2, + init/1, + handle_event/3, + handle_sync_event/4, + code_change/4, + handle_info/3, + terminate/3, + send/2, + setopts/2, + controlling_process/2, + close/1, + process_request/1]). + +%%-define(ejabberd_debug, true). + +-include("ejabberd.hrl"). +-include("jlib.hrl"). +-include("ejabberd_http.hrl"). + +-record(http_bind, {id, pid, to, hold, wait}). + +%% http binding request +-record(hbr, {rid, + key, + in, + out}). + +-record(state, {id, + rid = error, + key, + output = "", + input = "", + waiting_input = false, + last_receiver, + last_poll, + ctime = 0, + timer, + req_list = [] % list of requests + }). + + +%-define(DBGFSM, true). + +-ifdef(DBGFSM). +-define(FSMOPTS, [{debug, [trace]}]). +-else. +-define(FSMOPTS, []). +-endif. + +-define(MAX_REQUESTS, 2). % number of simultaneous requests +-define(MIN_POLLING, "2"). % don't poll faster than that or we will shoot you +-define(MAX_WAIT, 60). % max num of secs to keep a request on hold +-define(MAX_INACTIVITY, 30000). % msecs to wait before terminating idle sessions +-define(CT, {"Content-Type", "text/xml; charset=utf-8"}). +-define(BAD_REQUEST, ?CT). + + +%%%---------------------------------------------------------------------- +%%% API +%%%---------------------------------------------------------------------- +start(ID, Key) -> + mnesia:create_table(http_bind, + [{ram_copies, [node()]}, + {attributes, record_info(fields, http_bind)}]), + supervisor:start_child(ejabberd_http_bind_sup, [ID, Key]). + +start_link(ID, Key) -> + gen_fsm:start_link(?MODULE, [ID, Key], ?FSMOPTS). + +send({http_bind, FsmRef}, Packet) -> + gen_fsm:sync_send_all_state_event(FsmRef, {send, Packet}). + +setopts({http_bind, FsmRef}, Opts) -> + case lists:member({active, once}, Opts) of + true -> + gen_fsm:sync_send_all_state_event(FsmRef, activate); + _ -> + ok + end. + +controlling_process(_Socket, _Pid) -> + ok. + +close({http_bind, FsmRef}) -> + catch gen_fsm:sync_send_all_state_event(FsmRef, close). + + +process_request(#request{path = [], + data = Data}) -> + case catch parse_request(Data) of + {ok, ID1, RID, Key, NewKey, Attrs, Packet} -> + XmppDomain = xml:get_attr_s("to",Attrs), + if + (ID1 == "") and (XmppDomain == "") -> + {200, [?CT], "<body type='terminate' " + "condition='improper-addressing' " + "xmlns='http://jabber.org/protocol/httpbind'/>"}; + true -> + ID = if + (ID1 == "") -> + %% create new session + NewID = sha:sha(term_to_binary({now(), make_ref()})), + {ok, Pid} = start(NewID, Key), + Wait = case + string:to_integer(xml:get_attr_s("wait",Attrs)) + of + {error, _} -> + ?MAX_WAIT; + {CWait, _} -> + if + (CWait > ?MAX_WAIT) -> + ?MAX_WAIT; + true -> + CWait + end + end, + Hold = case + string:to_integer( + xml:get_attr_s("hold",Attrs)) + of + {error, _} -> + (?MAX_REQUESTS - 1); + {CHold, _} -> + if + (CHold > (?MAX_REQUESTS - 1)) -> + (?MAX_REQUESTS - 1); + true -> + CHold + end + end, + mnesia:transaction( + fun() -> + mnesia:write(#http_bind{id = NewID, + pid = Pid, + to = XmppDomain, + wait = Wait, + hold = Hold}) + end), + StreamStart = if + (XmppDomain /= "") -> + true; + true -> + false + end, + InPacket = Packet, + NewID; + true -> + %% old session + Type = xml:get_attr_s("type",Attrs), + StreamStart = + case xml:get_attr_s("xmpp:restart",Attrs) of + "true" -> + true; + _ -> + false + end, + Wait = ?MAX_WAIT, + Hold = (?MAX_REQUESTS - 1), + if + (Type == "terminate") -> + %% terminate session + InPacket = Packet ++ "</stream:stream>"; + true -> + InPacket = Packet + end, + ID1 + end, +%% ?DEBUG("~n InPacket: ~s ~n", [InPacket]), + case http_put(ID, RID, Key, NewKey, Hold, InPacket, StreamStart) of + {error, not_exists} -> + ?DEBUG("no session associated with sid: ~p", [ID]), + {404, [?BAD_REQUEST], ""}; + {error, bad_key} -> + ?DEBUG("bad key: ~s", [Key]), + case mnesia:dirty_read({http_bind, ID}) of + [] -> + {404, [?BAD_REQUEST], ""}; + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop), + {404, [?BAD_REQUEST], ""} + end; + {error, polling_too_frequently} -> + ?DEBUG("polling too frequently: ~p", [ID]), + case mnesia:dirty_read({http_bind, ID}) of + [] -> %% unlikely! (?) + {404, [?BAD_REQUEST], ""}; + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop), + {403, [?BAD_REQUEST], ""} + end; + {repeat, OutPacket} -> + ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", + [OutPacket]), + send_outpacket(ID, OutPacket); + ok -> + receive_loop(ID,ID1,RID,Wait,Hold,Attrs) + end + end; + _ -> + {400, [?BAD_REQUEST], ""} + end; +process_request(_Request) -> + {400, [], {xmlelement, "h1", [], + [{xmlcdata, "400 Bad Request"}]}}. + +receive_loop(ID,ID1,RID,Wait,Hold,Attrs) -> + receive + after 100 -> ok + end, + prepare_response(ID,ID1,RID,Wait,Hold,Attrs). + +prepare_response(ID,ID1,RID,Wait,Hold,Attrs) -> + case http_get(ID,RID) of + {error, not_exists} -> + ?DEBUG("no session associated with sid: ~s", ID), + {404, [?BAD_REQUEST], ""}; + {ok, keep_on_hold} -> + receive_loop(ID,ID1,RID,Wait,Hold,Attrs); + {ok, cancel} -> + %% actually it would be better if we could completely + %% cancel this request, but then we would have to hack + %% ejabberd_http and I'm too lazy now + {404, [?BAD_REQUEST], ""}; + {ok, OutPacket} -> + ?DEBUG("OutPacket: ~s", [OutPacket]), + if + ID == ID1 -> + send_outpacket(ID, OutPacket); + true -> + To = xml:get_attr_s("to",Attrs), + OutEls = case xml_stream:parse_element( + OutPacket++"</stream:stream>") of + El when element(1, El) == xmlelement -> + {xmlelement, _, OutAttrs, Els} = El, + AuthID = xml:get_attr_s("id", OutAttrs), + StreamError = false, + case Els of + [] -> + []; + [{xmlelement, "stream:features", StreamAttribs, StreamEls} | StreamTail] -> + [{xmlelement, "stream:features", [{"xmlns:stream","http://etherx.jabber.org/streams"}] ++ StreamAttribs, StreamEls}] ++ StreamTail; + Xml -> + Xml + end; + {error, _} -> + AuthID = "", + StreamError = true, + [] + end, + if + To == "" -> + {200, [?CT], "<body type='terminate' " + "condition='improper-addressing' " + "xmlns='http://jabber.org/protocol/httpbind'/>"}; + StreamError == true -> + {200, [?CT], "<body type='terminate' " + "condition='host-unknown' " + "xmlns='http://jabber.org/protocol/httpbind'/>"}; + true -> + {200, [?CT], + xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + "http://jabber.org/protocol/httpbind"}, + {"sid",ID}, + {"wait", integer_to_list(Wait)}, + {"requests", integer_to_list(Hold+1)}, + {"inactivity", + integer_to_list(trunc(?MAX_INACTIVITY/1000))}, + {"polling", ?MIN_POLLING}, + {"authid", AuthID} + ],OutEls})} + end + end + end. + +send_outpacket(ID, OutPacket) -> + case OutPacket of + "" -> + {200, [?CT], "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; + "</stream:stream>" -> + case mnesia:dirty_read({http_bind, ID}) of + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop) + end, + {200, [?CT], "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; + _ -> + case xml_stream:parse_element("<body>" + ++ OutPacket + ++ "</body>") + of + El when element(1, El) == xmlelement -> + {xmlelement, _, _, OEls} = El, + TypedEls = [xml:replace_tag_attr("xmlns", + "jabber:client",OEl) || + OEl <- OEls], + ?DEBUG(" --- outgoing data --- ~n~s~n --- END --- ~n", + [xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + "http://jabber.org/protocol/httpbind"}], + TypedEls})] + ), + {200, [?CT], + xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + "http://jabber.org/protocol/httpbind"}], + TypedEls})}; + {error, _E} -> + OutEls = case xml_stream:parse_element( + OutPacket++"</stream:stream>") of + SEl when element(1, SEl) == xmlelement -> + {xmlelement, _, _OutAttrs, SEls} = SEl, + StreamError = false, + case SEls of + [] -> + []; + [{xmlelement, "stream:features", StreamAttribs, StreamEls} | StreamTail] -> + TypedTail = [xml:replace_tag_attr("xmlns", + "jabber:client",OEl) || + OEl <- StreamTail], + [{xmlelement, "stream:features", [{"xmlns:stream","http://etherx.jabber.org/streams"}] ++ StreamAttribs, StreamEls}] ++ TypedTail; + Xml -> + Xml + end; + {error, _} -> + StreamError = true, + [] + end, + if + StreamError -> + StreamErrCond = case xml_stream:parse_element( + "<stream:stream>"++OutPacket) of + El when element(1, El) == xmlelement -> + {xmlelement, _Tag, _Attr, Els} = El, + [{xmlelement, SE, _, Cond} | _] = Els, + if + SE == "stream:error" -> + Cond; + true -> + null + end; + {error, _E} -> + null + end, + case mnesia:dirty_read({http_bind, ID}) of + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop); + _ -> + err %% hu? + end, + case StreamErrCond of + null -> + {200, [?CT], + "<body type='terminate' " + "condition='internal-server-error' " + "xmlns='http://jabber.org/protocol/httpbind'/>"}; + _ -> + {200, [?CT], + "<body type='terminate' " + "condition='remote-stream-error' " + "xmlns='http://jabber.org/protocol/httpbind'>" ++ + elements_to_string(StreamErrCond) ++ + "</body>"} + end; + true -> + {200, [?CT], + xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + "http://jabber.org/protocol/httpbind"}], + OutEls})} + end + end + end. + +%%%---------------------------------------------------------------------- +%%% Callback functions from gen_fsm +%%%---------------------------------------------------------------------- + +%%---------------------------------------------------------------------- +%% Func: init/1 +%% Returns: {ok, StateName, StateData} | +%% {ok, StateName, StateData, Timeout} | +%% ignore | +%% {stop, StopReason} +%%---------------------------------------------------------------------- +init([ID, Key]) -> + ?INFO_MSG("started: ~p", [{ID, Key}]), + Opts = [], % TODO + {ok, C2SPid} = ejabberd_c2s:start({?MODULE, {http_bind, self()}}, Opts), + ejabberd_c2s:become_controller(C2SPid), + Timer = erlang:start_timer(?MAX_INACTIVITY, self(), []), + {ok, loop, #state{id = ID, + key = Key, + timer = Timer}}. + +%%---------------------------------------------------------------------- +%% Func: StateName/2 +%% Returns: {next_state, NextStateName, NextStateData} | +%% {next_state, NextStateName, NextStateData, Timeout} | +%% {stop, Reason, NewStateData} +%%---------------------------------------------------------------------- + + +%%---------------------------------------------------------------------- +%% 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) -> + {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, Packet}, _From, StateName, StateData) -> + Output = [StateData#state.output | Packet], + Reply = ok, + {reply, Reply, StateName, StateData#state{output = Output}}; + +handle_sync_event(activate, From, StateName, StateData) -> + case StateData#state.input of + "" -> + {reply, ok, StateName, StateData#state{ + waiting_input = From}}; + Input -> + From ! {tcp, {http_bind, self()}, list_to_binary(Input)}, + {reply, ok, StateName, StateData#state{ + input = "", + waiting_input = false, + last_receiver = From}} + end; + +handle_sync_event(stop, _From, _StateName, StateData) -> + Reply = ok, + {stop, normal, Reply, StateData}; + +handle_sync_event({http_put, RID, Key, NewKey, Hold, Packet, StartTo}, + _From, StateName, StateData) -> + %% check if RID valid + RidAllow = case RID of + error -> + false; + _ -> + case StateData#state.rid of + error -> + %% first request - nothing saved so far + true; + OldRID -> + ?DEBUG("state.rid/cur rid: ~p/~p", + [OldRID, RID]), + if + (OldRID < RID) and + (RID =< (OldRID + Hold + 1)) -> + true; + (RID =< OldRID) and + (RID > OldRID - Hold - 1) -> + repeat; + true -> + false + end + end + end, + %% check if key valid + KeyAllow = case RidAllow of + repeat -> + true; + false -> + false; + true -> + case StateData#state.key of + "" -> + true; + OldKey -> + NextKey = httpd_util:to_lower( + hex(binary_to_list( + crypto:sha(Key)))), + ?DEBUG("Key/OldKey/NextKey: ~s/~s/~s", + [Key, OldKey, NextKey]), + if + OldKey == NextKey -> + true; + true -> + ?DEBUG("wrong key: ~s",[Key]), + false + end + end + end, + {_,TSec,TMSec} = now(), + TNow = TSec*1000*1000 + TMSec, + LastPoll = if + Packet == "" -> + TNow; + true -> + 0 + end, + {MinPoll, _} = string:to_integer(?MIN_POLLING), + if + (Packet == "") and + (TNow - StateData#state.last_poll < MinPoll*1000*1000) -> + Reply = {error, polling_too_frequently}, + {reply, Reply, StateName, StateData}; + KeyAllow -> + case RidAllow of + false -> + Reply = {error, not_exists}, + {reply, Reply, StateName, StateData}; + repeat -> + ?DEBUG("REPEATING ~p", [RID]), + [Out | _XS] = [El#hbr.out || + El <- StateData#state.req_list, + El#hbr.rid == RID], + case Out of + [[] | OutPacket] -> + Reply = {repeat, OutPacket}; + _ -> + Reply = {repeat, Out} + end, + {reply, Reply, StateName, + StateData#state{input = "cancel", last_poll = LastPoll}}; + true -> + SaveKey = if + NewKey == "" -> + Key; + true -> + NewKey + end, + ?DEBUG(" -- SaveKey: ~s~n", [SaveKey]), + + %% save request + ReqList = [#hbr{rid=RID, + key=StateData#state.key, + in=StateData#state.input, + out=StateData#state.output + } | + [El || El <- StateData#state.req_list, + El#hbr.rid < RID, + El#hbr.rid > (RID - 1 - Hold)] + ], +%% ?DEBUG("reqlist: ~p", [ReqList]), + case StateData#state.waiting_input of + false -> + cancel_timer(StateData#state.timer), + Timer = erlang:start_timer( + ?MAX_INACTIVITY, self(), []), + Input = Packet ++ [StateData#state.input], + Reply = ok, + {reply, Reply, StateName, + StateData#state{input = Input, + rid = RID, + key = SaveKey, + ctime = TNow, + timer = Timer, + last_poll = LastPoll, + req_list = ReqList + }}; + {Receiver, _Tag} -> + SendPacket = + if + StartTo /= "" -> + ["<stream:stream to='", + StartTo, + "' xmlns='jabber:client' " + "version='1.0' " + "xmlns:stream='http://etherx.jabber.org/streams'>"] ++ Packet; + true -> + Packet + end, + ?DEBUG("really sending now: ~s", [SendPacket]), + Receiver ! {tcp, {http_bind, self()}, + list_to_binary(SendPacket)}, + cancel_timer(StateData#state.timer), + Timer = erlang:start_timer( + ?MAX_INACTIVITY, self(), []), + Reply = ok, + {reply, Reply, StateName, + StateData#state{waiting_input = false, + last_receiver = Receiver, + input = "", + rid = RID, + key = SaveKey, + ctime = TNow, + timer = Timer, + last_poll = LastPoll, + req_list = ReqList + }} + end + end; + true -> + Reply = {error, bad_key}, + {reply, Reply, StateName, StateData} + end; + +handle_sync_event({http_get, RID, Wait, Hold}, _From, StateName, StateData) -> + {_,TSec,TMSec} = now(), + TNow = TSec*1000*1000 + TMSec, + cancel_timer(StateData#state.timer), + Timer = erlang:start_timer(?MAX_INACTIVITY, self(), []), + if + (Hold > 0) and + (StateData#state.output == "") and + ((TNow - StateData#state.ctime) < (Wait*1000*1000)) and + (StateData#state.rid == RID) and + (StateData#state.input /= "cancel") -> + Output = StateData#state.output, + ReqList = StateData#state.req_list, + Reply = {ok, keep_on_hold}; + (StateData#state.input == "cancel") -> + Output = StateData#state.output, + ReqList = StateData#state.req_list, + Reply = {ok, cancel}; + true -> + case StateData#state.output of + [[]| OutPacket] -> + Reply = {ok, OutPacket}; + _ -> + Reply = {ok, StateData#state.output} + end, + %% save request + ReqList = [#hbr{rid=RID, + key=StateData#state.key, + in=StateData#state.input, + out=StateData#state.output + } | + [El || El <- StateData#state.req_list, + El#hbr.rid /= RID ] + ], + Output = "" + end, + {reply, Reply, StateName, StateData#state{ + input = "", + output = Output, + timer = Timer, + req_list = ReqList}}; + +handle_sync_event(_Event, _From, StateName, StateData) -> + Reply = ok, + {reply, Reply, StateName, StateData}. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. + +%%---------------------------------------------------------------------- +%% Func: handle_info/3 +%% Returns: {next_state, NextStateName, NextStateData} | +%% {next_state, NextStateName, NextStateData, Timeout} | +%% {stop, Reason, NewStateData} +%%---------------------------------------------------------------------- +handle_info({timeout, Timer, _}, _StateName, + #state{timer = Timer} = StateData) -> + ?DEBUG("ding dong", []), + {stop, normal, StateData}; + +handle_info(_, StateName, StateData) -> + {next_state, StateName, StateData}. + +%%---------------------------------------------------------------------- +%% Func: terminate/3 +%% Purpose: Shutdown the fsm +%% Returns: any +%%---------------------------------------------------------------------- +terminate(_Reason, _StateName, StateData) -> + ?DEBUG("terminate: deleting session ~s", [StateData#state.id]), + mnesia:transaction( + fun() -> + mnesia:delete({http_bind, StateData#state.id}) + end), + case StateData#state.waiting_input of + false -> + case StateData#state.last_receiver of + undefined -> ok; + Receiver -> Receiver ! {tcp_closed, {http_bind, self()}} + end; + {Receiver, _Tag} -> Receiver ! {tcp_closed, {http_bind, self()}} + end, + ok. + +%%%---------------------------------------------------------------------- +%%% Internal functions +%%%---------------------------------------------------------------------- + + +http_put(ID, RID, Key, NewKey, Hold, Packet, Restart) -> + ?DEBUG("http-put",[]), + case mnesia:dirty_read({http_bind, ID}) of + [] -> + ?DEBUG("not found",[]), + {error, not_exists}; + [#http_bind{pid = FsmRef,to=To}] -> + case Restart of + true -> + ?DEBUG("restart requested for ~s", [To]), + gen_fsm:sync_send_all_state_event( + FsmRef, {http_put, RID, Key, NewKey, Hold, Packet, To}); + _ -> + gen_fsm:sync_send_all_state_event( + FsmRef, {http_put, RID, Key, NewKey, Hold, Packet, ""}) + end + end. + +http_get(ID,RID) -> + case mnesia:dirty_read({http_bind, ID}) of + [] -> + {error, not_exists}; + [#http_bind{pid = FsmRef, wait = Wait, hold = Hold}] -> + gen_fsm:sync_send_all_state_event(FsmRef, + {http_get, RID, Wait, Hold}) + end. + + +parse_request(Data) -> + ?DEBUG("--- incoming data --- ~n~s~n --- END --- ", + [Data]), + case xml_stream:parse_element(Data) of + El when element(1, El) == xmlelement -> + {xmlelement, Name, Attrs, Els} = El, + ID = xml:get_attr_s("sid",Attrs), + {RID,_X} = string:to_integer(xml:get_attr_s("rid",Attrs)), + Key = xml:get_attr_s("key",Attrs), + NewKey = xml:get_attr_s("newkey",Attrs), + Xmlns = xml:get_attr_s("xmlns",Attrs), + lists:map(fun(E) -> + EXmlns = xml:get_tag_attr_s("xmlns",E), + if + EXmlns == "jabber:client" -> + xml:remove_tag_attr("xmlns",E); + true -> + ok + end + end, Els), + Packet = [xml:element_to_string(E) || E <- Els], + ?DEBUG("ns fixed packet(s): ~s", [Packet]), + if + Name /= "body" -> + {error, bad_request}; + Xmlns /= "http://jabber.org/protocol/httpbind" -> + {error, bad_request}; + true -> + {ok, ID, RID, Key, NewKey, Attrs, Packet} + end; + {error, _Reason} -> + {error, bad_request} + end. + +cancel_timer(Timer) -> + erlang:cancel_timer(Timer), + receive + {timeout, Timer, _} -> + ok + after 0 -> + ok + end. + +hex(Bin) when binary(Bin) -> hex(binary_to_list(Bin)); +hex([]) -> ""; +hex([H|T]) -> + [A,B] = if + H == 0 -> "00"; + H < 16 -> [$0,element(H,{$1,$2,$3,$4,$5,$6,$7,$8,$9,$a,$b,$c,$d,$e,$f})]; + true -> erlang:integer_to_list(H,16) + end, + [A,B|hex(T)]. + +elements_to_string([]) -> + []; +elements_to_string([El | Els]) -> + xml:element_to_string(El) ++ elements_to_string(Els). diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl new file mode 100644 index 000000000..1cebd0f5e --- /dev/null +++ b/src/web/mod_http_bind.erl @@ -0,0 +1,102 @@ +%%%---------------------------------------------------------------------- +%%% File : mod_http_bind.erl +%%% Author : Stefan Strigler <steve@zeank.in-berlin.de> +%%% Purpose : Implementation of XMPP over BOSH (XEP-0206) +%%% Created : Tue Feb 20 13:15:52 CET 2007 +%%% Id : $Id: $ +%%%---------------------------------------------------------------------- + +%%%---------------------------------------------------------------------- +%%% this module acts as a bridge to ejabberd_http_bind which implements +%%% the real stuff, this is to handle the new pluggable architecture for +%%% extending ejabberd's http service +%%%---------------------------------------------------------------------- + +-module(mod_http_bind). +-author('steve@zeank.in-berlin.de'). + +-define(MOD_HTTP_BIND_VERSION, "1.0"). +-vsn(?MOD_HTTP_BIND_VERSION). + +%%-define(ejabberd_debug, true). + +-behaviour(gen_mod). + +-export([ + start/2, + stop/1, + process/2 + ]). + +-include("ejabberd.hrl"). +-include("jlib.hrl"). +-include("ejabberd_http.hrl"). + + +%%%---------------------------------------------------------------------- +%%% API +%%%---------------------------------------------------------------------- + +process([], #request{method = 'POST', + data = []}) -> + ?DEBUG("Bad Request: no data", []), + {400, [], {xmlelement, "h1", [], + [{xmlcdata, "400 Bad Request"}]}}; +process([], #request{method = 'POST', + data = Data}) -> + ?DEBUG("Incoming data: ~s", [Data]), + ejabberd_http_bind:process_request(Data); +process([], #request{method = 'GET', + data = []}) -> + Heading = "Ejabberd " ++ atom_to_list(?MODULE) ++ " v" ++ ?MOD_HTTP_BIND_VERSION, + {xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}], + [{xmlelement, "head", [], + [{xmlelement, "title", [], [{xmlcdata, Heading}]}]}, + {xmlelement, "body", [], + [{xmlelement, "h1", [], [{xmlcdata, Heading}]}, + {xmlelement, "p", [], + [{xmlcdata, "An implementation of "}, + {xmlelement, "a", [{"href", "http://www.xmpp.org/extensions/xep-0206.html"}], + [{xmlcdata, "XMPP over BOSH (XEP-0206)"}]}]}, + {xmlelement, "p", [], + [{xmlcdata, integer_to_list(mnesia:table_info(http_bind, size)) ++ " sessions found."}]}, + {xmlelement, "p", [], + [{xmlcdata, "Sponsored by "}, + {xmlelement, "a", [{"href", "http://mabber.com"}], + [{xmlcdata, "mabber"}]}, + {xmlcdata, "."}]} + ]}]}; +process(_Path, _Request) -> + ?DEBUG("Bad Request: ~p", [_Request]), + {400, [], {xmlelement, "h1", [], + [{xmlcdata, "400 Bad Request"}]}}. + + +%%%---------------------------------------------------------------------- +%%% BEHAVIOUR CALLBACKS +%%%---------------------------------------------------------------------- +start(_Host, _Opts) -> + HTTPBindSupervisor = + {ejabberd_http_bind_sup, + {ejabberd_tmp_sup, start_link, + [ejabberd_http_bind_sup, ejabberd_http_bind]}, + permanent, + infinity, + supervisor, + [ejabberd_tmp_sup]}, + case supervisor:start_child(ejabberd_sup, HTTPBindSupervisor) of + {ok, _Pid} -> + ok; + {ok, _Pid, _Info} -> + ok; + {error, Error} -> + {'EXIT', {start_child_error, Error}} + end. + +stop(_Host) -> + case supervisor:terminate_child(ejabberd_sup, ejabberd_http_bind_sup) of + ok -> + ok; + {error, Error} -> + {'EXIT', {terminate_child_error, Error}} + end. From 7d62dff7e5ed25e54ccab166cd8f305564cdb4fd Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:23:45 +0000 Subject: [PATCH 377/582] Make use of new api for plugable http based services (thanks to Stefan Strigler) SVN Revision: 2262 --- src/web/ejabberd_http_bind.erl | 114 +++++++++++++++++++-------------- src/web/mod_http_bind.erl | 30 ++------- 2 files changed, 71 insertions(+), 73 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index d462e0a0d..11043808a 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -26,7 +26,7 @@ close/1, process_request/1]). -%%-define(ejabberd_debug, true). +-define(ejabberd_debug, true). -include("ejabberd.hrl"). -include("jlib.hrl"). @@ -54,7 +54,7 @@ }). -%-define(DBGFSM, true). +%%-define(DBGFSM, true). -ifdef(DBGFSM). -define(FSMOPTS, [{debug, [trace]}]). @@ -64,10 +64,10 @@ -define(MAX_REQUESTS, 2). % number of simultaneous requests -define(MIN_POLLING, "2"). % don't poll faster than that or we will shoot you --define(MAX_WAIT, 60). % max num of secs to keep a request on hold +-define(MAX_WAIT, 3600). % max num of secs to keep a request on hold -define(MAX_INACTIVITY, 30000). % msecs to wait before terminating idle sessions -define(CT, {"Content-Type", "text/xml; charset=utf-8"}). --define(BAD_REQUEST, ?CT). +-define(HEADER, [?CT,{"X-Sponsored-By", "http://mabber.com"}]). %%%---------------------------------------------------------------------- @@ -88,7 +88,7 @@ send({http_bind, FsmRef}, Packet) -> setopts({http_bind, FsmRef}, Opts) -> case lists:member({active, once}, Opts) of true -> - gen_fsm:sync_send_all_state_event(FsmRef, activate); + gen_fsm:send_all_state_event(FsmRef, {activate, self()}); _ -> ok end. @@ -100,14 +100,13 @@ close({http_bind, FsmRef}) -> catch gen_fsm:sync_send_all_state_event(FsmRef, close). -process_request(#request{path = [], - data = Data}) -> +process_request(Data) -> case catch parse_request(Data) of {ok, ID1, RID, Key, NewKey, Attrs, Packet} -> XmppDomain = xml:get_attr_s("to",Attrs), if (ID1 == "") and (XmppDomain == "") -> - {200, [?CT], "<body type='terminate' " + {200, ?HEADER, "<body type='terminate' " "condition='improper-addressing' " "xmlns='http://jabber.org/protocol/httpbind'/>"}; true -> @@ -116,6 +115,7 @@ process_request(#request{path = [], %% create new session NewID = sha:sha(term_to_binary({now(), make_ref()})), {ok, Pid} = start(NewID, Key), + ?DEBUG("got pid: ~p", [Pid]), Wait = case string:to_integer(xml:get_attr_s("wait",Attrs)) of @@ -184,24 +184,24 @@ process_request(#request{path = [], case http_put(ID, RID, Key, NewKey, Hold, InPacket, StreamStart) of {error, not_exists} -> ?DEBUG("no session associated with sid: ~p", [ID]), - {404, [?BAD_REQUEST], ""}; + {404, ?HEADER, ""}; {error, bad_key} -> ?DEBUG("bad key: ~s", [Key]), case mnesia:dirty_read({http_bind, ID}) of [] -> - {404, [?BAD_REQUEST], ""}; + {404, ?HEADER, ""}; [#http_bind{pid = FsmRef}] -> gen_fsm:sync_send_all_state_event(FsmRef,stop), - {404, [?BAD_REQUEST], ""} + {404, ?HEADER, ""} end; {error, polling_too_frequently} -> ?DEBUG("polling too frequently: ~p", [ID]), case mnesia:dirty_read({http_bind, ID}) of [] -> %% unlikely! (?) - {404, [?BAD_REQUEST], ""}; + {404, ?HEADER, ""}; [#http_bind{pid = FsmRef}] -> gen_fsm:sync_send_all_state_event(FsmRef,stop), - {403, [?BAD_REQUEST], ""} + {403, ?HEADER, ""} end; {repeat, OutPacket} -> ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", @@ -212,11 +212,8 @@ process_request(#request{path = [], end end; _ -> - {400, [?BAD_REQUEST], ""} - end; -process_request(_Request) -> - {400, [], {xmlelement, "h1", [], - [{xmlcdata, "400 Bad Request"}]}}. + {400, ?HEADER, ""} + end. receive_loop(ID,ID1,RID,Wait,Hold,Attrs) -> receive @@ -228,14 +225,14 @@ prepare_response(ID,ID1,RID,Wait,Hold,Attrs) -> case http_get(ID,RID) of {error, not_exists} -> ?DEBUG("no session associated with sid: ~s", ID), - {404, [?BAD_REQUEST], ""}; + {404, ?HEADER, ""}; {ok, keep_on_hold} -> receive_loop(ID,ID1,RID,Wait,Hold,Attrs); {ok, cancel} -> %% actually it would be better if we could completely %% cancel this request, but then we would have to hack %% ejabberd_http and I'm too lazy now - {404, [?BAD_REQUEST], ""}; + {404, ?HEADER, ""}; {ok, OutPacket} -> ?DEBUG("OutPacket: ~s", [OutPacket]), if @@ -264,15 +261,15 @@ prepare_response(ID,ID1,RID,Wait,Hold,Attrs) -> end, if To == "" -> - {200, [?CT], "<body type='terminate' " + {200, ?HEADER, "<body type='terminate' " "condition='improper-addressing' " "xmlns='http://jabber.org/protocol/httpbind'/>"}; StreamError == true -> - {200, [?CT], "<body type='terminate' " + {200, ?HEADER, "<body type='terminate' " "condition='host-unknown' " "xmlns='http://jabber.org/protocol/httpbind'/>"}; true -> - {200, [?CT], + {200, ?HEADER, xml:element_to_string( {xmlelement,"body", [{"xmlns", @@ -292,13 +289,13 @@ prepare_response(ID,ID1,RID,Wait,Hold,Attrs) -> send_outpacket(ID, OutPacket) -> case OutPacket of "" -> - {200, [?CT], "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; + {200, ?HEADER, "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; "</stream:stream>" -> case mnesia:dirty_read({http_bind, ID}) of [#http_bind{pid = FsmRef}] -> gen_fsm:sync_send_all_state_event(FsmRef,stop) end, - {200, [?CT], "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; + {200, ?HEADER, "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; _ -> case xml_stream:parse_element("<body>" ++ OutPacket @@ -316,7 +313,7 @@ send_outpacket(ID, OutPacket) -> "http://jabber.org/protocol/httpbind"}], TypedEls})] ), - {200, [?CT], + {200, ?HEADER, xml:element_to_string( {xmlelement,"body", [{"xmlns", @@ -367,12 +364,12 @@ send_outpacket(ID, OutPacket) -> end, case StreamErrCond of null -> - {200, [?CT], + {200, ?HEADER, "<body type='terminate' " "condition='internal-server-error' " "xmlns='http://jabber.org/protocol/httpbind'/>"}; _ -> - {200, [?CT], + {200, ?HEADER, "<body type='terminate' " "condition='remote-stream-error' " "xmlns='http://jabber.org/protocol/httpbind'>" ++ @@ -380,7 +377,7 @@ send_outpacket(ID, OutPacket) -> "</body>"} end; true -> - {200, [?CT], + {200, ?HEADER, xml:element_to_string( {xmlelement,"body", [{"xmlns", @@ -404,8 +401,9 @@ send_outpacket(ID, OutPacket) -> init([ID, Key]) -> ?INFO_MSG("started: ~p", [{ID, Key}]), Opts = [], % TODO - {ok, C2SPid} = ejabberd_c2s:start({?MODULE, {http_bind, self()}}, Opts), - ejabberd_c2s:become_controller(C2SPid), + ejabberd_socket:start(ejabberd_c2s, ?MODULE, {http_bind, self()}, Opts), +% {ok, C2SPid} = ejabberd_c2s:start({?MODULE, {http_bind, self()}}, Opts), +% ejabberd_c2s:become_controller(C2SPid), Timer = erlang:start_timer(?MAX_INACTIVITY, self(), []), {ok, loop, #state{id = ID, key = Key, @@ -438,6 +436,20 @@ init([ID, Key]) -> %% {next_state, NextStateName, NextStateData, Timeout} | %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- +handle_event({activate, From}, StateName, StateData) -> + case StateData#state.input of + "" -> + {next_state, StateName, StateData#state{ + waiting_input = {From, ok}}}; + Input -> + Receiver = From, + Receiver ! {tcp, {http_bind, self()}, list_to_binary(Input)}, + {next_state, StateName, StateData#state{ + input = "", + waiting_input = false, + last_receiver = Receiver}} + end; + handle_event(_Event, StateName, StateData) -> {next_state, StateName, StateData}. @@ -455,19 +467,6 @@ handle_sync_event({send, Packet}, _From, StateName, StateData) -> Reply = ok, {reply, Reply, StateName, StateData#state{output = Output}}; -handle_sync_event(activate, From, StateName, StateData) -> - case StateData#state.input of - "" -> - {reply, ok, StateName, StateData#state{ - waiting_input = From}}; - Input -> - From ! {tcp, {http_bind, self()}, list_to_binary(Input)}, - {reply, ok, StateName, StateData#state{ - input = "", - waiting_input = false, - last_receiver = From}} - end; - handle_sync_event(stop, _From, _StateName, StateData) -> Reply = ok, {stop, normal, Reply, StateData}; @@ -751,6 +750,16 @@ parse_request(Data) -> case xml_stream:parse_element(Data) of El when element(1, El) == xmlelement -> {xmlelement, Name, Attrs, Els} = El, + FixedEls = + lists:filter( + fun(I) -> + case I of + {xmlelement, _, _, _} -> + true; + _ -> + false + end + end, Els), ID = xml:get_attr_s("sid",Attrs), {RID,_X} = string:to_integer(xml:get_attr_s("rid",Attrs)), Key = xml:get_attr_s("key",Attrs), @@ -760,13 +769,12 @@ parse_request(Data) -> EXmlns = xml:get_tag_attr_s("xmlns",E), if EXmlns == "jabber:client" -> - xml:remove_tag_attr("xmlns",E); + remove_tag_attr("xmlns",E); true -> ok end - end, Els), - Packet = [xml:element_to_string(E) || E <- Els], - ?DEBUG("ns fixed packet(s): ~s", [Packet]), + end, FixedEls), + Packet = [xml:element_to_string(E) || E <- FixedEls], if Name /= "body" -> {error, bad_request}; @@ -802,3 +810,13 @@ elements_to_string([]) -> []; elements_to_string([El | Els]) -> xml:element_to_string(El) ++ elements_to_string(Els). + + +remove_tag_attr(Attr, El) -> + case El of + {xmlelement, Name, Attrs, Els} -> + Attrs1 = lists:keydelete(Attr, 1, Attrs), + {xmlelement, Name, Attrs1, Els}; + _ -> + El + end. diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index 1cebd0f5e..c57624e36 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -17,8 +17,7 @@ -define(MOD_HTTP_BIND_VERSION, "1.0"). -vsn(?MOD_HTTP_BIND_VERSION). - -%%-define(ejabberd_debug, true). +-define(ejabberd_debug, true). -behaviour(gen_mod). @@ -44,7 +43,7 @@ process([], #request{method = 'POST', [{xmlcdata, "400 Bad Request"}]}}; process([], #request{method = 'POST', data = Data}) -> - ?DEBUG("Incoming data: ~s", [Data]), + ?DEBUG("Data: '~p'", [Data]), ejabberd_http_bind:process_request(Data); process([], #request{method = 'GET', data = []}) -> @@ -75,28 +74,9 @@ process(_Path, _Request) -> %%%---------------------------------------------------------------------- %%% BEHAVIOUR CALLBACKS %%%---------------------------------------------------------------------- + start(_Host, _Opts) -> - HTTPBindSupervisor = - {ejabberd_http_bind_sup, - {ejabberd_tmp_sup, start_link, - [ejabberd_http_bind_sup, ejabberd_http_bind]}, - permanent, - infinity, - supervisor, - [ejabberd_tmp_sup]}, - case supervisor:start_child(ejabberd_sup, HTTPBindSupervisor) of - {ok, _Pid} -> - ok; - {ok, _Pid, _Info} -> - ok; - {error, Error} -> - {'EXIT', {start_child_error, Error}} - end. + ok. stop(_Host) -> - case supervisor:terminate_child(ejabberd_sup, ejabberd_http_bind_sup) of - ok -> - ok; - {error, Error} -> - {'EXIT', {terminate_child_error, Error}} - end. + ok. From d019405d51e4b786fe1f5b8be522011ddb485398 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:23:49 +0000 Subject: [PATCH 378/582] Start supervisor here (thanks to Stefan Strigler) SVN Revision: 2263 --- src/web/mod_http_bind.erl | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index c57624e36..34ed88722 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -74,9 +74,18 @@ process(_Path, _Request) -> %%%---------------------------------------------------------------------- %%% BEHAVIOUR CALLBACKS %%%---------------------------------------------------------------------- - start(_Host, _Opts) -> - ok. + supervisor:start_child( + ejabberd_sup, + {ejabberd_http_bind_sup, + {ejabberd_tmp_sup, start_link, + [ejabberd_http_bind_sup, ejabberd_http_bind]}, + permanent, + infinity, + supervisor, + [ejabberd_tmp_sup]}), + ok. stop(_Host) -> - ok. + supervisor:terminate_child(ejabberd_sup, ejabberd_http_bind_sup), + ok. From ecc2bbd7521232b9fc7338b8d88ed442e951d3b7 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:23:53 +0000 Subject: [PATCH 379/582] Renamed some vars for (thanks to Stefan Strigler) SVN Revision: 2264 --- src/web/ejabberd_http_bind.erl | 130 ++++++++++++++++----------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 11043808a..9c98ba179 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -73,14 +73,14 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- -start(ID, Key) -> +start(Sid, Key) -> mnesia:create_table(http_bind, [{ram_copies, [node()]}, {attributes, record_info(fields, http_bind)}]), - supervisor:start_child(ejabberd_http_bind_sup, [ID, Key]). + supervisor:start_child(ejabberd_http_bind_sup, [Sid, Key]). -start_link(ID, Key) -> - gen_fsm:start_link(?MODULE, [ID, Key], ?FSMOPTS). +start_link(Sid, Key) -> + gen_fsm:start_link(?MODULE, [Sid, Key], ?FSMOPTS). send({http_bind, FsmRef}, Packet) -> gen_fsm:sync_send_all_state_event(FsmRef, {send, Packet}). @@ -102,19 +102,19 @@ close({http_bind, FsmRef}) -> process_request(Data) -> case catch parse_request(Data) of - {ok, ID1, RID, Key, NewKey, Attrs, Packet} -> + {ok, {ParsedSid, Rid, Key, NewKey, Attrs, Packet}} -> XmppDomain = xml:get_attr_s("to",Attrs), if - (ID1 == "") and (XmppDomain == "") -> + (ParsedSid == "") and (XmppDomain == "") -> {200, ?HEADER, "<body type='terminate' " "condition='improper-addressing' " "xmlns='http://jabber.org/protocol/httpbind'/>"}; true -> - ID = if - (ID1 == "") -> + Sid = if + (ParsedSid == "") -> %% create new session - NewID = sha:sha(term_to_binary({now(), make_ref()})), - {ok, Pid} = start(NewID, Key), + NewSid = sha:sha(term_to_binary({now(), make_ref()})), + {ok, Pid} = start(NewSid, Key), ?DEBUG("got pid: ~p", [Pid]), Wait = case string:to_integer(xml:get_attr_s("wait",Attrs)) @@ -145,7 +145,7 @@ process_request(Data) -> end, mnesia:transaction( fun() -> - mnesia:write(#http_bind{id = NewID, + mnesia:write(#http_bind{id = NewSid, pid = Pid, to = XmppDomain, wait = Wait, @@ -158,7 +158,7 @@ process_request(Data) -> false end, InPacket = Packet, - NewID; + NewSid; true -> %% old session Type = xml:get_attr_s("type",Attrs), @@ -178,16 +178,16 @@ process_request(Data) -> true -> InPacket = Packet end, - ID1 + ParsedSid end, %% ?DEBUG("~n InPacket: ~s ~n", [InPacket]), - case http_put(ID, RID, Key, NewKey, Hold, InPacket, StreamStart) of + case http_put(Sid, Rid, Key, NewKey, Hold, InPacket, StreamStart) of {error, not_exists} -> - ?DEBUG("no session associated with sid: ~p", [ID]), + ?DEBUG("no session associated with sid: ~p", [Sid]), {404, ?HEADER, ""}; {error, bad_key} -> ?DEBUG("bad key: ~s", [Key]), - case mnesia:dirty_read({http_bind, ID}) of + case mnesia:dirty_read({http_bind, Sid}) of [] -> {404, ?HEADER, ""}; [#http_bind{pid = FsmRef}] -> @@ -195,8 +195,8 @@ process_request(Data) -> {404, ?HEADER, ""} end; {error, polling_too_frequently} -> - ?DEBUG("polling too frequently: ~p", [ID]), - case mnesia:dirty_read({http_bind, ID}) of + ?DEBUG("polling too frequently: ~p", [Sid]), + case mnesia:dirty_read({http_bind, Sid}) of [] -> %% unlikely! (?) {404, ?HEADER, ""}; [#http_bind{pid = FsmRef}] -> @@ -206,28 +206,28 @@ process_request(Data) -> {repeat, OutPacket} -> ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", [OutPacket]), - send_outpacket(ID, OutPacket); + send_outpacket(Sid, OutPacket); ok -> - receive_loop(ID,ID1,RID,Wait,Hold,Attrs) + receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs) end end; _ -> {400, ?HEADER, ""} end. -receive_loop(ID,ID1,RID,Wait,Hold,Attrs) -> +receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs) -> receive after 100 -> ok end, - prepare_response(ID,ID1,RID,Wait,Hold,Attrs). + prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs). -prepare_response(ID,ID1,RID,Wait,Hold,Attrs) -> - case http_get(ID,RID) of +prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs) -> + case http_get(Sid,Rid) of {error, not_exists} -> - ?DEBUG("no session associated with sid: ~s", ID), + ?DEBUG("no session associated with sid: ~s", Sid), {404, ?HEADER, ""}; {ok, keep_on_hold} -> - receive_loop(ID,ID1,RID,Wait,Hold,Attrs); + receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs); {ok, cancel} -> %% actually it would be better if we could completely %% cancel this request, but then we would have to hack @@ -236,8 +236,8 @@ prepare_response(ID,ID1,RID,Wait,Hold,Attrs) -> {ok, OutPacket} -> ?DEBUG("OutPacket: ~s", [OutPacket]), if - ID == ID1 -> - send_outpacket(ID, OutPacket); + Sid == ParsedSid -> + send_outpacket(Sid, OutPacket); true -> To = xml:get_attr_s("to",Attrs), OutEls = case xml_stream:parse_element( @@ -274,7 +274,7 @@ prepare_response(ID,ID1,RID,Wait,Hold,Attrs) -> {xmlelement,"body", [{"xmlns", "http://jabber.org/protocol/httpbind"}, - {"sid",ID}, + {"sid",Sid}, {"wait", integer_to_list(Wait)}, {"requests", integer_to_list(Hold+1)}, {"inactivity", @@ -286,12 +286,12 @@ prepare_response(ID,ID1,RID,Wait,Hold,Attrs) -> end end. -send_outpacket(ID, OutPacket) -> +send_outpacket(Sid, OutPacket) -> case OutPacket of "" -> {200, ?HEADER, "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; "</stream:stream>" -> - case mnesia:dirty_read({http_bind, ID}) of + case mnesia:dirty_read({http_bind, Sid}) of [#http_bind{pid = FsmRef}] -> gen_fsm:sync_send_all_state_event(FsmRef,stop) end, @@ -356,7 +356,7 @@ send_outpacket(ID, OutPacket) -> {error, _E} -> null end, - case mnesia:dirty_read({http_bind, ID}) of + case mnesia:dirty_read({http_bind, Sid}) of [#http_bind{pid = FsmRef}] -> gen_fsm:sync_send_all_state_event(FsmRef,stop); _ -> @@ -398,14 +398,14 @@ send_outpacket(ID, OutPacket) -> %% ignore | %% {stop, StopReason} %%---------------------------------------------------------------------- -init([ID, Key]) -> - ?INFO_MSG("started: ~p", [{ID, Key}]), +init([Sid, Key]) -> + ?INFO_MSG("started: ~p", [{Sid, Key}]), Opts = [], % TODO ejabberd_socket:start(ejabberd_c2s, ?MODULE, {http_bind, self()}, Opts), % {ok, C2SPid} = ejabberd_c2s:start({?MODULE, {http_bind, self()}}, Opts), % ejabberd_c2s:become_controller(C2SPid), Timer = erlang:start_timer(?MAX_INACTIVITY, self(), []), - {ok, loop, #state{id = ID, + {ok, loop, #state{id = Sid, key = Key, timer = Timer}}. @@ -471,10 +471,10 @@ handle_sync_event(stop, _From, _StateName, StateData) -> Reply = ok, {stop, normal, Reply, StateData}; -handle_sync_event({http_put, RID, Key, NewKey, Hold, Packet, StartTo}, +handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StartTo}, _From, StateName, StateData) -> - %% check if RID valid - RidAllow = case RID of + %% check if Rid valid + RidAllow = case Rid of error -> false; _ -> @@ -482,15 +482,15 @@ handle_sync_event({http_put, RID, Key, NewKey, Hold, Packet, StartTo}, error -> %% first request - nothing saved so far true; - OldRID -> + OldRid -> ?DEBUG("state.rid/cur rid: ~p/~p", - [OldRID, RID]), + [OldRid, Rid]), if - (OldRID < RID) and - (RID =< (OldRID + Hold + 1)) -> + (OldRid < Rid) and + (Rid =< (OldRid + Hold + 1)) -> true; - (RID =< OldRID) and - (RID > OldRID - Hold - 1) -> + (Rid =< OldRid) and + (Rid > OldRid - Hold - 1) -> repeat; true -> false @@ -542,10 +542,10 @@ handle_sync_event({http_put, RID, Key, NewKey, Hold, Packet, StartTo}, Reply = {error, not_exists}, {reply, Reply, StateName, StateData}; repeat -> - ?DEBUG("REPEATING ~p", [RID]), + ?DEBUG("REPEATING ~p", [Rid]), [Out | _XS] = [El#hbr.out || El <- StateData#state.req_list, - El#hbr.rid == RID], + El#hbr.rid == Rid], case Out of [[] | OutPacket] -> Reply = {repeat, OutPacket}; @@ -564,14 +564,14 @@ handle_sync_event({http_put, RID, Key, NewKey, Hold, Packet, StartTo}, ?DEBUG(" -- SaveKey: ~s~n", [SaveKey]), %% save request - ReqList = [#hbr{rid=RID, + ReqList = [#hbr{rid=Rid, key=StateData#state.key, in=StateData#state.input, out=StateData#state.output } | [El || El <- StateData#state.req_list, - El#hbr.rid < RID, - El#hbr.rid > (RID - 1 - Hold)] + El#hbr.rid < Rid, + El#hbr.rid > (Rid - 1 - Hold)] ], %% ?DEBUG("reqlist: ~p", [ReqList]), case StateData#state.waiting_input of @@ -583,7 +583,7 @@ handle_sync_event({http_put, RID, Key, NewKey, Hold, Packet, StartTo}, Reply = ok, {reply, Reply, StateName, StateData#state{input = Input, - rid = RID, + rid = Rid, key = SaveKey, ctime = TNow, timer = Timer, @@ -613,7 +613,7 @@ handle_sync_event({http_put, RID, Key, NewKey, Hold, Packet, StartTo}, StateData#state{waiting_input = false, last_receiver = Receiver, input = "", - rid = RID, + rid = Rid, key = SaveKey, ctime = TNow, timer = Timer, @@ -627,7 +627,7 @@ handle_sync_event({http_put, RID, Key, NewKey, Hold, Packet, StartTo}, {reply, Reply, StateName, StateData} end; -handle_sync_event({http_get, RID, Wait, Hold}, _From, StateName, StateData) -> +handle_sync_event({http_get, Rid, Wait, Hold}, _From, StateName, StateData) -> {_,TSec,TMSec} = now(), TNow = TSec*1000*1000 + TMSec, cancel_timer(StateData#state.timer), @@ -636,7 +636,7 @@ handle_sync_event({http_get, RID, Wait, Hold}, _From, StateName, StateData) -> (Hold > 0) and (StateData#state.output == "") and ((TNow - StateData#state.ctime) < (Wait*1000*1000)) and - (StateData#state.rid == RID) and + (StateData#state.rid == Rid) and (StateData#state.input /= "cancel") -> Output = StateData#state.output, ReqList = StateData#state.req_list, @@ -653,13 +653,13 @@ handle_sync_event({http_get, RID, Wait, Hold}, _From, StateName, StateData) -> Reply = {ok, StateData#state.output} end, %% save request - ReqList = [#hbr{rid=RID, + ReqList = [#hbr{rid=Rid, key=StateData#state.key, in=StateData#state.input, out=StateData#state.output } | [El || El <- StateData#state.req_list, - El#hbr.rid /= RID ] + El#hbr.rid /= Rid ] ], Output = "" end, @@ -716,9 +716,9 @@ terminate(_Reason, _StateName, StateData) -> %%%---------------------------------------------------------------------- -http_put(ID, RID, Key, NewKey, Hold, Packet, Restart) -> +http_put(Sid, Rid, Key, NewKey, Hold, Packet, Restart) -> ?DEBUG("http-put",[]), - case mnesia:dirty_read({http_bind, ID}) of + case mnesia:dirty_read({http_bind, Sid}) of [] -> ?DEBUG("not found",[]), {error, not_exists}; @@ -727,20 +727,20 @@ http_put(ID, RID, Key, NewKey, Hold, Packet, Restart) -> true -> ?DEBUG("restart requested for ~s", [To]), gen_fsm:sync_send_all_state_event( - FsmRef, {http_put, RID, Key, NewKey, Hold, Packet, To}); + FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, To}); _ -> gen_fsm:sync_send_all_state_event( - FsmRef, {http_put, RID, Key, NewKey, Hold, Packet, ""}) + FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, ""}) end end. -http_get(ID,RID) -> - case mnesia:dirty_read({http_bind, ID}) of +http_get(Sid,Rid) -> + case mnesia:dirty_read({http_bind, Sid}) of [] -> {error, not_exists}; [#http_bind{pid = FsmRef, wait = Wait, hold = Hold}] -> gen_fsm:sync_send_all_state_event(FsmRef, - {http_get, RID, Wait, Hold}) + {http_get, Rid, Wait, Hold}) end. @@ -760,8 +760,8 @@ parse_request(Data) -> false end end, Els), - ID = xml:get_attr_s("sid",Attrs), - {RID,_X} = string:to_integer(xml:get_attr_s("rid",Attrs)), + Sid = xml:get_attr_s("sid",Attrs), + {Rid,_X} = string:to_integer(xml:get_attr_s("rid",Attrs)), Key = xml:get_attr_s("key",Attrs), NewKey = xml:get_attr_s("newkey",Attrs), Xmlns = xml:get_attr_s("xmlns",Attrs), @@ -781,7 +781,7 @@ parse_request(Data) -> Xmlns /= "http://jabber.org/protocol/httpbind" -> {error, bad_request}; true -> - {ok, ID, RID, Key, NewKey, Attrs, Packet} + {ok, {Sid, Rid, Key, NewKey, Attrs, Packet}} end; {error, _Reason} -> {error, bad_request} From f5223b1643df17bb9a79b754741af07a0870a943 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:23:57 +0000 Subject: [PATCH 380/582] Removed my own supervisor (thanks to Stefan Strigler) SVN Revision: 2265 --- src/web/ejabberd_http_bind.erl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 9c98ba179..96c9fd085 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -62,6 +62,8 @@ -define(FSMOPTS, []). -endif. +-define(BOSH_VERSION, "1.6"). + -define(MAX_REQUESTS, 2). % number of simultaneous requests -define(MIN_POLLING, "2"). % don't poll faster than that or we will shoot you -define(MAX_WAIT, 3600). % max num of secs to keep a request on hold From 33896adf9df1099f873621fb2f9eac24669b536b Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:24:01 +0000 Subject: [PATCH 381/582] Disabled debug (thanks to Stefan Strigler) SVN Revision: 2266 --- src/web/ejabberd_http_bind.erl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 96c9fd085..d16a5d0c4 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -26,7 +26,7 @@ close/1, process_request/1]). --define(ejabberd_debug, true). +%%-define(ejabberd_debug, true). -include("ejabberd.hrl"). -include("jlib.hrl"). @@ -62,8 +62,6 @@ -define(FSMOPTS, []). -endif. --define(BOSH_VERSION, "1.6"). - -define(MAX_REQUESTS, 2). % number of simultaneous requests -define(MIN_POLLING, "2"). % don't poll faster than that or we will shoot you -define(MAX_WAIT, 3600). % max num of secs to keep a request on hold From eca818be5a60401d867f40541f683aea5c777001 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:24:05 +0000 Subject: [PATCH 382/582] Deal with return values from starting/terminating supervisor (thanks to Stefan Strigler) SVN Revision: 2267 --- src/web/mod_http_bind.erl | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index 34ed88722..4f590c659 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -75,17 +75,27 @@ process(_Path, _Request) -> %%% BEHAVIOUR CALLBACKS %%%---------------------------------------------------------------------- start(_Host, _Opts) -> - supervisor:start_child( - ejabberd_sup, - {ejabberd_http_bind_sup, - {ejabberd_tmp_sup, start_link, - [ejabberd_http_bind_sup, ejabberd_http_bind]}, - permanent, - infinity, - supervisor, - [ejabberd_tmp_sup]}), - ok. + HTTPBindSupervisor = + {ejabberd_http_bind_sup, + {ejabberd_tmp_sup, start_link, + [ejabberd_http_bind_sup, ejabberd_http_bind]}, + permanent, + infinity, + supervisor, + [ejabberd_tmp_sup]}, + case supervisor:start_child(ejabberd_sup, HTTPBindSupervisor) of + {ok, _Pid} -> + ok; + {ok, _Pid, _Info} -> + ok; + {error, Error} -> + {'EXIT', {start_child_error, Error}} + end. stop(_Host) -> - supervisor:terminate_child(ejabberd_sup, ejabberd_http_bind_sup), - ok. + case supervisor:terminate_child(ejabberd_sup, ejabberd_http_bind_sup) of + ok -> + ok; + {error, Error} -> + {'EXIT', {terminate_child_error, Error}} + end. From bb229a3a0c7498d0ad9530f291715976775b646e Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:24:09 +0000 Subject: [PATCH 383/582] Disabled debug (thanks to Stefan Strigler) SVN Revision: 2268 --- src/web/mod_http_bind.erl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index 4f590c659..1cebd0f5e 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -17,7 +17,8 @@ -define(MOD_HTTP_BIND_VERSION, "1.0"). -vsn(?MOD_HTTP_BIND_VERSION). --define(ejabberd_debug, true). + +%%-define(ejabberd_debug, true). -behaviour(gen_mod). @@ -43,7 +44,7 @@ process([], #request{method = 'POST', [{xmlcdata, "400 Bad Request"}]}}; process([], #request{method = 'POST', data = Data}) -> - ?DEBUG("Data: '~p'", [Data]), + ?DEBUG("Incoming data: ~s", [Data]), ejabberd_http_bind:process_request(Data); process([], #request{method = 'GET', data = []}) -> From 197639a34b7b1aac2703f046896a1a68d674b6c6 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:24:14 +0000 Subject: [PATCH 384/582] Minor changes (thanks to Stefan Strigler) SVN Revision: 2269 --- src/web/ejabberd_http_bind.erl | 952 ++++++++++++++++----------------- src/web/mod_http_bind.erl | 18 +- 2 files changed, 469 insertions(+), 501 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index d16a5d0c4..0cbe40e86 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -3,17 +3,16 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : HTTP Binding support (JEP-0124) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('Revision: 1.4'). +-vsn('1.9'). -behaviour(gen_fsm). %% External exports --export([start_link/2, +-export([start_link/3, init/1, handle_event/3, handle_sync_event/4, @@ -26,7 +25,7 @@ close/1, process_request/1]). -%%-define(ejabberd_debug, true). +-define(ejabberd_debug, true). -include("ejabberd.hrl"). -include("jlib.hrl"). @@ -35,10 +34,7 @@ -record(http_bind, {id, pid, to, hold, wait}). %% http binding request --record(hbr, {rid, - key, - in, - out}). +-record(hbr, {rid, key, in, out}). -record(state, {id, rid = error, @@ -53,8 +49,7 @@ req_list = [] % list of requests }). - -%%-define(DBGFSM, true). +-define(DBGFSM, true). -ifdef(DBGFSM). -define(FSMOPTS, [{debug, [trace]}]). @@ -62,6 +57,8 @@ -define(FSMOPTS, []). -endif. +-define(BOSH_VERSION, "1.6"). + -define(MAX_REQUESTS, 2). % number of simultaneous requests -define(MIN_POLLING, "2"). % don't poll faster than that or we will shoot you -define(MAX_WAIT, 3600). % max num of secs to keep a request on hold @@ -69,18 +66,17 @@ -define(CT, {"Content-Type", "text/xml; charset=utf-8"}). -define(HEADER, [?CT,{"X-Sponsored-By", "http://mabber.com"}]). - %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- -start(Sid, Key) -> +start(Sid, Rid, Key) -> mnesia:create_table(http_bind, [{ram_copies, [node()]}, {attributes, record_info(fields, http_bind)}]), - supervisor:start_child(ejabberd_http_bind_sup, [Sid, Key]). + supervisor:start_child(ejabberd_http_bind_sup, [Sid, Rid, Key]). -start_link(Sid, Key) -> - gen_fsm:start_link(?MODULE, [Sid, Key], ?FSMOPTS). +start_link(Sid, Rid, Key) -> + gen_fsm:start_link(?MODULE, [Sid, Rid, Key], ?FSMOPTS). send({http_bind, FsmRef}, Packet) -> gen_fsm:sync_send_all_state_event(FsmRef, {send, Packet}). @@ -99,294 +95,58 @@ controlling_process(_Socket, _Pid) -> close({http_bind, FsmRef}) -> catch gen_fsm:sync_send_all_state_event(FsmRef, close). - process_request(Data) -> case catch parse_request(Data) of - {ok, {ParsedSid, Rid, Key, NewKey, Attrs, Packet}} -> - XmppDomain = xml:get_attr_s("to",Attrs), - if - (ParsedSid == "") and (XmppDomain == "") -> - {200, ?HEADER, "<body type='terminate' " - "condition='improper-addressing' " - "xmlns='http://jabber.org/protocol/httpbind'/>"}; - true -> - Sid = if - (ParsedSid == "") -> - %% create new session - NewSid = sha:sha(term_to_binary({now(), make_ref()})), - {ok, Pid} = start(NewSid, Key), - ?DEBUG("got pid: ~p", [Pid]), - Wait = case - string:to_integer(xml:get_attr_s("wait",Attrs)) - of - {error, _} -> - ?MAX_WAIT; - {CWait, _} -> - if - (CWait > ?MAX_WAIT) -> - ?MAX_WAIT; - true -> - CWait - end - end, - Hold = case - string:to_integer( - xml:get_attr_s("hold",Attrs)) - of - {error, _} -> - (?MAX_REQUESTS - 1); - {CHold, _} -> - if - (CHold > (?MAX_REQUESTS - 1)) -> - (?MAX_REQUESTS - 1); - true -> - CHold - end - end, - mnesia:transaction( - fun() -> - mnesia:write(#http_bind{id = NewSid, - pid = Pid, - to = XmppDomain, - wait = Wait, - hold = Hold}) - end), - StreamStart = if - (XmppDomain /= "") -> - true; - true -> - false - end, - InPacket = Packet, - NewSid; - true -> - %% old session - Type = xml:get_attr_s("type",Attrs), - StreamStart = - case xml:get_attr_s("xmpp:restart",Attrs) of - "true" -> - true; - _ -> - false - end, - Wait = ?MAX_WAIT, - Hold = (?MAX_REQUESTS - 1), - if - (Type == "terminate") -> - %% terminate session - InPacket = Packet ++ "</stream:stream>"; - true -> - InPacket = Packet - end, - ParsedSid - end, -%% ?DEBUG("~n InPacket: ~s ~n", [InPacket]), - case http_put(Sid, Rid, Key, NewKey, Hold, InPacket, StreamStart) of - {error, not_exists} -> - ?DEBUG("no session associated with sid: ~p", [Sid]), - {404, ?HEADER, ""}; - {error, bad_key} -> - ?DEBUG("bad key: ~s", [Key]), - case mnesia:dirty_read({http_bind, Sid}) of - [] -> - {404, ?HEADER, ""}; - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop), - {404, ?HEADER, ""} - end; - {error, polling_too_frequently} -> - ?DEBUG("polling too frequently: ~p", [Sid]), - case mnesia:dirty_read({http_bind, Sid}) of - [] -> %% unlikely! (?) - {404, ?HEADER, ""}; - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop), - {403, ?HEADER, ""} - end; - {repeat, OutPacket} -> - ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", - [OutPacket]), - send_outpacket(Sid, OutPacket); - ok -> - receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs) - end - end; + {ok, {[], Attrs, Packet}} -> %% no session id - create a new one! + ?DEBUG("no sid given. create a new session?", []), + case xml:get_attr_s("to",Attrs) of + [] -> %% missing 'to' - can't proceed + ?DEBUG("missing 'to' attribute, can't create session", []), + {200, ?HEADER, "<body type='terminate' " + "condition='improper-addressing' " + "xmlns='http://jabber.org/protocol/httpbind'/>"}; + XmppDomain -> + create_session(XmppDomain, Attrs, Packet) + end; + {ok, {Sid, Attrs, Packet}} -> + case check_request(Sid, Attrs, Packet) of + {error, not_exists} -> + ?DEBUG("no session associated with sid: ~p", [Sid]), + {404, ?HEADER, ""}; + {error, bad_key} -> + %%?DEBUG("bad key: ~s", [Key]), + case mnesia:dirty_read({http_bind, Sid}) of + [] -> + {404, ?HEADER, ""}; + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop), + {404, ?HEADER, ""} + end; + {repeat, OutPacket} -> + ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", + [OutPacket]), + send_outpacket(Sid, OutPacket); + {ok, Rid} -> + case http_put(Sid, Attrs, Packet) of + {error, polling_too_frequently} -> + ?DEBUG("polling too frequently: ~p", [Sid]), + case mnesia:dirty_read({http_bind, Sid}) of + [] -> %% unlikely! (?) + {404, ?HEADER, ""}; + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop), + {403, ?HEADER, ""} + end; + ok -> + receive_loop(Sid, Rid); + _ -> + {400, ?HEADER, ""} + end + end; _ -> {400, ?HEADER, ""} end. -receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs) -> - receive - after 100 -> ok - end, - prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs). - -prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs) -> - case http_get(Sid,Rid) of - {error, not_exists} -> - ?DEBUG("no session associated with sid: ~s", Sid), - {404, ?HEADER, ""}; - {ok, keep_on_hold} -> - receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs); - {ok, cancel} -> - %% actually it would be better if we could completely - %% cancel this request, but then we would have to hack - %% ejabberd_http and I'm too lazy now - {404, ?HEADER, ""}; - {ok, OutPacket} -> - ?DEBUG("OutPacket: ~s", [OutPacket]), - if - Sid == ParsedSid -> - send_outpacket(Sid, OutPacket); - true -> - To = xml:get_attr_s("to",Attrs), - OutEls = case xml_stream:parse_element( - OutPacket++"</stream:stream>") of - El when element(1, El) == xmlelement -> - {xmlelement, _, OutAttrs, Els} = El, - AuthID = xml:get_attr_s("id", OutAttrs), - StreamError = false, - case Els of - [] -> - []; - [{xmlelement, "stream:features", StreamAttribs, StreamEls} | StreamTail] -> - [{xmlelement, "stream:features", [{"xmlns:stream","http://etherx.jabber.org/streams"}] ++ StreamAttribs, StreamEls}] ++ StreamTail; - Xml -> - Xml - end; - {error, _} -> - AuthID = "", - StreamError = true, - [] - end, - if - To == "" -> - {200, ?HEADER, "<body type='terminate' " - "condition='improper-addressing' " - "xmlns='http://jabber.org/protocol/httpbind'/>"}; - StreamError == true -> - {200, ?HEADER, "<body type='terminate' " - "condition='host-unknown' " - "xmlns='http://jabber.org/protocol/httpbind'/>"}; - true -> - {200, ?HEADER, - xml:element_to_string( - {xmlelement,"body", - [{"xmlns", - "http://jabber.org/protocol/httpbind"}, - {"sid",Sid}, - {"wait", integer_to_list(Wait)}, - {"requests", integer_to_list(Hold+1)}, - {"inactivity", - integer_to_list(trunc(?MAX_INACTIVITY/1000))}, - {"polling", ?MIN_POLLING}, - {"authid", AuthID} - ],OutEls})} - end - end - end. - -send_outpacket(Sid, OutPacket) -> - case OutPacket of - "" -> - {200, ?HEADER, "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; - "</stream:stream>" -> - case mnesia:dirty_read({http_bind, Sid}) of - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop) - end, - {200, ?HEADER, "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; - _ -> - case xml_stream:parse_element("<body>" - ++ OutPacket - ++ "</body>") - of - El when element(1, El) == xmlelement -> - {xmlelement, _, _, OEls} = El, - TypedEls = [xml:replace_tag_attr("xmlns", - "jabber:client",OEl) || - OEl <- OEls], - ?DEBUG(" --- outgoing data --- ~n~s~n --- END --- ~n", - [xml:element_to_string( - {xmlelement,"body", - [{"xmlns", - "http://jabber.org/protocol/httpbind"}], - TypedEls})] - ), - {200, ?HEADER, - xml:element_to_string( - {xmlelement,"body", - [{"xmlns", - "http://jabber.org/protocol/httpbind"}], - TypedEls})}; - {error, _E} -> - OutEls = case xml_stream:parse_element( - OutPacket++"</stream:stream>") of - SEl when element(1, SEl) == xmlelement -> - {xmlelement, _, _OutAttrs, SEls} = SEl, - StreamError = false, - case SEls of - [] -> - []; - [{xmlelement, "stream:features", StreamAttribs, StreamEls} | StreamTail] -> - TypedTail = [xml:replace_tag_attr("xmlns", - "jabber:client",OEl) || - OEl <- StreamTail], - [{xmlelement, "stream:features", [{"xmlns:stream","http://etherx.jabber.org/streams"}] ++ StreamAttribs, StreamEls}] ++ TypedTail; - Xml -> - Xml - end; - {error, _} -> - StreamError = true, - [] - end, - if - StreamError -> - StreamErrCond = case xml_stream:parse_element( - "<stream:stream>"++OutPacket) of - El when element(1, El) == xmlelement -> - {xmlelement, _Tag, _Attr, Els} = El, - [{xmlelement, SE, _, Cond} | _] = Els, - if - SE == "stream:error" -> - Cond; - true -> - null - end; - {error, _E} -> - null - end, - case mnesia:dirty_read({http_bind, Sid}) of - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop); - _ -> - err %% hu? - end, - case StreamErrCond of - null -> - {200, ?HEADER, - "<body type='terminate' " - "condition='internal-server-error' " - "xmlns='http://jabber.org/protocol/httpbind'/>"}; - _ -> - {200, ?HEADER, - "<body type='terminate' " - "condition='remote-stream-error' " - "xmlns='http://jabber.org/protocol/httpbind'>" ++ - elements_to_string(StreamErrCond) ++ - "</body>"} - end; - true -> - {200, ?HEADER, - xml:element_to_string( - {xmlelement,"body", - [{"xmlns", - "http://jabber.org/protocol/httpbind"}], - OutEls})} - end - end - end. - %%%---------------------------------------------------------------------- %%% Callback functions from gen_fsm %%%---------------------------------------------------------------------- @@ -398,7 +158,7 @@ send_outpacket(Sid, OutPacket) -> %% ignore | %% {stop, StopReason} %%---------------------------------------------------------------------- -init([Sid, Key]) -> +init([Sid, Rid, Key]) -> ?INFO_MSG("started: ~p", [{Sid, Key}]), Opts = [], % TODO ejabberd_socket:start(ejabberd_c2s, ?MODULE, {http_bind, self()}, Opts), @@ -406,6 +166,7 @@ init([Sid, Key]) -> % ejabberd_c2s:become_controller(C2SPid), Timer = erlang:start_timer(?MAX_INACTIVITY, self(), []), {ok, loop, #state{id = Sid, + rid = Rid, key = Key, timer = Timer}}. @@ -471,57 +232,73 @@ handle_sync_event(stop, _From, _StateName, StateData) -> Reply = ok, {stop, normal, Reply, StateData}; -handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StartTo}, - _From, StateName, StateData) -> - %% check if Rid valid - RidAllow = case Rid of - error -> - false; - _ -> - case StateData#state.rid of - error -> - %% first request - nothing saved so far - true; - OldRid -> - ?DEBUG("state.rid/cur rid: ~p/~p", - [OldRid, Rid]), - if - (OldRid < Rid) and - (Rid =< (OldRid + Hold + 1)) -> - true; - (Rid =< OldRid) and - (Rid > OldRid - Hold - 1) -> - repeat; - true -> - false - end - end - end, - %% check if key valid - KeyAllow = case RidAllow of - repeat -> - true; - false -> - false; - true -> - case StateData#state.key of - "" -> - true; - OldKey -> - NextKey = httpd_util:to_lower( - hex(binary_to_list( - crypto:sha(Key)))), - ?DEBUG("Key/OldKey/NextKey: ~s/~s/~s", - [Key, OldKey, NextKey]), - if - OldKey == NextKey -> - true; - true -> - ?DEBUG("wrong key: ~s",[Key]), - false - end - end - end, +handle_sync_event({check_request, Attrs, Packet, _Hold}, + _From, check_key, StateData) -> + Key = xml:get_attr_s("key", Attrs), + case StateData#state.key of + "" -> + NewKey = xml:get_attr_s("newkey", Attrs), + {next_state, check_rid, StateData#state{key = NewKey}}; + StateKey -> + case httpd_util:to_lower( + hex(binary_to_list( + crypto:sha(Key)))) of + StateKey -> + case xml:get_attr_s("newkey", Attrs) of + "" -> + {next_state, check_rid, StateData#state{key = Key}}; + NewKey -> + {next_state, check_rid, StateData#state{key = NewKey}} + end; + _ -> + Reply = {error, bad_key}, + {reply, Reply, check_key, StateData} + end + end; + +handle_sync_event({check_request, Attrs, Packet, Hold}, + _From, check_rid = StateName, StateData) -> + case string:to_integer(xml:get_attr_s("rid", Attrs)) of + {error, _} -> + Reply = {error, not_exists}, + {reply, Reply, StateName, StateData}; + {Rid, _} -> + case StateData#state.rid of + error -> + {reply, ok, request_checked, StateData#state{rid = Rid}}; + StateRid -> + if + (StateRid < Rid) and + (Rid =< StateRid + Hold + 1) -> + {reply, {ok, Rid}, request_checked, StateData#state{rid = Rid}}; + ((StateRid-Hold-1) < Rid )and + (Rid =< StateRid) -> + %% Repeat request + [Out | _XS] = [El#hbr.out || + El <- StateData#state.req_list, + El#hbr.rid == Rid], + Reply = case Out of + [[] | OutPacket] -> + {repeat, OutPacket}; + _ -> + {repeat, Out} + end, + {reply, Reply, StateName, + StateData#state{input = "cancel"}}; + true -> + Reply = {error, not_exists}, + {reply, Reply, StateName, StateData} + end + end + end; + +handle_sync_event({check_request, Attrs, Packet, Hold}, + _From, _StateName, StateData) -> + {next_state, check_key, StateData}; + +handle_sync_event({http_put, _Rid, Attrs, Packet, Hold}, + _From, check_activity, StateData) -> + ?DEBUG("check activity", []), {_,TSec,TMSec} = now(), TNow = TSec*1000*1000 + TMSec, LastPoll = if @@ -535,98 +312,75 @@ handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StartTo}, (Packet == "") and (TNow - StateData#state.last_poll < MinPoll*1000*1000) -> Reply = {error, polling_too_frequently}, - {reply, Reply, StateName, StateData}; - KeyAllow -> - case RidAllow of - false -> - Reply = {error, not_exists}, - {reply, Reply, StateName, StateData}; - repeat -> - ?DEBUG("REPEATING ~p", [Rid]), - [Out | _XS] = [El#hbr.out || - El <- StateData#state.req_list, - El#hbr.rid == Rid], - case Out of - [[] | OutPacket] -> - Reply = {repeat, OutPacket}; - _ -> - Reply = {repeat, Out} - end, - {reply, Reply, StateName, - StateData#state{input = "cancel", last_poll = LastPoll}}; - true -> - SaveKey = if - NewKey == "" -> - Key; - true -> - NewKey - end, - ?DEBUG(" -- SaveKey: ~s~n", [SaveKey]), - - %% save request - ReqList = [#hbr{rid=Rid, - key=StateData#state.key, - in=StateData#state.input, - out=StateData#state.output - } | - [El || El <- StateData#state.req_list, - El#hbr.rid < Rid, - El#hbr.rid > (Rid - 1 - Hold)] - ], -%% ?DEBUG("reqlist: ~p", [ReqList]), - case StateData#state.waiting_input of - false -> - cancel_timer(StateData#state.timer), - Timer = erlang:start_timer( - ?MAX_INACTIVITY, self(), []), - Input = Packet ++ [StateData#state.input], - Reply = ok, - {reply, Reply, StateName, - StateData#state{input = Input, - rid = Rid, - key = SaveKey, - ctime = TNow, - timer = Timer, - last_poll = LastPoll, - req_list = ReqList - }}; - {Receiver, _Tag} -> - SendPacket = - if - StartTo /= "" -> - ["<stream:stream to='", - StartTo, - "' xmlns='jabber:client' " - "version='1.0' " - "xmlns:stream='http://etherx.jabber.org/streams'>"] ++ Packet; - true -> - Packet - end, - ?DEBUG("really sending now: ~s", [SendPacket]), - Receiver ! {tcp, {http_bind, self()}, - list_to_binary(SendPacket)}, - cancel_timer(StateData#state.timer), - Timer = erlang:start_timer( - ?MAX_INACTIVITY, self(), []), - Reply = ok, - {reply, Reply, StateName, - StateData#state{waiting_input = false, - last_receiver = Receiver, - input = "", - rid = Rid, - key = SaveKey, - ctime = TNow, - timer = Timer, - last_poll = LastPoll, - req_list = ReqList - }} - end - end; - true -> - Reply = {error, bad_key}, - {reply, Reply, StateName, StateData} + {reply, Reply, send2server, StateData}; + true -> + {next_state, send2server, StateData#state{last_poll = LastPoll}} end; +handle_sync_event({http_put, Rid, Packet, StartTo, Hold}, + _From, send2server = StateName, StateData) -> + + %% save request + ReqList = [#hbr{rid=Rid, + key=StateData#state.key, + in=StateData#state.input, + out=StateData#state.output + } | + [El || El <- StateData#state.req_list, + El#hbr.rid < Rid, + El#hbr.rid > (Rid - 1 - Hold)] + ], + + {_,TSec,TMSec} = now(), + TNow = TSec*1000*1000 + TMSec, + + case StateData#state.waiting_input of + false -> + cancel_timer(StateData#state.timer), + Timer = erlang:start_timer( + ?MAX_INACTIVITY, self(), []), + Input = Packet ++ [StateData#state.input], + Reply = ok, + {reply, Reply, StateName, + StateData#state{input = Input, + ctime = TNow, + timer = Timer, + req_list = ReqList + }}; + {Receiver, _Tag} -> + SendPacket = + if + StartTo /= "" -> + ["<stream:stream to='", + StartTo, + "' xmlns='jabber:client' " + %% version='1.0' " + "xmlns:stream='http://etherx.jabber.org/streams'>"] ++ Packet; + true -> + Packet + end, + ?DEBUG("really sending now: ~s", [SendPacket]), + Receiver ! {tcp, {http_bind, self()}, + list_to_binary(SendPacket)}, + cancel_timer(StateData#state.timer), + Timer = erlang:start_timer( + ?MAX_INACTIVITY, self(), []), + Reply = ok, + {reply, Reply, StateName, + StateData#state{waiting_input = false, + last_receiver = Receiver, + input = "", + ctime = TNow, + timer = Timer, + req_list = ReqList + }} + end; +handle_sync_event({http_put, Rid, Packet, StartTo, Hold}, + _From, StateName, StateData) -> + ?DEBUG("http-put checking acitivtiy", []), + {next_state, check_activity, StateData}; + + handle_sync_event({http_get, Rid, Wait, Hold}, _From, StateName, StateData) -> {_,TSec,TMSec} = now(), TNow = TSec*1000*1000 + TMSec, @@ -714,27 +468,251 @@ terminate(_Reason, _StateName, StateData) -> %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- +limit_val_max(Val, Max) when is_list(Val) -> + case string:to_integer(Val) of + {error, _} -> Max; + {IntVal, _} -> limit_val_max(IntVal, Max) + end; +limit_val_max(Val, Max) when is_integer(Val) and (Val =< Max) -> + Val; +limit_val_max(Val, Max) when is_integer(Val) and (Val > Max) -> + Max; +limit_val_max(_, Max) -> Max. +create_session(XmppDomain, Attrs, Packet) -> + case string:to_integer(xml:get_attr_s("rid", Attrs)) of + {error, _} -> + ?DEBUG("'rid' invalid", []), + {400, ?HEADER, ""}; + {Rid, _} -> + Sid = sha:sha(term_to_binary({now(), make_ref()})), + Key = xml:get_attr_s("key", Attrs), + {ok, Pid} = start(Sid, Rid, Key), + Wait = limit_val_max(xml:get_attr_s("wait",Attrs), ?MAX_WAIT), + Hold = limit_val_max(xml:get_attr_s("hold",Attrs), (?MAX_REQUESTS-1)), + F = fun() -> + mnesia:write( + #http_bind{id = Sid, + pid = Pid, + to = XmppDomain, + wait = Wait, + hold = Hold}) + end, + case catch mnesia:transaction(F) of + {atomic, ok} -> + ?DEBUG("created session with sid: ~s", [Sid]), + case http_put(Sid, Attrs, Packet) of + ok -> + receive_loop(Sid, Rid); + _ -> + {400, ?HEADER, ""} + end; + _E -> + ?DEBUG("error creating session: ~p", [_E]), + close({http_bind, Pid}), + {200, ?HEADER, + "<body type='terminate' " + "condition='internal-server-error' " + "xmlns='http://jabber.org/protocol/httpbind'/>"} + end + end. -http_put(Sid, Rid, Key, NewKey, Hold, Packet, Restart) -> - ?DEBUG("http-put",[]), +receive_loop(Sid, Rid) -> + receive + after 100 -> ok + end, + prepare_response(Sid, Rid). + +prepare_response(Sid, Rid) -> + case http_get(Sid,Rid) of + {error, not_exists} -> + ?DEBUG("no session associated with sid: ~s", Sid), + {404, ?HEADER, ""}; + {ok, keep_on_hold} -> + receive_loop(Sid, Rid); + {ok, cancel} -> + %% actually it would be better if we could completely + %% cancel this request, but then we would have to hack + %% ejabberd_http and I'm too lazy now + {404, ?HEADER, ""}; + {ok, OutPacket} -> + ?DEBUG("OutPacket: ~s", [OutPacket]), + send_outpacket(Sid, OutPacket); + {ok, stream_start, OutPacket} -> + ?DEBUG("OutPacket: ~s", [OutPacket]), + OutEls = case xml_stream:parse_element( + OutPacket++"</stream:stream>") of + El when element(1, El) == xmlelement -> + {xmlelement, _, OutAttrs, Els} = El, + AuthID = xml:get_attr_s("id", OutAttrs), + StreamError = false, + case Els of + [] -> + []; + [{xmlelement, "stream:features", StreamAttribs, StreamEls} | StreamTail] -> + [{xmlelement, "stream:features", [{"xmlns:stream","http://etherx.jabber.org/streams"}] ++ StreamAttribs, StreamEls}] ++ StreamTail; + Xml -> + Xml + end; + {error, _} -> + AuthID = "", + StreamError = true, + [] + end, +% To = xml:get_attr_s("to",Attrs), + if +% To == "" -> +% {200, ?HEADER, "<body type='terminate' " +% "condition='improper-addressing' " +% "xmlns='http://jabber.org/protocol/httpbind'/>"}; + StreamError == true -> + {200, ?HEADER, "<body type='terminate' " + "condition='host-unknown' " + "xmlns='http://jabber.org/protocol/httpbind'/>"}; + true -> + case mnesia:dirty_read({http_bind, Sid}) of + [#http_bind{wait = Wait, hold = Hold}] -> + {200, ?HEADER, + xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + "http://jabber.org/protocol/httpbind"}, + {"sid",Sid}, + {"wait", integer_to_list(Wait)}, + {"requests", integer_to_list(Hold+1)}, + {"inactivity", + integer_to_list(trunc(?MAX_INACTIVITY/1000))}, + {"polling", ?MIN_POLLING}, + {"authid", AuthID} + ],OutEls})}; + _ -> + {404, ?HEADER, ""} + end + end + end. + +send_outpacket(Sid, []) -> + {200, ?HEADER, "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; +send_outpacket(Sid, "</stream:stream>") -> + case mnesia:dirty_read({http_bind, Sid}) of + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop) + end, + {200, ?HEADER, "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; +send_outpacket(Sid, OutPacket) -> + case xml_stream:parse_element("<body>" + ++ OutPacket + ++ "</body>") of + El when element(1, El) == xmlelement -> + {xmlelement, _, _, OEls} = El, + TypedEls = [xml:replace_tag_attr("xmlns", + "jabber:client",OEl) || + OEl <- OEls], + ?DEBUG(" --- outgoing data --- ~n~s~n --- END --- ~n", + [xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + "http://jabber.org/protocol/httpbind"}], + TypedEls})] + ), + {200, ?HEADER, + xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + "http://jabber.org/protocol/httpbind"}], + TypedEls})}; + {error, _E} -> + OutEls = case xml_stream:parse_element( + OutPacket++"</stream:stream>") of + SEl when element(1, SEl) == xmlelement -> + {xmlelement, _, _OutAttrs, SEls} = SEl, + StreamError = false, + case SEls of + [] -> + []; + [{xmlelement, "stream:features", StreamAttribs, StreamEls} | StreamTail] -> + TypedTail = [xml:replace_tag_attr("xmlns", + "jabber:client",OEl) || + OEl <- StreamTail], + [{xmlelement, "stream:features", [{"xmlns:stream","http://etherx.jabber.org/streams"}] ++ StreamAttribs, StreamEls}] ++ TypedTail; + Xml -> + Xml + end; + {error, _} -> + StreamError = true, + [] + end, + if + StreamError -> + StreamErrCond = case xml_stream:parse_element( + "<stream:stream>"++OutPacket) of + El when element(1, El) == xmlelement -> + {xmlelement, _Tag, _Attr, Els} = El, + [{xmlelement, SE, _, Cond} | _] = Els, + if + SE == "stream:error" -> + Cond; + true -> + null + end; + {error, _E} -> + null + end, + case mnesia:dirty_read({http_bind, Sid}) of + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop); + _ -> + err %% hu? + end, + case StreamErrCond of + null -> + {200, ?HEADER, + "<body type='terminate' " + "condition='internal-server-error' " + "xmlns='http://jabber.org/protocol/httpbind'/>"}; + _ -> + {200, ?HEADER, + "<body type='terminate' " + "condition='remote-stream-error' " + "xmlns='http://jabber.org/protocol/httpbind'>" ++ + elements_to_string(StreamErrCond) ++ + "</body>"} + end; + true -> + {200, ?HEADER, + xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + "http://jabber.org/protocol/httpbind"}], + OutEls})} + end + end. + +check_request(Sid, Attrs, Packet) -> case mnesia:dirty_read({http_bind, Sid}) of [] -> ?DEBUG("not found",[]), {error, not_exists}; - [#http_bind{pid = FsmRef,to=To}] -> - case Restart of - true -> - ?DEBUG("restart requested for ~s", [To]), - gen_fsm:sync_send_all_state_event( - FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, To}); - _ -> - gen_fsm:sync_send_all_state_event( - FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, ""}) - end + [#http_bind{pid = FsmRef, hold = Hold}] -> + gen_fsm:sync_send_all_state_event( + FsmRef, {http_put, Attrs, Packet, Hold}) + end. + + +http_put(Sid, Attrs, Packet) -> + ?DEBUG("http-put",[]), + {Rid, _} = string:to_integer(xml:get_attr_s("rid", Attrs)), + To = xml:get_attr_s("to", Attrs), + case mnesia:dirty_read({http_bind, Sid}) of + [] -> + ?DEBUG("not found",[]), + {error, not_exists}; + [#http_bind{pid = FsmRef, to = To, hold = Hold}] -> + gen_fsm:sync_send_all_state_event( + FsmRef, {http_put, Rid, Packet, To, Hold}) end. -http_get(Sid,Rid) -> +http_get(Sid, Rid) -> case mnesia:dirty_read({http_bind, Sid}) of [] -> {error, not_exists}; @@ -747,43 +725,39 @@ http_get(Sid,Rid) -> parse_request(Data) -> ?DEBUG("--- incoming data --- ~n~s~n --- END --- ", [Data]), - case xml_stream:parse_element(Data) of - El when element(1, El) == xmlelement -> - {xmlelement, Name, Attrs, Els} = El, - FixedEls = - lists:filter( - fun(I) -> - case I of - {xmlelement, _, _, _} -> - true; - _ -> - false - end - end, Els), - Sid = xml:get_attr_s("sid",Attrs), - {Rid,_X} = string:to_integer(xml:get_attr_s("rid",Attrs)), - Key = xml:get_attr_s("key",Attrs), - NewKey = xml:get_attr_s("newkey",Attrs), - Xmlns = xml:get_attr_s("xmlns",Attrs), - lists:map(fun(E) -> - EXmlns = xml:get_tag_attr_s("xmlns",E), - if - EXmlns == "jabber:client" -> - remove_tag_attr("xmlns",E); - true -> - ok - end - end, FixedEls), - Packet = [xml:element_to_string(E) || E <- FixedEls], - if - Name /= "body" -> - {error, bad_request}; - Xmlns /= "http://jabber.org/protocol/httpbind" -> - {error, bad_request}; - true -> - {ok, {Sid, Rid, Key, NewKey, Attrs, Packet}} - end; - {error, _Reason} -> + case catch xml_stream:parse_element(Data) of + {xmlelement, "body", Attrs, Els} -> + case xml:get_attr_s("xmlns",Attrs) of + "http://jabber.org/protocol/httpbind" -> + Sid = xml:get_attr_s("sid",Attrs), + %% normalize tree - actually not needed by XEP but + %% where playing nicely here + FixedEls = + lists:filter( + fun(I) -> + case I of + {xmlelement, _, _, _} -> + true; + _ -> + false + end + end, Els), + %% fix namespace of child element + lists:map(fun(E) -> + case xml:get_tag_attr_s("xmlns",E) of + "jabber:client" -> + remove_tag_attr("xmlns",E); + true -> + ok + end + end, FixedEls), + %% revert to string + Packet = [xml:element_to_string(E) || E <- FixedEls], + {ok, {Sid, Attrs, Packet}}; + _ -> %% bad namespace + {error, bad_request} + end; + _ -> {error, bad_request} end. diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index 1cebd0f5e..989d025e3 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -3,7 +3,6 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : Implementation of XMPP over BOSH (XEP-0206) %%% Created : Tue Feb 20 13:15:52 CET 2007 -%%% Id : $Id: $ %%%---------------------------------------------------------------------- %%%---------------------------------------------------------------------- @@ -15,7 +14,7 @@ -module(mod_http_bind). -author('steve@zeank.in-berlin.de'). --define(MOD_HTTP_BIND_VERSION, "1.0"). +-define(MOD_HTTP_BIND_VERSION, '1.0'). -vsn(?MOD_HTTP_BIND_VERSION). %%-define(ejabberd_debug, true). @@ -48,7 +47,7 @@ process([], #request{method = 'POST', ejabberd_http_bind:process_request(Data); process([], #request{method = 'GET', data = []}) -> - Heading = "Ejabberd " ++ atom_to_list(?MODULE) ++ " v" ++ ?MOD_HTTP_BIND_VERSION, + Heading = "Ejabberd " ++ atom_to_list(?MODULE) ++ " v" ++ lists:concat([?MOD_HTTP_BIND_VERSION]), {xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}], [{xmlelement, "head", [], [{xmlelement, "title", [], [{xmlcdata, Heading}]}]}, @@ -57,21 +56,16 @@ process([], #request{method = 'GET', {xmlelement, "p", [], [{xmlcdata, "An implementation of "}, {xmlelement, "a", [{"href", "http://www.xmpp.org/extensions/xep-0206.html"}], - [{xmlcdata, "XMPP over BOSH (XEP-0206)"}]}]}, + [{xmlcdata, "XMPP over BOSH (XEP-0206)"}]}, + {xmlcdata, "."}]}, {xmlelement, "p", [], - [{xmlcdata, integer_to_list(mnesia:table_info(http_bind, size)) ++ " sessions found."}]}, - {xmlelement, "p", [], - [{xmlcdata, "Sponsored by "}, - {xmlelement, "a", [{"href", "http://mabber.com"}], - [{xmlcdata, "mabber"}]}, - {xmlcdata, "."}]} - ]}]}; + [{xmlcdata, integer_to_list(mnesia:table_info(http_bind, size)) ++ " sessions found."}]} + ]}]}; process(_Path, _Request) -> ?DEBUG("Bad Request: ~p", [_Request]), {400, [], {xmlelement, "h1", [], [{xmlcdata, "400 Bad Request"}]}}. - %%%---------------------------------------------------------------------- %%% BEHAVIOUR CALLBACKS %%%---------------------------------------------------------------------- From 832d59803aa72c0fcf0fdf0937eaea0a756d0fbc Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:24:18 +0000 Subject: [PATCH 385/582] Reverted to r76 as 97 is completely broken and should not have been checked in at all (thanks to Stefan Strigler) SVN Revision: 2270 --- src/web/ejabberd_http_bind.erl | 950 +++++++++++++++++---------------- src/web/mod_http_bind.erl | 18 +- 2 files changed, 500 insertions(+), 468 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 0cbe40e86..d16a5d0c4 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -3,16 +3,17 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : HTTP Binding support (JEP-0124) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> +%%% Id : $Id: $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('1.9'). +-vsn('Revision: 1.4'). -behaviour(gen_fsm). %% External exports --export([start_link/3, +-export([start_link/2, init/1, handle_event/3, handle_sync_event/4, @@ -25,7 +26,7 @@ close/1, process_request/1]). --define(ejabberd_debug, true). +%%-define(ejabberd_debug, true). -include("ejabberd.hrl"). -include("jlib.hrl"). @@ -34,7 +35,10 @@ -record(http_bind, {id, pid, to, hold, wait}). %% http binding request --record(hbr, {rid, key, in, out}). +-record(hbr, {rid, + key, + in, + out}). -record(state, {id, rid = error, @@ -49,7 +53,8 @@ req_list = [] % list of requests }). --define(DBGFSM, true). + +%%-define(DBGFSM, true). -ifdef(DBGFSM). -define(FSMOPTS, [{debug, [trace]}]). @@ -57,8 +62,6 @@ -define(FSMOPTS, []). -endif. --define(BOSH_VERSION, "1.6"). - -define(MAX_REQUESTS, 2). % number of simultaneous requests -define(MIN_POLLING, "2"). % don't poll faster than that or we will shoot you -define(MAX_WAIT, 3600). % max num of secs to keep a request on hold @@ -66,17 +69,18 @@ -define(CT, {"Content-Type", "text/xml; charset=utf-8"}). -define(HEADER, [?CT,{"X-Sponsored-By", "http://mabber.com"}]). + %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- -start(Sid, Rid, Key) -> +start(Sid, Key) -> mnesia:create_table(http_bind, [{ram_copies, [node()]}, {attributes, record_info(fields, http_bind)}]), - supervisor:start_child(ejabberd_http_bind_sup, [Sid, Rid, Key]). + supervisor:start_child(ejabberd_http_bind_sup, [Sid, Key]). -start_link(Sid, Rid, Key) -> - gen_fsm:start_link(?MODULE, [Sid, Rid, Key], ?FSMOPTS). +start_link(Sid, Key) -> + gen_fsm:start_link(?MODULE, [Sid, Key], ?FSMOPTS). send({http_bind, FsmRef}, Packet) -> gen_fsm:sync_send_all_state_event(FsmRef, {send, Packet}). @@ -95,58 +99,294 @@ controlling_process(_Socket, _Pid) -> close({http_bind, FsmRef}) -> catch gen_fsm:sync_send_all_state_event(FsmRef, close). + process_request(Data) -> case catch parse_request(Data) of - {ok, {[], Attrs, Packet}} -> %% no session id - create a new one! - ?DEBUG("no sid given. create a new session?", []), - case xml:get_attr_s("to",Attrs) of - [] -> %% missing 'to' - can't proceed - ?DEBUG("missing 'to' attribute, can't create session", []), - {200, ?HEADER, "<body type='terminate' " - "condition='improper-addressing' " - "xmlns='http://jabber.org/protocol/httpbind'/>"}; - XmppDomain -> - create_session(XmppDomain, Attrs, Packet) - end; - {ok, {Sid, Attrs, Packet}} -> - case check_request(Sid, Attrs, Packet) of - {error, not_exists} -> - ?DEBUG("no session associated with sid: ~p", [Sid]), - {404, ?HEADER, ""}; - {error, bad_key} -> - %%?DEBUG("bad key: ~s", [Key]), - case mnesia:dirty_read({http_bind, Sid}) of - [] -> - {404, ?HEADER, ""}; - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop), - {404, ?HEADER, ""} - end; - {repeat, OutPacket} -> - ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", - [OutPacket]), - send_outpacket(Sid, OutPacket); - {ok, Rid} -> - case http_put(Sid, Attrs, Packet) of - {error, polling_too_frequently} -> - ?DEBUG("polling too frequently: ~p", [Sid]), - case mnesia:dirty_read({http_bind, Sid}) of - [] -> %% unlikely! (?) - {404, ?HEADER, ""}; - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop), - {403, ?HEADER, ""} - end; - ok -> - receive_loop(Sid, Rid); - _ -> - {400, ?HEADER, ""} - end - end; + {ok, {ParsedSid, Rid, Key, NewKey, Attrs, Packet}} -> + XmppDomain = xml:get_attr_s("to",Attrs), + if + (ParsedSid == "") and (XmppDomain == "") -> + {200, ?HEADER, "<body type='terminate' " + "condition='improper-addressing' " + "xmlns='http://jabber.org/protocol/httpbind'/>"}; + true -> + Sid = if + (ParsedSid == "") -> + %% create new session + NewSid = sha:sha(term_to_binary({now(), make_ref()})), + {ok, Pid} = start(NewSid, Key), + ?DEBUG("got pid: ~p", [Pid]), + Wait = case + string:to_integer(xml:get_attr_s("wait",Attrs)) + of + {error, _} -> + ?MAX_WAIT; + {CWait, _} -> + if + (CWait > ?MAX_WAIT) -> + ?MAX_WAIT; + true -> + CWait + end + end, + Hold = case + string:to_integer( + xml:get_attr_s("hold",Attrs)) + of + {error, _} -> + (?MAX_REQUESTS - 1); + {CHold, _} -> + if + (CHold > (?MAX_REQUESTS - 1)) -> + (?MAX_REQUESTS - 1); + true -> + CHold + end + end, + mnesia:transaction( + fun() -> + mnesia:write(#http_bind{id = NewSid, + pid = Pid, + to = XmppDomain, + wait = Wait, + hold = Hold}) + end), + StreamStart = if + (XmppDomain /= "") -> + true; + true -> + false + end, + InPacket = Packet, + NewSid; + true -> + %% old session + Type = xml:get_attr_s("type",Attrs), + StreamStart = + case xml:get_attr_s("xmpp:restart",Attrs) of + "true" -> + true; + _ -> + false + end, + Wait = ?MAX_WAIT, + Hold = (?MAX_REQUESTS - 1), + if + (Type == "terminate") -> + %% terminate session + InPacket = Packet ++ "</stream:stream>"; + true -> + InPacket = Packet + end, + ParsedSid + end, +%% ?DEBUG("~n InPacket: ~s ~n", [InPacket]), + case http_put(Sid, Rid, Key, NewKey, Hold, InPacket, StreamStart) of + {error, not_exists} -> + ?DEBUG("no session associated with sid: ~p", [Sid]), + {404, ?HEADER, ""}; + {error, bad_key} -> + ?DEBUG("bad key: ~s", [Key]), + case mnesia:dirty_read({http_bind, Sid}) of + [] -> + {404, ?HEADER, ""}; + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop), + {404, ?HEADER, ""} + end; + {error, polling_too_frequently} -> + ?DEBUG("polling too frequently: ~p", [Sid]), + case mnesia:dirty_read({http_bind, Sid}) of + [] -> %% unlikely! (?) + {404, ?HEADER, ""}; + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop), + {403, ?HEADER, ""} + end; + {repeat, OutPacket} -> + ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", + [OutPacket]), + send_outpacket(Sid, OutPacket); + ok -> + receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs) + end + end; _ -> {400, ?HEADER, ""} end. +receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs) -> + receive + after 100 -> ok + end, + prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs). + +prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs) -> + case http_get(Sid,Rid) of + {error, not_exists} -> + ?DEBUG("no session associated with sid: ~s", Sid), + {404, ?HEADER, ""}; + {ok, keep_on_hold} -> + receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs); + {ok, cancel} -> + %% actually it would be better if we could completely + %% cancel this request, but then we would have to hack + %% ejabberd_http and I'm too lazy now + {404, ?HEADER, ""}; + {ok, OutPacket} -> + ?DEBUG("OutPacket: ~s", [OutPacket]), + if + Sid == ParsedSid -> + send_outpacket(Sid, OutPacket); + true -> + To = xml:get_attr_s("to",Attrs), + OutEls = case xml_stream:parse_element( + OutPacket++"</stream:stream>") of + El when element(1, El) == xmlelement -> + {xmlelement, _, OutAttrs, Els} = El, + AuthID = xml:get_attr_s("id", OutAttrs), + StreamError = false, + case Els of + [] -> + []; + [{xmlelement, "stream:features", StreamAttribs, StreamEls} | StreamTail] -> + [{xmlelement, "stream:features", [{"xmlns:stream","http://etherx.jabber.org/streams"}] ++ StreamAttribs, StreamEls}] ++ StreamTail; + Xml -> + Xml + end; + {error, _} -> + AuthID = "", + StreamError = true, + [] + end, + if + To == "" -> + {200, ?HEADER, "<body type='terminate' " + "condition='improper-addressing' " + "xmlns='http://jabber.org/protocol/httpbind'/>"}; + StreamError == true -> + {200, ?HEADER, "<body type='terminate' " + "condition='host-unknown' " + "xmlns='http://jabber.org/protocol/httpbind'/>"}; + true -> + {200, ?HEADER, + xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + "http://jabber.org/protocol/httpbind"}, + {"sid",Sid}, + {"wait", integer_to_list(Wait)}, + {"requests", integer_to_list(Hold+1)}, + {"inactivity", + integer_to_list(trunc(?MAX_INACTIVITY/1000))}, + {"polling", ?MIN_POLLING}, + {"authid", AuthID} + ],OutEls})} + end + end + end. + +send_outpacket(Sid, OutPacket) -> + case OutPacket of + "" -> + {200, ?HEADER, "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; + "</stream:stream>" -> + case mnesia:dirty_read({http_bind, Sid}) of + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop) + end, + {200, ?HEADER, "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; + _ -> + case xml_stream:parse_element("<body>" + ++ OutPacket + ++ "</body>") + of + El when element(1, El) == xmlelement -> + {xmlelement, _, _, OEls} = El, + TypedEls = [xml:replace_tag_attr("xmlns", + "jabber:client",OEl) || + OEl <- OEls], + ?DEBUG(" --- outgoing data --- ~n~s~n --- END --- ~n", + [xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + "http://jabber.org/protocol/httpbind"}], + TypedEls})] + ), + {200, ?HEADER, + xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + "http://jabber.org/protocol/httpbind"}], + TypedEls})}; + {error, _E} -> + OutEls = case xml_stream:parse_element( + OutPacket++"</stream:stream>") of + SEl when element(1, SEl) == xmlelement -> + {xmlelement, _, _OutAttrs, SEls} = SEl, + StreamError = false, + case SEls of + [] -> + []; + [{xmlelement, "stream:features", StreamAttribs, StreamEls} | StreamTail] -> + TypedTail = [xml:replace_tag_attr("xmlns", + "jabber:client",OEl) || + OEl <- StreamTail], + [{xmlelement, "stream:features", [{"xmlns:stream","http://etherx.jabber.org/streams"}] ++ StreamAttribs, StreamEls}] ++ TypedTail; + Xml -> + Xml + end; + {error, _} -> + StreamError = true, + [] + end, + if + StreamError -> + StreamErrCond = case xml_stream:parse_element( + "<stream:stream>"++OutPacket) of + El when element(1, El) == xmlelement -> + {xmlelement, _Tag, _Attr, Els} = El, + [{xmlelement, SE, _, Cond} | _] = Els, + if + SE == "stream:error" -> + Cond; + true -> + null + end; + {error, _E} -> + null + end, + case mnesia:dirty_read({http_bind, Sid}) of + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop); + _ -> + err %% hu? + end, + case StreamErrCond of + null -> + {200, ?HEADER, + "<body type='terminate' " + "condition='internal-server-error' " + "xmlns='http://jabber.org/protocol/httpbind'/>"}; + _ -> + {200, ?HEADER, + "<body type='terminate' " + "condition='remote-stream-error' " + "xmlns='http://jabber.org/protocol/httpbind'>" ++ + elements_to_string(StreamErrCond) ++ + "</body>"} + end; + true -> + {200, ?HEADER, + xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + "http://jabber.org/protocol/httpbind"}], + OutEls})} + end + end + end. + %%%---------------------------------------------------------------------- %%% Callback functions from gen_fsm %%%---------------------------------------------------------------------- @@ -158,7 +398,7 @@ process_request(Data) -> %% ignore | %% {stop, StopReason} %%---------------------------------------------------------------------- -init([Sid, Rid, Key]) -> +init([Sid, Key]) -> ?INFO_MSG("started: ~p", [{Sid, Key}]), Opts = [], % TODO ejabberd_socket:start(ejabberd_c2s, ?MODULE, {http_bind, self()}, Opts), @@ -166,7 +406,6 @@ init([Sid, Rid, Key]) -> % ejabberd_c2s:become_controller(C2SPid), Timer = erlang:start_timer(?MAX_INACTIVITY, self(), []), {ok, loop, #state{id = Sid, - rid = Rid, key = Key, timer = Timer}}. @@ -232,73 +471,57 @@ handle_sync_event(stop, _From, _StateName, StateData) -> Reply = ok, {stop, normal, Reply, StateData}; -handle_sync_event({check_request, Attrs, Packet, _Hold}, - _From, check_key, StateData) -> - Key = xml:get_attr_s("key", Attrs), - case StateData#state.key of - "" -> - NewKey = xml:get_attr_s("newkey", Attrs), - {next_state, check_rid, StateData#state{key = NewKey}}; - StateKey -> - case httpd_util:to_lower( - hex(binary_to_list( - crypto:sha(Key)))) of - StateKey -> - case xml:get_attr_s("newkey", Attrs) of - "" -> - {next_state, check_rid, StateData#state{key = Key}}; - NewKey -> - {next_state, check_rid, StateData#state{key = NewKey}} - end; - _ -> - Reply = {error, bad_key}, - {reply, Reply, check_key, StateData} - end - end; - -handle_sync_event({check_request, Attrs, Packet, Hold}, - _From, check_rid = StateName, StateData) -> - case string:to_integer(xml:get_attr_s("rid", Attrs)) of - {error, _} -> - Reply = {error, not_exists}, - {reply, Reply, StateName, StateData}; - {Rid, _} -> - case StateData#state.rid of - error -> - {reply, ok, request_checked, StateData#state{rid = Rid}}; - StateRid -> - if - (StateRid < Rid) and - (Rid =< StateRid + Hold + 1) -> - {reply, {ok, Rid}, request_checked, StateData#state{rid = Rid}}; - ((StateRid-Hold-1) < Rid )and - (Rid =< StateRid) -> - %% Repeat request - [Out | _XS] = [El#hbr.out || - El <- StateData#state.req_list, - El#hbr.rid == Rid], - Reply = case Out of - [[] | OutPacket] -> - {repeat, OutPacket}; - _ -> - {repeat, Out} - end, - {reply, Reply, StateName, - StateData#state{input = "cancel"}}; - true -> - Reply = {error, not_exists}, - {reply, Reply, StateName, StateData} - end - end - end; - -handle_sync_event({check_request, Attrs, Packet, Hold}, - _From, _StateName, StateData) -> - {next_state, check_key, StateData}; - -handle_sync_event({http_put, _Rid, Attrs, Packet, Hold}, - _From, check_activity, StateData) -> - ?DEBUG("check activity", []), +handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StartTo}, + _From, StateName, StateData) -> + %% check if Rid valid + RidAllow = case Rid of + error -> + false; + _ -> + case StateData#state.rid of + error -> + %% first request - nothing saved so far + true; + OldRid -> + ?DEBUG("state.rid/cur rid: ~p/~p", + [OldRid, Rid]), + if + (OldRid < Rid) and + (Rid =< (OldRid + Hold + 1)) -> + true; + (Rid =< OldRid) and + (Rid > OldRid - Hold - 1) -> + repeat; + true -> + false + end + end + end, + %% check if key valid + KeyAllow = case RidAllow of + repeat -> + true; + false -> + false; + true -> + case StateData#state.key of + "" -> + true; + OldKey -> + NextKey = httpd_util:to_lower( + hex(binary_to_list( + crypto:sha(Key)))), + ?DEBUG("Key/OldKey/NextKey: ~s/~s/~s", + [Key, OldKey, NextKey]), + if + OldKey == NextKey -> + true; + true -> + ?DEBUG("wrong key: ~s",[Key]), + false + end + end + end, {_,TSec,TMSec} = now(), TNow = TSec*1000*1000 + TMSec, LastPoll = if @@ -312,75 +535,98 @@ handle_sync_event({http_put, _Rid, Attrs, Packet, Hold}, (Packet == "") and (TNow - StateData#state.last_poll < MinPoll*1000*1000) -> Reply = {error, polling_too_frequently}, - {reply, Reply, send2server, StateData}; - true -> - {next_state, send2server, StateData#state{last_poll = LastPoll}} + {reply, Reply, StateName, StateData}; + KeyAllow -> + case RidAllow of + false -> + Reply = {error, not_exists}, + {reply, Reply, StateName, StateData}; + repeat -> + ?DEBUG("REPEATING ~p", [Rid]), + [Out | _XS] = [El#hbr.out || + El <- StateData#state.req_list, + El#hbr.rid == Rid], + case Out of + [[] | OutPacket] -> + Reply = {repeat, OutPacket}; + _ -> + Reply = {repeat, Out} + end, + {reply, Reply, StateName, + StateData#state{input = "cancel", last_poll = LastPoll}}; + true -> + SaveKey = if + NewKey == "" -> + Key; + true -> + NewKey + end, + ?DEBUG(" -- SaveKey: ~s~n", [SaveKey]), + + %% save request + ReqList = [#hbr{rid=Rid, + key=StateData#state.key, + in=StateData#state.input, + out=StateData#state.output + } | + [El || El <- StateData#state.req_list, + El#hbr.rid < Rid, + El#hbr.rid > (Rid - 1 - Hold)] + ], +%% ?DEBUG("reqlist: ~p", [ReqList]), + case StateData#state.waiting_input of + false -> + cancel_timer(StateData#state.timer), + Timer = erlang:start_timer( + ?MAX_INACTIVITY, self(), []), + Input = Packet ++ [StateData#state.input], + Reply = ok, + {reply, Reply, StateName, + StateData#state{input = Input, + rid = Rid, + key = SaveKey, + ctime = TNow, + timer = Timer, + last_poll = LastPoll, + req_list = ReqList + }}; + {Receiver, _Tag} -> + SendPacket = + if + StartTo /= "" -> + ["<stream:stream to='", + StartTo, + "' xmlns='jabber:client' " + "version='1.0' " + "xmlns:stream='http://etherx.jabber.org/streams'>"] ++ Packet; + true -> + Packet + end, + ?DEBUG("really sending now: ~s", [SendPacket]), + Receiver ! {tcp, {http_bind, self()}, + list_to_binary(SendPacket)}, + cancel_timer(StateData#state.timer), + Timer = erlang:start_timer( + ?MAX_INACTIVITY, self(), []), + Reply = ok, + {reply, Reply, StateName, + StateData#state{waiting_input = false, + last_receiver = Receiver, + input = "", + rid = Rid, + key = SaveKey, + ctime = TNow, + timer = Timer, + last_poll = LastPoll, + req_list = ReqList + }} + end + end; + true -> + Reply = {error, bad_key}, + {reply, Reply, StateName, StateData} end; -handle_sync_event({http_put, Rid, Packet, StartTo, Hold}, - _From, send2server = StateName, StateData) -> - - %% save request - ReqList = [#hbr{rid=Rid, - key=StateData#state.key, - in=StateData#state.input, - out=StateData#state.output - } | - [El || El <- StateData#state.req_list, - El#hbr.rid < Rid, - El#hbr.rid > (Rid - 1 - Hold)] - ], - - {_,TSec,TMSec} = now(), - TNow = TSec*1000*1000 + TMSec, - - case StateData#state.waiting_input of - false -> - cancel_timer(StateData#state.timer), - Timer = erlang:start_timer( - ?MAX_INACTIVITY, self(), []), - Input = Packet ++ [StateData#state.input], - Reply = ok, - {reply, Reply, StateName, - StateData#state{input = Input, - ctime = TNow, - timer = Timer, - req_list = ReqList - }}; - {Receiver, _Tag} -> - SendPacket = - if - StartTo /= "" -> - ["<stream:stream to='", - StartTo, - "' xmlns='jabber:client' " - %% version='1.0' " - "xmlns:stream='http://etherx.jabber.org/streams'>"] ++ Packet; - true -> - Packet - end, - ?DEBUG("really sending now: ~s", [SendPacket]), - Receiver ! {tcp, {http_bind, self()}, - list_to_binary(SendPacket)}, - cancel_timer(StateData#state.timer), - Timer = erlang:start_timer( - ?MAX_INACTIVITY, self(), []), - Reply = ok, - {reply, Reply, StateName, - StateData#state{waiting_input = false, - last_receiver = Receiver, - input = "", - ctime = TNow, - timer = Timer, - req_list = ReqList - }} - end; -handle_sync_event({http_put, Rid, Packet, StartTo, Hold}, - _From, StateName, StateData) -> - ?DEBUG("http-put checking acitivtiy", []), - {next_state, check_activity, StateData}; - - handle_sync_event({http_get, Rid, Wait, Hold}, _From, StateName, StateData) -> {_,TSec,TMSec} = now(), TNow = TSec*1000*1000 + TMSec, @@ -468,251 +714,27 @@ terminate(_Reason, _StateName, StateData) -> %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- -limit_val_max(Val, Max) when is_list(Val) -> - case string:to_integer(Val) of - {error, _} -> Max; - {IntVal, _} -> limit_val_max(IntVal, Max) - end; -limit_val_max(Val, Max) when is_integer(Val) and (Val =< Max) -> - Val; -limit_val_max(Val, Max) when is_integer(Val) and (Val > Max) -> - Max; -limit_val_max(_, Max) -> Max. -create_session(XmppDomain, Attrs, Packet) -> - case string:to_integer(xml:get_attr_s("rid", Attrs)) of - {error, _} -> - ?DEBUG("'rid' invalid", []), - {400, ?HEADER, ""}; - {Rid, _} -> - Sid = sha:sha(term_to_binary({now(), make_ref()})), - Key = xml:get_attr_s("key", Attrs), - {ok, Pid} = start(Sid, Rid, Key), - Wait = limit_val_max(xml:get_attr_s("wait",Attrs), ?MAX_WAIT), - Hold = limit_val_max(xml:get_attr_s("hold",Attrs), (?MAX_REQUESTS-1)), - F = fun() -> - mnesia:write( - #http_bind{id = Sid, - pid = Pid, - to = XmppDomain, - wait = Wait, - hold = Hold}) - end, - case catch mnesia:transaction(F) of - {atomic, ok} -> - ?DEBUG("created session with sid: ~s", [Sid]), - case http_put(Sid, Attrs, Packet) of - ok -> - receive_loop(Sid, Rid); - _ -> - {400, ?HEADER, ""} - end; - _E -> - ?DEBUG("error creating session: ~p", [_E]), - close({http_bind, Pid}), - {200, ?HEADER, - "<body type='terminate' " - "condition='internal-server-error' " - "xmlns='http://jabber.org/protocol/httpbind'/>"} - end - end. -receive_loop(Sid, Rid) -> - receive - after 100 -> ok - end, - prepare_response(Sid, Rid). - -prepare_response(Sid, Rid) -> - case http_get(Sid,Rid) of - {error, not_exists} -> - ?DEBUG("no session associated with sid: ~s", Sid), - {404, ?HEADER, ""}; - {ok, keep_on_hold} -> - receive_loop(Sid, Rid); - {ok, cancel} -> - %% actually it would be better if we could completely - %% cancel this request, but then we would have to hack - %% ejabberd_http and I'm too lazy now - {404, ?HEADER, ""}; - {ok, OutPacket} -> - ?DEBUG("OutPacket: ~s", [OutPacket]), - send_outpacket(Sid, OutPacket); - {ok, stream_start, OutPacket} -> - ?DEBUG("OutPacket: ~s", [OutPacket]), - OutEls = case xml_stream:parse_element( - OutPacket++"</stream:stream>") of - El when element(1, El) == xmlelement -> - {xmlelement, _, OutAttrs, Els} = El, - AuthID = xml:get_attr_s("id", OutAttrs), - StreamError = false, - case Els of - [] -> - []; - [{xmlelement, "stream:features", StreamAttribs, StreamEls} | StreamTail] -> - [{xmlelement, "stream:features", [{"xmlns:stream","http://etherx.jabber.org/streams"}] ++ StreamAttribs, StreamEls}] ++ StreamTail; - Xml -> - Xml - end; - {error, _} -> - AuthID = "", - StreamError = true, - [] - end, -% To = xml:get_attr_s("to",Attrs), - if -% To == "" -> -% {200, ?HEADER, "<body type='terminate' " -% "condition='improper-addressing' " -% "xmlns='http://jabber.org/protocol/httpbind'/>"}; - StreamError == true -> - {200, ?HEADER, "<body type='terminate' " - "condition='host-unknown' " - "xmlns='http://jabber.org/protocol/httpbind'/>"}; - true -> - case mnesia:dirty_read({http_bind, Sid}) of - [#http_bind{wait = Wait, hold = Hold}] -> - {200, ?HEADER, - xml:element_to_string( - {xmlelement,"body", - [{"xmlns", - "http://jabber.org/protocol/httpbind"}, - {"sid",Sid}, - {"wait", integer_to_list(Wait)}, - {"requests", integer_to_list(Hold+1)}, - {"inactivity", - integer_to_list(trunc(?MAX_INACTIVITY/1000))}, - {"polling", ?MIN_POLLING}, - {"authid", AuthID} - ],OutEls})}; - _ -> - {404, ?HEADER, ""} - end - end - end. - -send_outpacket(Sid, []) -> - {200, ?HEADER, "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; -send_outpacket(Sid, "</stream:stream>") -> - case mnesia:dirty_read({http_bind, Sid}) of - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop) - end, - {200, ?HEADER, "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; -send_outpacket(Sid, OutPacket) -> - case xml_stream:parse_element("<body>" - ++ OutPacket - ++ "</body>") of - El when element(1, El) == xmlelement -> - {xmlelement, _, _, OEls} = El, - TypedEls = [xml:replace_tag_attr("xmlns", - "jabber:client",OEl) || - OEl <- OEls], - ?DEBUG(" --- outgoing data --- ~n~s~n --- END --- ~n", - [xml:element_to_string( - {xmlelement,"body", - [{"xmlns", - "http://jabber.org/protocol/httpbind"}], - TypedEls})] - ), - {200, ?HEADER, - xml:element_to_string( - {xmlelement,"body", - [{"xmlns", - "http://jabber.org/protocol/httpbind"}], - TypedEls})}; - {error, _E} -> - OutEls = case xml_stream:parse_element( - OutPacket++"</stream:stream>") of - SEl when element(1, SEl) == xmlelement -> - {xmlelement, _, _OutAttrs, SEls} = SEl, - StreamError = false, - case SEls of - [] -> - []; - [{xmlelement, "stream:features", StreamAttribs, StreamEls} | StreamTail] -> - TypedTail = [xml:replace_tag_attr("xmlns", - "jabber:client",OEl) || - OEl <- StreamTail], - [{xmlelement, "stream:features", [{"xmlns:stream","http://etherx.jabber.org/streams"}] ++ StreamAttribs, StreamEls}] ++ TypedTail; - Xml -> - Xml - end; - {error, _} -> - StreamError = true, - [] - end, - if - StreamError -> - StreamErrCond = case xml_stream:parse_element( - "<stream:stream>"++OutPacket) of - El when element(1, El) == xmlelement -> - {xmlelement, _Tag, _Attr, Els} = El, - [{xmlelement, SE, _, Cond} | _] = Els, - if - SE == "stream:error" -> - Cond; - true -> - null - end; - {error, _E} -> - null - end, - case mnesia:dirty_read({http_bind, Sid}) of - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop); - _ -> - err %% hu? - end, - case StreamErrCond of - null -> - {200, ?HEADER, - "<body type='terminate' " - "condition='internal-server-error' " - "xmlns='http://jabber.org/protocol/httpbind'/>"}; - _ -> - {200, ?HEADER, - "<body type='terminate' " - "condition='remote-stream-error' " - "xmlns='http://jabber.org/protocol/httpbind'>" ++ - elements_to_string(StreamErrCond) ++ - "</body>"} - end; - true -> - {200, ?HEADER, - xml:element_to_string( - {xmlelement,"body", - [{"xmlns", - "http://jabber.org/protocol/httpbind"}], - OutEls})} - end - end. - -check_request(Sid, Attrs, Packet) -> - case mnesia:dirty_read({http_bind, Sid}) of - [] -> - ?DEBUG("not found",[]), - {error, not_exists}; - [#http_bind{pid = FsmRef, hold = Hold}] -> - gen_fsm:sync_send_all_state_event( - FsmRef, {http_put, Attrs, Packet, Hold}) - end. - - -http_put(Sid, Attrs, Packet) -> +http_put(Sid, Rid, Key, NewKey, Hold, Packet, Restart) -> ?DEBUG("http-put",[]), - {Rid, _} = string:to_integer(xml:get_attr_s("rid", Attrs)), - To = xml:get_attr_s("to", Attrs), case mnesia:dirty_read({http_bind, Sid}) of [] -> ?DEBUG("not found",[]), {error, not_exists}; - [#http_bind{pid = FsmRef, to = To, hold = Hold}] -> - gen_fsm:sync_send_all_state_event( - FsmRef, {http_put, Rid, Packet, To, Hold}) + [#http_bind{pid = FsmRef,to=To}] -> + case Restart of + true -> + ?DEBUG("restart requested for ~s", [To]), + gen_fsm:sync_send_all_state_event( + FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, To}); + _ -> + gen_fsm:sync_send_all_state_event( + FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, ""}) + end end. -http_get(Sid, Rid) -> +http_get(Sid,Rid) -> case mnesia:dirty_read({http_bind, Sid}) of [] -> {error, not_exists}; @@ -725,39 +747,43 @@ http_get(Sid, Rid) -> parse_request(Data) -> ?DEBUG("--- incoming data --- ~n~s~n --- END --- ", [Data]), - case catch xml_stream:parse_element(Data) of - {xmlelement, "body", Attrs, Els} -> - case xml:get_attr_s("xmlns",Attrs) of - "http://jabber.org/protocol/httpbind" -> - Sid = xml:get_attr_s("sid",Attrs), - %% normalize tree - actually not needed by XEP but - %% where playing nicely here - FixedEls = - lists:filter( - fun(I) -> - case I of - {xmlelement, _, _, _} -> - true; - _ -> - false - end - end, Els), - %% fix namespace of child element - lists:map(fun(E) -> - case xml:get_tag_attr_s("xmlns",E) of - "jabber:client" -> - remove_tag_attr("xmlns",E); - true -> - ok - end - end, FixedEls), - %% revert to string - Packet = [xml:element_to_string(E) || E <- FixedEls], - {ok, {Sid, Attrs, Packet}}; - _ -> %% bad namespace - {error, bad_request} - end; - _ -> + case xml_stream:parse_element(Data) of + El when element(1, El) == xmlelement -> + {xmlelement, Name, Attrs, Els} = El, + FixedEls = + lists:filter( + fun(I) -> + case I of + {xmlelement, _, _, _} -> + true; + _ -> + false + end + end, Els), + Sid = xml:get_attr_s("sid",Attrs), + {Rid,_X} = string:to_integer(xml:get_attr_s("rid",Attrs)), + Key = xml:get_attr_s("key",Attrs), + NewKey = xml:get_attr_s("newkey",Attrs), + Xmlns = xml:get_attr_s("xmlns",Attrs), + lists:map(fun(E) -> + EXmlns = xml:get_tag_attr_s("xmlns",E), + if + EXmlns == "jabber:client" -> + remove_tag_attr("xmlns",E); + true -> + ok + end + end, FixedEls), + Packet = [xml:element_to_string(E) || E <- FixedEls], + if + Name /= "body" -> + {error, bad_request}; + Xmlns /= "http://jabber.org/protocol/httpbind" -> + {error, bad_request}; + true -> + {ok, {Sid, Rid, Key, NewKey, Attrs, Packet}} + end; + {error, _Reason} -> {error, bad_request} end. diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index 989d025e3..1cebd0f5e 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -3,6 +3,7 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : Implementation of XMPP over BOSH (XEP-0206) %%% Created : Tue Feb 20 13:15:52 CET 2007 +%%% Id : $Id: $ %%%---------------------------------------------------------------------- %%%---------------------------------------------------------------------- @@ -14,7 +15,7 @@ -module(mod_http_bind). -author('steve@zeank.in-berlin.de'). --define(MOD_HTTP_BIND_VERSION, '1.0'). +-define(MOD_HTTP_BIND_VERSION, "1.0"). -vsn(?MOD_HTTP_BIND_VERSION). %%-define(ejabberd_debug, true). @@ -47,7 +48,7 @@ process([], #request{method = 'POST', ejabberd_http_bind:process_request(Data); process([], #request{method = 'GET', data = []}) -> - Heading = "Ejabberd " ++ atom_to_list(?MODULE) ++ " v" ++ lists:concat([?MOD_HTTP_BIND_VERSION]), + Heading = "Ejabberd " ++ atom_to_list(?MODULE) ++ " v" ++ ?MOD_HTTP_BIND_VERSION, {xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}], [{xmlelement, "head", [], [{xmlelement, "title", [], [{xmlcdata, Heading}]}]}, @@ -56,16 +57,21 @@ process([], #request{method = 'GET', {xmlelement, "p", [], [{xmlcdata, "An implementation of "}, {xmlelement, "a", [{"href", "http://www.xmpp.org/extensions/xep-0206.html"}], - [{xmlcdata, "XMPP over BOSH (XEP-0206)"}]}, - {xmlcdata, "."}]}, + [{xmlcdata, "XMPP over BOSH (XEP-0206)"}]}]}, {xmlelement, "p", [], - [{xmlcdata, integer_to_list(mnesia:table_info(http_bind, size)) ++ " sessions found."}]} - ]}]}; + [{xmlcdata, integer_to_list(mnesia:table_info(http_bind, size)) ++ " sessions found."}]}, + {xmlelement, "p", [], + [{xmlcdata, "Sponsored by "}, + {xmlelement, "a", [{"href", "http://mabber.com"}], + [{xmlcdata, "mabber"}]}, + {xmlcdata, "."}]} + ]}]}; process(_Path, _Request) -> ?DEBUG("Bad Request: ~p", [_Request]), {400, [], {xmlelement, "h1", [], [{xmlcdata, "400 Bad Request"}]}}. + %%%---------------------------------------------------------------------- %%% BEHAVIOUR CALLBACKS %%%---------------------------------------------------------------------- From 229c24e1f2921f6d3e1ce998ac25ecba33fd0462 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:24:22 +0000 Subject: [PATCH 386/582] Implements sockname and peername for compatibility (thanks to Christohpe Romain) SVN Revision: 2271 --- src/web/ejabberd_http_bind.erl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index d16a5d0c4..5ac3f96d3 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -22,6 +22,7 @@ terminate/3, send/2, setopts/2, + sockname/1, peername/1, controlling_process/2, close/1, process_request/1]). @@ -99,6 +100,11 @@ controlling_process(_Socket, _Pid) -> close({http_bind, FsmRef}) -> catch gen_fsm:sync_send_all_state_event(FsmRef, close). +sockname(_Socket) -> + {ok, {{0, 0, 0, 0}, 0}}. + +peername(_Socket) -> + {ok, {{0, 0, 0, 0}, 0}}. process_request(Data) -> case catch parse_request(Data) of From 2f8112b10888ed424b17d3ce26fbd54f462b4047 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:24:26 +0000 Subject: [PATCH 387/582] Prepare_response: fixed a dbg message. Changed http header (thanks to Stefan Strigler) SVN Revision: 2272 --- src/web/ejabberd_http_bind.erl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 5ac3f96d3..98f7a3e95 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -64,11 +64,13 @@ -endif. -define(MAX_REQUESTS, 2). % number of simultaneous requests --define(MIN_POLLING, "2"). % don't poll faster than that or we will shoot you --define(MAX_WAIT, 3600). % max num of secs to keep a request on hold --define(MAX_INACTIVITY, 30000). % msecs to wait before terminating idle sessions +-define(MIN_POLLING, "2"). % don't poll faster than that or we will + % shoot you +-define(MAX_WAIT, 3600). % max num of secs to keep a request on hold +-define(MAX_INACTIVITY, 30000). % msecs to wait before terminating + % idle sessions -define(CT, {"Content-Type", "text/xml; charset=utf-8"}). --define(HEADER, [?CT,{"X-Sponsored-By", "http://mabber.com"}]). +-define(HEADER, [?CT]). %%%---------------------------------------------------------------------- @@ -230,7 +232,7 @@ receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs) -> prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs) -> case http_get(Sid,Rid) of {error, not_exists} -> - ?DEBUG("no session associated with sid: ~s", Sid), + ?DEBUG("no session associated with sid: ~s", [Sid]), {404, ?HEADER, ""}; {ok, keep_on_hold} -> receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs); From 5495516c30a4580f49cce768c461502461f57983 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:24:30 +0000 Subject: [PATCH 388/582] We do not send a 'version' attribute at the stream header for now (thanks to Stefan Strigler) SVN Revision: 2273 --- src/web/ejabberd_http_bind.erl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 98f7a3e95..0d01fe7c1 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -3,12 +3,12 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : HTTP Binding support (JEP-0124) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: $ +%%% Id : $Id: ejabberd_http_bind.erl 123 2007-05-30 13:48:02Z sstrigler $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('Revision: 1.4'). +-vsn('$Rev: 123 $'). -behaviour(gen_fsm). @@ -22,7 +22,8 @@ terminate/3, send/2, setopts/2, - sockname/1, peername/1, + sockname/1, + peername/1, controlling_process/2, close/1, process_request/1]). @@ -605,7 +606,7 @@ handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StartTo}, ["<stream:stream to='", StartTo, "' xmlns='jabber:client' " - "version='1.0' " + %%"version='1.0' " "xmlns:stream='http://etherx.jabber.org/streams'>"] ++ Packet; true -> Packet From 01dc4611b945b1d0288b36970cee9d5a81775783 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:24:34 +0000 Subject: [PATCH 389/582] Restore ejabberd directory structure (src/web) for integration as patch (thanks to Christohpe Romain) SVN Revision: 2274 --- src/web/ejabberd_http_bind.erl | 5 +++-- src/web/mod_http_bind.erl | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 0d01fe7c1..c3a9dde0e 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -3,12 +3,12 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : HTTP Binding support (JEP-0124) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 123 2007-05-30 13:48:02Z sstrigler $ +%%% Id : $Id: ejabberd_http_bind.erl 156 2007-06-25 09:22:57Z cromain $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 123 $'). +-vsn('$Rev: 156 $'). -behaviour(gen_fsm). @@ -542,6 +542,7 @@ handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StartTo}, {MinPoll, _} = string:to_integer(?MIN_POLLING), if (Packet == "") and + (Hold == 0) and (TNow - StateData#state.last_poll < MinPoll*1000*1000) -> Reply = {error, polling_too_frequently}, {reply, Reply, StateName, StateData}; diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index 1cebd0f5e..1dba7d193 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -3,7 +3,7 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : Implementation of XMPP over BOSH (XEP-0206) %%% Created : Tue Feb 20 13:15:52 CET 2007 -%%% Id : $Id: $ +%%% Id : $Id: mod_http_bind.erl 156 2007-06-25 09:22:57Z cromain $ %%%---------------------------------------------------------------------- %%%---------------------------------------------------------------------- @@ -15,7 +15,7 @@ -module(mod_http_bind). -author('steve@zeank.in-berlin.de'). --define(MOD_HTTP_BIND_VERSION, "1.0"). +-define(MOD_HTTP_BIND_VERSION, "1.2"). -vsn(?MOD_HTTP_BIND_VERSION). %%-define(ejabberd_debug, true). @@ -23,9 +23,9 @@ -behaviour(gen_mod). -export([ - start/2, - stop/1, - process/2 + start/2, + stop/1, + process/2 ]). -include("ejabberd.hrl"). From 5048b6bdaff46c5924b192586ee15f05f07eb224 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:24:38 +0000 Subject: [PATCH 390/582] Bosh compliance: honor xmpp:version (thanks to Stefan Strigler) SVN Revision: 2275 --- src/web/ejabberd_http_bind.erl | 247 ++++++++++++++++++--------------- 1 file changed, 133 insertions(+), 114 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index c3a9dde0e..4f0b0938a 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -3,12 +3,12 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : HTTP Binding support (JEP-0124) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 156 2007-06-25 09:22:57Z cromain $ +%%% Id : $Id: ejabberd_http_bind.erl 239 2007-08-03 10:54:00Z sstrigler $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 156 $'). +-vsn('$Rev: 239 $'). -behaviour(gen_fsm). @@ -64,6 +64,8 @@ -define(FSMOPTS, []). -endif. +-define(BOSH_VERSION, "1.6"). + -define(MAX_REQUESTS, 2). % number of simultaneous requests -define(MIN_POLLING, "2"). % don't poll faster than that or we will % shoot you @@ -119,106 +121,108 @@ process_request(Data) -> "condition='improper-addressing' " "xmlns='http://jabber.org/protocol/httpbind'/>"}; true -> - Sid = if - (ParsedSid == "") -> - %% create new session - NewSid = sha:sha(term_to_binary({now(), make_ref()})), - {ok, Pid} = start(NewSid, Key), - ?DEBUG("got pid: ~p", [Pid]), - Wait = case - string:to_integer(xml:get_attr_s("wait",Attrs)) - of - {error, _} -> - ?MAX_WAIT; - {CWait, _} -> - if - (CWait > ?MAX_WAIT) -> - ?MAX_WAIT; - true -> - CWait - end - end, - Hold = case - string:to_integer( - xml:get_attr_s("hold",Attrs)) - of - {error, _} -> - (?MAX_REQUESTS - 1); - {CHold, _} -> - if - (CHold > (?MAX_REQUESTS - 1)) -> - (?MAX_REQUESTS - 1); - true -> - CHold - end - end, - mnesia:transaction( - fun() -> - mnesia:write(#http_bind{id = NewSid, - pid = Pid, - to = XmppDomain, - wait = Wait, - hold = Hold}) - end), - StreamStart = if - (XmppDomain /= "") -> - true; - true -> - false - end, - InPacket = Packet, - NewSid; - true -> - %% old session - Type = xml:get_attr_s("type",Attrs), - StreamStart = - case xml:get_attr_s("xmpp:restart",Attrs) of - "true" -> - true; - _ -> - false - end, - Wait = ?MAX_WAIT, - Hold = (?MAX_REQUESTS - 1), - if - (Type == "terminate") -> - %% terminate session - InPacket = Packet ++ "</stream:stream>"; - true -> - InPacket = Packet - end, - ParsedSid - end, -%% ?DEBUG("~n InPacket: ~s ~n", [InPacket]), - case http_put(Sid, Rid, Key, NewKey, Hold, InPacket, StreamStart) of - {error, not_exists} -> - ?DEBUG("no session associated with sid: ~p", [Sid]), - {404, ?HEADER, ""}; - {error, bad_key} -> - ?DEBUG("bad key: ~s", [Key]), - case mnesia:dirty_read({http_bind, Sid}) of - [] -> - {404, ?HEADER, ""}; - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop), - {404, ?HEADER, ""} - end; - {error, polling_too_frequently} -> - ?DEBUG("polling too frequently: ~p", [Sid]), - case mnesia:dirty_read({http_bind, Sid}) of - [] -> %% unlikely! (?) - {404, ?HEADER, ""}; - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop), - {403, ?HEADER, ""} - end; - {repeat, OutPacket} -> - ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", - [OutPacket]), - send_outpacket(Sid, OutPacket); - ok -> - receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs) - end + Sid = + if + (ParsedSid == "") -> + %% create new session + NewSid = sha:sha(term_to_binary({now(), make_ref()})), + {ok, Pid} = start(NewSid, Key), + ?DEBUG("got pid: ~p", [Pid]), + Wait = case + string:to_integer(xml:get_attr_s("wait",Attrs)) + of + {error, _} -> + ?MAX_WAIT; + {CWait, _} -> + if + (CWait > ?MAX_WAIT) -> + ?MAX_WAIT; + true -> + CWait + end + end, + Hold = case + string:to_integer( + xml:get_attr_s("hold",Attrs)) + of + {error, _} -> + (?MAX_REQUESTS - 1); + {CHold, _} -> + if + (CHold > (?MAX_REQUESTS - 1)) -> + (?MAX_REQUESTS - 1); + true -> + CHold + end + end, + XmppVersion = xml:get_attr_s("xmpp:version", Attrs), + mnesia:transaction( + fun() -> + mnesia:write(#http_bind{id = NewSid, + pid = Pid, + to = {XmppDomain, XmppVersion}, + wait = Wait, + hold = Hold}) + end), + StreamStart = if + (XmppDomain /= "") -> + true; + true -> + false + end, + InPacket = Packet, + NewSid; + true -> + %% old session + Type = xml:get_attr_s("type",Attrs), + StreamStart = + case xml:get_attr_s("xmpp:restart",Attrs) of + "true" -> + true; + _ -> + false + end, + Wait = ?MAX_WAIT, + Hold = (?MAX_REQUESTS - 1), + if + (Type == "terminate") -> + %% terminate session + InPacket = Packet ++ "</stream:stream>"; + true -> + InPacket = Packet + end, + ParsedSid + end, + %% ?DEBUG("~n InPacket: ~s ~n", [InPacket]), + case http_put(Sid, Rid, Key, NewKey, Hold, InPacket, StreamStart) of + {error, not_exists} -> + ?DEBUG("no session associated with sid: ~p", [Sid]), + {404, ?HEADER, ""}; + {error, bad_key} -> + ?DEBUG("bad key: ~s", [Key]), + case mnesia:dirty_read({http_bind, Sid}) of + [] -> + {404, ?HEADER, ""}; + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop), + {404, ?HEADER, ""} + end; + {error, polling_too_frequently} -> + ?DEBUG("polling too frequently: ~p", [Sid]), + case mnesia:dirty_read({http_bind, Sid}) of + [] -> %% unlikely! (?) + {404, ?HEADER, ""}; + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop), + {403, ?HEADER, ""} + end; + {repeat, OutPacket} -> + ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", + [OutPacket]), + send_outpacket(Sid, OutPacket); + ok -> + receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs) + end end; _ -> {400, ?HEADER, ""} @@ -278,6 +282,16 @@ prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs) -> "condition='host-unknown' " "xmlns='http://jabber.org/protocol/httpbind'/>"}; true -> + BOSH_attribs = + [{"authid", AuthID}, + {"xmlns:xmpp", "urn:xmpp:xbosh"}, + {"xmlns:stream","http://etherx.jabber.org/streams"}] ++ + case OutEls of + [] -> + []; + _ -> + [{"xmpp:version", "1.0"}] + end, {200, ?HEADER, xml:element_to_string( {xmlelement,"body", @@ -289,8 +303,10 @@ prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs) -> {"inactivity", integer_to_list(trunc(?MAX_INACTIVITY/1000))}, {"polling", ?MIN_POLLING}, - {"authid", AuthID} - ],OutEls})} + {"ver", ?BOSH_VERSION}, + {"from", To}, + {"secure", "true"} %% we're always being secure + ] ++ BOSH_attribs,OutEls})} end end end. @@ -480,7 +496,7 @@ handle_sync_event(stop, _From, _StateName, StateData) -> Reply = ok, {stop, normal, Reply, StateData}; -handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StartTo}, +handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StreamTo}, _From, StateName, StateData) -> %% check if Rid valid RidAllow = case Rid of @@ -602,14 +618,17 @@ handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StartTo}, }}; {Receiver, _Tag} -> SendPacket = - if - StartTo /= "" -> - ["<stream:stream to='", - StartTo, - "' xmlns='jabber:client' " - %%"version='1.0' " + case StreamTo of + {To, ""} -> + ["<stream:stream to='", To, "' " + "xmlns='jabber:client' " "xmlns:stream='http://etherx.jabber.org/streams'>"] ++ Packet; - true -> + {To, Version} -> + ["<stream:stream to='", To, "' " + "xmlns='jabber:client' " + "version='", Version, "' " + "xmlns:stream='http://etherx.jabber.org/streams'>"] ++ Packet; + _ -> Packet end, ?DEBUG("really sending now: ~s", [SendPacket]), @@ -732,12 +751,12 @@ http_put(Sid, Rid, Key, NewKey, Hold, Packet, Restart) -> [] -> ?DEBUG("not found",[]), {error, not_exists}; - [#http_bind{pid = FsmRef,to=To}] -> + [#http_bind{pid = FsmRef,to=StreamTo}] -> case Restart of true -> ?DEBUG("restart requested for ~s", [To]), gen_fsm:sync_send_all_state_event( - FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, To}); + FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, StreamTo}); _ -> gen_fsm:sync_send_all_state_event( FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, ""}) From f422ec457a6d9a79147d74414ce7dc20f17009f7 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:24:42 +0000 Subject: [PATCH 391/582] Some code cleanup (thanks to Stefan Strigler) SVN Revision: 2276 --- src/web/ejabberd_http_bind.erl | 251 ++++++++++++++++----------------- 1 file changed, 120 insertions(+), 131 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 4f0b0938a..fdf916698 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -3,12 +3,12 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : HTTP Binding support (JEP-0124) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 239 2007-08-03 10:54:00Z sstrigler $ +%%% Id : $Id: ejabberd_http_bind.erl 240 2007-08-03 12:05:14Z sstrigler $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 239 $'). +-vsn('$Rev: 240 $'). -behaviour(gen_fsm). @@ -28,7 +28,7 @@ close/1, process_request/1]). -%%-define(ejabberd_debug, true). +-define(ejabberd_debug, true). -include("ejabberd.hrl"). -include("jlib.hrl"). @@ -113,134 +113,123 @@ peername(_Socket) -> process_request(Data) -> case catch parse_request(Data) of - {ok, {ParsedSid, Rid, Key, NewKey, Attrs, Packet}} -> - XmppDomain = xml:get_attr_s("to",Attrs), - if - (ParsedSid == "") and (XmppDomain == "") -> + {ok, {"", Rid, Key, NewKey, Attrs, Packet}} -> + case xml:get_attr_s("to",Attrs) of + "" -> {200, ?HEADER, "<body type='terminate' " "condition='improper-addressing' " "xmlns='http://jabber.org/protocol/httpbind'/>"}; - true -> - Sid = - if - (ParsedSid == "") -> - %% create new session - NewSid = sha:sha(term_to_binary({now(), make_ref()})), - {ok, Pid} = start(NewSid, Key), - ?DEBUG("got pid: ~p", [Pid]), - Wait = case - string:to_integer(xml:get_attr_s("wait",Attrs)) - of - {error, _} -> - ?MAX_WAIT; - {CWait, _} -> - if - (CWait > ?MAX_WAIT) -> - ?MAX_WAIT; - true -> - CWait - end - end, - Hold = case - string:to_integer( - xml:get_attr_s("hold",Attrs)) - of - {error, _} -> - (?MAX_REQUESTS - 1); - {CHold, _} -> - if - (CHold > (?MAX_REQUESTS - 1)) -> - (?MAX_REQUESTS - 1); - true -> - CHold - end - end, - XmppVersion = xml:get_attr_s("xmpp:version", Attrs), - mnesia:transaction( - fun() -> - mnesia:write(#http_bind{id = NewSid, - pid = Pid, - to = {XmppDomain, XmppVersion}, - wait = Wait, - hold = Hold}) - end), - StreamStart = if - (XmppDomain /= "") -> - true; - true -> - false - end, - InPacket = Packet, - NewSid; - true -> - %% old session - Type = xml:get_attr_s("type",Attrs), - StreamStart = - case xml:get_attr_s("xmpp:restart",Attrs) of - "true" -> - true; - _ -> - false - end, - Wait = ?MAX_WAIT, - Hold = (?MAX_REQUESTS - 1), - if - (Type == "terminate") -> - %% terminate session - InPacket = Packet ++ "</stream:stream>"; - true -> - InPacket = Packet - end, - ParsedSid - end, - %% ?DEBUG("~n InPacket: ~s ~n", [InPacket]), - case http_put(Sid, Rid, Key, NewKey, Hold, InPacket, StreamStart) of - {error, not_exists} -> - ?DEBUG("no session associated with sid: ~p", [Sid]), - {404, ?HEADER, ""}; - {error, bad_key} -> - ?DEBUG("bad key: ~s", [Key]), - case mnesia:dirty_read({http_bind, Sid}) of - [] -> - {404, ?HEADER, ""}; - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop), - {404, ?HEADER, ""} - end; - {error, polling_too_frequently} -> - ?DEBUG("polling too frequently: ~p", [Sid]), - case mnesia:dirty_read({http_bind, Sid}) of - [] -> %% unlikely! (?) - {404, ?HEADER, ""}; - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop), - {403, ?HEADER, ""} - end; - {repeat, OutPacket} -> - ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", - [OutPacket]), - send_outpacket(Sid, OutPacket); - ok -> - receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs) - end - end; - _ -> - {400, ?HEADER, ""} + XmppDomain -> + %% create new session + Sid = sha:sha(term_to_binary({now(), make_ref()})), + {ok, Pid} = start(Sid, Key), + ?DEBUG("got pid: ~p", [Pid]), + Wait = case + string:to_integer(xml:get_attr_s("wait",Attrs)) + of + {error, _} -> + ?MAX_WAIT; + {CWait, _} -> + if + (CWait > ?MAX_WAIT) -> + ?MAX_WAIT; + true -> + CWait + end + end, + Hold = case + string:to_integer( + xml:get_attr_s("hold",Attrs)) + of + {error, _} -> + (?MAX_REQUESTS - 1); + {CHold, _} -> + if + (CHold > (?MAX_REQUESTS - 1)) -> + (?MAX_REQUESTS - 1); + true -> + CHold + end + end, + XmppVersion = xml:get_attr_s("xmpp:version", Attrs), + mnesia:transaction( + fun() -> + mnesia:write(#http_bind{id = Sid, + pid = Pid, + to = {XmppDomain, XmppVersion}, + wait = Wait, + hold = Hold}) + end), + handle_http_put(Sid, Rid, Key, NewKey, Wait, Hold, Attrs, Packet, true) + end; + {ok, {Sid, Rid, Key, NewKey, Attrs, Packet}} -> + %% old session + StreamStart = + case xml:get_attr_s("xmpp:restart",Attrs) of + "true" -> + true; + _ -> + false + end, + Wait = ?MAX_WAIT, + Hold = (?MAX_REQUESTS - 1), + InPacket = case xml:get_attr_s("type",Attrs) of + "terminate" -> + %% close stream + Packet ++ "</stream:stream>"; + _ -> + Packet + end, + handle_http_put(Sid, Rid, Key, NewKey, Wait, Hold, Attrs, InPacket, StreamStart); + _ -> + {400, ?HEADER, ""} end. -receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs) -> +handle_http_put(Sid, Rid, Key, NewKey, Wait, Hold, Attrs, Packet, StreamStart) -> + case http_put(Sid, Rid, Key, NewKey, Hold, Packet, StreamStart) of + {error, not_exists} -> + ?DEBUG("no session associated with sid: ~p", [Sid]), + {404, ?HEADER, ""}; + {error, bad_key} -> + ?DEBUG("bad key: ~s", [Key]), + case mnesia:dirty_read({http_bind, Sid}) of + [] -> + {404, ?HEADER, ""}; + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop), + {404, ?HEADER, ""} + end; + {error, polling_too_frequently} -> + ?DEBUG("polling too frequently: ~p", [Sid]), + case mnesia:dirty_read({http_bind, Sid}) of + [] -> %% unlikely! (?) + {404, ?HEADER, ""}; + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop), + {403, ?HEADER, ""} + end; + {repeat, OutPacket} -> + ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", + [OutPacket]), + send_outpacket(Sid, OutPacket); + ok -> + receive_loop(Sid, Rid, Wait, Hold, Attrs, StreamStart) + end. + + +receive_loop(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> receive after 100 -> ok end, - prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs). + prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart). -prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs) -> - case http_get(Sid,Rid) of +prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> + case http_get(Sid, Rid) of {error, not_exists} -> ?DEBUG("no session associated with sid: ~s", [Sid]), {404, ?HEADER, ""}; {ok, keep_on_hold} -> - receive_loop(Sid,ParsedSid,Rid,Wait,Hold,Attrs); + receive_loop(Sid, Rid, Wait, Hold, Attrs, StreamStart); {ok, cancel} -> %% actually it would be better if we could completely %% cancel this request, but then we would have to hack @@ -248,16 +237,18 @@ prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs) -> {404, ?HEADER, ""}; {ok, OutPacket} -> ?DEBUG("OutPacket: ~s", [OutPacket]), - if - Sid == ParsedSid -> + case StreamStart of + false -> send_outpacket(Sid, OutPacket); true -> - To = xml:get_attr_s("to",Attrs), OutEls = case xml_stream:parse_element( OutPacket++"</stream:stream>") of El when element(1, El) == xmlelement -> + ?DEBUG("~p", [El]), {xmlelement, _, OutAttrs, Els} = El, AuthID = xml:get_attr_s("id", OutAttrs), + From = xml:get_attr_s("from", OutAttrs), + Version = xml:get_attr_s("version", OutAttrs), StreamError = false, case Els of [] -> @@ -269,14 +260,12 @@ prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs) -> end; {error, _} -> AuthID = "", + From = "", + Version = "", StreamError = true, [] end, if - To == "" -> - {200, ?HEADER, "<body type='terminate' " - "condition='improper-addressing' " - "xmlns='http://jabber.org/protocol/httpbind'/>"}; StreamError == true -> {200, ?HEADER, "<body type='terminate' " "condition='host-unknown' " @@ -290,7 +279,7 @@ prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs) -> [] -> []; _ -> - [{"xmpp:version", "1.0"}] + [{"xmpp:version", Version}] end, {200, ?HEADER, xml:element_to_string( @@ -304,7 +293,7 @@ prepare_response(Sid,ParsedSid,Rid,Wait,Hold,Attrs) -> integer_to_list(trunc(?MAX_INACTIVITY/1000))}, {"polling", ?MIN_POLLING}, {"ver", ?BOSH_VERSION}, - {"from", To}, + {"from", From}, {"secure", "true"} %% we're always being secure ] ++ BOSH_attribs,OutEls})} end @@ -745,18 +734,18 @@ terminate(_Reason, _StateName, StateData) -> %%%---------------------------------------------------------------------- -http_put(Sid, Rid, Key, NewKey, Hold, Packet, Restart) -> +http_put(Sid, Rid, Key, NewKey, Hold, Packet, StreamStart) -> ?DEBUG("http-put",[]), case mnesia:dirty_read({http_bind, Sid}) of [] -> ?DEBUG("not found",[]), {error, not_exists}; - [#http_bind{pid = FsmRef,to=StreamTo}] -> - case Restart of + [#http_bind{pid = FsmRef,to={To, Version}}] -> + case StreamStart of true -> ?DEBUG("restart requested for ~s", [To]), gen_fsm:sync_send_all_state_event( - FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, StreamTo}); + FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, {To, Version}}); _ -> gen_fsm:sync_send_all_state_event( FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, ""}) From 80b59441d557956d0cbd8eff0c4fca3321fa8ccd Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:24:46 +0000 Subject: [PATCH 392/582] Disabled debugging (thanks to Stefan Strigler) SVN Revision: 2277 --- src/web/ejabberd_http_bind.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index fdf916698..6020e46cf 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -3,12 +3,12 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : HTTP Binding support (JEP-0124) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 240 2007-08-03 12:05:14Z sstrigler $ +%%% Id : $Id: ejabberd_http_bind.erl 241 2007-08-03 12:13:13Z sstrigler $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 240 $'). +-vsn('$Rev: 241 $'). -behaviour(gen_fsm). @@ -28,7 +28,7 @@ close/1, process_request/1]). --define(ejabberd_debug, true). +%%-define(ejabberd_debug, true). -include("ejabberd.hrl"). -include("jlib.hrl"). From b79473b2f5b54126f37c9c7433e6a066bb265a80 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:24:50 +0000 Subject: [PATCH 393/582] Fix for 'terminate' in request, send empty body instead of error (thanks to Stefan Strigler) SVN Revision: 2278 --- src/web/ejabberd_http_bind.erl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 6020e46cf..fc10140e9 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -3,12 +3,12 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : HTTP Binding support (JEP-0124) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 241 2007-08-03 12:13:13Z sstrigler $ +%%% Id : $Id: ejabberd_http_bind.erl 243 2007-08-03 13:48:49Z sstrigler $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 241 $'). +-vsn('$Rev: 243 $'). -behaviour(gen_fsm). @@ -226,8 +226,13 @@ receive_loop(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> case http_get(Sid, Rid) of {error, not_exists} -> - ?DEBUG("no session associated with sid: ~s", [Sid]), - {404, ?HEADER, ""}; + case xml:get_attr_s("type", Attrs) of + "terminate" -> + {200, ?HEADER, "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; + _ -> + ?DEBUG("no session associated with sid: ~s", [Sid]), + {404, ?HEADER, ""} + end; {ok, keep_on_hold} -> receive_loop(Sid, Rid, Wait, Hold, Attrs, StreamStart); {ok, cancel} -> From 702978fa4b490888fc6fd5ae31c2d8e8938ea1be Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:24:54 +0000 Subject: [PATCH 394/582] Make use of macros for namespaces. Some code cleanup. (thanks to Stefan Strigler) SVN Revision: 2279 --- src/web/ejabberd_http_bind.erl | 170 +++++++++++++++++++-------------- 1 file changed, 100 insertions(+), 70 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index fc10140e9..4b912b0d0 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -3,12 +3,12 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : HTTP Binding support (JEP-0124) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 243 2007-08-03 13:48:49Z sstrigler $ +%%% Id : $Id: ejabberd_http_bind.erl 272 2007-08-15 12:11:06Z sstrigler $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 243 $'). +-vsn('$Rev: 272 $'). -behaviour(gen_fsm). @@ -65,6 +65,9 @@ -endif. -define(BOSH_VERSION, "1.6"). +-define(NS_CLIENT, "jabber:client"). +-define(NS_BOSH, "urn:xmpp:xbosh"). +-define(NS_HTTP_BIND, "http://jabber.org/protocol/httpbind"). -define(MAX_REQUESTS, 2). % number of simultaneous requests -define(MIN_POLLING, "2"). % don't poll faster than that or we will @@ -118,7 +121,7 @@ process_request(Data) -> "" -> {200, ?HEADER, "<body type='terminate' " "condition='improper-addressing' " - "xmlns='http://jabber.org/protocol/httpbind'/>"}; + "xmlns='" ++ ?NS_HTTP_BIND ++ "'/>"}; XmppDomain -> %% create new session Sid = sha:sha(term_to_binary({now(), make_ref()})), @@ -156,11 +159,13 @@ process_request(Data) -> fun() -> mnesia:write(#http_bind{id = Sid, pid = Pid, - to = {XmppDomain, XmppVersion}, + to = {XmppDomain, + XmppVersion}, wait = Wait, hold = Hold}) end), - handle_http_put(Sid, Rid, Key, NewKey, Wait, Hold, Attrs, Packet, true) + handle_http_put(Sid, Rid, Key, NewKey, Wait, Hold, + Attrs, Packet, true) end; {ok, {Sid, Rid, Key, NewKey, Attrs, Packet}} -> %% old session @@ -180,12 +185,14 @@ process_request(Data) -> _ -> Packet end, - handle_http_put(Sid, Rid, Key, NewKey, Wait, Hold, Attrs, InPacket, StreamStart); + handle_http_put(Sid, Rid, Key, NewKey, Wait, Hold, Attrs, + InPacket, StreamStart); _ -> {400, ?HEADER, ""} end. -handle_http_put(Sid, Rid, Key, NewKey, Wait, Hold, Attrs, Packet, StreamStart) -> +handle_http_put(Sid, Rid, Key, NewKey, Wait, Hold, Attrs, + Packet, StreamStart) -> case http_put(Sid, Rid, Key, NewKey, Hold, Packet, StreamStart) of {error, not_exists} -> ?DEBUG("no session associated with sid: ~p", [Sid]), @@ -228,7 +235,7 @@ prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> {error, not_exists} -> case xml:get_attr_s("type", Attrs) of "terminate" -> - {200, ?HEADER, "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; + {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; _ -> ?DEBUG("no session associated with sid: ~s", [Sid]), {404, ?HEADER, ""} @@ -239,47 +246,56 @@ prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> %% actually it would be better if we could completely %% cancel this request, but then we would have to hack %% ejabberd_http and I'm too lazy now - {404, ?HEADER, ""}; + {200, ?HEADER, "<body type='error' xmlns='"++?NS_HTTP_BIND++"'/>"}; {ok, OutPacket} -> ?DEBUG("OutPacket: ~s", [OutPacket]), case StreamStart of false -> send_outpacket(Sid, OutPacket); true -> - OutEls = case xml_stream:parse_element( - OutPacket++"</stream:stream>") of - El when element(1, El) == xmlelement -> - ?DEBUG("~p", [El]), - {xmlelement, _, OutAttrs, Els} = El, - AuthID = xml:get_attr_s("id", OutAttrs), - From = xml:get_attr_s("from", OutAttrs), - Version = xml:get_attr_s("version", OutAttrs), - StreamError = false, - case Els of - [] -> - []; - [{xmlelement, "stream:features", StreamAttribs, StreamEls} | StreamTail] -> - [{xmlelement, "stream:features", [{"xmlns:stream","http://etherx.jabber.org/streams"}] ++ StreamAttribs, StreamEls}] ++ StreamTail; - Xml -> - Xml - end; - {error, _} -> - AuthID = "", - From = "", - Version = "", - StreamError = true, - [] - end, + OutEls = + case xml_stream:parse_element( + OutPacket++"</stream:stream>") of + El when element(1, El) == xmlelement -> + ?DEBUG("~p", [El]), + {xmlelement, _, OutAttrs, Els} = El, + AuthID = xml:get_attr_s("id", OutAttrs), + From = xml:get_attr_s("from", OutAttrs), + Version = xml:get_attr_s("version", OutAttrs), + StreamError = false, + case Els of + [] -> + []; + [{xmlelement, "stream:features", + StreamAttribs, StreamEls} + | StreamTail] -> + [{xmlelement, "stream:features", + [{"xmlns:stream", + ?NS_STREAM} + ] + ++ StreamAttribs, + StreamEls + }] ++ StreamTail; + Xml -> + Xml + end; + {error, _} -> + AuthID = "", + From = "", + Version = "", + StreamError = true, + [] + end, if StreamError == true -> {200, ?HEADER, "<body type='terminate' " "condition='host-unknown' " - "xmlns='http://jabber.org/protocol/httpbind'/>"}; + "xmlns='"++?NS_HTTP_BIND++"'/>"}; true -> BOSH_attribs = [{"authid", AuthID}, - {"xmlns:xmpp", "urn:xmpp:xbosh"}, - {"xmlns:stream","http://etherx.jabber.org/streams"}] ++ + {"xmlns:xmpp", ?NS_BOSH}, + {"xmlns:stream", ?NS_STREAM}] ++ case OutEls of [] -> []; @@ -290,7 +306,7 @@ prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> xml:element_to_string( {xmlelement,"body", [{"xmlns", - "http://jabber.org/protocol/httpbind"}, + ?NS_HTTP_BIND}, {"sid",Sid}, {"wait", integer_to_list(Wait)}, {"requests", integer_to_list(Hold+1)}, @@ -308,13 +324,13 @@ prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> send_outpacket(Sid, OutPacket) -> case OutPacket of "" -> - {200, ?HEADER, "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; + {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; "</stream:stream>" -> case mnesia:dirty_read({http_bind, Sid}) of [#http_bind{pid = FsmRef}] -> gen_fsm:sync_send_all_state_event(FsmRef,stop) end, - {200, ?HEADER, "<body xmlns='http://jabber.org/protocol/httpbind'/>"}; + {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; _ -> case xml_stream:parse_element("<body>" ++ OutPacket @@ -323,20 +339,20 @@ send_outpacket(Sid, OutPacket) -> El when element(1, El) == xmlelement -> {xmlelement, _, _, OEls} = El, TypedEls = [xml:replace_tag_attr("xmlns", - "jabber:client",OEl) || + ?NS_CLIENT,OEl) || OEl <- OEls], ?DEBUG(" --- outgoing data --- ~n~s~n --- END --- ~n", [xml:element_to_string( {xmlelement,"body", [{"xmlns", - "http://jabber.org/protocol/httpbind"}], + ?NS_HTTP_BIND}], TypedEls})] ), {200, ?HEADER, xml:element_to_string( {xmlelement,"body", [{"xmlns", - "http://jabber.org/protocol/httpbind"}], + ?NS_HTTP_BIND}], TypedEls})}; {error, _E} -> OutEls = case xml_stream:parse_element( @@ -347,11 +363,21 @@ send_outpacket(Sid, OutPacket) -> case SEls of [] -> []; - [{xmlelement, "stream:features", StreamAttribs, StreamEls} | StreamTail] -> - TypedTail = [xml:replace_tag_attr("xmlns", - "jabber:client",OEl) || + [{xmlelement, + "stream:features", + StreamAttribs, StreamEls} | + StreamTail] -> + TypedTail = + [xml:replace_tag_attr( + "xmlns", + ?NS_CLIENT,OEl) || OEl <- StreamTail], - [{xmlelement, "stream:features", [{"xmlns:stream","http://etherx.jabber.org/streams"}] ++ StreamAttribs, StreamEls}] ++ TypedTail; + [{xmlelement, + "stream:features", + [{"xmlns:stream", + ?NS_STREAM}] ++ + StreamAttribs, StreamEls}] ++ + TypedTail; Xml -> Xml end; @@ -361,23 +387,25 @@ send_outpacket(Sid, OutPacket) -> end, if StreamError -> - StreamErrCond = case xml_stream:parse_element( - "<stream:stream>"++OutPacket) of - El when element(1, El) == xmlelement -> - {xmlelement, _Tag, _Attr, Els} = El, - [{xmlelement, SE, _, Cond} | _] = Els, - if - SE == "stream:error" -> - Cond; - true -> - null - end; - {error, _E} -> - null - end, + StreamErrCond = + case xml_stream:parse_element( + "<stream:stream>"++OutPacket) of + El when element(1, El) == xmlelement -> + {xmlelement, _Tag, _Attr, Els} = El, + [{xmlelement, SE, _, Cond} | _] = Els, + if + SE == "stream:error" -> + Cond; + true -> + null + end; + {error, _E} -> + null + end, case mnesia:dirty_read({http_bind, Sid}) of [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop); + gen_fsm:sync_send_all_state_event(FsmRef, + stop); _ -> err %% hu? end, @@ -386,12 +414,12 @@ send_outpacket(Sid, OutPacket) -> {200, ?HEADER, "<body type='terminate' " "condition='internal-server-error' " - "xmlns='http://jabber.org/protocol/httpbind'/>"}; + "xmlns='"++?NS_HTTP_BIND++"'/>"}; _ -> {200, ?HEADER, "<body type='terminate' " "condition='remote-stream-error' " - "xmlns='http://jabber.org/protocol/httpbind'>" ++ + "xmlns='"++?NS_HTTP_BIND++"'>" ++ elements_to_string(StreamErrCond) ++ "</body>"} end; @@ -400,7 +428,7 @@ send_outpacket(Sid, OutPacket) -> xml:element_to_string( {xmlelement,"body", [{"xmlns", - "http://jabber.org/protocol/httpbind"}], + ?NS_HTTP_BIND}], OutEls})} end end @@ -615,13 +643,15 @@ handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StreamTo}, case StreamTo of {To, ""} -> ["<stream:stream to='", To, "' " - "xmlns='jabber:client' " - "xmlns:stream='http://etherx.jabber.org/streams'>"] ++ Packet; + "xmlns='"++?NS_CLIENT++"' " + "xmlns:stream='"++?NS_STREAM++"'>"] + ++ Packet; {To, Version} -> ["<stream:stream to='", To, "' " - "xmlns='jabber:client' " + "xmlns='"++?NS_CLIENT++"' " "version='", Version, "' " - "xmlns:stream='http://etherx.jabber.org/streams'>"] ++ Packet; + "xmlns:stream='"++?NS_STREAM++"'>"] + ++ Packet; _ -> Packet end, @@ -791,7 +821,7 @@ parse_request(Data) -> lists:map(fun(E) -> EXmlns = xml:get_tag_attr_s("xmlns",E), if - EXmlns == "jabber:client" -> + EXmlns == ?NS_CLIENT -> remove_tag_attr("xmlns",E); true -> ok @@ -801,7 +831,7 @@ parse_request(Data) -> if Name /= "body" -> {error, bad_request}; - Xmlns /= "http://jabber.org/protocol/httpbind" -> + Xmlns /= ?NS_HTTP_BIND -> {error, bad_request}; true -> {ok, {Sid, Rid, Key, NewKey, Attrs, Packet}} From f07df01185e0eef7e6fe1dace06328ca399b8311 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:24:58 +0000 Subject: [PATCH 395/582] Code rearranged (thanks to Stefan Strigler) SVN Revision: 2280 --- src/web/ejabberd_http_bind.erl | 493 +++++++++++++++++---------------- 1 file changed, 247 insertions(+), 246 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 4b912b0d0..d7a16c14e 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -3,12 +3,12 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : HTTP Binding support (JEP-0124) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 272 2007-08-15 12:11:06Z sstrigler $ +%%% Id : $Id: ejabberd_http_bind.erl 273 2007-08-15 13:53:00Z sstrigler $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 272 $'). +-vsn('$Rev: 273 $'). -behaviour(gen_fsm). @@ -154,6 +154,7 @@ process_request(Data) -> CHold end end, + Version = xml:get_attr_s("ver", Attrs), XmppVersion = xml:get_attr_s("xmpp:version", Attrs), mnesia:transaction( fun() -> @@ -161,6 +162,7 @@ process_request(Data) -> pid = Pid, to = {XmppDomain, XmppVersion}, + version = Version, wait = Wait, hold = Hold}) end), @@ -191,249 +193,6 @@ process_request(Data) -> {400, ?HEADER, ""} end. -handle_http_put(Sid, Rid, Key, NewKey, Wait, Hold, Attrs, - Packet, StreamStart) -> - case http_put(Sid, Rid, Key, NewKey, Hold, Packet, StreamStart) of - {error, not_exists} -> - ?DEBUG("no session associated with sid: ~p", [Sid]), - {404, ?HEADER, ""}; - {error, bad_key} -> - ?DEBUG("bad key: ~s", [Key]), - case mnesia:dirty_read({http_bind, Sid}) of - [] -> - {404, ?HEADER, ""}; - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop), - {404, ?HEADER, ""} - end; - {error, polling_too_frequently} -> - ?DEBUG("polling too frequently: ~p", [Sid]), - case mnesia:dirty_read({http_bind, Sid}) of - [] -> %% unlikely! (?) - {404, ?HEADER, ""}; - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop), - {403, ?HEADER, ""} - end; - {repeat, OutPacket} -> - ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", - [OutPacket]), - send_outpacket(Sid, OutPacket); - ok -> - receive_loop(Sid, Rid, Wait, Hold, Attrs, StreamStart) - end. - - -receive_loop(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> - receive - after 100 -> ok - end, - prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart). - -prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> - case http_get(Sid, Rid) of - {error, not_exists} -> - case xml:get_attr_s("type", Attrs) of - "terminate" -> - {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; - _ -> - ?DEBUG("no session associated with sid: ~s", [Sid]), - {404, ?HEADER, ""} - end; - {ok, keep_on_hold} -> - receive_loop(Sid, Rid, Wait, Hold, Attrs, StreamStart); - {ok, cancel} -> - %% actually it would be better if we could completely - %% cancel this request, but then we would have to hack - %% ejabberd_http and I'm too lazy now - {200, ?HEADER, "<body type='error' xmlns='"++?NS_HTTP_BIND++"'/>"}; - {ok, OutPacket} -> - ?DEBUG("OutPacket: ~s", [OutPacket]), - case StreamStart of - false -> - send_outpacket(Sid, OutPacket); - true -> - OutEls = - case xml_stream:parse_element( - OutPacket++"</stream:stream>") of - El when element(1, El) == xmlelement -> - ?DEBUG("~p", [El]), - {xmlelement, _, OutAttrs, Els} = El, - AuthID = xml:get_attr_s("id", OutAttrs), - From = xml:get_attr_s("from", OutAttrs), - Version = xml:get_attr_s("version", OutAttrs), - StreamError = false, - case Els of - [] -> - []; - [{xmlelement, "stream:features", - StreamAttribs, StreamEls} - | StreamTail] -> - [{xmlelement, "stream:features", - [{"xmlns:stream", - ?NS_STREAM} - ] - ++ StreamAttribs, - StreamEls - }] ++ StreamTail; - Xml -> - Xml - end; - {error, _} -> - AuthID = "", - From = "", - Version = "", - StreamError = true, - [] - end, - if - StreamError == true -> - {200, ?HEADER, "<body type='terminate' " - "condition='host-unknown' " - "xmlns='"++?NS_HTTP_BIND++"'/>"}; - true -> - BOSH_attribs = - [{"authid", AuthID}, - {"xmlns:xmpp", ?NS_BOSH}, - {"xmlns:stream", ?NS_STREAM}] ++ - case OutEls of - [] -> - []; - _ -> - [{"xmpp:version", Version}] - end, - {200, ?HEADER, - xml:element_to_string( - {xmlelement,"body", - [{"xmlns", - ?NS_HTTP_BIND}, - {"sid",Sid}, - {"wait", integer_to_list(Wait)}, - {"requests", integer_to_list(Hold+1)}, - {"inactivity", - integer_to_list(trunc(?MAX_INACTIVITY/1000))}, - {"polling", ?MIN_POLLING}, - {"ver", ?BOSH_VERSION}, - {"from", From}, - {"secure", "true"} %% we're always being secure - ] ++ BOSH_attribs,OutEls})} - end - end - end. - -send_outpacket(Sid, OutPacket) -> - case OutPacket of - "" -> - {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; - "</stream:stream>" -> - case mnesia:dirty_read({http_bind, Sid}) of - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop) - end, - {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; - _ -> - case xml_stream:parse_element("<body>" - ++ OutPacket - ++ "</body>") - of - El when element(1, El) == xmlelement -> - {xmlelement, _, _, OEls} = El, - TypedEls = [xml:replace_tag_attr("xmlns", - ?NS_CLIENT,OEl) || - OEl <- OEls], - ?DEBUG(" --- outgoing data --- ~n~s~n --- END --- ~n", - [xml:element_to_string( - {xmlelement,"body", - [{"xmlns", - ?NS_HTTP_BIND}], - TypedEls})] - ), - {200, ?HEADER, - xml:element_to_string( - {xmlelement,"body", - [{"xmlns", - ?NS_HTTP_BIND}], - TypedEls})}; - {error, _E} -> - OutEls = case xml_stream:parse_element( - OutPacket++"</stream:stream>") of - SEl when element(1, SEl) == xmlelement -> - {xmlelement, _, _OutAttrs, SEls} = SEl, - StreamError = false, - case SEls of - [] -> - []; - [{xmlelement, - "stream:features", - StreamAttribs, StreamEls} | - StreamTail] -> - TypedTail = - [xml:replace_tag_attr( - "xmlns", - ?NS_CLIENT,OEl) || - OEl <- StreamTail], - [{xmlelement, - "stream:features", - [{"xmlns:stream", - ?NS_STREAM}] ++ - StreamAttribs, StreamEls}] ++ - TypedTail; - Xml -> - Xml - end; - {error, _} -> - StreamError = true, - [] - end, - if - StreamError -> - StreamErrCond = - case xml_stream:parse_element( - "<stream:stream>"++OutPacket) of - El when element(1, El) == xmlelement -> - {xmlelement, _Tag, _Attr, Els} = El, - [{xmlelement, SE, _, Cond} | _] = Els, - if - SE == "stream:error" -> - Cond; - true -> - null - end; - {error, _E} -> - null - end, - case mnesia:dirty_read({http_bind, Sid}) of - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef, - stop); - _ -> - err %% hu? - end, - case StreamErrCond of - null -> - {200, ?HEADER, - "<body type='terminate' " - "condition='internal-server-error' " - "xmlns='"++?NS_HTTP_BIND++"'/>"}; - _ -> - {200, ?HEADER, - "<body type='terminate' " - "condition='remote-stream-error' " - "xmlns='"++?NS_HTTP_BIND++"'>" ++ - elements_to_string(StreamErrCond) ++ - "</body>"} - end; - true -> - {200, ?HEADER, - xml:element_to_string( - {xmlelement,"body", - [{"xmlns", - ?NS_HTTP_BIND}], - OutEls})} - end - end - end. - %%%---------------------------------------------------------------------- %%% Callback functions from gen_fsm %%%---------------------------------------------------------------------- @@ -768,7 +527,6 @@ terminate(_Reason, _StateName, StateData) -> %%% Internal functions %%%---------------------------------------------------------------------- - http_put(Sid, Rid, Key, NewKey, Hold, Packet, StreamStart) -> ?DEBUG("http-put",[]), case mnesia:dirty_read({http_bind, Sid}) of @@ -787,6 +545,7 @@ http_put(Sid, Rid, Key, NewKey, Hold, Packet, StreamStart) -> end end. + http_get(Sid,Rid) -> case mnesia:dirty_read({http_bind, Sid}) of [] -> @@ -796,6 +555,248 @@ http_get(Sid,Rid) -> {http_get, Rid, Wait, Hold}) end. +handle_http_put(Sid, Rid, Key, NewKey, Wait, Hold, Attrs, + Packet, StreamStart) -> + case http_put(Sid, Rid, Key, NewKey, Hold, Packet, StreamStart) of + {error, not_exists} -> + ?DEBUG("no session associated with sid: ~p", [Sid]), + {404, ?HEADER, ""}; + {error, bad_key} -> + ?DEBUG("bad key: ~s", [Key]), + case mnesia:dirty_read({http_bind, Sid}) of + [] -> + {404, ?HEADER, ""}; + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop), + {404, ?HEADER, ""} + end; + {error, polling_too_frequently} -> + ?DEBUG("polling too frequently: ~p", [Sid]), + case mnesia:dirty_read({http_bind, Sid}) of + [] -> %% unlikely! (?) + {404, ?HEADER, ""}; + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop), + {403, ?HEADER, ""} + end; + {repeat, OutPacket} -> + ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", + [OutPacket]), + send_outpacket(Sid, OutPacket); + ok -> + receive_loop(Sid, Rid, Wait, Hold, Attrs, StreamStart) + end. + + +receive_loop(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> + receive + after 100 -> ok + end, + prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart). + +prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> + case http_get(Sid, Rid) of + {error, not_exists} -> + case xml:get_attr_s("type", Attrs) of + "terminate" -> + {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; + _ -> + ?DEBUG("no session associated with sid: ~s", [Sid]), + {404, ?HEADER, ""} + end; + {ok, keep_on_hold} -> + receive_loop(Sid, Rid, Wait, Hold, Attrs, StreamStart); + {ok, cancel} -> + %% actually it would be better if we could completely + %% cancel this request, but then we would have to hack + %% ejabberd_http and I'm too lazy now + {200, ?HEADER, "<body type='error' xmlns='"++?NS_HTTP_BIND++"'/>"}; + {ok, OutPacket} -> + ?DEBUG("OutPacket: ~s", [OutPacket]), + case StreamStart of + false -> + send_outpacket(Sid, OutPacket); + true -> + OutEls = + case xml_stream:parse_element( + OutPacket++"</stream:stream>") of + El when element(1, El) == xmlelement -> + ?DEBUG("~p", [El]), + {xmlelement, _, OutAttrs, Els} = El, + AuthID = xml:get_attr_s("id", OutAttrs), + From = xml:get_attr_s("from", OutAttrs), + Version = xml:get_attr_s("version", OutAttrs), + StreamError = false, + case Els of + [] -> + []; + [{xmlelement, "stream:features", + StreamAttribs, StreamEls} + | StreamTail] -> + [{xmlelement, "stream:features", + [{"xmlns:stream", + ?NS_STREAM} + ] + ++ StreamAttribs, + StreamEls + }] ++ StreamTail; + Xml -> + Xml + end; + {error, _} -> + AuthID = "", + From = "", + Version = "", + StreamError = true, + [] + end, + if + StreamError == true -> + {200, ?HEADER, "<body type='terminate' " + "condition='host-unknown' " + "xmlns='"++?NS_HTTP_BIND++"'/>"}; + true -> + BOSH_attribs = + [{"authid", AuthID}, + {"xmlns:xmpp", ?NS_BOSH}, + {"xmlns:stream", ?NS_STREAM}] ++ + case OutEls of + [] -> + []; + _ -> + [{"xmpp:version", Version}] + end, + {200, ?HEADER, + xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + ?NS_HTTP_BIND}, + {"sid",Sid}, + {"wait", integer_to_list(Wait)}, + {"requests", integer_to_list(Hold+1)}, + {"inactivity", + integer_to_list(trunc(?MAX_INACTIVITY/1000))}, + {"polling", ?MIN_POLLING}, + {"ver", ?BOSH_VERSION}, + {"from", From}, + {"secure", "true"} %% we're always being secure + ] ++ BOSH_attribs,OutEls})} + end + end + end. + +send_outpacket(Sid, OutPacket) -> + case OutPacket of + "" -> + {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; + "</stream:stream>" -> + case mnesia:dirty_read({http_bind, Sid}) of + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef,stop) + end, + {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; + _ -> + case xml_stream:parse_element("<body>" + ++ OutPacket + ++ "</body>") + of + El when element(1, El) == xmlelement -> + {xmlelement, _, _, OEls} = El, + TypedEls = [xml:replace_tag_attr("xmlns", + ?NS_CLIENT,OEl) || + OEl <- OEls], + ?DEBUG(" --- outgoing data --- ~n~s~n --- END --- ~n", + [xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + ?NS_HTTP_BIND}], + TypedEls})] + ), + {200, ?HEADER, + xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + ?NS_HTTP_BIND}], + TypedEls})}; + {error, _E} -> + OutEls = case xml_stream:parse_element( + OutPacket++"</stream:stream>") of + SEl when element(1, SEl) == xmlelement -> + {xmlelement, _, _OutAttrs, SEls} = SEl, + StreamError = false, + case SEls of + [] -> + []; + [{xmlelement, + "stream:features", + StreamAttribs, StreamEls} | + StreamTail] -> + TypedTail = + [xml:replace_tag_attr( + "xmlns", + ?NS_CLIENT,OEl) || + OEl <- StreamTail], + [{xmlelement, + "stream:features", + [{"xmlns:stream", + ?NS_STREAM}] ++ + StreamAttribs, StreamEls}] ++ + TypedTail; + Xml -> + Xml + end; + {error, _} -> + StreamError = true, + [] + end, + if + StreamError -> + StreamErrCond = + case xml_stream:parse_element( + "<stream:stream>"++OutPacket) of + El when element(1, El) == xmlelement -> + {xmlelement, _Tag, _Attr, Els} = El, + [{xmlelement, SE, _, Cond} | _] = Els, + if + SE == "stream:error" -> + Cond; + true -> + null + end; + {error, _E} -> + null + end, + case mnesia:dirty_read({http_bind, Sid}) of + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef, + stop); + _ -> + err %% hu? + end, + case StreamErrCond of + null -> + {200, ?HEADER, + "<body type='terminate' " + "condition='internal-server-error' " + "xmlns='"++?NS_HTTP_BIND++"'/>"}; + _ -> + {200, ?HEADER, + "<body type='terminate' " + "condition='remote-stream-error' " + "xmlns='"++?NS_HTTP_BIND++"'>" ++ + elements_to_string(StreamErrCond) ++ + "</body>"} + end; + true -> + {200, ?HEADER, + xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + ?NS_HTTP_BIND}], + OutEls})} + end + end + end. parse_request(Data) -> ?DEBUG("--- incoming data --- ~n~s~n --- END --- ", From 202bece16d422460eb18a05b94ac065f56b00cdb Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:25:02 +0000 Subject: [PATCH 396/582] Save bosh version with session (thanks to Stefan Strigler) SVN Revision: 2281 --- src/web/ejabberd_http_bind.erl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index d7a16c14e..7eb10b3f6 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -3,12 +3,12 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : HTTP Binding support (JEP-0124) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 273 2007-08-15 13:53:00Z sstrigler $ +%%% Id : $Id: ejabberd_http_bind.erl 274 2007-08-15 13:54:05Z sstrigler $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 273 $'). +-vsn('$Rev: 274 $'). -behaviour(gen_fsm). @@ -34,7 +34,7 @@ -include("jlib.hrl"). -include("ejabberd_http.hrl"). --record(http_bind, {id, pid, to, hold, wait}). +-record(http_bind, {id, pid, to, hold, wait, version}). %% http binding request -record(hbr, {rid, @@ -162,9 +162,9 @@ process_request(Data) -> pid = Pid, to = {XmppDomain, XmppVersion}, - version = Version, wait = Wait, - hold = Hold}) + hold = Hold, + version = Version}) end), handle_http_put(Sid, Rid, Key, NewKey, Wait, Hold, Attrs, Packet, true) From 6cbae7025c3841b6d7f3235503d574dc1c8d566a Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:25:06 +0000 Subject: [PATCH 397/582] Store version as float (thanks to Stefan Strigler) SVN Revision: 2282 --- src/web/ejabberd_http_bind.erl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 7eb10b3f6..f5decd27b 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -3,12 +3,12 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : HTTP Binding support (JEP-0124) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 274 2007-08-15 13:54:05Z sstrigler $ +%%% Id : $Id: ejabberd_http_bind.erl 275 2007-08-15 13:57:51Z sstrigler $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 274 $'). +-vsn('$Rev: 275 $'). -behaviour(gen_fsm). @@ -154,7 +154,11 @@ process_request(Data) -> CHold end end, - Version = xml:get_attr_s("ver", Attrs), + Version = + case list_to_float(xml:get_attr_s("ver", Attrs)) of + {'EXIT', _} -> 0.0; + V -> V + end, XmppVersion = xml:get_attr_s("xmpp:version", Attrs), mnesia:transaction( fun() -> From 7cb0b1a911553c928d9baec738609f330e372f54 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:25:10 +0000 Subject: [PATCH 398/582] Code cleanup. Code reorganization. Store version of bosh session. Use bosh version for error conditions (thanks to Stefan Strigler) SVN Revision: 2283 --- src/web/ejabberd_http_bind.erl | 320 +++++++++++++++++---------------- 1 file changed, 166 insertions(+), 154 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index f5decd27b..34748f9d4 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -3,12 +3,12 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : HTTP Binding support (JEP-0124) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 275 2007-08-15 13:57:51Z sstrigler $ +%%% Id : $Id: ejabberd_http_bind.erl 276 2007-08-15 16:09:23Z sstrigler $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 275 $'). +-vsn('$Rev: 276 $'). -behaviour(gen_fsm). @@ -43,7 +43,7 @@ out}). -record(state, {id, - rid = error, + rid = none, key, output = "", input = "", @@ -70,8 +70,8 @@ -define(NS_HTTP_BIND, "http://jabber.org/protocol/httpbind"). -define(MAX_REQUESTS, 2). % number of simultaneous requests --define(MIN_POLLING, "2"). % don't poll faster than that or we will - % shoot you +-define(MIN_POLLING, 2000000). % don't poll faster than that or we will + % shoot you (time in sec) -define(MAX_WAIT, 3600). % max num of secs to keep a request on hold -define(MAX_INACTIVITY, 30000). % msecs to wait before terminating % idle sessions @@ -116,7 +116,7 @@ peername(_Socket) -> process_request(Data) -> case catch parse_request(Data) of - {ok, {"", Rid, Key, NewKey, Attrs, Packet}} -> + {ok, {"", Rid, Attrs, Payload}} -> case xml:get_attr_s("to",Attrs) of "" -> {200, ?HEADER, "<body type='terminate' " @@ -125,7 +125,7 @@ process_request(Data) -> XmppDomain -> %% create new session Sid = sha:sha(term_to_binary({now(), make_ref()})), - {ok, Pid} = start(Sid, Key), + {ok, Pid} = start(Sid, ""), ?DEBUG("got pid: ~p", [Pid]), Wait = case string:to_integer(xml:get_attr_s("wait",Attrs)) @@ -160,20 +160,26 @@ process_request(Data) -> V -> V end, XmppVersion = xml:get_attr_s("xmpp:version", Attrs), - mnesia:transaction( - fun() -> - mnesia:write(#http_bind{id = Sid, + case catch mnesia:transaction( + fun() -> + mnesia:write( + #http_bind{id = Sid, pid = Pid, to = {XmppDomain, XmppVersion}, - wait = Wait, hold = Hold, - version = Version}) - end), - handle_http_put(Sid, Rid, Key, NewKey, Wait, Hold, - Attrs, Packet, true) + wait = Wait, + version = Version + }) + end) of + {'EXIT', Reason} -> + ?DEBUG("failed storing session: ~p", [Reason]); + Foo -> + ?DEBUG("foo: ~p", [Foo]) + end, + handle_http_put(Sid, Rid, Attrs, Payload, true) end; - {ok, {Sid, Rid, Key, NewKey, Attrs, Packet}} -> + {ok, {Sid, Rid, Attrs, Payload1}} -> %% old session StreamStart = case xml:get_attr_s("xmpp:restart",Attrs) of @@ -182,17 +188,14 @@ process_request(Data) -> _ -> false end, - Wait = ?MAX_WAIT, - Hold = (?MAX_REQUESTS - 1), - InPacket = case xml:get_attr_s("type",Attrs) of + Payload2 = case xml:get_attr_s("type",Attrs) of "terminate" -> %% close stream - Packet ++ "</stream:stream>"; + Payload1 ++ "</stream:stream>"; _ -> - Packet + Payload1 end, - handle_http_put(Sid, Rid, Key, NewKey, Wait, Hold, Attrs, - InPacket, StreamStart); + handle_http_put(Sid, Rid, Attrs, Payload2, StreamStart); _ -> {400, ?HEADER, ""} end. @@ -281,32 +284,29 @@ handle_sync_event(stop, _From, _StateName, StateData) -> Reply = ok, {stop, normal, Reply, StateData}; -handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StreamTo}, +handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, _From, StateName, StateData) -> + Key = xml:get_attr_s("key", Attrs), + NewKey = xml:get_attr_s("newkey", Attrs), %% check if Rid valid - RidAllow = case Rid of - error -> - false; - _ -> - case StateData#state.rid of - error -> - %% first request - nothing saved so far - true; - OldRid -> - ?DEBUG("state.rid/cur rid: ~p/~p", - [OldRid, Rid]), - if - (OldRid < Rid) and - (Rid =< (OldRid + Hold + 1)) -> - true; - (Rid =< OldRid) and - (Rid > OldRid - Hold - 1) -> - repeat; - true -> - false - end - end - end, + RidAllow = case StateData#state.rid of + none -> + %% first request - nothing saved so far + true; + OldRid -> + ?DEBUG("state.rid/cur rid: ~p/~p", + [OldRid, Rid]), + if + (OldRid < Rid) and + (Rid =< (OldRid + Hold + 1)) -> + true; + (Rid =< OldRid) and + (Rid > OldRid - Hold - 1) -> + repeat; + true -> + false + end + end, %% check if key valid KeyAllow = case RidAllow of repeat -> @@ -335,16 +335,15 @@ handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StreamTo}, {_,TSec,TMSec} = now(), TNow = TSec*1000*1000 + TMSec, LastPoll = if - Packet == "" -> + Payload == "" -> TNow; true -> 0 end, - {MinPoll, _} = string:to_integer(?MIN_POLLING), if - (Packet == "") and + (Payload == "") and (Hold == 0) and - (TNow - StateData#state.last_poll < MinPoll*1000*1000) -> + (TNow - StateData#state.last_poll < ?MIN_POLLING) -> Reply = {error, polling_too_frequently}, {reply, Reply, StateName, StateData}; KeyAllow -> @@ -390,7 +389,7 @@ handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StreamTo}, cancel_timer(StateData#state.timer), Timer = erlang:start_timer( ?MAX_INACTIVITY, self(), []), - Input = Packet ++ [StateData#state.input], + Input = Payload ++ [StateData#state.input], Reply = ok, {reply, Reply, StateName, StateData#state{input = Input, @@ -408,15 +407,15 @@ handle_sync_event({http_put, Rid, Key, NewKey, Hold, Packet, StreamTo}, ["<stream:stream to='", To, "' " "xmlns='"++?NS_CLIENT++"' " "xmlns:stream='"++?NS_STREAM++"'>"] - ++ Packet; + ++ Payload; {To, Version} -> ["<stream:stream to='", To, "' " "xmlns='"++?NS_CLIENT++"' " "version='", Version, "' " "xmlns:stream='"++?NS_STREAM++"'>"] - ++ Packet; + ++ Payload; _ -> - Packet + Payload end, ?DEBUG("really sending now: ~s", [SendPacket]), Receiver ! {tcp, {http_bind, self()}, @@ -531,75 +530,85 @@ terminate(_Reason, _StateName, StateData) -> %%% Internal functions %%%---------------------------------------------------------------------- -http_put(Sid, Rid, Key, NewKey, Hold, Packet, StreamStart) -> - ?DEBUG("http-put",[]), - case mnesia:dirty_read({http_bind, Sid}) of - [] -> - ?DEBUG("not found",[]), - {error, not_exists}; - [#http_bind{pid = FsmRef,to={To, Version}}] -> - case StreamStart of - true -> - ?DEBUG("restart requested for ~s", [To]), - gen_fsm:sync_send_all_state_event( - FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, {To, Version}}); - _ -> - gen_fsm:sync_send_all_state_event( - FsmRef, {http_put, Rid, Key, NewKey, Hold, Packet, ""}) - end - end. - - -http_get(Sid,Rid) -> - case mnesia:dirty_read({http_bind, Sid}) of - [] -> - {error, not_exists}; - [#http_bind{pid = FsmRef, wait = Wait, hold = Hold}] -> - gen_fsm:sync_send_all_state_event(FsmRef, - {http_get, Rid, Wait, Hold}) - end. - -handle_http_put(Sid, Rid, Key, NewKey, Wait, Hold, Attrs, - Packet, StreamStart) -> - case http_put(Sid, Rid, Key, NewKey, Hold, Packet, StreamStart) of +handle_http_put(Sid, Rid, Attrs, Payload, StreamStart) -> + case http_put(Sid, Rid, Attrs, Payload, StreamStart) of {error, not_exists} -> ?DEBUG("no session associated with sid: ~p", [Sid]), {404, ?HEADER, ""}; - {error, bad_key} -> - ?DEBUG("bad key: ~s", [Key]), - case mnesia:dirty_read({http_bind, Sid}) of - [] -> - {404, ?HEADER, ""}; - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop), - {404, ?HEADER, ""} - end; - {error, polling_too_frequently} -> - ?DEBUG("polling too frequently: ~p", [Sid]), - case mnesia:dirty_read({http_bind, Sid}) of - [] -> %% unlikely! (?) - {404, ?HEADER, ""}; - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop), - {403, ?HEADER, ""} - end; - {repeat, OutPacket} -> + {{error, Reason}, Sess} -> + handle_http_put_error(Reason, Sess); + {{repeat, OutPacket}, Sess} -> ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", [OutPacket]), - send_outpacket(Sid, OutPacket); - ok -> - receive_loop(Sid, Rid, Wait, Hold, Attrs, StreamStart) + send_outpacket(Sess, OutPacket); + {ok, Sess} -> + receive_loop(Sess, Rid, Attrs, StreamStart) + end. + +http_put(Sid, Rid, Attrs, Payload, StreamStart) -> + ?DEBUG("http-put",[]), + case mnesia:dirty_read({http_bind, Sid}) of + [] -> + {error, not_exists}; + [#http_bind{pid = FsmRef, hold=Hold, to={To, StreamVersion}}=Sess] -> + NewStream = + case StreamStart of + true -> + {To, StreamVersion}; + _ -> + "" + end, + {gen_fsm:sync_send_all_state_event( + FsmRef, {http_put, Rid, Attrs, Payload, Hold, NewStream}), Sess} + end. + +handle_http_put_error(Reason, #http_bind{pid=FsmRef, version=Version}) + when Version >= 0 -> + gen_fsm:sync_send_all_state_event(FsmRef,stop), + case Reason of + not_exists -> + {200, ?HEADER, + xml:element_to_string( + {xmlelement, "body", + [{"xmlns", ?NS_HTTP_BIND}, + {"type", "terminate"}, + {"condition", "item-not-found"}], []})}; + bad_key -> + {200, ?HEADER, + xml:element_to_string( + {xmlelement, "body", + [{"xmlns", ?NS_HTTP_BIND}, + {"type", "terminate"}, + {"condition", "item-not-found"}], []})}; + polling_too_frequently -> + {200, ?HEADER, + xml:element_to_string( + {xmlelement, "body", + [{"xmlns", ?NS_HTTP_BIND}, + {"type", "terminate"}, + {"condition", "policy-violation"}], []})} + end; +handle_http_put_error(Reason, #http_bind{pid=FsmRef}) -> + gen_fsm:sync_send_all_state_event(FsmRef,stop), + case Reason of + not_exists -> %% bad rid + {404, ?HEADER, ""}; + bad_key -> + {404, ?HEADER, ""}; + polling_too_frequently -> + {403, ?HEADER, ""} end. -receive_loop(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> +receive_loop(Sess, Rid, Attrs, StreamStart) -> receive after 100 -> ok end, - prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart). + prepare_response(Sess, Rid, Attrs, StreamStart). -prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> - case http_get(Sid, Rid) of +prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold}=Sess, + Rid, Attrs, StreamStart) -> + case http_get(Sess, Rid) of {error, not_exists} -> case xml:get_attr_s("type", Attrs) of "terminate" -> @@ -609,7 +618,7 @@ prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> {404, ?HEADER, ""} end; {ok, keep_on_hold} -> - receive_loop(Sid, Rid, Wait, Hold, Attrs, StreamStart); + receive_loop(Sess, Rid, Attrs, StreamStart); {ok, cancel} -> %% actually it would be better if we could completely %% cancel this request, but then we would have to hack @@ -619,7 +628,7 @@ prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> ?DEBUG("OutPacket: ~s", [OutPacket]), case StreamStart of false -> - send_outpacket(Sid, OutPacket); + send_outpacket(Sess, OutPacket); true -> OutEls = case xml_stream:parse_element( @@ -675,12 +684,15 @@ prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> {xmlelement,"body", [{"xmlns", ?NS_HTTP_BIND}, - {"sid",Sid}, + {"sid", Sid}, {"wait", integer_to_list(Wait)}, {"requests", integer_to_list(Hold+1)}, {"inactivity", - integer_to_list(trunc(?MAX_INACTIVITY/1000))}, - {"polling", ?MIN_POLLING}, + integer_to_list( + trunc(?MAX_INACTIVITY/1000))}, + {"polling", + integer_to_list( + trunc(?MIN_POLLING/1000000))}, {"ver", ?BOSH_VERSION}, {"from", From}, {"secure", "true"} %% we're always being secure @@ -688,16 +700,17 @@ prepare_response(Sid, Rid, Wait, Hold, Attrs, StreamStart) -> end end end. + +http_get(#http_bind{pid = FsmRef, wait = Wait, hold = Hold}, Rid) -> + gen_fsm:sync_send_all_state_event(FsmRef, + {http_get, Rid, Wait, Hold}). -send_outpacket(Sid, OutPacket) -> +send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> case OutPacket of "" -> {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; "</stream:stream>" -> - case mnesia:dirty_read({http_bind, Sid}) of - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef,stop) - end, + gen_fsm:sync_send_all_state_event(FsmRef,stop), {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; _ -> case xml_stream:parse_element("<body>" @@ -770,13 +783,8 @@ send_outpacket(Sid, OutPacket) -> {error, _E} -> null end, - case mnesia:dirty_read({http_bind, Sid}) of - [#http_bind{pid = FsmRef}] -> - gen_fsm:sync_send_all_state_event(FsmRef, - stop); - _ -> - err %% hu? - end, + gen_fsm:sync_send_all_state_event(FsmRef, + stop), case StreamErrCond of null -> {200, ?HEADER, @@ -808,38 +816,42 @@ parse_request(Data) -> case xml_stream:parse_element(Data) of El when element(1, El) == xmlelement -> {xmlelement, Name, Attrs, Els} = El, - FixedEls = - lists:filter( - fun(I) -> - case I of - {xmlelement, _, _, _} -> - true; - _ -> - false - end - end, Els), - Sid = xml:get_attr_s("sid",Attrs), - {Rid,_X} = string:to_integer(xml:get_attr_s("rid",Attrs)), - Key = xml:get_attr_s("key",Attrs), - NewKey = xml:get_attr_s("newkey",Attrs), Xmlns = xml:get_attr_s("xmlns",Attrs), - lists:map(fun(E) -> - EXmlns = xml:get_tag_attr_s("xmlns",E), - if - EXmlns == ?NS_CLIENT -> - remove_tag_attr("xmlns",E); - true -> - ok - end - end, FixedEls), - Packet = [xml:element_to_string(E) || E <- FixedEls], if Name /= "body" -> {error, bad_request}; Xmlns /= ?NS_HTTP_BIND -> {error, bad_request}; true -> - {ok, {Sid, Rid, Key, NewKey, Attrs, Packet}} + case list_to_integer(xml:get_attr_s("rid", Attrs)) of + {'EXIT', _} -> + {error, bad_request}; + Rid -> + FixedEls = + lists:filter( + fun(I) -> + case I of + {xmlelement, _, _, _} -> + true; + _ -> + false + end + end, Els), + lists:map( + fun(E) -> + EXmlns = xml:get_tag_attr_s("xmlns",E), + if + EXmlns == ?NS_CLIENT -> + remove_tag_attr("xmlns",E); + true -> + ok + end + end, FixedEls), + Payload = [xml:element_to_string(E) || + E <- FixedEls], + Sid = xml:get_attr_s("sid",Attrs), + {ok, {Sid, Rid, Attrs, Payload}} + end end; {error, _Reason} -> {error, bad_request} From bf4e927142a1c4ae248d291f456a576070dc44cc Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:25:14 +0000 Subject: [PATCH 399/582] Removed debugging stuff. Removed error condition (thanks to Stefan Strigler) SVN Revision: 2284 --- src/web/ejabberd_http_bind.erl | 41 ++++++++++++---------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 34748f9d4..31a9a5ca1 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -3,12 +3,12 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : HTTP Binding support (JEP-0124) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 276 2007-08-15 16:09:23Z sstrigler $ +%%% Id : $Id: ejabberd_http_bind.erl 277 2007-08-16 09:39:05Z sstrigler $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 276 $'). +-vsn('$Rev: 277 $'). -behaviour(gen_fsm). @@ -160,23 +160,18 @@ process_request(Data) -> V -> V end, XmppVersion = xml:get_attr_s("xmpp:version", Attrs), - case catch mnesia:transaction( - fun() -> - mnesia:write( - #http_bind{id = Sid, - pid = Pid, - to = {XmppDomain, - XmppVersion}, - hold = Hold, - wait = Wait, - version = Version - }) - end) of - {'EXIT', Reason} -> - ?DEBUG("failed storing session: ~p", [Reason]); - Foo -> - ?DEBUG("foo: ~p", [Foo]) - end, + mnesia:transaction( + fun() -> + mnesia:write( + #http_bind{id = Sid, + pid = Pid, + to = {XmppDomain, + XmppVersion}, + hold = Hold, + wait = Wait, + version = Version + }) + end), handle_http_put(Sid, Rid, Attrs, Payload, true) end; {ok, {Sid, Rid, Attrs, Payload1}} -> @@ -609,14 +604,6 @@ receive_loop(Sess, Rid, Attrs, StreamStart) -> prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold}=Sess, Rid, Attrs, StreamStart) -> case http_get(Sess, Rid) of - {error, not_exists} -> - case xml:get_attr_s("type", Attrs) of - "terminate" -> - {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; - _ -> - ?DEBUG("no session associated with sid: ~s", [Sid]), - {404, ?HEADER, ""} - end; {ok, keep_on_hold} -> receive_loop(Sess, Rid, Attrs, StreamStart); {ok, cancel} -> From c151da684d2414095eb07322afec0c829182c9dd Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:25:18 +0000 Subject: [PATCH 400/582] Comment-header: talk about xmpp over bosh rather than http binding (thanks to Stefan Strigler) SVN Revision: 2285 --- src/web/ejabberd_http_bind.erl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 31a9a5ca1..658d42e56 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -1,14 +1,15 @@ %%%---------------------------------------------------------------------- %%% File : ejabberd_http_bind.erl %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> -%%% Purpose : HTTP Binding support (JEP-0124) +%%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as +%%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 277 2007-08-16 09:39:05Z sstrigler $ +%%% Id : $Id: ejabberd_http_bind.erl 278 2007-08-16 10:53:28Z sstrigler $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 277 $'). +-vsn('$Rev: 278 $'). -behaviour(gen_fsm). From 8aede811885ea3e27839355cabe913a7b7586b98 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:25:22 +0000 Subject: [PATCH 401/582] Support pausing sessions (thanks to Stefan Strigler) (thanks to Stefan Strigler) SVN Revision: 2286 --- src/web/ejabberd_http_bind.erl | 60 +++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 658d42e56..6cb8ca44d 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,12 +4,12 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 278 2007-08-16 10:53:28Z sstrigler $ +%%% Id : $Id: ejabberd_http_bind.erl 280 2007-08-16 13:25:41Z sstrigler $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 278 $'). +-vsn('$Rev: 280 $'). -behaviour(gen_fsm). @@ -53,6 +53,7 @@ last_poll, ctime = 0, timer, + pause=0, req_list = [] % list of requests }). @@ -73,9 +74,12 @@ -define(MAX_REQUESTS, 2). % number of simultaneous requests -define(MIN_POLLING, 2000000). % don't poll faster than that or we will % shoot you (time in sec) --define(MAX_WAIT, 3600). % max num of secs to keep a request on hold +-define(MAX_WAIT, 3600). % max num of secs to keep a request on hold -define(MAX_INACTIVITY, 30000). % msecs to wait before terminating % idle sessions +-define(MAX_PAUSE, 120). % may num of sec a client is allowed to pause + % the session + -define(CT, {"Content-Type", "text/xml; charset=utf-8"}). -define(HEADER, [?CT]). @@ -288,14 +292,19 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, RidAllow = case StateData#state.rid of none -> %% first request - nothing saved so far - true; + {true, 0}; OldRid -> ?DEBUG("state.rid/cur rid: ~p/~p", [OldRid, Rid]), if (OldRid < Rid) and (Rid =< (OldRid + Hold + 1)) -> - true; + case xml:get_attr_s("pause", Attrs) of + Pause1 when Pause1 =< ?MAX_PAUSE -> + {true, Pause1}; + _ -> + {true, 0} + end; (Rid =< OldRid) and (Rid > OldRid - Hold - 1) -> repeat; @@ -309,7 +318,7 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, true; false -> false; - true -> + {true, _} -> case StateData#state.key of "" -> true; @@ -360,7 +369,7 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, end, {reply, Reply, StateName, StateData#state{input = "cancel", last_poll = LastPoll}}; - true -> + {true, Pause} -> SaveKey = if NewKey == "" -> Key; @@ -380,11 +389,19 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, El#hbr.rid > (Rid - 1 - Hold)] ], %% ?DEBUG("reqlist: ~p", [ReqList]), + + %% setup next timer + cancel_timer(StateData#state.timer), + if + Pause > 0 -> + Timer = erlang:start_timer( + Pause, self(), []); + true -> + Timer = erlang:start_timer( + ?MAX_INACTIVITY, self(), []) + end, case StateData#state.waiting_input of false -> - cancel_timer(StateData#state.timer), - Timer = erlang:start_timer( - ?MAX_INACTIVITY, self(), []), Input = Payload ++ [StateData#state.input], Reply = ok, {reply, Reply, StateName, @@ -393,6 +410,7 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, key = SaveKey, ctime = TNow, timer = Timer, + pause = Pause, last_poll = LastPoll, req_list = ReqList }}; @@ -416,9 +434,6 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, ?DEBUG("really sending now: ~s", [SendPacket]), Receiver ! {tcp, {http_bind, self()}, list_to_binary(SendPacket)}, - cancel_timer(StateData#state.timer), - Timer = erlang:start_timer( - ?MAX_INACTIVITY, self(), []), Reply = ok, {reply, Reply, StateName, StateData#state{waiting_input = false, @@ -428,6 +443,7 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, key = SaveKey, ctime = TNow, timer = Timer, + pause = Pause, last_poll = LastPoll, req_list = ReqList }} @@ -439,16 +455,26 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, end; handle_sync_event({http_get, Rid, Wait, Hold}, _From, StateName, StateData) -> + %% setup timer + cancel_timer(StateData#state.timer), + if + StateData#state.pause > 0 -> + Timer = erlang:start_timer( + StateData#state.pause, self(), []); + true -> + Timer = erlang:start_timer( + ?MAX_INACTIVITY, self(), []) + end, + {_,TSec,TMSec} = now(), TNow = TSec*1000*1000 + TMSec, - cancel_timer(StateData#state.timer), - Timer = erlang:start_timer(?MAX_INACTIVITY, self(), []), if (Hold > 0) and (StateData#state.output == "") and ((TNow - StateData#state.ctime) < (Wait*1000*1000)) and (StateData#state.rid == Rid) and - (StateData#state.input /= "cancel") -> + (StateData#state.input /= "cancel") and + (StateData#state.pause == 0) -> Output = StateData#state.output, ReqList = StateData#state.req_list, Reply = {ok, keep_on_hold}; @@ -678,6 +704,8 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold}=Sess, {"inactivity", integer_to_list( trunc(?MAX_INACTIVITY/1000))}, + {"maxpause", + integer_to_list(?MAX_PAUSE)}, {"polling", integer_to_list( trunc(?MIN_POLLING/1000000))}, From 2f29e761c27c1c383818a28d5e31e4704b26226a Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:25:26 +0000 Subject: [PATCH 402/582] Fixes for pausing sessions; did not parse 'pause' attribute to int (thanks to Stefan Strigler) SVN Revision: 2287 --- src/web/ejabberd_http_bind.erl | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 6cb8ca44d..b092affa4 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,12 +4,12 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 280 2007-08-16 13:25:41Z sstrigler $ +%%% Id : $Id: ejabberd_http_bind.erl 282 2007-08-16 14:53:04Z sstrigler $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 280 $'). +-vsn('$Rev: 282 $'). -behaviour(gen_fsm). @@ -299,8 +299,12 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, if (OldRid < Rid) and (Rid =< (OldRid + Hold + 1)) -> - case xml:get_attr_s("pause", Attrs) of + case catch list_to_integer( + xml:get_attr_s("pause", Attrs)) of + {'EXIT', _} -> + {true, 0}; Pause1 when Pause1 =< ?MAX_PAUSE -> + ?DEBUG("got pause: ~p", [Pause1]), {true, Pause1}; _ -> {true, 0} @@ -395,7 +399,7 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, if Pause > 0 -> Timer = erlang:start_timer( - Pause, self(), []); + Pause*1000, self(), []); true -> Timer = erlang:start_timer( ?MAX_INACTIVITY, self(), []) @@ -460,7 +464,7 @@ handle_sync_event({http_get, Rid, Wait, Hold}, _From, StateName, StateData) -> if StateData#state.pause > 0 -> Timer = erlang:start_timer( - StateData#state.pause, self(), []); + StateData#state.pause*1000, self(), []); true -> Timer = erlang:start_timer( ?MAX_INACTIVITY, self(), []) From 4adf23b4e9ad1ace59870c6d79a16e92966fa668 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:25:30 +0000 Subject: [PATCH 403/582] Forgot keyword 'catch' when doing list_to_float on bosh version attribute for initial request (thanks to Stefan Strigler) SVN Revision: 2288 --- src/web/ejabberd_http_bind.erl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index b092affa4..094e92793 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,12 +4,12 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 282 2007-08-16 14:53:04Z sstrigler $ +%%% Id : $Id: ejabberd_http_bind.erl 349 2007-08-30 13:39:57Z sstrigler $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 282 $'). +-vsn('$Rev: 349 $'). -behaviour(gen_fsm). @@ -160,7 +160,8 @@ process_request(Data) -> end end, Version = - case list_to_float(xml:get_attr_s("ver", Attrs)) of + case catch list_to_float( + xml:get_attr_s("ver", Attrs)) of {'EXIT', _} -> 0.0; V -> V end, From b0b708ddea5934372394d196177ab0ba8222d578 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:25:34 +0000 Subject: [PATCH 404/582] Use DEBUG instead of INFO_MSG to keep log files small. Fix parse errors for grepping 'stream:error' (thanks to Stefan Strigler) SVN Revision: 2289 --- src/web/ejabberd_http_bind.erl | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 094e92793..f366a7c1a 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,12 +4,12 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 349 2007-08-30 13:39:57Z sstrigler $ +%%% Id : $Id: ejabberd_http_bind.erl 389 2007-09-25 15:27:44Z sstrigler $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 349 $'). +-vsn('$Rev: 389 $'). -behaviour(gen_fsm). @@ -213,7 +213,7 @@ process_request(Data) -> %% {stop, StopReason} %%---------------------------------------------------------------------- init([Sid, Key]) -> - ?INFO_MSG("started: ~p", [{Sid, Key}]), + ?DEBUG("started: ~p", [{Sid, Key}]), Opts = [], % TODO ejabberd_socket:start(ejabberd_c2s, ?MODULE, {http_bind, self()}, Opts), % {ok, C2SPid} = ejabberd_c2s:start({?MODULE, {http_bind, self()}}, Opts), @@ -793,14 +793,12 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> case xml_stream:parse_element( "<stream:stream>"++OutPacket) of El when element(1, El) == xmlelement -> - {xmlelement, _Tag, _Attr, Els} = El, - [{xmlelement, SE, _, Cond} | _] = Els, - if - SE == "stream:error" -> - Cond; - true -> - null - end; + case xml:get_subtag(El, "stream:error") of + false -> + null; + {xmlelement, _, _, Cond} -> + Cond + end; {error, _E} -> null end, From 5f7356c16c1aee304da00d15bc6456de6db890c9 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:25:38 +0000 Subject: [PATCH 405/582] The Erlang/OTP function httpd_util:to_lower/1 is deprecated, and it is recommended to use string:to_lower/1 instead. SVN Revision: 2290 --- src/web/ejabberd_http_bind.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index f366a7c1a..ac01ccb24 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,12 +4,12 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 389 2007-09-25 15:27:44Z sstrigler $ +%%% Id : $Id: ejabberd_http_bind.erl 403 2007-10-20 15:36:13Z badlop $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 389 $'). +-vsn('$Rev: 403 $'). -behaviour(gen_fsm). @@ -328,7 +328,7 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, "" -> true; OldKey -> - NextKey = httpd_util:to_lower( + NextKey = string:to_lower( hex(binary_to_list( crypto:sha(Key)))), ?DEBUG("Key/OldKey/NextKey: ~s/~s/~s", From 818f28d85f3e43b4a2cb6e0eedea6ba8176f81cb Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:25:42 +0000 Subject: [PATCH 406/582] Support for c2s ACL access, max_stanza and shaper on http_poll connections (EJAB-243, EJAB-415, EJAB-416)(thanks to Michael Remond) SVN Revision: 2291 --- src/web/ejabberd_http_bind.erl | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index ac01ccb24..7d16e7451 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,12 +4,12 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 403 2007-10-20 15:36:13Z badlop $ +%%% Id : $Id: ejabberd_http_bind.erl 405 2007-11-02 14:58:36Z mremond $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 403 $'). +-vsn('$Rev: 405 $'). -behaviour(gen_fsm). @@ -214,7 +214,15 @@ process_request(Data) -> %%---------------------------------------------------------------------- init([Sid, Key]) -> ?DEBUG("started: ~p", [{Sid, Key}]), - Opts = [], % TODO + + %% Read c2s options from the first ejabberd_c2s configuration in + %% the config file listen section + %% TODO: We should have different access and shaper values for + %% each connector. The default behaviour should be however to use + %% the default c2s restrictions if not defined for the current + %% connector. + Opts = ejabberd_c2s_config:get_c2s_limits(), + ejabberd_socket:start(ejabberd_c2s, ?MODULE, {http_bind, self()}, Opts), % {ok, C2SPid} = ejabberd_c2s:start({?MODULE, {http_bind, self()}}, Opts), % ejabberd_c2s:become_controller(C2SPid), From 86738e965fbbf395b215845af53300dd80573709 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:25:46 +0000 Subject: [PATCH 407/582] Do not overwrite the stanza namespace (thanks to Anastasia Gornostaeva) SVN Revision: 2292 --- src/web/ejabberd_http_bind.erl | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 7d16e7451..e68ef8a8e 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,12 +4,12 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 405 2007-11-02 14:58:36Z mremond $ +%%% Id : $Id: ejabberd_http_bind.erl 408 2007-11-08 15:48:24Z badlop $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 405 $'). +-vsn('$Rev: 408 $'). -behaviour(gen_fsm). @@ -748,8 +748,7 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> of El when element(1, El) == xmlelement -> {xmlelement, _, _, OEls} = El, - TypedEls = [xml:replace_tag_attr("xmlns", - ?NS_CLIENT,OEl) || + TypedEls = [check_default_xmlns(OEl) || OEl <- OEls], ?DEBUG(" --- outgoing data --- ~n~s~n --- END --- ~n", [xml:element_to_string( @@ -778,10 +777,8 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> StreamAttribs, StreamEls} | StreamTail] -> TypedTail = - [xml:replace_tag_attr( - "xmlns", - ?NS_CLIENT,OEl) || - OEl <- StreamTail], + [check_default_xmlns(OEl) || + OEl <- StreamTail], [{xmlelement, "stream:features", [{"xmlns:stream", @@ -917,3 +914,12 @@ remove_tag_attr(Attr, El) -> _ -> El end. + +check_default_xmlns({xmlelement, Name, Attrs, Els} = El) -> + EXmlns = xml:get_tag_attr_s("xmlns", El), + if + EXmlns == "" -> + {xmlelement, Name, [{"xmlns", ?NS_CLIENT} | Attrs], Els}; + true -> + El + end. From d84a2f821530602da55427b83df7459d2655a74a Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:25:51 +0000 Subject: [PATCH 408/582] Migration code for people using previous version of the HTTP binding module (EJAB-390) SVN Revision: 2293 --- src/web/ejabberd_http_bind.erl | 24 +++++++++++++++++++----- src/web/mod_http_bind.erl | 2 +- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index e68ef8a8e..b0204c1cc 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,12 +4,12 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 408 2007-11-08 15:48:24Z badlop $ +%%% Id : $Id: ejabberd_http_bind.erl 430 2007-11-27 22:03:44Z badlop $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 408 $'). +-vsn('$Rev: 430 $ '). -behaviour(gen_fsm). @@ -88,9 +88,7 @@ %%% API %%%---------------------------------------------------------------------- start(Sid, Key) -> - mnesia:create_table(http_bind, - [{ram_copies, [node()]}, - {attributes, record_info(fields, http_bind)}]), + setup_database(), supervisor:start_child(ejabberd_http_bind_sup, [Sid, Key]). start_link(Sid, Key) -> @@ -923,3 +921,19 @@ check_default_xmlns({xmlelement, Name, Attrs, Els} = El) -> true -> El end. + +setup_database() -> + migrate_database(), + mnesia:create_table(http_bind, + [{ram_copies, [node()]}, + {attributes, record_info(fields, http_bind)}]). + +migrate_database() -> + case mnesia:table_info(http_bind, attributes) of + [id, pid, to, hold, wait, version] -> + ok; + _ -> + %% Since the stored information is not important, instead + %% of actually migrating data, let's just destroy the table + mnesia:delete_table(http_bind) + end. diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index 1dba7d193..edd9fa08c 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -3,7 +3,7 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : Implementation of XMPP over BOSH (XEP-0206) %%% Created : Tue Feb 20 13:15:52 CET 2007 -%%% Id : $Id: mod_http_bind.erl 156 2007-06-25 09:22:57Z cromain $ +%%% Id : $Id: mod_http_bind.erl 412 2007-11-15 10:10:09Z mremond $ %%%---------------------------------------------------------------------- %%%---------------------------------------------------------------------- From ff4ccc1d85d40262dc89fd2e8edb7364c0ca4602 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:25:54 +0000 Subject: [PATCH 409/582] Bugfix when table does not exist (thanks to Justin Kirby) SVN Revision: 2294 --- src/web/ejabberd_http_bind.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index b0204c1cc..8c3826d91 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,12 +4,12 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 430 2007-11-27 22:03:44Z badlop $ +%%% Id : $Id: ejabberd_http_bind.erl 431 2007-11-28 18:52:39Z badlop $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 430 $ '). +-vsn('$Rev: 431 $ '). -behaviour(gen_fsm). @@ -929,7 +929,7 @@ setup_database() -> {attributes, record_info(fields, http_bind)}]). migrate_database() -> - case mnesia:table_info(http_bind, attributes) of + case catch mnesia:table_info(http_bind, attributes) of [id, pid, to, hold, wait, version] -> ok; _ -> From 68754c4b5d75cff5350e511abe4e3d8bd269f0e6 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:25:59 +0000 Subject: [PATCH 410/582] Remove Erlang module attribute 'vsn' because it does not provide any worth feature, and it difficults hot code update (EJAB-440) SVN Revision: 2295 --- src/web/ejabberd_http_bind.erl | 3 +-- src/web/mod_http_bind.erl | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 8c3826d91..19331c5ac 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,12 +4,11 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 431 2007-11-28 18:52:39Z badlop $ +%%% Id : $Id: ejabberd_http_bind.erl 440 2007-12-06 22:36:21Z badlop $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). -author('steve@zeank.in-berlin.de'). --vsn('$Rev: 431 $ '). -behaviour(gen_fsm). diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index edd9fa08c..9f3dddbe6 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -3,7 +3,7 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : Implementation of XMPP over BOSH (XEP-0206) %%% Created : Tue Feb 20 13:15:52 CET 2007 -%%% Id : $Id: mod_http_bind.erl 412 2007-11-15 10:10:09Z mremond $ +%%% Id : $Id: mod_http_bind.erl 440 2007-12-06 22:36:21Z badlop $ %%%---------------------------------------------------------------------- %%%---------------------------------------------------------------------- @@ -16,7 +16,6 @@ -author('steve@zeank.in-berlin.de'). -define(MOD_HTTP_BIND_VERSION, "1.2"). --vsn(?MOD_HTTP_BIND_VERSION). %%-define(ejabberd_debug, true). From 5f07b4bf9beefb976939320d310efd459a53dbc9 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:26:02 +0000 Subject: [PATCH 411/582] Removed receive_loop (thanks to Alexey Shchepin) SVN Revision: 2296 --- src/web/ejabberd_http_bind.erl | 148 +++++++++++++++++++++++---------- 1 file changed, 104 insertions(+), 44 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 19331c5ac..9e18559cd 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 440 2007-12-06 22:36:21Z badlop $ +%%% Id : $Id: ejabberd_http_bind.erl 449 2007-12-18 15:00:10Z alexey $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -50,6 +50,8 @@ waiting_input = false, last_receiver, last_poll, + http_receiver, + wait_timer, ctime = 0, timer, pause=0, @@ -72,7 +74,7 @@ -define(MAX_REQUESTS, 2). % number of simultaneous requests -define(MIN_POLLING, 2000000). % don't poll faster than that or we will - % shoot you (time in sec) + % shoot you (time in sec) -define(MAX_WAIT, 3600). % max num of secs to keep a request on hold -define(MAX_INACTIVITY, 30000). % msecs to wait before terminating % idle sessions @@ -283,8 +285,30 @@ handle_event(_Event, StateName, StateData) -> %%---------------------------------------------------------------------- handle_sync_event({send, Packet}, _From, StateName, StateData) -> Output = [StateData#state.output | Packet], - Reply = ok, - {reply, Reply, StateName, StateData#state{output = Output}}; + if + StateData#state.http_receiver /= undefined -> + HTTPReply = case Output of + [[]| OutPacket] -> + {ok, OutPacket}; + _ -> + {ok, Output} + end, + gen_fsm:reply(StateData#state.http_receiver, HTTPReply), + if + StateData#state.wait_timer /= undefined -> + cancel_timer(StateData#state.wait_timer); + true -> + ok + end, + Reply = ok, + {reply, Reply, StateName, + StateData#state{output = [], + http_receiver = undefined, + wait_timer = undefined}}; + true -> + Reply = ok, + {reply, Reply, StateName, StateData#state{output = Output}} + end; handle_sync_event(stop, _From, _StateName, StateData) -> Reply = ok, @@ -333,7 +357,7 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, "" -> true; OldKey -> - NextKey = string:to_lower( + NextKey = jlib:tolower( hex(binary_to_list( crypto:sha(Key)))), ?DEBUG("Key/OldKey/NextKey: ~s/~s/~s", @@ -464,18 +488,29 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, {reply, Reply, StateName, StateData} end; -handle_sync_event({http_get, Rid, Wait, Hold}, _From, StateName, StateData) -> +handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> %% setup timer cancel_timer(StateData#state.timer), - if - StateData#state.pause > 0 -> - Timer = erlang:start_timer( + Timer = if + StateData#state.pause > 0 -> + erlang:start_timer( StateData#state.pause*1000, self(), []); - true -> - Timer = erlang:start_timer( + true -> + erlang:start_timer( ?MAX_INACTIVITY, self(), []) + end, + if + StateData#state.http_receiver /= undefined -> + gen_fsm:reply(StateData#state.http_receiver, {ok, empty}); + true -> + ok + end, + if + StateData#state.wait_timer /= undefined -> + cancel_timer(StateData#state.wait_timer); + true -> + ok end, - {_,TSec,TMSec} = now(), TNow = TSec*1000*1000 + TMSec, if @@ -487,11 +522,25 @@ handle_sync_event({http_get, Rid, Wait, Hold}, _From, StateName, StateData) -> (StateData#state.pause == 0) -> Output = StateData#state.output, ReqList = StateData#state.req_list, - Reply = {ok, keep_on_hold}; + WaitTimer = erlang:start_timer(Wait * 1000, self(), []), + {next_state, StateName, StateData#state{ + input = "", + output = Output, + http_receiver = From, + wait_timer = WaitTimer, + timer = Timer, + req_list = ReqList}}; (StateData#state.input == "cancel") -> Output = StateData#state.output, ReqList = StateData#state.req_list, - Reply = {ok, cancel}; + Reply = {ok, cancel}, + {reply, Reply, StateName, StateData#state{ + input = "", + output = Output, + http_receiver = undefined, + wait_timer = undefined, + timer = Timer, + req_list = ReqList}}; true -> case StateData#state.output of [[]| OutPacket] -> @@ -508,13 +557,15 @@ handle_sync_event({http_get, Rid, Wait, Hold}, _From, StateName, StateData) -> [El || El <- StateData#state.req_list, El#hbr.rid /= Rid ] ], - Output = "" - end, - {reply, Reply, StateName, StateData#state{ - input = "", - output = Output, - timer = Timer, - req_list = ReqList}}; + Output = "", + {reply, Reply, StateName, StateData#state{ + input = "", + output = Output, + http_receiver = undefined, + wait_timer = undefined, + timer = Timer, + req_list = ReqList}} + end; handle_sync_event(_Event, _From, StateName, StateData) -> Reply = ok, @@ -534,6 +585,18 @@ handle_info({timeout, Timer, _}, _StateName, ?DEBUG("ding dong", []), {stop, normal, StateData}; +handle_info({timeout, Timer, _}, StateName, + #state{wait_timer = Timer} = StateData) -> + if + StateData#state.http_receiver /= undefined -> + gen_fsm:reply(StateData#state.http_receiver, {ok, empty}), + {next_state, StateName, + StateData#state{http_receiver = undefined, + wait_timer = undefined}}; + true -> + {next_state, StateName, StateData} + end; + handle_info(_, StateName, StateData) -> {next_state, StateName, StateData}. @@ -574,7 +637,7 @@ handle_http_put(Sid, Rid, Attrs, Payload, StreamStart) -> [OutPacket]), send_outpacket(Sess, OutPacket); {ok, Sess} -> - receive_loop(Sess, Rid, Attrs, StreamStart) + prepare_response(Sess, Rid, Attrs, StreamStart) end. http_put(Sid, Rid, Attrs, Payload, StreamStart) -> @@ -632,22 +695,17 @@ handle_http_put_error(Reason, #http_bind{pid=FsmRef}) -> end. -receive_loop(Sess, Rid, Attrs, StreamStart) -> - receive - after 100 -> ok - end, - prepare_response(Sess, Rid, Attrs, StreamStart). - prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold}=Sess, Rid, Attrs, StreamStart) -> - case http_get(Sess, Rid) of - {ok, keep_on_hold} -> - receive_loop(Sess, Rid, Attrs, StreamStart); + receive after 100 -> ok end, + case catch http_get(Sess, Rid) of {ok, cancel} -> %% actually it would be better if we could completely %% cancel this request, but then we would have to hack %% ejabberd_http and I'm too lazy now {200, ?HEADER, "<body type='error' xmlns='"++?NS_HTTP_BIND++"'/>"}; + {ok, empty} -> + {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; {ok, OutPacket} -> ?DEBUG("OutPacket: ~s", [OutPacket]), case StreamStart of @@ -724,13 +782,15 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold}=Sess, {"secure", "true"} %% we're always being secure ] ++ BOSH_attribs,OutEls})} end - end + end; + {'EXIT', _Reason} -> + {200, ?HEADER, "<body type='terminate' xmlns='"++?NS_HTTP_BIND++"'/>"} end. http_get(#http_bind{pid = FsmRef, wait = Wait, hold = Hold}, Rid) -> - gen_fsm:sync_send_all_state_event(FsmRef, - {http_get, Rid, Wait, Hold}). - + gen_fsm:sync_send_all_state_event( + FsmRef, {http_get, Rid, Wait, Hold}, 2 * ?MAX_WAIT * 1000). + send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> case OutPacket of "" -> @@ -789,18 +849,18 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> StreamError = true, [] end, - if + if StreamError -> StreamErrCond = case xml_stream:parse_element( - "<stream:stream>"++OutPacket) of + "<stream:stream>" ++ OutPacket) of El when element(1, El) == xmlelement -> - case xml:get_subtag(El, "stream:error") of - false -> - null; - {xmlelement, _, _, Cond} -> - Cond - end; + case xml:get_subtag(El, "stream:error") of + false -> + null; + {xmlelement, _, _, Cond} -> + Cond + end; {error, _E} -> null end, @@ -844,7 +904,7 @@ parse_request(Data) -> Xmlns /= ?NS_HTTP_BIND -> {error, bad_request}; true -> - case list_to_integer(xml:get_attr_s("rid", Attrs)) of + case catch list_to_integer(xml:get_attr_s("rid", Attrs)) of {'EXIT', _} -> {error, bad_request}; Rid -> From 94c3a384b16e8edd41553a7d9fbb8d0bc1b522a4 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:26:07 +0000 Subject: [PATCH 412/582] Bugfixes (thanks to Alexey Shchepin) SVN Revision: 2297 --- src/web/ejabberd_http_bind.erl | 118 +++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 28 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 9e18559cd..d2806da51 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 449 2007-12-18 15:00:10Z alexey $ +%%% Id : $Id: ejabberd_http_bind.erl 453 2007-12-20 14:35:04Z alexey $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -74,7 +74,7 @@ -define(MAX_REQUESTS, 2). % number of simultaneous requests -define(MIN_POLLING, 2000000). % don't poll faster than that or we will - % shoot you (time in sec) + % shoot you (time in microsec) -define(MAX_WAIT, 3600). % max num of secs to keep a request on hold -define(MAX_INACTIVITY, 30000). % msecs to wait before terminating % idle sessions @@ -110,7 +110,7 @@ controlling_process(_Socket, _Pid) -> ok. close({http_bind, FsmRef}) -> - catch gen_fsm:sync_send_all_state_event(FsmRef, close). + catch gen_fsm:sync_send_all_state_event(FsmRef, stop). sockname(_Socket) -> {ok, {{0, 0, 0, 0}, 0}}. @@ -287,6 +287,20 @@ handle_sync_event({send, Packet}, _From, StateName, StateData) -> Output = [StateData#state.output | Packet], if StateData#state.http_receiver /= undefined -> + if + StateData#state.timer /= undefined -> + cancel_timer(StateData#state.timer); + true -> + ok + end, + Timer = if + StateData#state.pause > 0 -> + erlang:start_timer( + StateData#state.pause*1000, self(), []); + true -> + erlang:start_timer( + ?MAX_INACTIVITY, self(), []) + end, HTTPReply = case Output of [[]| OutPacket] -> {ok, OutPacket}; @@ -304,7 +318,8 @@ handle_sync_event({send, Packet}, _From, StateName, StateData) -> {reply, Reply, StateName, StateData#state{output = [], http_receiver = undefined, - wait_timer = undefined}}; + wait_timer = undefined, + timer = Timer}}; true -> Reply = ok, {reply, Reply, StateName, StateData#state{output = Output}} @@ -371,8 +386,8 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, end end end, - {_,TSec,TMSec} = now(), - TNow = TSec*1000*1000 + TMSec, + {TMegSec, TSec, TMSec} = now(), + TNow = (TMegSec * 1000000 + TSec) * 1000000 + TMSec, LastPoll = if Payload == "" -> TNow; @@ -425,15 +440,20 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, %% ?DEBUG("reqlist: ~p", [ReqList]), %% setup next timer - cancel_timer(StateData#state.timer), - if - Pause > 0 -> - Timer = erlang:start_timer( + if + StateData#state.timer /= undefined -> + cancel_timer(StateData#state.timer); + true -> + ok + end, + Timer = if + Pause > 0 -> + erlang:start_timer( Pause*1000, self(), []); - true -> - Timer = erlang:start_timer( + true -> + erlang:start_timer( ?MAX_INACTIVITY, self(), []) - end, + end, case StateData#state.waiting_input of false -> Input = Payload ++ [StateData#state.input], @@ -490,15 +510,6 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> %% setup timer - cancel_timer(StateData#state.timer), - Timer = if - StateData#state.pause > 0 -> - erlang:start_timer( - StateData#state.pause*1000, self(), []); - true -> - erlang:start_timer( - ?MAX_INACTIVITY, self(), []) - end, if StateData#state.http_receiver /= undefined -> gen_fsm:reply(StateData#state.http_receiver, {ok, empty}); @@ -511,8 +522,8 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> true -> ok end, - {_,TSec,TMSec} = now(), - TNow = TSec*1000*1000 + TMSec, + {TMegSec, TSec, TMSec} = now(), + TNow = (TMegSec * 1000000 + TSec) * 1000000 + TMSec, if (Hold > 0) and (StateData#state.output == "") and @@ -528,9 +539,23 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> output = Output, http_receiver = From, wait_timer = WaitTimer, - timer = Timer, + timer = undefined, req_list = ReqList}}; (StateData#state.input == "cancel") -> + if + StateData#state.timer /= undefined -> + cancel_timer(StateData#state.timer); + true -> + ok + end, + Timer = if + StateData#state.pause > 0 -> + erlang:start_timer( + StateData#state.pause*1000, self(), []); + true -> + erlang:start_timer( + ?MAX_INACTIVITY, self(), []) + end, Output = StateData#state.output, ReqList = StateData#state.req_list, Reply = {ok, cancel}, @@ -542,6 +567,20 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> timer = Timer, req_list = ReqList}}; true -> + if + StateData#state.timer /= undefined -> + cancel_timer(StateData#state.timer); + true -> + ok + end, + Timer = if + StateData#state.pause > 0 -> + erlang:start_timer( + StateData#state.pause*1000, self(), []); + true -> + erlang:start_timer( + ?MAX_INACTIVITY, self(), []) + end, case StateData#state.output of [[]| OutPacket] -> Reply = {ok, OutPacket}; @@ -585,14 +624,29 @@ handle_info({timeout, Timer, _}, _StateName, ?DEBUG("ding dong", []), {stop, normal, StateData}; -handle_info({timeout, Timer, _}, StateName, - #state{wait_timer = Timer} = StateData) -> +handle_info({timeout, WaitTimer, _}, StateName, + #state{wait_timer = WaitTimer} = StateData) -> if StateData#state.http_receiver /= undefined -> + if + StateData#state.timer /= undefined -> + cancel_timer(StateData#state.timer); + true -> + ok + end, + Timer = if + StateData#state.pause > 0 -> + erlang:start_timer( + StateData#state.pause*1000, self(), []); + true -> + erlang:start_timer( + ?MAX_INACTIVITY, self(), []) + end, gen_fsm:reply(StateData#state.http_receiver, {ok, empty}), {next_state, StateName, StateData#state{http_receiver = undefined, - wait_timer = undefined}}; + wait_timer = undefined, + timer = Timer}}; true -> {next_state, StateName, StateData} end; @@ -611,6 +665,12 @@ terminate(_Reason, _StateName, StateData) -> fun() -> mnesia:delete({http_bind, StateData#state.id}) end), + if + StateData#state.http_receiver /= undefined -> + gen_fsm:reply(StateData#state.http_receiver, {ok, terminate}); + true -> + ok + end, case StateData#state.waiting_input of false -> case StateData#state.last_receiver of @@ -706,6 +766,8 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold}=Sess, {200, ?HEADER, "<body type='error' xmlns='"++?NS_HTTP_BIND++"'/>"}; {ok, empty} -> {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; + {ok, terminate} -> + {200, ?HEADER, "<body type='terminate' xmlns='"++?NS_HTTP_BIND++"'/>"}; {ok, OutPacket} -> ?DEBUG("OutPacket: ~s", [OutPacket]), case StreamStart of From 292e2f6b690c928566f7946bf6f9d3047bf9af7e Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:26:11 +0000 Subject: [PATCH 413/582] Removed small warning SVN Revision: 2298 --- src/web/ejabberd_http_bind.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index d2806da51..93c82ae6a 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 453 2007-12-20 14:35:04Z alexey $ +%%% Id : $Id: ejabberd_http_bind.erl 457 2007-12-21 19:55:21Z badlop $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -756,7 +756,7 @@ handle_http_put_error(Reason, #http_bind{pid=FsmRef}) -> prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold}=Sess, - Rid, Attrs, StreamStart) -> + Rid, _, StreamStart) -> receive after 100 -> ok end, case catch http_get(Sess, Rid) of {ok, cancel} -> From 38ce8b494ed6bd78ca78350542900b80789e7cfc Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:26:15 +0000 Subject: [PATCH 414/582] Provide explanation in error message when module is already started for another vhost SVN Revision: 2299 --- src/web/mod_http_bind.erl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index 9f3dddbe6..1b9338554 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -3,7 +3,7 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : Implementation of XMPP over BOSH (XEP-0206) %%% Created : Tue Feb 20 13:15:52 CET 2007 -%%% Id : $Id: mod_http_bind.erl 440 2007-12-06 22:36:21Z badlop $ +%%% Id : $Id: mod_http_bind.erl 514 2008-03-12 21:54:18Z badlop $ %%%---------------------------------------------------------------------- %%%---------------------------------------------------------------------- @@ -74,7 +74,7 @@ process(_Path, _Request) -> %%%---------------------------------------------------------------------- %%% BEHAVIOUR CALLBACKS %%%---------------------------------------------------------------------- -start(_Host, _Opts) -> +start(Host, _Opts) -> HTTPBindSupervisor = {ejabberd_http_bind_sup, {ejabberd_tmp_sup, start_link, @@ -88,6 +88,11 @@ start(_Host, _Opts) -> ok; {ok, _Pid, _Info} -> ok; + {error, {already_started, _PidOther}} -> + ErrorText = "mod_http_bind is already started, " + "so it will not be started again for " + ++ Host, + {'EXIT', {start_child_error, ErrorText}}; {error, Error} -> {'EXIT', {start_child_error, Error}} end. From 3e2c626696d7662cbbb2653b8c9bb152f8149c59 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:26:19 +0000 Subject: [PATCH 415/582] Do not display error message when starting several hosts (EJAB-571) (thanks to Christohpe Romain) SVN Revision: 2300 --- src/web/mod_http_bind.erl | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index 1b9338554..2b0bcc6d6 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -3,7 +3,7 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : Implementation of XMPP over BOSH (XEP-0206) %%% Created : Tue Feb 20 13:15:52 CET 2007 -%%% Id : $Id: mod_http_bind.erl 514 2008-03-12 21:54:18Z badlop $ +%%% Id : $Id: mod_http_bind.erl 549 2008-04-02 09:12:44Z cromain $ %%%---------------------------------------------------------------------- %%%---------------------------------------------------------------------- @@ -89,10 +89,8 @@ start(Host, _Opts) -> {ok, _Pid, _Info} -> ok; {error, {already_started, _PidOther}} -> - ErrorText = "mod_http_bind is already started, " - "so it will not be started again for " - ++ Host, - {'EXIT', {start_child_error, ErrorText}}; + % mod_http_bind is already started so it will not be started again + ok; {error, Error} -> {'EXIT', {start_child_error, Error}} end. From 646477be08dafbab4877782fa3172d33cdba87ff Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:26:23 +0000 Subject: [PATCH 416/582] Removed HTTP bind session count. Removed the 'sponsored bind session' text. (thanks to Michael Remond) Details: Removed the HTTP bind session count because it leaks information on the size of the platform. Removed the text 'sponsored by Mabber' because it is confusing, as people could think a third-party service using HTTP bind is sponsored by Mabber. SVN Revision: 2301 --- src/web/mod_http_bind.erl | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index 2b0bcc6d6..1218aa06b 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -3,7 +3,7 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : Implementation of XMPP over BOSH (XEP-0206) %%% Created : Tue Feb 20 13:15:52 CET 2007 -%%% Id : $Id: mod_http_bind.erl 549 2008-04-02 09:12:44Z cromain $ +%%% Id : $Id: mod_http_bind.erl 665 2008-06-26 08:41:48Z mremond $ %%%---------------------------------------------------------------------- %%%---------------------------------------------------------------------- @@ -57,14 +57,7 @@ process([], #request{method = 'GET', [{xmlcdata, "An implementation of "}, {xmlelement, "a", [{"href", "http://www.xmpp.org/extensions/xep-0206.html"}], [{xmlcdata, "XMPP over BOSH (XEP-0206)"}]}]}, - {xmlelement, "p", [], - [{xmlcdata, integer_to_list(mnesia:table_info(http_bind, size)) ++ " sessions found."}]}, - {xmlelement, "p", [], - [{xmlcdata, "Sponsored by "}, - {xmlelement, "a", [{"href", "http://mabber.com"}], - [{xmlcdata, "mabber"}]}, - {xmlcdata, "."}]} - ]}]}; + ]}]}; process(_Path, _Request) -> ?DEBUG("Bad Request: ~p", [_Request]), {400, [], {xmlelement, "h1", [], From 481c7ea4e611d37a3c4ef996c63fac03514fc32b Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:26:27 +0000 Subject: [PATCH 417/582] Fix syntax error. (thanks to Jerome Sautret) SVN Revision: 2302 --- src/web/mod_http_bind.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index 1218aa06b..bb1327534 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -3,7 +3,7 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : Implementation of XMPP over BOSH (XEP-0206) %%% Created : Tue Feb 20 13:15:52 CET 2007 -%%% Id : $Id: mod_http_bind.erl 665 2008-06-26 08:41:48Z mremond $ +%%% Id : $Id: mod_http_bind.erl 669 2008-06-30 13:08:16Z jsautret $ %%%---------------------------------------------------------------------- %%%---------------------------------------------------------------------- @@ -53,10 +53,10 @@ process([], #request{method = 'GET', [{xmlelement, "title", [], [{xmlcdata, Heading}]}]}, {xmlelement, "body", [], [{xmlelement, "h1", [], [{xmlcdata, Heading}]}, - {xmlelement, "p", [], + {xmlelement, "p", [], [{xmlcdata, "An implementation of "}, {xmlelement, "a", [{"href", "http://www.xmpp.org/extensions/xep-0206.html"}], - [{xmlcdata, "XMPP over BOSH (XEP-0206)"}]}]}, + [{xmlcdata, "XMPP over BOSH (XEP-0206)"}]}]} ]}]}; process(_Path, _Request) -> ?DEBUG("Bad Request: ~p", [_Request]), From 3e0827deea9592b5c94a832c814d746ceea9105f Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:26:31 +0000 Subject: [PATCH 418/582] Retrieve correct IP from http connection (thanks to Christohpe Romain) SVN Revision: 2303 --- src/web/ejabberd_http_bind.erl | 54 ++++++++++++++++++++++------------ src/web/mod_http_bind.erl | 7 +++-- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 93c82ae6a..17e52783a 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 457 2007-12-21 19:55:21Z badlop $ +%%% Id : $Id: ejabberd_http_bind.erl 674 2008-07-03 15:58:15Z cromain $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -22,11 +22,11 @@ terminate/3, send/2, setopts/2, - sockname/1, - peername/1, + sockname/1, + peername/1, controlling_process/2, close/1, - process_request/1]). + process_request/2]). %%-define(ejabberd_debug, true). @@ -36,6 +36,8 @@ -record(http_bind, {id, pid, to, hold, wait, version}). +-define(NULL_PEER, {{0, 0, 0, 0}, 0}). + %% http binding request -record(hbr, {rid, key, @@ -54,8 +56,9 @@ wait_timer, ctime = 0, timer, - pause=0, - req_list = [] % list of requests + pause=0, + req_list = [], % list of requests + ip = ?NULL_PEER }). @@ -113,12 +116,19 @@ close({http_bind, FsmRef}) -> catch gen_fsm:sync_send_all_state_event(FsmRef, stop). sockname(_Socket) -> - {ok, {{0, 0, 0, 0}, 0}}. + {ok, ?NULL_PEER}. -peername(_Socket) -> - {ok, {{0, 0, 0, 0}, 0}}. +peername({http_bind, FsmRef}) -> + gen_fsm:send_all_state_event(FsmRef, {peername, self()}), + %% XXX should improve that, but sync call seems not possible + receive + {peername, PeerName} -> {ok, PeerName} + after 1000 -> {ok, ?NULL_PEER} + end; +peername(_) -> + {ok, ?NULL_PEER}. -process_request(Data) -> +process_request(Data, IP) -> case catch parse_request(Data) of {ok, {"", Rid, Attrs, Payload}} -> case xml:get_attr_s("to",Attrs) of @@ -177,7 +187,7 @@ process_request(Data) -> version = Version }) end), - handle_http_put(Sid, Rid, Attrs, Payload, true) + handle_http_put(Sid, Rid, Attrs, Payload, true, IP) end; {ok, {Sid, Rid, Attrs, Payload1}} -> %% old session @@ -195,7 +205,7 @@ process_request(Data) -> _ -> Payload1 end, - handle_http_put(Sid, Rid, Attrs, Payload2, StreamStart); + handle_http_put(Sid, Rid, Attrs, Payload2, StreamStart, IP); _ -> {400, ?HEADER, ""} end. @@ -271,6 +281,10 @@ handle_event({activate, From}, StateName, StateData) -> last_receiver = Receiver}} end; +handle_event({peername, From}, StateName, StateData) -> + From ! {peername, StateData#state.ip}, + {next_state, StateName, StateData}; + handle_event(_Event, StateName, StateData) -> {next_state, StateName, StateData}. @@ -329,7 +343,7 @@ handle_sync_event(stop, _From, _StateName, StateData) -> Reply = ok, {stop, normal, Reply, StateData}; -handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, +handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, _From, StateName, StateData) -> Key = xml:get_attr_s("key", Attrs), NewKey = xml:get_attr_s("newkey", Attrs), @@ -466,7 +480,8 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, timer = Timer, pause = Pause, last_poll = LastPoll, - req_list = ReqList + req_list = ReqList, + ip = IP }}; {Receiver, _Tag} -> SendPacket = @@ -499,7 +514,8 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo}, timer = Timer, pause = Pause, last_poll = LastPoll, - req_list = ReqList + req_list = ReqList, + ip = IP }} end end; @@ -685,8 +701,8 @@ terminate(_Reason, _StateName, StateData) -> %%% Internal functions %%%---------------------------------------------------------------------- -handle_http_put(Sid, Rid, Attrs, Payload, StreamStart) -> - case http_put(Sid, Rid, Attrs, Payload, StreamStart) of +handle_http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) -> + case http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) of {error, not_exists} -> ?DEBUG("no session associated with sid: ~p", [Sid]), {404, ?HEADER, ""}; @@ -700,7 +716,7 @@ handle_http_put(Sid, Rid, Attrs, Payload, StreamStart) -> prepare_response(Sess, Rid, Attrs, StreamStart) end. -http_put(Sid, Rid, Attrs, Payload, StreamStart) -> +http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) -> ?DEBUG("http-put",[]), case mnesia:dirty_read({http_bind, Sid}) of [] -> @@ -714,7 +730,7 @@ http_put(Sid, Rid, Attrs, Payload, StreamStart) -> "" end, {gen_fsm:sync_send_all_state_event( - FsmRef, {http_put, Rid, Attrs, Payload, Hold, NewStream}), Sess} + FsmRef, {http_put, Rid, Attrs, Payload, Hold, NewStream, IP}), Sess} end. handle_http_put_error(Reason, #http_bind{pid=FsmRef, version=Version}) diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index bb1327534..20870ac42 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -3,7 +3,7 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : Implementation of XMPP over BOSH (XEP-0206) %%% Created : Tue Feb 20 13:15:52 CET 2007 -%%% Id : $Id: mod_http_bind.erl 669 2008-06-30 13:08:16Z jsautret $ +%%% Id : $Id: mod_http_bind.erl 674 2008-07-03 15:58:15Z cromain $ %%%---------------------------------------------------------------------- %%%---------------------------------------------------------------------- @@ -42,9 +42,10 @@ process([], #request{method = 'POST', {400, [], {xmlelement, "h1", [], [{xmlcdata, "400 Bad Request"}]}}; process([], #request{method = 'POST', - data = Data}) -> + data = Data, + ip = IP}) -> ?DEBUG("Incoming data: ~s", [Data]), - ejabberd_http_bind:process_request(Data); + ejabberd_http_bind:process_request(Data, IP); process([], #request{method = 'GET', data = []}) -> Heading = "Ejabberd " ++ atom_to_list(?MODULE) ++ " v" ++ ?MOD_HTTP_BIND_VERSION, From d25bd8c1c6a8652fc0ccb69a6b64de8b4e689424 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:26:36 +0000 Subject: [PATCH 419/582] Improve ip fetching patch (thanks to Christohpe Romain) SVN Revision: 2304 --- src/web/ejabberd_http_bind.erl | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 17e52783a..0e2f5fe82 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 674 2008-07-03 15:58:15Z cromain $ +%%% Id : $Id: ejabberd_http_bind.erl 683 2008-07-08 10:30:45Z cromain $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -119,11 +119,9 @@ sockname(_Socket) -> {ok, ?NULL_PEER}. peername({http_bind, FsmRef}) -> - gen_fsm:send_all_state_event(FsmRef, {peername, self()}), - %% XXX should improve that, but sync call seems not possible - receive - {peername, PeerName} -> {ok, PeerName} - after 1000 -> {ok, ?NULL_PEER} + case catch gen_fsm:sync_send_all_state_event(FsmRef, peername, 1000) of + {ok, IP} -> {ok, IP}; + _ -> {ok, ?NULL_PEER} end; peername(_) -> {ok, ?NULL_PEER}. @@ -281,10 +279,6 @@ handle_event({activate, From}, StateName, StateData) -> last_receiver = Receiver}} end; -handle_event({peername, From}, StateName, StateData) -> - From ! {peername, StateData#state.ip}, - {next_state, StateName, StateData}; - handle_event(_Event, StateName, StateData) -> {next_state, StateName, StateData}. @@ -622,6 +616,10 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> req_list = ReqList}} end; +handle_sync_event(peername, _From, StateName, StateData) -> + Reply = {ok, StateData#state.ip}, + {reply, Reply, StateName, StateData}; + handle_sync_event(_Event, _From, StateName, StateData) -> Reply = ok, {reply, Reply, StateName, StateData}. From 1d1f72fdc2ab03435f3d30e939403c96af309b62 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:26:40 +0000 Subject: [PATCH 420/582] Updated IP retrieving (thanks to Alexey Shchepin) SVN Revision: 2305 --- src/web/ejabberd_http_bind.erl | 48 ++++++++++++++++------------------ 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 0e2f5fe82..8ab7627a7 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 683 2008-07-08 10:30:45Z cromain $ +%%% Id : $Id: ejabberd_http_bind.erl 694 2008-07-15 13:27:03Z alexey $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -13,7 +13,7 @@ -behaviour(gen_fsm). %% External exports --export([start_link/2, +-export([start_link/3, init/1, handle_event/3, handle_sync_event/4, @@ -47,6 +47,7 @@ -record(state, {id, rid = none, key, + socket, output = "", input = "", waiting_input = false, @@ -91,17 +92,17 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- -start(Sid, Key) -> +start(Sid, Key, IP) -> setup_database(), - supervisor:start_child(ejabberd_http_bind_sup, [Sid, Key]). + supervisor:start_child(ejabberd_http_bind_sup, [Sid, Key, IP]). -start_link(Sid, Key) -> - gen_fsm:start_link(?MODULE, [Sid, Key], ?FSMOPTS). +start_link(Sid, Key, IP) -> + gen_fsm:start_link(?MODULE, [Sid, Key, IP], ?FSMOPTS). -send({http_bind, FsmRef}, Packet) -> +send({http_bind, FsmRef, _IP}, Packet) -> gen_fsm:sync_send_all_state_event(FsmRef, {send, Packet}). -setopts({http_bind, FsmRef}, Opts) -> +setopts({http_bind, FsmRef, _IP}, Opts) -> case lists:member({active, once}, Opts) of true -> gen_fsm:send_all_state_event(FsmRef, {activate, self()}); @@ -112,19 +113,14 @@ setopts({http_bind, FsmRef}, Opts) -> controlling_process(_Socket, _Pid) -> ok. -close({http_bind, FsmRef}) -> +close({http_bind, FsmRef, _IP}) -> catch gen_fsm:sync_send_all_state_event(FsmRef, stop). sockname(_Socket) -> {ok, ?NULL_PEER}. -peername({http_bind, FsmRef}) -> - case catch gen_fsm:sync_send_all_state_event(FsmRef, peername, 1000) of - {ok, IP} -> {ok, IP}; - _ -> {ok, ?NULL_PEER} - end; -peername(_) -> - {ok, ?NULL_PEER}. +peername({http_bind, _FsmRef, IP}) -> + {ok, IP}. process_request(Data, IP) -> case catch parse_request(Data) of @@ -137,7 +133,7 @@ process_request(Data, IP) -> XmppDomain -> %% create new session Sid = sha:sha(term_to_binary({now(), make_ref()})), - {ok, Pid} = start(Sid, ""), + {ok, Pid} = start(Sid, "", IP), ?DEBUG("got pid: ~p", [Pid]), Wait = case string:to_integer(xml:get_attr_s("wait",Attrs)) @@ -219,8 +215,8 @@ process_request(Data, IP) -> %% ignore | %% {stop, StopReason} %%---------------------------------------------------------------------- -init([Sid, Key]) -> - ?DEBUG("started: ~p", [{Sid, Key}]), +init([Sid, Key, IP]) -> + ?DEBUG("started: ~p", [{Sid, Key, IP}]), %% Read c2s options from the first ejabberd_c2s configuration in %% the config file listen section @@ -230,12 +226,12 @@ init([Sid, Key]) -> %% connector. Opts = ejabberd_c2s_config:get_c2s_limits(), - ejabberd_socket:start(ejabberd_c2s, ?MODULE, {http_bind, self()}, Opts), -% {ok, C2SPid} = ejabberd_c2s:start({?MODULE, {http_bind, self()}}, Opts), -% ejabberd_c2s:become_controller(C2SPid), + Socket = {http_bind, self(), IP}, + ejabberd_socket:start(ejabberd_c2s, ?MODULE, Socket, Opts), Timer = erlang:start_timer(?MAX_INACTIVITY, self(), []), {ok, loop, #state{id = Sid, key = Key, + socket = Socket, timer = Timer}}. %%---------------------------------------------------------------------- @@ -272,7 +268,7 @@ handle_event({activate, From}, StateName, StateData) -> waiting_input = {From, ok}}}; Input -> Receiver = From, - Receiver ! {tcp, {http_bind, self()}, list_to_binary(Input)}, + Receiver ! {tcp, StateData#state.socket, list_to_binary(Input)}, {next_state, StateName, StateData#state{ input = "", waiting_input = false, @@ -495,7 +491,7 @@ handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, Payload end, ?DEBUG("really sending now: ~s", [SendPacket]), - Receiver ! {tcp, {http_bind, self()}, + Receiver ! {tcp, StateData#state.socket, list_to_binary(SendPacket)}, Reply = ok, {reply, Reply, StateName, @@ -689,9 +685,9 @@ terminate(_Reason, _StateName, StateData) -> false -> case StateData#state.last_receiver of undefined -> ok; - Receiver -> Receiver ! {tcp_closed, {http_bind, self()}} + Receiver -> Receiver ! {tcp_closed, StateData#state.socket} end; - {Receiver, _Tag} -> Receiver ! {tcp_closed, {http_bind, self()}} + {Receiver, _Tag} -> Receiver ! {tcp_closed, StateData#state.socket} end, ok. From 6e52ca3f4ee3dd96550b31cbe2d8323146160c89 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:26:44 +0000 Subject: [PATCH 421/582] Implement packets reordering to avoid race conditions (EJAB-724).(thanks to Michael Remond) SVN Revision: 2306 --- src/web/ejabberd_http_bind.erl | 396 ++++++++++++++++++--------------- 1 file changed, 217 insertions(+), 179 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 8ab7627a7..d3849f723 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 694 2008-07-15 13:27:03Z alexey $ +%%% Id : $Id: ejabberd_http_bind.erl 720 2008-09-17 15:52:58Z mremond $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -58,7 +58,8 @@ ctime = 0, timer, pause=0, - req_list = [], % list of requests + unprocessed_req_list = [], % list of request that have been delayed for proper reordering + req_list = [], % list of requests (cache) ip = ?NULL_PEER }). @@ -333,187 +334,57 @@ handle_sync_event(stop, _From, _StateName, StateData) -> Reply = ok, {stop, normal, Reply, StateData}; -handle_sync_event({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, +%% HTTP PUT: Receive packets from the client +handle_sync_event({http_put, Rid, Attrs, _Payload, Hold, _StreamTo, _IP}=Request, _From, StateName, StateData) -> - Key = xml:get_attr_s("key", Attrs), - NewKey = xml:get_attr_s("newkey", Attrs), - %% check if Rid valid - RidAllow = case StateData#state.rid of - none -> - %% first request - nothing saved so far - {true, 0}; - OldRid -> - ?DEBUG("state.rid/cur rid: ~p/~p", - [OldRid, Rid]), - if - (OldRid < Rid) and - (Rid =< (OldRid + Hold + 1)) -> - case catch list_to_integer( - xml:get_attr_s("pause", Attrs)) of - {'EXIT', _} -> - {true, 0}; - Pause1 when Pause1 =< ?MAX_PAUSE -> - ?DEBUG("got pause: ~p", [Pause1]), - {true, Pause1}; - _ -> - {true, 0} - end; - (Rid =< OldRid) and - (Rid > OldRid - Hold - 1) -> - repeat; - true -> - false - end - end, - %% check if key valid - KeyAllow = case RidAllow of - repeat -> - true; - false -> - false; - {true, _} -> - case StateData#state.key of - "" -> - true; - OldKey -> - NextKey = jlib:tolower( - hex(binary_to_list( - crypto:sha(Key)))), - ?DEBUG("Key/OldKey/NextKey: ~s/~s/~s", - [Key, OldKey, NextKey]), - if - OldKey == NextKey -> - true; - true -> - ?DEBUG("wrong key: ~s",[Key]), - false - end - end - end, - {TMegSec, TSec, TMSec} = now(), - TNow = (TMegSec * 1000000 + TSec) * 1000000 + TMSec, - LastPoll = if - Payload == "" -> - TNow; - true -> - 0 - end, - if - (Payload == "") and - (Hold == 0) and - (TNow - StateData#state.last_poll < ?MIN_POLLING) -> - Reply = {error, polling_too_frequently}, - {reply, Reply, StateName, StateData}; - KeyAllow -> - case RidAllow of - false -> - Reply = {error, not_exists}, - {reply, Reply, StateName, StateData}; - repeat -> - ?DEBUG("REPEATING ~p", [Rid]), - [Out | _XS] = [El#hbr.out || - El <- StateData#state.req_list, - El#hbr.rid == Rid], - case Out of - [[] | OutPacket] -> - Reply = {repeat, OutPacket}; + %% Check if Rid valid + RidAllow = + case StateData#state.rid of + none -> + %% First request - nothing saved so far + {true, 0}; + OldRid -> + ?DEBUG("state.rid/cur rid: ~p/~p", [OldRid, Rid]), + if + %% We did not miss any packet, we can process it immediately: + Rid == OldRid + 1 -> + case catch list_to_integer( + xml:get_attr_s("pause", Attrs)) of + {'EXIT', _} -> + {true, 0}; + Pause1 when Pause1 =< ?MAX_PAUSE -> + ?DEBUG("got pause: ~p", [Pause1]), + {true, Pause1}; _ -> - Reply = {repeat, Out} - end, - {reply, Reply, StateName, - StateData#state{input = "cancel", last_poll = LastPoll}}; - {true, Pause} -> - SaveKey = if - NewKey == "" -> - Key; - true -> - NewKey - end, - ?DEBUG(" -- SaveKey: ~s~n", [SaveKey]), - - %% save request - ReqList = [#hbr{rid=Rid, - key=StateData#state.key, - in=StateData#state.input, - out=StateData#state.output - } | - [El || El <- StateData#state.req_list, - El#hbr.rid < Rid, - El#hbr.rid > (Rid - 1 - Hold)] - ], -%% ?DEBUG("reqlist: ~p", [ReqList]), - - %% setup next timer - if - StateData#state.timer /= undefined -> - cancel_timer(StateData#state.timer); - true -> - ok - end, - Timer = if - Pause > 0 -> - erlang:start_timer( - Pause*1000, self(), []); - true -> - erlang:start_timer( - ?MAX_INACTIVITY, self(), []) - end, - case StateData#state.waiting_input of - false -> - Input = Payload ++ [StateData#state.input], - Reply = ok, - {reply, Reply, StateName, - StateData#state{input = Input, - rid = Rid, - key = SaveKey, - ctime = TNow, - timer = Timer, - pause = Pause, - last_poll = LastPoll, - req_list = ReqList, - ip = IP - }}; - {Receiver, _Tag} -> - SendPacket = - case StreamTo of - {To, ""} -> - ["<stream:stream to='", To, "' " - "xmlns='"++?NS_CLIENT++"' " - "xmlns:stream='"++?NS_STREAM++"'>"] - ++ Payload; - {To, Version} -> - ["<stream:stream to='", To, "' " - "xmlns='"++?NS_CLIENT++"' " - "version='", Version, "' " - "xmlns:stream='"++?NS_STREAM++"'>"] - ++ Payload; - _ -> - Payload - end, - ?DEBUG("really sending now: ~s", [SendPacket]), - Receiver ! {tcp, StateData#state.socket, - list_to_binary(SendPacket)}, - Reply = ok, - {reply, Reply, StateName, - StateData#state{waiting_input = false, - last_receiver = Receiver, - input = "", - rid = Rid, - key = SaveKey, - ctime = TNow, - timer = Timer, - pause = Pause, - last_poll = LastPoll, - req_list = ReqList, - ip = IP - }} - end - end; - true -> - Reply = {error, bad_key}, - {reply, Reply, StateName, StateData} + {true, 0} + end; + %% We have missed packets, we need to cached it to process it later on: + (OldRid < Rid) and + (Rid =< (OldRid + Hold + 1)) -> + buffer; + (Rid =< OldRid) and + (Rid > OldRid - Hold - 1) -> + repeat; + true -> + false + end + end, + + %% Check if Rid is in sequence or out of sequence: + case RidAllow of + buffer -> + ?DEBUG("Buffered request: ~p", [Request]), + %% Request is out of sequence: + PendingRequests = StateData#state.unprocessed_req_list, + %% In case an existing RID was already buffered: + Requests = lists:keydelete(Rid, 2, PendingRequests), + {reply, ok, StateName, StateData#state{unprocessed_req_list=[Request|Requests]}}; + _ -> + %% Request is in sequence: + process_http_put(Request, StateName, StateData, RidAllow) end; +%% HTTP GET: send packets to the client handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> %% setup timer if @@ -695,6 +566,173 @@ terminate(_Reason, _StateName, StateData) -> %%% Internal functions %%%---------------------------------------------------------------------- +%% PUT / Get processing: +process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, + StateName, StateData, RidAllow) -> + %% Check if key valid + Key = xml:get_attr_s("key", Attrs), + NewKey = xml:get_attr_s("newkey", Attrs), + KeyAllow = + case RidAllow of + repeat -> + true; + false -> + false; + {true, _} -> + case StateData#state.key of + "" -> + true; + OldKey -> + NextKey = jlib:tolower( + hex(binary_to_list( + crypto:sha(Key)))), + ?DEBUG("Key/OldKey/NextKey: ~s/~s/~s", [Key, OldKey, NextKey]), + if + OldKey == NextKey -> + true; + true -> + ?DEBUG("wrong key: ~s",[Key]), + false + end + end + end, + {TMegSec, TSec, TMSec} = now(), + TNow = (TMegSec * 1000000 + TSec) * 1000000 + TMSec, + LastPoll = if + Payload == "" -> + TNow; + true -> + 0 + end, + if + (Payload == "") and + (Hold == 0) and + (TNow - StateData#state.last_poll < ?MIN_POLLING) -> + Reply = {error, polling_too_frequently}, + {reply, Reply, StateName, StateData}; + KeyAllow -> + case RidAllow of + false -> + Reply = {error, not_exists}, + {reply, Reply, StateName, StateData}; + repeat -> + ?DEBUG("REPEATING ~p", [Rid]), + [Out | _XS] = [El#hbr.out || + El <- StateData#state.req_list, + El#hbr.rid == Rid], + case Out of + [[] | OutPacket] -> + Reply = {repeat, OutPacket}; + _ -> + Reply = {repeat, Out} + end, + {reply, Reply, StateName, + StateData#state{input = "cancel", last_poll = LastPoll}}; + {true, Pause} -> + SaveKey = if + NewKey == "" -> + Key; + true -> + NewKey + end, + ?DEBUG(" -- SaveKey: ~s~n", [SaveKey]), + + %% save request + ReqList = [#hbr{rid=Rid, + key=StateData#state.key, + in=StateData#state.input, + out=StateData#state.output + } | + [El || El <- StateData#state.req_list, + El#hbr.rid < Rid, + El#hbr.rid > (Rid - 1 - Hold)] + ], +%% ?DEBUG("reqlist: ~p", [ReqList]), + + %% setup next timer + if + StateData#state.timer /= undefined -> + cancel_timer(StateData#state.timer); + true -> + ok + end, + Timer = if + Pause > 0 -> + erlang:start_timer( + Pause*1000, self(), []); + true -> + erlang:start_timer( + ?MAX_INACTIVITY, self(), []) + end, + case StateData#state.waiting_input of + false -> + Input = Payload ++ [StateData#state.input], + Reply = ok, + process_buffered_request(Reply, StateName, + StateData#state{input = Input, + rid = Rid, + key = SaveKey, + ctime = TNow, + timer = Timer, + pause = Pause, + last_poll = LastPoll, + req_list = ReqList, + ip = IP + }); + {Receiver, _Tag} -> + SendPacket = + case StreamTo of + {To, ""} -> + ["<stream:stream to='", To, "' " + "xmlns='"++?NS_CLIENT++"' " + "xmlns:stream='"++?NS_STREAM++"'>"] + ++ Payload; + {To, Version} -> + ["<stream:stream to='", To, "' " + "xmlns='"++?NS_CLIENT++"' " + "version='", Version, "' " + "xmlns:stream='"++?NS_STREAM++"'>"] + ++ Payload; + _ -> + Payload + end, + ?DEBUG("really sending now: ~s", [SendPacket]), + Receiver ! {tcp, StateData#state.socket, + list_to_binary(SendPacket)}, + Reply = ok, + process_buffered_request(Reply, StateName, + StateData#state{waiting_input = false, + last_receiver = Receiver, + input = "", + rid = Rid, + key = SaveKey, + ctime = TNow, + timer = Timer, + pause = Pause, + last_poll = LastPoll, + req_list = ReqList, + ip = IP + }) + end + end; + true -> + Reply = {error, bad_key}, + {reply, Reply, StateName, StateData} + end. + +process_buffered_request(Reply, StateName, StateData) -> + Rid = StateData#state.rid, + Requests = StateData#state.unprocessed_req_list, + case lists:keysearch(Rid+1, 2, Requests) of + {value, Request} -> + ?DEBUG("Processing buffered request: ~p", [Request]), + NewRequests = Requests -- [Request], + handle_sync_event(Request, undefined, StateName, + StateData#state{unprocessed_req_list=NewRequests}); + _ -> + {reply, Reply, StateName, StateData} + end. + handle_http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) -> case http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) of {error, not_exists} -> From 1c2d0afd952cf3906c4eab8b1348e6572c361aa5 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:26:48 +0000 Subject: [PATCH 422/582] Fix unknown rid error (thanks to Jerome Sautret) SVN Revision: 2307 --- src/web/ejabberd_http_bind.erl | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index d3849f723..a3feaf7e7 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 720 2008-09-17 15:52:58Z mremond $ +%%% Id : $Id: ejabberd_http_bind.erl 827 2008-11-21 15:49:09Z jsautret $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -617,14 +617,15 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, {reply, Reply, StateName, StateData}; repeat -> ?DEBUG("REPEATING ~p", [Rid]), - [Out | _XS] = [El#hbr.out || + Reply = case [El#hbr.out || El <- StateData#state.req_list, - El#hbr.rid == Rid], - case Out of - [[] | OutPacket] -> - Reply = {repeat, OutPacket}; - _ -> - Reply = {repeat, Out} + El#hbr.rid == Rid] of + [] -> + {error, not_exists}; + [ [[] | Out] | _XS] -> + {repeat, Out}; + [Out | _XS] -> + {repeat, Out} end, {reply, Reply, StateName, StateData#state{input = "cancel", last_poll = LastPoll}}; @@ -647,7 +648,7 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, El#hbr.rid < Rid, El#hbr.rid > (Rid - 1 - Hold)] ], -%% ?DEBUG("reqlist: ~p", [ReqList]), + ?DEBUG("reqlist: ~p", [ReqList]), %% setup next timer if From a1bce244611cd1e89d40ef1941c861dcc65b352d Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:26:53 +0000 Subject: [PATCH 423/582] Include condition in http-bind terminate body when service stops (EJAB-792) SVN Revision: 2308 --- src/web/ejabberd_http_bind.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index a3feaf7e7..05468e3a1 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 827 2008-11-21 15:49:09Z jsautret $ +%%% Id : $Id: ejabberd_http_bind.erl 854 2009-01-12 23:37:40Z badlop $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -894,6 +894,8 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold}=Sess, ] ++ BOSH_attribs,OutEls})} end end; + {'EXIT', {shutdown, _}} -> + {200, ?HEADER, "<body type='terminate' condition='system-shutdown' xmlns='"++?NS_HTTP_BIND++"'/>"}; {'EXIT', _Reason} -> {200, ?HEADER, "<body type='terminate' xmlns='"++?NS_HTTP_BIND++"'/>"} end. From 66f3f0f3de27c77a76035f51c16f9eed7a686f87 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:26:57 +0000 Subject: [PATCH 424/582] Fix warning of unused Host variable SVN Revision: 2309 --- src/web/mod_http_bind.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index 20870ac42..0e238f1f7 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -3,7 +3,7 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : Implementation of XMPP over BOSH (XEP-0206) %%% Created : Tue Feb 20 13:15:52 CET 2007 -%%% Id : $Id: mod_http_bind.erl 674 2008-07-03 15:58:15Z cromain $ +%%% Id : $Id: mod_http_bind.erl 856 2009-01-13 17:11:02Z badlop $ %%%---------------------------------------------------------------------- %%%---------------------------------------------------------------------- @@ -68,7 +68,7 @@ process(_Path, _Request) -> %%%---------------------------------------------------------------------- %%% BEHAVIOUR CALLBACKS %%%---------------------------------------------------------------------- -start(Host, _Opts) -> +start(_Host, _Opts) -> HTTPBindSupervisor = {ejabberd_http_bind_sup, {ejabberd_tmp_sup, start_link, From eeb11046d563e27377611fd9427f330a6241f359 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:27:01 +0000 Subject: [PATCH 425/582] New option max_inactivity to configure maximum inactivity period (EJAB-512) SVN Revision: 2310 --- src/web/ejabberd_http_bind.erl | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 05468e3a1..59e58ecaa 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 854 2009-01-12 23:37:40Z badlop $ +%%% Id : $Id: ejabberd_http_bind.erl 885 2009-02-14 09:01:54Z badlop $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -60,7 +60,8 @@ pause=0, unprocessed_req_list = [], % list of request that have been delayed for proper reordering req_list = [], % list of requests (cache) - ip = ?NULL_PEER + max_inactivity, + ip = ?NULL_PEER }). @@ -233,6 +234,7 @@ init([Sid, Key, IP]) -> {ok, loop, #state{id = Sid, key = Key, socket = Socket, + max_inactivity = ?MAX_INACTIVITY, timer = Timer}}. %%---------------------------------------------------------------------- @@ -304,7 +306,7 @@ handle_sync_event({send, Packet}, _From, StateName, StateData) -> StateData#state.pause*1000, self(), []); true -> erlang:start_timer( - ?MAX_INACTIVITY, self(), []) + StateData#state.max_inactivity, self(), []) end, HTTPReply = case Output of [[]| OutPacket] -> @@ -431,7 +433,7 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> StateData#state.pause*1000, self(), []); true -> erlang:start_timer( - ?MAX_INACTIVITY, self(), []) + StateData#state.max_inactivity, self(), []) end, Output = StateData#state.output, ReqList = StateData#state.req_list, @@ -456,7 +458,7 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> StateData#state.pause*1000, self(), []); true -> erlang:start_timer( - ?MAX_INACTIVITY, self(), []) + StateData#state.max_inactivity, self(), []) end, case StateData#state.output of [[]| OutPacket] -> @@ -521,7 +523,7 @@ handle_info({timeout, WaitTimer, _}, StateName, StateData#state.pause*1000, self(), []); true -> erlang:start_timer( - ?MAX_INACTIVITY, self(), []) + StateData#state.max_inactivity, self(), []) end, gen_fsm:reply(StateData#state.http_receiver, {ok, empty}), {next_state, StateName, @@ -663,7 +665,7 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, Pause*1000, self(), []); true -> erlang:start_timer( - ?MAX_INACTIVITY, self(), []) + StateData#state.max_inactivity, self(), []) end, case StateData#state.waiting_input of false -> @@ -697,6 +699,7 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, _ -> Payload end, + MaxInactivity = get_max_inactivity(StreamTo, StateData#state.max_inactivity), ?DEBUG("really sending now: ~s", [SendPacket]), Receiver ! {tcp, StateData#state.socket, list_to_binary(SendPacket)}, @@ -712,6 +715,7 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, pause = Pause, last_poll = LastPoll, req_list = ReqList, + max_inactivity = MaxInactivity, ip = IP }) end @@ -804,7 +808,7 @@ handle_http_put_error(Reason, #http_bind{pid=FsmRef}) -> end. -prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold}=Sess, +prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold, to=To}=Sess, Rid, _, StreamStart) -> receive after 100 -> ok end, case catch http_get(Sess, Rid) of @@ -872,6 +876,7 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold}=Sess, _ -> [{"xmpp:version", Version}] end, + MaxInactivity = get_max_inactivity(To, ?MAX_INACTIVITY), {200, ?HEADER, xml:element_to_string( {xmlelement,"body", @@ -882,7 +887,7 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold}=Sess, {"requests", integer_to_list(Hold+1)}, {"inactivity", integer_to_list( - trunc(?MAX_INACTIVITY/1000))}, + trunc(MaxInactivity/1000))}, {"maxpause", integer_to_list(?MAX_PAUSE)}, {"polling", @@ -1075,6 +1080,17 @@ elements_to_string([]) -> elements_to_string([El | Els]) -> xml:element_to_string(El) ++ elements_to_string(Els). +%% @spec (To, Default::integer()) -> integer() +%% where To = [] | {Host::string(), Version::string()} +get_max_inactivity({Host, _}, Default) -> + case gen_mod:get_module_opt(Host, mod_http_bind, max_inactivity, undefined) of + Seconds when is_integer(Seconds) -> + Seconds * 1000; + undefined -> + Default + end; +get_max_inactivity(_, Default) -> + Default. remove_tag_attr(Attr, El) -> case El of From c74ef80f79ca43344d2bb8bf80e45440dc909fab Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:27:05 +0000 Subject: [PATCH 426/582] Fix remote-stream-error stanzas SVN Revision: 2311 --- src/web/ejabberd_http_bind.erl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 59e58ecaa..cdb8ecac9 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 885 2009-02-14 09:01:54Z badlop $ +%%% Id : $Id: ejabberd_http_bind.erl 917 2009-03-13 16:27:30Z badlop $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -976,8 +976,8 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> case xml:get_subtag(El, "stream:error") of false -> null; - {xmlelement, _, _, Cond} -> - Cond + {xmlelement, _, _, _Cond} = StreamErrorTag -> + [StreamErrorTag] end; {error, _E} -> null @@ -994,7 +994,8 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> {200, ?HEADER, "<body type='terminate' " "condition='remote-stream-error' " - "xmlns='"++?NS_HTTP_BIND++"'>" ++ + "xmlns='"++?NS_HTTP_BIND++"' " ++ + "xmlns:stream='"++?NS_STREAM++"'>" ++ elements_to_string(StreamErrCond) ++ "</body>"} end; From 24ab5026c929b2d4e4fd2e2397e54b84262b4bb5 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:27:10 +0000 Subject: [PATCH 427/582] Changed the place where database is created(thanks to Michael Remond) SVN Revision: 2312 --- src/web/ejabberd_http_bind.erl | 19 +------------------ src/web/mod_http_bind.erl | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index cdb8ecac9..e55b840cb 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 917 2009-03-13 16:27:30Z badlop $ +%%% Id : $Id: ejabberd_http_bind.erl 942 2009-04-22 15:25:31Z mremond $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -95,7 +95,6 @@ %%% API %%%---------------------------------------------------------------------- start(Sid, Key, IP) -> - setup_database(), supervisor:start_child(ejabberd_http_bind_sup, [Sid, Key, IP]). start_link(Sid, Key, IP) -> @@ -1110,19 +1109,3 @@ check_default_xmlns({xmlelement, Name, Attrs, Els} = El) -> true -> El end. - -setup_database() -> - migrate_database(), - mnesia:create_table(http_bind, - [{ram_copies, [node()]}, - {attributes, record_info(fields, http_bind)}]). - -migrate_database() -> - case catch mnesia:table_info(http_bind, attributes) of - [id, pid, to, hold, wait, version] -> - ok; - _ -> - %% Since the stored information is not important, instead - %% of actually migrating data, let's just destroy the table - mnesia:delete_table(http_bind) - end. diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index 0e238f1f7..68688e328 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -3,7 +3,7 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : Implementation of XMPP over BOSH (XEP-0206) %%% Created : Tue Feb 20 13:15:52 CET 2007 -%%% Id : $Id: mod_http_bind.erl 856 2009-01-13 17:11:02Z badlop $ +%%% Id : $Id: mod_http_bind.erl 942 2009-04-22 15:25:31Z mremond $ %%%---------------------------------------------------------------------- %%%---------------------------------------------------------------------- @@ -31,6 +31,9 @@ -include("jlib.hrl"). -include("ejabberd_http.hrl"). +%% Duplicated from ejabberd_http_bind. +%% TODO: move to hrl file. +-record(http_bind, {id, pid, to, hold, wait, version}). %%%---------------------------------------------------------------------- %%% API @@ -69,6 +72,7 @@ process(_Path, _Request) -> %%% BEHAVIOUR CALLBACKS %%%---------------------------------------------------------------------- start(_Host, _Opts) -> + setup_database(), HTTPBindSupervisor = {ejabberd_http_bind_sup, {ejabberd_tmp_sup, start_link, @@ -96,3 +100,19 @@ stop(_Host) -> {error, Error} -> {'EXIT', {terminate_child_error, Error}} end. + +setup_database() -> + migrate_database(), + mnesia:create_table(http_bind, + [{ram_copies, [node()]}, + {attributes, record_info(fields, http_bind)}]). + +migrate_database() -> + case catch mnesia:table_info(http_bind, attributes) of + [id, pid, to, hold, wait, version] -> + ok; + _ -> + %% Since the stored information is not important, instead + %% of actually migrating data, let's just destroy the table + mnesia:delete_table(http_bind) + end. From 2c33e72eea5c0d81be8d499d66ee53a5f9cc87af Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:27:14 +0000 Subject: [PATCH 428/582] Do not clear input when dispatching a get when we have nothing to output. (thanks to Geoff Cant) SVN Revision: 2313 --- src/web/ejabberd_http_bind.erl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index e55b840cb..8893998c5 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 942 2009-04-22 15:25:31Z mremond $ +%%% Id : $Id: ejabberd_http_bind.erl 944 2009-04-30 18:03:23Z gcant $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -413,7 +413,6 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> ReqList = StateData#state.req_list, WaitTimer = erlang:start_timer(Wait * 1000, self(), []), {next_state, StateName, StateData#state{ - input = "", output = Output, http_receiver = From, wait_timer = WaitTimer, From 5854edafddea262b1af120c272650b226515b6b3 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:27:18 +0000 Subject: [PATCH 429/582] Properly warn user and admin when mod_http_bind is not started.(thanks to Michael Remond) SVN Revision: 2314 --- src/web/ejabberd_http_bind.erl | 126 +++++++++++++++++++-------------- 1 file changed, 74 insertions(+), 52 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 8893998c5..a6de96b3e 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 944 2009-04-30 18:03:23Z gcant $ +%%% Id : $Id: ejabberd_http_bind.erl 949 2009-05-04 01:16:36Z mremond $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -94,8 +94,15 @@ %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- -start(Sid, Key, IP) -> - supervisor:start_child(ejabberd_http_bind_sup, [Sid, Key, IP]). +%% TODO: If compile with no supervisor option, start the session without +%% supervisor +start(XMPPDomain, Sid, Key, IP) -> + ?DEBUG("Starting session", []), + case catch supervisor:start_child(ejabberd_http_bind_sup, [Sid, Key, IP]) of + {ok, Pid} -> {ok, Pid}; + _ -> check_bind_module(XMPPDomain), + {error, "Cannot start HTTP bind session"} + end. start_link(Sid, Key, IP) -> gen_fsm:start_link(?MODULE, [Sid, Key, IP], ?FSMOPTS). @@ -134,55 +141,14 @@ process_request(Data, IP) -> XmppDomain -> %% create new session Sid = sha:sha(term_to_binary({now(), make_ref()})), - {ok, Pid} = start(Sid, "", IP), - ?DEBUG("got pid: ~p", [Pid]), - Wait = case - string:to_integer(xml:get_attr_s("wait",Attrs)) - of - {error, _} -> - ?MAX_WAIT; - {CWait, _} -> - if - (CWait > ?MAX_WAIT) -> - ?MAX_WAIT; - true -> - CWait - end - end, - Hold = case - string:to_integer( - xml:get_attr_s("hold",Attrs)) - of - {error, _} -> - (?MAX_REQUESTS - 1); - {CHold, _} -> - if - (CHold > (?MAX_REQUESTS - 1)) -> - (?MAX_REQUESTS - 1); - true -> - CHold - end - end, - Version = - case catch list_to_float( - xml:get_attr_s("ver", Attrs)) of - {'EXIT', _} -> 0.0; - V -> V - end, - XmppVersion = xml:get_attr_s("xmpp:version", Attrs), - mnesia:transaction( - fun() -> - mnesia:write( - #http_bind{id = Sid, - pid = Pid, - to = {XmppDomain, - XmppVersion}, - hold = Hold, - wait = Wait, - version = Version - }) - end), - handle_http_put(Sid, Rid, Attrs, Payload, true, IP) + case start(XmppDomain, Sid, "", IP) of + {error, _} -> + {200, ?HEADER, "<body type='terminate' " + "condition='internal-server-error' " + "xmlns='" ++ ?NS_HTTP_BIND ++ "'>BOSH module not started</body"}; + {ok, Pid} -> + handle_session_start(Pid, XmppDomain, Sid, Rid, Attrs, Payload, IP) + end end; {ok, {Sid, Rid, Attrs, Payload1}} -> %% old session @@ -205,6 +171,55 @@ process_request(Data, IP) -> {400, ?HEADER, ""} end. +handle_session_start(Pid, XmppDomain, Sid, Rid, Attrs, Payload, IP) -> + ?DEBUG("got pid: ~p", [Pid]), + Wait = case + string:to_integer(xml:get_attr_s("wait",Attrs)) + of + {error, _} -> + ?MAX_WAIT; + {CWait, _} -> + if + (CWait > ?MAX_WAIT) -> + ?MAX_WAIT; + true -> + CWait + end + end, + Hold = case + string:to_integer(xml:get_attr_s("hold",Attrs)) + of + {error, _} -> + (?MAX_REQUESTS - 1); + {CHold, _} -> + if + (CHold > (?MAX_REQUESTS - 1)) -> + (?MAX_REQUESTS - 1); + true -> + CHold + end + end, + Version = + case catch list_to_float( + xml:get_attr_s("ver", Attrs)) of + {'EXIT', _} -> 0.0; + V -> V + end, + XmppVersion = xml:get_attr_s("xmpp:version", Attrs), + mnesia:transaction( + fun() -> + mnesia:write( + #http_bind{id = Sid, + pid = Pid, + to = {XmppDomain, + XmppVersion}, + hold = Hold, + wait = Wait, + version = Version + }) + end), + handle_http_put(Sid, Rid, Attrs, Payload, true, IP). + %%%---------------------------------------------------------------------- %%% Callback functions from gen_fsm %%%---------------------------------------------------------------------- @@ -1108,3 +1123,10 @@ check_default_xmlns({xmlelement, Name, Attrs, Els} = El) -> true -> El end. + +check_bind_module(XmppDomain) -> + case gen_mod:is_loaded(XmppDomain, mod_http_bind) of + true -> ok; + false -> ?ERROR_MSG("You are trying to use HTTP Bind (BOSH), but the module mod_http_bind is not started.~n" + "Check your 'modules' section in your ejabberd configuration file.",[]) + end. From c19cc61c48715294c9e366cc52b617db3657b077 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:27:24 +0000 Subject: [PATCH 430/582] Simplified code.(thanks to Michael Remond) SVN Revision: 2315 --- src/web/ejabberd_http_bind.erl | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index a6de96b3e..b067665dd 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 949 2009-05-04 01:16:36Z mremond $ +%%% Id : $Id: ejabberd_http_bind.erl 950 2009-05-04 01:23:55Z mremond $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -99,7 +99,7 @@ start(XMPPDomain, Sid, Key, IP) -> ?DEBUG("Starting session", []), case catch supervisor:start_child(ejabberd_http_bind_sup, [Sid, Key, IP]) of - {ok, Pid} -> {ok, Pid}; + {ok, Pid} -> {ok, Pid}; _ -> check_bind_module(XMPPDomain), {error, "Cannot start HTTP bind session"} end. @@ -424,15 +424,11 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> (StateData#state.rid == Rid) and (StateData#state.input /= "cancel") and (StateData#state.pause == 0) -> - Output = StateData#state.output, - ReqList = StateData#state.req_list, WaitTimer = erlang:start_timer(Wait * 1000, self(), []), {next_state, StateName, StateData#state{ - output = Output, http_receiver = From, wait_timer = WaitTimer, - timer = undefined, - req_list = ReqList}}; + timer = undefined}}; (StateData#state.input == "cancel") -> if StateData#state.timer /= undefined -> @@ -448,16 +444,12 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> erlang:start_timer( StateData#state.max_inactivity, self(), []) end, - Output = StateData#state.output, - ReqList = StateData#state.req_list, Reply = {ok, cancel}, {reply, Reply, StateName, StateData#state{ input = "", - output = Output, http_receiver = undefined, wait_timer = undefined, - timer = Timer, - req_list = ReqList}}; + timer = Timer}}; true -> if StateData#state.timer /= undefined -> @@ -488,10 +480,9 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> [El || El <- StateData#state.req_list, El#hbr.rid /= Rid ] ], - Output = "", {reply, Reply, StateName, StateData#state{ input = "", - output = Output, + output = "", http_receiver = undefined, wait_timer = undefined, timer = Timer, From 3e3d01063d7a586b675caaaff986050cb90bc25c Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:27:27 +0000 Subject: [PATCH 431/582] Replace TYPE/1 with is_TYPE/1 (EJAB-922) SVN Revision: 2316 --- src/web/ejabberd_http_bind.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index b067665dd..df2ba5c41 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 950 2009-05-04 01:23:55Z mremond $ +%%% Id : $Id: ejabberd_http_bind.erl 952 2009-05-06 17:29:39Z badlop $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -1070,7 +1070,7 @@ cancel_timer(Timer) -> ok end. -hex(Bin) when binary(Bin) -> hex(binary_to_list(Bin)); +hex(Bin) when is_binary(Bin) -> hex(binary_to_list(Bin)); hex([]) -> ""; hex([H|T]) -> [A,B] = if From a1b84c6fa3129dca916010afced45dbf4381e296 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:27:31 +0000 Subject: [PATCH 432/582] Replaced sha1 to hexadecimal transformation with sha:sha/1 call (thanks to Alexey Shchepin) SVN Revision: 2317 --- src/web/ejabberd_http_bind.erl | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index df2ba5c41..11431ab6e 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 952 2009-05-06 17:29:39Z badlop $ +%%% Id : $Id: ejabberd_http_bind.erl 953 2009-05-07 10:40:40Z alexey $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -589,9 +589,7 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, "" -> true; OldKey -> - NextKey = jlib:tolower( - hex(binary_to_list( - crypto:sha(Key)))), + NextKey = sha:sha(Key), ?DEBUG("Key/OldKey/NextKey: ~s/~s/~s", [Key, OldKey, NextKey]), if OldKey == NextKey -> @@ -1070,16 +1068,6 @@ cancel_timer(Timer) -> ok end. -hex(Bin) when is_binary(Bin) -> hex(binary_to_list(Bin)); -hex([]) -> ""; -hex([H|T]) -> - [A,B] = if - H == 0 -> "00"; - H < 16 -> [$0,element(H,{$1,$2,$3,$4,$5,$6,$7,$8,$9,$a,$b,$c,$d,$e,$f})]; - true -> erlang:integer_to_list(H,16) - end, - [A,B|hex(T)]. - elements_to_string([]) -> []; elements_to_string([El | Els]) -> From b74cb8828ba72c3763add810e11a12c36b0a0191 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:27:35 +0000 Subject: [PATCH 433/582] Started code clean-up (EJAB-936)(thanks to Michael Remond) SVN Revision: 2318 --- src/web/ejabberd_http_bind.erl | 291 +++++++++++++++------------------ 1 file changed, 129 insertions(+), 162 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 11431ab6e..4f3648a9b 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -1,10 +1,10 @@ %%%---------------------------------------------------------------------- %%% File : ejabberd_http_bind.erl %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> -%%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as +%%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 953 2009-05-07 10:40:40Z alexey $ +%%% Id : $Id: ejabberd_http_bind.erl 958 2009-05-12 14:43:41Z mremond $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -22,7 +22,7 @@ terminate/3, send/2, setopts/2, - sockname/1, + sockname/1, peername/1, controlling_process/2, close/1, @@ -84,7 +84,7 @@ -define(MAX_WAIT, 3600). % max num of secs to keep a request on hold -define(MAX_INACTIVITY, 30000). % msecs to wait before terminating % idle sessions --define(MAX_PAUSE, 120). % may num of sec a client is allowed to pause +-define(MAX_PAUSE, 120). % may num of sec a client is allowed to pause % the session -define(CT, {"Content-Type", "text/xml; charset=utf-8"}). @@ -135,6 +135,7 @@ process_request(Data, IP) -> {ok, {"", Rid, Attrs, Payload}} -> case xml:get_attr_s("to",Attrs) of "" -> + ?ERROR_MSG("Session not created (Improper addressing)", []), {200, ?HEADER, "<body type='terminate' " "condition='improper-addressing' " "xmlns='" ++ ?NS_HTTP_BIND ++ "'/>"}; @@ -152,7 +153,7 @@ process_request(Data, IP) -> end; {ok, {Sid, Rid, Attrs, Payload1}} -> %% old session - StreamStart = + StreamStart = case xml:get_attr_s("xmpp:restart",Attrs) of "true" -> true; @@ -168,38 +169,35 @@ process_request(Data, IP) -> end, handle_http_put(Sid, Rid, Attrs, Payload2, StreamStart, IP); _ -> + ?ERROR_MSG("Received bad request: ~p", [Data]), {400, ?HEADER, ""} end. handle_session_start(Pid, XmppDomain, Sid, Rid, Attrs, Payload, IP) -> ?DEBUG("got pid: ~p", [Pid]), - Wait = case - string:to_integer(xml:get_attr_s("wait",Attrs)) - of + Wait = case string:to_integer(xml:get_attr_s("wait",Attrs)) of {error, _} -> ?MAX_WAIT; {CWait, _} -> - if + if (CWait > ?MAX_WAIT) -> ?MAX_WAIT; true -> CWait end end, - Hold = case - string:to_integer(xml:get_attr_s("hold",Attrs)) - of + Hold = case string:to_integer(xml:get_attr_s("hold",Attrs)) of {error, _} -> (?MAX_REQUESTS - 1); {CHold, _} -> - if + if (CHold > (?MAX_REQUESTS - 1)) -> (?MAX_REQUESTS - 1); true -> CHold end end, - Version = + Version = case catch list_to_float( xml:get_attr_s("ver", Attrs)) of {'EXIT', _} -> 0.0; @@ -211,7 +209,7 @@ handle_session_start(Pid, XmppDomain, Sid, Rid, Attrs, Payload, IP) -> mnesia:write( #http_bind{id = Sid, pid = Pid, - to = {XmppDomain, + to = {XmppDomain, XmppVersion}, hold = Hold, wait = Wait, @@ -229,7 +227,7 @@ handle_session_start(Pid, XmppDomain, Sid, Rid, Attrs, Payload, IP) -> %% Returns: {ok, StateName, StateData} | %% {ok, StateName, StateData, Timeout} | %% ignore | -%% {stop, StopReason} +%% {stop, StopReason} %%---------------------------------------------------------------------- init([Sid, Key, IP]) -> ?DEBUG("started: ~p", [{Sid, Key, IP}]), @@ -255,7 +253,7 @@ init([Sid, Key, IP]) -> %% Func: StateName/2 %% Returns: {next_state, NextStateName, NextStateData} | %% {next_state, NextStateName, NextStateData, Timeout} | -%% {stop, Reason, NewStateData} +%% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- @@ -266,7 +264,7 @@ init([Sid, Key, IP]) -> %% {reply, Reply, NextStateName, NextStateData} | %% {reply, Reply, NextStateName, NextStateData, Timeout} | %% {stop, Reason, NewStateData} | -%% {stop, Reason, Reply, NewStateData} +%% {stop, Reason, Reply, NewStateData} %%---------------------------------------------------------------------- %state_name(Event, From, StateData) -> % Reply = ok, @@ -276,7 +274,7 @@ init([Sid, Key, IP]) -> %% Func: handle_event/3 %% Returns: {next_state, NextStateName, NextStateData} | %% {next_state, NextStateName, NextStateData, Timeout} | -%% {stop, Reason, NewStateData} +%% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- handle_event({activate, From}, StateName, StateData) -> case StateData#state.input of @@ -302,19 +300,14 @@ handle_event(_Event, StateName, StateData) -> %% {reply, Reply, NextStateName, NextStateData} | %% {reply, Reply, NextStateName, NextStateData, Timeout} | %% {stop, Reason, NewStateData} | -%% {stop, Reason, Reply, NewStateData} +%% {stop, Reason, Reply, NewStateData} %%---------------------------------------------------------------------- handle_sync_event({send, Packet}, _From, StateName, StateData) -> Output = [StateData#state.output | Packet], if StateData#state.http_receiver /= undefined -> - if - StateData#state.timer /= undefined -> - cancel_timer(StateData#state.timer); - true -> - ok - end, - Timer = if + cancel_timer(StateData#state.timer), + Timer = if StateData#state.pause > 0 -> erlang:start_timer( StateData#state.pause*1000, self(), []); @@ -329,12 +322,7 @@ handle_sync_event({send, Packet}, _From, StateName, StateData) -> {ok, Output} end, gen_fsm:reply(StateData#state.http_receiver, HTTPReply), - if - StateData#state.wait_timer /= undefined -> - cancel_timer(StateData#state.wait_timer); - true -> - ok - end, + cancel_timer(StateData#state.wait_timer), Reply = ok, {reply, Reply, StateName, StateData#state{output = [], @@ -354,9 +342,9 @@ handle_sync_event(stop, _From, _StateName, StateData) -> handle_sync_event({http_put, Rid, Attrs, _Payload, Hold, _StreamTo, _IP}=Request, _From, StateName, StateData) -> %% Check if Rid valid - RidAllow = + RidAllow = case StateData#state.rid of - none -> + none -> %% First request - nothing saved so far {true, 0}; OldRid -> @@ -375,17 +363,17 @@ handle_sync_event({http_put, Rid, Attrs, _Payload, Hold, _StreamTo, _IP}=Request {true, 0} end; %% We have missed packets, we need to cached it to process it later on: - (OldRid < Rid) and + (OldRid < Rid) and (Rid =< (OldRid + Hold + 1)) -> buffer; - (Rid =< OldRid) and + (Rid =< OldRid) and (Rid > OldRid - Hold - 1) -> repeat; true -> false end end, - + %% Check if Rid is in sequence or out of sequence: case RidAllow of buffer -> @@ -409,19 +397,14 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> true -> ok end, - if - StateData#state.wait_timer /= undefined -> - cancel_timer(StateData#state.wait_timer); - true -> - ok - end, + cancel_timer(StateData#state.wait_timer), {TMegSec, TSec, TMSec} = now(), TNow = (TMegSec * 1000000 + TSec) * 1000000 + TMSec, - if - (Hold > 0) and - (StateData#state.output == "") and - ((TNow - StateData#state.ctime) < (Wait*1000*1000)) and - (StateData#state.rid == Rid) and + if + (Hold > 0) and + (StateData#state.output == "") and + ((TNow - StateData#state.ctime) < (Wait*1000*1000)) and + (StateData#state.rid == Rid) and (StateData#state.input /= "cancel") and (StateData#state.pause == 0) -> WaitTimer = erlang:start_timer(Wait * 1000, self(), []), @@ -430,13 +413,8 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> wait_timer = WaitTimer, timer = undefined}}; (StateData#state.input == "cancel") -> - if - StateData#state.timer /= undefined -> - cancel_timer(StateData#state.timer); - true -> - ok - end, - Timer = if + cancel_timer(StateData#state.timer), + Timer = if StateData#state.pause > 0 -> erlang:start_timer( StateData#state.pause*1000, self(), []); @@ -451,13 +429,8 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> wait_timer = undefined, timer = Timer}}; true -> - if - StateData#state.timer /= undefined -> - cancel_timer(StateData#state.timer); - true -> - ok - end, - Timer = if + cancel_timer(StateData#state.timer), + Timer = if StateData#state.pause > 0 -> erlang:start_timer( StateData#state.pause*1000, self(), []); @@ -476,9 +449,9 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> key=StateData#state.key, in=StateData#state.input, out=StateData#state.output - } | - [El || El <- StateData#state.req_list, - El#hbr.rid /= Rid ] + } | + [El || El <- StateData#state.req_list, + El#hbr.rid /= Rid ] ], {reply, Reply, StateName, StateData#state{ input = "", @@ -504,24 +477,19 @@ code_change(_OldVsn, StateName, StateData, _Extra) -> %% Func: handle_info/3 %% Returns: {next_state, NextStateName, NextStateData} | %% {next_state, NextStateName, NextStateData, Timeout} | -%% {stop, Reason, NewStateData} +%% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- handle_info({timeout, Timer, _}, _StateName, #state{timer = Timer} = StateData) -> - ?DEBUG("ding dong", []), + ?DEBUG("Session timeout. Closing the HTTP bind Session.", []), {stop, normal, StateData}; handle_info({timeout, WaitTimer, _}, StateName, #state{wait_timer = WaitTimer} = StateData) -> if StateData#state.http_receiver /= undefined -> - if - StateData#state.timer /= undefined -> - cancel_timer(StateData#state.timer); - true -> - ok - end, - Timer = if + cancel_timer(StateData#state.timer), + Timer = if StateData#state.pause > 0 -> erlang:start_timer( StateData#state.pause*1000, self(), []); @@ -580,7 +548,7 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, NewKey = xml:get_attr_s("newkey", Attrs), KeyAllow = case RidAllow of - repeat -> + repeat -> true; false -> false; @@ -602,14 +570,14 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, end, {TMegSec, TSec, TMSec} = now(), TNow = (TMegSec * 1000000 + TSec) * 1000000 + TMSec, - LastPoll = if + LastPoll = if Payload == "" -> TNow; true -> 0 end, if - (Payload == "") and + (Payload == "") and (Hold == 0) and (TNow - StateData#state.last_poll < ?MIN_POLLING) -> Reply = {error, polling_too_frequently}, @@ -622,7 +590,7 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, repeat -> ?DEBUG("REPEATING ~p", [Rid]), Reply = case [El#hbr.out || - El <- StateData#state.req_list, + El <- StateData#state.req_list, El#hbr.rid == Rid] of [] -> {error, not_exists}; @@ -631,10 +599,10 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, [Out | _XS] -> {repeat, Out} end, - {reply, Reply, StateName, + {reply, Reply, StateName, StateData#state{input = "cancel", last_poll = LastPoll}}; {true, Pause} -> - SaveKey = if + SaveKey = if NewKey == "" -> Key; true -> @@ -647,20 +615,15 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, key=StateData#state.key, in=StateData#state.input, out=StateData#state.output - } | - [El || El <- StateData#state.req_list, - El#hbr.rid < Rid, + } | + [El || El <- StateData#state.req_list, + El#hbr.rid < Rid, El#hbr.rid > (Rid - 1 - Hold)] ], ?DEBUG("reqlist: ~p", [ReqList]), - + %% setup next timer - if - StateData#state.timer /= undefined -> - cancel_timer(StateData#state.timer); - true -> - ok - end, + cancel_timer(StateData#state.timer), Timer = if Pause > 0 -> erlang:start_timer( @@ -673,7 +636,7 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, false -> Input = Payload ++ [StateData#state.input], Reply = ok, - process_buffered_request(Reply, StateName, + process_buffered_request(Reply, StateName, StateData#state{input = Input, rid = Rid, key = SaveKey, @@ -685,18 +648,18 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, ip = IP }); {Receiver, _Tag} -> - SendPacket = + SendPacket = case StreamTo of {To, ""} -> ["<stream:stream to='", To, "' " "xmlns='"++?NS_CLIENT++"' " - "xmlns:stream='"++?NS_STREAM++"'>"] + "xmlns:stream='"++?NS_STREAM++"'>"] ++ Payload; {To, Version} -> ["<stream:stream to='", To, "' " "xmlns='"++?NS_CLIENT++"' " "version='", Version, "' " - "xmlns:stream='"++?NS_STREAM++"'>"] + "xmlns:stream='"++?NS_STREAM++"'>"] ++ Payload; _ -> Payload @@ -706,7 +669,7 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, Receiver ! {tcp, StateData#state.socket, list_to_binary(SendPacket)}, Reply = ok, - process_buffered_request(Reply, StateName, + process_buffered_request(Reply, StateName, StateData#state{waiting_input = false, last_receiver = Receiver, input = "", @@ -743,13 +706,13 @@ process_buffered_request(Reply, StateName, StateData) -> handle_http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) -> case http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) of {error, not_exists} -> - ?DEBUG("no session associated with sid: ~p", [Sid]), + ?ERROR_MSG("no session associated with sid: ~p", [Sid]), {404, ?HEADER, ""}; {{error, Reason}, Sess} -> + ?ERROR_MSG("Error on HTTP put. Reason: ~p", [Reason]), handle_http_put_error(Reason, Sess); {{repeat, OutPacket}, Sess} -> - ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", - [OutPacket]), + ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", [OutPacket]), send_outpacket(Sess, OutPacket); {ok, Sess} -> prepare_response(Sess, Rid, Attrs, StreamStart) @@ -761,7 +724,7 @@ http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) -> [] -> {error, not_exists}; [#http_bind{pid = FsmRef, hold=Hold, to={To, StreamVersion}}=Sess] -> - NewStream = + NewStream = case StreamStart of true -> {To, StreamVersion}; @@ -772,26 +735,26 @@ http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) -> FsmRef, {http_put, Rid, Attrs, Payload, Hold, NewStream, IP}), Sess} end. -handle_http_put_error(Reason, #http_bind{pid=FsmRef, version=Version}) +handle_http_put_error(Reason, #http_bind{pid=FsmRef, version=Version}) when Version >= 0 -> gen_fsm:sync_send_all_state_event(FsmRef,stop), case Reason of not_exists -> - {200, ?HEADER, + {200, ?HEADER, xml:element_to_string( {xmlelement, "body", [{"xmlns", ?NS_HTTP_BIND}, {"type", "terminate"}, {"condition", "item-not-found"}], []})}; bad_key -> - {200, ?HEADER, + {200, ?HEADER, xml:element_to_string( {xmlelement, "body", [{"xmlns", ?NS_HTTP_BIND}, {"type", "terminate"}, {"condition", "item-not-found"}], []})}; polling_too_frequently -> - {200, ?HEADER, + {200, ?HEADER, xml:element_to_string( {xmlelement, "body", [{"xmlns", ?NS_HTTP_BIND}, @@ -800,19 +763,21 @@ handle_http_put_error(Reason, #http_bind{pid=FsmRef, version=Version}) end; handle_http_put_error(Reason, #http_bind{pid=FsmRef}) -> gen_fsm:sync_send_all_state_event(FsmRef,stop), - case Reason of + case Reason of not_exists -> %% bad rid + ?ERROR_MSG("Closing HTTP bind session (Bad rid).", []), {404, ?HEADER, ""}; bad_key -> + ?ERROR_MSG("Closing HTTP bind session (Bad key).", []), {404, ?HEADER, ""}; polling_too_frequently -> - {403, ?HEADER, ""} + ?ERROR_MSG("Closing HTTP bind session (User polling too frequently).", []), + {403, ?HEADER, ""} end. - -prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold, to=To}=Sess, +prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold, to=To}=Sess, Rid, _, StreamStart) -> - receive after 100 -> ok end, + receive after 100 -> ok end, %% TODO: Why is this needed. Argh. Bad programming practice. case catch http_get(Sess, Rid) of {ok, cancel} -> %% actually it would be better if we could completely @@ -829,7 +794,7 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold, to=To}=Sess, false -> send_outpacket(Sess, OutPacket); true -> - OutEls = + OutEls = case xml_stream:parse_element( OutPacket++"</stream:stream>") of El when element(1, El) == xmlelement -> @@ -842,14 +807,14 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold, to=To}=Sess, case Els of [] -> []; - [{xmlelement, "stream:features", - StreamAttribs, StreamEls} + [{xmlelement, "stream:features", + StreamAttribs, StreamEls} | StreamTail] -> - [{xmlelement, "stream:features", + [{xmlelement, "stream:features", [{"xmlns:stream", ?NS_STREAM} - ] - ++ StreamAttribs, + ] + ++ StreamAttribs, StreamEls }] ++ StreamTail; Xml -> @@ -868,11 +833,11 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold, to=To}=Sess, "condition='host-unknown' " "xmlns='"++?NS_HTTP_BIND++"'/>"}; true -> - BOSH_attribs = + BOSH_attribs = [{"authid", AuthID}, {"xmlns:xmpp", ?NS_BOSH}, {"xmlns:stream", ?NS_STREAM}] ++ - case OutEls of + case OutEls of [] -> []; _ -> @@ -887,12 +852,12 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold, to=To}=Sess, {"sid", Sid}, {"wait", integer_to_list(Wait)}, {"requests", integer_to_list(Hold+1)}, - {"inactivity", + {"inactivity", integer_to_list( trunc(MaxInactivity/1000))}, {"maxpause", integer_to_list(?MAX_PAUSE)}, - {"polling", + {"polling", integer_to_list( trunc(?MIN_POLLING/1000000))}, {"ver", ?BOSH_VERSION}, @@ -919,9 +884,9 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> gen_fsm:sync_send_all_state_event(FsmRef,stop), {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; _ -> - case xml_stream:parse_element("<body>" + case xml_stream:parse_element("<body>" ++ OutPacket - ++ "</body>") + ++ "</body>") of El when element(1, El) == xmlelement -> {xmlelement, _, _, OEls} = El, @@ -949,18 +914,18 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> case SEls of [] -> []; - [{xmlelement, - "stream:features", - StreamAttribs, StreamEls} | + [{xmlelement, + "stream:features", + StreamAttribs, StreamEls} | StreamTail] -> - TypedTail = + TypedTail = [check_default_xmlns(OEl) || OEl <- StreamTail], - [{xmlelement, - "stream:features", + [{xmlelement, + "stream:features", [{"xmlns:stream", - ?NS_STREAM}] ++ - StreamAttribs, StreamEls}] ++ + ?NS_STREAM}] ++ + StreamAttribs, StreamEls}] ++ TypedTail; Xml -> Xml @@ -971,7 +936,7 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> end, if StreamError -> - StreamErrCond = + StreamErrCond = case xml_stream:parse_element( "<stream:stream>" ++ OutPacket) of El when element(1, El) == xmlelement -> @@ -1013,14 +978,13 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> end. parse_request(Data) -> - ?DEBUG("--- incoming data --- ~n~s~n --- END --- ", - [Data]), + ?DEBUG("--- incoming data --- ~n~s~n --- END --- ", [Data]), case xml_stream:parse_element(Data) of El when element(1, El) == xmlelement -> {xmlelement, Name, Attrs, Els} = El, Xmlns = xml:get_attr_s("xmlns",Attrs), - if - Name /= "body" -> + if + Name /= "body" -> {error, bad_request}; Xmlns /= ?NS_HTTP_BIND -> {error, bad_request}; @@ -1029,29 +993,32 @@ parse_request(Data) -> {'EXIT', _} -> {error, bad_request}; Rid -> - FixedEls = + %% I guess this is to remove XMLCDATA: + FixedEls = lists:filter( - fun(I) -> - case I of + fun(I) -> + case I of {xmlelement, _, _, _} -> true; _ -> false end end, Els), - lists:map( - fun(E) -> - EXmlns = xml:get_tag_attr_s("xmlns",E), - if - EXmlns == ?NS_CLIENT -> - remove_tag_attr("xmlns",E); - true -> - ok - end - end, FixedEls), - Payload = [xml:element_to_string(E) || - E <- FixedEls], + %% MR: I commented this code, because it is not used. +%% lists:map( +%% fun(E) -> +%% EXmlns = xml:get_tag_attr_s("xmlns",E), +%% if +%% EXmlns == ?NS_CLIENT -> +%% remove_tag_attr("xmlns",E); +%% true -> +%% ok +%% end +%% end, FixedEls), + Payload = [xml:element_to_string(E) || E <- FixedEls], Sid = xml:get_attr_s("sid",Attrs), + %% MR: I do not think we need to extract + %% Sid. We should have it somewhere else: {ok, {Sid, Rid, Attrs, Payload}} end end; @@ -1059,6 +1026,9 @@ parse_request(Data) -> {error, bad_request} end. +%% Cancel timer and empty message queue. +cancel_timer(undefined) -> + ok; cancel_timer(Timer) -> erlang:cancel_timer(Timer), receive @@ -1068,6 +1038,7 @@ cancel_timer(Timer) -> ok end. +%% TODO: Use tail recursion and list reverse ? elements_to_string([]) -> []; elements_to_string([El | Els]) -> @@ -1085,24 +1056,20 @@ get_max_inactivity({Host, _}, Default) -> get_max_inactivity(_, Default) -> Default. +remove_tag_attr(Attr, {xmlelement, Name, Attrs, Els}) -> + Attrs1 = lists:keydelete(Attr, 1, Attrs), + {xmlelement, Name, Attrs1, Els}; remove_tag_attr(Attr, El) -> - case El of - {xmlelement, Name, Attrs, Els} -> - Attrs1 = lists:keydelete(Attr, 1, Attrs), - {xmlelement, Name, Attrs1, Els}; - _ -> - El - end. + El. check_default_xmlns({xmlelement, Name, Attrs, Els} = El) -> - EXmlns = xml:get_tag_attr_s("xmlns", El), - if - EXmlns == "" -> - {xmlelement, Name, [{"xmlns", ?NS_CLIENT} | Attrs], Els}; - true -> - El + case xml:get_tag_attr_s("xmlns", El) of + "" -> {xmlelement, Name, [{"xmlns", ?NS_CLIENT} | Attrs], Els}; + _ -> El end. +%% Check that mod_http_bind has been defined in config file. +%% Print a warning in log file if this is not the case. check_bind_module(XmppDomain) -> case gen_mod:is_loaded(XmppDomain, mod_http_bind) of true -> ok; From 35c6ea68cc0d21803ffa930efb4071cd5fedb81f Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:27:40 +0000 Subject: [PATCH 434/582] Code clean-up (EJAB-936)(thanks to Michael Remond) SVN Revision: 2319 --- src/web/ejabberd_http_bind.erl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 4f3648a9b..13b6c8a21 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 958 2009-05-12 14:43:41Z mremond $ +%%% Id : $Id: ejabberd_http_bind.erl 959 2009-05-12 14:45:27Z mremond $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -1056,11 +1056,11 @@ get_max_inactivity({Host, _}, Default) -> get_max_inactivity(_, Default) -> Default. -remove_tag_attr(Attr, {xmlelement, Name, Attrs, Els}) -> - Attrs1 = lists:keydelete(Attr, 1, Attrs), - {xmlelement, Name, Attrs1, Els}; -remove_tag_attr(Attr, El) -> - El. +%% remove_tag_attr(Attr, {xmlelement, Name, Attrs, Els}) -> +%% Attrs1 = lists:keydelete(Attr, 1, Attrs), +%% {xmlelement, Name, Attrs1, Els}; +%% remove_tag_attr(Attr, El) -> +%% El. check_default_xmlns({xmlelement, Name, Attrs, Els} = El) -> case xml:get_tag_attr_s("xmlns", El) of From ab5b66faccff60fb83612f23dcf4674d0a0212db Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:27:45 +0000 Subject: [PATCH 435/582] Easier debugging (EJAB-936)(thanks to Michael Remond) SVN Revision: 2320 --- src/web/ejabberd_http_bind.erl | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 13b6c8a21..a511eb9fc 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,7 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 959 2009-05-12 14:45:27Z mremond $ +%%% Id : $Id: ejabberd_http_bind.erl 960 2009-05-12 16:35:36Z mremond $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). @@ -28,7 +28,7 @@ close/1, process_request/2]). -%%-define(ejabberd_debug, true). +-define(ejabberd_debug, true). -include("ejabberd.hrl"). -include("jlib.hrl"). @@ -122,7 +122,7 @@ controlling_process(_Socket, _Pid) -> ok. close({http_bind, FsmRef, _IP}) -> - catch gen_fsm:sync_send_all_state_event(FsmRef, stop). + catch gen_fsm:sync_send_all_state_event(FsmRef, {stop, close}). sockname(_Socket) -> {ok, ?NULL_PEER}. @@ -204,6 +204,7 @@ handle_session_start(Pid, XmppDomain, Sid, Rid, Attrs, Payload, IP) -> V -> V end, XmppVersion = xml:get_attr_s("xmpp:version", Attrs), + ?DEBUG("Create session: ~p", [Sid]), mnesia:transaction( fun() -> mnesia:write( @@ -334,9 +335,17 @@ handle_sync_event({send, Packet}, _From, StateName, StateData) -> {reply, Reply, StateName, StateData#state{output = Output}} end; -handle_sync_event(stop, _From, _StateName, StateData) -> +handle_sync_event({stop,close}, _From, _StateName, StateData) -> Reply = ok, {stop, normal, Reply, StateData}; +handle_sync_event({stop,stream_closed}, _From, _StateName, StateData) -> + Reply = ok, + {stop, normal, Reply, StateData}; +handle_sync_event({stop,Reason}, _From, _StateName, StateData) -> + ?ERROR_MSG("Closing bind session ~p - Reason: ~p", [StateData#state.id, Reason]), + Reply = ok, + {stop, normal, Reply, StateData}; + %% HTTP PUT: Receive packets from the client handle_sync_event({http_put, Rid, Attrs, _Payload, Hold, _StreamTo, _IP}=Request, @@ -408,6 +417,7 @@ handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> (StateData#state.input /= "cancel") and (StateData#state.pause == 0) -> WaitTimer = erlang:start_timer(Wait * 1000, self(), []), + cancel_timer(StateData#state.timer), {next_state, StateName, StateData#state{ http_receiver = From, wait_timer = WaitTimer, @@ -480,8 +490,8 @@ code_change(_OldVsn, StateName, StateData, _Extra) -> %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- handle_info({timeout, Timer, _}, _StateName, - #state{timer = Timer} = StateData) -> - ?DEBUG("Session timeout. Closing the HTTP bind Session.", []), + #state{id=SID, timer = Timer} = StateData) -> + ?WARNING_MSG("Session timeout. Closing the HTTP bind session: ~p", [SID]), {stop, normal, StateData}; handle_info({timeout, WaitTimer, _}, StateName, @@ -515,7 +525,7 @@ handle_info(_, StateName, StateData) -> %% Returns: any %%---------------------------------------------------------------------- terminate(_Reason, _StateName, StateData) -> - ?DEBUG("terminate: deleting session ~s", [StateData#state.id]), + ?DEBUG("terminate: Deleting session ~s", [StateData#state.id]), mnesia:transaction( fun() -> mnesia:delete({http_bind, StateData#state.id}) @@ -719,7 +729,7 @@ handle_http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) -> end. http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) -> - ?DEBUG("http-put",[]), + ?DEBUG("Looking for session: ~p", [Sid]), case mnesia:dirty_read({http_bind, Sid}) of [] -> {error, not_exists}; @@ -737,7 +747,7 @@ http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) -> handle_http_put_error(Reason, #http_bind{pid=FsmRef, version=Version}) when Version >= 0 -> - gen_fsm:sync_send_all_state_event(FsmRef,stop), + gen_fsm:sync_send_all_state_event(FsmRef, {stop, {put_error,Reason}}), case Reason of not_exists -> {200, ?HEADER, @@ -762,7 +772,7 @@ handle_http_put_error(Reason, #http_bind{pid=FsmRef, version=Version}) {"condition", "policy-violation"}], []})} end; handle_http_put_error(Reason, #http_bind{pid=FsmRef}) -> - gen_fsm:sync_send_all_state_event(FsmRef,stop), + gen_fsm:sync_send_all_state_event(FsmRef,{stop, {put_error_no_version, Reason}}), case Reason of not_exists -> %% bad rid ?ERROR_MSG("Closing HTTP bind session (Bad rid).", []), @@ -881,7 +891,7 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> "" -> {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; "</stream:stream>" -> - gen_fsm:sync_send_all_state_event(FsmRef,stop), + gen_fsm:sync_send_all_state_event(FsmRef,{stop,stream_closed}), {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; _ -> case xml_stream:parse_element("<body>" @@ -950,7 +960,7 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> null end, gen_fsm:sync_send_all_state_event(FsmRef, - stop), + {stop, {stream_error,OutPacket}}), case StreamErrCond of null -> {200, ?HEADER, From b49f8a81a8a322d9b71590c027e2b4aab992756b Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:27:51 +0000 Subject: [PATCH 436/582] Add forgotten copyright and license notices. SVN Revision: 2321 --- src/web/ejabberd_http_bind.erl | 20 +++++++++++++++++++- src/web/mod_http_bind.erl | 24 +++++++++++++++++++++--- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index a511eb9fc..61d15943b 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,7 +4,25 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler <steve@zeank.in-berlin.de> -%%% Id : $Id: ejabberd_http_bind.erl 960 2009-05-12 16:35:36Z mremond $ +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). diff --git a/src/web/mod_http_bind.erl b/src/web/mod_http_bind.erl index 68688e328..615642ce5 100644 --- a/src/web/mod_http_bind.erl +++ b/src/web/mod_http_bind.erl @@ -3,13 +3,31 @@ %%% Author : Stefan Strigler <steve@zeank.in-berlin.de> %%% Purpose : Implementation of XMPP over BOSH (XEP-0206) %%% Created : Tue Feb 20 13:15:52 CET 2007 -%%% Id : $Id: mod_http_bind.erl 942 2009-04-22 15:25:31Z mremond $ +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% %%%---------------------------------------------------------------------- %%%---------------------------------------------------------------------- -%%% this module acts as a bridge to ejabberd_http_bind which implements +%%% This module acts as a bridge to ejabberd_http_bind which implements %%% the real stuff, this is to handle the new pluggable architecture for -%%% extending ejabberd's http service +%%% extending ejabberd's http service. %%%---------------------------------------------------------------------- -module(mod_http_bind). From a6b5e6360b5b9c7c30dc96bf7624570aa15b28ba Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:27:55 +0000 Subject: [PATCH 437/582] Add unit test script for http-bind service (thanks to Stefan Strigler) SVN Revision: 2322 --- tools/jhbtest.pl | 451 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 451 insertions(+) create mode 100755 tools/jhbtest.pl diff --git a/tools/jhbtest.pl b/tools/jhbtest.pl new file mode 100755 index 000000000..854e09ee7 --- /dev/null +++ b/tools/jhbtest.pl @@ -0,0 +1,451 @@ +#!/usr/bin/perl -w + +use strict; # har har + +use constant ERR => 0; +use constant WARN => 1; +use constant INFO => 2; +use constant DEBUG => 3; + +use constant RID => 31974; + +### ### ### conf ### ### ### + +my $BASE_ADDRESS = "http://localhost:5280/http-bind/"; +my $JABBER_SERVER = "localhost"; + +my $RID = RID; + +my $WAIT = 60; + +my $USER = "tester"; +my $UPW = "mysecret"; + +my $DEBUG = INFO; + +### ### ### END conf ### ### ### + +# create an agent we can use for our requests +use LWP::UserAgent; +my $ua = new LWP::UserAgent(); + +# create a tree parser to parse response content +use XML::Parser; +my $p = new XML::Parser(Style => 'Tree'); + + +### ### ### subs ### ### ### +sub doSend() { + my $content = shift; + + # create a request + my $req = new HTTP::Request(POST => $BASE_ADDRESS); + $req->content_type('text/xml; charset=utf-8'); + $req->content($content); + + debug(DEBUG,"<< Request\n".$req->as_string."<< END Request"); + + # send request + my $res = $ua->request($req); + + debug(DEBUG,">> Response\n" . $res->as_string .">> END Response"); + return $res; +} + +# getChildEls +# used to strip enclosing body element +# PARAMS: @tree - tree style array from XML::Parser +# RETURN: @children - child elements of top level element +sub getChildEls +{ + my $t = $_[0]; + + shift @{$t->[1]}; + return @{$t->[1]}; +} + +sub debug +{ + my $lvl = shift; + my $msg = shift; + + return if ($DEBUG < $lvl); + + my $prefix = "["; + $prefix .= "ERROR" if ($lvl == ERR); + $prefix .= "WARNING" if ($lvl == WARN); + $prefix .= "INFO" if ($lvl == INFO); + $prefix .= "DEBUG" if ($lvl == DEBUG); + $prefix .= "] "; + + $msg =~ s/\n/\n$prefix/g; + print STDERR $prefix . $msg . "\n"; +} +### ### ### main ### ### ### + +$| = 1; # set streaming output + +# no body +print "Sending some 'foo': "; +my $res = &doSend("foo"); +if ($res->code == 400) { + print "OK.\n"; +} else { + print "Failed!\n"; + print $res->as_string, "\n"; +} +# no body +print "Sending some '<foo />': "; +$res = &doSend("<foo />"); +if ($res->code == 400) { + print "OK.\n"; +} else { + print "Failed!\n"; + print $res->as_string, "\n"; +} + +# empty body +print "Sending empty body: "; +$res = &doSend("<body />"); +if ($res->code == 400) { + print "OK.\n"; +} else { + print "Failed!\n"; + print $res->as_string, "\n"; +} + +# fake a sid +print "Sending wrong sid: "; +$res = &doSend("<body sid='08154711' rid='$RID' xmlns='http://jabber.org/protocol/httpbind'/>"); +if ($res->code == 404) { + print "OK.\n"; +} else { + print "Failed!\n"; + print $res->as_string, "\n"; +} + +# forget to send 'to' +print "Missing 'to' attribute at session creation request: "; +$res = &doSend("<body content='text/xml; charset=utf-8' hold='0' rid='$RID' wait='60' xml:lang='en' xmlns='http://jabber.org/protocol/httpbind'/>"); +if ($res->is_success && $res->content =~ /<body .*type=["']terminate['"]/ && $res->content =~/<body .*condition=["']improper-addressing['"] /) { + print "OK.\n"; +} else { + print "Failed!\n"; + print $res->as_string, "\n"; +} + +# sending empty 'to' attribute +print "Empty 'to' attribute at session creation request: "; +$res = &doSend("<body content='text/xml; charset=utf-8' hold='0' rid='$RID' to='' wait='60' xml:lang='en' xmlns='http://jabber.org/protocol/httpbind'/>"); +if ($res->is_success && $res->content =~ /<body .*type=["']terminate['"]/ && $res->content =~/<body .*condition=["']improper-addressing['"] /) { + print "OK.\n"; +} else { + print "Failed!\n"; + print $res->as_string, "\n"; +} + +# forget to send a rid +print "Missing 'rid' attribute at session creation request: "; +$res = &doSend("<body content='text/xml; charset=utf-8' hold='0' to='$JABBER_SERVER' wait='60' xml:lang='en' xmlns='http://jabber.org/protocol/httpbind'/>"); +if ($res->code == 404) { + print "OK.\n"; +} else { + print "Failed!\n"; + print $res->as_string, "\n"; +} +# trying to connect to non-existent domain +print "Connecting to non-existent domain: "; +$res = &doSend("<body content='text/xml; charset=utf-8' hold='0' rid='$RID' to='foo.bar' wait='60' xml:lang='en' xmlns='http://jabber.org/protocol/httpbind'/>"); +if ($res->is_success && $res->content =~ /<body .*type=["']terminate['"]/ && $res->content =~/<body .*condition=["']host-unknown['"] /) { + print "OK.\n"; +} else { + print "Failed!\n"; + print $res->as_string, "\n"; +} + +# trying to connect to non-existent jabber server +print "Connecting to non-existent jabber server: "; +$res = &doSend("<body content='text/xml; charset=utf-8' hold='0' rid='$RID' to='www.jabber.org' wait='60' xml:lang='en' xmlns='http://jabber.org/protocol/httpbind'/>"); +if ($res->is_success && $res->content =~ /<body .*type=["']terminate['"]/ && ($res->content =~/<body .*condition=["']remote-connection-failed['"] / || $res->content =~/<body .*condition=["']host-unknown['"] /)) { + print "OK.\n"; +} else { + print "Failed!\n"; + print $res->as_string, "\n"; +} + +# connection to foreign server +#print "Connecting to foreign jabber server: "; +#$res = &doSend("<body content='text/xml; charset=utf-8' hold='0' rid='$RID' to='jwchat.org' wait='60' xml:lang='en' xmlns='http://jabber.org/protocol/httpbind'/>"); +#if ($res->is_success && $res->content =~ /<body .*type=["']terminate['"]/ && $res->content =~/<body .*condition=["']host-unknown['"] /) { +# print "OK.\n"; +#} else { +# print "Failed!\n"; +# print $res->as_string, "\n"; +#} + +my %sess; +sub getSess +{ + $sess{rid} = RID; # a rid to start + $res = &doSend("<body content='text/xml; charset=utf-8' hold='0' rid='$sess{rid}' to='$JABBER_SERVER' wait='$WAIT' xml:lang='en' xmlns='http://jabber.org/protocol/httpbind'/>"); + if ($res->is_success) { + my $t = $p->parse($res->content); + %sess = %{$t->[1]->[0]}; + $sess{rid} = RID; # a rid to start + + if (defined($sess{sid}) && $sess{sid} ne "" && defined($sess{wait}) && $sess{wait} ne '' && $sess{wait} <= $WAIT) { + debug(INFO,"sid: $sess{sid}"); + debug(INFO, "authid: $sess{authid}") if (defined($sess{authid})); + debug(INFO, "wait: $sess{wait}"); + debug(INFO, "inactivity: $sess{inactivity}") if (defined($sess{inactivity})); + debug(INFO, "polling: $sess{polling}") if (defined($sess{polling})); + debug(INFO, "requests: $sess{requests}") if (defined($sess{requests})); + debug(INFO, "accept: $sess{accept}") if (defined($sess{accept})); + debug(INFO, "charsets: $sess{charsets}") if (defined($sess{charsets})); + + debug (WARN, "authid missing") unless (defined($sess{authid}) && $sess{authid} ne ''); + debug (WARN, "server indicates polling mode") if (defined($sess{requests}) && $sess{requests} == 1); + return 1; + } + + } + + debug(ERR, "sid missing") unless (defined($sess{sid}) && $sess{sid} ne ""); + debug(ERR, "wait missing") unless (defined($sess{wait}) && $sess{wait} ne ''); + debug(ERR, "wait bigger then requested") unless (defined($sess{wait}) && $sess{wait} ne '' && $sess{wait} <= $WAIT); + + debug(DEBUG, $res->as_string); + return 0; +} + +# try to get a real sid +print "Create a new session: "; +if (&getSess()) { + print "OK.\n"; +} else { + debug(ERR, "Aborting."); + exit(1); +} + +# checking wait attribute +print "Creating another session with smaller 'wait' then before: "; +$WAIT = $sess{wait} - 1; +if (&getSess()) { + print "OK.\n"; +} else { + print "FAILED!\n"; + debug(ERR, "Aborting."); + exit(1); +} + +sub doAuth +{ +# query auth + $sess{rid}++; + $res = &doSend("<body rid='$sess{rid}' sid='$sess{sid}' xmlns='http://jabber.org/protocol/httpbind'><iq type='get' id='auth1'><query xmlns='jabber:iq:auth'><username>$USER</username></query></iq></body>"); + my @els = (&getChildEls($p->parse($res->content))); + unless ($els[0] eq 'iq' && $els[1]->[0]->{'type'} eq 'result') { + debug(ERR, $res->content); + return 0; + } + +# send auth + $sess{rid}++; + $res = &doSend("<body rid='$sess{rid}' sid='$sess{sid}' xmlns='http://jabber.org/protocol/httpbind'><iq type='set' id='auth2'><query xmlns='jabber:iq:auth'><username>$USER</username><resource>test</resource><password>$UPW</password></query></iq></body>"); + @els = (&getChildEls($p->parse($res->content))); + unless ($els[0] eq 'iq' && $els[1]->[0]->{'type'} eq 'result') { + debug(ERR, $res->content); + return 0; + } + + return 1; +} + +print "Authenticating: "; +if (&doAuth()) { + print "OK.\n"; +} else { + print "FAILED!\n"; + debug(ERR, "Aborting."); + exit(1); +} + + +sub doPoll +{ + $sess{rid}++; + return &doSend("<body rid='$sess{rid}' sid='$sess{sid}' xmlns='http://jabber.org/protocol/httpbind'/>"); + } + + +print "Polling with wrong 'rid': "; +$sess{rid}--; +$res = &doPoll(); +if ($res->code != 404) { + print "FAILED!\n"; + debug(ERR, "Aborting."); + # exit(1); +} +print "OK.\n"; +print "Checking if session terminated: "; +$res = &doPoll(); +if ($res->code != 404) { + print "FAILED!\n"; + debug(ERR, "Aborting."); + # exit(1); +} +print "OK.\n"; + +print "Create a new session: "; +if (&getSess()) { + print "OK.\n"; +} else { + debug(ERR, "Aborting."); + exit(1); +} + +print "Authenticating: "; +if (&doAuth()) { + print "OK.\n"; +} else { + print "FAILED!\n"; + debug(ERR, "Aborting."); + # exit(1); +} + +print "Polling too frequently: "; +$res = &doPoll(); +if ($res->code != 200) { + print "First poll failed unexpectedly!\n"; + debug(ERR, "Aborting."); + #exit(1); +} +$res = &doPoll(); +if ($res->code != 403) { + print "FAILED!\n"; + debug(ERR, "Aborting."); + #exit(1); +} +print "OK.\n"; + +print "Checking if session terminated: "; +$res = &doPoll(); +if ($res->code != 404) { + print "FAILED!\n"; + debug(ERR, "Aborting."); + #exit(1); +} +print "OK.\n"; + +print "Create a new session: "; +if (&getSess()) { + print "OK.\n"; +} else { + debug(ERR, "Aborting."); + exit(1); +} + +print "Authenticating: "; +if (&doAuth()) { + print "OK.\n"; +} else { + print "FAILED!\n"; + debug(ERR, "Aborting."); + exit(1); +} + +print "Test if proper polling is allowed: "; +$res = &doPoll(); +if ($res->code != 200) { + print "FAILED!\n"; + debug(ERR, "Aborting."); + exit(1); +} +sleep $sess{polling}; +$res = &doPoll(); +if ($res->code != 200) { + print "FAILED!\n"; + debug(ERR, "Aborting."); + exit(1); +} +print "OK.\n"; + +print "Waiting for session to timeout: "; +my $STEP=10; +for (my $i=0; $i<$sess{inactivity}; $i+=$STEP) { + print "."; + sleep $STEP; +} +sleep 1; # take another nap +$res = &doPoll(); +if ($res->code != 404) { + print "FAILED!\n"; + debug(ERR, "Aborting."); + exit(1); +} +print "OK.\n"; + +print "Create a new session: "; +if (&getSess()) { + print "OK.\n"; +} else { + debug(ERR, "Aborting."); + exit(1); +} + +print "Authenticating: "; +if (&doAuth()) { + print "OK.\n"; +} else { + print "FAILED!\n"; + debug(ERR, "Aborting."); + exit(1); +} + + +# [TODO] +# Check for +# * KEY Sequence Algorithm Compliance +# * Too Many Simultaneous Connections (probably hard to achieve for polling mode) +# * request custom content-type/-encoding + +# get roster +print "getting roster\n"; +$sess{rid}++; +$res = &doSend("<body rid='$sess{rid}' sid='$sess{sid}' xmlns='http://jabber.org/protocol/httpbind'><iq type='get'><query xmlns='jabber:iq:roster' /></iq></body>"); +debug(INFO, $res->content); + +# send presence +print "sending presence\n"; +$sess{rid}++; +$res = &doSend("<body rid='$sess{rid}' sid='$sess{sid}' xmlns='http://jabber.org/protocol/httpbind'><presence /></body>"); +debug(INFO, $res->content); + +# sending bullshit +print "sending bullshit\n"; +$sess{rid}++; +$res = &doSend("<body rid='$sess{rid}' sid='$sess{sid}' xmlns='http://jabber.org/protocol/httpbind'>sending bullshit</body>"); +debug(INFO, $res->content); + +# send presence +print "sending xa presence\n"; +$sess{rid}++; +$res = &doSend("<body rid='$sess{rid}' sid='$sess{sid}' xmlns='http://jabber.org/protocol/httpbind'><presence><show>xa</show></presence></body>"); +debug(INFO, $res->content); + +# disconnect +sleep 3; +print "logout\n"; +$sess{rid}++; +$res = &doSend("<body rid='$sess{rid}' sid='$sess{sid}' type='terminate' xmlns='http://jabber.org/protocol/httpbind'><presence type='unavailable'/></body>"); +debug(INFO, $res->content); + + +print "Checking if session terminated: "; +$res = &doPoll(); +if ($res->code != 404) { + print "FAILED!\n"; + debug(ERR, "Aborting."); + exit(1); +} +print "OK.\n"; From 08ebf50480403aeab06a374b36531d8e81c153ae Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:28:01 +0000 Subject: [PATCH 438/582] Add permanent section about mod_http_fileserver to the Guide. Example config. SVN Revision: 2323 --- contrib/ejabberd-modules.repo | 4 +- doc/Makefile | 6 +- doc/guide.html | 267 ++++++++++++++++++++-------------- doc/guide.tex | 77 +++++++++- src/ejabberd.cfg.example | 2 + 5 files changed, 238 insertions(+), 118 deletions(-) diff --git a/contrib/ejabberd-modules.repo b/contrib/ejabberd-modules.repo index a38715e90..dfd4a1d17 100644 --- a/contrib/ejabberd-modules.repo +++ b/contrib/ejabberd-modules.repo @@ -1,5 +1,5 @@ % List of ejabberd-modules to add for ejabberd packaging (source archive and installer) % % HTTP-binding: -https://svn.process-one.net/ejabberd-modules/http_bind/trunk -https://svn.process-one.net/ejabberd-modules/mod_http_fileserver/trunk +%https://svn.process-one.net/ejabberd-modules/http_bind/trunk +%https://svn.process-one.net/ejabberd-modules/mod_http_fileserver/trunk diff --git a/doc/Makefile b/doc/Makefile index aa1a71673..e0dec3789 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -3,9 +3,9 @@ SHELL = /bin/bash CONTRIBUTED_MODULES = "" -ifeq ($(shell ls mod_http_bind.tex),mod_http_bind.tex) - CONTRIBUTED_MODULES += "\\n\\setboolean{modhttpbind}{true}" -endif +#ifeq ($(shell ls mod_http_bind.tex),mod_http_bind.tex) +# CONTRIBUTED_MODULES += "\\n\\setboolean{modhttpbind}{true}" +#endif all: release pdf html diff --git a/doc/guide.html b/doc/guide.html index fdfaf3baf..81e88646f 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -142,77 +142,78 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;} </LI><LI CLASS="li-toc"><A HREF="#htoc40">3.3.3  <TT>mod_announce</TT></A> </LI><LI CLASS="li-toc"><A HREF="#htoc41">3.3.4  <TT>mod_disco</TT></A> </LI><LI CLASS="li-toc"><A HREF="#htoc42">3.3.5  <TT>mod_echo</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc43">3.3.6  <TT>mod_http_fileserver</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc44">3.3.7  <TT>mod_last</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc45">3.3.8  <TT>mod_muc</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc46">3.3.9  <TT>mod_muc_log</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc47">3.3.10  <TT>mod_offline</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc48">3.3.11  <TT>mod_privacy</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc49">3.3.12  <TT>mod_private</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc50">3.3.13  <TT>mod_proxy65</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc51">3.3.14  <TT>mod_pubsub</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc52">3.3.15  <TT>mod_register</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc53">3.3.16  <TT>mod_roster</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc54">3.3.17  <TT>mod_service_log</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc55">3.3.18  <TT>mod_shared_roster</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc56">3.3.19  <TT>mod_stats</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc57">3.3.20  <TT>mod_time</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc58">3.3.21  <TT>mod_vcard</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc59">3.3.22  <TT>mod_vcard_ldap</TT></A> -</LI><LI CLASS="li-toc"><A HREF="#htoc60">3.3.23  <TT>mod_version</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc43">3.3.6  <TT>mod_http_bind</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc44">3.3.7  <TT>mod_http_fileserver</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc45">3.3.8  <TT>mod_last</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc46">3.3.9  <TT>mod_muc</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc47">3.3.10  <TT>mod_muc_log</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc48">3.3.11  <TT>mod_offline</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc49">3.3.12  <TT>mod_privacy</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc50">3.3.13  <TT>mod_private</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc51">3.3.14  <TT>mod_proxy65</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc52">3.3.15  <TT>mod_pubsub</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc53">3.3.16  <TT>mod_register</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc54">3.3.17  <TT>mod_roster</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc55">3.3.18  <TT>mod_service_log</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc56">3.3.19  <TT>mod_shared_roster</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc57">3.3.20  <TT>mod_stats</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc58">3.3.21  <TT>mod_time</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc59">3.3.22  <TT>mod_vcard</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc60">3.3.23  <TT>mod_vcard_ldap</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc61">3.3.24  <TT>mod_version</TT></A> </LI></UL> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc61">Chapter 4  Managing an <TT>ejabberd</TT> Server</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc62">Chapter 4  Managing an <TT>ejabberd</TT> Server</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc62">4.1  <TT>ejabberdctl</TT></A> +<A HREF="#htoc63">4.1  <TT>ejabberdctl</TT></A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc63">4.1.1  ejabberdctl Commands</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc64">4.1.2  Erlang Runtime System</A> +<A HREF="#htoc64">4.1.1  ejabberdctl Commands</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc65">4.1.2  Erlang Runtime System</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc65">4.2  <TT>ejabberd</TT> Commands</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc66">4.2  <TT>ejabberd</TT> Commands</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc66">4.2.1  List of ejabberd Commands</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc67">4.2.2  Restrict Execution with AccessCommands</A> +<A HREF="#htoc67">4.2.1  List of ejabberd Commands</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc68">4.2.2  Restrict Execution with AccessCommands</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc68">4.3  Web Admin</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc69">4.4  Ad-hoc Commands</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc70">4.5  Change Computer Hostname</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc69">4.3  Web Admin</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc70">4.4  Ad-hoc Commands</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc71">4.5  Change Computer Hostname</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc71">Chapter 5  Securing <TT>ejabberd</TT></A> +</LI><LI CLASS="li-toc"><A HREF="#htoc72">Chapter 5  Securing <TT>ejabberd</TT></A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc72">5.1  Firewall Settings</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc73">5.2  epmd</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc74">5.3  Erlang Cookie</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc75">5.4  Erlang Node Name</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc76">5.5  Securing Sensible Files</A> +<A HREF="#htoc73">5.1  Firewall Settings</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc74">5.2  epmd</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc75">5.3  Erlang Cookie</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc76">5.4  Erlang Node Name</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc77">5.5  Securing Sensible Files</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc77">Chapter 6  Clustering</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc78">Chapter 6  Clustering</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc78">6.1  How it Works</A> +<A HREF="#htoc79">6.1  How it Works</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc79">6.1.1  Router</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc80">6.1.2  Local Router</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc81">6.1.3  Session Manager</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc82">6.1.4  s2s Manager</A> +<A HREF="#htoc80">6.1.1  Router</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc81">6.1.2  Local Router</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc82">6.1.3  Session Manager</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc83">6.1.4  s2s Manager</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc83">6.2  Clustering Setup</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc84">6.3  Service Load-Balancing</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc84">6.2  Clustering Setup</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc85">6.3  Service Load-Balancing</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc85">6.3.1  Components Load-Balancing</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc86">6.3.2  Domain Load-Balancing Algorithm</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc87">6.3.3  Load-Balancing Buckets</A> +<A HREF="#htoc86">6.3.1  Components Load-Balancing</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc87">6.3.2  Domain Load-Balancing Algorithm</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc88">6.3.3  Load-Balancing Buckets</A> </LI></UL> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc88">Chapter 7  Debugging</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc89">Chapter 7  Debugging</A> <UL CLASS="toc"><LI CLASS="li-toc"> -<A HREF="#htoc89">7.1  Log Files</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc90">7.2  Debug Console</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc91">7.3  Watchdog Alerts</A> +<A HREF="#htoc90">7.1  Log Files</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc91">7.2  Debug Console</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc92">7.3  Watchdog Alerts</A> </LI></UL> -</LI><LI CLASS="li-toc"><A HREF="#htoc92">Appendix A  Internationalization and Localization</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc93">Appendix B  Release Notes</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc94">Appendix C  Acknowledgements</A> -</LI><LI CLASS="li-toc"><A HREF="#htoc95">Appendix D  Copyright Information</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc93">Appendix A  Internationalization and Localization</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc94">Appendix B  Release Notes</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc95">Appendix C  Acknowledgements</A> +</LI><LI CLASS="li-toc"><A HREF="#htoc96">Appendix D  Copyright Information</A> </LI></UL><!--TOC chapter Introduction--> <H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc1">Chapter 1</A>  Introduction</H1><!--SEC END --><P> <A NAME="intro"></A></P><P><TT>ejabberd</TT> is a free and open source instant messaging server written in <A HREF="http://www.erlang.org/">Erlang</A>.</P><P><TT>ejabberd</TT> is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.</P><P><TT>ejabberd</TT> is designed to be a rock-solid and feature rich XMPP server.</P><P><TT>ejabberd</TT> is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.</P><!--TOC section Key Features--> @@ -490,7 +491,7 @@ There are two ways to register a Jabber account: <OL CLASS="enumerate" type=a><LI CLASS="li-enumerate"> Using <TT>ejabberdctl</TT> (see section <A HREF="#ejabberdctl">4.1</A>): <PRE CLASS="verbatim">ejabberdctl register admin1 example.org FgT5bk3 -</PRE></LI><LI CLASS="li-enumerate">Using a Jabber client and In-Band Registration (see section <A HREF="#modregister">3.3.15</A>). +</PRE></LI><LI CLASS="li-enumerate">Using a Jabber client and In-Band Registration (see section <A HREF="#modregister">3.3.16</A>). </LI></OL> </LI><LI CLASS="li-enumerate">Edit the <TT>ejabberd</TT> configuration file to give administration rights to the Jabber account you created: <PRE CLASS="verbatim">{acl, admins, {user, "admin1", "example.org"}}. @@ -1886,7 +1887,7 @@ message is sent to all registered users. If the user is online and connected to several resources, only the resource with the highest priority will receive the message. If the registered user is not connected, the message will be stored offline in assumption that offline storage -(see section <A HREF="#modoffline">3.3.10</A>) is enabled. +(see section <A HREF="#modoffline">3.3.11</A>) is enabled. </DD><DT CLASS="dt-description"><B><TT>example.org/announce/online (example.org/announce/all-hosts/online)</TT></B></DT><DD CLASS="dd-description">The message is sent to all connected users. If the user is online and connected to several resources, all resources will receive the message. @@ -1996,8 +1997,58 @@ of them all? {mod_echo, [{host, "mirror.example.org"}]}, ... ]}. +</PRE><P> <A NAME="modhttpbind"></A> </P><!--TOC subsection <TT>mod_http_bind</TT>--> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc43">3.3.6</A>  <A HREF="#modhttpbind"><TT>mod_http_bind</TT></A></H3><!--SEC END --><P> <A NAME="modhttpbind"></A> +</P><P>This module implements XMPP over Bosh (formerly known as HTTP Binding) +as defined in <A HREF="http://www.xmpp.org/extensions/xep-0124.html">XEP-0124</A> and <A HREF="http://www.xmpp.org/extensions/xep-0206.html">XEP-0206</A>. +It extends ejabberd’s built in HTTP service with a configurable +resource at which this service will be hosted.</P><P>To use HTTP-Binding, enable the module: +</P><PRE CLASS="verbatim">{modules, + [ + ... + {mod_http_bind, []}, + ... +]}. +</PRE><P>and add <CODE>http_bind</CODE> in the HTTP service. For example: +</P><PRE CLASS="verbatim">{listen, + [ + ... + {5280, ejabberd_http, [ + http_bind, + http_poll, + web_admin + ] + }, + ... +]}. +</PRE><P>With this configuration, the module will serve the requests sent to +<CODE>http://example.org:5280/http-bind/</CODE> +Remember that this page is not designed to be used by web browsers, +it is used by Jabber clients that support XMPP over Bosh.</P><P>If you want to set the service in a different URI path or use a different module, +you can configure it manually using the option <CODE>request_handlers</CODE>. +For example: +</P><PRE CLASS="verbatim">{listen, + [ + ... + {5280, ejabberd_http, [ + {request_handlers, [{["http-bind"], mod_http_bind}]}, + http_poll, + web_admin + ] + }, + ... +]}. +</PRE><P>The maximum inactivity period is by default 30 seconds. +This can be configured with the module option <TT>max_inactivity</TT>. +For example, to set 50 seconds: +</P><PRE CLASS="verbatim">{modules, + [ + ... + {mod_http_bind, [ {max_inactivity, 50} ]}, + ... +]}. </PRE><P> <A NAME="modhttpfileserver"></A> </P><!--TOC subsection <TT>mod_http_fileserver</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc43">3.3.6</A>  <A HREF="#modhttpfileserver"><TT>mod_http_fileserver</TT></A></H3><!--SEC END --><P> <A NAME="modhttpfileserver"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc44">3.3.7</A>  <A HREF="#modhttpfileserver"><TT>mod_http_fileserver</TT></A></H3><!--SEC END --><P> <A NAME="modhttpfileserver"></A> </P><P>This simple module serves files from the local disk over HTTP.</P><P>Options: </P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>docroot</TT></B></DT><DD CLASS="dd-description"> @@ -2043,7 +2094,7 @@ To use this module you must enable it: ... ]}. </PRE><P> <A NAME="modlast"></A> </P><!--TOC subsection <TT>mod_last</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc44">3.3.7</A>  <A HREF="#modlast"><TT>mod_last</TT></A></H3><!--SEC END --><P> <A NAME="modlast"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc45">3.3.8</A>  <A HREF="#modlast"><TT>mod_last</TT></A></H3><!--SEC END --><P> <A NAME="modlast"></A> </P><P>This module adds support for Last Activity (<A HREF="http://www.xmpp.org/extensions/xep-0012.html">XEP-0012</A>). It can be used to discover when a disconnected user last accessed the server, to know when a connected user was last active on the server, or to query the uptime of the @@ -2052,7 +2103,7 @@ connected user was last active on the server, or to query the uptime of the <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Last activity (<TT>jabber:iq:last</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modmuc"></A> </P><!--TOC subsection <TT>mod_muc</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc45">3.3.8</A>  <A HREF="#modmuc"><TT>mod_muc</TT></A></H3><!--SEC END --><P> <A NAME="modmuc"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc46">3.3.9</A>  <A HREF="#modmuc"><TT>mod_muc</TT></A></H3><!--SEC END --><P> <A NAME="modmuc"></A> </P><P>This module provides a Multi-User Chat (<A HREF="http://www.xmpp.org/extensions/xep-0045.html">XEP-0045</A>) service. Users can discover existing rooms, join or create them. Occupants of a room can chat in public or have private chats.</P><P>Some of the features of Multi-User Chat: @@ -2275,7 +2326,7 @@ the newly created rooms have by default those options. ... ]}. </PRE></LI></UL><P> <A NAME="modmuclog"></A> </P><!--TOC subsection <TT>mod_muc_log</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc46">3.3.9</A>  <A HREF="#modmuclog"><TT>mod_muc_log</TT></A></H3><!--SEC END --><P> <A NAME="modmuclog"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc47">3.3.10</A>  <A HREF="#modmuclog"><TT>mod_muc_log</TT></A></H3><!--SEC END --><P> <A NAME="modmuclog"></A> </P><P>This module enables optional logging of Multi-User Chat (MUC) public conversations to HTML. Once you enable this module, users can join a room using a MUC capable Jabber client, and if they have enough privileges, they can request the @@ -2395,7 +2446,7 @@ top link will be the default <CODE><a href="/">Home</a></CODE>. ... ]}. </PRE></LI></UL><P> <A NAME="modoffline"></A> </P><!--TOC subsection <TT>mod_offline</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc47">3.3.10</A>  <A HREF="#modoffline"><TT>mod_offline</TT></A></H3><!--SEC END --><P> <A NAME="modoffline"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc48">3.3.11</A>  <A HREF="#modoffline"><TT>mod_offline</TT></A></H3><!--SEC END --><P> <A NAME="modoffline"></A> </P><P>This module implements offline message storage. This means that all messages sent to an offline user will be stored on the server until that user comes online again. Thus it is very similar to how email works. Note that @@ -2426,7 +2477,7 @@ and all the other users up to 100. ... ]}. </PRE><P> <A NAME="modprivacy"></A> </P><!--TOC subsection <TT>mod_privacy</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc48">3.3.11</A>  <A HREF="#modprivacy"><TT>mod_privacy</TT></A></H3><!--SEC END --><P> <A NAME="modprivacy"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc49">3.3.12</A>  <A HREF="#modprivacy"><TT>mod_privacy</TT></A></H3><!--SEC END --><P> <A NAME="modprivacy"></A> </P><P>This module implements Blocking Communication (also known as Privacy Rules) as defined in section 10 from XMPP IM. If end users have support for it in their Jabber client, they will be able to: @@ -2454,7 +2505,7 @@ subscription type (or globally). <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Blocking Communication (<TT>jabber:iq:privacy</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modprivate"></A> </P><!--TOC subsection <TT>mod_private</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc49">3.3.12</A>  <A HREF="#modprivate"><TT>mod_private</TT></A></H3><!--SEC END --><P> <A NAME="modprivate"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc50">3.3.13</A>  <A HREF="#modprivate"><TT>mod_private</TT></A></H3><!--SEC END --><P> <A NAME="modprivate"></A> </P><P>This module adds support for Private XML Storage (<A HREF="http://www.xmpp.org/extensions/xep-0049.html">XEP-0049</A>): </P><BLOCKQUOTE CLASS="quote"> Using this method, Jabber entities can store private data on the server and @@ -2466,7 +2517,7 @@ of client-specific preferences; another is Bookmark Storage (<A HREF="http://www <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Private XML Storage (<TT>jabber:iq:private</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modproxy"></A> </P><!--TOC subsection <TT>mod_proxy65</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc50">3.3.13</A>  <A HREF="#modproxy"><TT>mod_proxy65</TT></A></H3><!--SEC END --><P> <A NAME="modproxy"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc51">3.3.14</A>  <A HREF="#modproxy"><TT>mod_proxy65</TT></A></H3><!--SEC END --><P> <A NAME="modproxy"></A> </P><P>This module implements SOCKS5 Bytestreams (<A HREF="http://www.xmpp.org/extensions/xep-0065.html">XEP-0065</A>). It allows <TT>ejabberd</TT> to act as a file transfer proxy between two XMPP clients.</P><P>Options: @@ -2521,7 +2572,7 @@ The simpliest configuration of the module: ... ]}. </PRE></LI></UL><P> <A NAME="modpubsub"></A> </P><!--TOC subsection <TT>mod_pubsub</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc51">3.3.14</A>  <A HREF="#modpubsub"><TT>mod_pubsub</TT></A></H3><!--SEC END --><P> <A NAME="modpubsub"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc52">3.3.15</A>  <A HREF="#modpubsub"><TT>mod_pubsub</TT></A></H3><!--SEC END --><P> <A NAME="modpubsub"></A> </P><P>This module offers a Publish-Subscribe Service (<A HREF="http://www.xmpp.org/extensions/xep-0060.html">XEP-0060</A>). The functionality in <TT>mod_pubsub</TT> can be extended using plugins. The plugin that implements PEP (Personal Eventing via Pubsub) (<A HREF="http://www.xmpp.org/extensions/xep-0163.html">XEP-0163</A>) @@ -2567,7 +2618,7 @@ The following example will use node_tune instead of node_pep for every PEP node ... ]}. </PRE><P> <A NAME="modregister"></A> </P><!--TOC subsection <TT>mod_register</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc52">3.3.15</A>  <A HREF="#modregister"><TT>mod_register</TT></A></H3><!--SEC END --><P> <A NAME="modregister"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc53">3.3.16</A>  <A HREF="#modregister"><TT>mod_register</TT></A></H3><!--SEC END --><P> <A NAME="modregister"></A> </P><P>This module adds support for In-Band Registration (<A HREF="http://www.xmpp.org/extensions/xep-0077.html">XEP-0077</A>). This protocol enables end users to use a Jabber client to: </P><UL CLASS="itemize"><LI CLASS="li-itemize"> @@ -2640,13 +2691,13 @@ Also define a registration timeout of one hour: ... ]}. </PRE></LI></UL><P> <A NAME="modroster"></A> </P><!--TOC subsection <TT>mod_roster</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc53">3.3.16</A>  <A HREF="#modroster"><TT>mod_roster</TT></A></H3><!--SEC END --><P> <A NAME="modroster"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc54">3.3.17</A>  <A HREF="#modroster"><TT>mod_roster</TT></A></H3><!--SEC END --><P> <A NAME="modroster"></A> </P><P>This module implements roster management as defined in <A HREF="http://www.xmpp.org/specs/rfc3921.html#roster">RFC 3921: XMPP IM</A>.</P><P>Options: </P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Roster Management (<TT>jabber:iq:roster</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modservicelog"></A> </P><!--TOC subsection <TT>mod_service_log</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc54">3.3.17</A>  <A HREF="#modservicelog"><TT>mod_service_log</TT></A></H3><!--SEC END --><P> <A NAME="modservicelog"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc55">3.3.18</A>  <A HREF="#modservicelog"><TT>mod_service_log</TT></A></H3><!--SEC END --><P> <A NAME="modservicelog"></A> </P><P>This module adds support for logging end user packets via a Jabber message auditing service such as <A HREF="http://www.funkypenguin.info/project/bandersnatch/">Bandersnatch</A>. All user @@ -2676,7 +2727,7 @@ To log all end user packets to the Bandersnatch service running on ... ]}. </PRE></LI></UL><P> <A NAME="modsharedroster"></A> </P><!--TOC subsection <TT>mod_shared_roster</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc55">3.3.18</A>  <A HREF="#modsharedroster"><TT>mod_shared_roster</TT></A></H3><!--SEC END --><P> <A NAME="modsharedroster"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc56">3.3.19</A>  <A HREF="#modsharedroster"><TT>mod_shared_roster</TT></A></H3><!--SEC END --><P> <A NAME="modsharedroster"></A> </P><P>This module enables you to create shared roster groups. This means that you can create groups of people that can see members from (other) groups in their rosters. The big advantages of this feature are that end users do not need to @@ -2751,7 +2802,7 @@ roster groups as shown in the following table: </TABLE> <DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV></DIV></BLOCKQUOTE> </LI></UL><P> <A NAME="modstats"></A> </P><!--TOC subsection <TT>mod_stats</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc56">3.3.19</A>  <A HREF="#modstats"><TT>mod_stats</TT></A></H3><!--SEC END --><P> <A NAME="modstats"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc57">3.3.20</A>  <A HREF="#modstats"><TT>mod_stats</TT></A></H3><!--SEC END --><P> <A NAME="modstats"></A> </P><P>This module adds support for Statistics Gathering (<A HREF="http://www.xmpp.org/extensions/xep-0039.html">XEP-0039</A>). This protocol allows you to retrieve next statistics from your <TT>ejabberd</TT> deployment: </P><UL CLASS="itemize"><LI CLASS="li-itemize"> @@ -2783,14 +2834,14 @@ by sending: </query> </iq> </PRE></LI></UL><P> <A NAME="modtime"></A> </P><!--TOC subsection <TT>mod_time</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc57">3.3.20</A>  <A HREF="#modtime"><TT>mod_time</TT></A></H3><!--SEC END --><P> <A NAME="modtime"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc58">3.3.21</A>  <A HREF="#modtime"><TT>mod_time</TT></A></H3><!--SEC END --><P> <A NAME="modtime"></A> </P><P>This module features support for Entity Time (<A HREF="http://www.xmpp.org/extensions/xep-0090.html">XEP-0090</A>). By using this XEP, you are able to discover the time at another entity’s location.</P><P>Options: </P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Entity Time (<TT>jabber:iq:time</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="modvcard"></A> </P><!--TOC subsection <TT>mod_vcard</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc58">3.3.21</A>  <A HREF="#modvcard"><TT>mod_vcard</TT></A></H3><!--SEC END --><P> <A NAME="modvcard"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc59">3.3.22</A>  <A HREF="#modvcard"><TT>mod_vcard</TT></A></H3><!--SEC END --><P> <A NAME="modvcard"></A> </P><P>This module allows end users to store and retrieve their vCard, and to retrieve other users vCards, as defined in vcard-temp (<A HREF="http://www.xmpp.org/extensions/xep-0054.html">XEP-0054</A>). The module also implements an uncomplicated Jabber User Directory based on the vCards of @@ -2845,7 +2896,7 @@ and that all virtual hosts will be searched instead of only the current one: ... ]}. </PRE></LI></UL><P> <A NAME="modvcardldap"></A> </P><!--TOC subsection <TT>mod_vcard_ldap</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc59">3.3.22</A>  <A HREF="#modvcardldap"><TT>mod_vcard_ldap</TT></A></H3><!--SEC END --><P> <A NAME="modvcardldap"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc60">3.3.23</A>  <A HREF="#modvcardldap"><TT>mod_vcard_ldap</TT></A></H3><!--SEC END --><P> <A NAME="modvcardldap"></A> </P><P><TT>ejabberd</TT> can map LDAP attributes to vCard fields. This behaviour is implemented in the <TT>mod_vcard_ldap</TT> module. This module does not depend on the authentication method (see <A HREF="#ldapauth">3.2.5</A>).</P><P>Note that <TT>ejabberd</TT> treats LDAP as a read-only storage: @@ -3021,7 +3072,7 @@ searching his info in LDAP.</P></LI><LI CLASS="li-itemize"><TT>ldap_vcard_map</T {"Nickname", "NICKNAME"} ]}, </PRE></LI></UL><P> <A NAME="modversion"></A> </P><!--TOC subsection <TT>mod_version</TT>--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc60">3.3.23</A>  <A HREF="#modversion"><TT>mod_version</TT></A></H3><!--SEC END --><P> <A NAME="modversion"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc61">3.3.24</A>  <A HREF="#modversion"><TT>mod_version</TT></A></H3><!--SEC END --><P> <A NAME="modversion"></A> </P><P>This module implements Software Version (<A HREF="http://www.xmpp.org/extensions/xep-0092.html">XEP-0092</A>). Consequently, it answers <TT>ejabberd</TT>’s version when queried.</P><P>Options: </P><DL CLASS="description"><DT CLASS="dt-description"> @@ -3030,8 +3081,8 @@ The default value is <TT>true</TT>. </DD><DT CLASS="dt-description"><B><TT>iqdisc</TT></B></DT><DD CLASS="dd-description"> This specifies the processing discipline for Software Version (<TT>jabber:iq:version</TT>) IQ queries (see section <A HREF="#modiqdiscoption">3.3.2</A>). </DD></DL><P> <A NAME="manage"></A> </P><!--TOC chapter Managing an <TT>ejabberd</TT> Server--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc61">Chapter 4</A>  <A HREF="#manage">Managing an <TT>ejabberd</TT> Server</A></H1><!--SEC END --><P> <A NAME="manage"></A> </P><P> <A NAME="ejabberdctl"></A> </P><!--TOC section <TT>ejabberdctl</TT>--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc62">4.1</A>  <A HREF="#ejabberdctl"><TT>ejabberdctl</TT></A></H2><!--SEC END --><P> <A NAME="ejabberdctl"></A> </P><P>With the <TT>ejabberdctl</TT> command line administration script +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc62">Chapter 4</A>  <A HREF="#manage">Managing an <TT>ejabberd</TT> Server</A></H1><!--SEC END --><P> <A NAME="manage"></A> </P><P> <A NAME="ejabberdctl"></A> </P><!--TOC section <TT>ejabberdctl</TT>--> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc63">4.1</A>  <A HREF="#ejabberdctl"><TT>ejabberdctl</TT></A></H2><!--SEC END --><P> <A NAME="ejabberdctl"></A> </P><P>With the <TT>ejabberdctl</TT> command line administration script you can execute <TT>ejabberdctl commands</TT> (described in the next section, <A HREF="#ectl-commands">4.1.1</A>) and also many general <TT>ejabberd commands</TT> (described in section <A HREF="#eja-commands">4.2</A>). This means you can start, stop and perform many other administrative tasks @@ -3043,7 +3094,7 @@ and other codes may be used for specific results. This can be used by other scripts to determine automatically if a command succeeded or failed, for example using: <TT>echo $?</TT></P><P> <A NAME="ectl-commands"></A> </P><!--TOC subsection ejabberdctl Commands--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc63">4.1.1</A>  <A HREF="#ectl-commands">ejabberdctl Commands</A></H3><!--SEC END --><P> <A NAME="ectl-commands"></A> </P><P>When <TT>ejabberdctl</TT> is executed without any parameter, +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc64">4.1.1</A>  <A HREF="#ectl-commands">ejabberdctl Commands</A></H3><!--SEC END --><P> <A NAME="ectl-commands"></A> </P><P>When <TT>ejabberdctl</TT> is executed without any parameter, it displays the available options. If there isn’t an <TT>ejabberd</TT> server running, the available parameters are: </P><DL CLASS="description"><DT CLASS="dt-description"> @@ -3079,7 +3130,7 @@ robot1 testuser1 testuser2 </PRE><P> <A NAME="erlangconfiguration"></A> </P><!--TOC subsection Erlang Runtime System--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc64">4.1.2</A>  <A HREF="#erlangconfiguration">Erlang Runtime System</A></H3><!--SEC END --><P> <A NAME="erlangconfiguration"></A> </P><P><TT>ejabberd</TT> is an Erlang/OTP application that runs inside an Erlang runtime system. +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc65">4.1.2</A>  <A HREF="#erlangconfiguration">Erlang Runtime System</A></H3><!--SEC END --><P> <A NAME="erlangconfiguration"></A> </P><P><TT>ejabberd</TT> is an Erlang/OTP application that runs inside an Erlang runtime system. This system is configured using environment variables and command line parameters. The <TT>ejabberdctl</TT> administration script uses many of those possibilities. You can configure some of them with the file <TT>ejabberdctl.cfg</TT>, @@ -3148,7 +3199,7 @@ Starts the Erlang system detached from the system console. </DD></DL><P> Note that some characters need to be escaped when used in shell scripts, for instance <CODE>"</CODE> and <CODE>{}</CODE>. You can find other options in the Erlang manual page (<TT>erl -man erl</TT>).</P><P> <A NAME="eja-commands"></A> </P><!--TOC section <TT>ejabberd</TT> Commands--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc65">4.2</A>  <A HREF="#eja-commands"><TT>ejabberd</TT> Commands</A></H2><!--SEC END --><P> <A NAME="eja-commands"></A> </P><P>An <TT>ejabberd command</TT> is an abstract function identified by a name, +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc66">4.2</A>  <A HREF="#eja-commands"><TT>ejabberd</TT> Commands</A></H2><!--SEC END --><P> <A NAME="eja-commands"></A> </P><P>An <TT>ejabberd command</TT> is an abstract function identified by a name, with a defined number and type of calling arguments and type of result that is registered in the <TT>ejabberd_commands</TT> service. Those commands can be defined in any Erlang module and executed using any valid frontend.</P><P><TT>ejabberd</TT> includes a frontend to execute <TT>ejabberd commands</TT>: the script <TT>ejabberdctl</TT>. @@ -3156,7 +3207,7 @@ Other known frontends that can be installed to execute ejabberd commands in diff <TT>ejabberd_xmlrpc</TT> (XML-RPC service), <TT>mod_rest</TT> (HTTP POST service), <TT>mod_shcommands</TT> (ejabberd WebAdmin page).</P><P> <A NAME="list-eja-commands"></A> </P><!--TOC subsection List of ejabberd Commands--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc66">4.2.1</A>  <A HREF="#list-eja-commands">List of ejabberd Commands</A></H3><!--SEC END --><P> <A NAME="list-eja-commands"></A> </P><P><TT>ejabberd</TT> includes a few ejabberd Commands by default. +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc67">4.2.1</A>  <A HREF="#list-eja-commands">List of ejabberd Commands</A></H3><!--SEC END --><P> <A NAME="list-eja-commands"></A> </P><P><TT>ejabberd</TT> includes a few ejabberd Commands by default. When more modules are installed, new commands may be available in the frontends.</P><P>The easiest way to get a list of the available commands, and get help for them is to use the ejabberdctl script: </P><PRE CLASS="verbatim">$ ejabberdctl help @@ -3196,7 +3247,7 @@ exist tutorials to <A HREF="http://www.ejabberd.im/migrate-to-ejabberd">migrate in offline storage. This might be useful when the number of offline messages is very high. </DD></DL><P> <A NAME="accesscommands"></A> </P><!--TOC subsection Restrict Execution with AccessCommands--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc67">4.2.2</A>  <A HREF="#accesscommands">Restrict Execution with AccessCommands</A></H3><!--SEC END --><P> <A NAME="accesscommands"></A> </P><P>The frontends can be configured to restrict access to certain commands. +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc68">4.2.2</A>  <A HREF="#accesscommands">Restrict Execution with AccessCommands</A></H3><!--SEC END --><P> <A NAME="accesscommands"></A> </P><P>The frontends can be configured to restrict access to certain commands. In that case, authentication information must be provided. In each frontend the <TT>AccessCommands</TT> option is defined in a different place. But in all cases the option syntax is the same: @@ -3242,7 +3293,7 @@ and the provided arguments do not contradict Arguments.</P><P>As an example to u {_bot_reg_test, [register, unregister], [{host, "test.org"}]} ] </PRE><P> <A NAME="webadmin"></A> </P><!--TOC section Web Admin--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc68">4.3</A>  <A HREF="#webadmin">Web Admin</A></H2><!--SEC END --><P> <A NAME="webadmin"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc69">4.3</A>  <A HREF="#webadmin">Web Admin</A></H2><!--SEC END --><P> <A NAME="webadmin"></A> </P><P>The <TT>ejabberd</TT> Web Admin allows to administer most of <TT>ejabberd</TT> using a web browser.</P><P>This feature is enabled by default: a <TT>ejabberd_http</TT> listener with the option <TT>web_admin</TT> (see section <A HREF="#listened">3.1.3</A>) is included in the listening ports. Then you can open @@ -3314,13 +3365,13 @@ The file is searched by default in The directory of the documentation can be specified in the environment variable <TT>EJABBERD_DOC_PATH</TT>. See section <A HREF="#erlangconfiguration">4.1.2</A>.</P><P> <A NAME="adhoccommands"></A> </P><!--TOC section Ad-hoc Commands--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc69">4.4</A>  <A HREF="#adhoccommands">Ad-hoc Commands</A></H2><!--SEC END --><P> <A NAME="adhoccommands"></A> </P><P>If you enable <TT>mod_configure</TT> and <TT>mod_adhoc</TT>, +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc70">4.4</A>  <A HREF="#adhoccommands">Ad-hoc Commands</A></H2><!--SEC END --><P> <A NAME="adhoccommands"></A> </P><P>If you enable <TT>mod_configure</TT> and <TT>mod_adhoc</TT>, you can perform several administrative tasks in <TT>ejabberd</TT> with a Jabber client. The client must support Ad-Hoc Commands (<A HREF="http://www.xmpp.org/extensions/xep-0050.html">XEP-0050</A>), and you must login in the Jabber server with an account with proper privileges.</P><P> <A NAME="changeerlangnodename"></A> </P><!--TOC section Change Computer Hostname--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc70">4.5</A>  <A HREF="#changeerlangnodename">Change Computer Hostname</A></H2><!--SEC END --><P> <A NAME="changeerlangnodename"></A> </P><P><TT>ejabberd</TT> uses the distributed Mnesia database. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc71">4.5</A>  <A HREF="#changeerlangnodename">Change Computer Hostname</A></H2><!--SEC END --><P> <A NAME="changeerlangnodename"></A> </P><P><TT>ejabberd</TT> uses the distributed Mnesia database. Being distributed, Mnesia enforces consistency of its file, so it stores the name of the Erlang node in it (see section <A HREF="#nodename">5.4</A>). The name of an Erlang node includes the hostname of the computer. @@ -3357,8 +3408,8 @@ mv /var/lib/ejabberd/*.* /var/lib/ejabberd/oldfiles/ </PRE></LI><LI CLASS="li-enumerate">Check that the information of the old database is available: accounts, rosters... After you finish, remember to delete the temporary backup files from public directories. </LI></OL><P> <A NAME="secure"></A> </P><!--TOC chapter Securing <TT>ejabberd</TT>--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc71">Chapter 5</A>  <A HREF="#secure">Securing <TT>ejabberd</TT></A></H1><!--SEC END --><P> <A NAME="secure"></A> </P><P> <A NAME="firewall"></A> </P><!--TOC section Firewall Settings--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc72">5.1</A>  <A HREF="#firewall">Firewall Settings</A></H2><!--SEC END --><P> <A NAME="firewall"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc72">Chapter 5</A>  <A HREF="#secure">Securing <TT>ejabberd</TT></A></H1><!--SEC END --><P> <A NAME="secure"></A> </P><P> <A NAME="firewall"></A> </P><!--TOC section Firewall Settings--> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc73">5.1</A>  <A HREF="#firewall">Firewall Settings</A></H2><!--SEC END --><P> <A NAME="firewall"></A> </P><P>You need to take the following TCP ports in mind when configuring your firewall: </P><BLOCKQUOTE CLASS="table"><DIV CLASS="center"><DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV> <TABLE BORDER=1 CELLSPACING=0 CELLPADDING=1><TR><TD ALIGN=left NOWRAP><B>Port</B></TD><TD ALIGN=left NOWRAP><B>Description</B></TD></TR> @@ -3369,7 +3420,7 @@ After you finish, remember to delete the temporary backup files from public dire <TR><TD ALIGN=left NOWRAP>port range</TD><TD ALIGN=left NOWRAP>Used for connections between Erlang nodes. This range is configurable (see section <A HREF="#epmd">5.2</A>).</TD></TR> </TABLE> <DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV></DIV></BLOCKQUOTE><P> <A NAME="epmd"></A> </P><!--TOC section epmd--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc73">5.2</A>  <A HREF="#epmd">epmd</A></H2><!--SEC END --><P> <A NAME="epmd"></A> </P><P><A HREF="http://www.erlang.org/doc/man/epmd.html">epmd (Erlang Port Mapper Daemon)</A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc74">5.2</A>  <A HREF="#epmd">epmd</A></H2><!--SEC END --><P> <A NAME="epmd"></A> </P><P><A HREF="http://www.erlang.org/doc/man/epmd.html">epmd (Erlang Port Mapper Daemon)</A> is a small name server included in Erlang/OTP and used by Erlang programs when establishing distributed Erlang communications. <TT>ejabberd</TT> needs <TT>epmd</TT> to use <TT>ejabberdctl</TT> and also when clustering <TT>ejabberd</TT> nodes. @@ -3394,7 +3445,7 @@ but can be configured in the file <TT>ejabberdctl.cfg</TT>. The Erlang command-line parameter used internally is, for example: </P><PRE CLASS="verbatim">erl ... -kernel inet_dist_listen_min 4370 inet_dist_listen_max 4375 </PRE><P> <A NAME="cookie"></A> </P><!--TOC section Erlang Cookie--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc74">5.3</A>  <A HREF="#cookie">Erlang Cookie</A></H2><!--SEC END --><P> <A NAME="cookie"></A> </P><P>The Erlang cookie is a string with numbers and letters. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc75">5.3</A>  <A HREF="#cookie">Erlang Cookie</A></H2><!--SEC END --><P> <A NAME="cookie"></A> </P><P>The Erlang cookie is a string with numbers and letters. An Erlang node reads the cookie at startup from the command-line parameter <TT>-setcookie</TT>. If not indicated, the cookie is read from the cookie file <TT>$HOME/.erlang.cookie</TT>. If this file does not exist, it is created immediately with a random cookie. @@ -3408,7 +3459,7 @@ to prevent unauthorized access or intrusion to an Erlang node. The communication between Erlang nodes are not encrypted, so the cookie could be read sniffing the traffic on the network. The recommended way to secure the Erlang node is to block the port 4369.</P><P> <A NAME="nodename"></A> </P><!--TOC section Erlang Node Name--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc75">5.4</A>  <A HREF="#nodename">Erlang Node Name</A></H2><!--SEC END --><P> <A NAME="nodename"></A> </P><P>An Erlang node may have a node name. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc76">5.4</A>  <A HREF="#nodename">Erlang Node Name</A></H2><!--SEC END --><P> <A NAME="nodename"></A> </P><P>An Erlang node may have a node name. The name can be short (if indicated with the command-line parameter <TT>-sname</TT>) or long (if indicated with the parameter <TT>-name</TT>). Starting an Erlang node with -sname limits the communication between Erlang nodes to the LAN.</P><P>Using the option <TT>-sname</TT> instead of <TT>-name</TT> is a simple method @@ -3417,7 +3468,7 @@ However, it is not ultimately effective to prevent access to the Erlang node, because it may be possible to fake the fact that you are on another network using a modified version of Erlang <TT>epmd</TT>. The recommended way to secure the Erlang node is to block the port 4369.</P><P> <A NAME="secure-files"></A> </P><!--TOC section Securing Sensible Files--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc76">5.5</A>  <A HREF="#secure-files">Securing Sensible Files</A></H2><!--SEC END --><P> <A NAME="secure-files"></A> </P><P><TT>ejabberd</TT> stores sensible data in the file system either in plain text or binary files. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc77">5.5</A>  <A HREF="#secure-files">Securing Sensible Files</A></H2><!--SEC END --><P> <A NAME="secure-files"></A> </P><P><TT>ejabberd</TT> stores sensible data in the file system either in plain text or binary files. The file system permissions should be set to only allow the proper user to read, write and execute those files and directories.</P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>ejabberd configuration file: /etc/ejabberd/ejabberd.cfg</TT></B></DT><DD CLASS="dd-description"> @@ -3437,9 +3488,9 @@ so it is preferable to secure the whole <TT>/var/lib/ejabberd/</TT> directory. </DD><DT CLASS="dt-description"><B><TT>Erlang cookie file: /var/lib/ejabberd/.erlang.cookie</TT></B></DT><DD CLASS="dd-description"> See section <A HREF="#cookie">5.3</A>. </DD></DL><P> <A NAME="clustering"></A> </P><!--TOC chapter Clustering--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc77">Chapter 6</A>  <A HREF="#clustering">Clustering</A></H1><!--SEC END --><P> <A NAME="clustering"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc78">Chapter 6</A>  <A HREF="#clustering">Clustering</A></H1><!--SEC END --><P> <A NAME="clustering"></A> </P><P> <A NAME="howitworks"></A> </P><!--TOC section How it Works--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc78">6.1</A>  <A HREF="#howitworks">How it Works</A></H2><!--SEC END --><P> <A NAME="howitworks"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc79">6.1</A>  <A HREF="#howitworks">How it Works</A></H2><!--SEC END --><P> <A NAME="howitworks"></A> </P><P>A Jabber domain is served by one or more <TT>ejabberd</TT> nodes. These nodes can be run on different machines that are connected via a network. They all must have the ability to connect to port 4369 of all another nodes, and must @@ -3453,29 +3504,29 @@ router, </LI><LI CLASS="li-itemize">session manager, </LI><LI CLASS="li-itemize">s2s manager. </LI></UL><P> <A NAME="router"></A> </P><!--TOC subsection Router--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc79">6.1.1</A>  <A HREF="#router">Router</A></H3><!--SEC END --><P> <A NAME="router"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc80">6.1.1</A>  <A HREF="#router">Router</A></H3><!--SEC END --><P> <A NAME="router"></A> </P><P>This module is the main router of Jabber packets on each node. It routes them based on their destination’s domains. It uses a global routing table. The domain of the packet’s destination is searched in the routing table, and if it is found, the packet is routed to the appropriate process. If not, it is sent to the s2s manager.</P><P> <A NAME="localrouter"></A> </P><!--TOC subsection Local Router--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc80">6.1.2</A>  <A HREF="#localrouter">Local Router</A></H3><!--SEC END --><P> <A NAME="localrouter"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc81">6.1.2</A>  <A HREF="#localrouter">Local Router</A></H3><!--SEC END --><P> <A NAME="localrouter"></A> </P><P>This module routes packets which have a destination domain equal to one of this server’s host names. If the destination JID has a non-empty user part, it is routed to the session manager, otherwise it is processed depending on its content.</P><P> <A NAME="sessionmanager"></A> </P><!--TOC subsection Session Manager--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc81">6.1.3</A>  <A HREF="#sessionmanager">Session Manager</A></H3><!--SEC END --><P> <A NAME="sessionmanager"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc82">6.1.3</A>  <A HREF="#sessionmanager">Session Manager</A></H3><!--SEC END --><P> <A NAME="sessionmanager"></A> </P><P>This module routes packets to local users. It looks up to which user resource a packet must be sent via a presence table. Then the packet is either routed to the appropriate c2s process, or stored in offline storage, or bounced back.</P><P> <A NAME="s2smanager"></A> </P><!--TOC subsection s2s Manager--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc82">6.1.4</A>  <A HREF="#s2smanager">s2s Manager</A></H3><!--SEC END --><P> <A NAME="s2smanager"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc83">6.1.4</A>  <A HREF="#s2smanager">s2s Manager</A></H3><!--SEC END --><P> <A NAME="s2smanager"></A> </P><P>This module routes packets to other Jabber servers. First, it checks if an opened s2s connection from the domain of the packet’s source to the domain of the packet’s destination exists. If that is the case, the s2s manager routes the packet to the process serving this connection, otherwise a new connection is opened.</P><P> <A NAME="cluster"></A> </P><!--TOC section Clustering Setup--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc83">6.2</A>  <A HREF="#cluster">Clustering Setup</A></H2><!--SEC END --><P> <A NAME="cluster"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc84">6.2</A>  <A HREF="#cluster">Clustering Setup</A></H2><!--SEC END --><P> <A NAME="cluster"></A> </P><P>Suppose you already configured <TT>ejabberd</TT> on one machine named (<TT>first</TT>), and you need to setup another one to make an <TT>ejabberd</TT> cluster. Then do following steps:</P><OL CLASS="enumerate" type=1><LI CLASS="li-enumerate"> @@ -3513,10 +3564,10 @@ and ‘<CODE>access</CODE>’ options because they will be taken from enabled only on one machine in the cluster. </LI></OL><P>You can repeat these steps for other machines supposed to serve this domain.</P><P> <A NAME="servicelb"></A> </P><!--TOC section Service Load-Balancing--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc84">6.3</A>  <A HREF="#servicelb">Service Load-Balancing</A></H2><!--SEC END --><P> <A NAME="servicelb"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc85">6.3</A>  <A HREF="#servicelb">Service Load-Balancing</A></H2><!--SEC END --><P> <A NAME="servicelb"></A> </P><P> <A NAME="componentlb"></A> </P><!--TOC subsection Components Load-Balancing--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc85">6.3.1</A>  <A HREF="#componentlb">Components Load-Balancing</A></H3><!--SEC END --><P> <A NAME="componentlb"></A> </P><P> <A NAME="domainlb"></A> </P><!--TOC subsection Domain Load-Balancing Algorithm--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc86">6.3.2</A>  <A HREF="#domainlb">Domain Load-Balancing Algorithm</A></H3><!--SEC END --><P> <A NAME="domainlb"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc86">6.3.1</A>  <A HREF="#componentlb">Components Load-Balancing</A></H3><!--SEC END --><P> <A NAME="componentlb"></A> </P><P> <A NAME="domainlb"></A> </P><!--TOC subsection Domain Load-Balancing Algorithm--> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc87">6.3.2</A>  <A HREF="#domainlb">Domain Load-Balancing Algorithm</A></H3><!--SEC END --><P> <A NAME="domainlb"></A> </P><P><TT>ejabberd</TT> includes an algorithm to load balance the components that are plugged on an <TT>ejabberd</TT> cluster. It means that you can plug one or several instances of the same component on each <TT>ejabberd</TT> cluster and that the traffic will be automatically distributed.</P><P>The default distribution algorithm try to deliver to a local instance of a component. If several local instances are available, one instance is chosen randomly. If no instance is available locally, one instance is chosen randomly among the remote component instances.</P><P>If you need a different behaviour, you can change the load balancing behaviour with the option <TT>domain_balancing</TT>. The syntax of the option is the following:</P><PRE CLASS="verbatim">{domain_balancing, "component.example.com", <balancing_criterium>}. </PRE><P>Several balancing criteria are available: </P><UL CLASS="itemize"><LI CLASS="li-itemize"> @@ -3525,13 +3576,13 @@ domain.</P><P> <A NAME="servicelb"></A> </P><!--TOC section Service Load-Balanci </LI><LI CLASS="li-itemize"><TT>bare_destination</TT>: the bare JID (without resource) of the packet <TT>to</TT> attribute is used. </LI><LI CLASS="li-itemize"><TT>bare_source</TT>: the bare JID (without resource) of the packet <TT>from</TT> attribute is used. </LI></UL><P>If the value corresponding to the criteria is the same, the same component instance in the cluster will be used.</P><P> <A NAME="lbbuckets"></A> </P><!--TOC subsection Load-Balancing Buckets--> -<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc87">6.3.3</A>  <A HREF="#lbbuckets">Load-Balancing Buckets</A></H3><!--SEC END --><P> <A NAME="lbbuckets"></A> +<H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc88">6.3.3</A>  <A HREF="#lbbuckets">Load-Balancing Buckets</A></H3><!--SEC END --><P> <A NAME="lbbuckets"></A> </P><P>When there is a risk of failure for a given component, domain balancing can cause service trouble. If one component is failing the service will not work correctly unless the sessions are rebalanced.</P><P>In this case, it is best to limit the problem to the sessions handled by the failing component. This is what the <TT>domain_balancing_component_number</TT> option does, making the load balancing algorithm not dynamic, but sticky on a fix number of component instances.</P><P>The syntax is the following: </P><PRE CLASS="verbatim">{domain_balancing_component_number, "component.example.com", N} </PRE><P> <A NAME="debugging"></A> </P><!--TOC chapter Debugging--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc88">Chapter 7</A>  <A HREF="#debugging">Debugging</A></H1><!--SEC END --><P> <A NAME="debugging"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc89">Chapter 7</A>  <A HREF="#debugging">Debugging</A></H1><!--SEC END --><P> <A NAME="debugging"></A> </P><P> <A NAME="logfiles"></A> </P><!--TOC section Log Files--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc89">7.1</A>  <A HREF="#logfiles">Log Files</A></H2><!--SEC END --><P> <A NAME="logfiles"></A> </P><P>An <TT>ejabberd</TT> node writes two log files: +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc90">7.1</A>  <A HREF="#logfiles">Log Files</A></H2><!--SEC END --><P> <A NAME="logfiles"></A> </P><P>An <TT>ejabberd</TT> node writes two log files: </P><DL CLASS="description"><DT CLASS="dt-description"> <B><TT>ejabberd.log</TT></B></DT><DD CLASS="dd-description"> is the ejabberd service log, with the messages reported by <TT>ejabberd</TT> code </DD><DT CLASS="dt-description"><B><TT>sasl.log</TT></B></DT><DD CLASS="dd-description"> is the Erlang/OTP system log, with the messages reported by Erlang/OTP using SASL (System Architecture Support Libraries) @@ -3553,12 +3604,12 @@ The ejabberdctl command <TT>reopen-log</TT> (please refer to section <A HREF="#ectl-commands">4.1.1</A>) reopens the log files, and also renames the old ones if you didn’t rename them.</P><P> <A NAME="debugconsole"></A> </P><!--TOC section Debug Console--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc90">7.2</A>  <A HREF="#debugconsole">Debug Console</A></H2><!--SEC END --><P> <A NAME="debugconsole"></A> </P><P>The Debug Console is an Erlang shell attached to an already running <TT>ejabberd</TT> server. +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc91">7.2</A>  <A HREF="#debugconsole">Debug Console</A></H2><!--SEC END --><P> <A NAME="debugconsole"></A> </P><P>The Debug Console is an Erlang shell attached to an already running <TT>ejabberd</TT> server. With this Erlang shell, an experienced administrator can perform complex tasks.</P><P>This shell gives complete control over the <TT>ejabberd</TT> server, so it is important to use it with extremely care. There are some simple and safe examples in the article <A HREF="http://www.ejabberd.im/interconnect-erl-nodes">Interconnecting Erlang Nodes</A></P><P>To exit the shell, close the window or press the keys: control+c control+c.</P><P> <A NAME="watchdog"></A> </P><!--TOC section Watchdog Alerts--> -<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc91">7.3</A>  <A HREF="#watchdog">Watchdog Alerts</A></H2><!--SEC END --><P> <A NAME="watchdog"></A> +<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc92">7.3</A>  <A HREF="#watchdog">Watchdog Alerts</A></H2><!--SEC END --><P> <A NAME="watchdog"></A> </P><P><TT>ejabberd</TT> includes a watchdog mechanism that may be useful to developers when troubleshooting a problem related to memory usage. If a process in the <TT>ejabberd</TT> server consumes more memory than the configured threshold, @@ -3576,7 +3627,7 @@ or in a conversation with the watchdog alert bot.</P><P>Example configuration: To remove all watchdog admins, set the option with an empty list: </P><PRE CLASS="verbatim">{watchdog_admins, []}. </PRE><P> <A NAME="i18ni10n"></A> </P><!--TOC chapter Internationalization and Localization--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc92">Appendix A</A>  <A HREF="#i18ni10n">Internationalization and Localization</A></H1><!--SEC END --><P> <A NAME="i18ni10n"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc93">Appendix A</A>  <A HREF="#i18ni10n">Internationalization and Localization</A></H1><!--SEC END --><P> <A NAME="i18ni10n"></A> </P><P>The source code of <TT>ejabberd</TT> supports localization. The translators can edit the <A HREF="http://www.gnu.org/software/gettext/">gettext</A> .po files @@ -3611,9 +3662,9 @@ HTTP header ‘Accept-Language: ru’</TD></TR> </TABLE></DIV> <A NAME="fig:webadmmainru"></A> <DIV CLASS="center"><HR WIDTH="80%" SIZE=2></DIV></DIV></BLOCKQUOTE><P> <A NAME="releasenotes"></A> </P><!--TOC chapter Release Notes--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc93">Appendix B</A>  <A HREF="#releasenotes">Release Notes</A></H1><!--SEC END --><P> <A NAME="releasenotes"></A> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc94">Appendix B</A>  <A HREF="#releasenotes">Release Notes</A></H1><!--SEC END --><P> <A NAME="releasenotes"></A> </P><P>Release notes are available from <A HREF="http://www.process-one.net/en/ejabberd/release_notes/">ejabberd Home Page</A></P><P> <A NAME="acknowledgements"></A> </P><!--TOC chapter Acknowledgements--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc94">Appendix C</A>  <A HREF="#acknowledgements">Acknowledgements</A></H1><!--SEC END --><P> <A NAME="acknowledgements"></A> </P><P>Thanks to all people who contributed to this guide: +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc95">Appendix C</A>  <A HREF="#acknowledgements">Acknowledgements</A></H1><!--SEC END --><P> <A NAME="acknowledgements"></A> </P><P>Thanks to all people who contributed to this guide: </P><UL CLASS="itemize"><LI CLASS="li-itemize"> Alexey Shchepin (<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A>) </LI><LI CLASS="li-itemize">Badlop (<A HREF="xmpp:badlop@jabberes.org"><TT>xmpp:badlop@jabberes.org</TT></A>) @@ -3625,7 +3676,7 @@ Alexey Shchepin (<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT </LI><LI CLASS="li-itemize">Sergei Golovan (<A HREF="xmpp:sgolovan@nes.ru"><TT>xmpp:sgolovan@nes.ru</TT></A>) </LI><LI CLASS="li-itemize">Vsevolod Pelipas (<A HREF="xmpp:vsevoload@jabber.ru"><TT>xmpp:vsevoload@jabber.ru</TT></A>) </LI></UL><P> <A NAME="copyright"></A> </P><!--TOC chapter Copyright Information--> -<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc95">Appendix D</A>  <A HREF="#copyright">Copyright Information</A></H1><!--SEC END --><P> <A NAME="copyright"></A> </P><P>Ejabberd Installation and Operation Guide.<BR> +<H1 CLASS="chapter"><!--SEC ANCHOR --><A NAME="htoc96">Appendix D</A>  <A HREF="#copyright">Copyright Information</A></H1><!--SEC END --><P> <A NAME="copyright"></A> </P><P>Ejabberd Installation and Operation Guide.<BR> Copyright © 2003 — 2009 ProcessOne</P><P>This document 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 diff --git a/doc/guide.tex b/doc/guide.tex index e613106dd..7b0b46c47 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -68,6 +68,7 @@ \newcommand{\modconfigure}{\module{mod\_configure}} \newcommand{\moddisco}{\module{mod\_disco}} \newcommand{\modecho}{\module{mod\_echo}} +\newcommand{\modhttpbind}{\module{mod\_http\_bind}} \newcommand{\modhttpfileserver}{\module{mod\_http\_fileserver}} \newcommand{\modlast}{\module{mod\_last}} \newcommand{\modlastodbc}{\module{mod\_last\_odbc}} @@ -94,10 +95,13 @@ \newcommand{\modversion}{\module{mod\_version}} %% Contributed modules -\usepackage{ifthen} -\newboolean{modhttpbind} -\newcommand{\modhttpbind}{\module{mod\_http\_bind}} -\include{contributed_modules} +%\usepackage{ifthen} +%\newboolean{modhttpbind} +%\newcommand{\modhttpbind}{\module{mod\_http\_bind}} +%\include{contributed_modules} +% +% Then in the document you can input the partial tex file with: +%\ifthenelse{\boolean{modhttpbind}}{\input{mod_http_bind.tex}}{} %% Common options \newcommand{\iqdiscitem}[1]{\titem{iqdisc} \ind{options!iqdisc}This specifies @@ -2647,7 +2651,70 @@ Example: Mirror, mirror, on the wall, who is the most beautiful ]}. \end{verbatim} -\ifthenelse{\boolean{modhttpbind}}{\input{mod_http_bind.tex}}{} +\makesubsection{modhttpbind}{\modhttpbind{}} +\ind{modules!\modhttpbind{}}\ind{modhttpbind} + +This module implements XMPP over Bosh (formerly known as HTTP Binding) +as defined in \xepref{0124} and \xepref{0206}. +It extends ejabberd's built in HTTP service with a configurable +resource at which this service will be hosted. + +To use HTTP-Binding, enable the module: +\begin{verbatim} +{modules, + [ + ... + {mod_http_bind, []}, + ... +]}. +\end{verbatim} +and add \verb|http_bind| in the HTTP service. For example: +\begin{verbatim} +{listen, + [ + ... + {5280, ejabberd_http, [ + http_bind, + http_poll, + web_admin + ] + }, + ... +]}. +\end{verbatim} +With this configuration, the module will serve the requests sent to +\verb|http://example.org:5280/http-bind/| +Remember that this page is not designed to be used by web browsers, +it is used by Jabber clients that support XMPP over Bosh. + +If you want to set the service in a different URI path or use a different module, +you can configure it manually using the option \verb|request_handlers|. +For example: +\begin{verbatim} +{listen, + [ + ... + {5280, ejabberd_http, [ + {request_handlers, [{["http-bind"], mod_http_bind}]}, + http_poll, + web_admin + ] + }, + ... +]}. +\end{verbatim} + +The maximum inactivity period is by default 30 seconds. +This can be configured with the module option \term{max\_inactivity}. +For example, to set 50 seconds: +\begin{verbatim} +{modules, + [ + ... + {mod_http_bind, [ {max_inactivity, 50} ]}, + ... +]}. +\end{verbatim} \makesubsection{modhttpfileserver}{\modhttpfileserver{}} \ind{modules!\modhttpfileserver{}}\ind{modhttpfileserver} diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index 8be6b1316..a97356824 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -155,6 +155,7 @@ %% {["pub", "archive"], mod_http_fileserver}, %% ]}, captcha, + http_bind, http_poll, web_admin ]} @@ -478,6 +479,7 @@ {mod_configure,[]}, % requires mod_adhoc {mod_disco, []}, %%{mod_echo, [{host, "echo.localhost"}]}, + {mod_http_bind, []}, %%{mod_http_fileserver, [ %% {docroot, "/var/www"}, %% {accesslog, "/var/log/ejabberd/access.log"} From 13c76c12f8c0e874b4511c1e5f1dcbec8abf0fa4 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Tue, 16 Jun 2009 18:28:06 +0000 Subject: [PATCH 439/582] Workaround to compile with exmpp SVN Revision: 2324 --- src/mod_offline.erl | 2 +- src/mod_offline_odbc.erl | 2 +- src/web/ejabberd_http_bind.erl | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 8b785bd03..c2f3da232 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -127,7 +127,7 @@ loop(AccessMaxOfflineMsgs) -> %% Function copied from ejabberd_sm.erl: get_max_user_messages(AccessRule, LUser, Host) -> case acl:match_rule( - Host, AccessRule, jlib:make_jid(LUser, Host, "")) of + Host, AccessRule, exmpp_jid:make(LUser, Host, "")) of Max when is_integer(Max) -> Max; infinity -> infinity; _ -> ?MAX_USER_MESSAGES diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index 2d4cd787a..254d75bc2 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -134,7 +134,7 @@ loop(Host, AccessMaxOfflineMsgs) -> %% Function copied from ejabberd_sm.erl: get_max_user_messages(AccessRule, LUser, Host) -> case acl:match_rule( - Host, AccessRule, jlib:make_jid(LUser, Host, "")) of + Host, AccessRule, exmpp_jid:make(LUser, Host, "")) of Max when is_integer(Max) -> Max; infinity -> infinity; _ -> ?MAX_USER_MESSAGES diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 61d15943b..b2e740c48 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -52,6 +52,9 @@ -include("jlib.hrl"). -include("ejabberd_http.hrl"). +%% TODO: Use exmpp library instead of including this +-define(NS_STREAM, "http://etherx.jabber.org/streams"). + -record(http_bind, {id, pid, to, hold, wait, version}). -define(NULL_PEER, {{0, 0, 0, 0}, 0}). From bfbc69e8f9ee18f5952f1e8edb06b8a5e25222f3 Mon Sep 17 00:00:00 2001 From: Badlop <badlop@process-one.net> Date: Wed, 17 Jun 2009 09:06:52 +0000 Subject: [PATCH 440/582] Update version number to 3.0.0-alpha SVN Revision: 2326 --- doc/dev.html | 5 ++--- doc/features.html | 5 ++--- doc/guide.html | 4 ++-- doc/version.tex | 2 +- src/ejabberd.app | 2 +- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/doc/dev.html b/doc/dev.html index ff3b7e2e1..ef50b169b 100644 --- a/doc/dev.html +++ b/doc/dev.html @@ -2,7 +2,7 @@ "http://www.w3.org/TR/REC-html40/loose.dtd"> <HTML> <HEAD> -<TITLE>Ejabberd 2.1.0-alpha Developers Guide +<TITLE>Ejabberd 3.0.0-alpha Developers Guide @@ -49,7 +49,7 @@ TD P{margin:0px;}

    -

    Ejabberd 2.1.0-alpha Developers Guide

    Alexey Shchepin
    +

    Ejabberd 3.0.0-alpha Developers Guide

    Alexey Shchepin
    mailto:alexey@sevcom.net
    xmpp:aleksey@jabber.ru

    @@ -141,7 +141,6 @@ Support for virtual hosting.
  • Multi-User Chat module with support for clustering and HTML logging.
  • Users Directory based on users vCards.
  • Publish-Subscribe component with support for Personal Eventing via Pubsub.
  • Support for web clients: HTTP Polling and HTTP Binding (BOSH) services. -
  • IRC transport.
  • Component support: interface with networks such as AIM, ICQ and MSN installing special tranports.
  • diff --git a/doc/features.html b/doc/features.html index a02460bef..04487a14f 100644 --- a/doc/features.html +++ b/doc/features.html @@ -2,7 +2,7 @@ "http://www.w3.org/TR/REC-html40/loose.dtd"> -Ejabberd 2.1.0-alpha Feature Sheet +<TITLE>Ejabberd 3.0.0-alpha Feature Sheet @@ -50,7 +50,7 @@ SPAN{width:20%; float:right; text-align:left; margin-left:auto;}

    -

    - + @@ -2845,7 +2845,7 @@ by sending: </iq>

    3.3.21  mod_time

    -

    This module features support for Entity Time (XEP-0090). By using this XEP, +

    This module features support for Entity Time (XEP-0202). By using this XEP, you are able to discover the time at another entity’s location.

    Options:

    iqdisc
    This specifies diff --git a/doc/guide.tex b/doc/guide.tex index 9a00a964b..6bf2be289 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -2385,7 +2385,7 @@ The following table lists all modules included in \ejabberd{}. \hline \ahrefloc{modsharedroster}{\modsharedroster{}} & Shared roster management & \modroster{} or \\ & & \modrosterodbc\\ \hline \ahrefloc{modstats}{\modstats{}} & Statistics Gathering (\xepref{0039}) & \\ - \hline \ahrefloc{modtime}{\modtime{}} & Entity Time (\xepref{0090}) & \\ + \hline \ahrefloc{modtime}{\modtime{}} & Entity Time (\xepref{0202}) & \\ \hline \ahrefloc{modvcard}{\modvcard{}} & vcard-temp (\xepref{0054}) & \\ \hline \ahrefloc{modvcardldap}{\modvcardldap{}} & vcard-temp (\xepref{0054}) & LDAP server \\ \hline \ahrefloc{modvcard}{\modvcardodbc{}} & vcard-temp (\xepref{0054}) & supported DB (*) \\ @@ -3670,9 +3670,9 @@ in order to get the statistics. Here they are: \end{itemize} \makesubsection{modtime}{\modtime{}} -\ind{modules!\modtime{}}\ind{protocols!XEP-0090: Entity Time} +\ind{modules!\modtime{}}\ind{protocols!XEP-0202: Entity Time} -This module features support for Entity Time (\xepref{0090}). By using this XEP, +This module features support for Entity Time (\xepref{0202}). By using this XEP, you are able to discover the time at another entity's location. Options: diff --git a/src/ejd2odbc.erl b/src/ejd2odbc.erl index f46b45eba..ed1292d09 100644 --- a/src/ejd2odbc.erl +++ b/src/ejd2odbc.erl @@ -127,7 +127,14 @@ export_offline(Server, Output) -> Packet0 = exmpp_stanza:set_jids(Packet, exmpp_jid:to_list(From), exmpp_jid:to_list(To)), - Packet1 = exmpp_xml:append_child(Packet0, + Packet0b = exmpp_xml:append_child(Packet0, + jlib:timestamp_to_xml( + calendar:now_to_universal_time(TimeStamp), + utc, + exmpp_jid:make("", Server, ""), + "Offline Storage")), + %% TODO: Delete the next three lines once XEP-0091 is Obsolete + Packet1 = exmpp_xml:append_child(Packet0b, jlib:timestamp_to_xml( calendar:now_to_universal_time(TimeStamp))), XML = diff --git a/src/jlib.erl b/src/jlib.erl index cf3dc5e8d..4729cd067 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -28,8 +28,10 @@ -author('alexey@process-one.net'). -export([parse_xdata_submit/1, - timestamp_to_iso/1, - timestamp_to_xml/1, + timestamp_to_iso/1, % TODO: Remove once XEP-0091 is Obsolete + timestamp_to_iso/2, + timestamp_to_xml/4, + timestamp_to_xml/1, % TODO: Remove once XEP-0091 is Obsolete now_to_utc_string/1, now_to_local_string/1, datetime_string_to_timestamp/1, @@ -149,11 +151,38 @@ rsm_encode_count(Count, Arr)-> i2b(I) when is_integer(I) -> list_to_binary(integer_to_list(I)); i2b(L) when is_list(L) -> list_to_binary(L). +%% Timezone = utc | {Hours, Minutes} +%% Hours = integer() +%% Minutes = integer() +timestamp_to_iso({{Year, Month, Day}, {Hour, Minute, Second}}, Timezone) -> + Timestamp_string = lists:flatten( + io_lib:format("~4..0w-~2..0w-~2..0wT~2..0w:~2..0w:~2..0w", + [Year, Month, Day, Hour, Minute, Second])), + Timezone_string = case Timezone of + utc -> "Z"; + {TZh, TZm} -> + Sign = case TZh >= 0 of + true -> "+"; + false -> "-" + end, + io_lib:format("~s~2..0w:~2..0w", [Sign, abs(TZh),TZm]) + end, + {Timestamp_string, Timezone_string}. + timestamp_to_iso({{Year, Month, Day}, {Hour, Minute, Second}}) -> lists:flatten( io_lib:format("~4..0w~2..0w~2..0wT~2..0w:~2..0w:~2..0w", [Year, Month, Day, Hour, Minute, Second])). +timestamp_to_xml(DateTime, Timezone, FromJID, Desc) -> + {T_string, Tz_string} = timestamp_to_iso(DateTime, Timezone), + From = exmpp_jid:to_list(FromJID), + P1 = exmpp_xml:set_attributes(#xmlel{ns = ?NS_DELAY, name = 'delay'}, + [{'from', From}, + {'stamp', T_string ++ Tz_string}]), + exmpp_xml:set_cdata(P1, Desc). + +%% TODO: Remove this function once XEP-0091 is Obsolete timestamp_to_xml({{Year, Month, Day}, {Hour, Minute, Second}}) -> Timestamp = lists:flatten( io_lib:format("~4..0w~2..0w~2..0wT~2..0w:~2..0w:~2..0w", diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 11d029ed2..7265950b6 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -570,6 +570,7 @@ handle_event({service_message, Msg}, _StateName, StateData) -> end, ?DICT:to_list(StateData#state.users)), NSD = add_message_to_history("", + StateData#state.jid, MessagePkt, StateData), {next_state, normal_state, NSD}; @@ -810,6 +811,7 @@ process_groupchat_message(From, #xmlel{name = 'message'} = Packet, ?DICT:to_list(StateData#state.users)), NewStateData2 = add_message_to_history(FromNick, + From, Packet, NewStateData1), {next_state, normal_state, NewStateData2}; @@ -2025,11 +2027,21 @@ lqueue_to_list(#lqueue{queue = Q1}) -> queue:to_list(Q1). -add_message_to_history(FromNick, Packet, StateData) -> +add_message_to_history(FromNick, FromJID, Packet, StateData) -> HaveSubject = exmpp_xml:has_element(Packet, 'subject'), TimeStamp = calendar:now_to_universal_time(now()), - TSPacket = exmpp_xml:append_child(Packet, - jlib:timestamp_to_xml(TimeStamp)), + %% Chatroom history is stored as XMPP packets, so + %% the decision to include the original sender's JID or not is based on the + %% chatroom configuration when the message was originally sent. + %% Also, if the chatroom is anonymous, even moderators will not get the real JID + SenderJid = case ((StateData#state.config)#config.anonymous) of + true -> StateData#state.jid; + false -> FromJID + end, + TSPacket = exmpp_xml:append_children(Packet, + [jlib:timestamp_to_xml(TimeStamp, utc, SenderJid, ""), + %% TODO: Delete the next line once XEP-0091 is Obsolete + jlib:timestamp_to_xml(TimeStamp)]), SPacket = exmpp_stanza:set_recipient( exmpp_stanza:set_sender(TSPacket, jid_replace_resource(StateData#state.jid, FromNick)), diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 8085d348a..483575fa7 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -174,9 +174,9 @@ get_sm_features(Acc, _From, _To, "", _Lang) -> {result, I} -> I; _ -> [] end, - {result, Feats ++ [?NS_FEATURE_MSGOFFLINE]}; + {result, Feats ++ [?NS_MSGOFFLINE]}; -get_sm_features(_Acc, _From, _To, ?NS_FEATURE_MSGOFFLINE, _Lang) -> +get_sm_features(_Acc, _From, _To, ?NS_MSGOFFLINE, _Lang) -> %% override all lesser features... {result, []}; @@ -286,10 +286,19 @@ resend_offline_messages(User, Server) -> {route, R#offline_msg.from, R#offline_msg.to, - exmpp_xml:append_child(Packet, - jlib:timestamp_to_xml( - calendar:now_to_universal_time( - R#offline_msg.timestamp)))} + exmpp_xml:append_children( + Packet, + [jlib:timestamp_to_xml( + calendar:now_to_universal_time(R#offline_msg.timestamp), + utc, + exmpp_jid:make("", Server, ""), + "Offline Storage"), + %% TODO: Delete the next three lines once XEP-0091 is Obsolete + jlib:timestamp_to_xml( + calendar:now_to_universal_time( + R#offline_msg.timestamp)) + ] + )} end, lists:keysort(#offline_msg.timestamp, Rs)); _ -> @@ -320,10 +329,19 @@ pop_offline_messages(Ls, User, Server) {route, R#offline_msg.from, R#offline_msg.to, - exmpp_xml:append_child(Packet, - jlib:timestamp_to_xml( - calendar:now_to_universal_time( - R#offline_msg.timestamp)))} + exmpp_xml:append_children( + Packet, + [jlib:timestamp_to_xml( + calendar:now_to_universal_time( + R#offline_msg.timestamp), + utc, + exmpp_jid:make("", Server, ""), + "Offline Storage"), + %% TODO: Delete the next three lines once XEP-0091 is Obsolete + jlib:timestamp_to_xml( + calendar:now_to_universal_time( + R#offline_msg.timestamp))] + )} end, lists:filter( fun(R) -> diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index 92de5548a..62e60ac26 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -113,10 +113,18 @@ loop(Host, AccessMaxOfflineMsgs) -> M#offline_msg.packet, From, To), - Packet1 = exmpp_xml:append_child(Packet0, - jlib:timestamp_to_xml( - calendar:now_to_universal_time( - M#offline_msg.timestamp))), + Packet1 = exmpp_xml:append_children( + Packet0, + [jlib:timestamp_to_xml( + calendar:now_to_universal_time( + M#offline_msg.timestamp), + utc, + jlib:make_jid("", Host, ""), + "Offline Storage"), + %% TODO: Delete the next three lines once XEP-0091 is Obsolete + jlib:timestamp_to_xml( + calendar:now_to_universal_time( + M#offline_msg.timestamp))]), XML = ejabberd_odbc:escape( exmpp_xml:document_to_list(Packet1)), @@ -181,9 +189,9 @@ get_sm_features(Acc, _From, _To, "", _Lang) -> {result, I} -> I; _ -> [] end, - {result, Feats ++ [?NS_FEATURE_MSGOFFLINE]}; + {result, Feats ++ [?NS_MSGOFFLINE]}; -get_sm_features(_Acc, _From, _To, ?NS_FEATURE_MSGOFFLINE, _Lang) -> +get_sm_features(_Acc, _From, _To, ?NS_MSGOFFLINE, _Lang) -> %% override all lesser features... {result, []}; diff --git a/src/mod_time.erl b/src/mod_time.erl index 4e12ac528..84efda45e 100644 --- a/src/mod_time.erl +++ b/src/mod_time.erl @@ -31,6 +31,7 @@ -export([start/2, stop/1, + process_local_iq90/3, % TODO: Remove once XEP-0090 is Obsolete process_local_iq/3]). -include_lib("exmpp/include/exmpp.hrl"). @@ -40,21 +41,45 @@ start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), + %% TODO: Remove the next two lines once XEP-0090 is Obsolete + gen_iq_handler:add_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_TIME_OLD, + ?MODULE, process_local_iq90, IQDisc), gen_iq_handler:add_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_TIME, ?MODULE, process_local_iq, IQDisc). stop(Host) -> + %% TODO: Remove the next two lines once XEP-0090 is Obsolete + gen_iq_handler:remove_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_TIME_OLD), gen_iq_handler:remove_iq_handler(ejabberd_local, list_to_binary(Host), ?NS_TIME). process_local_iq(_From, _To, #iq{type = get} = IQ_Rec) -> - UTC = jlib:timestamp_to_iso(calendar:universal_time()), - Result = #xmlel{ns = ?NS_TIME, name = 'query', children = [ - #xmlel{ns = ?NS_TIME, name = 'utc', children = [ - #xmlcdata{cdata = list_to_binary(UTC)} - ]} + Now = now(), + Now_universal = calendar:now_to_universal_time(Now), + Now_local = calendar:now_to_local_time(Now), + {UTC, UTC_diff} = jlib:timestamp_to_iso(Now_universal, utc), + Seconds_diff = calendar:datetime_to_gregorian_seconds(Now_local) + - calendar:datetime_to_gregorian_seconds(Now_universal), + {Hd, Md, _} = calendar:seconds_to_time(Seconds_diff), + {_, TZO_diff} = jlib:timestamp_to_iso({{0, 0, 0}, {0, 0, 0}}, {Hd, Md}), + Result = #xmlel{ns = ?NS_TIME, name = 'time', children = [ + #xmlel{ns = ?NS_TIME, name = 'tzo', children = [ + #xmlcdata{cdata = list_to_binary(TZO_diff)}]}, + #xmlel{ns = ?NS_TIME, name = 'utc', children = [ + #xmlcdata{cdata = list_to_binary(UTC ++ UTC_diff)}]} ]}, exmpp_iq:result(IQ_Rec, Result); process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) -> exmpp_iq:error(IQ_Rec, 'not-allowed'). - +%% TODO: Remove this function once XEP-0090 is Obsolete +process_local_iq90(_From, _To, #iq{type = get} = IQ_Rec) -> + UTC = jlib:timestamp_to_iso(calendar:universal_time()), + Result = #xmlel{ns = ?NS_TIME_OLD, name = 'query', + children = [#xmlel{ns = ?NS_TIME_OLD, name = 'utc', + children=[#xmlcdata{cdata = + list_to_binary(UTC)} + ]} + ]}, + exmpp_iq:result(IQ_Rec, Result); +process_local_iq90(_From, _To, #iq{type = set} = IQ_Rec) -> + exmpp_iq:error(IQ_Rec, 'not-allowed'). From f82131af15ec20826e3f4190e73d8e6443e946f6 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 30 Jun 2009 17:51:37 +0000 Subject: [PATCH 451/582] Include original timestamp on delayed presences (thanks to Mickael Remond)(EJAB-234) SVN Revision: 2349 --- src/ejabberd_c2s.erl | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 744a24933..a3af8205a 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1359,7 +1359,13 @@ process_presence_probe(From, To, StateData) -> andalso ?SETS:is_element(LFrom, StateData#state.pres_a), if Cond1 -> - Packet = StateData#state.pres_last, + Timestamp = StateData#state.pres_timestamp, + Packet = exmpp_xml:append_children( + StateData#state.pres_last, + %% To is the one sending the presence (the target of the probe) + [jlib:timestamp_to_xml(Timestamp, utc, To, ""), + %% TODO: Delete the next line once XEP-0091 is Obsolete + jlib:timestamp_to_xml(Timestamp)]), case ejabberd_hooks:run_fold( privacy_check_packet, StateData#state.server, allow, @@ -1406,6 +1412,7 @@ presence_update(From, Packet, StateData) -> presence_broadcast(StateData, From, StateData#state.pres_a, Packet), presence_broadcast(StateData, From, StateData#state.pres_i, Packet), StateData#state{pres_last = undefined, + pres_timestamp = undefined, pres_a = ?SETS:new(), pres_i = ?SETS:new(), pres_invis = false}; @@ -1426,6 +1433,7 @@ presence_update(From, Packet, StateData) -> StateData#state.pres_i, Packet), S1 = StateData#state{pres_last = undefined, + pres_timestamp = undefined, pres_a = ?SETS:new(), pres_i = ?SETS:new(), pres_invis = true}, @@ -1462,6 +1470,7 @@ presence_update(From, Packet, StateData) -> catch _Exception1 -> 0 end, + Timestamp = calendar:now_to_universal_time(now()), update_priority(NewPriority, Packet, StateData), FromUnavail = (StateData#state.pres_last == undefined) or StateData#state.pres_invis, @@ -1480,7 +1489,8 @@ presence_update(From, Packet, StateData) -> end, presence_broadcast_first( From, StateData#state{pres_last = Packet, - pres_invis = false + pres_invis = false, + pres_timestamp = Timestamp }, Packet); true -> presence_broadcast_to_trusted(StateData, @@ -1494,7 +1504,8 @@ presence_update(From, Packet, StateData) -> ok end, StateData#state{pres_last = Packet, - pres_invis = false + pres_invis = false, + pres_timestamp = Timestamp } end, NewState From 0e19ca68b4efb4d218ef0ec9b48cfb46d8378df1 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 30 Jun 2009 19:33:09 +0000 Subject: [PATCH 452/582] Support XEP-0085 Chat State Notifications (EJAB-961) SVN Revision: 2351 --- src/mod_offline.erl | 37 ++++++++++++++++++++++---------- src/mod_offline_odbc.erl | 46 +++++++++++++++++++++++++++------------- 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 483575fa7..f0a8cef59 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -189,7 +189,7 @@ store_packet(From, To, Packet) -> if (Type /= <<"error">>) and (Type /= <<"groupchat">>) and (Type /= <<"headline">>) -> - case check_event(From, To, Packet) of + case check_event_chatstates(From, To, Packet) of true -> LUser = exmpp_jid:prep_node_as_list(To), LServer = exmpp_jid:prep_domain_as_list(To), @@ -210,11 +210,21 @@ store_packet(From, To, Packet) -> ok end. -check_event(From, To, Packet) -> - case find_x_event(Packet#xmlel.children) of - false -> +%% Check if the packet has any content about XEP-0022 or XEP-0085 +check_event_chatstates(From, To, Packet) -> + case find_x_event_chatstates(Packet#xmlel.children, {false, false, false}) of + %% There wasn't any x:event or chatstates subelements + {false, false, _} -> true; - El -> + %% There a chatstates subelement and other stuff, but no x:event + {false, CEl, true} when CEl /= false -> + true; + %% There was only a subelement: a chatstates + {false, CEl, false} when CEl /= false -> + %% Don't allow offline storage + false; + %% There was an x:event element, and maybe also other stuff + {El, _, _} when El /= false-> case exmpp_xml:get_element(El, 'id') of undefined -> case exmpp_xml:get_element(El, 'offline') of @@ -240,12 +250,17 @@ check_event(From, To, Packet) -> end end. -find_x_event([]) -> - false; -find_x_event([#xmlel{ns = ?NS_MESSAGE_EVENT} = El | _Els]) -> - El; -find_x_event([_ | Els]) -> - find_x_event(Els). +%% Check if the packet has subelements about XEP-0022, XEP-0085 or other +find_x_event_chatstates([], Res) -> + Res; +find_x_event_chatstates([#xmlel{ns = ?NS_MESSAGE_EVENT} = El | Els], {_, B, C}) -> + find_x_event_chatstates(Els, {El, B, C}); +find_x_event_chatstates([#xmlel{ns = ?NS_CHATSTATES} = El | Els], {A, _, C}) -> + find_x_event_chatstates(Els, {A, El, C}); +find_x_event_chatstates([#xmlcdata{} = _ | Els], {A, B, C}) -> + find_x_event_chatstates(Els, {A, B, C}); +find_x_event_chatstates([_ | Els], {A, B, _}) -> + find_x_event_chatstates(Els, {A, B, true}). find_x_expire(_, []) -> never; diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index 62e60ac26..abab042df 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -204,7 +204,7 @@ store_packet(From, To, Packet) -> if (Type /= <<"error">>) and (Type /= <<"groupchat">>) and (Type /= <<"headline">>) -> - case check_event(From, To, Packet) of + case check_event_chatstates(From, To, Packet) of true -> LUser = exmpp_jid:prep_node_as_list(To), TimeStamp = now(), @@ -224,41 +224,57 @@ store_packet(From, To, Packet) -> ok end. -check_event(From, To, Packet) -> - case find_x_event(Packet#xmlel.children) of - false -> +%% Check if the packet has any content about XEP-0022 or XEP-0085 +check_event_chatstates(From, To, Packet) -> + case find_x_event_chatstates(Packet#xmlel.children, {false, false, false}) of + %% There wasn't any x:event or chatstates subelements + {false, false, _} -> true; - El -> + %% There a chatstates subelement and other stuff, but no x:event + {false, CEl, true} when CEl /= false -> + true; + %% There was only a subelement: a chatstates + {false, CEl, false} when CEl /= false -> + %% Don't allow offline storage + false; + %% There was an x:event element, and maybe also other stuff + {El, _, _} when El /= false-> case exmpp_xml:get_element(El, 'id') of undefined -> case exmpp_xml:get_element(El, 'offline') of undefined -> true; _ -> - ID = case exmpp_xml:get_attribute_as_list(Packet, 'id', "") of - "" -> + ID = case exmpp_stanza:get_id(Packet) of + undefined -> #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'id'}; S -> #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'id', - children = [#xmlcdata{cdata = list_to_binary(S)}]} + children = [#xmlcdata{cdata = + S}]} end, X = #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'x', children = [ID, #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'offline'}]}, ejabberd_router:route( To, From, exmpp_xml:set_children(Packet, [X])), true - end; + end; _ -> false end end. -find_x_event([]) -> - false; -find_x_event([#xmlel{ns = ?NS_MESSAGE_EVENT} = El | _Els]) -> - El; -find_x_event([_ | Els]) -> - find_x_event(Els). +%% Check if the packet has subelements about XEP-0022, XEP-0085 or other +find_x_event_chatstates([], Res) -> + Res; +find_x_event_chatstates([#xmlel{ns = ?NS_MESSAGE_EVENT} = El | Els], {_, B, C}) -> + find_x_event_chatstates(Els, {El, B, C}); +find_x_event_chatstates([#xmlel{ns = ?NS_CHATSTATES} = El | Els], {A, _, C}) -> + find_x_event_chatstates(Els, {A, El, C}); +find_x_event_chatstates([#xmlcdata{} = _ | Els], {A, B, C}) -> + find_x_event_chatstates(Els, {A, B, C}); +find_x_event_chatstates([_ | Els], {A, B, _}) -> + find_x_event_chatstates(Els, {A, B, true}). find_x_expire(_, []) -> never; From 30697ca0a1503b942d6f1b7c3004b6752424089e Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 6 Jul 2009 14:11:31 +0000 Subject: [PATCH 453/582] Add -hidden flag when calling Debug or Ctl SVN Revision: 2356 --- doc/guide.tex | 4 ++++ src/ejabberdctl.template | 2 ++ tools/ejabberdctl | 2 ++ 3 files changed, 8 insertions(+) diff --git a/doc/guide.tex b/doc/guide.tex index 6bf2be289..0ef8e39ae 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -4111,6 +4111,10 @@ The command line parameters: Maximum number of Erlang processes. \titem{-remsh ejabberd@localhost} Open an Erlang shell in a remote Erlang node. + \titem{-hidden} + The connections to other nodes are hidden (not published). + The result is that this node is not considered part of the cluster. + This is important when starting a temporary \term{ctl} or \term{debug} node. \end{description} Note that some characters need to be escaped when used in shell scripts, for instance \verb|"| and \verb|{}|. You can find other options in the Erlang manual page (\shell{erl -man erl}). diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template index 5ed63b70e..71634d87f 100644 --- a/src/ejabberdctl.template +++ b/src/ejabberdctl.template @@ -164,6 +164,7 @@ debug () $EXEC_CMD "$ERL \ $NAME ${NODE}debug \ -remsh $ERLANG_NODE \ + -hidden \ $ERLANG_OPTS $ARGS \"$@\"" } @@ -218,6 +219,7 @@ ctl () $EXEC_CMD "$ERL \ $NAME ejabberdctl \ -noinput \ + -hidden \ -pa $EJABBERD_EBIN_PATH \ -s ejabberd_ctl -extra $ERLANG_NODE $COMMAND" result=$? diff --git a/tools/ejabberdctl b/tools/ejabberdctl index c821e8081..f084059a4 100755 --- a/tools/ejabberdctl +++ b/tools/ejabberdctl @@ -39,6 +39,7 @@ function debug -sname debug$NODE@$HOST \ -pa $EJABBERD_EBIN \ -mnesia dir "\"$EJABBERD_DB\"" \ + -hidden \ -remsh $NODE@$HOST } @@ -48,6 +49,7 @@ function ctl -noinput \ -sname ejabberdctl@$HOST \ -pa $EJABBERD_EBIN \ + -hidden \ -s ejabberd_ctl -extra $NODE@$HOST $@ } From be5b35e999c6cfae3826afe342bbc635c9a25d55 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 6 Jul 2009 14:11:35 +0000 Subject: [PATCH 454/582] Temporary Debug and Ctl nodes must get nodename similar to destination. SVN Revision: 2357 --- src/ejabberdctl.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template index 71634d87f..eb85ce266 100644 --- a/src/ejabberdctl.template +++ b/src/ejabberdctl.template @@ -162,7 +162,7 @@ debug () read foo echo "" $EXEC_CMD "$ERL \ - $NAME ${NODE}debug \ + $NAME debug-${ERLANG_NODE} \ -remsh $ERLANG_NODE \ -hidden \ $ERLANG_OPTS $ARGS \"$@\"" @@ -217,7 +217,7 @@ ctl () { COMMAND=$@ $EXEC_CMD "$ERL \ - $NAME ejabberdctl \ + $NAME ctl-${ERLANG_NODE} \ -noinput \ -hidden \ -pa $EJABBERD_EBIN_PATH \ From b49a15efebca5f9b69047d0f6d3ee60a550c9bce Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 7 Jul 2009 08:27:58 +0000 Subject: [PATCH 455/582] If directory /sbin is created, set permissions 755, not 750. SVN Revision: 2359 --- src/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.in b/src/Makefile.in index 24b12e301..cc9780918 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -183,7 +183,7 @@ install: all install -b -m 644 $(G_USER) inetrc $(ETCDIR)/inetrc # # Administration script - [ -d $(SBINDIR) ] || install -d -m 750 $(SBINDIR) + [ -d $(SBINDIR) ] || install -d -m 755 $(SBINDIR) install -m 550 $(G_USER) ejabberdctl.example $(SBINDIR)/ejabberdctl # # Binary Erlang files From f3db058fef54cd34cf68b74c6f6d11f3180aa54a Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 16 Jul 2009 20:18:36 +0000 Subject: [PATCH 456/582] If a command is already defined: log as Debug, not as Warning. SVN Revision: 2363 --- src/ejabberd_commands.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl index 67096fb9d..3eb5cae27 100644 --- a/src/ejabberd_commands.erl +++ b/src/ejabberd_commands.erl @@ -238,7 +238,7 @@ register_commands(Commands) -> true -> ok; false -> - ?WARNING_MSG("This command is already defined:~n~p", [Command]) + ?DEBUG("This command is already defined:~n~p", [Command]) end end, Commands). From 8d988d1bd237bc3942d203ba9df4465a3d52375e Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 17 Jul 2009 19:06:42 +0000 Subject: [PATCH 457/582] Store account number in internal auth of (EJAB-981)(thanks to Juan Pablo Carlino) SVN Revision: 2366 --- src/ejabberd_auth_internal.erl | 65 +++++++++++++++++++++++++++++++--- src/ejabberd_sm.erl | 51 +++++++++++++++++++++++++- 2 files changed, 111 insertions(+), 5 deletions(-) diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl index 74aa82c7c..61c57d7e7 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_internal.erl @@ -49,6 +49,7 @@ -include("ejabberd.hrl"). -record(passwd, {us, password}). +-record(reg_users_counter, {vhost, count}). %%%---------------------------------------------------------------------- %%% API @@ -57,12 +58,22 @@ %% @spec (Host) -> ok %% Host = string() -start(_Host) -> +start(Host) -> mnesia:create_table(passwd, [{disc_copies, [node()]}, {attributes, record_info(fields, passwd)}]), + mnesia:create_table(reg_users_counter, + [{ram_copies, [node()]}, + {attributes, record_info(fields, reg_users_counter)}]), update_table(), + update_reg_users_counter_table(Host), ok. +update_reg_users_counter_table(Server) -> + Set = get_vh_registered_users(Server), + Size = length(Set), + LServer = exmpp_jid:prep_domain(exmpp_jid:parse(Server)), + set_vh_registered_users_counter(LServer, Size). + %% @spec () -> bool() plain_password_required() -> @@ -151,6 +162,7 @@ try_register(User, Server, Password) -> [] -> mnesia:write(#passwd{us = US, password = Password}), + inc_vh_registered_users_counter(LServer), ok; [_E] -> exists @@ -249,8 +261,17 @@ get_vh_registered_users(Server, _) -> %% Users_Number = integer() get_vh_registered_users_number(Server) -> - Set = get_vh_registered_users(Server), - length(Set). + LServer = exmpp_jid:prep_domain(exmpp_jid:parse(Server)), + Query = mnesia:dirty_select( + reg_users_counter, + [{#reg_users_counter{vhost = LServer, count = '$1'}, + [], + ['$1']}]), + case Query of + [Count] -> + Count; + _ -> 0 + end. %% @spec (Server, [{prefix, Prefix}]) -> Users_Number %% Server = string() @@ -264,6 +285,40 @@ get_vh_registered_users_number(Server, [{prefix, Prefix}]) when is_list(Prefix) get_vh_registered_users_number(Server, _) -> get_vh_registered_users_number(Server). +inc_vh_registered_users_counter(LServer) -> + F = fun() -> + case mnesia:wread({reg_users_counter, LServer}) of + [C] -> + Count = C#reg_users_counter.count + 1, + C2 = C#reg_users_counter{count = Count}, + mnesia:write(C2); + _ -> + mnesia:write(#reg_users_counter{vhost = LServer, + count = 1}) + end + end, + mnesia:sync_dirty(F). + +dec_vh_registered_users_counter(LServer) -> + F = fun() -> + case mnesia:wread({reg_users_counter, LServer}) of + [C] -> + Count = C#reg_users_counter.count - 1, + C2 = C#reg_users_counter{count = Count}, + mnesia:write(C2); + _ -> + error + end + end, + mnesia:sync_dirty(F). + +set_vh_registered_users_counter(LServer, Count) -> + F = fun() -> + mnesia:write(#reg_users_counter{vhost = LServer, + count = Count}) + end, + mnesia:sync_dirty(F). + %% @spec (User, Server) -> Password | false %% User = string() %% Server = string() @@ -341,7 +396,8 @@ remove_user(User, Server) -> LServer = exmpp_stringprep:nameprep(Server), US = {LUser, LServer}, F = fun() -> - mnesia:delete({passwd, US}) + mnesia:delete({passwd, US}), + dec_vh_registered_users_counter(LServer) end, mnesia:transaction(F), ok @@ -365,6 +421,7 @@ remove_user(User, Server, Password) -> case mnesia:read({passwd, US}) of [#passwd{password = Password}] -> mnesia:delete({passwd, US}), + dec_vh_registered_users_counter(LServer), ok; [_] -> not_allowed; diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 511f7ec5e..009d32bd7 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -43,6 +43,7 @@ dirty_get_sessions_list/0, dirty_get_my_sessions_list/0, get_vh_session_list/1, + get_vh_session_number/1, register_iq_handler/4, register_iq_handler/5, unregister_iq_handler/2, @@ -65,6 +66,7 @@ -include("mod_privacy.hrl"). -record(session, {sid, usr, us, priority, info}). +-record(session_counter, {vhost, count}). -record(state, {}). %% default value for the maximum number of user connections @@ -111,6 +113,7 @@ route(From, To, Packet) -> open_session(SID, JID, Info) when ?IS_JID(JID) -> set_session(SID, JID, undefined, Info), + inc_session_counter(exmpp_jid:domain(JID)), check_for_sessions_to_replace(JID), ejabberd_hooks:run(sm_register_connection_hook, exmpp_jid:prep_domain(JID), [SID, JID, Info]). @@ -121,7 +124,8 @@ close_session(SID, JID ) when ?IS_JID(JID)-> [#session{info=I}] -> I end, F = fun() -> - mnesia:delete({session, SID}) + mnesia:delete({session, SID}), + dec_session_counter(exmpp_jid:domain(JID)) end, mnesia:sync_dirty(F), ejabberd_hooks:run(sm_remove_connection_hook, exmpp_jid:prep_domain(JID), @@ -249,6 +253,19 @@ get_vh_session_list(Server) when is_binary(Server) -> [{'==', {element, 2, '$1'}, LServer}], ['$1']}]). +get_vh_session_number(Server) -> + LServer = exmpp_jid:prep_domain(exmpp_jid:parse(Server)), + Query = mnesia:dirty_select( + session_counter, + [{#session_counter{vhost = LServer, count = '$1'}, + [], + ['$1']}]), + case Query of + [Count] -> + Count; + _ -> 0 + end. + register_iq_handler(Host, XMLNS, Module, Fun) -> ejabberd_sm ! {register_iq_handler, Host, XMLNS, Module, Fun}. @@ -275,6 +292,9 @@ init([]) -> mnesia:create_table(session, [{ram_copies, [node()]}, {attributes, record_info(fields, session)}]), + mnesia:create_table(session_counter, + [{ram_copies, [node()]}, + {attributes, record_info(fields, session_counter)}]), mnesia:add_table_index(session, usr), mnesia:add_table_index(session, us), mnesia:add_table_copy(session, node(), ram_copies), @@ -406,6 +426,8 @@ clean_table_from_bad_node(Node) -> [{'==', {node, '$1'}, Node}], ['$_']}]), lists:foreach(fun(E) -> + {_, LServer} = E#session.us, + dec_session_counter(LServer), mnesia:delete({session, E#session.sid}) end, Es) end, @@ -684,6 +706,33 @@ get_max_user_sessions(JID) -> _ -> ?MAX_USER_SESSIONS end. +inc_session_counter(LServer) -> + F = fun() -> + case mnesia:wread({session_counter, LServer}) of + [C] -> + Count = C#session_counter.count + 1, + C2 = C#session_counter{count = Count}, + mnesia:write(C2); + _ -> + mnesia:write(#session_counter{vhost = LServer, + count = 1}) + end + end, + mnesia:sync_dirty(F). + +dec_session_counter(LServer) -> + F = fun() -> + case mnesia:wread({session_counter, LServer}) of + [C] -> + Count = C#session_counter.count - 1, + C2 = C#session_counter{count = Count}, + mnesia:write(C2); + _ -> + error + end + end, + mnesia:sync_dirty(F). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% From 5e05ad03bbce627361a30081eee8909eec0bedca Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 17 Jul 2009 20:47:40 +0000 Subject: [PATCH 458/582] Support XEP-0157: Contact Addresses for XMPP Services (EJAB-235) SVN Revision: 2369 --- doc/guide.html | 39 +++++++++++++- doc/guide.tex | 38 ++++++++++++-- src/mod_disco.erl | 68 ++++++++++++++++++++++++- src/mod_muc/mod_muc.erl | 7 ++- src/mod_proxy65/mod_proxy65_service.erl | 8 ++- src/mod_pubsub/mod_pubsub.erl | 6 ++- src/mod_vcard.erl | 6 ++- src/mod_vcard_ldap.erl | 7 ++- src/mod_vcard_odbc.erl | 6 ++- 9 files changed, 170 insertions(+), 15 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index d40ff02b9..a11d78baf 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -1949,6 +1949,7 @@ disabled for instances of ejabberd with hundreds of thousands users.

    This module adds support for Service Discovery (XEP-0030). With this module enabled, services on your server can be discovered by Jabber clients. Note that ejabberd has no modules with support @@ -1960,8 +1961,16 @@ the services you offer.

    Options: iqdisc

    This specifies the processing discipline for Service Discovery (http://jabber.org/protocol/disco#items and http://jabber.org/protocol/disco#info) IQ queries (see section 3.3.2). -
    extra_domains
    With this option, -extra domains can be added to the Service Discovery item list. +
    {extra_domains, [ Domain ]}
    With this option, +you can specify a list of extra domains that are added to the Service Discovery item list. +
    {server_info, [ {Modules, Field, [Value]} ]}
    +Specify additional information about the server, +as described in Contact Addresses for XMPP Services (XEP-0157). +Modules can be the keyword ‘all’, +in which case the information is reported in all the services; +or a list of ejabberd modules, +in which case the information is only specified for the services provided by those modules. +Any arbitrary Field and Value can be specified, not only contact addresses.

    Examples:

    • To serve a link to the Jabber User Directory on jabber.org: @@ -1987,6 +1996,28 @@ To serve a link to the Jabber User Directory on jabber.org: "example.com"]}]}, ... ]}. +
    • With this configuration, all services show abuse addresses, +feedback address on the main server, +and admin addresses for both the main server and the vJUD service: +
      {modules,
      + [
      +  ...
      +  {mod_disco, [{server_info, [
      +      {all,
      +       "abuse-addresses",
      +       ["mailto:abuse@shakespeare.lit"]},
      +      {[mod_muc],
      +       "Web chatroom logs",
      +       ["http://www.example.org/muc-logs"]},
      +      {[mod_disco],
      +       "feedback-addresses",
      +       ["http://shakespeare.lit/feedback.php", "mailto:feedback@shakespeare.lit", "xmpp:feedback@shakespeare.lit"]},
      +      {[mod_disco, mod_vcard],
      +       "admin-addresses",
      +       ["mailto:xmpp@shakespeare.lit", "xmpp:admins@shakespeare.lit"]}
      +  ]}]},
      +  ...
      + ]}.
       

    3.3.5  mod_echo

    This module simply echoes any Jabber @@ -3206,6 +3237,10 @@ Starts the Erlang system detached from the system console. Maximum number of Erlang processes.

    -remsh ejabberd@localhost
    Open an Erlang shell in a remote Erlang node. +
    -hidden
    + The connections to other nodes are hidden (not published). + The result is that this node is not considered part of the cluster. + This is important when starting a temporary ctl or debug node.

    Note that some characters need to be escaped when used in shell scripts, for instance " and {}. You can find other options in the Erlang manual page (erl -man erl).

    diff --git a/doc/guide.tex b/doc/guide.tex index 0ef8e39ae..03f08067e 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -2587,6 +2587,7 @@ disabled for instances of \ejabberd{} with hundreds of thousands users. \ind{protocols!XEP-0030: Service Discovery} \ind{protocols!XEP-0011: Jabber Browsing} \ind{protocols!XEP-0094: Agent Information} +\ind{protocols!XEP-0157: Contact Addresses for XMPP Services} This module adds support for Service Discovery (\xepref{0030}). With this module enabled, services on your server can be discovered by @@ -2600,8 +2601,16 @@ Options: \begin{description} \iqdiscitem{Service Discovery (\ns{http://jabber.org/protocol/disco\#items} and \ns{http://jabber.org/protocol/disco\#info})} -\titem{extra\_domains} \ind{options!extra\_domains}With this option, - extra domains can be added to the Service Discovery item list. +\titem{\{extra\_domains, [ Domain ]\}} \ind{options!extra\_domains}With this option, + you can specify a list of extra domains that are added to the Service Discovery item list. +\titem{\{server\_info, [ \{Modules, Field, [Value]\} ]\}} \ind{options!server\_info} + Specify additional information about the server, + as described in Contact Addresses for XMPP Services (\xepref{0157}). + \term{Modules} can be the keyword `all', + in which case the information is reported in all the services; + or a list of \ejabberd{} modules, + in which case the information is only specified for the services provided by those modules. + Any arbitrary \term{Field} and \term{Value} can be specified, not only contact addresses. \end{description} Examples: @@ -2635,9 +2644,32 @@ Examples: ... ]}. \end{verbatim} +\item With this configuration, all services show abuse addresses, +feedback address on the main server, +and admin addresses for both the main server and the vJUD service: +\begin{verbatim} +{modules, + [ + ... + {mod_disco, [{server_info, [ + {all, + "abuse-addresses", + ["mailto:abuse@shakespeare.lit"]}, + {[mod_muc], + "Web chatroom logs", + ["http://www.example.org/muc-logs"]}, + {[mod_disco], + "feedback-addresses", + ["http://shakespeare.lit/feedback.php", "mailto:feedback@shakespeare.lit", "xmpp:feedback@shakespeare.lit"]}, + {[mod_disco, mod_vcard], + "admin-addresses", + ["mailto:xmpp@shakespeare.lit", "xmpp:admins@shakespeare.lit"]} + ]}]}, + ... + ]}. +\end{verbatim} \end{itemize} - \makesubsection{modecho}{\modecho{}} \ind{modules!\modecho{}}\ind{debugging} diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 60c7a26b0..1c4f1cbe4 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -41,6 +41,7 @@ get_sm_identity/5, get_sm_features/5, get_sm_items/5, + get_info/5, register_feature/2, unregister_feature/2, register_extra_domain/2, @@ -82,6 +83,7 @@ start(Host, Opts) -> ejabberd_hooks:add(disco_sm_items, HostB, ?MODULE, get_sm_items, 100), ejabberd_hooks:add(disco_sm_features, HostB, ?MODULE, get_sm_features, 100), ejabberd_hooks:add(disco_sm_identity, HostB, ?MODULE, get_sm_identity, 100), + ejabberd_hooks:add(disco_info, HostB, ?MODULE, get_info, 100), ok. stop(Host) -> @@ -92,6 +94,7 @@ stop(Host) -> ejabberd_hooks:delete(disco_local_identity, HostB, ?MODULE, get_local_identity, 100), ejabberd_hooks:delete(disco_local_features, HostB, ?MODULE, get_local_features, 100), ejabberd_hooks:delete(disco_local_items, HostB, ?MODULE, get_local_services, 100), + ejabberd_hooks:delete(disco_info, HostB, ?MODULE, get_info, 100), gen_iq_handler:remove_iq_handler(ejabberd_local, HostB, ?NS_DISCO_ITEMS), gen_iq_handler:remove_iq_handler(ejabberd_local, HostB, ?NS_DISCO_INFO), gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_DISCO_ITEMS), @@ -143,10 +146,14 @@ process_local_iq_items(_From, _To, #iq{type = set} = IQ_Rec) -> process_local_iq_info(From, To, #iq{type = get, payload = SubEl, lang = Lang} = IQ_Rec) -> Node = exmpp_xml:get_attribute_as_binary(SubEl, 'node', <<>>), + HostB = exmpp_jid:prep_domain(To), Identity = ejabberd_hooks:run_fold(disco_local_identity, - exmpp_jid:prep_domain(To), + HostB, [], [From, To, Node, Lang]), + Host = exmpp_jid:prep_domain_as_list(To), + Info = ejabberd_hooks:run_fold(disco_info, HostB, [], + [Host, ?MODULE, Node, Lang]), case ejabberd_hooks:run_fold(disco_local_features, exmpp_jid:prep_domain(To), empty, @@ -158,7 +165,7 @@ process_local_iq_info(From, To, #iq{type = get, payload = SubEl, end, Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', attrs = ANode, - children = Identity ++ lists:map(fun feature_to_xml/1, + children = Identity ++ Info ++ lists:map(fun feature_to_xml/1, Features)}, exmpp_iq:result(IQ_Rec, Result); {error, Error} -> @@ -369,3 +376,60 @@ get_user_resources(JID) -> ?XMLATTR('name', exmpp_jid:prep_node(JID)) ]} end, lists:sort(Rs)). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%% Support for: XEP-0157 Contact Addresses for XMPP Services + +get_info(Acc, Host, Module, Node, _Lang) when Node == <<>> -> + Serverinfo_fields = get_fields_xml(Host, Module), + CData1 = #xmlcdata{cdata = list_to_binary(?NS_SERVERINFO_s)}, + Value1 = #xmlel{name = 'value', children = [CData1]}, + Field1 = #xmlel{name = 'field', + attrs = [?XMLATTR('type', <<"hidden">>), + ?XMLATTR('var', <<"FORM_TYPE">>)], + children = [Value1] + }, + X = #xmlel{name = 'x', + ns = ?NS_DATA_FORMS, + attrs = [?XMLATTR('type', <<"result">>)], + children = [Field1 | Serverinfo_fields] + }, + [X | Acc]; + +get_info(_, _, _, _Node, _) -> + []. + +get_fields_xml(Host, Module) -> + Fields = gen_mod:get_module_opt(Host, ?MODULE, server_info, []), + + %% filter, and get only the ones allowed for this module + Fields_good = lists:filter( + fun({Modules, _, _}) -> + case Modules of + all -> true; + Modules -> lists:member(Module, Modules) + end + end, + Fields), + + fields_to_xml(Fields_good). + +fields_to_xml(Fields) -> + [ field_to_xml(Field) || Field <- Fields]. + +field_to_xml({_, Var, Values}) -> + Values_xml = values_to_xml(Values), + #xmlel{name = 'field', + attrs = [?XMLATTR('var', list_to_binary(Var))], + children = Values_xml + }. + +values_to_xml(Values) -> + lists:map( + fun(Value) -> + CData= #xmlcdata{cdata = list_to_binary(Value)}, + #xmlel{name = 'value', children = [CData]} + end, + Values + ). diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index 15c924d1c..593fc5143 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -356,9 +356,12 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, case exmpp_iq:xmlel_to_iq(Packet) of #iq{type = get, ns = ?NS_DISCO_INFO = XMLNS, payload = _SubEl, lang = Lang} = IQ -> - + ServerHostB = list_to_binary(ServerHost), + Info = ejabberd_hooks:run_fold( + disco_info, ServerHostB, [], + [ServerHost, ?MODULE, <<>>, ""]), ResPayload = #xmlel{ns = XMLNS, name = 'query', - children = iq_disco_info(Lang)}, + children = iq_disco_info(Lang)++Info}, Res = exmpp_iq:result(IQ, ResPayload), ejabberd_router:route(To, From, diff --git a/src/mod_proxy65/mod_proxy65_service.erl b/src/mod_proxy65/mod_proxy65_service.erl index c3b4a8766..58a30f980 100644 --- a/src/mod_proxy65/mod_proxy65_service.erl +++ b/src/mod_proxy65/mod_proxy65_service.erl @@ -122,9 +122,13 @@ delete_listener(Host) -> %%%------------------------ %% disco#info request -process_iq(_, #iq{type = get, ns = ?NS_DISCO_INFO, lang = Lang} = IQ_Rec, #state{name=Name}) -> +process_iq(_, #iq{type = get, ns = ?NS_DISCO_INFO, lang = Lang} = IQ_Rec, + #state{name=Name, serverhost = ServerHost}) -> + ServerHostB = list_to_binary(ServerHost), + Info = ejabberd_hooks:run_fold( + disco_info, ServerHostB, [], [ServerHost, ?MODULE, <<>>, ""]), Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', - children = iq_disco_info(Lang, Name)}, + children = iq_disco_info(Lang, Name)++Info}, exmpp_iq:result(IQ_Rec, Result); %% disco#items request diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 36d03f689..ead9e405f 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -840,11 +840,15 @@ do_route(ServerHost, Access, Plugins, Host, From, To, Packet) -> QAttrs = SubEl#xmlel.attrs, Node = exmpp_xml:get_attribute_from_list_as_list(QAttrs, 'node', ""), + ServerHostB = exmpp_jid:prep_domain(ServerHost), + Info = ejabberd_hooks:run_fold( + disco_info, ServerHostB, [], + [ServerHost, ?MODULE, <<>>, ""]), Res = case iq_disco_info(Host, Node, From, Lang) of {result, IQRes} -> Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', attrs = QAttrs, - children = IQRes}, + children = IQRes++Info}, exmpp_iq:result(Packet, Result); {error, Error} -> exmpp_iq:error(Packet, Error) diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index 156c88660..4aedf18d2 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -366,8 +366,12 @@ do_route(ServerHost, From, To, Packet) -> Err = exmpp_iq:error(Packet, 'not-allowed'), ejabberd_router:route(To, From, Err); {get, ?NS_DISCO_INFO} -> + ServerHostB = list_to_binary(ServerHost), + Info = ejabberd_hooks:run_fold( + disco_info, ServerHostB, [], + [ServerHost, ?MODULE, <<>>, ""]), Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', - children = [ + children = Info ++ [ #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [ ?XMLATTR('category', <<"directory">>), diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index 401ad0daf..b4d17feed 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -410,6 +410,7 @@ do_route(State, From, To, Packet) -> route(State, From, To, Packet) -> User = exmpp_jid:node(To), Resource = exmpp_jid:resource(To), + ServerHost = State#state.serverhost, if (User /= undefined) or (Resource /= undefined) -> Err = exmpp_stanza:reply_with_error(Packet, 'service-unavailable'), @@ -463,8 +464,12 @@ route(State, From, To, Packet) -> Err = exmpp_iq:error(Packet, 'not-allowed'), ejabberd_router:route(To, From, Err); {get, ?NS_DISCO_INFO} -> + ServerHostB = list_to_binary(ServerHost), + Info = ejabberd_hooks:run_fold( + disco_info, ServerHostB, [], + [ServerHost, ?MODULE, <<>>, ""]), Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', - children = [ + children = Info ++ [ #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [ ?XMLATTR('category', <<"directory">>), diff --git a/src/mod_vcard_odbc.erl b/src/mod_vcard_odbc.erl index 6f3cb96d7..71b7aa21e 100644 --- a/src/mod_vcard_odbc.erl +++ b/src/mod_vcard_odbc.erl @@ -333,8 +333,12 @@ do_route(ServerHost, From, To, Packet) -> Err = exmpp_iq:error(Packet, 'not-allowed'), ejabberd_router:route(To, From, Err); {get, ?NS_DISCO_INFO} -> + ServerHostB = list_to_binary(ServerHost), + Info = ejabberd_hooks:run_fold( + disco_info, ServerHostB, [], + [ServerHost, ?MODULE, <<>>, ""]), Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query', - children = [ + children = Info ++ [ #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [ ?XMLATTR('category', <<"directory">>), From 020a3e6d6b6a123330722f9bd0036bb9df74439c Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 17 Jul 2009 21:47:26 +0000 Subject: [PATCH 459/582] Revert workaround of EJAB-611 because it seems no longer required (EJAB-709) SVN Revision: 2371 --- src/web/ejabberd_http.erl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/web/ejabberd_http.erl b/src/web/ejabberd_http.erl index facfcef4b..866b260d1 100644 --- a/src/web/ejabberd_http.erl +++ b/src/web/ejabberd_http.erl @@ -453,10 +453,7 @@ recv_data(_State, 0, Acc) -> recv_data(State, Len, Acc) -> case State#state.trail of [] -> - %% TODO: Fix the problem in tls C driver and revert this workaround - %% https://support.process-one.net/browse/EJAB-611 - %%case (State#state.sockmod):recv(State#state.socket, Len, 300000) of - case (State#state.sockmod):recv(State#state.socket, 0, 300000) of + case (State#state.sockmod):recv(State#state.socket, Len, 300000) of {ok, Data} -> recv_data(State, Len - size(Data), [Acc | Data]); _ -> From 338af10aaf02a1ecd3120b008c686fd182049c76 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 20 Jul 2009 09:21:42 +0000 Subject: [PATCH 460/582] moved some log reports from error to debug level (thanks to Evgeniy Khramtsov) SVN Revision: 2374 --- src/web/ejabberd_http_bind.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index b2e740c48..e37ed4307 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -363,7 +363,7 @@ handle_sync_event({stop,stream_closed}, _From, _StateName, StateData) -> Reply = ok, {stop, normal, Reply, StateData}; handle_sync_event({stop,Reason}, _From, _StateName, StateData) -> - ?ERROR_MSG("Closing bind session ~p - Reason: ~p", [StateData#state.id, Reason]), + ?DEBUG("Closing bind session ~p - Reason: ~p", [StateData#state.id, Reason]), Reply = ok, {stop, normal, Reply, StateData}; @@ -737,10 +737,10 @@ process_buffered_request(Reply, StateName, StateData) -> handle_http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) -> case http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) of {error, not_exists} -> - ?ERROR_MSG("no session associated with sid: ~p", [Sid]), + ?DEBUG("no session associated with sid: ~p", [Sid]), {404, ?HEADER, ""}; {{error, Reason}, Sess} -> - ?ERROR_MSG("Error on HTTP put. Reason: ~p", [Reason]), + ?DEBUG("Error on HTTP put. Reason: ~p", [Reason]), handle_http_put_error(Reason, Sess); {{repeat, OutPacket}, Sess} -> ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", [OutPacket]), From 97ee31e7512709aca7d18b1418e8cb794a731e7c Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 21 Jul 2009 17:32:29 +0000 Subject: [PATCH 461/582] Allow content types to be configured in ejabberd.cfg (EJAB-975)(thanks to Brian Cully) SVN Revision: 2377 --- doc/guide.html | 19 ++++++- doc/guide.tex | 19 ++++++- src/web/mod_http_fileserver.erl | 94 ++++++++++++++++++++++----------- 3 files changed, 97 insertions(+), 35 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index a11d78baf..0348dbf3f 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -2102,17 +2102,32 @@ Indicate one or more directory index files, similarly to Apache’s DirectoryIndex variable. When a web request hits a directory instead of a regular file, those directory indices are looked in order, and the first one found is returned. +
    content_types
    +Specify a mapping of extensions to content types. +There are several content types already defined, +with this option you can add new definitions, modify or delete existing ones. +To delete an existing definition, simply define it with a value: ‘undefined’. +
    default_content_type
    +Specify the content type to use for unknown extensions. +Default value is ‘application/octet-stream’.

    This example configuration will serve the files from the local directory /var/www in the address http://example.org:5280/pub/archive/. +In this example a new content type ogg is defined, +png is redefined, and jpg definition is deleted. To use this module you must enable it:

    {modules,
      [
       ...
       {mod_http_fileserver, [
                              {docroot, "/var/www"}, 
    -    {directory_indices, ["index.html", "main.htm"]},
    -                         {accesslog, "/var/log/ejabberd/access.log"}
    +                         {accesslog, "/var/log/ejabberd/access.log"},
    +                         {directory_indices, ["index.html", "main.htm"]},
    +                         {content_types, [{".ogg", "audio/ogg"},
    +                                          {".png", "image/png"},
    +                                          {".jpg", undefined}
    +                                         ]},
    +                         {default_content_type, "text/html"}
                             ]
       },
       ...
    diff --git a/doc/guide.tex b/doc/guide.tex
    index 03f08067e..663c0c7aa 100644
    --- a/doc/guide.tex
    +++ b/doc/guide.tex
    @@ -2775,11 +2775,21 @@ Options:
         DirectoryIndex variable. When a web request hits a directory
         instead of a regular file, those directory indices are looked in
         order, and the first one found is returned.
    +  \titem{content\_types} \ind{options!contenttypes}
    +    Specify a mapping of extensions to content types.
    +    There are several content types already defined,
    +    with this option you can add new definitions, modify or delete existing ones.
    +    To delete an existing definition, simply define it with a value: `undefined'.
    +  \titem{default\_content\_type} \ind{options!defaultcontenttype}
    +    Specify the content type to use for unknown extensions.
    +    Default value is `application/octet-stream'.
     \end{description}
     
     This example configuration will serve the files from 
     the local directory \verb|/var/www|
     in the address \verb|http://example.org:5280/pub/archive/|.
    +In this example a new content type \term{ogg} is defined,
    +\term{png} is redefined, and \term{jpg} definition is deleted.
     To use this module you must enable it:
     \begin{verbatim}
     {modules,
    @@ -2787,8 +2797,13 @@ To use this module you must enable it:
       ...
       {mod_http_fileserver, [
                              {docroot, "/var/www"}, 
    -			 {directory_indices, ["index.html", "main.htm"]},
    -                         {accesslog, "/var/log/ejabberd/access.log"}
    +                         {accesslog, "/var/log/ejabberd/access.log"},
    +                         {directory_indices, ["index.html", "main.htm"]},
    +                         {content_types, [{".ogg", "audio/ogg"},
    +                                          {".png", "image/png"},
    +                                          {".jpg", undefined}
    +                                         ]},
    +                         {default_content_type, "text/html"}
                             ]
       },
       ...
    diff --git a/src/web/mod_http_fileserver.erl b/src/web/mod_http_fileserver.erl
    index 5d5eebb7f..3f13b6cf6 100644
    --- a/src/web/mod_http_fileserver.erl
    +++ b/src/web/mod_http_fileserver.erl
    @@ -72,7 +72,8 @@
     -define(STRING2LOWER, httpd_util).
     -endif.
     
    --record(state, {host, docroot, accesslog, accesslogfd, directory_indices}).
    +-record(state, {host, docroot, accesslog, accesslogfd, directory_indices,
    +                default_content_type, content_types = []}).
     
     -define(PROCNAME, ejabberd_mod_http_fileserver).
     
    @@ -80,6 +81,19 @@
     -define(HTTP_ERR_FILE_NOT_FOUND, {-1, 404, [], "Not found"}).
     -define(HTTP_ERR_FORBIDDEN,      {-1, 403, [], "Forbidden"}).
     
    +-define(DEFAULT_CONTENT_TYPE, "application/octet-stream").
    +-define(DEFAULT_CONTENT_TYPES, [{".css",  "text/css"},
    +                                {".gif",  "image/gif"},
    +                                {".html", "text/html"},
    +                                {".jar",  "application/java-archive"},
    +                                {".jpeg", "image/jpeg"},
    +				{".jpg",  "image/jpeg"},
    +                                {".js",   "text/javascript"},
    +                                {".png",  "image/png"},
    +                                {".txt",  "text/plain"},
    +                                {".xpi",  "application/x-xpinstall"},
    +                                {".xul",  "application/vnd.mozilla.xul+xml"}]).
    +
     -compile(export_all).
     
     %%====================================================================
    @@ -91,7 +105,7 @@ start(Host, Opts) ->
         ChildSpec =
     	{Proc,
     	 {?MODULE, start_link, [Host, Opts]},
    -	 temporary,
    +	 transient, % if process crashes abruptly, it gets restarted
     	 1000,
     	 worker,
     	 [?MODULE]},
    @@ -126,12 +140,15 @@ start_link(Host, Opts) ->
     %%--------------------------------------------------------------------
     init([Host, Opts]) ->
         try initialize(Host, Opts) of
    -	{DocRoot, AccessLog, AccessLogFD, DirectoryIndices} ->
    +	{DocRoot, AccessLog, AccessLogFD, DirectoryIndices,
    +         DefaultContentType, ContentTypes} ->
     	    {ok, #state{host = Host,
     			accesslog = AccessLog,
     			accesslogfd = AccessLogFD,
     			docroot = DocRoot,
    -                        directory_indices = DirectoryIndices}}
    +                        directory_indices = DirectoryIndices,
    +                        default_content_type = DefaultContentType,
    +                        content_types = ContentTypes}}
         catch
     	throw:Reason ->
     	    {stop, Reason}
    @@ -146,7 +163,23 @@ initialize(Host, Opts) ->
         AccessLog = gen_mod:get_opt(accesslog, Opts, undefined),
         AccessLogFD = try_open_log(AccessLog, Host),
         DirectoryIndices = gen_mod:get_opt(directory_indices, Opts, []),
    -    {DocRoot, AccessLog, AccessLogFD, DirectoryIndices}.
    +    DefaultContentType = gen_mod:get_opt(default_content_type, Opts,
    +                                         ?DEFAULT_CONTENT_TYPE),
    +    ContentTypes = build_list_content_types(gen_mod:get_opt(content_types, Opts, []), ?DEFAULT_CONTENT_TYPES),
    +    ?INFO_MSG("initialize: ~n ~p", [ContentTypes]),%+++
    +    {DocRoot, AccessLog, AccessLogFD, DirectoryIndices,
    +     DefaultContentType, ContentTypes}.
    +
    +%% @spec (AdminCTs::[CT], Default::[CT]) -> [CT]
    +%% where CT = {Extension::string(), Value}
    +%%       Value = string() | undefined
    +%% Returns a unified list without duplicates where elements of AdminCTs have more priority.
    +%% If a CT is declared as 'undefined', then it is not included in the result.
    +build_list_content_types(AdminCTsUnsorted, DefaultCTsUnsorted) ->
    +    AdminCTs = lists:ukeysort(1, AdminCTsUnsorted),
    +    DefaultCTs = lists:ukeysort(1, DefaultCTsUnsorted),
    +    CTsUnfiltered = lists:ukeymerge(1, AdminCTs, DefaultCTs),
    +    [{Extension, Value} || {Extension, Value} <- CTsUnfiltered, Value /= undefined].
     
     check_docroot_defined(DocRoot, Host) ->
         case DocRoot of
    @@ -183,7 +216,8 @@ try_open_log(FN, Host) ->
     		 ?ERROR_MSG("Cannot open access log file: ~p~nReason: ~p", [FN, Reason]),
     		 undefined
     	 end,
    -    ejabberd_hooks:add(reopen_log_hook, Host, ?MODULE, reopen_log, 50),
    +    HostB = list_to_binary(Host),
    +    ejabberd_hooks:add(reopen_log_hook, HostB, ?MODULE, reopen_log, 50),
         FD.
     
     %%--------------------------------------------------------------------
    @@ -196,7 +230,8 @@ try_open_log(FN, Host) ->
     %% Description: Handling call messages
     %%--------------------------------------------------------------------
     handle_call({serve, LocalPath}, _From, State) ->
    -    Reply = serve(LocalPath, State#state.docroot, State#state.directory_indices),
    +    Reply = serve(LocalPath, State#state.docroot, State#state.directory_indices,
    +                  State#state.default_content_type, State#state.content_types),
         {reply, Reply, State};
     handle_call(_Request, _From, State) ->
         {reply, ok, State}.
    @@ -263,36 +298,42 @@ process(LocalPath, Request) ->
     	    ejabberd_web:error(not_found)
         end.
     
    -serve(LocalPath, DocRoot, DirectoryIndices) ->
    +serve(LocalPath, DocRoot, DirectoryIndices, DefaultContentType, ContentTypes) ->
         FileName = filename:join(filename:split(DocRoot) ++ LocalPath),
         case file:read_file_info(FileName) of
             {error, enoent}                    -> ?HTTP_ERR_FILE_NOT_FOUND;
             {error, eacces}                    -> ?HTTP_ERR_FORBIDDEN;
    -        {ok, #file_info{type = directory}} -> serve_index(FileName, DirectoryIndices);
    -        {ok, FileInfo}                     -> serve_file(FileInfo, FileName)
    +        {ok, #file_info{type = directory}} -> serve_index(FileName,
    +                                                          DirectoryIndices,
    +                                                          DefaultContentType,
    +                                                          ContentTypes);
    +        {ok, FileInfo}                     -> serve_file(FileInfo, FileName,
    +                                                         DefaultContentType,
    +                                                         ContentTypes)
         end.
     
     %% Troll through the directory indices attempting to find one which
     %% works, if none can be found, return a 404.
    -serve_index(_FileName, []) ->
    +serve_index(_FileName, [], _DefaultContentType, _ContentTypes) ->
         ?HTTP_ERR_FILE_NOT_FOUND;
    -serve_index(FileName, [Index | T]) ->
    +serve_index(FileName, [Index | T], DefaultContentType, ContentTypes) ->
         IndexFileName = filename:join([FileName] ++ [Index]),
         case file:read_file_info(IndexFileName) of
    -        {error, _Error}                    -> serve_index(FileName, T);
    -        {ok, #file_info{type = directory}} -> serve_index(FileName, T);
    -        {ok, FileInfo}                     -> serve_file(FileInfo, IndexFileName)
    +        {error, _Error}                    -> serve_index(FileName, T, DefaultContentType, ContentTypes);
    +        {ok, #file_info{type = directory}} -> serve_index(FileName, T, DefaultContentType, ContentTypes);
    +        {ok, FileInfo}                     -> serve_file(FileInfo, IndexFileName, DefaultContentType, ContentTypes)
         end.
     
     %% Assume the file exists if we got this far and attempt to read it in
     %% and serve it up.
    -serve_file(FileInfo, FileName) ->
    +serve_file(FileInfo, FileName, DefaultContentType, ContentTypes) ->
         ?DEBUG("Delivering: ~s", [FileName]),
         {ok, FileContents} = file:read_file(FileName),
    +    ContentType = content_type(FileName, DefaultContentType, ContentTypes),
         {FileInfo#file_info.size,
          200, [{"Server", "ejabberd"},
                {"Last-Modified", last_modified(FileInfo)},
    -           {"Content-Type", content_type(FileName)}],
    +           {"Content-Type", ContentType}],
          FileContents}.
     
     %%----------------------------------------------------------------------
    @@ -369,20 +410,11 @@ join([E], _) ->
     join([H | T], Separator) ->
         lists:foldl(fun(E, Acc) -> lists:concat([Acc, Separator, E]) end, H, T).
     
    -content_type(Filename) ->
    -    case ?STRING2LOWER:to_lower(filename:extension(Filename)) of
    -        ".jpg"  -> "image/jpeg";
    -        ".jpeg" -> "image/jpeg";
    -        ".gif"  -> "image/gif";
    -        ".png"  -> "image/png";
    -        ".html" -> "text/html";
    -        ".css"  -> "text/css";
    -        ".txt"  -> "text/plain";
    -        ".xul"  -> "application/vnd.mozilla.xul+xml";
    -        ".jar"  -> "application/java-archive";
    -        ".xpi"  -> "application/x-xpinstall";
    -        ".js"   -> "application/x-javascript";
    -        _Else   -> "application/octet-stream"
    +content_type(Filename, DefaultContentType, ContentTypes) ->
    +    Extension = ?STRING2LOWER:to_lower(filename:extension(Filename)),
    +    case lists:keysearch(Extension, 1, ContentTypes) of
    +        {value, {_, ContentType}} -> ContentType;
    +        false                     -> DefaultContentType
         end.
     
     last_modified(FileInfo) ->
    
    From 97dfcb9fb0bfec20a06dc72c1730244c1243a9c9 Mon Sep 17 00:00:00 2001
    From: Badlop 
    Date: Tue, 21 Jul 2009 18:35:20 +0000
    Subject: [PATCH 462/582] HTML room logs: fix formatting of spaces; log config
     when disabling logging; display occupants (EJAB-986)
    
    SVN Revision: 2379
    ---
     src/mod_muc/mod_muc_log.erl  | 94 +++++++++++++++++++++++++++++++++---
     src/mod_muc/mod_muc_room.erl | 19 +++++++-
     2 files changed, 106 insertions(+), 7 deletions(-)
    
    diff --git a/src/mod_muc/mod_muc_log.erl b/src/mod_muc/mod_muc_log.erl
    index f6d1d2ace..cf4dd0117 100644
    --- a/src/mod_muc/mod_muc_log.erl
    +++ b/src/mod_muc/mod_muc_log.erl
    @@ -44,13 +44,17 @@
     -include_lib("exmpp/include/exmpp.hrl").
     
     -include("ejabberd.hrl").
    +-include("mod_muc_room.hrl").
    +
    +%% Copied from mod_muc/mod_muc.erl
    +-record(muc_online_room, {name_host, pid}).
     
     -define(T(Text), translate:translate(Lang, Text)).
     -define(PROCNAME, ejabberd_mod_muc_log).
     -record(room, {jid, title, subject, subject_author, config}).
     
     
    --record(state, {host,
    +-record(logstate, {host,
     		out_dir,
     		dir_type,
     		dir_name,
    @@ -131,7 +135,7 @@ init([Host, Opts]) ->
     		   end;
     	       L -> L
     	   end,
    -    {ok, #state{host = Host,
    +    {ok, #logstate{host = Host,
     		out_dir = OutDir,
     		dir_type = DirType,
     		dir_name = DirName,
    @@ -153,7 +157,7 @@ init([Host, Opts]) ->
     %% Description: Handling call messages
     %%--------------------------------------------------------------------
     handle_call({check_access_log, ServerHost, FromJID}, _From, State) ->
    -    Reply = acl:match_rule(ServerHost, State#state.access, FromJID),
    +    Reply = acl:match_rule(ServerHost, State#logstate.access, FromJID),
         {reply, Reply, State};
     handle_call(stop, _From, State) ->
         {stop, normal, ok, State}.
    @@ -217,9 +221,12 @@ add_to_log2(text, {Nick, Packet}, Room, Opts, State) ->
     	    add_message_to_log(binary_to_list(Nick), Message, Room, Opts, State)
         end;
     
    -add_to_log2(roomconfig_change, _, Room, Opts, State) ->
    +add_to_log2(roomconfig_change, _Occupants, Room, Opts, State) ->
         add_message_to_log("", roomconfig_change, Room, Opts, State);
     
    +add_to_log2(roomconfig_change_enabledlogging, Occupants, Room, Opts, State) ->
    +    add_message_to_log("", {roomconfig_change, Occupants}, Room, Opts, State);
    +
     add_to_log2(nickchange, {OldNick, NewNick}, Room, Opts, State) ->
         add_message_to_log(binary_to_list(NewNick), {nickchange, binary_to_list(OldNick)}, Room, Opts, State);
     
    @@ -304,7 +311,7 @@ write_last_lines(F, Images_dir, _FileFormat) ->
         fw(F, "").
     
     add_message_to_log(Nick1, Message, RoomJID, Opts, State) ->
    -    #state{out_dir = OutDir,
    +    #logstate{out_dir = OutDir,
     	   dir_type = DirType,
     	   dir_name = DirName,
     	   file_format = FileFormat,
    @@ -364,6 +371,13 @@ add_message_to_log(Nick1, Message, RoomJID, Opts, State) ->
     		   put_room_config(F, RoomConfig, Lang, FileFormat),
     		   io_lib:format("~s
    ", [?T("Chatroom configuration modified")]); + {roomconfig_change, Occupants} -> + RoomConfig = roomconfig_to_string(Room#room.config, Lang, FileFormat), + put_room_config(F, RoomConfig, Lang, FileFormat), + RoomOccupants = roomoccupants_to_string(Occupants, FileFormat), + put_room_occupants(F, RoomOccupants, Lang, FileFormat), + io_lib:format("~s
    ", + [?T("Chatroom configuration modified")]); join -> io_lib:format("~s ~s
    ", [Nick, ?T("joins the room")]); @@ -675,6 +689,9 @@ put_header(F, Room, Date, CSSFile, Lang, Hour_offset, Date_prev, Date_next, Top_ end, RoomConfig = roomconfig_to_string(Room#room.config, Lang, FileFormat), put_room_config(F, RoomConfig, Lang, FileFormat), + Occupants = get_room_occupants(Room#room.jid), + RoomOccupants = roomoccupants_to_string(Occupants, FileFormat), + put_room_occupants(F, RoomOccupants, Lang, FileFormat), Time_offset_str = case Hour_offset<0 of true -> io_lib:format("~p", [Hour_offset]); false -> io_lib:format("+~p", [Hour_offset]) @@ -733,6 +750,15 @@ put_room_config(F, RoomConfig, Lang, _FileFormat) -> fw(F, "

    ~s
    ", [Now2, RoomConfig]), fw(F, ""). +put_room_occupants(_F, _RoomOccupants, _Lang, plaintext) -> + ok; +put_room_occupants(F, RoomOccupants, Lang, _FileFormat) -> + {_, Now2, _} = now(), + fw(F, "
    "), + fw(F, "
    ~s
    ", [Now2, ?T("Room Occupants")]), + fw(F, "

    ~s
    ", [Now2, RoomOccupants]), + fw(F, "
    "). + %% htmlize %% The default behaviour is to ignore the nofollow spam prevention on links %% (NoFollow=false) @@ -770,7 +796,9 @@ htmlize2(S1, NoFollow) -> S5 = element(2, regexp:gsub(S4, "((http|https|ftp)://|(mailto|xmpp):)[^] )\'\"}]+", link_regexp(NoFollow))), %% Remove 'right-to-left override' unicode character 0x202e - element(2, regexp:gsub(S5, [226,128,174], "[RLO]")). + S6 = element(2, regexp:gsub(S5, " ", "\\ \\ ")), + S7 = element(2, regexp:gsub(S6, "\\t", "\\ \\ \\ \\ ")), + element(2, regexp:gsub(S7, [226,128,174], "[RLO]")). %% Regexp link %% Add the nofollow rel attribute when required @@ -859,6 +887,60 @@ get_roomconfig_text(allow_user_invites) -> "Allow users to send invites"; get_roomconfig_text(logging) -> "Enable logging"; get_roomconfig_text(_) -> undefined. +%% Users = [{JID, Nick, Role}] +roomoccupants_to_string(Users, _FileFormat) -> + Res = [role_users_to_string(RoleS, Users1) + || {RoleS, Users1} <- group_by_role(Users), Users1 /= []], + lists:flatten(["
    ", Res, "
    "]). + +%% Users = [{JID, Nick, Role}] +group_by_role(Users) -> + {Ms, Ps, Vs, Ns} = + lists:foldl( + fun({JID, Nick, moderator}, {Mod, Par, Vis, Non}) -> + {[{JID, Nick}]++Mod, Par, Vis, Non}; + ({JID, Nick, participant}, {Mod, Par, Vis, Non}) -> + {Mod, [{JID, Nick}]++Par, Vis, Non}; + ({JID, Nick, visitor}, {Mod, Par, Vis, Non}) -> + {Mod, Par, [{JID, Nick}]++Vis, Non}; + ({JID, Nick, none}, {Mod, Par, Vis, Non}) -> + {Mod, Par, Vis, [{JID, Nick}]++Non} + end, + {[], [], [], []}, + Users), + case Ms of [] -> []; _ -> [{"Moderator", Ms}] end + ++ case Ms of [] -> []; _ -> [{"Participant", Ps}] end + ++ case Ms of [] -> []; _ -> [{"Visitor", Vs}] end + ++ case Ms of [] -> []; _ -> [{"None", Ns}] end. + +%% Role = atom() +%% Users = [{JID, Nick}] +role_users_to_string(RoleS, Users) -> + SortedUsers = lists:keysort(2, Users), + UsersString = [[Nick, "
    "] || {_JID, Nick} <- SortedUsers], + [RoleS, ": ", UsersString]. + +get_room_occupants(RoomJIDString) -> + RoomJID = exmpp_jid:parse(RoomJIDString), + RoomName = exmpp_jid:node(RoomJID), + MucService = exmpp_jid:domain(RoomJID), + StateData = get_room_state(RoomName, MucService), + [{U#user.jid, U#user.nick, U#user.role} + || {_, U} <- ?DICT:to_list(StateData#state.users)]. + +get_room_state(RoomName, MucService) -> + case mnesia:dirty_read(muc_online_room, {RoomName, MucService}) of + [R] -> + RoomPid = R#muc_online_room.pid, + get_room_state(RoomPid); + [] -> + room_not_found + end. + +get_room_state(RoomPid) -> + {ok, R} = gen_fsm:sync_send_all_state_event(RoomPid, get_state), + R. + get_proc_name(Host) -> gen_mod:get_module_proc(Host, ?PROCNAME). calc_hour_offset(TimeHere) -> diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl index 7265950b6..4edd36b36 100644 --- a/src/mod_muc/mod_muc_room.erl +++ b/src/mod_muc/mod_muc_room.erl @@ -2981,7 +2981,18 @@ set_config(XEl, StateData) -> #config{} = Config -> Res = change_config(Config, StateData), {result, _, NSD} = Res, - add_to_log(roomconfig_change, [], NSD), + Type = case {(StateData#state.config)#config.logging, + Config#config.logging} of + {true, false} -> + roomconfig_change_disabledlogging; + {false, true} -> + roomconfig_change_enabledlogging; + {_, _} -> + roomconfig_change + end, + Users = [{U#user.jid, U#user.nick, U#user.role} || + {_, U} <- ?DICT:to_list(StateData#state.users)], + add_to_log(Type, Users, NSD), Res; Err -> Err @@ -3492,6 +3503,12 @@ send_error_only_occupants(Packet, Lang, RoomJID, From) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Logging +add_to_log(Type, Data, StateData) + when Type == roomconfig_change_disabledlogging -> + %% When logging is disabled, the config change message must be logged: + mod_muc_log:add_to_log( + StateData#state.server_host, roomconfig_change, Data, + StateData#state.jid, make_opts(StateData)); add_to_log(Type, Data, StateData) -> case (StateData#state.config)#config.logging of true -> From ee142c5fe131e4837c64a9121e871ba310ce8f55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20R=C3=A9mond?= Date: Tue, 21 Jul 2009 19:18:22 +0000 Subject: [PATCH 463/582] Fix typo from EJAB-988 SVN Revision: 2381 --- src/ejabberd.cfg.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index a97356824..07b9010c8 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -152,7 +152,7 @@ {5280, ejabberd_http, [ %%{request_handlers, %% [ - %% {["pub", "archive"], mod_http_fileserver}, + %% {["pub", "archive"], mod_http_fileserver} %% ]}, captcha, http_bind, From 553969f0fdf6ed3ed9d017e5761b4cdee24506fb Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 22 Jul 2009 06:52:47 +0000 Subject: [PATCH 464/582] delete/2 now does not crash when there is nothing to delete. fold/1 added SVN Revision: 2385 --- src/treap.erl | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/treap.erl b/src/treap.erl index ab5c4d33f..360f543de 100644 --- a/src/treap.erl +++ b/src/treap.erl @@ -32,7 +32,8 @@ delete_root/1, get_root/1, lookup/2, - is_empty/1]). + is_empty/1, + fold/3]). empty() -> nil. @@ -105,6 +106,8 @@ delete(Key, Tree) -> HashKey = {erlang:phash2(Key), Key}, delete1(HashKey, Tree). +delete1(_HashKey, nil) -> + nil; delete1(HashKey, {HashKey1, Priority1, Value1, Left, Right} = Tree) -> if HashKey < HashKey1 -> @@ -162,3 +165,9 @@ lookup1({HashKey1, Priority1, Value1, Left, Right}, HashKey) -> {ok, Priority1, Value1} end. +fold(_F, Acc, nil) -> + Acc; +fold(F, Acc, {{_Hash, Key}, Priority, Value, Left, Right}) -> + Acc1 = F({Key, Priority, Value}, Acc), + Acc2 = fold(F, Acc1, Left), + fold(F, Acc2, Right). From 73f2fc76d9545dd074d7ad2cc8907299d1d56bc7 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 23 Jul 2009 14:51:16 +0000 Subject: [PATCH 465/582] Log an error if HTTP request does not include Host header (EJAB-966) SVN Revision: 2387 --- src/web/ejabberd_http.erl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/web/ejabberd_http.erl b/src/web/ejabberd_http.erl index 866b260d1..820f5646a 100644 --- a/src/web/ejabberd_http.erl +++ b/src/web/ejabberd_http.erl @@ -239,6 +239,9 @@ process_header(State, Data) -> request_headers=add_header(Name, Host, State)}; {ok, {http_header, _, Name, _, Value}} -> State#state{request_headers=add_header(Name, Value, State)}; + {ok, http_eoh} when State#state.request_host == undefined -> + ?WARNING_MSG("An HTTP request without 'Host' HTTP header was received.", []), + throw(http_request_no_host_header); {ok, http_eoh} -> ?DEBUG("(~w) http query: ~w ~s~n", [State#state.socket, From 646adbf186b3c3fdf8e095f5ecf6fa0fd5e46f21 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 23 Jul 2009 15:23:21 +0000 Subject: [PATCH 466/582] Add support to delete content and delete table. SVN Revision: 2390 --- src/web/ejabberd_web_admin.erl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 209cc76d3..929c6667c 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -2233,7 +2233,9 @@ db_storage_select(ID, Opt, Lang) -> end, [{ram_copies, "RAM copy"}, {disc_copies, "RAM and disc copy"}, {disc_only_copies, "Disc only copy"}, - {unknown, "Remote copy"}])). + {unknown, "Remote copy"}, + {delete_content, "Delete content"}, + {delete_table, "Delete table"}])). node_db_parse_query(_Node, _Tables, [{nokey,[]}]) -> nothing; @@ -2248,11 +2250,17 @@ node_db_parse_query(Node, Tables, Query) -> "ram_copies" -> ram_copies; "disc_copies" -> disc_copies; "disc_only_copies" -> disc_only_copies; + "delete_content" -> delete_content; + "delete_table" -> delete_table; _ -> false end, if Type == false -> ok; + Type == delete_content -> + mnesia:clear_table(Table); + Type == delete_table -> + mnesia:delete_table(Table); Type == unknown -> mnesia:del_table_copy(Table, Node); true -> From 620a50223c89f993da282690a7007b9b6af9344e Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 23 Jul 2009 15:23:26 +0000 Subject: [PATCH 467/582] New command to dump a table to text file. SVN Revision: 2391 --- src/ejabberd_admin.erl | 53 ++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl index d7f00b185..2c03d10b6 100644 --- a/src/ejabberd_admin.erl +++ b/src/ejabberd_admin.erl @@ -39,9 +39,9 @@ delete_expired_messages/0, delete_old_messages/1, %% Mnesia backup_mnesia/1, restore_mnesia/1, - dump_mnesia/1, load_mnesia/1, + dump_mnesia/1, dump_table/2, load_mnesia/1, install_fallback_mnesia/1, - dump_to_textfile/1, + dump_to_textfile/1, dump_to_textfile/2, mnesia_change_nodename/4, restore/1 % Still used by some modules ]). @@ -133,6 +133,10 @@ commands() -> desc = "Dump the database to text file", module = ?MODULE, function = dump_mnesia, args = [{file, string}], result = {res, restuple}}, + #ejabberd_commands{name = dump_table, tags = [mnesia], + desc = "Dump a table to text file", + module = ?MODULE, function = dump_table, + args = [{file, string}, {table, string}], result = {res, restuple}}, #ejabberd_commands{name = load, tags = [mnesia], desc = "Restore the database from text file", module = ?MODULE, function = load_mnesia, @@ -320,19 +324,7 @@ module_tables(mod_shared_roster) -> [sr_group, sr_user]; module_tables(mod_vcard) -> [vcard, vcard_search]; module_tables(_Other) -> []. -dump_mnesia(Path) -> - case dump_to_textfile(Path) of - ok -> - {ok, ""}; - {error, Reason} -> - String = io_lib:format("Can't store dump in ~p at node ~p: ~p", - [filename:absname(Path), node(), Reason]), - {cannot_dump, String} - end. - -dump_to_textfile(File) -> - dump_to_textfile(mnesia:system_info(is_running), file:open(File, [write])). -dump_to_textfile(yes, {ok, F}) -> +get_local_tables() -> Tabs1 = lists:delete(schema, mnesia:system_info(local_tables)), Tabs = lists:filter( fun(T) -> @@ -342,6 +334,33 @@ dump_to_textfile(yes, {ok, F}) -> _ -> false end end, Tabs1), + Tabs. + +dump_mnesia(Path) -> + Tabs = get_local_tables(), + dump_tables(Path, Tabs). + +dump_table(Path, STable) -> + Table = list_to_atom(STable), + dump_tables(Path, [Table]). + +dump_tables(Path, Tables) -> + case dump_to_textfile(Path, Tables) of + ok -> + {ok, ""}; + {error, Reason} -> + String = io_lib:format("Can't store dump in ~p at node ~p: ~p", + [filename:absname(Path), node(), Reason]), + {cannot_dump, String} + end. + +dump_to_textfile(File) -> + Tabs = get_local_tables(), + dump_to_textfile(File, Tabs). + +dump_to_textfile(File, Tabs) -> + dump_to_textfile(mnesia:system_info(is_running), Tabs, file:open(File, [write])). +dump_to_textfile(yes, Tabs, {ok, F}) -> Defs = lists:map( fun(T) -> {T, [{record_name, mnesia:table_info(T, record_name)}, {attributes, mnesia:table_info(T, attributes)}]} @@ -350,10 +369,10 @@ dump_to_textfile(yes, {ok, F}) -> io:format(F, "~p.~n", [{tables, Defs}]), lists:foreach(fun(T) -> dump_tab(F, T) end, Tabs), file:close(F); -dump_to_textfile(_, {ok, F}) -> +dump_to_textfile(_, _, {ok, F}) -> file:close(F), {error, mnesia_not_running}; -dump_to_textfile(_, {error, Reason}) -> +dump_to_textfile(_, _, {error, Reason}) -> {error, Reason}. dump_tab(F, T) -> From e6205e8f264570454d7c77be730fe5ac490bb1a9 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 27 Jul 2009 09:37:24 +0000 Subject: [PATCH 468/582] Fix error when nick registration stanza doesn't contain Value. SVN Revision: 2395 --- src/mod_muc/mod_muc.erl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index 593fc5143..d8de5af3b 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -756,14 +756,14 @@ process_iq_register_set(Host, From, SubEl, Lang) -> {error, 'bad-request'}; _ -> case lists:keysearch("nick", 1, XData) of - false -> + {value, {_, [Nick]}} -> + iq_set_register_info(Host, From, list_to_binary(Nick), Lang); + _ -> ErrText = "You must fill in field \"Nickname\" in the form", Err = exmpp_stanza:error(SubEl#xmlel.ns, 'not-acceptable', {Lang, translate:translate(Lang,ErrText)}), - {error, Err}; - {value, {_, [Nick]}} -> - iq_set_register_info(Host, From, list_to_binary(Nick), Lang) + {error, Err} end end; _ -> From 504cc7b7dd7803fef2b40a318a07b745930b0e6e Mon Sep 17 00:00:00 2001 From: Geoff Cant Date: Tue, 28 Jul 2009 13:43:00 +0000 Subject: [PATCH 469/582] EJAB-940: Implements reliable ODBC transaction nesting. SVN Revision: 2396 --- src/odbc/ejabberd_odbc.erl | 250 +++++++++++++++++++++---------------- 1 file changed, 139 insertions(+), 111 deletions(-) diff --git a/src/odbc/ejabberd_odbc.erl b/src/odbc/ejabberd_odbc.erl index a85aa2d77..b8040a902 100644 --- a/src/odbc/ejabberd_odbc.erl +++ b/src/odbc/ejabberd_odbc.erl @@ -52,6 +52,8 @@ -record(state, {db_ref, db_type}). -define(STATE_KEY, ejabberd_odbc_state). +-define(NESTING_KEY, ejabberd_odbc_nesting_level). +-define(TOP_LEVEL_TXN, 0). -define(MAX_TRANSACTION_RESTARTS, 10). -define(PGSQL_PORT, 5432). -define(MYSQL_PORT, 3306). @@ -70,8 +72,7 @@ start_link(Host, StartInterval) -> gen_server:start_link(ejabberd_odbc, [Host, StartInterval], []). sql_query(Host, Query) -> - Msg = {sql_query, Query}, - sql_call(Host, Msg). + sql_call(Host, {sql_query, Query}). %% SQL transaction based on a list of queries %% This function automatically @@ -84,34 +85,27 @@ sql_transaction(Host, Queries) when is_list(Queries) -> end, sql_transaction(Host, F); %% SQL transaction, based on a erlang anonymous function (F = fun) -sql_transaction(Host, F) -> - Msg = {sql_transaction, F}, - sql_call(Host, Msg). +sql_transaction(Host, F) when is_function(F) -> + sql_call(Host, {sql_transaction, F}). %% SQL bloc, based on a erlang anonymous function (F = fun) sql_bloc(Host, F) -> - Msg = {sql_bloc, F}, - sql_call(Host, Msg). + sql_call(Host, {sql_bloc, F}). sql_call(Host, Msg) -> case get(?STATE_KEY) of undefined -> gen_server:call(ejabberd_odbc_sup:get_random_pid(Host), - Msg, ?TRANSACTION_TIMEOUT); - State -> - %% Query, Transaction or Bloc nested inside transaction - nested_op(Msg, State) + {sql_cmd, Msg}, ?TRANSACTION_TIMEOUT); + _State -> + nested_op(Msg) end. %% This function is intended to be used from inside an sql_transaction: sql_query_t(Query) -> - State = get(?STATE_KEY), - QRes = sql_query_internal(State, Query), + QRes = sql_query_internal(Query), case QRes of - {error, "No SQL-driver information available."} -> - % workaround for odbc bug - {updated, 0}; {error, Reason} -> throw({aborted, Reason}); Rs when is_list(Rs) -> @@ -187,8 +181,13 @@ init([Host, StartInterval]) -> %% {stop, Reason, Reply, State} | (terminate/2 is called) %% {stop, Reason, State} (terminate/2 is called) %%---------------------------------------------------------------------- -handle_call(Command, _From, State) -> - dispatch_sql_command(Command, State). +handle_call({sql_cmd, Command}, _From, State) -> + put(?NESTING_KEY, ?TOP_LEVEL_TXN), + put(?STATE_KEY, State), + abort_on_driver_error(outer_op(Command)); +handle_call(Request, {Who, _Ref}, State) -> + ?WARNING_MSG("Unexpected call ~p from ~p.", [Request, Who]), + {reply, ok, State}. %%---------------------------------------------------------------------- %% Func: handle_cast/2 @@ -236,110 +235,139 @@ terminate(_Reason, State) -> %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- -dispatch_sql_command({sql_query, Query}, State) -> - abort_on_driver_error(sql_query_internal(State, Query), State); -dispatch_sql_command({sql_transaction, F}, State) -> - abort_on_driver_error( - execute_transaction(State, F, ?MAX_TRANSACTION_RESTARTS, ""), State); -dispatch_sql_command({sql_bloc, F}, State) -> - abort_on_driver_error(execute_bloc(State, F), State); -dispatch_sql_command(Request, State) -> - ?WARNING_MSG("Unexpected call ~p.", [Request]), - {reply, ok, State}. -sql_query_internal(State, Query) -> - Nested = case get(?STATE_KEY) of - undefined -> put(?STATE_KEY, State), false; - _State -> true - end, - Result = case State#state.db_type of - odbc -> - odbc:sql_query(State#state.db_ref, Query); - pgsql -> - pgsql_to_odbc(pgsql:squery(State#state.db_ref, Query)); - mysql -> - ?DEBUG("MySQL, Send query~n~p~n", [Query]), - R = mysql_to_odbc(mysql_conn:fetch(State#state.db_ref, Query, self())), - ?DEBUG("MySQL, Received result~n~p~n", [R]), - R - end, - case Nested of - true -> Result; - false -> erase(?STATE_KEY), Result +%% Only called by handle_call, only handles top level operations. +%% @spec outer_op(Op) -> {error, Reason} | {aborted, Reason} | {atomic, Result} +outer_op({sql_query, Query}) -> + sql_query_internal(Query); +outer_op({sql_transaction, F}) -> + outer_transaction(F, ?MAX_TRANSACTION_RESTARTS, ""); +outer_op({sql_bloc, F}) -> + execute_bloc(F). + +%% Called via sql_query/transaction/bloc from client code when inside a +%% nested operation +nested_op({sql_query, Query}) -> + %% XXX - use sql_query_t here insted? Most likely would break + %% callers who expect {error, _} tuples (sql_query_t turns + %% these into throws) + sql_query_internal(Query); +nested_op({sql_transaction, F}) -> + NestingLevel = get(?NESTING_KEY), + if NestingLevel =:= ?TOP_LEVEL_TXN -> + %% First transaction inside a (series of) sql_blocs + outer_transaction(F, ?MAX_TRANSACTION_RESTARTS, ""); + true -> + %% Transaction inside a transaction + inner_transaction(F) + end; +nested_op({sql_bloc, F}) -> + execute_bloc(F). + +%% Never retry nested transactions - only outer transactions +inner_transaction(F) -> + PreviousNestingLevel = get(?NESTING_KEY), + case get(?NESTING_KEY) of + ?TOP_LEVEL_TXN -> + {backtrace, T} = process_info(self(), backtrace), + ?ERROR_MSG("inner transaction called at outer txn level. Trace: ~s", [T]), + erlang:exit(implementation_faulty); + _N -> ok + end, + put(?NESTING_KEY, PreviousNestingLevel + 1), + Result = (catch F()), + put(?NESTING_KEY, PreviousNestingLevel), + case Result of + {aborted, Reason} -> + {aborted, Reason}; + {'EXIT', Reason} -> + {'EXIT', Reason}; + {atomic, Res} -> + {atomic, Res}; + Res -> + {atomic, Res} end. -execute_transaction(State, _F, 0, Reason) -> - ?ERROR_MSG("SQL transaction restarts exceeded~n" - "** Restarts: ~p~n" - "** Last abort reason: ~p~n" - "** Stacktrace: ~p~n" - "** When State == ~p", - [?MAX_TRANSACTION_RESTARTS, Reason, - erlang:get_stacktrace(), State]), - sql_query_internal(State, "rollback;"), - {aborted, restarts_exceeded}; -execute_transaction(State, F, NRestarts, _Reason) -> - Nested = case get(?STATE_KEY) of - undefined -> - put(?STATE_KEY, State), - sql_query_internal(State, "begin;"), - false; - _State -> - true - end, - Result = case catch F() of - {aborted, Reason} -> - execute_transaction(State, F, NRestarts - 1, Reason); - {'EXIT', Reason} -> - sql_query_internal(State, "rollback;"), - {aborted, Reason}; - Res -> - {atomic, Res} - end, - case Nested of - true -> Result; - false -> sql_query_internal(State, "commit;"), erase(?STATE_KEY), Result +outer_transaction(F, NRestarts, _Reason) -> + PreviousNestingLevel = get(?NESTING_KEY), + case get(?NESTING_KEY) of + ?TOP_LEVEL_TXN -> + ok; + _N -> + {backtrace, T} = process_info(self(), backtrace), + ?ERROR_MSG("outer transaction called at inner txn level. Trace: ~s", [T]), + erlang:exit(implementation_faulty) + end, + sql_query_internal("begin;"), + put(?NESTING_KEY, PreviousNestingLevel + 1), + Result = (catch F()), + put(?NESTING_KEY, PreviousNestingLevel), + case Result of + {aborted, Reason} when NRestarts > 0 -> + %% Retry outer transaction upto NRestarts times. + sql_query_internal("rollback;"), + outer_transaction(F, NRestarts - 1, Reason); + {aborted, Reason} when NRestarts =:= 0 -> + %% Too many retries of outer transaction. + ?ERROR_MSG("SQL transaction restarts exceeded~n" + "** Restarts: ~p~n" + "** Last abort reason: ~p~n" + "** Stacktrace: ~p~n" + "** When State == ~p", + [?MAX_TRANSACTION_RESTARTS, Reason, + erlang:get_stacktrace(), get(?STATE_KEY)]), + sql_query_internal("rollback;"), + {aborted, Reason}; + {'EXIT', Reason} -> + %% Abort sql transaction on EXIT from outer txn only. + sql_query_internal("rollback;"), + {aborted, Reason}; + Res -> + %% Commit successful outer txn + sql_query_internal("commit;"), + {atomic, Res} end. -execute_bloc(State, F) -> - Nested = case get(?STATE_KEY) of - undefined -> put(?STATE_KEY, State), false; - _State -> true - end, - Result = case catch F() of - {aborted, Reason} -> - {aborted, Reason}; - {'EXIT', Reason} -> - {aborted, Reason}; - Res -> - {atomic, Res} - end, - case Nested of - true -> Result; - false -> erase(?STATE_KEY), Result +execute_bloc(F) -> + %% We don't alter ?NESTING_KEY here as only SQL transactions alter txn nesting + case catch F() of + {aborted, Reason} -> + {aborted, Reason}; + {'EXIT', Reason} -> + {aborted, Reason}; + Res -> + {atomic, Res} end. -nested_op(Op, State) -> - case dispatch_sql_command(Op, State) of - {reply, Res, NewState} -> - put(?STATE_KEY, NewState), - Res; - {stop, _Reason, Reply, NewState} -> - put(?STATE_KEY, NewState), - throw({aborted, Reply}); - {noreply, NewState} -> - put(?STATE_KEY, NewState), - exit({bad_op_in_nested_txn, Op}) +sql_query_internal(Query) -> + State = get(?STATE_KEY), + Res = case State#state.db_type of + odbc -> + odbc:sql_query(State#state.db_ref, Query); + pgsql -> + pgsql_to_odbc(pgsql:squery(State#state.db_ref, Query)); + mysql -> + ?DEBUG("MySQL, Send query~n~p~n", [Query]), + R = mysql_to_odbc(mysql_conn:fetch(State#state.db_ref, Query, self())), + ?INFO_MSG("MySQL, Received result~n~p~n", [R]), + R + end, + case Res of + {error, "No SQL-driver information available."} -> + % workaround for odbc bug + {updated, 0}; + _Else -> Res end. -abort_on_driver_error({error, "query timed out"} = Reply, State) -> +%% Generate the OTP callback return tuple depending on the driver result. +abort_on_driver_error({error, "query timed out"} = Reply) -> %% mysql driver error - {stop, timeout, Reply, State}; -abort_on_driver_error({error, "Failed sending data on socket"++_} = Reply, State) -> + {stop, timeout, Reply, get(?STATE_KEY)}; +abort_on_driver_error({error, "Failed sending data on socket"++_} = Reply) -> %% mysql driver error - {stop, closed, Reply, State}; -abort_on_driver_error(Reply, State) -> - {reply, Reply, State}. + {stop, closed, Reply, get(?STATE_KEY)}; +abort_on_driver_error(Reply) -> + {reply, Reply, get(?STATE_KEY)}. %% == pure ODBC code From c6f3fbb82c4d2b152541a525ad618d2cb9804486 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 29 Jul 2009 03:43:58 +0000 Subject: [PATCH 470/582] treap.erl backport SVN Revision: 2400 --- src/treap.erl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/treap.erl b/src/treap.erl index 360f543de..42438f228 100644 --- a/src/treap.erl +++ b/src/treap.erl @@ -44,7 +44,7 @@ insert(Key, Priority, Value, Tree) -> insert1(nil, HashKey, Priority, Value) -> {HashKey, Priority, Value, nil, nil}; -insert1({HashKey1, Priority1, Value1, Left, Right}, +insert1({HashKey1, Priority1, Value1, Left, Right} = Tree, HashKey, Priority, Value) -> if HashKey < HashKey1 -> @@ -55,8 +55,10 @@ insert1({HashKey1, Priority1, Value1, Left, Right}, heapify({HashKey1, Priority1, Value1, Left, insert1(Right, HashKey, Priority, Value)}); + Priority == Priority1 -> + {HashKey, Priority, Value, Left, Right}; true -> - erlang:error(key_exists) + insert1(delete_root(Tree), HashKey, Priority, Value) end. heapify(nil) -> From 628b03f3c06117e3a68367f0b326dca54f73a86a Mon Sep 17 00:00:00 2001 From: Geoff Cant Date: Thu, 30 Jul 2009 12:35:18 +0000 Subject: [PATCH 471/582] EJAB-994: Implements DNS timeouts and retries. SVN Revision: 2405 --- src/ejabberd_config.erl | 2 ++ src/ejabberd_s2s_out.erl | 34 +++++++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 883e484b5..2d1e8398e 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -344,6 +344,8 @@ process_term(Term, State) -> add_option(outgoing_s2s_port, Port, State); {outgoing_s2s_options, Methods, Timeout} -> add_option(outgoing_s2s_options, {Methods, Timeout}, State); + {s2s_dns_options, PropList} -> + add_option(s2s_dns_options, PropList, State); {s2s_use_starttls, Port} -> add_option(s2s_use_starttls, Port, State); {s2s_certfile, CertFile} -> diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 2ee8ddeb9..51295443d 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -948,11 +948,7 @@ is_verify_res(_) -> -include_lib("kernel/include/inet.hrl"). get_addr_port(Server) -> - Res = case inet_res:getbyname("_xmpp-server._tcp." ++ Server, srv) of - {error, _Reason1} -> - inet_res:getbyname("_jabber._tcp." ++ Server, srv); - {ok, _HEnt} = R -> R - end, + Res = srv_lookup(Server), case Res of {error, Reason} -> ?DEBUG("srv lookup of '~s' failed: ~p~n", [Server, Reason]), @@ -989,6 +985,34 @@ get_addr_port(Server) -> end end. +srv_lookup(Server) -> + Options = case ejabberd_config:get_local_option(s2s_dns_options) of + L when is_list(L) -> L; + _ -> [] + end, + Timeout = proplists:get_value(timeout, Options, timer:seconds(10)), + Retries = proplists:get_value(retries, Options, 2), + srv_lookup(Server, Timeout, Retries). + +%% XXX - this behaviour is suboptimal in the case that the domain +%% has a "_xmpp-server._tcp." but not a "_jabber._tcp." record and +%% we don't get a DNS reply for the "_xmpp-server._tcp." lookup. In this +%% case we'll give up when we get the "_jabber._tcp." nxdomain reply. +srv_lookup(_Server, _Timeout, Retries) when Retries < 1 -> + {error, timeout}; +srv_lookup(Server, Timeout, Retries) -> + case inet_res:getbyname("_xmpp-server._tcp." ++ Server, srv, Timeout) of + {error, _Reason} -> + case inet_res:getbyname("_jabber._tcp." ++ Server, srv, Timeout) of + {error, timeout} -> + ?ERROR_MSG("Couldn't resolve SRV records for ~p via nameservers ~p.", + [Server, inet_db:res_option(nameserver)]), + srv_lookup(Server, Timeout, Retries - 1); + R -> R + end; + {ok, _HEnt} = R -> R + end. + test_get_addr_port(Server) -> lists:foldl( fun(_, Acc) -> From 35c1c3774cdb635612dce0b035f33cda21876877 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Thu, 30 Jul 2009 13:10:01 +0000 Subject: [PATCH 472/582] do not crash on unmatched request SVN Revision: 2407 --- src/ejabberd_captcha.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ejabberd_captcha.erl b/src/ejabberd_captcha.erl index 3406cabaf..07e2a44c6 100644 --- a/src/ejabberd_captcha.erl +++ b/src/ejabberd_captcha.erl @@ -241,8 +241,10 @@ process(_Handlers, #request{method='POST', q=Q, lang=Lang, path=[_, Id]}) -> ejabberd_web:error(not_allowed); captcha_not_found -> ejabberd_web:error(not_found) - end. + end; +process(_Handlers, _Request) -> + ejabberd_web:error(not_found). %%==================================================================== %% gen_server callbacks From f5868a09522309c2bb747e053a40084b2bfa9a68 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 30 Jul 2009 17:57:56 +0000 Subject: [PATCH 473/582] Delete expat_erl, stringprep, xml and xml_stream; replaced by exmpp (EJAB-991) SVN Revision: 2409 --- README | 1 - doc/guide.html | 1 - doc/guide.tex | 1 - src/Makefile.in | 4 +- src/configure | 494 ++--- src/configure.ac | 3 - src/ejabberd_app.erl | 14 +- src/expat_erl.c | 190 -- src/mod_privacy.erl | 4 +- src/stringprep/Makefile.in | 60 - src/stringprep/Makefile.win32 | 40 - src/stringprep/stringprep.erl | 113 - src/stringprep/stringprep_drv.c | 410 ---- src/stringprep/stringprep_sup.erl | 68 - src/stringprep/uni_data.c | 1257 ----------- src/stringprep/uni_norm.c | 3264 ----------------------------- src/stringprep/uni_parse.tcl | 437 ---- src/stringprep/uni_parse2.tcl | 702 ------- src/xml.erl | 234 --- src/xml_stream.erl | 190 -- 20 files changed, 124 insertions(+), 7363 deletions(-) delete mode 100644 src/expat_erl.c delete mode 100644 src/stringprep/Makefile.in delete mode 100644 src/stringprep/Makefile.win32 delete mode 100644 src/stringprep/stringprep.erl delete mode 100644 src/stringprep/stringprep_drv.c delete mode 100644 src/stringprep/stringprep_sup.erl delete mode 100644 src/stringprep/uni_data.c delete mode 100644 src/stringprep/uni_norm.c delete mode 100644 src/stringprep/uni_parse.tcl delete mode 100644 src/stringprep/uni_parse2.tcl delete mode 100644 src/xml.erl delete mode 100644 src/xml_stream.erl diff --git a/README b/README index 3b9ce0aa3..131946b3a 100644 --- a/README +++ b/README @@ -8,7 +8,6 @@ Quickstart guide To compile ejabberd you need: - GNU Make - GCC - - Libexpat 1.95 or higher - Erlang/OTP R12B-5. Support for R13 or higher is experimental. - exmpp 0.9.1 or higher - OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL diff --git a/doc/guide.html b/doc/guide.html index 0348dbf3f..bba8c2c2b 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -335,7 +335,6 @@ as long as your system have all the dependencies.

    -
  • Chapter 4  Managing an ejabberd Server +
  • Chapter 4  Managing an ejabberd Server -
  • Chapter 5  Securing ejabberd +
  • Chapter 5  Securing ejabberd -
  • Chapter 6  Clustering +
  • Chapter 6  Clustering -
  • Chapter 7  Debugging +
  • Chapter 7  Debugging -
  • Appendix A  Internationalization and Localization -
  • Appendix B  Release Notes -
  • Appendix C  Acknowledgements -
  • Appendix D  Copyright Information +
  • Appendix A  Internationalization and Localization +
  • Appendix B  Release Notes +
  • Appendix C  Acknowledgements +
  • Appendix D  Copyright Information
  • Chapter 1  Introduction

    ejabberd is a free and open source instant messaging server written in Erlang.

    ejabberd is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.

    ejabberd is designed to be a rock-solid and feature rich XMPP server.

    ejabberd is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.

    @@ -492,7 +493,7 @@ There are two ways to register a Jabber account:
    1. Using ejabberdctl (see section 4.1):
      ejabberdctl register admin1 example.org FgT5bk3
      -
    2. Using a Jabber client and In-Band Registration (see section 3.3.16). +
  • Using a Jabber client and In-Band Registration (see section 3.3.17).
  • Edit the ejabberd configuration file to give administration rights to the Jabber account you created:
    {acl, admins, {user, "admin1", "example.org"}}.
    @@ -1786,6 +1787,7 @@ all entries end with a comma:
     
  • + @@ -2506,7 +2508,8 @@ top link will be the default <a href="/">Home</a>. ]}.

    3.3.11  mod_offline

    -

    This module implements offline message storage. This means that all messages +

    This module implements offline message storage (XEP-0160). +This means that all messages sent to an offline user will be stored on the server until that user comes online again. Thus it is very similar to how email works. Note that ejabberdctl has a command to delete expired messages @@ -2535,8 +2538,36 @@ and all the other users up to 100. {mod_offline, [ {access_max_user_messages, max_user_offline_messages} ]}, ... ]}. +

    +

    3.3.12  mod_ping

    +

    This module implements support for XMPP Ping (XEP-0199) and periodic keepalives. +When this module is enabled ejabberd responds correctly to +ping requests, as defined in the protocol.

    Configuration options: +

    +{send_pings, true | false}
    +If this option is set to true, the server sends pings to connected clients +that are not active in a given interval ping_interval. +This is useful to keep client connections alive or checking availability. +By default this option is disabled. +
    {ping_interval, Seconds}
    +How often to send pings to connected clients, if the previous option is enabled. +If a client connection does not send or receive any stanza in this interval, +a ping request is sent to the client. +The default value is 60 seconds. +
    {timeout_action, none | kill}
    +What to do when a client does not answer to a server ping request in less than 32 seconds. +The default is to do nothing. +

    This example enables Ping responses, configures the module to send pings +to client connections that are inactive for 4 minutes, +and if a client does not answer to the ping in less than 32 seconds, its connection is closed: +

    {modules,
    + [
    +  ...
    +  {mod_ping,  [{send_pings, true}, {ping_interval, 240}, {timeout_action, kill}]},
    +  ...
    + ]}.
     

    -

    3.3.12  mod_privacy

    +

    3.3.13  mod_privacy

    This module implements Blocking Communication (also known as Privacy Rules) as defined in section 10 from XMPP IM. If end users have support for it in their Jabber client, they will be able to: @@ -2564,7 +2595,7 @@ subscription type (or globally). iqdisc

    This specifies the processing discipline for Blocking Communication (jabber:iq:privacy) IQ queries (see section 3.3.2).

    -

    3.3.13  mod_private

    +

    3.3.14  mod_private

    This module adds support for Private XML Storage (XEP-0049):

    Using this method, Jabber entities can store private data on the server and @@ -2576,7 +2607,7 @@ of client-specific preferences; another is Bookmark Storage ( This specifies the processing discipline for Private XML Storage (jabber:iq:private) IQ queries (see section 3.3.2).

    -

    3.3.14  mod_proxy65

    +

    3.3.15  mod_proxy65

    This module implements SOCKS5 Bytestreams (XEP-0065). It allows ejabberd to act as a file transfer proxy between two XMPP clients.

    Options: @@ -2631,7 +2662,7 @@ The simpliest configuration of the module: ... ]}.

    -

    3.3.15  mod_pubsub

    +

    3.3.16  mod_pubsub

    This module offers a Publish-Subscribe Service (XEP-0060). The functionality in mod_pubsub can be extended using plugins. The plugin that implements PEP (Personal Eventing via Pubsub) (XEP-0163) @@ -2677,7 +2708,7 @@ The following example will use node_tune instead of node_pep for every PEP node ... ]}.

    -

    3.3.16  mod_register

    +

    3.3.17  mod_register

    This module adds support for In-Band Registration (XEP-0077). This protocol enables end users to use a Jabber client to:

    • @@ -2750,13 +2781,13 @@ Also define a registration timeout of one hour: ... ]}.

    -

    3.3.17  mod_roster

    +

    3.3.18  mod_roster

    This module implements roster management as defined in RFC 3921: XMPP IM.

    Options:

    iqdisc
    This specifies the processing discipline for Roster Management (jabber:iq:roster) IQ queries (see section 3.3.2).

    -

    3.3.18  mod_service_log

    +

    3.3.19  mod_service_log

    This module adds support for logging end user packets via a Jabber message auditing service such as Bandersnatch. All user @@ -2786,7 +2817,7 @@ To log all end user packets to the Bandersnatch service running on ... ]}.

    -

    3.3.19  mod_shared_roster

    +

    3.3.20  mod_shared_roster

    This module enables you to create shared roster groups. This means that you can create groups of people that can see members from (other) groups in their rosters. The big advantages of this feature are that end users do not need to @@ -2861,7 +2892,7 @@ roster groups as shown in the following table:

    Ejabberd 2.1.0-alpha Feature Sheet

    Sander Devrieze
    +

    Ejabberd 3.0.0-alpha Feature Sheet

    Sander Devrieze
    mailto:s.devrieze@pandora.be
    xmpp:sander@devrieze.dyndns.org

    @@ -120,7 +120,6 @@ Support for virtual hosting.
  • Multi-User Chat module with support for clustering and HTML logging.
  • Users Directory based on users vCards.
  • Publish-Subscribe component with support for Personal Eventing via Pubsub.
  • Support for web clients: HTTP Polling and HTTP Binding (BOSH) services. -
  • IRC transport.
  • Component support: interface with networks such as AIM, ICQ and MSN installing special tranports.
  • diff --git a/doc/guide.html b/doc/guide.html index 81e88646f..f33925a41 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -6,7 +6,7 @@ - ejabberd 2.1.0-alpha + ejabberd 3.0.0-alpha Installation and Operation Guide @@ -76,7 +76,7 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}


    - +
    ejabberd 2.1.0-alpha
    ejabberd 3.0.0-alpha
     
    Installation and Operation Guide

    diff --git a/doc/version.tex b/doc/version.tex index e48c09bfa..ad915bf3d 100644 --- a/doc/version.tex +++ b/doc/version.tex @@ -1,2 +1,2 @@ % ejabberd version (automatically generated). -\newcommand{\version}{2.1.0-alpha} +\newcommand{\version}{3.0.0-alpha} diff --git a/src/ejabberd.app b/src/ejabberd.app index c80650df3..f6d05a07c 100644 --- a/src/ejabberd.app +++ b/src/ejabberd.app @@ -2,7 +2,7 @@ {application, ejabberd, [{description, "ejabberd"}, - {vsn, "2.1.0-alpha"}, + {vsn, "3.0.0-alpha"}, {modules, [acl, adhoc, configure, From a6e8e10a3d6ea25382b40001a33c0bf2c28cacc9 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 17 Jun 2009 09:06:57 +0000 Subject: [PATCH 441/582] Erlang/OTP R13B can be used, but its support is still experimental. SVN Revision: 2327 --- README | 2 +- doc/guide.html | 6 +++--- doc/guide.tex | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README b/README index ac5986191..c76f3188a 100644 --- a/README +++ b/README @@ -9,7 +9,7 @@ To compile ejabberd you need: - GNU Make - GCC - Libexpat 1.95 or higher - - Erlang/OTP R12B-5. R13 is not supported yet. + - Erlang/OTP R12B-5. Support for R13 or higher is experimental. - OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended. - Zlib 1.2.3 or higher, for Stream Compression support diff --git a/doc/guide.html b/doc/guide.html index f33925a41..0589a6e83 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -336,7 +336,7 @@ as long as your system have all the dependencies.

  • GCC
  • Libexpat 1.95 or higher -
  • Erlang/OTP R12B-5. R13 is not supported yet. +
  • Erlang/OTP R12B-5. Support for R13 or higher is experimental.
  • OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended.
  • Zlib 1.2.3 or higher, for Stream Compression support (XEP-0138). Optional.
  • Erlang mysql library. Optional. For MySQL authentication or storage. See section 3.2.1. @@ -457,14 +457,14 @@ for example:

    Requirements

    To compile ejabberd on a Microsoft Windows system, you need:

    Compilation

    We assume that we will try to put as much library as possible into C:\sdk\ to make it easier to track what is install for ejabberd.

    1. -Install Erlang emulator (for example, into C:\sdk\erl5.5.5). +Install Erlang emulator (for example, into C:\sdk\erl5.6.5).
    2. Install Expat library into C:\sdk\Expat-2.0.0 directory.

      Copy file C:\sdk\Expat-2.0.0\Libs\libexpat.dll to your Windows system directory (for example, C:\WINNT or diff --git a/doc/guide.tex b/doc/guide.tex index 7b0b46c47..ee2c5909d 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -300,7 +300,7 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need: \item GNU Make \item GCC \item Libexpat 1.95 or higher -\item Erlang/OTP R12B-5. R13 is not supported yet. +\item Erlang/OTP R12B-5. Support for R13 or higher is experimental. \item OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended. \item Zlib 1.2.3 or higher, for Stream Compression support (\xepref{0138}). Optional. \item Erlang mysql library. Optional. For MySQL authentication or storage. See section \ref{compilemysql}. @@ -485,7 +485,7 @@ gmake -f Makefile.gi ginstall To compile \ejabberd{} on a Microsoft Windows system, you need: \begin{itemize} \item MS Visual C++ 6.0 Compiler -\item \footahref{http://www.erlang.org/download.html}{Erlang/OTP R11B-5} +\item \footahref{http://www.erlang.org/download.html}{Erlang/OTP R12B-5}. Support for R13 or higher is experimental. \item \footahref{http://sourceforge.net/project/showfiles.php?group\_id=10127\&package\_id=11277}{Expat 2.0.0 or higher} \item \footahref{http://www.slproweb.com/products/Win32OpenSSL.html}{Shining Light OpenSSL 0.9.8d or higher} (to enable SSL connections) @@ -498,7 +498,7 @@ To compile \ejabberd{} on a Microsoft Windows system, you need: We assume that we will try to put as much library as possible into \verb|C:\sdk\| to make it easier to track what is install for \ejabberd{}. \begin{enumerate} -\item Install Erlang emulator (for example, into \verb|C:\sdk\erl5.5.5|). +\item Install Erlang emulator (for example, into \verb|C:\sdk\erl5.6.5|). \item Install Expat library into \verb|C:\sdk\Expat-2.0.0| directory. From 0aca6920a7cace52adffd8d71ce3708f3d99a6e7 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 17 Jun 2009 09:07:02 +0000 Subject: [PATCH 442/582] ejabbed 3.0.0 requires exmpp 0.9.1 or higher. SVN Revision: 2328 --- README | 2 ++ doc/guide.html | 2 ++ doc/guide.tex | 2 ++ 3 files changed, 6 insertions(+) diff --git a/README b/README index c76f3188a..3b9ce0aa3 100644 --- a/README +++ b/README @@ -10,6 +10,7 @@ To compile ejabberd you need: - GCC - Libexpat 1.95 or higher - Erlang/OTP R12B-5. Support for R13 or higher is experimental. + - exmpp 0.9.1 or higher - OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended. - Zlib 1.2.3 or higher, for Stream Compression support @@ -17,6 +18,7 @@ To compile ejabberd you need: - Erlang mysql library. Optional. MySQL authentication/storage. - Erlang pgsql library. Optional. PostgreSQL authentication/storage. - PAM library. Optional. For Pluggable Authentication Modules (PAM). + - ImageMagick’s Convert program. Optional. For CAPTCHA challenges. 1. Compile and install on *nix systems diff --git a/doc/guide.html b/doc/guide.html index 0589a6e83..8f5744e5e 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -337,6 +337,7 @@ GNU Make

    3. GCC
    4. Libexpat 1.95 or higher
    5. Erlang/OTP R12B-5. Support for R13 or higher is experimental. +
    6. exmpp 0.9.1 or higher
    7. OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended.
    8. Zlib 1.2.3 or higher, for Stream Compression support (XEP-0138). Optional.
    9. Erlang mysql library. Optional. For MySQL authentication or storage. See section 3.2.1. @@ -458,6 +459,7 @@ for example:

      • MS Visual C++ 6.0 Compiler
      • Erlang/OTP R12B-5. Support for R13 or higher is experimental. +
      • exmpp 0.9.1 or higher
      • Expat 2.0.0 or higher
      • Shining Light OpenSSL 0.9.8d or higher (to enable SSL connections) diff --git a/doc/guide.tex b/doc/guide.tex index ee2c5909d..b667e1dc0 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -301,6 +301,7 @@ To compile \ejabberd{} on a `Unix-like' operating system, you need: \item GCC \item Libexpat 1.95 or higher \item Erlang/OTP R12B-5. Support for R13 or higher is experimental. +\item exmpp 0.9.1 or higher \item OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended. \item Zlib 1.2.3 or higher, for Stream Compression support (\xepref{0138}). Optional. \item Erlang mysql library. Optional. For MySQL authentication or storage. See section \ref{compilemysql}. @@ -486,6 +487,7 @@ To compile \ejabberd{} on a Microsoft Windows system, you need: \begin{itemize} \item MS Visual C++ 6.0 Compiler \item \footahref{http://www.erlang.org/download.html}{Erlang/OTP R12B-5}. Support for R13 or higher is experimental. +\item \footahref{http://support.process-one.net/doc/display/EXMPP}{exmpp 0.9.1 or higher} \item \footahref{http://sourceforge.net/project/showfiles.php?group\_id=10127\&package\_id=11277}{Expat 2.0.0 or higher} \item \footahref{http://www.slproweb.com/products/Win32OpenSSL.html}{Shining Light OpenSSL 0.9.8d or higher} (to enable SSL connections) From b9cbb7a72bedf6de390c23edca72b14723c73fb8 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 22 Jun 2009 23:14:18 +0000 Subject: [PATCH 443/582] Detect auth errors and report in log file. Support auth when domain not provided. SVN Revision: 2331 --- src/web/ejabberd_web_admin.erl | 101 +++++++++++++++++++-------------- 1 file changed, 58 insertions(+), 43 deletions(-) diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 21892def6..f84c608af 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -45,7 +45,6 @@ ?XMLATTR('name', Name), ?XMLATTR('value', Value)])). - process(["doc", LocalFile], _Request) -> DocPath = case os:getenv("EJABBERD_DOC_PATH") of P when is_list(P) -> P; @@ -70,71 +69,87 @@ process(["doc", LocalFile], _Request) -> end end; -process(["server", SHost | RPath], #request{auth = Auth} = Request) -> +process(["server", SHost | RPath], #request{auth = Auth, lang = Lang, host = HostHTTP} = Request) -> Host = exmpp_stringprep:nameprep(SHost), case lists:member(Host, ?MYHOSTS) of true -> - case get_auth(Auth) of - {User, Server} -> - case acl:match_rule( - Host, configure, exmpp_jid:make(User, Server)) of - deny -> - ejabberd_web:error(not_allowed); - allow -> - process_admin( - Host, Request#request{path = RPath, - us = {User, Server}}) - end; - unauthorized -> + case get_auth_admin(Auth, Host, HostHTTP) of + {ok, {User, Server}} -> + process_admin(Host, Request#request{path = RPath, + us = {User, Server}}); + {unauthorized, "no-auth-provided"} -> {401, [{"WWW-Authenticate", "basic realm=\"ejabberd\""}], - ejabberd_web:make_xhtml([#xmlel{ns = ?NS_XHTML, name = 'h1', children = - [#xmlcdata{cdata = <<"401 Unauthorized">>}]}])} + ejabberd_web:make_xhtml([?XCT('h1', "Unauthorized")])}; + {unauthorized, Error} -> + ?WARNING_MSG("Access ~p failed with error: ~p~n~p", + [Auth, Error, Request]), + {401, + [{"WWW-Authenticate", + "basic realm=\"auth error, retry login to ejabberd\""}], + ejabberd_web:make_xhtml([?XCT('h1', "Unauthorized")])} end; false -> ejabberd_web:error(not_found) end; -process(RPath, #request{auth = Auth} = Request) -> - case get_auth(Auth) of - {User, Server} -> - case acl:match_rule( - global, configure, exmpp_jid:make(User, Server)) of - deny -> - ejabberd_web:error(not_allowed); - allow -> - process_admin( - global, Request#request{path = RPath, - us = {User, Server}}) - end; - unauthorized -> - %% XXX bard: any reason to send this data now and not - %% always in case of an 401? ought to check http specs... - {401, +process(RPath, #request{auth = Auth, lang = Lang, host = HostHTTP} = Request) -> + case get_auth_admin(Auth, global, HostHTTP) of + {ok, {User, Server}} -> + process_admin(global, Request#request{path = RPath, + us = {User, Server}}); + {unauthorized, "no-auth-provided"} -> + {401, [{"WWW-Authenticate", "basic realm=\"ejabberd\""}], - ejabberd_web:make_xhtml([#xmlel{ns = ?NS_XHTML, name = 'h1', children = - [#xmlcdata{cdata = <<"401 Unauthorized">>}]}])} + ejabberd_web:make_xhtml([?XCT('h1', "Unauthorized")])}; + {unauthorized, Error} -> + ?WARNING_MSG("Access ~p failed with error: ~p~n~p", + [Auth, Error, Request]), + {401, + [{"WWW-Authenticate", + "basic realm=\"auth error, retry login to ejabberd\""}], + ejabberd_web:make_xhtml([?XCT('h1', "Unauthorized")])} end. -get_auth(Auth) -> +get_auth_admin(Auth, Host, HostHTTP) -> case Auth of - {SJID, P} -> + {SJID, Pass} -> try JID = exmpp_jid:parse(SJID), - U = exmpp_jid:node_as_list(JID), - S = exmpp_jid:domain_as_list(JID), - case ejabberd_auth:check_password(U, S, P) of + User = exmpp_jid:node_as_list(JID), + Server = exmpp_jid:domain_as_list(JID), + case User == undefined of true -> - {U, S}; + %% If only specified username, not username@server + get_auth_account(Host, Server, HostHTTP, Pass); false -> - unauthorized + get_auth_account(Host, User, Server, Pass) end catch _ -> - unauthorized + {unauthorized, "badformed-jid"} end; _ -> - unauthorized + {unauthorized, "no-auth-provided"} + end. + +get_auth_account(Host, User, Server, Pass) -> + case ejabberd_auth:check_password(User, Server, Pass) of + true -> + case acl:match_rule(Host, configure, + exmpp_jid:make(User, Server)) of + deny -> + {unauthorized, "unprivileged-account"}; + allow -> + {ok, {User, Server}} + end; + false -> + case ejabberd_auth:is_user_exists(User, Server) of + true -> + {unauthorized, "bad-password"}; + false -> + {unauthorized, "inexistent-account"} + end end. make_xhtml(Els, Host, Lang) -> From 6ac4157fc173476eaccfde4962779647d78ef343 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 23 Jun 2009 21:13:04 +0000 Subject: [PATCH 444/582] Add Vim folding SVN Revision: 2335 --- src/web/ejabberd_web_admin.erl | 40 +++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index f84c608af..35934d94d 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -24,6 +24,8 @@ %%% %%%---------------------------------------------------------------------- +%%%% definitions + -module(ejabberd_web_admin). -author('alexey@process-one.net'). @@ -45,6 +47,9 @@ ?XMLATTR('name', Name), ?XMLATTR('value', Value)])). +%%%================================== +%%%% process/2 + process(["doc", LocalFile], _Request) -> DocPath = case os:getenv("EJABBERD_DOC_PATH") of P when is_list(P) -> P; @@ -152,6 +157,9 @@ get_auth_account(Host, User, Server, Pass) -> end end. +%%%================================== +%%%% make_xhtml + make_xhtml(Els, Host, Lang) -> make_xhtml(Els, Host, cluster, Lang). @@ -217,6 +225,9 @@ get_base_path(Host, cluster) -> "/admin/server/" ++ Host ++ "/"; get_base_path(global, Node) -> "/admin/node/" ++ atom_to_list(Node) ++ "/"; get_base_path(Host, Node) -> "/admin/server/" ++ Host ++ "/node/" ++ atom_to_list(Node) ++ "/". +%%%================================== +%%%% css & images + additions_js() -> " function selectAll() { @@ -645,6 +656,8 @@ logo_fill() -> "AEFJREFUCNdlw0sRwCAQBUE+gSRHLGABC1jAAhbWAhZwC+88XdXOXb4UlFAr" "SmwN5ekdJY2BkudEec1QvrVQ/r3xOlK9HsTvertmAAAAAElFTkSuQmCC"). +%%%================================== +%%%% process_admin process_admin(global, #request{path = [], @@ -1024,6 +1037,9 @@ process_admin(Host, make_xhtml(Res, Host, Node, Lang) end; +%%%================================== +%%%% process_admin default case + process_admin(Host, #request{lang = Lang} = Request) -> {Hook, Opts} = case Host of global -> {webadmin_page_main, [Request]}; @@ -1034,7 +1050,8 @@ process_admin(Host, #request{lang = Lang} = Request) -> Res -> make_xhtml(Res, Host, Lang) end. - +%%%================================== +%%%% acl acls_to_xhtml(ACLs) -> ?XAE('table', [], @@ -1330,6 +1347,8 @@ parse_access_rule(Text) -> {ok, Rs} end. +%%%================================== +%%%% list_vhosts list_vhosts(Lang) -> Hosts = ?MYHOSTS, @@ -1356,6 +1375,8 @@ list_vhosts(Lang) -> end, SHosts) )])]. +%%%================================== +%%%% list_users list_users(Host, Query, Lang, URLFunc) -> Res = list_users_parse_query(Query, Host), @@ -1503,6 +1524,8 @@ us_to_list({User, Server}) -> su_to_list({Server, User}) -> exmpp_jid:to_list(User, Server, undefined). +%%%================================== +%%%% get_stats get_stats(global, Lang) -> OnlineUsers = mnesia:table_info(session, size), @@ -1705,6 +1728,8 @@ histogram([], _Integral, _Current, Count, Hist) -> lists:reverse(Hist) end. +%%%================================== +%%%% get_nodes get_nodes(Lang) -> RunningNodes = mnesia:system_info(running_db_nodes), @@ -2063,7 +2088,8 @@ get_node(Host, Node, NPath, Query, Lang) -> Res -> Res end. - +%%%================================== +%%%% node parse node_parse_query(Node, Query) -> case lists:keysearch("restart", 1, Query) of @@ -2420,10 +2446,8 @@ pretty_string_int(String) when is_list(String) -> lists:reverse(String)), Result. - -%%% -%%% Navigation Menu -%%% +%%%================================== +%%%% navigation menu %% @spec (Host, Node, Lang) -> [LI] make_navigation(Host, Node, Lang) -> @@ -2550,3 +2574,7 @@ make_menu_item(item, 2, URI, Name, Lang) -> ?LI([?XAE('div', [?XMLATTR('id', <<"navitemsub">>)], [?ACT(URI, Name)] )]); make_menu_item(item, 3, URI, Name, Lang) -> ?LI([?XAE('div', [?XMLATTR('id', <<"navitemsubsub">>)], [?ACT(URI, Name)] )]). + +%%%================================== + +%%% vim: set foldmethod=marker foldmarker=%%%%,%%%=: From e37b26e0685d2dd6a4b7807097808f5dec648993 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 25 Jun 2009 17:04:03 +0000 Subject: [PATCH 445/582] Improvements in the WebAdmin browsing menus. SVN Revision: 2336 --- src/web/ejabberd_web_admin.erl | 284 +++++++++++++++++++++++---------- 1 file changed, 202 insertions(+), 82 deletions(-) diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 35934d94d..209cc76d3 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -47,6 +47,95 @@ ?XMLATTR('name', Name), ?XMLATTR('value', Value)])). +%%%================================== +%%%% get_acl_access + +%% @spec (Path::[string()]) -> {HostOfRule, AccessRule} + +%% All accounts can access those URLs +get_acl_rule([]) -> {"localhost", all}; +get_acl_rule(["style.css"]) -> {"localhost", all}; +get_acl_rule(["logo.png"]) -> {"localhost", all}; +get_acl_rule(["logo-fill.png"]) -> {"localhost", all}; +get_acl_rule(["favicon.ico"]) -> {"localhost", all}; +get_acl_rule(["additions.js"]) -> {"localhost", all}; +%% This page only displays vhosts that the user is admin: +get_acl_rule(["vhosts"]) -> {"localhost", all}; + +%% The pages of a vhost are only accesible if the user is admin of that vhost: +get_acl_rule(["server", VHost | _RPath]) -> {VHost, configure}; + +%% Default rule: only global admins can access any other random page +get_acl_rule(_RPath) -> {global, configure}. + +%%%================================== +%%%% Menu Items Access + +get_jid(Auth, HostHTTP) -> + case get_auth_admin(Auth, HostHTTP, []) of + {ok, {User, Server}} -> + exmpp_jid:make(User, Server, ""); + {unauthorized, Error} -> + ?ERROR_MSG("Unauthorized ~p: ~p", [Auth, Error]), + throw({unauthorized, Auth}) + end. + +get_menu_items(global, cluster, Lang, JID) -> + {Base, _, Items} = make_server_menu([], [], Lang, JID), + lists:map( + fun({URI, Name}) -> + {Base++URI++"/", Name}; + ({URI, Name, _SubMenu}) -> + {Base++URI++"/", Name} + end, + Items + ); +get_menu_items(Host, cluster, Lang, JID) -> + {Base, _, Items} = make_host_menu(Host, [], Lang, JID), + lists:map( + fun({URI, Name}) -> + {Base++URI++"/", Name}; + ({URI, Name, _SubMenu}) -> + {Base++URI++"/", Name} + end, + Items + ); +get_menu_items(Host, Node, Lang, JID) -> + {Base, _, Items} = make_host_node_menu(Host, Node, Lang, JID), + lists:map( + fun({URI, Name}) -> + {Base++URI++"/", Name}; + ({URI, Name, _SubMenu}) -> + {Base++URI++"/", Name} + end, + Items + ). + +is_allowed_path(BasePath, {Path, _}, JID) -> + is_allowed_path(BasePath ++ [Path], JID); +is_allowed_path(BasePath, {Path, _, _}, JID) -> + is_allowed_path(BasePath ++ [Path], JID). + +is_allowed_path(["admin" | Path], JID) -> + is_allowed_path(Path, JID); +is_allowed_path(Path, JID) -> + {HostOfRule, AccessRule} = get_acl_rule(Path), + allow == acl:match_rule(HostOfRule, AccessRule, JID). + +%% @spec(Path) -> URL +%% where Path = [string()] +%% URL = string() +%% Convert ["admin", "user", "tom"] -> "/admin/user/tom/" +%%path_to_url(Path) -> +%% "/" ++ string:join(Path, "/") ++ "/". + +%% @spec(URL) -> Path +%% where Path = [string()] +%% URL = string() +%% Convert "admin/user/tom" -> ["admin", "user", "tom"] +url_to_path(URL) -> + string:tokens(URL, "/"). + %%%================================== %%%% process/2 @@ -74,13 +163,15 @@ process(["doc", LocalFile], _Request) -> end end; -process(["server", SHost | RPath], #request{auth = Auth, lang = Lang, host = HostHTTP} = Request) -> +process(["server", SHost | RPath] = Path, #request{auth = Auth, lang = Lang, host = HostHTTP} = Request) -> Host = exmpp_stringprep:nameprep(SHost), case lists:member(Host, ?MYHOSTS) of true -> - case get_auth_admin(Auth, Host, HostHTTP) of + case get_auth_admin(Auth, HostHTTP, Path) of {ok, {User, Server}} -> + AJID = get_jid(Auth, HostHTTP), process_admin(Host, Request#request{path = RPath, + auth = {auth_jid, Auth, AJID}, us = {User, Server}}); {unauthorized, "no-auth-provided"} -> {401, @@ -99,9 +190,11 @@ process(["server", SHost | RPath], #request{auth = Auth, lang = Lang, host = Hos end; process(RPath, #request{auth = Auth, lang = Lang, host = HostHTTP} = Request) -> - case get_auth_admin(Auth, global, HostHTTP) of + case get_auth_admin(Auth, HostHTTP, RPath) of {ok, {User, Server}} -> + AJID = get_jid(Auth, HostHTTP), process_admin(global, Request#request{path = RPath, + auth = {auth_jid, Auth, AJID}, us = {User, Server}}); {unauthorized, "no-auth-provided"} -> {401, @@ -116,19 +209,20 @@ process(RPath, #request{auth = Auth, lang = Lang, host = HostHTTP} = Request) -> ejabberd_web:make_xhtml([?XCT('h1', "Unauthorized")])} end. -get_auth_admin(Auth, Host, HostHTTP) -> +get_auth_admin(Auth, HostHTTP, RPath) -> case Auth of {SJID, Pass} -> try + {HostOfRule, AccessRule} = get_acl_rule(RPath), JID = exmpp_jid:parse(SJID), User = exmpp_jid:node_as_list(JID), Server = exmpp_jid:domain_as_list(JID), case User == undefined of true -> %% If only specified username, not username@server - get_auth_account(Host, Server, HostHTTP, Pass); + get_auth_account(HostOfRule, AccessRule, User, HostHTTP, Pass); false -> - get_auth_account(Host, User, Server, Pass) + get_auth_account(HostOfRule, AccessRule, User, Server, Pass) end catch _ -> @@ -138,10 +232,10 @@ get_auth_admin(Auth, Host, HostHTTP) -> {unauthorized, "no-auth-provided"} end. -get_auth_account(Host, User, Server, Pass) -> +get_auth_account(HostOfRule, AccessRule, User, Server, Pass) -> case ejabberd_auth:check_password(User, Server, Pass) of true -> - case acl:match_rule(Host, configure, + case acl:match_rule(HostOfRule, AccessRule, exmpp_jid:make(User, Server)) of deny -> {unauthorized, "unprivileged-account"}; @@ -160,15 +254,16 @@ get_auth_account(Host, User, Server, Pass) -> %%%================================== %%%% make_xhtml -make_xhtml(Els, Host, Lang) -> - make_xhtml(Els, Host, cluster, Lang). +make_xhtml(Els, Host, Lang, JID) -> + make_xhtml(Els, Host, cluster, Lang, JID). -%% @spec (Els, Host, Node, Lang) -> {200, [html], xmlelement()} +%% @spec (Els, Host, Node, Lang, JID) -> {200, [html], xmlelement()} %% where Host = global | string() %% Node = cluster | atom() -make_xhtml(Els, Host, Node, Lang) -> +%% JID = jid() +make_xhtml(Els, Host, Node, Lang, JID) -> Base = get_base_path(Host, cluster), %% Enforcing 'cluster' on purpose here - MenuItems = make_navigation(Host, Node, Lang), + MenuItems = make_navigation(Host, Node, Lang, JID), {200, [html], #xmlel{ns = ?NS_XHTML, name = 'html', attrs = [ exmpp_xml:attribute(?NS_XML, 'lang', Lang), @@ -661,41 +756,25 @@ logo_fill() -> process_admin(global, #request{path = [], + auth = {_, _, AJID}, lang = Lang}) -> - Base = get_base_path(global, cluster), - MenuItems2 = make_menu_items(global, cluster, Base, Lang), + %%Base = get_base_path(global, cluster), make_xhtml(?H1GL(?T("Administration"), "toc", "Contents") ++ [?XE('ul', - [?LI([?ACT("/admin/acls/", "Access Control Lists"), ?C(" "), - ?ACT("/admin/acls-raw/", "(Raw)")]), - ?LI([?ACT("/admin/access/", "Access Rules"), ?C(" "), - ?ACT("/admin/access-raw/", "(Raw)")]), - ?LI([?ACT("/admin/vhosts/", "Virtual Hosts")]), - ?LI([?ACT("/admin/nodes/", "Nodes")]), - ?LI([?ACT("/admin/stats/", "Statistics")]) - ] ++ MenuItems2 + [?LI([?ACT(MIU, MIN)]) || {MIU, MIN} <- get_menu_items(global, cluster, Lang, AJID)] ) - ], global, Lang); + ], global, Lang, AJID); process_admin(Host, #request{path = [], + auth = {_, _Auth, AJID}, lang = Lang}) -> - Base = get_base_path(Host, cluster), - MenuItems2 = make_menu_items(Host, cluster, Base, Lang), + %%Base = get_base_path(Host, cluster), make_xhtml([?XCT('h1', "Administration"), ?XE('ul', - [?LI([?ACT(Base ++ "acls/", "Access Control Lists"), ?C(" "), - ?ACT(Base ++ "acls-raw/", "(Raw)")]), - ?LI([?ACT(Base ++ "access/", "Access Rules"), ?C(" "), - ?ACT(Base ++ "access-raw/", "(Raw)")]), - ?LI([?ACT(Base ++ "users/", "Users")]), - ?LI([?ACT(Base ++ "online-users/", "Online Users")]), - ?LI([?ACT(Base ++ "last-activity/", "Last Activity")]), - ?LI([?ACT(Base ++ "nodes/", "Nodes")]), - ?LI([?ACT(Base ++ "stats/", "Statistics")]) - ] ++ MenuItems2 + [?LI([?ACT(MIU, MIN)]) || {MIU, MIN} <- get_menu_items(Host, cluster, Lang, AJID)] ) - ], Host, Lang); + ], Host, Lang, AJID); process_admin(Host, #request{path = ["style.css"]}) -> {200, [{"Content-Type", "text/css"}, last_modified(), cache_control_public()], css(Host)}; @@ -715,6 +794,7 @@ process_admin(_Host, #request{path = ["additions.js"]}) -> process_admin(Host, #request{path = ["acls-raw"], q = Query, + auth = {_, _Auth, AJID}, lang = Lang}) -> Res = case lists:keysearch("acls", 1, Query) of @@ -752,11 +832,12 @@ process_admin(Host, ?BR, ?INPUTT("submit", "submit", "Submit") ]) - ], Host, Lang); + ], Host, Lang, AJID); process_admin(Host, #request{method = Method, path = ["acls"], + auth = {_, _Auth, AJID}, q = Query, lang = Lang}) -> ?DEBUG("query: ~p", [Query]), @@ -795,10 +876,11 @@ process_admin(Host, ?C(" "), ?INPUTT("submit", "submit", "Submit") ]) - ], Host, Lang); + ], Host, Lang, AJID); process_admin(Host, #request{path = ["access-raw"], + auth = {_, _Auth, AJID}, q = Query, lang = Lang}) -> SetAccess = @@ -859,12 +941,13 @@ process_admin(Host, ?BR, ?INPUTT("submit", "submit", "Submit") ]) - ], Host, Lang); + ], Host, Lang, AJID); process_admin(Host, #request{method = Method, path = ["access"], q = Query, + auth = {_, _Auth, AJID}, lang = Lang}) -> ?DEBUG("query: ~p", [Query]), Res = case Method of @@ -895,11 +978,12 @@ process_admin(Host, ?BR, ?INPUTT("submit", "delete", "Delete Selected") ]) - ], Host, Lang); + ], Host, Lang, AJID); process_admin(Host, #request{path = ["access", SName], q = Query, + auth = {_, _Auth, AJID}, lang = Lang}) -> ?DEBUG("query: ~p", [Query]), Name = list_to_atom(SName), @@ -934,36 +1018,41 @@ process_admin(Host, ?BR, ?INPUTT("submit", "submit", "Submit") ]) - ], Host, Lang); + ], Host, Lang, AJID); process_admin(global, #request{path = ["vhosts"], + auth = {_, _Auth, AJID}, lang = Lang}) -> - Res = list_vhosts(Lang), - make_xhtml(?H1GL(?T("ejabberd virtual hosts"), "virtualhost", "Virtual Hosting") ++ Res, global, Lang); + Res = list_vhosts(Lang, AJID), + make_xhtml(?H1GL(?T("ejabberd virtual hosts"), "virtualhost", "Virtual Hosting") ++ Res, global, Lang, AJID); process_admin(Host, #request{path = ["users"], q = Query, + auth = {_, _Auth, AJID}, lang = Lang}) when is_list(Host) -> Res = list_users(Host, Query, Lang, fun url_func/1), - make_xhtml([?XCT('h1', "Users")] ++ Res, Host, Lang); + make_xhtml([?XCT('h1', "Users")] ++ Res, Host, Lang, AJID); process_admin(Host, #request{path = ["users", Diap], + auth = {_, _Auth, AJID}, lang = Lang}) when is_list(Host) -> Res = list_users_in_diapason(Host, Diap, Lang, fun url_func/1), - make_xhtml([?XCT('h1', "Users")] ++ Res, Host, Lang); + make_xhtml([?XCT('h1', "Users")] ++ Res, Host, Lang, AJID); process_admin(Host, #request{ path = ["online-users"], + auth = {_, _Auth, AJID}, lang = Lang}) when is_list(Host) -> Res = list_online_users(Host, Lang), - make_xhtml([?XCT('h1', "Online Users")] ++ Res, Host, Lang); + make_xhtml([?XCT('h1', "Online Users")] ++ Res, Host, Lang, AJID); process_admin(Host, #request{path = ["last-activity"], + auth = {_, _Auth, AJID}, q = Query, lang = Lang}) when is_list(Host) -> ?DEBUG("query: ~p", [Query]), @@ -999,55 +1088,61 @@ process_admin(Host, ?C(" "), ?INPUTT("submit", "integral", "Show Integral Table") ])] ++ - Res, Host, Lang); + Res, Host, Lang, AJID); process_admin(Host, #request{path = ["stats"], + auth = {_, _Auth, AJID}, lang = Lang}) -> Res = get_stats(Host, Lang), - make_xhtml([?XCT('h1', "Statistics")] ++ Res, Host, Lang); + make_xhtml([?XCT('h1', "Statistics")] ++ Res, Host, Lang, AJID); process_admin(Host, #request{path = ["user", U], + auth = {_, _Auth, AJID}, q = Query, lang = Lang}) -> case ejabberd_auth:is_user_exists(U, Host) of true -> Res = user_info(U, Host, Query, Lang), - make_xhtml(Res, Host, Lang); + make_xhtml(Res, Host, Lang, AJID); false -> - make_xhtml([?XCT('h1', "Not Found")], Host, Lang) + make_xhtml([?XCT('h1', "Not Found")], Host, Lang, AJID) end; process_admin(Host, #request{path = ["nodes"], + auth = {_, _Auth, AJID}, lang = Lang}) -> Res = get_nodes(Lang), - make_xhtml(Res, Host, Lang); + make_xhtml(Res, Host, Lang, AJID); process_admin(Host, #request{path = ["node", SNode | NPath], + auth = {_, _Auth, AJID}, q = Query, lang = Lang}) -> case search_running_node(SNode) of false -> - make_xhtml([?XCT('h1', "Node not found")], Host, Lang); + make_xhtml([?XCT('h1', "Node not found")], Host, Lang, AJID); Node -> Res = get_node(Host, Node, NPath, Query, Lang), - make_xhtml(Res, Host, Node, Lang) + make_xhtml(Res, Host, Node, Lang, AJID) end; %%%================================== %%%% process_admin default case -process_admin(Host, #request{lang = Lang} = Request) -> +process_admin(Host, #request{lang = Lang, + auth = {_, _Auth, AJID} + } = Request) -> {Hook, Opts} = case Host of global -> {webadmin_page_main, [Request]}; Host -> {webadmin_page_host, [Host, Request]} end, case ejabberd_hooks:run_fold(Hook, list_to_binary(Host), [], Opts) of - [] -> setelement(1, make_xhtml([?XC('h1', "Not Found")], Host, Lang), 404); - Res -> make_xhtml(Res, Host, Lang) + [] -> setelement(1, make_xhtml([?XC('h1', "Not Found")], Host, Lang, AJID), 404); + Res -> make_xhtml(Res, Host, Lang, AJID) end. %%%================================== @@ -1350,8 +1445,17 @@ parse_access_rule(Text) -> %%%================================== %%%% list_vhosts -list_vhosts(Lang) -> +list_vhosts(Lang, JID) -> Hosts = ?MYHOSTS, + HostsAllowed = lists:filter( + fun(Host) -> + allow == acl:match_rule(Host, configure, JID) + end, + Hosts + ), + list_vhosts2(Lang, HostsAllowed). + +list_vhosts2(Lang, Hosts) -> SHosts = lists:sort(Hosts), [?XE('table', [?XE('thead', @@ -2449,14 +2553,24 @@ pretty_string_int(String) when is_list(String) -> %%%================================== %%%% navigation menu -%% @spec (Host, Node, Lang) -> [LI] -make_navigation(Host, Node, Lang) -> - HostNodeMenu = make_host_node_menu(Host, Node, Lang), - HostMenu = make_host_menu(Host, HostNodeMenu, Lang), - NodeMenu = make_node_menu(Host, Node, Lang), - Menu = make_server_menu(HostMenu, NodeMenu, Lang), +%% @spec (Host, Node, Lang, JID::jid()) -> [LI] +make_navigation(Host, Node, Lang, JID) -> + Menu = make_navigation_menu(Host, Node, Lang, JID), make_menu_items(Lang, Menu). +%% @spec (Host, Node, Lang, JID::jid()) -> Menu +%% where Host = global | string() +%% Node = cluster | string() +%% Lang = string() +%% Menu = {URL, Title} | {URL, Title, [Menu]} +%% URL = string() +%% Title = string() +make_navigation_menu(Host, Node, Lang, JID) -> + HostNodeMenu = make_host_node_menu(Host, Node, Lang, JID), + HostMenu = make_host_menu(Host, HostNodeMenu, Lang, JID), + NodeMenu = make_node_menu(Host, Node, Lang), + make_server_menu(HostMenu, NodeMenu, Lang, JID). + %% @spec (Host, Node, Base, Lang) -> [LI] make_menu_items(global, cluster, Base, Lang) -> HookItems = get_menu_items_hook(server, Lang), @@ -2475,19 +2589,21 @@ make_menu_items(Host, Node, Base, Lang) -> make_menu_items(Lang, {Base, "", HookItems}). -make_host_node_menu(global, _, _Lang) -> +make_host_node_menu(global, _, _Lang, _JID) -> {"", "", []}; -make_host_node_menu(_, cluster, _Lang) -> +make_host_node_menu(_, cluster, _Lang, _JID) -> {"", "", []}; -make_host_node_menu(Host, Node, Lang) -> +make_host_node_menu(Host, Node, Lang, JID) -> HostNodeBase = get_base_path(Host, Node), - HostNodeFixed = [{"modules/", "Modules"}], - HostNodeHook = get_menu_items_hook({hostnode, Host, Node}, Lang), - {HostNodeBase, atom_to_list(Node), HostNodeFixed ++ HostNodeHook}. + HostNodeFixed = [{"modules/", "Modules"}] + ++ get_menu_items_hook({hostnode, Host, Node}, Lang), + HostNodeBasePath = url_to_path(HostNodeBase), + HostNodeFixed2 = [Tuple || Tuple <- HostNodeFixed, is_allowed_path(HostNodeBasePath, Tuple, JID)], + {HostNodeBase, atom_to_list(Node), HostNodeFixed2}. -make_host_menu(global, _HostNodeMenu, _Lang) -> +make_host_menu(global, _HostNodeMenu, _Lang, _JID) -> {"", "", []}; -make_host_menu(Host, HostNodeMenu, Lang) -> +make_host_menu(Host, HostNodeMenu, Lang, JID) -> HostBase = get_base_path(Host, cluster), HostFixed = [{"acls", "Access Control Lists"}, {"access", "Access Rules"}, @@ -2495,9 +2611,11 @@ make_host_menu(Host, HostNodeMenu, Lang) -> {"online-users", "Online Users"}, {"last-activity", "Last Activity"}, {"nodes", "Nodes", HostNodeMenu}, - {"stats", "Statistics"}], - HostHook = get_menu_items_hook({host, Host}, Lang), - {HostBase, Host, HostFixed ++ HostHook}. + {"stats", "Statistics"}] + ++ get_menu_items_hook({host, Host}, Lang), + HostBasePath = url_to_path(HostBase), + HostFixed2 = [Tuple || Tuple <- HostFixed, is_allowed_path(HostBasePath, Tuple, JID)], + {HostBase, Host, HostFixed2}. make_node_menu(_Host, cluster, _Lang) -> {"", "", []}; @@ -2507,21 +2625,23 @@ make_node_menu(global, Node, Lang) -> {"backup/", "Backup"}, {"ports/", "Listened Ports"}, {"stats/", "Statistics"}, - {"update/", "Update"}], - NodeHook = get_menu_items_hook({node, Node}, Lang), - {NodeBase, atom_to_list(Node), NodeFixed ++ NodeHook}; + {"update/", "Update"}] + ++ get_menu_items_hook({node, Node}, Lang), + {NodeBase, atom_to_list(Node), NodeFixed}; make_node_menu(_Host, _Node, _Lang) -> {"", "", []}. -make_server_menu(HostMenu, NodeMenu, Lang) -> +make_server_menu(HostMenu, NodeMenu, Lang, JID) -> Base = get_base_path(global, cluster), Fixed = [{"acls", "Access Control Lists"}, {"access", "Access Rules"}, {"vhosts", "Virtual Hosts", HostMenu}, {"nodes", "Nodes", NodeMenu}, - {"stats", "Statistics"}], - Hook = get_menu_items_hook(server, Lang), - {Base, "ejabberd", Fixed ++ Hook}. + {"stats", "Statistics"}] + ++ get_menu_items_hook(server, Lang), + BasePath = url_to_path(Base), + Fixed2 = [Tuple || Tuple <- Fixed, is_allowed_path(BasePath, Tuple, JID)], + {Base, "ejabberd", Fixed2}. get_menu_items_hook({hostnode, Host, Node}, Lang) -> From 52c0fd8f09dfed7c9241d69dd388d2e02f3f283e Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 25 Jun 2009 17:09:06 +0000 Subject: [PATCH 446/582] Add note about PAM configuration for pam_winbind (thanks to Jon Bendtsen) SVN Revision: 2338 --- doc/guide.html | 2 ++ doc/guide.tex | 2 ++ 2 files changed, 4 insertions(+) diff --git a/doc/guide.html b/doc/guide.html index 8f5744e5e..bf51b3ac0 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -1063,6 +1063,8 @@ to this file, so a malicious user can’t use your configuration to perform attacks.
      • You may want to allow login access only for certain users. pam_listfile.so module provides such functionality. +
      • If you use pam_winbind to authorise against a Windows Active Directory, +then /etc/nssswitch.conf must be configured to use winbind as well.

      3.1.5  Access Rules

      diff --git a/doc/guide.tex b/doc/guide.tex index b667e1dc0..5c7aa1027 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -1267,6 +1267,8 @@ to this file, so a malicious user can't use your configuration to perform brute- attacks. \item You may want to allow login access only for certain users. \term{pam\_listfile.so} module provides such functionality. +\item If you use \term{pam\_winbind} to authorise against a Windows Active Directory, +then \term{/etc/nssswitch.conf} must be configured to use \term{winbind} as well. \end{itemize} \makesubsection{accessrules}{Access Rules} From 82b3790f85b9a04598fed5ae08d8307126840c55 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 25 Jun 2009 18:03:29 +0000 Subject: [PATCH 447/582] Improve explanation about SSL for port 5223 and its option 'tls'. SVN Revision: 2340 --- doc/guide.html | 12 +++++++++--- doc/guide.tex | 12 +++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index bf51b3ac0..4efcc7a17 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -751,8 +751,14 @@ No unencrypted connections will be allowed. You should also set the certfile option. You can define a certificate file for a specific domain using the global option domain_certfile.
      tls
      This option specifies that traffic on -the port will be encrypted using SSL immediately after connecting. You -should also set the certfile option. +the port will be encrypted using SSL immediately after connecting. +This was the traditional encryption method in the early Jabber software, +commonly on port 5223 for client-to-server communications. +But this method is nowadays deprecated and not recommended. +The preferable encryption method is STARTTLS on port 5222, as defined +RFC 3920: XMPP Core, +which can be enabled in ejabberd with the option starttls. +If this option is set, you should also set the certfile option.
      web_admin
      This option enables the Web Admin for ejabberd administration which is available at http://server:port/admin/. Login and password are the username and @@ -762,7 +768,7 @@ password of one of the registered users who are granted access by the option specifies that Zlib stream compression (as defined in XEP-0138) is available on connections to the port. Client connections cannot use stream compression and stream encryption simultaneously. Hence, if you -specify both tls (or ssl) and zlib, the latter +specify both starttls (or tls) and zlib, the latter option will not affect connections (there will be no stream compression).

      There are some additional global options that can be specified in the ejabberd configuration file (outside listen):

      diff --git a/doc/guide.tex b/doc/guide.tex index 5c7aa1027..9a00a964b 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -884,8 +884,14 @@ This is a detailed description of each option allowed by the listening modules: You should also set the \option{certfile} option. You can define a certificate file for a specific domain using the global option \option{domain\_certfile}. \titem{tls} \ind{options!tls}\ind{TLS}This option specifies that traffic on - the port will be encrypted using SSL immediately after connecting. You - should also set the \option{certfile} option. + the port will be encrypted using SSL immediately after connecting. + This was the traditional encryption method in the early Jabber software, + commonly on port 5223 for client-to-server communications. + But this method is nowadays deprecated and not recommended. + The preferable encryption method is STARTTLS on port 5222, as defined + \footahref{http://www.xmpp.org/specs/rfc3920.html\#tls}{RFC 3920: XMPP Core}, + which can be enabled in \ejabberd{} with the option \term{starttls}. + If this option is set, you should also set the \option{certfile} option. \titem{web\_admin} \ind{options!web\_admin}\ind{web admin}This option enables the Web Admin for \ejabberd{} administration which is available at \verb|http://server:port/admin/|. Login and password are the username and @@ -895,7 +901,7 @@ This is a detailed description of each option allowed by the listening modules: option specifies that Zlib stream compression (as defined in \xepref{0138}) is available on connections to the port. Client connections cannot use stream compression and stream encryption simultaneously. Hence, if you - specify both \option{tls} (or \option{ssl}) and \option{zlib}, the latter + specify both \option{starttls} (or \option{tls}) and \option{zlib}, the latter option will not affect connections (there will be no stream compression). \end{description} From ba335346f29d3f2e549bd393cce16c66776c79e3 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 25 Jun 2009 18:05:34 +0000 Subject: [PATCH 448/582] Don't use lists:keyfind/3 bcause it was introduced only in recent R13A. SVN Revision: 2342 --- src/ejabberd_loglevel.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ejabberd_loglevel.erl b/src/ejabberd_loglevel.erl index 2a340606b..dcb23d8a5 100644 --- a/src/ejabberd_loglevel.erl +++ b/src/ejabberd_loglevel.erl @@ -59,8 +59,8 @@ set(_) -> exit("Loglevel must be an integer"). level_to_integer(Level) -> - case lists:keyfind(Level, 2, ?LOG_LEVELS) of - {Int, Level, _Desc} -> Int; + case lists:keysearch(Level, 2, ?LOG_LEVELS) of + {value, {Int, Level, _Desc}} -> Int; _ -> erlang:error({no_such_loglevel, Level}) end. From cdac156f2e7474f92da584725fe76b65ba12c80e Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 30 Jun 2009 16:54:46 +0000 Subject: [PATCH 449/582] Add announcement of offline feature to service discovery (EJAB-234) SVN Revision: 2346 --- src/mod_offline.erl | 23 +++++++++++++++++++++++ src/mod_offline_odbc.erl | 22 ++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/src/mod_offline.erl b/src/mod_offline.erl index c2f3da232..8085d348a 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -35,6 +35,7 @@ store_packet/3, resend_offline_messages/2, pop_offline_messages/3, + get_sm_features/5, remove_expired_messages/0, remove_old_messages/1, remove_user/2, @@ -76,6 +77,10 @@ start(Host, Opts) -> ?MODULE, remove_user, 50), ejabberd_hooks:add(anonymous_purge_hook, HostB, ?MODULE, remove_user, 50), + ejabberd_hooks:add(disco_sm_features, HostB, + ?MODULE, get_sm_features, 50), + ejabberd_hooks:add(disco_local_features, HostB, + ?MODULE, get_sm_features, 50), ejabberd_hooks:add(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), ejabberd_hooks:add(webadmin_user, HostB, @@ -152,6 +157,8 @@ stop(Host) -> ?MODULE, remove_user, 50), ejabberd_hooks:delete(anonymous_purge_hook, HostB, ?MODULE, remove_user, 50), + ejabberd_hooks:delete(disco_sm_features, HostB, ?MODULE, get_sm_features, 50), + ejabberd_hooks:delete(disco_local_features, HostB, ?MODULE, get_sm_features, 50), ejabberd_hooks:delete(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), ejabberd_hooks:delete(webadmin_user, HostB, @@ -162,6 +169,21 @@ stop(Host) -> exit(whereis(Proc), stop), {wait, Proc}. +get_sm_features(Acc, _From, _To, "", _Lang) -> + Feats = case Acc of + {result, I} -> I; + _ -> [] + end, + {result, Feats ++ [?NS_FEATURE_MSGOFFLINE]}; + +get_sm_features(_Acc, _From, _To, ?NS_FEATURE_MSGOFFLINE, _Lang) -> + %% override all lesser features... + {result, []}; + +get_sm_features(Acc, _From, _To, _Node, _Lang) -> + Acc. + + store_packet(From, To, Packet) -> Type = exmpp_stanza:get_type(Packet), if @@ -321,6 +343,7 @@ pop_offline_messages(Ls, User, Server) Ls end. + remove_expired_messages() -> TimeStamp = now(), F = fun() -> diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index 254d75bc2..92de5548a 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -36,6 +36,7 @@ stop/1, store_packet/3, pop_offline_messages/3, + get_sm_features/5, remove_user/2, webadmin_page/3, webadmin_user/4, @@ -70,6 +71,10 @@ start(Host, Opts) -> ?MODULE, remove_user, 50), ejabberd_hooks:add(anonymous_purge_hook, HostB, ?MODULE, remove_user, 50), + ejabberd_hooks:add(disco_sm_features, HostB, + ?MODULE, get_sm_features, 50), + ejabberd_hooks:add(disco_local_features, HostB, + ?MODULE, get_sm_features, 50), ejabberd_hooks:add(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), ejabberd_hooks:add(webadmin_user, HostB, @@ -159,6 +164,8 @@ stop(Host) -> ?MODULE, remove_user, 50), ejabberd_hooks:delete(anonymous_purge_hook, HostB, ?MODULE, remove_user, 50), + ejabberd_hooks:delete(disco_sm_features, HostB, ?MODULE, get_sm_features, 50), + ejabberd_hooks:delete(disco_local_features, HostB, ?MODULE, get_sm_features, 50), ejabberd_hooks:delete(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), ejabberd_hooks:delete(webadmin_user, HostB, @@ -169,6 +176,21 @@ stop(Host) -> exit(whereis(Proc), stop), ok. +get_sm_features(Acc, _From, _To, "", _Lang) -> + Feats = case Acc of + {result, I} -> I; + _ -> [] + end, + {result, Feats ++ [?NS_FEATURE_MSGOFFLINE]}; + +get_sm_features(_Acc, _From, _To, ?NS_FEATURE_MSGOFFLINE, _Lang) -> + %% override all lesser features... + {result, []}; + +get_sm_features(Acc, _From, _To, _Node, _Lang) -> + Acc. + + store_packet(From, To, Packet) -> Type = exmpp_stanza:get_type(Packet), if From 16ca8d178d823be50492c9977f2988a54ee01a79 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 30 Jun 2009 16:55:26 +0000 Subject: [PATCH 450/582] Add XEP82 Date Time, update XEP202 Entity Time and XEP203 Delayed Delivery (EJAB-234) SVN Revision: 2347 --- doc/guide.html | 4 ++-- doc/guide.tex | 6 +++--- src/ejd2odbc.erl | 9 ++++++++- src/jlib.erl | 33 +++++++++++++++++++++++++++++-- src/mod_muc/mod_muc_room.erl | 18 ++++++++++++++--- src/mod_offline.erl | 38 ++++++++++++++++++++++++++---------- src/mod_offline_odbc.erl | 20 +++++++++++++------ src/mod_time.erl | 37 +++++++++++++++++++++++++++++------ 8 files changed, 132 insertions(+), 33 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 4efcc7a17..d40ff02b9 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -1796,7 +1796,7 @@ all entries end with a comma:
  • mod_shared_rosterShared roster managementmod_roster or
      mod_roster_odbc
    mod_statsStatistics Gathering (XEP-0039) 
    mod_timeEntity Time (XEP-0090) 
    mod_timeEntity Time (XEP-0202) 
    mod_vcardvcard-temp (XEP-0054) 
    mod_vcard_ldapvcard-temp (XEP-0054)LDAP server
    mod_vcard_odbcvcard-temp (XEP-0054)supported DB (*)
    mod_muc_logMulti-User Chat room loggingmod_muc
    mod_offlineOffline message storage (XEP-0160) 
    mod_offline_odbcOffline message storage (XEP-0160)supported DB (*)
    mod_pingXMPP Ping and periodic keepalives (XEP-0199) 
    mod_privacyBlocking Communication (XMPP IM) 
    mod_privacy_odbcBlocking Communication (XMPP IM)supported DB (*)
    mod_privatePrivate XML Storage (XEP-0049) 

    -

    3.3.20  mod_stats

    +

    3.3.21  mod_stats

    This module adds support for Statistics Gathering (XEP-0039). This protocol allows you to retrieve next statistics from your ejabberd deployment:

    • @@ -2893,14 +2924,14 @@ by sending: </query> </iq>

    -

    3.3.21  mod_time

    +

    3.3.22  mod_time

    This module features support for Entity Time (XEP-0202). By using this XEP, you are able to discover the time at another entity’s location.

    Options:

    iqdisc
    This specifies the processing discipline for Entity Time (jabber:iq:time) IQ queries (see section 3.3.2).

    -

    3.3.22  mod_vcard

    +

    3.3.23  mod_vcard

    This module allows end users to store and retrieve their vCard, and to retrieve other users vCards, as defined in vcard-temp (XEP-0054). The module also implements an uncomplicated Jabber User Directory based on the vCards of @@ -2955,7 +2986,7 @@ and that all virtual hosts will be searched instead of only the current one: ... ]}.

    -

    3.3.23  mod_vcard_ldap

    +

    3.3.24  mod_vcard_ldap

    ejabberd can map LDAP attributes to vCard fields. This behaviour is implemented in the mod_vcard_ldap module. This module does not depend on the authentication method (see 3.2.5).

    Note that ejabberd treats LDAP as a read-only storage: @@ -3131,7 +3162,7 @@ searching his info in LDAP.

  • ldap_vcard_map
  • -

    3.3.24  mod_version

    +

    3.3.25  mod_version

    This module implements Software Version (XEP-0092). Consequently, it answers ejabberd’s version when queried.

    Options:

    @@ -3140,8 +3171,8 @@ The default value is true.
    iqdisc
    This specifies the processing discipline for Software Version (jabber:iq:version) IQ queries (see section 3.3.2).

    -

    Chapter 4  Managing an ejabberd Server

    -

    4.1  ejabberdctl

    With the ejabberdctl command line administration script +

    Chapter 4  Managing an ejabberd Server

    +

    4.1  ejabberdctl

    With the ejabberdctl command line administration script you can execute ejabberdctl commands (described in the next section, 4.1.1) and also many general ejabberd commands (described in section 4.2). This means you can start, stop and perform many other administrative tasks @@ -3153,7 +3184,7 @@ and other codes may be used for specific results. This can be used by other scripts to determine automatically if a command succeeded or failed, for example using: echo $?

    -

    4.1.1  ejabberdctl Commands

    When ejabberdctl is executed without any parameter, +

    4.1.1  ejabberdctl Commands

    When ejabberdctl is executed without any parameter, it displays the available options. If there isn’t an ejabberd server running, the available parameters are:

    @@ -3189,7 +3220,7 @@ robot1 testuser1 testuser2

    -

    4.1.2  Erlang Runtime System

    ejabberd is an Erlang/OTP application that runs inside an Erlang runtime system. +

    4.1.2  Erlang Runtime System

    ejabberd is an Erlang/OTP application that runs inside an Erlang runtime system. This system is configured using environment variables and command line parameters. The ejabberdctl administration script uses many of those possibilities. You can configure some of them with the file ejabberdctl.cfg, @@ -3262,7 +3293,7 @@ Starts the Erlang system detached from the system console.

    Note that some characters need to be escaped when used in shell scripts, for instance " and {}. You can find other options in the Erlang manual page (erl -man erl).

    -

    4.2  ejabberd Commands

    An ejabberd command is an abstract function identified by a name, +

    4.2  ejabberd Commands

    An ejabberd command is an abstract function identified by a name, with a defined number and type of calling arguments and type of result that is registered in the ejabberd_commands service. Those commands can be defined in any Erlang module and executed using any valid frontend.

    ejabberd includes a frontend to execute ejabberd commands: the script ejabberdctl. @@ -3270,7 +3301,7 @@ Other known frontends that can be installed to execute ejabberd commands in diff ejabberd_xmlrpc (XML-RPC service), mod_rest (HTTP POST service), mod_shcommands (ejabberd WebAdmin page).

    -

    4.2.1  List of ejabberd Commands

    ejabberd includes a few ejabberd Commands by default. +

    4.2.1  List of ejabberd Commands

    ejabberd includes a few ejabberd Commands by default. When more modules are installed, new commands may be available in the frontends.

    The easiest way to get a list of the available commands, and get help for them is to use the ejabberdctl script:

    $ ejabberdctl help
    @@ -3310,7 +3341,7 @@ exist tutorials to migrate
     in offline storage. This might be useful when the number of offline messages
     is very high.
     

    -

    4.2.2  Restrict Execution with AccessCommands

    The frontends can be configured to restrict access to certain commands. +

    4.2.2  Restrict Execution with AccessCommands

    The frontends can be configured to restrict access to certain commands. In that case, authentication information must be provided. In each frontend the AccessCommands option is defined in a different place. But in all cases the option syntax is the same: @@ -3356,7 +3387,7 @@ and the provided arguments do not contradict Arguments.

    As an example to u {_bot_reg_test, [register, unregister], [{host, "test.org"}]} ]

    -

    4.3  Web Admin

    +

    4.3  Web Admin

    The ejabberd Web Admin allows to administer most of ejabberd using a web browser.

    This feature is enabled by default: a ejabberd_http listener with the option web_admin (see section 3.1.3) is included in the listening ports. Then you can open @@ -3428,13 +3459,13 @@ The file is searched by default in The directory of the documentation can be specified in the environment variable EJABBERD_DOC_PATH. See section 4.1.2.

    -

    4.4  Ad-hoc Commands

    If you enable mod_configure and mod_adhoc, +

    4.4  Ad-hoc Commands

    If you enable mod_configure and mod_adhoc, you can perform several administrative tasks in ejabberd with a Jabber client. The client must support Ad-Hoc Commands (XEP-0050), and you must login in the Jabber server with an account with proper privileges.

    -

    4.5  Change Computer Hostname

    ejabberd uses the distributed Mnesia database. +

    4.5  Change Computer Hostname

    ejabberd uses the distributed Mnesia database. Being distributed, Mnesia enforces consistency of its file, so it stores the name of the Erlang node in it (see section 5.4). The name of an Erlang node includes the hostname of the computer. @@ -3471,8 +3502,8 @@ mv /var/lib/ejabberd/*.* /var/lib/ejabberd/oldfiles/

  • Check that the information of the old database is available: accounts, rosters... After you finish, remember to delete the temporary backup files from public directories.
  • -

    Chapter 5  Securing ejabberd

    -

    5.1  Firewall Settings

    +

    Chapter 5  Securing ejabberd

    +

    5.1  Firewall Settings

    You need to take the following TCP ports in mind when configuring your firewall:


    @@ -3483,7 +3514,7 @@ After you finish, remember to delete the temporary backup files from public dire
    PortDescription
    port rangeUsed for connections between Erlang nodes. This range is configurable (see section 5.2).

    -

    5.2  epmd

    epmd (Erlang Port Mapper Daemon) +

    5.2  epmd

    epmd (Erlang Port Mapper Daemon) is a small name server included in Erlang/OTP and used by Erlang programs when establishing distributed Erlang communications. ejabberd needs epmd to use ejabberdctl and also when clustering ejabberd nodes. @@ -3508,7 +3539,7 @@ but can be configured in the file ejabberdctl.cfg. The Erlang command-line parameter used internally is, for example:

    erl ... -kernel inet_dist_listen_min 4370 inet_dist_listen_max 4375
     

    -

    5.3  Erlang Cookie

    The Erlang cookie is a string with numbers and letters. +

    5.3  Erlang Cookie

    The Erlang cookie is a string with numbers and letters. An Erlang node reads the cookie at startup from the command-line parameter -setcookie. If not indicated, the cookie is read from the cookie file $HOME/.erlang.cookie. If this file does not exist, it is created immediately with a random cookie. @@ -3522,7 +3553,7 @@ to prevent unauthorized access or intrusion to an Erlang node. The communication between Erlang nodes are not encrypted, so the cookie could be read sniffing the traffic on the network. The recommended way to secure the Erlang node is to block the port 4369.

    -

    5.4  Erlang Node Name

    An Erlang node may have a node name. +

    5.4  Erlang Node Name

    An Erlang node may have a node name. The name can be short (if indicated with the command-line parameter -sname) or long (if indicated with the parameter -name). Starting an Erlang node with -sname limits the communication between Erlang nodes to the LAN.

    Using the option -sname instead of -name is a simple method @@ -3531,7 +3562,7 @@ However, it is not ultimately effective to prevent access to the Erlang node, because it may be possible to fake the fact that you are on another network using a modified version of Erlang epmd. The recommended way to secure the Erlang node is to block the port 4369.

    -

    5.5  Securing Sensible Files

    ejabberd stores sensible data in the file system either in plain text or binary files. +

    5.5  Securing Sensible Files

    ejabberd stores sensible data in the file system either in plain text or binary files. The file system permissions should be set to only allow the proper user to read, write and execute those files and directories.

    ejabberd configuration file: /etc/ejabberd/ejabberd.cfg
    @@ -3551,9 +3582,9 @@ so it is preferable to secure the whole /var/lib/ejabberd/ directory.
    Erlang cookie file: /var/lib/ejabberd/.erlang.cookie
    See section 5.3.

    -

    Chapter 6  Clustering

    +

    Chapter 6  Clustering

    -

    6.1  How it Works

    +

    6.1  How it Works

    A Jabber domain is served by one or more ejabberd nodes. These nodes can be run on different machines that are connected via a network. They all must have the ability to connect to port 4369 of all another nodes, and must @@ -3567,29 +3598,29 @@ router,

  • session manager,
  • s2s manager.
  • -

    6.1.1  Router

    +

    6.1.1  Router

    This module is the main router of Jabber packets on each node. It routes them based on their destination’s domains. It uses a global routing table. The domain of the packet’s destination is searched in the routing table, and if it is found, the packet is routed to the appropriate process. If not, it is sent to the s2s manager.

    -

    6.1.2  Local Router

    +

    6.1.2  Local Router

    This module routes packets which have a destination domain equal to one of this server’s host names. If the destination JID has a non-empty user part, it is routed to the session manager, otherwise it is processed depending on its content.

    -

    6.1.3  Session Manager

    +

    6.1.3  Session Manager

    This module routes packets to local users. It looks up to which user resource a packet must be sent via a presence table. Then the packet is either routed to the appropriate c2s process, or stored in offline storage, or bounced back.

    -

    6.1.4  s2s Manager

    +

    6.1.4  s2s Manager

    This module routes packets to other Jabber servers. First, it checks if an opened s2s connection from the domain of the packet’s source to the domain of the packet’s destination exists. If that is the case, the s2s manager routes the packet to the process serving this connection, otherwise a new connection is opened.

    -

    6.2  Clustering Setup

    +

    6.2  Clustering Setup

    Suppose you already configured ejabberd on one machine named (first), and you need to setup another one to make an ejabberd cluster. Then do following steps:

    1. @@ -3627,10 +3658,10 @@ and ‘access’ options because they will be taken from enabled only on one machine in the cluster.

    You can repeat these steps for other machines supposed to serve this domain.

    -

    6.3  Service Load-Balancing

    +

    6.3  Service Load-Balancing

    -

    6.3.1  Components Load-Balancing

    -

    6.3.2  Domain Load-Balancing Algorithm

    +

    6.3.1  Components Load-Balancing

    +

    6.3.2  Domain Load-Balancing Algorithm

    ejabberd includes an algorithm to load balance the components that are plugged on an ejabberd cluster. It means that you can plug one or several instances of the same component on each ejabberd cluster and that the traffic will be automatically distributed.

    The default distribution algorithm try to deliver to a local instance of a component. If several local instances are available, one instance is chosen randomly. If no instance is available locally, one instance is chosen randomly among the remote component instances.

    If you need a different behaviour, you can change the load balancing behaviour with the option domain_balancing. The syntax of the option is the following:

    {domain_balancing, "component.example.com", <balancing_criterium>}.
     

    Several balancing criteria are available:

    • @@ -3639,13 +3670,13 @@ domain.

      -

      6.3.3  Load-Balancing Buckets

      +

      6.3.3  Load-Balancing Buckets

      When there is a risk of failure for a given component, domain balancing can cause service trouble. If one component is failing the service will not work correctly unless the sessions are rebalanced.

      In this case, it is best to limit the problem to the sessions handled by the failing component. This is what the domain_balancing_component_number option does, making the load balancing algorithm not dynamic, but sticky on a fix number of component instances.

      The syntax is the following:

      {domain_balancing_component_number, "component.example.com", N}
       

      -

      Chapter 7  Debugging

      +

      Chapter 7  Debugging

      -

      7.1  Log Files

      An ejabberd node writes two log files: +

      7.1  Log Files

      An ejabberd node writes two log files:

      ejabberd.log
      is the ejabberd service log, with the messages reported by ejabberd code
      sasl.log
      is the Erlang/OTP system log, with the messages reported by Erlang/OTP using SASL (System Architecture Support Libraries) @@ -3667,12 +3698,12 @@ The ejabberdctl command reopen-log (please refer to section 4.1.1) reopens the log files, and also renames the old ones if you didn’t rename them.

      -

      7.2  Debug Console

      The Debug Console is an Erlang shell attached to an already running ejabberd server. +

      7.2  Debug Console

      The Debug Console is an Erlang shell attached to an already running ejabberd server. With this Erlang shell, an experienced administrator can perform complex tasks.

      This shell gives complete control over the ejabberd server, so it is important to use it with extremely care. There are some simple and safe examples in the article Interconnecting Erlang Nodes

      To exit the shell, close the window or press the keys: control+c control+c.

      -

      7.3  Watchdog Alerts

      +

      7.3  Watchdog Alerts

      ejabberd includes a watchdog mechanism that may be useful to developers when troubleshooting a problem related to memory usage. If a process in the ejabberd server consumes more memory than the configured threshold, @@ -3690,7 +3721,7 @@ or in a conversation with the watchdog alert bot.

      Example configuration: To remove all watchdog admins, set the option with an empty list:

      {watchdog_admins, []}.
       

      -

      Appendix A  Internationalization and Localization

      +

      Appendix A  Internationalization and Localization

      The source code of ejabberd supports localization. The translators can edit the gettext .po files @@ -3725,9 +3756,9 @@ HTTP header ‘Accept-Language: ru’


    -

    Appendix B  Release Notes

    +

    Appendix B  Release Notes

    Release notes are available from ejabberd Home Page

    -

    Appendix C  Acknowledgements

    Thanks to all people who contributed to this guide: +

    Appendix C  Acknowledgements

    Thanks to all people who contributed to this guide:

    -

    Appendix D  Copyright Information

    Ejabberd Installation and Operation Guide.
    +

    Appendix D  Copyright Information

    Ejabberd Installation and Operation Guide.
    Copyright © 2003 — 2009 ProcessOne

    This document 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 diff --git a/doc/guide.tex b/doc/guide.tex index fbd4d0c49..ecdc6cd7b 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -76,6 +76,7 @@ \newcommand{\modmuclog}{\module{mod\_muc\_log}} \newcommand{\modoffline}{\module{mod\_offline}} \newcommand{\modofflineodbc}{\module{mod\_offline\_odbc}} +\newcommand{\modping}{\module{mod\_ping}} \newcommand{\modprivacy}{\module{mod\_privacy}} \newcommand{\modprivacyodbc}{\module{mod\_privacy\_odbc}} \newcommand{\modprivate}{\module{mod\_private}} @@ -2375,6 +2376,7 @@ The following table lists all modules included in \ejabberd{}. \hline \ahrefloc{modmuclog}{\modmuclog{}} & Multi-User Chat room logging & \modmuc{} \\ \hline \ahrefloc{modoffline}{\modoffline{}} & Offline message storage (\xepref{0160}) & \\ \hline \ahrefloc{modoffline}{\modofflineodbc{}} & Offline message storage (\xepref{0160}) & supported DB (*) \\ + \hline \ahrefloc{modping}{\modping{}} & XMPP Ping and periodic keepalives (\xepref{0199}) & \\ \hline \ahrefloc{modprivacy}{\modprivacy{}} & Blocking Communication (XMPP IM) & \\ \hline \ahrefloc{modprivacy}{\modprivacyodbc{}} & Blocking Communication (XMPP IM) & supported DB (*) \\ \hline \ahrefloc{modprivate}{\modprivate{}} & Private XML Storage (\xepref{0049}) & \\ @@ -3224,7 +3226,8 @@ Examples: \makesubsection{modoffline}{\modoffline{}} \ind{modules!\modoffline{}} -This module implements offline message storage. This means that all messages +This module implements offline message storage (\xepref{0160}). +This means that all messages sent to an offline user will be stored on the server until that user comes online again. Thus it is very similar to how email works. Note that \term{ejabberdctl}\ind{ejabberdctl} has a command to delete expired messages @@ -3260,6 +3263,43 @@ and all the other users up to 100. ]}. \end{verbatim} +\makesubsection{modping}{\modping{}} +\ind{modules!\modping{}} + +This module implements support for XMPP Ping (\xepref{0199}) and periodic keepalives. +When this module is enabled ejabberd responds correctly to +ping requests, as defined in the protocol. + +Configuration options: +\begin{description} + \titem{\{send\_pings, true | false\}}\ind{options!send\_pings} + If this option is set to \term{true}, the server sends pings to connected clients + that are not active in a given interval \term{ping\_interval}. + This is useful to keep client connections alive or checking availability. + By default this option is disabled. + % because it is mostly not needed and consumes resources. + \titem{\{ping\_interval, Seconds\}}\ind{options!ping\_interval} + How often to send pings to connected clients, if the previous option is enabled. + If a client connection does not send or receive any stanza in this interval, + a ping request is sent to the client. + The default value is 60 seconds. + \titem{\{timeout\_action, none | kill\}}\ind{options!timeout\_action} + What to do when a client does not answer to a server ping request in less than 32 seconds. + % Those 32 seconds are defined in ejabberd_local.erl: -define(IQ_TIMEOUT, 32000). + The default is to do nothing. +\end{description} + +This example enables Ping responses, configures the module to send pings +to client connections that are inactive for 4 minutes, +and if a client does not answer to the ping in less than 32 seconds, its connection is closed: +\begin{verbatim} +{modules, + [ + ... + {mod_ping, [{send_pings, true}, {ping_interval, 240}, {timeout_action, kill}]}, + ... + ]}. +\end{verbatim} \makesubsection{modprivacy}{\modprivacy{}} \ind{modules!\modprivacy{}}\ind{Blocking Communication}\ind{Privacy Rules}\ind{protocols!RFC 3921: XMPP IM} diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index 07b9010c8..a23b714be 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -494,6 +494,7 @@ ]}, %%{mod_muc_log,[]}, {mod_offline, [{access_max_user_messages, max_user_offline_messages}]}, + {mod_ping, []}, {mod_privacy, []}, {mod_private, []}, %%{mod_proxy65,[]}, diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index a3af8205a..f77c35a9d 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -32,6 +32,7 @@ %% External exports -export([start/2, + stop/1, start_link/2, send_text/2, send_element/2, @@ -150,6 +151,9 @@ get_presence(FsmRef) -> get_state(FsmRef) -> gen_fsm:sync_send_all_state_event(FsmRef, get_state, 1000). +stop(FsmRef) -> + gen_fsm:send_event(FsmRef, closed). + %%%---------------------------------------------------------------------- %%% Callback functions from gen_fsm %%%---------------------------------------------------------------------- diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 275449deb..e7a0014af 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -33,6 +33,8 @@ -export([start_link/0]). -export([route/3, + route_iq/4, + process_iq_reply/3, register_iq_handler/4, register_iq_handler/5, register_iq_response_handler/4, @@ -52,10 +54,13 @@ -record(state, {}). --record(iq_response, {id, module, function}). +-record(iq_response, {id, module, function, timer}). -define(IQTABLE, local_iqtable). +%% This value is used in SIP and Megaco for a transaction lifetime. +-define(IQ_TIMEOUT, 32000). + % These are the namespace already declared by the stream opening. This is % used at serialization time. -define(DEFAULT_NS, ?NS_JABBER_CLIENT). @@ -94,37 +99,27 @@ process_iq(From, To, Packet) -> Err = exmpp_iq:error(Packet, 'feature-not-implemented'), ejabberd_router:route(To, From, Err) end; - #iq{kind = response} = IQ_Rec -> - process_iq_reply(From, To, IQ_Rec); + #iq{kind = response} = IQReply -> + %%IQReply = jlib:iq_query_or_response_info(IQ_Rec), + process_iq_reply(From, To, IQReply); _ -> Err = exmpp_iq:error(Packet, 'bad-request'), ejabberd_router:route(To, From, Err), ok end. -process_iq_reply(From, To, #iq{id = ID} = IQ_Rec) -> - case catch mnesia:dirty_read(iq_response, ID) of - [] -> +process_iq_reply(From, To, #iq{id = ID} = IQ) -> + case get_iq_callback(ID) of + {ok, undefined, Function} -> + Function(IQ), + ok; + {ok, Module, Function} -> + Module:Function(From, To, IQ), ok; _ -> - F = fun() -> - case mnesia:read({iq_response, ID}) of - [] -> - nothing; - [#iq_response{module = Module, - function = Function}] -> - mnesia:delete({iq_response, ID}), - {Module, Function} - end - end, - case mnesia:transaction(F) of - {atomic, {Module, Function}} -> - Module:Function(From, To, IQ_Rec); - _ -> - ok - end + nothing end. - + route(FromOld, ToOld, #xmlelement{} = PacketOld) -> catch throw(for_stacktrace), % To have a stacktrace. io:format("~nLOCAL: old #xmlelement:~n~p~n~p~n~n", @@ -144,8 +139,21 @@ route(From, To, Packet) -> ok end. +route_iq(From, To, #iq{type = Type} = IQ, F) when is_function(F) -> + Packet = if Type == set; Type == get -> + ID = list_to_binary(randoms:get_string()), + Host = exmpp_jid:prep_domain(From), + register_iq_response_handler(Host, ID, undefined, F), + exmpp_iq:iq_to_xmlel(IQ#iq{id = ID}); + true -> + exmpp_iq:iq_to_xmlel(IQ) + end, + ejabberd_router:route(From, To, Packet). + register_iq_response_handler(Host, ID, Module, Fun) -> - ejabberd_local ! {register_iq_response_handler, Host, ID, Module, Fun}. + gen_server:call(ejabberd_local, + {register_iq_response_handler, + Host, ID, Module, Fun}). register_iq_handler(Host, XMLNS, Module, Fun) -> ejabberd_local ! {register_iq_handler, Host, XMLNS, Module, Fun}. @@ -153,8 +161,9 @@ register_iq_handler(Host, XMLNS, Module, Fun) -> register_iq_handler(Host, XMLNS, Module, Fun, Opts) -> ejabberd_local ! {register_iq_handler, Host, XMLNS, Module, Fun, Opts}. -unregister_iq_response_handler(Host, ID) -> - ejabberd_local ! {unregister_iq_response_handler, Host, ID}. +unregister_iq_response_handler(_Host, ID) -> + catch get_iq_callback(ID), + ok. unregister_iq_handler(Host, XMLNS) -> ejabberd_local ! {unregister_iq_handler, Host, XMLNS}. @@ -186,6 +195,7 @@ init([]) -> ?MODULE, bounce_resource_packet, 100) end, ?MYHOSTS), catch ets:new(?IQTABLE, [named_table, public]), + update_table(), mnesia:create_table(iq_response, [{ram_copies, [node()]}, {attributes, record_info(fields, iq_response)}]), @@ -201,6 +211,14 @@ init([]) -> %% {stop, Reason, State} %% Description: Handling call messages %%-------------------------------------------------------------------- +handle_call({register_iq_response_handler, _Host, + ID, Module, Function}, _From, State) -> + TRef = erlang:start_timer(?IQ_TIMEOUT, self(), ID), + mnesia:dirty_write(#iq_response{id = ID, + module = Module, + function = Function, + timer = TRef}), + {reply, ok, State}; handle_call(_Request, _From, State) -> Reply = ok, {reply, Reply, State}. @@ -239,12 +257,6 @@ handle_info({route, From, To, Packet}, State) -> ok end, {noreply, State}; -handle_info({register_iq_response_handler, _Host, ID, Module, Function}, State) -> - mnesia:dirty_write(#iq_response{id = ID, module = Module, function = Function}), - {noreply, State}; -handle_info({unregister_iq_response_handler, _Host, ID}, State) -> - mnesia:dirty_delete({iq_response, ID}), - {noreply, State}; handle_info({register_iq_handler, Host, XMLNS, Module, Function}, State) -> ets:insert(?IQTABLE, {{XMLNS, Host}, Module, Function}), catch mod_disco:register_feature(Host, XMLNS), @@ -276,6 +288,9 @@ handle_info(refresh_iq_handlers, State) -> end end, ets:tab2list(?IQTABLE)), {noreply, State}; +handle_info({timeout, _TRef, ID}, State) -> + process_iq_timeout(ID), + {noreply, State}; handle_info(_Info, State) -> {noreply, State}. @@ -330,3 +345,52 @@ do_route(From, To, Packet) -> end end. +update_table() -> + case catch mnesia:table_info(iq_response, attributes) of + [id, module, function] -> + mnesia:delete_table(iq_response); + [id, module, function, timer] -> + ok; + {'EXIT', _} -> + ok + end. + +get_iq_callback(ID) -> + case mnesia:dirty_read(iq_response, ID) of + [#iq_response{module = Module, timer = TRef, + function = Function}] -> + cancel_timer(TRef), + mnesia:dirty_delete(iq_response, ID), + {ok, Module, Function}; + _ -> + error + end. + +process_iq_timeout(ID) -> + spawn(fun process_iq_timeout/0) ! ID. + +process_iq_timeout() -> + receive + ID -> + case get_iq_callback(ID) of + {ok, undefined, Function} -> + Function(timeout); + _ -> + ok + end + after 5000 -> + ok + end. + +cancel_timer(TRef) -> + case erlang:cancel_timer(TRef) of + false -> + receive + {timeout, TRef, _} -> + ok + after 0 -> + ok + end; + _ -> + ok + end. diff --git a/src/mod_ping.erl b/src/mod_ping.erl new file mode 100644 index 000000000..e22894333 --- /dev/null +++ b/src/mod_ping.erl @@ -0,0 +1,243 @@ +%%%---------------------------------------------------------------------- +%%% File : mod_ping.erl +%%% Author : Brian Cully +%%% Purpose : Support XEP-0199 XMPP Ping and periodic keepalives +%%% Created : 11 Jul 2009 by Brian Cully +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%%---------------------------------------------------------------------- + +-module(mod_ping). +-author('bjc@kublai.com'). + +-behavior(gen_mod). +-behavior(gen_server). + +-include("ejabberd.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). + +-define(SUPERVISOR, ejabberd_sup). +-define(DEFAULT_SEND_PINGS, false). % bool() +-define(DEFAULT_PING_INTERVAL, 60). % seconds + +-define(DICT, dict). + +%% API +-export([start_link/2, start_ping/2, stop_ping/2]). + +%% gen_mod callbacks +-export([start/2, stop/1]). + +%% gen_server callbacks +-export([init/1, terminate/2, handle_call/3, handle_cast/2, + handle_info/2, code_change/3]). + +%% Hook callbacks +-export([iq_ping/3, user_online/3, user_offline/3, user_send/3]). + +-record(state, {host = "", + send_pings = ?DEFAULT_SEND_PINGS, + ping_interval = ?DEFAULT_PING_INTERVAL, + timeout_action = none, + timers = ?DICT:new()}). + +%%==================================================================== +%% API +%%==================================================================== +start_link(Host, Opts) -> + Proc = gen_mod:get_module_proc(Host, ?MODULE), + gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []). + +start_ping(Host, JID) -> + Proc = gen_mod:get_module_proc(Host, ?MODULE), + gen_server:cast(Proc, {start_ping, JID}). + +stop_ping(Host, JID) -> + Proc = gen_mod:get_module_proc(Host, ?MODULE), + gen_server:cast(Proc, {stop_ping, JID}). + +%%==================================================================== +%% gen_mod callbacks +%%==================================================================== +start(Host, Opts) -> + Proc = gen_mod:get_module_proc(Host, ?MODULE), + PingSpec = {Proc, {?MODULE, start_link, [Host, Opts]}, + transient, 2000, worker, [?MODULE]}, + supervisor:start_child(?SUPERVISOR, PingSpec). + +stop(Host) -> + Proc = gen_mod:get_module_proc(Host, ?MODULE), + gen_server:call(Proc, stop), + supervisor:delete_child(?SUPERVISOR, Proc). + +%%==================================================================== +%% gen_server callbacks +%%==================================================================== +init([Host, Opts]) -> + HostB = list_to_binary(Host), + SendPings = gen_mod:get_opt(send_pings, Opts, ?DEFAULT_SEND_PINGS), + PingInterval = gen_mod:get_opt(ping_interval, Opts, ?DEFAULT_PING_INTERVAL), + TimeoutAction = gen_mod:get_opt(timeout_action, Opts, none), + IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), + mod_disco:register_feature(Host, ?NS_PING), + gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_PING, + ?MODULE, iq_ping, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_local, HostB, ?NS_PING, + ?MODULE, iq_ping, IQDisc), + case SendPings of + true -> + ejabberd_hooks:add(sm_register_connection_hook, HostB, + ?MODULE, user_online, 100), + ejabberd_hooks:add(sm_remove_connection_hook, HostB, + ?MODULE, user_offline, 100), + ejabberd_hooks:add(user_send_packet, HostB, + ?MODULE, user_send, 100); + _ -> + ok + end, + {ok, #state{host = Host, + send_pings = SendPings, + ping_interval = PingInterval, + timeout_action = TimeoutAction, + timers = ?DICT:new()}}. + +terminate(_Reason, #state{host = Host}) -> + HostB = list_to_binary(Host), + ejabberd_hooks:delete(sm_remove_connection_hook, HostB, + ?MODULE, user_offline, 100), + ejabberd_hooks:delete(sm_register_connection_hook, HostB, + ?MODULE, user_online, 100), + ejabberd_hooks:delete(user_send_packet, HostB, + ?MODULE, user_send, 100), + gen_iq_handler:remove_iq_handler(ejabberd_local, HostB, ?NS_PING), + gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_PING), + mod_disco:unregister_feature(Host, ?NS_PING). + +handle_call(stop, _From, State) -> + {stop, normal, ok, State}; +handle_call(_Req, _From, State) -> + {reply, {error, badarg}, State}. + +handle_cast({start_ping, JID}, State) -> + Timers = add_timer(JID, State#state.ping_interval, State#state.timers), + {noreply, State#state{timers = Timers}}; +handle_cast({stop_ping, JID}, State) -> + Timers = del_timer(JID, State#state.timers), + {noreply, State#state{timers = Timers}}; +handle_cast({iq_pong, JID, timeout}, State) -> + Timers = del_timer(JID, State#state.timers), + ejabberd_hooks:run(user_ping_timeout, list_to_binary(State#state.host), [JID]), + case State#state.timeout_action of + kill -> + case ejabberd_sm:get_session_pid(JID) of + Pid when is_pid(Pid) -> + ejabberd_c2s:stop(Pid); + _ -> + ok + end; + _ -> + ok + end, + {noreply, State#state{timers = Timers}}; +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info({timeout, _TRef, {ping, JID}}, State) -> + %%IQ = #iq{type = get, + %% sub_el = [{xmlelement, "ping", [{"xmlns", ?NS_PING}], []}]}, + + %% Build an iq:query request + %%IQ = exmpp_iq:get(?NS_PING, #xmlel{ns = ?NS_PING, name = 'ping'}), + IQ = #iq{type = get, payload = #xmlel{name = 'ping', ns = ?NS_PING}}, + + Pid = self(), + F = fun(Response) -> + gen_server:cast(Pid, {iq_pong, JID, Response}) + end, + From = exmpp_jid:make(State#state.host), + ejabberd_local:route_iq(From, JID, IQ, F), + Timers = add_timer(JID, State#state.ping_interval, State#state.timers), + {noreply, State#state{timers = Timers}}; +handle_info(_Info, State) -> + {noreply, State}. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%==================================================================== +%% Hook callbacks +%%==================================================================== +iq_ping(_From, _To, #iq{type = Type, payload = SubEl} = IQ) -> + case {Type, SubEl} of + {get, #xmlel{name = ping, ns = ?NS_PING}} -> + exmpp_iq:result(IQ); + _ -> + exmpp_iq:error(IQ, 'feature-not-implemented') + end. + +user_online(_SID, JID, _Info) -> + Host = exmpp_jid:prep_domain_as_list(JID), + start_ping(Host, JID). + +user_offline(_SID, JID, _Info) -> + Host = exmpp_jid:prep_domain_as_list(JID), + start_ping(Host, JID). + +user_send(JID, _From, _Packet) -> + Host = exmpp_jid:prep_domain_as_list(JID), + start_ping(Host, JID). + +%%==================================================================== +%% Internal functions +%%==================================================================== +add_timer(JID, Interval, Timers) -> + LJID = exmpp_jid:prep_to_binary(JID), + NewTimers = case ?DICT:find(LJID, Timers) of + {ok, OldTRef} -> + cancel_timer(OldTRef), + ?DICT:erase(LJID, Timers); + _ -> + Timers + end, + TRef = erlang:start_timer(Interval * 1000, self(), {ping, JID}), + ?DICT:store(LJID, TRef, NewTimers). + +del_timer(JID, Timers) -> + LJID = exmpp_jid:prep_to_binary(JID), + case ?DICT:find(LJID, Timers) of + {ok, TRef} -> + cancel_timer(TRef), + ?DICT:erase(LJID, Timers); + _ -> + Timers + end. + +cancel_timer(TRef) -> + case erlang:cancel_timer(TRef) of + false -> + receive + {timeout, TRef, _} -> + ok + after 0 -> + ok + end; + _ -> + ok + end. From 92ad67a814ae60456c9a6a9fc70828507cd46c0a Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Wed, 5 Aug 2009 17:39:47 +0000 Subject: [PATCH 478/582] Fix problems when deleting a roster item. The deleted item was left on the user roster, and unsubscribe presence stanza wasn't sent to the unsubscribed user. SVN Revision: 2420 --- src/mod_roster.erl | 27 +++++++++++---------------- src/mod_roster_odbc.erl | 25 +++++++++++-------------- 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 9d18dd071..564291077 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -271,8 +271,7 @@ process_item_set(From, To, #xmlel{} = El) -> Item2 = process_item_els(Item1, El#xmlel.children), case Item2#roster.subscription of remove -> - send_unsubscribing_presence(From, Item), - ok; + mnesia:delete({roster, {LUser, LServer, LJID}}); _ -> mnesia:write(Item2) end, @@ -725,28 +724,24 @@ send_unsubscribing_presence(From, Item) -> from -> true; _ -> false end, - {INode, IDom, IRes} = Item#roster.jid, - SendToJID = exmpp_jid:make(INode, IDom, IRes), + {INode, IDom, IRes} = Item#roster.jid, + SendToJID = exmpp_jid:make(INode, IDom, IRes), if IsTo -> - send_presence_type( - jlib:jid_remove_resource(From), - SendToJID, "unsubscribe"); + ejabberd_router:route( + exmpp_jid:bare(From), + SendToJID, + exmpp_presence:unsubscribe()); true -> ok end, if IsFrom -> - send_presence_type( - jlib:jid_remove_resource(From), - SendToJID, "unsubscribed"); + ejabberd_router:route( + exmpp_jid:bare(From), + SendToJID, + exmpp_presence:unsubscribed()); true -> ok end, ok. -send_presence_type(From, To, Type) -> - ejabberd_router:route( - From, To, - {xmlelement, "presence", - [{"type", Type}], - []}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 64e125e4a..d79604526 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -253,8 +253,7 @@ process_item_set(From, To, #xmlel{} = El) -> Item2 = process_item_els(Item1, El#xmlel.children), case Item2#roster.subscription of remove -> - send_unsubscribing_presence(From, Item), - ok; + odbc_queries:del_roster(LServer, Username, SJID); _ -> ItemVals = record_to_string(Item2), ItemGroups = groups_to_string(Item2), @@ -661,26 +660,24 @@ send_unsubscribing_presence(From, Item) -> from -> true; _ -> false end, + {INode, IDom, IRes} = Item#roster.jid, + SendToJID = exmpp_jid:make(INode, IDom, IRes), if IsTo -> - send_presence_type( - jlib:jid_remove_resource(From), - jlib:make_jid(Item#roster.jid), "unsubscribe"); + ejabberd_router:route( + exmpp_jid:bare(From), + SendToJID, + exmpp_presence:unsubscribe()); true -> ok end, if IsFrom -> - send_presence_type( - jlib:jid_remove_resource(From), - jlib:make_jid(Item#roster.jid), "unsubscribed"); + ejabberd_router:route( + exmpp_jid:bare(From), + SendToJID, + exmpp_presence:unsubscribed()); true -> ok end, ok. -send_presence_type(From, To, Type) -> - ejabberd_router:route( - From, To, - {xmlelement, "presence", - [{"type", Type}], - []}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% From 6aa3706bec0499f6a2ebaae28694632df9f71815 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 5 Aug 2009 18:23:54 +0000 Subject: [PATCH 479/582] Support XEP-0227 Portable Import/Export (EJAB-993) SVN Revision: 2421 --- doc/guide.html | 14 +- doc/guide.tex | 14 +- src/ejabberd_admin.erl | 17 +- src/ejabberd_piefxis.erl | 640 +++++++++++++++++++++++++++++++++ src/web/ejabberd_web_admin.erl | 69 +++- 5 files changed, 740 insertions(+), 14 deletions(-) create mode 100644 src/ejabberd_piefxis.erl diff --git a/doc/guide.html b/doc/guide.html index bf4ed09ff..7c447dcdb 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -3334,9 +3334,19 @@ Dump internal Mnesia database to a text file dump. Restore immediately from a text file dump. This is not recommended for big databases, as it will consume much time, memory and processor. In that case it’s preferable to use backup and install-fallback. +

    import-piefxis, export-piefxis, export-piefxis-host
    +These options can be used to migrate accounts +using XEP-0227 formatted XML files +from/to other Jabber/XMPP servers +or move users of a vhost to another ejabberd installation. +See also +ejabberd migration kit.
    import-file, import-dir
    -These options can be used to migrate from other Jabber/XMPP servers. There -exist tutorials to migrate from other software to ejabberd. +These options can be used to migrate accounts +using jabberd1.4 formatted XML files. +from other Jabber/XMPP servers +There exist tutorials to +migrate from other software to ejabberd.
    delete-expired-messages
    This option can be used to delete old messages in offline storage. This might be useful when the number of offline messages is very high. diff --git a/doc/guide.tex b/doc/guide.tex index ecdc6cd7b..2f7fbdc21 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -4264,9 +4264,19 @@ The more interesting ones are: memory and processor. In that case it's preferable to use \term{backup} and \term{install-fallback}. %%More information about backuping can %% be found in section~\ref{backup}. +\titem{import-piefxis, export-piefxis, export-piefxis-host} \ind{migrate between servers} + These options can be used to migrate accounts + using \xepref{0227} formatted XML files + from/to other \Jabber{}/XMPP servers + or move users of a vhost to another ejabberd installation. + See also + \footahref{https://support.process-one.net/doc/display/P1/ejabberd+migration+kit}{ejabberd migration kit}. \titem{import-file, import-dir} \ind{migration from other software} - These options can be used to migrate from other \Jabber{}/XMPP servers. There - exist tutorials to \footahref{http://www.ejabberd.im/migrate-to-ejabberd}{migrate from other software to ejabberd}. + These options can be used to migrate accounts + using jabberd1.4 formatted XML files. + from other \Jabber{}/XMPP servers + There exist tutorials to + \footahref{http://www.ejabberd.im/migrate-to-ejabberd}{migrate from other software to ejabberd}. \titem{delete-expired-messages} This option can be used to delete old messages in offline storage. This might be useful when the number of offline messages is very high. diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl index 2c03d10b6..5e81a2b37 100644 --- a/src/ejabberd_admin.erl +++ b/src/ejabberd_admin.erl @@ -33,7 +33,7 @@ %% Accounts register/3, unregister/2, registered_users/1, - %% Migration + %% Migration jabberd1.4 import_file/1, import_dir/1, %% Purge DB delete_expired_messages/0, delete_old_messages/1, @@ -101,11 +101,24 @@ commands() -> module = ?MODULE, function = import_file, args = [{file, string}], result = {res, restuple}}, #ejabberd_commands{name = import_dir, tags = [mnesia], - desc = "Import user data from jabberd14 spool dir", + desc = "Import users data from jabberd14 spool dir", module = ?MODULE, function = import_dir, args = [{file, string}], result = {res, restuple}}, + #ejabberd_commands{name = import_piefxis, tags = [mnesia], + desc = "Import users data from a PIEFXIS file (XEP-0227)", + module = ejabberd_piefxis, function = import_file, + args = [{file, string}], result = {res, rescode}}, + #ejabberd_commands{name = export_piefxis, tags = [mnesia], + desc = "Export data of all users in the server to PIEFXIS files (XEP-0227)", + module = ejabberd_piefxis, function = export_server, + args = [{dir, string}], result = {res, rescode}}, + #ejabberd_commands{name = export_piefxis_host, tags = [mnesia], + desc = "Export data of users in a host to PIEFXIS files (XEP-0227)", + module = ejabberd_piefxis, function = export_host, + args = [{dir, string}, {host, string}], result = {res, rescode}}, + #ejabberd_commands{name = delete_expired_messages, tags = [purge], desc = "Delete expired offline messages from database", module = ?MODULE, function = delete_expired_messages, diff --git a/src/ejabberd_piefxis.erl b/src/ejabberd_piefxis.erl new file mode 100644 index 000000000..1f0540890 --- /dev/null +++ b/src/ejabberd_piefxis.erl @@ -0,0 +1,640 @@ +%%%---------------------------------------------------------------------- +%%% File : ejabberd_piefxis.erl +%%% Author : Pablo Polvorin, Vidal Santiago Martinez +%%% Purpose : XEP-0227: Portable Import/Export Format for XMPP-IM Servers +%%% Created : 17 Jul 2008 by Pablo Polvorin +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%%---------------------------------------------------------------------- + +%%% Not implemented: +%%% - Export from mod_offline_odbc.erl +%%% - Export from mod_private_odbc.erl +%%% - XEP-227: 6. Security Considerations +%%% - Other schemas of XInclude are not tested, and may not be imported correctly. +%%% - If a host has many users, split that host in XML files with 50 users each. + +%%%% Headers + +-module(ejabberd_piefxis). + +-export([import_file/1, export_server/1, export_host/2]). + +-record(parsing_state, {parser, host, dir}). + +-include("ejabberd.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). +-include_lib("exmpp/include/exmpp_client.hrl"). + +%% Copied from mod_private.erl +-record(private_storage, {usns, xml}). + +%%-define(ERROR_MSG(M,Args),io:format(M,Args)). +%%-define(INFO_MSG(M,Args),ok). + +-define(CHUNK_SIZE,1024*20). %20k + +-define(BTL, binary_to_list). +-define(LTB, list_to_binary). + +-define(NS_XINCLUDE, 'http://www.w3.org/2001/XInclude'). + +%%%================================== + +%%%% Import file + +import_file(FileName) -> + import_file(FileName, 2). + +import_file(FileName, RootDepth) -> + try_start_exmpp(), + Dir = filename:dirname(FileName), + {ok, IO} = try_open_file(FileName), + Parser = exmpp_xml:start_parser([{max_size,infinity}, + {root_depth, RootDepth}, + {emit_endtag,true}]), + read_chunks(IO, #parsing_state{parser=Parser, dir=Dir}), + file:close(IO), + exmpp_xml:stop_parser(Parser). + +try_start_exmpp() -> + try exmpp:start() + catch + error:{already_started, exmpp} -> ok; + error:undef -> throw({error, exmpp_not_installed}) + end. + +try_open_file(FileName) -> + case file:open(FileName,[read,binary]) of + {ok, IO} -> {ok, IO}; + {error, enoent} -> throw({error, {file_not_found, FileName}}) + end. + +%%File could be large.. we read it in chunks +read_chunks(IO,State) -> + case file:read(IO,?CHUNK_SIZE) of + {ok,Chunk} -> + NewState = process_chunk(Chunk,State), + read_chunks(IO,NewState); + eof -> + ok + end. + +process_chunk(Chunk,S =#parsing_state{parser=Parser}) -> + case exmpp_xml:parse(Parser,Chunk) of + continue -> + S; + XMLElements -> + process_elements(XMLElements,S) + end. + +%%%================================== +%%%% Process Elements + +process_elements(Elements,State) -> + lists:foldl(fun process_element/2,State,Elements). + +%%%================================== +%%%% Process Element + +process_element(El=#xmlel{name=user, ns=_XMLNS}, + State=#parsing_state{host=Host}) -> + case add_user(El,Host) of + {error, _Other} -> error; + _ -> ok + end, + State; + +process_element(H=#xmlel{name=host},State) -> + State#parsing_state{host=exmpp_xml:get_attribute(H,"jid",none)}; + +process_element(#xmlel{name='server-data'},State) -> + State; + +process_element(El=#xmlel{name=include, ns=?NS_XINCLUDE}, State=#parsing_state{dir=Dir}) -> + case exmpp_xml:get_attribute(El, href, none) of + none -> + ok; + HrefB -> + Href = binary_to_list(HrefB), + %%?INFO_MSG("Parse also this file: ~n~p", [Href]), + FileName = filename:join([Dir, Href]), + import_file(FileName, 1), + Href + end, + State; + +process_element(#xmlcdata{cdata = _CData},State) -> + State; + +process_element(#xmlendtag{ns = _NS, name='server-data'},State) -> + State; + +process_element(#xmlendtag{ns = _NS, name=_Name},State) -> + State; + +process_element(El,State) -> + io:format("Warning!: unknown element found: ~p ~n",[El]), + State. + +%%%================================== +%%%% Add user + +add_user(El, Domain) -> + User = exmpp_xml:get_attribute(El,name,none), + Password = exmpp_xml:get_attribute(El,password,none), + add_user(El, Domain, User, Password). + +%% @spec El = XML element +%% Domain = String with a domain name +%% User = String with an user name +%% Password = String with an user password +%% @ret ok | {atomic, exists} | {error, not_allowed} +%% @doc Add a new user to the database. +%% If user already exists, it will be only updated. +add_user(El, Domain, User, Password) -> + case create_user(User,Password,Domain) of + ok -> + ok = exmpp_xml:foreach( + fun(_,Child) -> + populate_user(User,Domain,Child) + end, + El), + ok; + {atomic, exists} -> + ?INFO_MSG("User ~p@~p already exists, using stored profile...~n", + [User, Domain]), + io:format(""), + ok = exmpp_xml:foreach( + fun(_,Child) -> + populate_user(User,Domain,Child) + end, + El); + {error, Other} -> + ?ERROR_MSG("Error adding user ~s@~s: ~p~n", [User, Domain, Other]) + end. + +%% @spec User = String with User name +%% Password = String with a Password value +%% Domain = Stirng with a Domain name +%% @ret ok | {atomic, exists} | {error, not_allowed} +%% @doc Create a new user +create_user(User,Password,Domain) -> + case ejabberd_auth:try_register(?BTL(User),?BTL(Domain),?BTL(Password)) of + {atomic,ok} -> ok; + {atomic, exists} -> {atomic, exists}; + {error, not_allowed} -> {error, not_allowed}; + Other -> {error, Other} + end. + +%%%================================== +%%%% Populate user + +%% @spec User = String +%% Domain = String +%% El = XML element +%% @ret ok | {error, not_found} +%% +%% @doc Add a new user from a XML file with a roster list. +%% +%% Example of a file: +%% +%% +%% +%% +%% +%% +%% Friends +%% +%% +%% +%% +%% + +populate_user(User,Domain,El=#xmlel{name='query', ns='jabber:iq:roster'}) -> + io:format("Trying to add/update roster list...",[]), + case loaded_module(Domain,[mod_roster_odbc,mod_roster]) of + {ok, M} -> + case M:set_items(User, Domain, El) of + {atomic, ok} -> + io:format(" DONE.~n",[]), + ok; + _ -> + io:format(" ERROR.~n",[]), + ?ERROR_MSG("Error trying to add a new user: ~s ~n", + [exmpp_xml:document_to_list(El)]), + {error, not_found} + end; + E -> io:format(" ERROR: ~p~n",[E]), + ?ERROR_MSG("No modules loaded [mod_roster, mod_roster_odbc] ~s ~n", + [exmpp_xml:document_to_list(El)]), + {error, not_found} + end; + + +%% @spec User = String with the user name +%% Domain = String with a domain name +%% El = Sub XML element with vCard tags values +%% @ret ok | {error, not_found} +%% @doc Read vcards from the XML and send it to the server +%% +%% Example: +%% +%% +%% +%% +%% +%% Admin +%% +%% +%% +%% + +populate_user(User,Domain,El=#xmlel{name='vCard', ns='vcard-temp'}) -> + io:format("Trying to add/update vCards...",[]), + case loaded_module(Domain,[mod_vcard,mod_vcard_odbc]) of + {ok, M} -> FullUser = exmpp_jid:make(User, Domain), + IQ = #iq{type = set, payload = El}, + case M:process_sm_iq(FullUser, FullUser , IQ) of + {error,_Err} -> + io:format(" ERROR.~n",[]), + ?ERROR_MSG("Error processing vcard ~s : ~p ~n", + [exmpp_xml:document_to_list(El), _Err]); + _ -> + io:format(" DONE.~n",[]), ok + end; + _ -> + io:format(" ERROR.~n",[]), + ?ERROR_MSG("No modules loaded [mod_vcard, mod_vcard_odbc] ~s ~n", + [exmpp_xml:document_to_list(El)]), + {error, not_found} + end; + +%% @spec User = String with the user name +%% Domain = String with a domain name +%% El = Sub XML element with offline messages values +%% @ret ok | {error, not_found} +%% @doc Read off-line message from the XML and send it to the server + +populate_user(User,Domain,El=#xmlel{name='offline-messages'}) -> + io:format("Trying to add/update offline-messages...",[]), + case loaded_module(Domain, [mod_offline, mod_offline_odbc]) of + {ok, M} -> + ok = exmpp_xml:foreach( + fun (_Element, {xmlcdata, _}) -> + ok; + (_Element, Child) -> + From = exmpp_xml:get_attribute(Child,from,none), + FullFrom = exmpp_jid:parse(From), + FullUser = exmpp_jid:make(User, Domain), + _R = M:store_packet(FullFrom, FullUser, Child) + end, El), io:format(" DONE.~n",[]); + _ -> + io:format(" ERROR.~n",[]), + ?ERROR_MSG("No modules loaded [mod_offline, mod_offline_odbc] ~s ~n", + [exmpp_xml:document_to_list(El)]), + {error, not_found} + end; + +%% @spec User = String with the user name +%% Domain = String with a domain name +%% El = Sub XML element with private storage values +%% @ret ok | {error, not_found} +%% @doc Private storage parsing + +populate_user(User,Domain,El=#xmlel{name='query', ns='jabber:iq:private'}) -> + io:format("Trying to add/update private storage...",[]), + case loaded_module(Domain,[mod_private_odbc,mod_private]) of + {ok, M} -> + FullUser = exmpp_jid:make(User, Domain), + IQ = #iq{type = set, + ns = 'jabber:iq:private', + kind = request, + iq_ns = 'jabberd:client', + payload = El}, + case M:process_sm_iq(FullUser, FullUser, IQ ) of + {error, _Err} -> + io:format(" ERROR.~n",[]), + ?ERROR_MSG("Error processing private storage ~s : ~p ~n", + [exmpp_xml:document_to_list(El), _Err]); + _ -> io:format(" DONE.~n",[]), ok + end; + _ -> + io:format(" ERROR.~n",[]), + ?ERROR_MSG("No modules loaded [mod_private, mod_private_odbc] ~s~n", + [exmpp_xml:document_to_list(El)]), + {error, not_found} + end; + +populate_user(_User, _Domain, #xmlcdata{cdata = _CData}) -> + ok; + +populate_user(_User, _Domain, _El) -> + ok. + +%%%================================== +%%%% Utilities + +loaded_module(Domain,Options) when is_binary(Domain) -> + loaded_module(?BTL(Domain),Options); +loaded_module(Domain,Options) -> + LoadedModules = gen_mod:loaded_modules(Domain), + case lists:filter(fun(Module) -> + lists:member(Module, LoadedModules) + end, Options) of + [M|_] -> {ok, M}; + [] -> {error,not_found} + end. + +%%%================================== + +%%%% Export server + +%% @spec (Dir::string()) -> ok +export_server(Dir) -> + + FnT = make_filename_template(), + DFn = make_main_basefilename(Dir, FnT), + + {ok, Fd} = file_open(DFn), + print(Fd, make_piefxis_xml_head()), + print(Fd, make_piefxis_server_head()), + + Hosts = ?MYHOSTS, + FilesAndHosts = [{make_host_filename(FnT, Host), Host} || Host <- Hosts], + [print(Fd, make_xinclude(FnH)) || {FnH, _Host} <- FilesAndHosts], + + print(Fd, make_piefxis_server_tail()), + print(Fd, make_piefxis_xml_tail()), + file_close(Fd), + + [export_host(Dir, FnH, Host) || {FnH, Host} <- FilesAndHosts], + + ok. + +%%%================================== +%%%% Export host + +%% @spec (Dir::string(), Host::string()) -> ok +export_host(Dir, Host) -> + FnT = make_filename_template(), + FnH = make_host_filename(FnT, Host), + export_host(Dir, FnH, Host). + +%% @spec (Dir::string(), Fn::string(), Host::string()) -> ok +export_host(Dir, FnH, Host) -> + + DFn = make_host_basefilename(Dir, FnH), + + {ok, Fd} = file_open(DFn), + print(Fd, make_piefxis_xml_head()), + print(Fd, make_piefxis_host_head(Host)), + + Users = ejabberd_auth:get_vh_registered_users(Host), + [export_user(Fd, Username, Host) || {Username, _Host} <- Users], + + print(Fd, make_piefxis_host_tail()), + print(Fd, make_piefxis_xml_tail()), + file_close(Fd). + +%%%================================== +%%%% PIEFXIS formatting + +%% @spec () -> string() +make_piefxis_xml_head() -> + "". + +%% @spec () -> string() +make_piefxis_xml_tail() -> + "". + +%% @spec () -> string() +make_piefxis_server_head() -> + "". + +%% @spec () -> string() +make_piefxis_server_tail() -> + "". + +%% @spec (Host::string()) -> string() +make_piefxis_host_head(Host) -> + NSString = + " xmlns='http://www.xmpp.org/extensions/xep-0227.html#ns'" + " xmlns:xi='http://www.w3.org/2001/XInclude'", + io_lib:format("", [NSString, Host]). + +%% @spec () -> string() +make_piefxis_host_tail() -> + "". + +%% @spec (Fn::string()) -> string() +make_xinclude(Fn) -> + Base = filename:basename(Fn), + io_lib:format("", [Base]). + +%%%================================== +%%%% Export user + +%% @spec (Fd, Username::string(), Host::string()) -> ok +%% extraer su informacion e imprimirla +export_user(Fd, Username, Host) -> + UserString = extract_user(Username, Host), + print(Fd, UserString). + +%% @spec (Username::string(), Host::string()) -> string() +extract_user(Username, Host) -> + Password = ejabberd_auth:get_password_s(Username, Host), + UserInfo = [extract_user_info(InfoName, Username, Host) || InfoName <- [roster, offline, private, vcard]], + UserInfoString = lists:flatten(UserInfo), + io_lib:format("~s", [Username, Password, UserInfoString]). + +%% @spec (InfoName::atom(), Username::string(), Host::string()) -> string() +extract_user_info(roster, Username, Host) -> + case loaded_module(Host,[mod_roster_odbc,mod_roster]) of + {ok, M} -> + From = To = exmpp_jid:make(Username, Host, ""), + SubelGet = exmpp_xml:element(?NS_ROSTER, 'query', [], []), + IQGet = #iq{type=get, ns=?NS_ROSTER, payload=[SubelGet]}, + Res = M:process_local_iq(From, To, IQGet), + case Res#iq.payload of + undefined -> ""; + El -> exmpp_xml:document_to_list(El) + end; + _E -> + "" + end; + +extract_user_info(offline, Username, Host) -> + case loaded_module(Host,[mod_offline,mod_offline_odbc]) of + {ok, mod_offline} -> + Els = mnesia_pop_offline_messages([], Username, Host), + case Els of + [] -> ""; + Els -> + OfEl = {xmlelement, "offline-messages", [], Els}, + exmpp_xml:document_to_list(OfEl) + end; + {ok, mod_offline_odbc} -> + ""; + _E -> + "" + end; + +extract_user_info(private, Username, Host) -> + case loaded_module(Host,[mod_private,mod_private_odbc]) of + {ok, mod_private} -> + get_user_private_mnesia(Username, Host); + {ok, mod_private_odbc} -> + ""; + _E -> + "" + end; + +extract_user_info(vcard, Username, Host) -> + case loaded_module(Host,[mod_vcard, mod_vcard_odbc, mod_vcard_odbc]) of + {ok, M} -> + From = To = exmpp_jid:make(Username, Host, ""), + SubelGet = exmpp_xml:element(?NS_VCARD, 'vCard', [], []), + IQGet = #iq{type=get, ns=?NS_VCARD, payload=[SubelGet]}, + Res = M:process_sm_iq(From, To, IQGet), + case Res#iq.payload of + undefined -> ""; + El -> exmpp_xml:document_to_list(El) + end; + _E -> + "" + end. + +%%%================================== +%%%% Interface with ejabberd offline storage + +%% Copied from mod_offline.erl and customized +-record(offline_msg, {us, timestamp, expire, from, to, packet}). +mnesia_pop_offline_messages(Ls, User, Server) -> + try + LUser = User, + LServer = Server, + US = {LUser, LServer}, + F = fun() -> + Rs = mnesia:wread({offline_msg, US}), + mnesia:delete({offline_msg, US}), + Rs + end, + case mnesia:transaction(F) of + {atomic, Rs} -> + TS = now(), + Ls ++ lists:map( + fun(R) -> + Packet = R#offline_msg.packet, + FromString = exmpp_jid:prep_to_list(R#offline_msg.from), + Packet2 = exmpp_xml:set_attribute(Packet, "from", FromString), + Packet3 = Packet2#xmlel{ns = ?NS_JABBER_CLIENT}, + exmpp_xml:append_children( + Packet3, + [jlib:timestamp_to_xml( + calendar:now_to_universal_time( + R#offline_msg.timestamp), + utc, + exmpp_jid:make("", Server, ""), + "Offline Storage"), + %% TODO: Delete the next three lines once XEP-0091 is Obsolete + jlib:timestamp_to_xml( + calendar:now_to_universal_time( + R#offline_msg.timestamp))] + ) + end, + lists:filter( + fun(R) -> + case R#offline_msg.expire of + never -> + true; + TimeStamp -> + TS < TimeStamp + end + end, + lists:keysort(#offline_msg.timestamp, Rs))); + _ -> + Ls + end + catch + _ -> + Ls + end. + + +%%%================================== +%%%% Interface with ejabberd private storage + +get_user_private_mnesia(Username, Host) -> + ListNsEl = mnesia:dirty_select(private_storage, + [{#private_storage{usns={?LTB(Username), ?LTB(Host), '$1'}, xml = '$2'}, + [], ['$$']}]), + Els = [exmpp_xml:document_to_list(El) || [_Ns, El] <- ListNsEl], + case lists:flatten(Els) of + "" -> ""; + ElsString -> + io_lib:format("~s", [ElsString]) + end. + +%%%================================== +%%%% Disk file access + +%% @spec () -> string() +make_filename_template() -> + {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:local_time(), + lists:flatten( + io_lib:format("~4..0w~2..0w~2..0w-~2..0w~2..0w~2..0w", + [Year, Month, Day, Hour, Minute, Second])). + +%% @spec (Dir::string(), FnT::string()) -> string() +make_main_basefilename(Dir, FnT) -> + Filename2 = filename:flatten([FnT, ".xml"]), + filename:join([Dir, Filename2]). + +%% @spec (FnT::string(), Host::string()) -> FnH::string() +%% FnH = FnT + _ + Host2 + Extension +%% Host2 = Host with any . replaced by _ +%% Example: ("20080804-231550", "jabber.example.org") -> "20080804-231550_jabber_example_org.xml" +make_host_filename(FnT, Host) -> + Host2 = string:join(string:tokens(Host, "."), "_"), + filename:flatten([FnT, "_", Host2, ".xml"]). + +make_host_basefilename(Dir, FnT) -> + filename:join([Dir, FnT]). + +%% @spec (Fn::string()) -> {ok, Fd} +file_open(Fn) -> + file:open(Fn, [write]). + +%% @spec (Fd) -> ok +file_close(Fd) -> + file:close(Fd). + +%% @spec (Fd, String::string()) -> ok +print(Fd, String) -> + io:format(Fd, String, []). + +%%%================================== + +%%% vim: set filetype=erlang tabstop=8 foldmarker=%%%%,%%%= foldmethod=marker: diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 929c6667c..132e49836 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -1979,6 +1979,7 @@ get_node(global, Node, ["db"], Query, Lang) -> end; get_node(global, Node, ["backup"], Query, Lang) -> + HomeDir = re:replace(filename:nativename(os:cmd("echo $HOME")), "\n", "", [{return, list}]), ResS = case node_backup_parse_query(Node, Query) of nothing -> []; ok -> [?XREST("Submitted")]; @@ -1993,14 +1994,14 @@ get_node(global, Node, ["backup"], Query, Lang) -> [?XE('tr', [?XCT('td', "Store binary backup:"), ?XE('td', [?INPUT("text", "storepath", - "ejabberd.backup")]), + filename:join(HomeDir, "ejabberd.backup"))]), ?XE('td', [?INPUTT("submit", "store", "OK")]) ]), ?XE('tr', [?XCT('td', "Restore binary backup immediately:"), ?XE('td', [?INPUT("text", "restorepath", - "ejabberd.backup")]), + filename:join(HomeDir, "ejabberd.backup"))]), ?XE('td', [?INPUTT("submit", "restore", "OK")]) ]), @@ -2008,23 +2009,59 @@ get_node(global, Node, ["backup"], Query, Lang) -> [?XCT('td', "Restore binary backup after next ejabberd restart (requires less memory):"), ?XE('td', [?INPUT("text", "fallbackpath", - "ejabberd.backup")]), + filename:join(HomeDir, "ejabberd.backup"))]), ?XE('td', [?INPUTT("submit", "fallback", "OK")]) ]), ?XE('tr', [?XCT('td', "Store plain text backup:"), ?XE('td', [?INPUT("text", "dumppath", - "ejabberd.dump")]), + filename:join(HomeDir, "ejabberd.dump"))]), ?XE('td', [?INPUTT("submit", "dump", "OK")]) ]), ?XE('tr', [?XCT('td', "Restore plain text backup immediately:"), ?XE('td', [?INPUT("text", "loadpath", - "ejabberd.dump")]), + filename:join(HomeDir, "ejabberd.dump"))]), ?XE('td', [?INPUTT("submit", "load", "OK")]) + ]), + ?XE("tr", + [?XCT("td", "Import users data from a PIEFXIS file (XEP-0277):"), + ?XE("td", [?INPUT("text", "import_piefxis_filepath", + filename:join(HomeDir, "users.xml"))]), + ?XE("td", [?INPUTT("submit", "import_piefxis_file", + "OK")]) + ]), + ?XE("tr", + [?XCT("td", "Export data of all users in the server to PIEFXIS files (XEP-0277):"), + ?XE("td", [?INPUT("text", "export_piefxis_dirpath", + HomeDir)]), + ?XE("td", [?INPUTT("submit", "export_piefxis_dir", + "OK")]) + ]), + ?XE("tr", + [?XE("td", [?CT("Export data of users in a host to PIEFXIS files (XEP-0277):"), + ?CT(" "), + ?INPUT("text", "export_piefxis_host_dirhost", ?MYNAME)]), + ?XE("td", [?INPUT("text", "export_piefxis_host_dirpath", HomeDir)]), + ?XE("td", [?INPUTT("submit", "export_piefxis_host_dir", + "OK")]) + ]), + ?XE("tr", + [?XCT("td", "Import user data from jabberd14 spool file:"), + ?XE("td", [?INPUT("text", "import_filepath", + filename:join(HomeDir, "user1.xml"))]), + ?XE("td", [?INPUTT("submit", "import_file", + "OK")]) + ]), + ?XE("tr", + [?XCT("td", "Import users data from jabberd14 spool directory:"), + ?XE("td", [?INPUT("text", "import_dirpath", + "/var/spool/jabber/")]), + ?XE("td", [?INPUTT("submit", "import_dir", + "OK")]) ]) ]) ])])]; @@ -2303,7 +2340,23 @@ node_backup_parse_query(Node, Query) -> dump_to_textfile, [Path]); "load" -> rpc:call(Node, mnesia, - load_textfile, [Path]) + load_textfile, [Path]); + "import_piefxis_file" -> + rpc:call(Node, ejabberd_piefxis, + import_file, [Path]); + "export_piefxis_dir" -> + rpc:call(Node, ejabberd_piefxis, + export_server, [Path]); + "export_piefxis_host_dir" -> + {value, {_, Host}} = lists:keysearch(Action ++ "host", 1, Query), + rpc:call(Node, ejabberd_piefxis, + export_host, [Path, Host]); + "import_file" -> + rpc:call(Node, ejabberd_admin, + import_file, [Path]); + "import_dir" -> + rpc:call(Node, ejabberd_admin, + import_dir, [Path]) end, case Res of {error, Reason} -> @@ -2321,8 +2374,8 @@ node_backup_parse_query(Node, Query) -> end; (_Action, Res) -> Res - end, nothing, ["store", "restore", "fallback", "dump", "load"]). - + end, nothing, ["store", "restore", "fallback", "dump", "load", "import_file", "import_dir", + "import_piefxis_file", "export_piefxis_dir", "export_piefxis_host_dir"]). node_ports_to_xhtml(Ports, Lang) -> ?XAE('table', [?XMLATTR('class', <<"withtextareas">>)], From 1b85310f1a4134aa6b1f6b337e2c38b6030038c5 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Thu, 6 Aug 2009 15:45:13 +0000 Subject: [PATCH 480/582] Support for roster versioning (EJAB-964) Introduces two options for mod_roster and mod_roster_odbc: - {versioning, true | false} Enable or disable roster versioning on ejabberd. - {store_current_id, true | false} If true, the current roster version is stored on DB (internal or odbc). Otherwise it is calculated on the fly each time. Performance: Setting store_current_id to true should help in reducing the load for both ejabberd and the DB. Details: If store_current_id is false, the roster version is a hash of the entire roster. If store_current_id is true, the roster version is a hash, but of the current time (this has to do with transactional semantics; we need to perform both the roster update and the version update on the same transaction, but we don't have the entire roster when we are changing a single item on DB. Loading it there requires significant changes to be introduced, so I opted for this simpler approach). In either case, there is no difference for the clients, the roster version ID is opaque. IMPORTANT: mod_shared_roster is not compatible with the option 'store_current_id'. Shared roster and roster versioning can be both enabled, but store_current_id MUST be set to false. SVN Revision: 2428 --- src/ejabberd_c2s.erl | 7 ++- src/mod_roster.erl | 125 +++++++++++++++++++++++++++++++++----- src/mod_roster.hrl | 2 + src/mod_roster_odbc.erl | 117 ++++++++++++++++++++++++++++++----- src/odbc/mssql2000.sql | 15 +++++ src/odbc/mysql.sql | 6 ++ src/odbc/odbc_queries.erl | 16 ++++- src/odbc/pg.sql | 5 +- src/roster_versioning.erl | 75 +++++++++++++++++++++++ 9 files changed, 336 insertions(+), 32 deletions(-) create mode 100644 src/roster_versioning.erl diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index f77c35a9d..e61b9e987 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -310,12 +310,17 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> _ -> case StateData#state.resource of undefined -> + RosterVersioningFeature = + case roster_versioning:is_enabled(ServerB) of + true -> [roster_versioning:stream_feature()]; + false -> [] + end, send_element( StateData, exmpp_stream:features([ exmpp_server_binding:feature(), exmpp_server_session:feature() - ])), + | RosterVersioningFeature])), fsm_next_state(wait_for_bind, StateData#state{ server = ServerB, diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 564291077..95c9e9247 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -42,7 +42,8 @@ get_jid_info/4, item_to_xml/1, webadmin_page/3, - webadmin_user/4]). + webadmin_user/4, + roster_versioning_enabled/1]). -include_lib("exmpp/include/exmpp.hrl"). @@ -74,8 +75,11 @@ start(Host, Opts) when is_list(Host) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), mnesia:create_table(roster,[{disc_copies, [node()]}, {attributes, record_info(fields, roster)}]), + mnesia:create_table(roster_version, [{disc_copies, [node()]}, + {attributes, record_info(fields, roster_version)}]), update_table(), mnesia:add_table_index(roster, us), + mnesia:add_table_index(roster_version, us), ejabberd_hooks:add(roster_get, HostB, ?MODULE, get_user_roster, 50), ejabberd_hooks:add(roster_in_subscription, HostB, @@ -127,6 +131,16 @@ stop(Host) when is_list(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_ROSTER). +%% @spec (Host) -> true | false +%% @type Host = binary() +roster_versioning_enabled(Host) -> + gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, versioning, false). + +%% @spec (Host) -> true | false +%% @type Host = binary() +roster_version_on_db(Host) -> + gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, store_current_id, false). + %% @spec (From, To, IQ_Rec) -> IQ_Result %% From = exmpp_jid:jid() %% To = exmpp_jid:jid() @@ -156,23 +170,90 @@ process_local_iq(From, To, #iq{type = set} = IQ_Rec) when ?IS_JID(From), ?IS_JID(To), ?IS_IQ_RECORD(IQ_Rec) -> process_iq_set(From, To, IQ_Rec). +roster_hash(Items) -> + sha:sha(term_to_binary( + lists:sort( + [R#roster{groups = lists:sort(Grs)} || + R = #roster{groups = Grs} <- Items]))). + +roster_version(LServer ,LUser) -> + US = {LUser, LServer}, + case roster_version_on_db(LServer) of + true -> + case mnesia:dirty_read(roster_version, US) of + [#roster_version{version =V}] -> V; + [] -> not_found + end; + false -> + roster_hash(ejabberd_hooks:run_fold(roster_get, LServer, [], [US])) + end. + %% @spec (From, To, IQ_Rec) -> IQ_Result %% From = exmpp_jid:jid() %% To = exmpp_jid:jid() %% IQ_Rec = exmpp_iq:iq() %% IQ_Result = exmpp_iq:iq() - +%% Load roster from DB only if neccesary +%% It is neccesary if +%% - roster versioning is disabled in server OR +%% - roster versioning is not used by the client OR +%% - roster versioning is used by server and client BUT the server isn't storing version IDs on db OR +%% - the roster version from client don't match current version process_iq_get(From, To, IQ_Rec) -> - US = {exmpp_jid:prep_node(From), exmpp_jid:prep_domain(From)}, - case catch ejabberd_hooks:run_fold(roster_get, exmpp_jid:prep_domain(To), [], [US]) of - Items when is_list(Items) -> - XItems = lists:map(fun item_to_xml/1, Items), - Result = #xmlel{ns = ?NS_ROSTER, name = 'query', - children = XItems}, - exmpp_iq:result(IQ_Rec, Result); - _ -> - exmpp_iq:error(IQ_Rec, 'internal-server-error') - end. + US = {_, LServer} = {exmpp_jid:prep_node(From), exmpp_jid:prep_domain(From)}, + try + {ItemsToSend, VersionToSend} = + case {exmpp_xml:get_attribute_as_list(exmpp_iq:get_request(IQ_Rec), ver, not_found), + roster_versioning_enabled(LServer), + roster_version_on_db(LServer)} of + {not_found, _ , _} -> + {lists:map(fun item_to_xml/1, + ejabberd_hooks:run_fold(roster_get, exmpp_jid:prep_domain(To), [], [US])), false}; + {_, false, _} -> + {lists:map(fun item_to_xml/1, + ejabberd_hooks:run_fold(roster_get, exmpp_jid:prep_domain(To), [], [US])), false}; + + {RequestedVersion, true, true} -> + %% Retrieve version from DB. Only load entire roster + %% when neccesary. + case mnesia:dirty_read(roster_version, US) of + [#roster_version{version = RequestedVersion}] -> + {false, false}; + [#roster_version{version = NewVersion}] -> + {lists:map(fun item_to_xml/1, + ejabberd_hooks:run_fold(roster_get, exmpp_jid:prep_domain(To), [], [US])), NewVersion}; + [] -> + RosterVersion = sha:sha(term_to_binary(now())), + mnesia:dirty_write(#roster_version{us = US, version = RosterVersion}), + {lists:map(fun item_to_xml/1, + ejabberd_hooks:run_fold(roster_get, exmpp_jid:prep_domain(To), [], [US])), RosterVersion} + end; + {RequestedVersion, true, false} -> + RosterItems = ejabberd_hooks:run_fold(roster_get, exmpp_jid:prep_domain(To), [] , [US]), + case roster_hash(RosterItems) of + RequestedVersion -> + {false, false}; + New -> + {lists:map(fun item_to_xml/1, RosterItems), New} + end + + end, + case {ItemsToSend, VersionToSend} of + {false, false} -> + exmpp_iq:result(IQ_Rec); + {Items, false} -> + exmpp_iq:result(IQ_Rec, exmpp_xml:element(?NS_ROSTER, 'query', [] , Items)); + {Items, Version} -> + exmpp_iq:result(IQ_Rec, exmpp_xml:element(?NS_ROSTER, 'query', [?XMLATTR('ver', Version)], Items)) + end + catch + _:_ -> + exmpp_iq:error(IQ_Rec, 'internal-server-error') + end. + + + + %% @spec (Acc, US) -> New_Acc %% Acc = [rosteritem()] @@ -279,6 +360,10 @@ process_item_set(From, To, #xmlel{} = El) -> %% subscription information from there: Item3 = ejabberd_hooks:run_fold(roster_process_item, exmpp_jid:prep_domain(From), Item2, [exmpp_jid:prep_domain(From)]), + case roster_version_on_db(LServer) of + true -> mnesia:write(#roster_version{us = {LUser, LServer}, version = sha:sha(term_to_binary(now()))}); + false -> ok + end, {Item, Item3} end, case mnesia:transaction(F) of @@ -389,9 +474,15 @@ push_item(User, Server, From, Item) [{item, Item#roster.jid, Item#roster.subscription}]}), - lists:foreach(fun(Resource) -> - push_item(User, Server, Resource, From, Item) - end, ejabberd_sm:get_user_resources(User, Server)). + + case roster_versioning_enabled(Server) of + true -> + roster_versioning:push_item(Server, User, From, Item, roster_version(Server, User)); + false -> + lists:foreach(fun(Resource) -> + push_item(User, Server, Resource, From, Item) + end, ejabberd_sm:get_user_resources(User, Server)) + end. %% @spec (User, Server, Resource, From, Item) -> term() %% User = binary() @@ -548,6 +639,10 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) ask = Pending, askmessage = AskBinary}, mnesia:write(NewItem), + case roster_version_on_db(Server) of + true -> mnesia:write(#roster_version{us = {User, Server}, version = sha:sha(term_to_binary(now()))}); + false -> ok + end, {{push, NewItem}, AutoReply} end end, diff --git a/src/mod_roster.hrl b/src/mod_roster.hrl index 4278a57b1..242f1d05a 100644 --- a/src/mod_roster.hrl +++ b/src/mod_roster.hrl @@ -29,3 +29,5 @@ askmessage = <<>>, xs = []}). +-record(roster_version, {us, + version}). diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index d79604526..0564e78c8 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -41,7 +41,8 @@ remove_user/2, get_jid_info/4, webadmin_page/3, - webadmin_user/4]). + webadmin_user/4, + roster_versioning_enabled/1]). -include_lib("exmpp/include/exmpp.hrl"). @@ -102,6 +103,12 @@ stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_ROSTER). +roster_versioning_enabled(Host) -> + gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, versioning, false). + +roster_version_on_db(Host) -> + gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, store_current_id, false). + process_iq(From, To, IQ_Rec) -> LServer = exmpp_jid:prep_domain_as_list(From), case lists:member(LServer, ?MYHOSTS) of @@ -118,17 +125,84 @@ process_local_iq(From, To, #iq{type = set} = IQ_Rec) -> +roster_hash(Items) -> + sha:sha(term_to_binary( + lists:sort( + [R#roster{groups = lists:sort(Grs)} || + R = #roster{groups = Grs} <- Items]))). + +roster_version(LServer ,LUser) -> + US = {LUser, LServer}, + case roster_version_on_db(LServer) of + true -> + case odbc_queries:get_roster_version(ejabberd_odbc:escape(LServer), ejabberd_odbc:escape(LUser)) of + {selected, ["version"], [{Version}]} -> Version; + {selected, ["version"], []} -> not_found + end; + false -> + roster_hash(ejabberd_hooks:run_fold(roster_get, LServer, [], [US])) + end. + +%% Load roster from DB only if neccesary. +%% It is neccesary if +%% - roster versioning is disabled in server OR +%% - roster versioning is not used by the client OR +%% - roster versioning is used by server and client, BUT the server isn't storing versions on db OR +%% - the roster version from client don't match current version. process_iq_get(From, To, IQ_Rec) -> - US = {exmpp_jid:prep_node(From), exmpp_jid:prep_domain(From)}, - case catch ejabberd_hooks:run_fold(roster_get, exmpp_jid:prep_domain(To), [], [US]) of - Items when is_list(Items) -> - XItems = lists:map(fun item_to_xml/1, Items), - Result = #xmlel{ns = ?NS_ROSTER, name = 'query', - children = XItems}, - exmpp_iq:result(IQ_Rec, Result); - _ -> - exmpp_iq:error(IQ_Rec, 'internal-server-error') - end. + US = {LUser, LServer} = {exmpp_jid:prep_node(From), exmpp_jid:prep_domain(From)}, + try + {ItemsToSend, VersionToSend} = + case {exmpp_xml:get_attribute_as_list(exmpp_iq:get_request(IQ_Rec), ver, not_found), + roster_versioning_enabled(LServer), + roster_version_on_db(LServer)} of + {not_found, _ , _} -> + {lists:map(fun item_to_xml/1, + ejabberd_hooks:run_fold(roster_get, exmpp_jid:prep_domain(To), [], [US])), false}; + {_, false, _} -> + {lists:map(fun item_to_xml/1, + ejabberd_hooks:run_fold(roster_get, exmpp_jid:prep_domain(To), [], [US])), false}; + + {RequestedVersion, true, true} -> + %% Retrieve version from DB. Only load entire roster + %% when neccesary. + case odbc_queries:get_roster_version(ejabberd_odbc:escape(LServer), ejabberd_odbc:escape(LUser)) of + {selected, ["version"], [{RequestedVersion}]} -> + {false, false}; + {selected, ["version"], [{NewVersion}]} -> + {lists:map(fun item_to_xml/1, + ejabberd_hooks:run_fold(roster_get, exmpp_jid:prep_domain(To), [], [US])), NewVersion}; + {selected, ["version"], []} -> + RosterVersion = sha:sha(term_to_binary(now())), + {atomic, {updated,1}} = odbc_queries:sql_transaction(binary_to_list(LServer), fun() -> + odbc_queries:set_roster_version(ejabberd_odbc:escape(LUser), RosterVersion) + end), + {lists:map(fun item_to_xml/1, + ejabberd_hooks:run_fold(roster_get, exmpp_jid:prep_domain(To), [], [US])), RosterVersion} + end; + + {RequestedVersion, true, false} -> + RosterItems = ejabberd_hooks:run_fold(roster_get, exmpp_jid:prep_domain(To), [] , [US]), + case roster_hash(RosterItems) of + RequestedVersion -> + {false, false}; + New -> + {lists:map(fun item_to_xml/1, RosterItems), New} + end + + end, + case {ItemsToSend, VersionToSend} of + {false, false} -> + exmpp_iq:result(IQ_Rec); + {Items, false} -> + exmpp_iq:result(IQ_Rec, exmpp_xml:element(?NS_ROSTER, 'query', [] , Items)); + {Items, Version} -> + exmpp_iq:result(IQ_Rec, exmpp_xml:element(?NS_ROSTER, 'query', [?XMLATTR('ver', Version)], Items)) + end + catch + _:_ -> + exmpp_iq:error(IQ_Rec, 'internal-server-error') + end. get_user_roster(Acc, {LUser, LServer}) -> Items = get_roster(LUser, LServer), @@ -263,6 +337,11 @@ process_item_set(From, To, #xmlel{} = El) -> %% subscription information from there: Item3 = ejabberd_hooks:run_fold(roster_process_item, exmpp_jid:prep_domain(From), Item2, [exmpp_jid:prep_domain(From)]), + case roster_version_on_db(Server) of + true -> odbc_queries:set_roster_version(Username, sha:sha(term_to_binary(now()))); + false -> ok + end, + {Item, Item3} end, case odbc_queries:sql_transaction(LServer, F) of @@ -352,9 +431,15 @@ push_item(User, Server, From, Item) when is_binary(User), is_binary(Server) -> [{item, Item#roster.jid, Item#roster.subscription}]}), - lists:foreach(fun(Resource) -> - push_item(User, Server, Resource, From, Item) - end, ejabberd_sm:get_user_resources(User, Server)). + case roster_versioning_enabled(Server) of + true -> + roster_versioning:push_item(Server, User, From, Item, roster_version(Server, User)); + false -> + lists:foreach(fun(Resource) -> + push_item(User, Server, Resource, From, Item) + end, ejabberd_sm:get_user_resources(User, Server)) + end. + % TODO: don't push to those who not load roster push_item(User, Server, Resource, From, Item) -> @@ -492,6 +577,10 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) askmessage = AskBinary}, ItemVals = record_to_string(NewItem), odbc_queries:roster_subscribe(LServer, Username, SJID, ItemVals), + case roster_version_on_db(Server) of + true -> odbc_queries:set_roster_version(Username, sha:sha(term_to_binary(now()))); + false -> ok + end, {{push, NewItem}, AutoReply} end end, diff --git a/src/odbc/mssql2000.sql b/src/odbc/mssql2000.sql index 1bb93d783..176ff8300 100644 --- a/src/odbc/mssql2000.sql +++ b/src/odbc/mssql2000.sql @@ -209,6 +209,14 @@ CREATE TABLE [dbo].[privacy_list_data] ( ) ON [PRIMARY] GO +/* Not tested on mssql */ +CREATE TABLE [dbo].[roster_version] ( + [username] [varchar] (250) NOT NULL , + [version] [varchar] (64) NOT NULL +) ON [PRIMARY] +GO + + /* Constraints to add: - id in privacy_list is a SERIAL autogenerated number - id in privacy_list_data must exist in the table privacy_list */ @@ -244,6 +252,13 @@ ALTER TABLE [dbo].[users] WITH NOCHECK ADD ) WITH FILLFACTOR = 90 ON [PRIMARY] GO +ALTER TABLE [dbo].[roster_version] WITH NOCHECK ADD + CONSTRAINT [PK_roster_version] PRIMARY KEY CLUSTERED + ( + [username] + ) WITH FILLFACTOR = 90 ON [PRIMARY] +GO + ALTER TABLE [dbo].[vcard] WITH NOCHECK ADD CONSTRAINT [PK_vcard] PRIMARY KEY CLUSTERED ( diff --git a/src/odbc/mysql.sql b/src/odbc/mysql.sql index e975b9231..dfbf69437 100644 --- a/src/odbc/mysql.sql +++ b/src/odbc/mysql.sql @@ -148,6 +148,12 @@ CREATE TABLE private_storage ( CREATE INDEX i_private_storage_username USING BTREE ON private_storage(username); CREATE UNIQUE INDEX i_private_storage_username_namespace USING BTREE ON private_storage(username(75), namespace(75)); +-- Not tested in mysql +CREATE TABLE roster_version ( + username varchar(250) PRIMARY KEY, + version text NOT NULL +) CHARACTER SET utf8; + -- To update from 1.x: -- ALTER TABLE rosterusers ADD COLUMN askmessage text AFTER ask; -- UPDATE rosterusers SET askmessage = ''; diff --git a/src/odbc/odbc_queries.erl b/src/odbc/odbc_queries.erl index ef1f59218..eeeebdddc 100644 --- a/src/odbc/odbc_queries.erl +++ b/src/odbc/odbc_queries.erl @@ -78,7 +78,9 @@ set_vcard/26, get_vcard/2, escape/1, - count_records_where/3]). + count_records_where/3, + get_roster_version/2, + set_roster_version/2]). %% We have only two compile time options for db queries: %-define(generic, true). @@ -555,6 +557,12 @@ count_records_where(LServer, Table, WhereClause) -> ejabberd_odbc:sql_query( LServer, ["select count(*) from ", Table, " ", WhereClause, ";"]). + +get_roster_version(LServer, LUser) -> + ejabberd_odbc:sql_query(LServer, + ["select version from roster_version where username = '", LUser, "'"]). +set_roster_version(LUser, Version) -> + update_t("roster_version", ["username", "version"], [LUser, Version], ["username = '", LUser, "'"]). -endif. %% ----------------- @@ -791,4 +799,10 @@ count_records_where(LServer, Table, WhereClause) -> ejabberd_odbc:sql_query( LServer, ["select count(*) from ", Table, " ", WhereClause, " with (nolock)"]). + +get_roster_version(LServer, LUser) -> + ejabberd_odbc:sql_query(LServer, + ["select version from dbo.roster_version where username = '", LUser, "'"]). +set_roster_version(LUser, Version) -> + update_t("dbo.roster_version", ["username", "version"], [LUser, Version], ["username = '", LUser, "'"]). -endif. diff --git a/src/odbc/pg.sql b/src/odbc/pg.sql index 3cf3a0949..60df5a195 100644 --- a/src/odbc/pg.sql +++ b/src/odbc/pg.sql @@ -145,7 +145,10 @@ CREATE TABLE private_storage ( CREATE INDEX i_private_storage_username ON private_storage USING btree (username); CREATE UNIQUE INDEX i_private_storage_username_namespace ON private_storage USING btree (username, namespace); - +CREATE TABLE roster_version ( + username text PRIMARY KEY, + version text NOT NULL +); -- To update from 0.9.8: -- CREATE SEQUENCE spool_seq_seq; -- ALTER TABLE spool ADD COLUMN seq integer; diff --git a/src/roster_versioning.erl b/src/roster_versioning.erl new file mode 100644 index 000000000..1aa7e4e3b --- /dev/null +++ b/src/roster_versioning.erl @@ -0,0 +1,75 @@ +%%%---------------------------------------------------------------------- +%%% File : mod_roster.erl +%%% Author : Pablo Polvorin +%%% Purpose : Common utility functions for XEP-0237 (Roster Versioning) +%%% Created : 19 Jul 2009 by Pablo Polvorin +%%% +%%% +%%% ejabberd, Copyright (C) 2009 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%% +%%% @doc The roster versioning follows an all-or-nothing strategy: +%%% - If the version supplied by the client is the lastest, return an empty response +%%% - If not, return the entire new roster (with updated version string). +%%% Roster version is a hash digest of the entire roster. +%%% No additional data is stored in DB. +%%%---------------------------------------------------------------------- +-module(roster_versioning). +-author('pablo.polvorin@process-one.net'). + +%%API +-export([is_enabled/1, + stream_feature/0, + push_item/5]). + + +-include("mod_roster.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). + +-define(NS_ROSTER_VER, "urn:xmpp:features:rosterver"). + +%%@doc is roster versioning enabled? +is_enabled(Host) -> + case gen_mod:is_loaded(binary_to_list(Host), mod_roster) of + true -> mod_roster:roster_versioning_enabled(Host); + false -> mod_roster_odbc:roster_versioning_enabled(Host) + end. + +stream_feature() -> + exmpp_xml:element(?NS_ROSTER_VER, 'ver', [], [exmpp_xml:element(?NS_ROSTER_VER, 'optional')]). + + + + +%% @doc Roster push, calculate and include the version attribute. +%% TODO: don't push to those who didn't load roster +push_item(Server, User, From, Item, RosterVersion) -> + lists:foreach(fun(Resource) -> + push_item(User, Server, Resource, From, Item, RosterVersion) + end, ejabberd_sm:get_user_resources(User, Server)). + +push_item(User, Server, Resource, From, Item, RosterVersion) -> + Request = #xmlel{ns = ?NS_ROSTER, name = 'query', attrs = [?XMLATTR('ver', RosterVersion)], + children = [mod_roster:item_to_xml(Item)]}, + ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request, + "push" ++ randoms:get_string()), + ejabberd_router:route( + From, + exmpp_jid:make(User, Server, Resource), + ResIQ). + From 4f6b67b190d20a14b8c94c209bdcd2c3e4040080 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 6 Aug 2009 21:07:18 +0000 Subject: [PATCH 481/582] Move functions from roster_versioning to mod_roster (EJAB-964) SVN Revision: 2431 --- src/ejabberd_c2s.erl | 6 +--- src/mod_roster.erl | 65 +++++++++++++++++++++++++++------ src/mod_roster_odbc.erl | 60 +++++++++++++++++++++++++++---- src/roster_versioning.erl | 75 --------------------------------------- 4 files changed, 108 insertions(+), 98 deletions(-) delete mode 100644 src/roster_versioning.erl diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index e61b9e987..7e1ee9509 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -310,11 +310,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> _ -> case StateData#state.resource of undefined -> - RosterVersioningFeature = - case roster_versioning:is_enabled(ServerB) of - true -> [roster_versioning:stream_feature()]; - false -> [] - end, + RosterVersioningFeature = ejabberd_hooks:run_fold(roster_get_versioning_feature, Server, [], [Server]), send_element( StateData, exmpp_stream:features([ diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 95c9e9247..e2c017d54 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -24,6 +24,15 @@ %%% %%%---------------------------------------------------------------------- +%%% @doc Roster management (Mnesia storage). +%%% +%%% Includes support for XEP-0237: Roster Versioning. +%%% The roster versioning follows an all-or-nothing strategy: +%%% - If the version supplied by the client is the latest, return an empty response. +%%% - If not, return the entire new roster (with updated version string). +%%% Roster version is a hash digest of the entire roster. +%%% No additional data is stored in DB. + -module(mod_roster). -author('alexey@process-one.net'). @@ -43,6 +52,7 @@ item_to_xml/1, webadmin_page/3, webadmin_user/4, + get_versioning_feature/2, roster_versioning_enabled/1]). -include_lib("exmpp/include/exmpp.hrl"). @@ -52,6 +62,8 @@ -include("web/ejabberd_http.hrl"). -include("web/ejabberd_web_admin.hrl"). +-define(NS_ROSTER_VER, "urn:xmpp:features:rosterver"). + %% @type rosteritem() = {roster, USJ, US, Contact_JID, Name, Subscription, Ask, Groups, Askmessage, Xs} %% USJ = {LUser, LServer, Prepd_Contact_JID} %% LUser = binary() @@ -96,6 +108,8 @@ start(Host, Opts) when is_list(Host) -> ?MODULE, remove_user, 50), ejabberd_hooks:add(resend_subscription_requests_hook, HostB, ?MODULE, get_in_pending_subscriptions, 50), + ejabberd_hooks:add(roster_get_versioning_feature, HostB, + ?MODULE, get_versioning_feature, 50), ejabberd_hooks:add(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), ejabberd_hooks:add(webadmin_user, HostB, @@ -124,6 +138,8 @@ stop(Host) when is_list(Host) -> ?MODULE, remove_user, 50), ejabberd_hooks:delete(resend_subscription_requests_hook, HostB, ?MODULE, get_in_pending_subscriptions, 50), + ejabberd_hooks:delete(roster_get_versioning_feature, HostB, + ?MODULE, get_versioning_feature, 50), ejabberd_hooks:delete(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), ejabberd_hooks:delete(webadmin_user, HostB, @@ -131,16 +147,6 @@ stop(Host) when is_list(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_ROSTER). -%% @spec (Host) -> true | false -%% @type Host = binary() -roster_versioning_enabled(Host) -> - gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, versioning, false). - -%% @spec (Host) -> true | false -%% @type Host = binary() -roster_version_on_db(Host) -> - gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, store_current_id, false). - %% @spec (From, To, IQ_Rec) -> IQ_Result %% From = exmpp_jid:jid() %% To = exmpp_jid:jid() @@ -176,6 +182,26 @@ roster_hash(Items) -> [R#roster{groups = lists:sort(Grs)} || R = #roster{groups = Grs} <- Items]))). +%% @spec (Host) -> true | false +%% @type Host = binary() +roster_versioning_enabled(Host) -> + gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, versioning, false). + +%% @spec (Host) -> true | false +%% @type Host = binary() +roster_version_on_db(Host) -> + gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, store_current_id, false). + +%% Returns a list that may contain an xmlelement with the XEP-237 feature if it's enabled. +get_versioning_feature(Acc, Host) -> + case roster_versioning_enabled(Host) of + true -> + Feature = exmpp_xml:element(?NS_ROSTER_VER, 'ver', [], + [exmpp_xml:element(?NS_ROSTER_VER, 'optional')]), + [Feature | Acc]; + false -> [] + end. + roster_version(LServer ,LUser) -> US = {LUser, LServer}, case roster_version_on_db(LServer) of @@ -477,7 +503,7 @@ push_item(User, Server, From, Item) case roster_versioning_enabled(Server) of true -> - roster_versioning:push_item(Server, User, From, Item, roster_version(Server, User)); + push_item_version(Server, User, From, Item, roster_version(Server, User)); false -> lists:foreach(fun(Resource) -> push_item(User, Server, Resource, From, Item) @@ -504,6 +530,23 @@ push_item(User, Server, Resource, From, Item) exmpp_jid:make(User, Server, Resource), ResIQ). +%% @doc Roster push, calculate and include the version attribute. +%% TODO: don't push to those who didn't load roster +push_item_version(Server, User, From, Item, RosterVersion) -> + lists:foreach(fun(Resource) -> + push_item_version(User, Server, Resource, From, Item, RosterVersion) + end, ejabberd_sm:get_user_resources(User, Server)). + +push_item_version(User, Server, Resource, From, Item, RosterVersion) -> + Request = #xmlel{ns = ?NS_ROSTER, name = 'query', attrs = [?XMLATTR('ver', RosterVersion)], + children = [mod_roster:item_to_xml(Item)]}, + ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request, + "push" ++ randoms:get_string()), + ejabberd_router:route( + From, + exmpp_jid:make(User, Server, Resource), + ResIQ). + %% @spec (Ignored, User, Server) -> Subscription_Lists %% Ignored = term() %% User = binary() diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 0564e78c8..790862b0a 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -24,6 +24,15 @@ %%% %%%---------------------------------------------------------------------- +%%% @doc Roster management (Mnesia storage). +%%% +%%% Includes support for XEP-0237: Roster Versioning. +%%% The roster versioning follows an all-or-nothing strategy: +%%% - If the version supplied by the client is the latest, return an empty response. +%%% - If not, return the entire new roster (with updated version string). +%%% Roster version is a hash digest of the entire roster. +%%% No additional data is stored in DB. + -module(mod_roster_odbc). -author('alexey@process-one.net'). @@ -42,6 +51,7 @@ get_jid_info/4, webadmin_page/3, webadmin_user/4, + get_versioning_feature/2, roster_versioning_enabled/1]). -include_lib("exmpp/include/exmpp.hrl"). @@ -51,6 +61,7 @@ -include("web/ejabberd_http.hrl"). -include("web/ejabberd_web_admin.hrl"). +-define(NS_ROSTER_VER, "urn:xmpp:features:rosterver"). start(Host, Opts) -> HostB = list_to_binary(Host), @@ -71,6 +82,8 @@ start(Host, Opts) -> ?MODULE, remove_user, 50), ejabberd_hooks:add(resend_subscription_requests_hook, HostB, ?MODULE, get_in_pending_subscriptions, 50), + ejabberd_hooks:add(roster_get_versioning_feature, HostB, + ?MODULE, get_versioning_feature, 50), ejabberd_hooks:add(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), ejabberd_hooks:add(webadmin_user, HostB, @@ -96,6 +109,8 @@ stop(Host) -> ?MODULE, remove_user, 50), ejabberd_hooks:delete(resend_subscription_requests_hook, HostB, ?MODULE, get_in_pending_subscriptions, 50), + ejabberd_hooks:delete(roster_get_versioning_feature, HostB, + ?MODULE, get_versioning_feature, 50), ejabberd_hooks:delete(webadmin_page_host, HostB, ?MODULE, webadmin_page, 50), ejabberd_hooks:delete(webadmin_user, HostB, @@ -103,12 +118,6 @@ stop(Host) -> gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB, ?NS_ROSTER). -roster_versioning_enabled(Host) -> - gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, versioning, false). - -roster_version_on_db(Host) -> - gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, store_current_id, false). - process_iq(From, To, IQ_Rec) -> LServer = exmpp_jid:prep_domain_as_list(From), case lists:member(LServer, ?MYHOSTS) of @@ -131,6 +140,26 @@ roster_hash(Items) -> [R#roster{groups = lists:sort(Grs)} || R = #roster{groups = Grs} <- Items]))). +%% @spec (Host) -> true | false +%% @type Host = binary() +roster_versioning_enabled(Host) -> + gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, versioning, false). + +%% @spec (Host) -> true | false +%% @type Host = binary() +roster_version_on_db(Host) -> + gen_mod:get_module_opt(binary_to_list(Host), ?MODULE, store_current_id, false). + +%% Returns a list that may contain an xmlelement with the XEP-237 feature if it's enabled. +get_versioning_feature(Acc, Host) -> + case roster_versioning_enabled(Host) of + true -> + Feature = exmpp_xml:element(?NS_ROSTER_VER, 'ver', [], + [exmpp_xml:element(?NS_ROSTER_VER, 'optional')]), + [Feature | Acc]; + false -> [] + end. + roster_version(LServer ,LUser) -> US = {LUser, LServer}, case roster_version_on_db(LServer) of @@ -433,7 +462,7 @@ push_item(User, Server, From, Item) when is_binary(User), is_binary(Server) -> Item#roster.subscription}]}), case roster_versioning_enabled(Server) of true -> - roster_versioning:push_item(Server, User, From, Item, roster_version(Server, User)); + push_item_version(Server, User, From, Item, roster_version(Server, User)); false -> lists:foreach(fun(Resource) -> push_item(User, Server, Resource, From, Item) @@ -452,6 +481,23 @@ push_item(User, Server, Resource, From, Item) -> exmpp_jid:make(User, Server, Resource), ResIQ). +%% @doc Roster push, calculate and include the version attribute. +%% TODO: don't push to those who didn't load roster +push_item_version(Server, User, From, Item, RosterVersion) -> + lists:foreach(fun(Resource) -> + push_item_version(User, Server, Resource, From, Item, RosterVersion) + end, ejabberd_sm:get_user_resources(User, Server)). + +push_item_version(User, Server, Resource, From, Item, RosterVersion) -> + Request = #xmlel{ns = ?NS_ROSTER, name = 'query', attrs = [?XMLATTR('ver', RosterVersion)], + children = [mod_roster:item_to_xml(Item)]}, + ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request, + "push" ++ randoms:get_string()), + ejabberd_router:route( + From, + exmpp_jid:make(User, Server, Resource), + ResIQ). + get_subscription_lists(_, User, Server) when is_binary(User), is_binary(Server) -> try diff --git a/src/roster_versioning.erl b/src/roster_versioning.erl deleted file mode 100644 index 1aa7e4e3b..000000000 --- a/src/roster_versioning.erl +++ /dev/null @@ -1,75 +0,0 @@ -%%%---------------------------------------------------------------------- -%%% File : mod_roster.erl -%%% Author : Pablo Polvorin -%%% Purpose : Common utility functions for XEP-0237 (Roster Versioning) -%%% Created : 19 Jul 2009 by Pablo Polvorin -%%% -%%% -%%% ejabberd, Copyright (C) 2009 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., 59 Temple Place, Suite 330, Boston, MA -%%% 02111-1307 USA -%%% -%%% -%%% @doc The roster versioning follows an all-or-nothing strategy: -%%% - If the version supplied by the client is the lastest, return an empty response -%%% - If not, return the entire new roster (with updated version string). -%%% Roster version is a hash digest of the entire roster. -%%% No additional data is stored in DB. -%%%---------------------------------------------------------------------- --module(roster_versioning). --author('pablo.polvorin@process-one.net'). - -%%API --export([is_enabled/1, - stream_feature/0, - push_item/5]). - - --include("mod_roster.hrl"). --include_lib("exmpp/include/exmpp.hrl"). - --define(NS_ROSTER_VER, "urn:xmpp:features:rosterver"). - -%%@doc is roster versioning enabled? -is_enabled(Host) -> - case gen_mod:is_loaded(binary_to_list(Host), mod_roster) of - true -> mod_roster:roster_versioning_enabled(Host); - false -> mod_roster_odbc:roster_versioning_enabled(Host) - end. - -stream_feature() -> - exmpp_xml:element(?NS_ROSTER_VER, 'ver', [], [exmpp_xml:element(?NS_ROSTER_VER, 'optional')]). - - - - -%% @doc Roster push, calculate and include the version attribute. -%% TODO: don't push to those who didn't load roster -push_item(Server, User, From, Item, RosterVersion) -> - lists:foreach(fun(Resource) -> - push_item(User, Server, Resource, From, Item, RosterVersion) - end, ejabberd_sm:get_user_resources(User, Server)). - -push_item(User, Server, Resource, From, Item, RosterVersion) -> - Request = #xmlel{ns = ?NS_ROSTER, name = 'query', attrs = [?XMLATTR('ver', RosterVersion)], - children = [mod_roster:item_to_xml(Item)]}, - ResIQ = exmpp_iq:set(?NS_JABBER_CLIENT, Request, - "push" ++ randoms:get_string()), - ejabberd_router:route( - From, - exmpp_jid:make(User, Server, Resource), - ResIQ). - From 663e29af892f5925be10ec65d13994ddec093873 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 6 Aug 2009 21:07:23 +0000 Subject: [PATCH 482/582] Document options for Roster Versioning (EJAB-964) SVN Revision: 2432 --- doc/guide.html | 24 ++++++++++++++++++++++-- doc/guide.tex | 25 ++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 7c447dcdb..67f9b34af 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -2782,11 +2782,31 @@ Also define a registration timeout of one hour: ]}.

    3.3.18  mod_roster

    -

    This module implements roster management as defined in RFC 3921: XMPP IM.

    Options: +

    This module implements roster management as defined in +RFC 3921: XMPP IM. +It also supports Roster Versioning (XEP-0237).

    Options:

    iqdisc
    This specifies the processing discipline for Roster Management (jabber:iq:roster) IQ queries (see section 3.3.2). -

    +
    {versioning, false | true}
    Enables +Roster Versioning. +This option is disabled by default. +
    {store_current_id, false | true}
    +If this option is enabled, the current version number is stored on the database. +If disabled, the version number is calculated on the fly each time. +Enabling this option reduces the load for both ejabberd and the database. +This option does not affect the client in any way. +This option is only useful if Roster Versioning is enabled. +This option is disabled by default. +Important: if you use mod_shared_roster, you must disable this option. +

    This example configuration enables Roster Versioning with storage of current id: +

    {modules,
    + [
    +  ...
    +  {mod_roster, [{versioning, true}, {store_current_id, true}]},
    +  ...
    + ]}.
    +

    3.3.19  mod_service_log

    This module adds support for logging end user packets via a Jabber message auditing service such as diff --git a/doc/guide.tex b/doc/guide.tex index 2f7fbdc21..9bec0d80f 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -3561,13 +3561,36 @@ Also define a registration timeout of one hour: \makesubsection{modroster}{\modroster{}} \ind{modules!\modroster{}}\ind{roster management}\ind{protocols!RFC 3921: XMPP IM} -This module implements roster management as defined in \footahref{http://www.xmpp.org/specs/rfc3921.html\#roster}{RFC 3921: XMPP IM}. +This module implements roster management as defined in +\footahref{http://www.xmpp.org/specs/rfc3921.html\#roster}{RFC 3921: XMPP IM}. +It also supports Roster Versioning (\xepref{0237}). Options: \begin{description} \iqdiscitem{Roster Management (\ns{jabber:iq:roster})} + \titem{\{versioning, false | true\}} \ind{options!versioning}Enables + Roster Versioning. + This option is disabled by default. + \titem{\{store\_current\_id, false | true\}} \ind{options!storecurrentid} + If this option is enabled, the current version number is stored on the database. + If disabled, the version number is calculated on the fly each time. + Enabling this option reduces the load for both ejabberd and the database. + This option does not affect the client in any way. + This option is only useful if Roster Versioning is enabled. + This option is disabled by default. + Important: if you use \modsharedroster, you must disable this option. \end{description} +This example configuration enables Roster Versioning with storage of current id: +\begin{verbatim} +{modules, + [ + ... + {mod_roster, [{versioning, true}, {store_current_id, true}]}, + ... + ]}. +\end{verbatim} + \makesubsection{modservicelog}{\modservicelog{}} \ind{modules!\modservicelog{}}\ind{message auditing}\ind{Bandersnatch} From 562e63a3b08c29074699bb2be678a7c9efa4c10c Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 6 Aug 2009 21:15:15 +0000 Subject: [PATCH 483/582] Fix argument passing SVN Revision: 2433 --- src/ejabberd_c2s.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 7e1ee9509..b9f19ef3e 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -310,7 +310,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> _ -> case StateData#state.resource of undefined -> - RosterVersioningFeature = ejabberd_hooks:run_fold(roster_get_versioning_feature, Server, [], [Server]), + RosterVersioningFeature = ejabberd_hooks:run_fold(roster_get_versioning_feature, ServerB, [], [ServerB]), send_element( StateData, exmpp_stream:features([ From 6aa4bb9f080e2248b4c35886d8486544de1cfa35 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 6 Aug 2009 21:54:10 +0000 Subject: [PATCH 484/582] Merge 2422, 2423: cosmetic change, fix shell function syntax (EJAB-1003), use variable for Erlang shell. SVN Revision: 2434 --- tools/ejabberdctl | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/ejabberdctl b/tools/ejabberdctl index f084059a4..033640ecd 100755 --- a/tools/ejabberdctl +++ b/tools/ejabberdctl @@ -4,6 +4,7 @@ NODE=ejabberd HOST=localhost # Define ejabberd environment +ERL=erl here=`which "$0" 2>/dev/null || echo .` base="`dirname $here`/.." ROOTDIR=`(cd "$base"; echo $PWD)` @@ -20,9 +21,9 @@ export ERL_MAX_PORTS=32000 [ -d $EJABBERD_DB ] || mkdir -p $EJABBERD_DB [ -f $EJABBERD_CONFIG_PATH ] || cp $ROOTDIR/src/ejabberd.cfg.example $EJABBERD_CONFIG_PATH -function start +start() { - erl \ + $ERL \ -noinput -detached \ -sname $NODE@$HOST \ -pa $EJABBERD_EBIN \ @@ -33,9 +34,9 @@ function start -sasl sasl_error_logger \{file,\"$SASL_LOG_PATH\"\} } -function debug +debug() { - erl \ + $ERL \ -sname debug$NODE@$HOST \ -pa $EJABBERD_EBIN \ -mnesia dir "\"$EJABBERD_DB\"" \ @@ -43,17 +44,17 @@ function debug -remsh $NODE@$HOST } -function ctl +ctl() { - erl \ - -noinput \ - -sname ejabberdctl@$HOST \ + $ERL \ + -sname ctl$NODE@$HOST \ -pa $EJABBERD_EBIN \ + -noinput \ -hidden \ -s ejabberd_ctl -extra $NODE@$HOST $@ } -function usage +usage() { ctl exit @@ -66,4 +67,3 @@ case $1 in debug) debug;; *) ctl $@;; esac - From 9a204593e1f4c61255439ee8cd8130f2c4803e04 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 6 Aug 2009 21:57:53 +0000 Subject: [PATCH 485/582] Merge 2425 from trunk: fix keepalive query, broken by r2092. SVN Revision: 2435 --- src/odbc/ejabberd_odbc.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/odbc/ejabberd_odbc.erl b/src/odbc/ejabberd_odbc.erl index b8040a902..423065767 100644 --- a/src/odbc/ejabberd_odbc.erl +++ b/src/odbc/ejabberd_odbc.erl @@ -469,7 +469,8 @@ mysql_item_to_odbc(Columns, Recs) -> % perform a harmless query on all opened connexions to avoid connexion close. keep_alive(PID) -> - gen_server:call(PID, {sql_query, ?KEEPALIVE_QUERY}, ?KEEPALIVE_TIMEOUT). + gen_server:call(PID, {sql_cmd, {sql_query, ?KEEPALIVE_QUERY}}, + ?KEEPALIVE_TIMEOUT). % log function used by MySQL driver log(Level, Format, Args) -> From 936b2d418842e5369032f45e349626e00d4c37c7 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 6 Aug 2009 22:01:01 +0000 Subject: [PATCH 486/582] Merge 2426 from trunk: add get/0 API function that returns current log level (EJAB-1004). SVN Revision: 2436 --- src/ejabberd_loglevel.erl | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/ejabberd_loglevel.erl b/src/ejabberd_loglevel.erl index dcb23d8a5..775164fe5 100644 --- a/src/ejabberd_loglevel.erl +++ b/src/ejabberd_loglevel.erl @@ -31,7 +31,7 @@ -module(ejabberd_loglevel). -author('mickael.remond@process-one.net'). --export([set/1]). +-export([set/1, get/0]). -include("ejabberd.hrl"). @@ -46,6 +46,14 @@ ,{5, debug, "Debug"} ]). +get() -> + Level = ejabberd_logger:get(), + case lists:keysearch(Level, 1, ?LOG_LEVELS) of + {value, Result} -> Result; + _ -> erlang:error({no_such_loglevel, Level}) + end. + + set(LogLevel) when is_atom(LogLevel) -> set(level_to_integer(LogLevel)); set(Loglevel) when is_integer(Loglevel) -> @@ -67,7 +75,7 @@ level_to_integer(Level) -> %% -------------------------------------------------------------- %% Code of the ejabberd logger, dynamically compiled and loaded %% This allows to dynamically change log level while keeping a -%% very efficient code. +%% very efficient code. ejabberd_logger_src(Loglevel) -> L = integer_to_list(Loglevel), "-module(ejabberd_logger). @@ -77,7 +85,10 @@ ejabberd_logger_src(Loglevel) -> info_msg/4, warning_msg/4, error_msg/4, - critical_msg/4]). + critical_msg/4, + get/0]). + + get() -> "++ L ++". %% Helper functions debug_msg(Module, Line, Format, Args) when " ++ L ++ " >= 5 -> From e0be5664918f23b36841f61048c487fa2abdbc78 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 7 Aug 2009 14:55:08 +0000 Subject: [PATCH 487/582] ejabberdctl commands use _ instead of -. For backwards compatibility - is still supported. SVN Revision: 2448 --- doc/guide.html | 12 ++++++------ doc/guide.tex | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 67f9b34af..d25796b5f 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -3336,7 +3336,7 @@ Available commands in this ejabberd node: ...

    The more interesting ones are:

    -reopen-log
    Reopen the log files after they were renamed. +reopen_log
    Reopen the log files after they were renamed. If the old files were not renamed before calling this command, they are automatically renamed to "*-old.log". See section 7.1.
    backup ejabberd.backup
    @@ -3344,7 +3344,7 @@ Store internal Mnesia database to a binary backup file.
    restore ejabberd.backup
    Restore immediately from a binary backup file the internal Mnesia database. This will consume quite some memory for big servers. -
    install-fallback ejabberd.backup
    +
    install_fallback ejabberd.backup
    The binary backup file is installed as fallback: it will be used to restore the database at the next ejabberd start. Similar to restore, but requires less memory. @@ -3353,21 +3353,21 @@ Dump internal Mnesia database to a text file dump.
    load ejabberd.dump
    Restore immediately from a text file dump. This is not recommended for big databases, as it will consume much time, -memory and processor. In that case it’s preferable to use backup and install-fallback. -
    import-piefxis, export-piefxis, export-piefxis-host
    +memory and processor. In that case it’s preferable to use backup and install_fallback. +
    import_piefxis, export_piefxis, export_piefxis_host
    These options can be used to migrate accounts using XEP-0227 formatted XML files from/to other Jabber/XMPP servers or move users of a vhost to another ejabberd installation. See also ejabberd migration kit. -
    import-file, import-dir
    +
    import_file, import_dir
    These options can be used to migrate accounts using jabberd1.4 formatted XML files. from other Jabber/XMPP servers There exist tutorials to migrate from other software to ejabberd. -
    delete-expired-messages
    This option can be used to delete old messages +
    delete_expired_messages
    This option can be used to delete old messages in offline storage. This might be useful when the number of offline messages is very high.

    diff --git a/doc/guide.tex b/doc/guide.tex index 9bec0d80f..a077e0c3a 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -4267,7 +4267,7 @@ Available commands in this ejabberd node: The more interesting ones are: \begin{description} -\titem{reopen-log} Reopen the log files after they were renamed. +\titem{reopen\_log} Reopen the log files after they were renamed. If the old files were not renamed before calling this command, they are automatically renamed to \term{"*-old.log"}. See section \ref{logfiles}. \titem {backup ejabberd.backup} @@ -4275,7 +4275,7 @@ The more interesting ones are: \titem {restore ejabberd.backup} Restore immediately from a binary backup file the internal Mnesia database. This will consume quite some memory for big servers. -\titem {install-fallback ejabberd.backup} +\titem {install\_fallback ejabberd.backup} The binary backup file is installed as fallback: it will be used to restore the database at the next ejabberd start. Similar to \term{restore}, but requires less memory. @@ -4284,23 +4284,23 @@ The more interesting ones are: \titem {load ejabberd.dump} Restore immediately from a text file dump. This is not recommended for big databases, as it will consume much time, - memory and processor. In that case it's preferable to use \term{backup} and \term{install-fallback}. + memory and processor. In that case it's preferable to use \term{backup} and \term{install\_fallback}. %%More information about backuping can %% be found in section~\ref{backup}. -\titem{import-piefxis, export-piefxis, export-piefxis-host} \ind{migrate between servers} +\titem{import\_piefxis, export\_piefxis, export\_piefxis\_host} \ind{migrate between servers} These options can be used to migrate accounts using \xepref{0227} formatted XML files from/to other \Jabber{}/XMPP servers or move users of a vhost to another ejabberd installation. See also \footahref{https://support.process-one.net/doc/display/P1/ejabberd+migration+kit}{ejabberd migration kit}. -\titem{import-file, import-dir} \ind{migration from other software} +\titem{import\_file, import\_dir} \ind{migration from other software} These options can be used to migrate accounts using jabberd1.4 formatted XML files. from other \Jabber{}/XMPP servers There exist tutorials to \footahref{http://www.ejabberd.im/migrate-to-ejabberd}{migrate from other software to ejabberd}. -\titem{delete-expired-messages} This option can be used to delete old messages +\titem{delete\_expired\_messages} This option can be used to delete old messages in offline storage. This might be useful when the number of offline messages is very high. \end{description} From 2e8fe6a1ab51d667b68c51ce31e2b9f57510d334 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 7 Aug 2009 14:56:12 +0000 Subject: [PATCH 488/582] Add ejabberd command to get the current loglevel (EJAB-1004) SVN Revision: 2449 --- src/ejabberd_admin.erl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl index 5e81a2b37..e2c95da91 100644 --- a/src/ejabberd_admin.erl +++ b/src/ejabberd_admin.erl @@ -79,6 +79,14 @@ commands() -> desc = "Reopen the log files", module = ?MODULE, function = reopen_log, args = [], result = {res, rescode}}, + #ejabberd_commands{name = get_loglevel, tags = [logs, server], + desc = "Get the current loglevel", + module = ejabberd_loglevel, function = get, + args = [], + result = {leveltuple, {tuple, [{levelnumber, integer}, + {levelatom, atom}, + {leveldesc, string} + ]}}}, #ejabberd_commands{name = register, tags = [accounts], desc = "Register a user", From b453ee5e1fb1504db655139e4853c0d99a549bbd Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 11 Aug 2009 11:49:54 +0000 Subject: [PATCH 489/582] Update URLs of IETF and XMPP protocol documents SVN Revision: 2456 --- doc/guide.html | 124 +++++++++++++++++++++---------------------- doc/guide.tex | 18 +++---- doc/introduction.tex | 2 +- 3 files changed, 72 insertions(+), 72 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index d25796b5f..310abe64a 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -217,7 +217,7 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}
  • Appendix D  Copyright Information
  • Chapter 1  Introduction

    -

    ejabberd is a free and open source instant messaging server written in Erlang.

    ejabberd is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.

    ejabberd is designed to be a rock-solid and feature rich XMPP server.

    ejabberd is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.

    +

    ejabberd is a free and open source instant messaging server written in Erlang/OTP.

    ejabberd is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.

    ejabberd is designed to be a rock-solid and feature rich XMPP server.

    ejabberd is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.

    1.1  Key Features

    ejabberd is: @@ -268,12 +268,12 @@ Internal Authentication.

  • Others
  • @@ -339,7 +339,7 @@ GNU Make
  • Erlang/OTP R12B-4 or higher, R13B or higher.
  • exmpp 0.9.1 or higher
  • OpenSSL 0.9.6 or higher, for STARTTLS, SASL and SSL encryption. Optional, highly recommended. -
  • Zlib 1.2.3 or higher, for Stream Compression support (XEP-0138). Optional. +
  • Zlib 1.2.3 or higher, for Stream Compression support (XEP-0138). Optional.
  • Erlang mysql library. Optional. For MySQL authentication or storage. See section 3.2.1.
  • Erlang pgsql library. Optional. For PostgreSQL authentication or storage. See section 3.2.3.
  • PAM library. Optional. For Pluggable Authentication Modules (PAM). See section 3.1.4. @@ -667,7 +667,7 @@ Handles incoming s2s connections.
    Options: max_stanza_size
    ejabberd_service
    Interacts with an external component -(as defined in the Jabber Component Protocol (XEP-0114).
    +(as defined in the Jabber Component Protocol (XEP-0114).
    Options: access, hosts, shaper, service_check_from
    ejabberd_http
    @@ -685,7 +685,7 @@ To define a certificate file specific for a given domain, use the global option This option can be used with ejabberd_service only. It is used to disable control on the from field on packets send by an external components. The option can be either true or -false. The default value is true which conforms to XEP-0114. +false. The default value is true which conforms to XEP-0114.
    {hosts, [Hostnames], [HostOptions]}
    The external Jabber component that connects to this ejabberd_service can serve one or more hostnames. @@ -698,7 +698,7 @@ as seen in an example below.
    captcha
    Simple web page that allows a user to fill a CAPTCHA challenge (see section 3.1.8).
    http_bind
    -This option enables HTTP Binding (XEP-0124 and XEP-0206) support. HTTP Bind +This option enables HTTP Binding (XEP-0124 and XEP-0206) support. HTTP Bind enables access via HTTP requests to ejabberd from behind firewalls which do not allow outgoing sockets on port 5222.

    Remember that you must also install and enable the module mod_http_bind.

    If HTTP Bind is enabled, it will be available at http://server:port/http-bind/. Be aware that support for HTTP Bind @@ -709,7 +709,7 @@ interesting to host a web-based Jabber client such as embedded local web server or Apache).

    http_poll
    -This option enables HTTP Polling (XEP-0025) support. HTTP Polling +This option enables HTTP Polling (XEP-0025) support. HTTP Polling enables access via HTTP requests to ejabberd from behind firewalls which do not allow outgoing sockets on port 5222.

    If HTTP Polling is enabled, it will be available at http://server:port/http-poll/. Be aware that support for HTTP Polling @@ -735,7 +735,7 @@ and you also want mod_http_bind to serve the URIs /http-bind/, use this option: {request_handlers, [{["a", "b"], mod_foo}, {["http-bind"], mod_http_bind}]}

    {service_check_from, true|false}
    By enabling this option, ejabberd allows the component to send packets with any arbitrary domain in the ’from’ attribute. -Note that XEP-0114 requires that the domain must match the hostname of the component. +Note that XEP-0114 requires that the domain must match the hostname of the component. Only enable this option if you are completely sure you need to enable it. Default value: false.
    {shaper, <access rule>}
    This option defines a @@ -756,7 +756,7 @@ This was the traditional encryption method in the early Jabber software, commonly on port 5223 for client-to-server communications. But this method is nowadays deprecated and not recommended. The preferable encryption method is STARTTLS on port 5222, as defined -RFC 3920: XMPP Core, +RFC 3920: XMPP Core, which can be enabled in ejabberd with the option starttls. If this option is set, you should also set the certfile option.
    web_admin
    This option @@ -765,7 +765,7 @@ at http://server:port/admin/. Login and password are the username a password of one of the registered users who are granted access by the ‘configure’ access rule.
    zlib
    This -option specifies that Zlib stream compression (as defined in XEP-0138) +option specifies that Zlib stream compression (as defined in XEP-0138) is available on connections to the port. Client connections cannot use stream compression and stream encryption simultaneously. Hence, if you specify both starttls (or tls) and zlib, the latter @@ -1216,7 +1216,7 @@ can be seen by Jabber clients. If a Jabber client does not support

    Appendix A provides more details about internationalization and localization.

    3.1.8  CAPTCHA

    Some ejabberd modules can be configured to require a CAPTCHA challenge on certain actions. -If the client does not support CAPTCHA Forms (XEP-0158), +If the client does not support CAPTCHA Forms (XEP-0158), a web link is provided so the user can fill the challenge in a web browser.

    An example script is provided that generates the image using ImageMagick’s Convert program.

    The configurable options are:

    @@ -1616,7 +1616,7 @@ user’s part of a JID. For example, "%u@example.org". The default value is "%u".
    ldap_filter
    -RFC 2254 LDAP filter. The +RFC 4515 LDAP filter. The default is none. Example: "(&(objectClass=shadowAccount)(memberOf=Jabber Users))". Please, do not forget to close brackets and do not use superfluous whitespaces. Also you @@ -1775,37 +1775,37 @@ all entries end with a comma:

    3.3.1  Modules Overview

    The following table lists all modules included in ejabberd.


    - + - + - + - - - + + + - - - + + + - - - - - + + + + + - - - - - - + + + + + +
    ModuleFeatureDependencies
    mod_adhocAd-Hoc Commands (XEP-0050) 
    mod_adhocAd-Hoc Commands (XEP-0050) 
    mod_announceManage announcementsrecommends mod_adhoc
    mod_capsEntity Capabilities (XEP-0115) 
    mod_capsEntity Capabilities (XEP-0115) 
    mod_configureServer configuration using Ad-Hocmod_adhoc
    mod_discoService Discovery (XEP-0030) 
    mod_discoService Discovery (XEP-0030) 
    mod_echoEchoes Jabber packets 
    mod_lastLast Activity (XEP-0012) 
    mod_last_odbcLast Activity (XEP-0012)supported DB (*)
    mod_mucMulti-User Chat (XEP-0045) 
    mod_lastLast Activity (XEP-0012) 
    mod_last_odbcLast Activity (XEP-0012)supported DB (*)
    mod_mucMulti-User Chat (XEP-0045) 
    mod_muc_logMulti-User Chat room loggingmod_muc
    mod_offlineOffline message storage (XEP-0160) 
    mod_offline_odbcOffline message storage (XEP-0160)supported DB (*)
    mod_pingXMPP Ping and periodic keepalives (XEP-0199) 
    mod_offlineOffline message storage (XEP-0160) 
    mod_offline_odbcOffline message storage (XEP-0160)supported DB (*)
    mod_pingXMPP Ping and periodic keepalives (XEP-0199) 
    mod_privacyBlocking Communication (XMPP IM) 
    mod_privacy_odbcBlocking Communication (XMPP IM)supported DB (*)
    mod_privatePrivate XML Storage (XEP-0049) 
    mod_private_odbcPrivate XML Storage (XEP-0049)supported DB (*)
    mod_proxy65SOCKS5 Bytestreams (XEP-0065) 
    mod_pubsubPub-Sub (XEP-0060), PEP (XEP-0163)mod_caps
    mod_registerIn-Band Registration (XEP-0077) 
    mod_privatePrivate XML Storage (XEP-0049) 
    mod_private_odbcPrivate XML Storage (XEP-0049)supported DB (*)
    mod_proxy65SOCKS5 Bytestreams (XEP-0065) 
    mod_pubsubPub-Sub (XEP-0060), PEP (XEP-0163)mod_caps
    mod_registerIn-Band Registration (XEP-0077) 
    mod_rosterRoster management (XMPP IM) 
    mod_roster_odbcRoster management (XMPP IM)supported DB (*)
    mod_service_logCopy user messages to logger service 
    mod_shared_rosterShared roster managementmod_roster or
      mod_roster_odbc
    mod_statsStatistics Gathering (XEP-0039) 
    mod_timeEntity Time (XEP-0202) 
    mod_vcardvcard-temp (XEP-0054) 
    mod_vcard_ldapvcard-temp (XEP-0054)LDAP server
    mod_vcard_odbcvcard-temp (XEP-0054)supported DB (*)
    mod_versionSoftware Version (XEP-0092) 
    mod_statsStatistics Gathering (XEP-0039) 
    mod_timeEntity Time (XEP-0202) 
    mod_vcardvcard-temp (XEP-0054) 
    mod_vcard_ldapvcard-temp (XEP-0054)LDAP server
    mod_vcard_odbcvcard-temp (XEP-0054)supported DB (*)
    mod_versionSoftware Version (XEP-0092) 

    • (*) This module requires a supported database. For a list of supported databases, see section 3.2. @@ -1955,11 +1955,11 @@ disabled for instances of ejabberd with hundreds of thousands users.

      This module adds support for Service Discovery (XEP-0030). With +

      This module adds support for Service Discovery (XEP-0030). With this module enabled, services on your server can be discovered by Jabber clients. Note that ejabberd has no modules with support -for the superseded Jabber Browsing (XEP-0011) and Agent Information -(XEP-0094). Accordingly, Jabber clients need to have support for +for the superseded Jabber Browsing (XEP-0011) and Agent Information +(XEP-0094). Accordingly, Jabber clients need to have support for the newer Service Discovery protocol if you want them be able to discover the services you offer.

      Options:

      @@ -1970,7 +1970,7 @@ the processing discipline for Service Discovery (http://jabber.org/protocol/ you can specify a list of extra domains that are added to the Service Discovery item list.
    {server_info, [ {Modules, Field, [Value]} ]}
    Specify additional information about the server, -as described in Contact Addresses for XMPP Services (XEP-0157). +as described in Contact Addresses for XMPP Services (XEP-0157). Modules can be the keyword ‘all’, in which case the information is reported in all the services; or a list of ejabberd modules, @@ -2046,7 +2046,7 @@ of them all?

    3.3.6  mod_http_bind

    This module implements XMPP over Bosh (formerly known as HTTP Binding) -as defined in XEP-0124 and XEP-0206. +as defined in XEP-0124 and XEP-0206. It extends ejabberd’s built in HTTP service with a configurable resource at which this service will be hosted.

    To use HTTP-Binding, enable the module:

    {modules,
    @@ -2156,7 +2156,7 @@ To use this module you must enable it:
     ]}.
     

    3.3.8  mod_last

    -

    This module adds support for Last Activity (XEP-0012). It can be used to +

    This module adds support for Last Activity (XEP-0012). It can be used to discover when a disconnected user last accessed the server, to know when a connected user was last active on the server, or to query the uptime of the ejabberd server.

    Options: @@ -2165,7 +2165,7 @@ connected user was last active on the server, or to query the uptime of the the processing discipline for Last activity (jabber:iq:last) IQ queries (see section 3.3.2).

    3.3.9  mod_muc

    -

    This module provides a Multi-User Chat (XEP-0045) service. +

    This module provides a Multi-User Chat (XEP-0045) service. Users can discover existing rooms, join or create them. Occupants of a room can chat in public or have private chats.

    Some of the features of Multi-User Chat:

    • @@ -2397,7 +2397,7 @@ Room details are added on top of each page: room title, JID, author, subject and configuration.
    • The room JID in the generated HTML is a link to join the room (using -XMPP URI). +XMPP URI).
    • Subject and room configuration changes are tracked and displayed.
    • Joins, leaves, nick changes, kicks, bans and ‘/me’ are tracked and displayed, including the reason if available. @@ -2508,7 +2508,7 @@ top link will be the default <a href="/">Home</a>. ]}.

    3.3.11  mod_offline

    -

    This module implements offline message storage (XEP-0160). +

    This module implements offline message storage (XEP-0160). This means that all messages sent to an offline user will be stored on the server until that user comes online again. Thus it is very similar to how email works. Note that @@ -2540,7 +2540,7 @@ and all the other users up to 100. ]}.

    3.3.12  mod_ping

    -

    This module implements support for XMPP Ping (XEP-0199) and periodic keepalives. +

    This module implements support for XMPP Ping (XEP-0199) and periodic keepalives. When this module is enabled ejabberd responds correctly to ping requests, as defined in the protocol.

    Configuration options:

    @@ -2589,26 +2589,26 @@ or subscription type (or globally).
  • Allowing or blocking all communications based on JID, group, or subscription type (or globally).
  • -(from http://www.xmpp.org/specs/rfc3921.html#privacy) +(from http://xmpp.org/specs/rfc3921.html#privacy)

    Options:

    iqdisc
    This specifies the processing discipline for Blocking Communication (jabber:iq:privacy) IQ queries (see section 3.3.2).

    3.3.14  mod_private

    -

    This module adds support for Private XML Storage (XEP-0049): +

    This module adds support for Private XML Storage (XEP-0049):

    Using this method, Jabber entities can store private data on the server and retrieve it whenever necessary. The data stored might be anything, as long as it is valid XML. One typical usage for this namespace is the server-side storage -of client-specific preferences; another is Bookmark Storage (XEP-0048). +of client-specific preferences; another is Bookmark Storage (XEP-0048).

    Options:

    iqdisc
    This specifies the processing discipline for Private XML Storage (jabber:iq:private) IQ queries (see section 3.3.2).

    3.3.15  mod_proxy65

    -

    This module implements SOCKS5 Bytestreams (XEP-0065). +

    This module implements SOCKS5 Bytestreams (XEP-0065). It allows ejabberd to act as a file transfer proxy between two XMPP clients.

    Options:

    @@ -2663,9 +2663,9 @@ The simpliest configuration of the module: ]}.

    3.3.16  mod_pubsub

    -

    This module offers a Publish-Subscribe Service (XEP-0060). +

    This module offers a Publish-Subscribe Service (XEP-0060). The functionality in mod_pubsub can be extended using plugins. -The plugin that implements PEP (Personal Eventing via Pubsub) (XEP-0163) +The plugin that implements PEP (Personal Eventing via Pubsub) (XEP-0163) is enabled in the default ejabberd configuration file, and it requires mod_caps.

    Options:

    @@ -2709,7 +2709,7 @@ The following example will use node_tune instead of node_pep for every PEP node ]}.

    3.3.17  mod_register

    -

    This module adds support for In-Band Registration (XEP-0077). This protocol +

    This module adds support for In-Band Registration (XEP-0077). This protocol enables end users to use a Jabber client to:

    • Register a new account on the server. @@ -2783,8 +2783,8 @@ Also define a registration timeout of one hour:

    3.3.18  mod_roster

    This module implements roster management as defined in -RFC 3921: XMPP IM. -It also supports Roster Versioning (XEP-0237).

    Options: +RFC 3921: XMPP IM. +It also supports Roster Versioning (XEP-0237).

    Options:

    iqdisc
    This specifies the processing discipline for Roster Management (jabber:iq:roster) IQ queries (see section 3.3.2). @@ -2913,7 +2913,7 @@ roster groups as shown in the following table:

    3.3.21  mod_stats

    -

    This module adds support for Statistics Gathering (XEP-0039). This protocol +

    This module adds support for Statistics Gathering (XEP-0039). This protocol allows you to retrieve next statistics from your ejabberd deployment:

    • Total number of registered users on the current virtual host (users/total). @@ -2945,7 +2945,7 @@ by sending: </iq>

    3.3.22  mod_time

    -

    This module features support for Entity Time (XEP-0202). By using this XEP, +

    This module features support for Entity Time (XEP-0202). By using this XEP, you are able to discover the time at another entity’s location.

    Options:

    iqdisc
    This specifies @@ -2953,7 +2953,7 @@ the processing discipline for Entity Time (jabber:iq:time) IQ queries (

    3.3.23  mod_vcard

    This module allows end users to store and retrieve their vCard, and to retrieve -other users vCards, as defined in vcard-temp (XEP-0054). The module also +other users vCards, as defined in vcard-temp (XEP-0054). The module also implements an uncomplicated Jabber User Directory based on the vCards of these users. Moreover, it enables the server to send its vCard when queried.

    Options:

    @@ -3040,7 +3040,7 @@ all search results are reported. The default value is 30. set the table that maps LDAP attributes to vCard fields. The format is: [Name_of_vCard_field, Pattern, List_of_LDAP_attributes, ...]. Name_of_vcard_field is the type name of the vCard as defined in -RFC 2426. Pattern is a +RFC 2426. Pattern is a string which contains pattern variables "%u", "%d" or "%s". List_of_LDAP_attributes is the list containing LDAP attributes. The pattern variables "%s" will be sequentially replaced @@ -3183,7 +3183,7 @@ searching his info in LDAP.

  • ldap_vcard_map
  • 3.3.25  mod_version

    -

    This module implements Software Version (XEP-0092). Consequently, it +

    This module implements Software Version (XEP-0092). Consequently, it answers ejabberd’s version when queried.

    Options:

    show_os
    Should the operating system be revealed or not. @@ -3356,7 +3356,7 @@ This is not recommended for big databases, as it will consume much time, memory and processor. In that case it’s preferable to use backup and install_fallback.
    import_piefxis, export_piefxis, export_piefxis_host
    These options can be used to migrate accounts -using XEP-0227 formatted XML files +using XEP-0227 formatted XML files from/to other Jabber/XMPP servers or move users of a vhost to another ejabberd installation. See also @@ -3492,7 +3492,7 @@ See section 4.1.2.

    4.4  Ad-hoc Commands

    If you enable mod_configure and mod_adhoc, you can perform several administrative tasks in ejabberd with a Jabber client. -The client must support Ad-Hoc Commands (XEP-0050), +The client must support Ad-Hoc Commands (XEP-0050), and you must login in the Jabber server with an account with proper privileges.

    4.5  Change Computer Hostname

    ejabberd uses the distributed Mnesia database. diff --git a/doc/guide.tex b/doc/guide.tex index a077e0c3a..cc703fccc 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -169,7 +169,7 @@ ejabberd Development Team \gdef\ahrefurl#1{\href{#1}{\texttt{#1}}} \gdef\footahref#1#2{#2\footnote{\href{#1}{\texttt{#1}}}} \end{latexonly} -\newcommand{\txepref}[2]{\footahref{http://www.xmpp.org/extensions/xep-#1.html}{#2}} +\newcommand{\txepref}[2]{\footahref{http://xmpp.org/extensions/xep-#1.html}{#2}} \newcommand{\xepref}[1]{\txepref{#1}{XEP-#1}} \begin{document} @@ -889,7 +889,7 @@ This is a detailed description of each option allowed by the listening modules: commonly on port 5223 for client-to-server communications. But this method is nowadays deprecated and not recommended. The preferable encryption method is STARTTLS on port 5222, as defined - \footahref{http://www.xmpp.org/specs/rfc3920.html\#tls}{RFC 3920: XMPP Core}, + \footahref{http://xmpp.org/specs/rfc3920.html\#tls}{RFC 3920: XMPP Core}, which can be enabled in \ejabberd{} with the option \term{starttls}. If this option is set, you should also set the \option{certfile} option. \titem{web\_admin} \ind{options!web\_admin}\ind{web admin}This option @@ -2159,9 +2159,9 @@ You can authenticate users against an LDAP directory. Available options are: user's part of a JID. For example, \term{"\%u@example.org"}. The default value is \term{"\%u"}. \end{description} - \titem{ldap\_filter}\ind{options!ldap\_filter}\ind{protocols!RFC 2254: The - String Representation of LDAP Search Filters} - \footahref{http://www.faqs.org/rfcs/rfc2254.html}{RFC 2254} LDAP filter. The + \titem{ldap\_filter}\ind{options!ldap\_filter}\ind{protocols!RFC 4515: + LDAP String Representation of Search Filters} + \footahref{http://tools.ietf.org/html/rfc4515}{RFC 4515} LDAP filter. The default is \term{none}. Example: \term{"(\&(objectClass=shadowAccount)(memberOf=Jabber Users))"}. Please, do not forget to close brackets and do not use superfluous whitespaces. Also you @@ -3104,7 +3104,7 @@ Features: author, subject and configuration. \item \ind{protocols!RFC 5122: Internationalized Resource Identifiers (IRIs) and Uniform Resource Identifiers (URIs) for the Extensible Messaging and Presence Protocol (XMPP)} The room JID in the generated HTML is a link to join the room (using - \footahref{http://www.xmpp.org/rfcs/rfc5122.html}{XMPP URI}). + \footahref{http://xmpp.org/rfcs/rfc5122.html}{XMPP URI}). \item Subject and room configuration changes are tracked and displayed. \item Joins, leaves, nick changes, kicks, bans and `/me' are tracked and displayed, including the reason if available. @@ -3325,7 +3325,7 @@ their \Jabber{} client, they will be able to: \item Allowing or blocking all communications based on JID, group, or subscription type (or globally). \end{itemize} -(from \ahrefurl{http://www.xmpp.org/specs/rfc3921.html\#privacy}) +(from \ahrefurl{http://xmpp.org/specs/rfc3921.html\#privacy}) \end{quote} Options: @@ -3562,7 +3562,7 @@ Also define a registration timeout of one hour: \ind{modules!\modroster{}}\ind{roster management}\ind{protocols!RFC 3921: XMPP IM} This module implements roster management as defined in -\footahref{http://www.xmpp.org/specs/rfc3921.html\#roster}{RFC 3921: XMPP IM}. +\footahref{http://xmpp.org/specs/rfc3921.html\#roster}{RFC 3921: XMPP IM}. It also supports Roster Versioning (\xepref{0237}). Options: @@ -3893,7 +3893,7 @@ consists of the following \modvcardldap{}-specific options: set the table that maps LDAP attributes to vCard fields. The format is: \term{[{Name\_of\_vCard\_field, Pattern, List\_of\_LDAP\_attributes}, ...]}.\ind{protocols!RFC 2426: vCard MIME Directory Profile} \term{Name\_of\_vcard\_field} is the type name of the vCard as defined in - \footahref{http://www.ietf.org/rfc/rfc2426.txt}{RFC 2426}. \term{Pattern} is a + \footahref{http://tools.ietf.org/html/rfc2426}{RFC 2426}. \term{Pattern} is a string which contains pattern variables \term{"\%u"}, \term{"\%d"} or \term{"\%s"}. \term{List\_of\_LDAP\_attributes} is the list containing LDAP attributes. The pattern variables \term{"\%s"} will be sequentially replaced diff --git a/doc/introduction.tex b/doc/introduction.tex index 6cedbd161..e90130d49 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -8,7 +8,7 @@ Joeri} %ejabberd is a free and open source instant messaging server written in Erlang. ejabberd is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication (Jabber/XMPP). -\ejabberd{} is a \marking{free and open source} instant messaging server written in \footahref{http://www.erlang.org/}{Erlang}. +\ejabberd{} is a \marking{free and open source} instant messaging server written in \footahref{http://www.erlang.org/}{Erlang/OTP}. \ejabberd{} is \marking{cross-platform}, distributed, fault-tolerant, and based on open standards to achieve real-time communication. From bf0dbeb8b311fd248ba43377ddef341270e4809d Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 11 Aug 2009 12:53:46 +0000 Subject: [PATCH 490/582] STUN support backport SVN Revision: 2457 --- src/ejabberd_config.erl | 4 +- src/ejabberd_listener.erl | 159 +++++++++++++++++++++++++++++--------- 2 files changed, 125 insertions(+), 38 deletions(-) diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 2d1e8398e..eba01159f 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -332,9 +332,9 @@ process_term(Term, State) -> Listeners2 = lists:map( fun({PortIP, Module, Opts}) -> - {Port, IPT, _, _, OptsClean} = + {Port, IPT, _, _, Proto, OptsClean} = ejabberd_listener:parse_listener_portip(PortIP, Opts), - {{Port, IPT}, Module, OptsClean} + {{Port, IPT, Proto}, Module, OptsClean} end, Listeners), add_option(listen, Listeners2, State); diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index adffe6680..26167351f 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -96,8 +96,8 @@ start_dependent(Port, Module, Opts) -> {error, Error} end. -init(PortIP, Module, Opts1) -> - {Port, IPT, IPS, IPV, OptsClean} = parse_listener_portip(PortIP, Opts1), +init(PortIP, Module, RawOpts) -> + {Port, IPT, IPS, IPV, Proto, OptsClean} = parse_listener_portip(PortIP, RawOpts), %% The first inet|inet6 and the last {ip, _} work, %% so overriding those in Opts Opts = [IPV | OptsClean] ++ [{ip, IPT}], @@ -106,6 +106,26 @@ init(PortIP, Module, Opts1) -> (inet) -> true; (_) -> false end, Opts), + if Proto == udp -> + init_udp(PortIP, Module, Opts, SockOpts, Port, IPS); + true -> + init_tcp(PortIP, Module, Opts, SockOpts, Port, IPS) + end. + +init_udp(PortIP, Module, Opts, SockOpts, Port, IPS) -> + case gen_udp:open(Port, [binary, + {active, false}, + {reuseaddr, true} | + SockOpts]) of + {ok, Socket} -> + %% Inform my parent that this port was opened succesfully + proc_lib:init_ack({ok, self()}), + udp_recv(Socket, Module, Opts); + {error, Reason} -> + socket_error(Reason, PortIP, Module, SockOpts, Port, IPS) + end. + +init_tcp(PortIP, Module, Opts, SockOpts, Port, IPS) -> Res = gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}, @@ -116,19 +136,12 @@ init(PortIP, Module, Opts1) -> SockOpts]), case Res of {ok, ListenSocket} -> - %% Inform my parent that this port was opened succesfully - proc_lib:init_ack({ok, self()}), - %% And now start accepting connection attempts + %% Inform my parent that this port was opened succesfully + proc_lib:init_ack({ok, self()}), + %% And now start accepting connection attempts accept(ListenSocket, Module, Opts); {error, Reason} -> - ReasonT = case Reason of - eaddrnotavail -> "IP address not available: " ++ IPS; - eaddrinuse -> "IP address and port number already used: "++IPS++" "++integer_to_list(Port); - _ -> atom_to_list(Reason) - end, - ?ERROR_MSG("Failed to open socket:~n ~p~nReason: ~s", - [{Port, Module, SockOpts}, ReasonT]), - throw({Reason, PortIP}) + socket_error(Reason, PortIP, Module, SockOpts, Port, IPS) end. %% @spec (PortIP, Opts) -> {Port, IPT, IPS, IPV, OptsClean} @@ -153,24 +166,34 @@ parse_listener_portip(PortIP, Opts) -> true -> {inet6, Opts2 -- [inet6]}; false -> {inet, Opts2} end, - {Port, IPT, IPS} = case PortIP of - P when is_integer(P) -> - T = get_ip_tuple(IPOpt, IPVOpt), - S = inet_parse:ntoa(T), - {P, T, S}; - {P, T} when is_integer(P) and is_tuple(T) -> - S = inet_parse:ntoa(T), - {P, T, S}; - {P, S} when is_integer(P) and is_list(S) -> - [S | _] = string:tokens(S, "/"), - {ok, T} = inet_parse:address(S), - {P, T, S} - end, + {Port, IPT, IPS, Proto} = + case add_proto(PortIP, Opts) of + {P, Prot} -> + T = get_ip_tuple(IPOpt, IPVOpt), + S = inet_parse:ntoa(T), + {P, T, S, Prot}; + {P, T, Prot} when is_integer(P) and is_tuple(T) -> + S = inet_parse:ntoa(T), + {P, T, S, Prot}; + {P, S, Prot} when is_integer(P) and is_list(S) -> + [S | _] = string:tokens(S, "/"), + {ok, T} = inet_parse:address(S), + {P, T, S, Prot} + end, IPV = case size(IPT) of 4 -> inet; 8 -> inet6 end, - {Port, IPT, IPS, IPV, OptsClean}. + {Port, IPT, IPS, IPV, Proto, OptsClean}. + +add_proto(Port, Opts) when is_integer(Port) -> + {Port, get_proto(Opts)}; +add_proto({Port, Proto}, _Opts) when is_atom(Proto) -> + {Port, normalize_proto(Proto)}; +add_proto({Port, Addr}, Opts) -> + {Port, Addr, get_proto(Opts)}; +add_proto({Port, Addr, Proto}, _Opts) -> + {Port, Addr, normalize_proto(Proto)}. strip_ip_option(Opts) -> {IPL, OptsNoIP} = lists:partition( @@ -215,6 +238,24 @@ accept(ListenSocket, Module, Opts) -> accept(ListenSocket, Module, Opts) end. +udp_recv(Socket, Module, Opts) -> + case gen_udp:recv(Socket, 0) of + {ok, {Addr, Port, Packet}} -> + case catch Module:udp_recv(Socket, Addr, Port, Packet, Opts) of + {'EXIT', Reason} -> + ?ERROR_MSG("failed to process UDP packet:~n" + "** Source: {~p, ~p}~n" + "** Reason: ~p~n** Packet: ~p", + [Addr, Port, Reason, Packet]); + _ -> + ok + end, + udp_recv(Socket, Module, Opts); + {error, Reason} -> + ?ERROR_MSG("unexpected UDP error: ~s", [format_error(Reason)]), + throw({error, Reason}) + end. + %% @spec (Port, Module, Opts) -> {ok, Pid} | {error, Error} start_listener(Port, Module, Opts) -> case start_listener2(Port, Module, Opts) of @@ -280,7 +321,9 @@ stop_listener(PortIP, _Module) -> %% Opts = [IPV | {ip, IPT} | atom() | tuple()] %% @doc Add a listener and store in config if success add_listener(PortIP, Module, Opts) -> - case start_listener(PortIP, Module, Opts) of + {Port, IPT, _, _, Proto, _} = parse_listener_portip(PortIP, Opts), + PortIP1 = {Port, IPT, Proto}, + case start_listener(PortIP1, Module, Opts) of {ok, _Pid} -> Ports = case ejabberd_config:get_local_option(listen) of undefined -> @@ -288,33 +331,39 @@ add_listener(PortIP, Module, Opts) -> Ls -> Ls end, - Ports1 = lists:keydelete(PortIP, 1, Ports), - Ports2 = [{PortIP, Module, Opts} | Ports1], + Ports1 = lists:keydelete(PortIP1, 1, Ports), + Ports2 = [{PortIP1, Module, Opts} | Ports1], ejabberd_config:add_local_option(listen, Ports2), - ok; + ok; {error, {already_started, _Pid}} -> {error, {already_started, PortIP}}; {error, Error} -> {error, Error} end. - -%% @spec (PortIP, Module) -> ok + +delete_listener(PortIP, Module) -> + delete_listener(PortIP, Module, []). + +%% @spec (PortIP, Module, Opts) -> ok %% where %% PortIP = {Port, IPT | IPS} %% Port = integer() %% IPT = tuple() %% IPS = string() %% Module = atom() -delete_listener(PortIP, Module) -> +%% Opts = [term()] +delete_listener(PortIP, Module, Opts) -> + {Port, IPT, _, _, Proto, _} = parse_listener_portip(PortIP, Opts), + PortIP1 = {Port, IPT, Proto}, Ports = case ejabberd_config:get_local_option(listen) of undefined -> []; Ls -> Ls end, - Ports1 = lists:keydelete(PortIP, 1, Ports), + Ports1 = lists:keydelete(PortIP1, 1, Ports), ejabberd_config:add_local_option(listen, Ports1), - stop_listener(PortIP, Module). + stop_listener(PortIP1, Module). is_frontend({frontend, _Module}) -> true; is_frontend(_) -> false. @@ -368,3 +417,41 @@ certfile_readable(Opts) -> false -> {false, Path} end end. + +get_proto(Opts) -> + case proplists:get_value(proto, Opts) of + undefined -> + tcp; + Proto -> + normalize_proto(Proto) + end. + +normalize_proto(tcp) -> tcp; +normalize_proto(udp) -> udp; +normalize_proto(UnknownProto) -> + ?WARNING_MSG("There is a problem in the configuration: " + "~p is an unknown IP protocol. Using tcp as fallback", + [UnknownProto]), + tcp. + +socket_error(Reason, PortIP, Module, SockOpts, Port, IPS) -> + ReasonT = case Reason of + eaddrnotavail -> + "IP address not available: " ++ IPS; + eaddrinuse -> + "IP address and port number already used: " + ++IPS++" "++integer_to_list(Port); + _ -> + format_error(Reason) + end, + ?ERROR_MSG("Failed to open socket:~n ~p~nReason: ~s", + [{Port, Module, SockOpts}, ReasonT]), + throw({Reason, PortIP}). + +format_error(Reason) -> + case inet:format_error(Reason) of + "unknown POSIX error" -> + atom_to_list(Reason); + ReasonStr -> + ReasonStr + end. From 0a8bcf6530277fd2ad67d652964bb8757ae0972a Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 11 Aug 2009 12:54:40 +0000 Subject: [PATCH 491/582] restore missing stun directory SVN Revision: 2458 --- src/stun/Makefile.in | 38 ++++ src/stun/Makefile.win32 | 18 ++ src/stun/ejabberd_stun.erl | 260 ++++++++++++++++++++++++++++ src/stun/stun.hrl | 78 +++++++++ src/stun/stun_codec.erl | 343 +++++++++++++++++++++++++++++++++++++ 5 files changed, 737 insertions(+) create mode 100644 src/stun/Makefile.in create mode 100644 src/stun/Makefile.win32 create mode 100644 src/stun/ejabberd_stun.erl create mode 100644 src/stun/stun.hrl create mode 100644 src/stun/stun_codec.erl diff --git a/src/stun/Makefile.in b/src/stun/Makefile.in new file mode 100644 index 000000000..e77da8452 --- /dev/null +++ b/src/stun/Makefile.in @@ -0,0 +1,38 @@ +# $Id: Makefile.in 1453 2008-07-16 16:58:42Z badlop $ + +CC = @CC@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ + +ERLANG_CFLAGS = @ERLANG_CFLAGS@ +ERLANG_LIBS = @ERLANG_LIBS@ + +EFLAGS += -I .. +EFLAGS += -pz .. + +# make debug=true to compile Erlang module with debug informations. +ifdef debug + EFLAGS+=+debug_info +endif + +OUTDIR = .. +SOURCES = $(wildcard *.erl) +BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam)) + + +all: $(BEAMS) + +$(OUTDIR)/%.beam: %.erl + @ERLC@ -W $(EFLAGS) -o $(OUTDIR) $< + +clean: + rm -f $(BEAMS) + +distclean: clean + rm -f Makefile + +TAGS: + etags *.erl + diff --git a/src/stun/Makefile.win32 b/src/stun/Makefile.win32 new file mode 100644 index 000000000..e70aba9f1 --- /dev/null +++ b/src/stun/Makefile.win32 @@ -0,0 +1,18 @@ + +include ..\Makefile.inc + +EFLAGS = -I .. -pz .. + +OUTDIR = .. +BEAMS = ..\stun_codec.beam ..\ejabberd_stun.beam + +ALL : $(BEAMS) + +CLEAN : + -@erase $(BEAMS) + +$(OUTDIR)\stun_codec.beam : stun_codec.erl + erlc -W $(EFLAGS) -o $(OUTDIR) stun_codec.erl + +$(OUTDIR)\ejabberd_stun.beam : ejabberd_stun.erl + erlc -W $(EFLAGS) -o $(OUTDIR) ejabberd_stun.erl diff --git a/src/stun/ejabberd_stun.erl b/src/stun/ejabberd_stun.erl new file mode 100644 index 000000000..d5085821f --- /dev/null +++ b/src/stun/ejabberd_stun.erl @@ -0,0 +1,260 @@ +%%%------------------------------------------------------------------- +%%% File : ejabberd_stun.erl +%%% Author : Evgeniy Khramtsov +%%% Description : RFC5389 implementation. +%%% Currently only Binding usage is supported. +%%% +%%% Created : 8 Aug 2009 by Evgeniy Khramtsov +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%%------------------------------------------------------------------- +-module(ejabberd_stun). + +-behaviour(gen_fsm). + +%% API +-export([start_link/2, + start/2, + socket_type/0, + udp_recv/5]). + +%% gen_fsm callbacks +-export([init/1, + handle_event/3, + handle_sync_event/4, + handle_info/3, + terminate/3, + code_change/4]). + +%% gen_fsm states +-export([wait_for_tls/2, + session_established/2]). + +-include("ejabberd.hrl"). +-include("stun.hrl"). + +-define(MAX_BUF_SIZE, 64*1024). %% 64kb +-define(TIMEOUT, 10000). %% 10 sec + +-record(state, {sock, + sock_mod = gen_tcp, + certfile, + peer, + tref, + buf = <<>>}). + +%%==================================================================== +%% API +%%==================================================================== +start({gen_tcp, Sock}, Opts) -> + supervisor:start_child(ejabberd_stun_sup, [Sock, Opts]). + +start_link(Sock, Opts) -> + gen_fsm:start_link(?MODULE, [Sock, Opts], []). + +socket_type() -> + raw. + +udp_recv(Sock, Addr, Port, Data, _Opts) -> + case stun_codec:decode(Data) of + {ok, Msg, <<>>} -> + ?DEBUG("got:~n~s", [stun_codec:pp(Msg)]), + case process(Addr, Port, Msg) of + RespMsg when is_record(RespMsg, stun) -> + ?DEBUG("sent:~n~s", [stun_codec:pp(RespMsg)]), + Data1 = stun_codec:encode(RespMsg), + gen_udp:send(Sock, Addr, Port, Data1); + _ -> + ok + end; + _ -> + ok + end. + +%%==================================================================== +%% gen_fsm callbacks +%%==================================================================== +init([Sock, Opts]) -> + case inet:peername(Sock) of + {ok, Addr} -> + inet:setopts(Sock, [{active, once}]), + TRef = erlang:start_timer(?TIMEOUT, self(), stop), + State = #state{sock = Sock, peer = Addr, tref = TRef}, + case proplists:get_value(certfile, Opts) of + undefined -> + {ok, session_established, State}; + CertFile -> + {ok, wait_for_tls, State#state{certfile = CertFile}} + end; + Err -> + Err + end. + +wait_for_tls(Event, State) -> + ?INFO_MSG("unexpected event in wait_for_tls: ~p", [Event]), + {next_state, wait_for_tls, State}. + +session_established(Msg, State) when is_record(Msg, stun) -> + ?DEBUG("got:~n~s", [stun_codec:pp(Msg)]), + {Addr, Port} = State#state.peer, + case process(Addr, Port, Msg) of + Resp when is_record(Resp, stun) -> + ?DEBUG("sent:~n~s", [stun_codec:pp(Resp)]), + Data = stun_codec:encode(Resp), + (State#state.sock_mod):send(State#state.sock, Data); + _ -> + ok + end, + {next_state, session_established, State}; +session_established(Event, State) -> + ?INFO_MSG("unexpected event in session_established: ~p", [Event]), + {next_state, session_established, State}. + +handle_event(_Event, StateName, State) -> + {next_state, StateName, State}. + +handle_sync_event(_Event, _From, StateName, State) -> + {reply, {error, badarg}, StateName, State}. + +handle_info({tcp, Sock, TLSData}, wait_for_tls, State) -> + Buf = <<(State#state.buf)/binary, TLSData/binary>>, + %% Check if the initial message is a TLS handshake + case Buf of + _ when size(Buf) < 3 -> + {next_state, wait_for_tls, + update_state(State#state{buf = Buf})}; + <<_:16, 1, _/binary>> -> + TLSOpts = [{certfile, State#state.certfile}], + {ok, TLSSock} = tls:tcp_to_tls(Sock, TLSOpts), + NewState = State#state{sock = TLSSock, + buf = <<>>, + sock_mod = tls}, + case tls:recv_data(TLSSock, Buf) of + {ok, Data} -> + process_data(session_established, NewState, Data); + _Err -> + {stop, normal, NewState} + end; + _ -> + process_data(session_established, State, TLSData) + end; +handle_info({tcp, _Sock, TLSData}, StateName, + #state{sock_mod = tls} = State) -> + case tls:recv_data(State#state.sock, TLSData) of + {ok, Data} -> + process_data(StateName, State, Data); + _Err -> + {stop, normal, State} + end; +handle_info({tcp, _Sock, Data}, StateName, State) -> + process_data(StateName, State, Data); +handle_info({tcp_closed, _Sock}, _StateName, State) -> + ?DEBUG("connection reset by peer", []), + {stop, normal, State}; +handle_info({tcp_error, _Sock, Reason}, _StateName, State) -> + ?DEBUG("connection error: ~p", [Reason]), + {stop, normal, State}; +handle_info({timeout, TRef, stop}, _StateName, + #state{tref = TRef} = State) -> + {stop, normal, State}; +handle_info(Info, StateName, State) -> + ?INFO_MSG("unexpected info: ~p", [Info]), + {next_state, StateName, State}. + +terminate(_Reason, _StateName, State) -> + catch (State#state.sock_mod):close(State#state.sock), + ok. + +code_change(_OldVsn, StateName, State, _Extra) -> + {ok, StateName, State}. + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +process(Addr, Port, #stun{class = request, unsupported = []} = Msg) -> + Resp = prepare_response(Msg), + if Msg#stun.method == ?STUN_METHOD_BINDING -> + case stun_codec:version(Msg) of + old -> + Resp#stun{class = response, + 'MAPPED-ADDRESS' = {Addr, Port}}; + new -> + Resp#stun{class = response, + 'MAPPED-ADDRESS' = {Addr, Port}, + 'XOR-MAPPED-ADDRESS' = {Addr, Port}} + end; + true -> + Resp#stun{class = error, + 'ERROR-CODE' = {405, <<"Method Not Allowed">>}} + end; +process(_Addr, _Port, #stun{class = request} = Msg) -> + Resp = prepare_response(Msg), + Resp#stun{class = error, + 'UNKNOWN-ATTRIBUTES' = Msg#stun.unsupported, + 'ERROR-CODE' = {420, stun_codec:reason(420)}}; +process(_Addr, _Port, _Msg) -> + pass. + +prepare_response(Msg) -> + Version = list_to_binary("ejabberd " ++ ?VERSION), + #stun{method = Msg#stun.method, + magic = Msg#stun.magic, + trid = Msg#stun.trid, + 'SOFTWARE' = Version}. + +process_data(NextStateName, #state{buf = Buf} = State, Data) -> + NewBuf = <>, + case stun_codec:decode(NewBuf) of + {ok, Msg, Tail} -> + gen_fsm:send_event(self(), Msg), + process_data(NextStateName, State#state{buf = <<>>}, Tail); + empty -> + NewState = State#state{buf = <<>>}, + {next_state, NextStateName, update_state(NewState)}; + more when size(NewBuf) < ?MAX_BUF_SIZE -> + NewState = State#state{buf = NewBuf}, + {next_state, NextStateName, update_state(NewState)}; + _ -> + {stop, normal, State} + end. + +update_state(#state{sock = Sock} = State) -> + case State#state.sock_mod of + gen_tcp -> + inet:setopts(Sock, [{active, once}]); + SockMod -> + SockMod:setopts(Sock, [{active, once}]) + end, + cancel_timer(State#state.tref), + TRef = erlang:start_timer(?TIMEOUT, self(), stop), + State#state{tref = TRef}. + +cancel_timer(TRef) -> + case erlang:cancel_timer(TRef) of + false -> + receive + {timeout, TRef, _} -> + ok + after 0 -> + ok + end; + _ -> + ok + end. diff --git a/src/stun/stun.hrl b/src/stun/stun.hrl new file mode 100644 index 000000000..c22184449 --- /dev/null +++ b/src/stun/stun.hrl @@ -0,0 +1,78 @@ +%%%------------------------------------------------------------------- +%%% File : stun.hrl +%%% Author : Evgeniy Khramtsov +%%% Description : STUN values +%%% Created : 8 Aug 2009 by Evgeniy Khramtsov +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%%------------------------------------------------------------------- +-define(STUN_MAGIC, 16#2112a442). + +%% I know, this is terrible. Refer to 'STUN Message Structure' of +%% RFC5389 to understand this. +-define(STUN_METHOD(Type), + ((Type band 16#3e00) bsr 2) bor + ((Type band 16#e0) bsr 1) bor (Type band 16#f)). +-define(STUN_CLASS(Type), + ((Type band 16#100) bsr 7) bor + ((Type band 16#10) bsr 4)). +-define(STUN_TYPE(C, M), + (((M band 16#f80) bsl 2) + bor ((M band 16#70) bsl 1) + bor (M band 16#f) ) + bor (((C band 16#2) bsl 7) bor ((C band 16#1) bsl 4))). + +-define(is_required(A), (A =< 16#7fff)). + +-define(STUN_METHOD_BINDING, 16#001). + +%% Comprehension-required range (0x0000-0x7FFF) +-define(STUN_ATTR_MAPPED_ADDRESS, 16#0001). +-define(STUN_ATTR_USERNAME, 16#0006). +-define(STUN_ATTR_MESSAGE_INTEGRITY, 16#0008). +-define(STUN_ATTR_ERROR_CODE, 16#0009). +-define(STUN_ATTR_UNKNOWN_ATTRIBUTES, 16#000a). +-define(STUN_ATTR_REALM, 16#0014). +-define(STUN_ATTR_NONCE, 16#0015). +-define(STUN_ATTR_XOR_MAPPED_ADDRESS, 16#0020). + +%% Comprehension-optional range (0x8000-0xFFFF) +-define(STUN_ATTR_SOFTWARE, 16#8022). +-define(STUN_ATTR_ALTERNATE_SERVER, 16#8023). +-define(STUN_ATTR_FINGERPRINT, 16#8028). + +-record(stun, {class, + method, + magic = ?STUN_MAGIC, + trid, + unsupported = [], + 'SOFTWARE', + 'ALTERNATE-SERVER', + 'MAPPED-ADDRESS', + 'XOR-MAPPED-ADDRESS', + 'USERNAME', + 'REALM', + 'NONCE', + 'MESSAGE-INTEGRITY', + 'ERROR-CODE', + 'UNKNOWN-ATTRIBUTES' = []}). + +%% Workarounds. +%%-define(NO_PADDING, true). diff --git a/src/stun/stun_codec.erl b/src/stun/stun_codec.erl new file mode 100644 index 000000000..2539da996 --- /dev/null +++ b/src/stun/stun_codec.erl @@ -0,0 +1,343 @@ +%%%------------------------------------------------------------------- +%%% File : stun_codec.erl +%%% Author : Evgeniy Khramtsov +%%% Description : STUN codec +%%% Created : 7 Aug 2009 by Evgeniy Khramtsov +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%%------------------------------------------------------------------- +-module(stun_codec). + +%% API +-export([decode/1, + encode/1, + version/1, + reason/1, + pp/1]). + +%% Tests +-export([test_udp/2, + test_tcp/2, + test_tls/2, + test_public/0]). + +-include("stun.hrl"). + +%%==================================================================== +%% API +%%==================================================================== +decode(<<0:2, Type:14, Len:16, Magic:32, TrID:96, + Body:Len/binary, Tail/binary>>) -> + case catch decode(Type, Magic, TrID, Body) of + {'EXIT', _} -> + {error, unparsed}; + Res -> + {ok, Res, Tail} + end; +decode(<<0:2, _/binary>>) -> + more; +decode(<<>>) -> + empty; +decode(_) -> + {error, unparsed}. + +encode(#stun{class = Class, + method = Method, + magic = Magic, + trid = TrID} = Msg) -> + ClassCode = case Class of + request -> 0; + indication -> 1; + response -> 2; + error -> 3 + end, + Type = ?STUN_TYPE(ClassCode, Method), + Attrs = enc_attrs(Msg), + Len = size(Attrs), + <<0:2, Type:14, Len:16, Magic:32, TrID:96, Attrs/binary>>. + +pp(Term) -> + io_lib_pretty:print(Term, fun pp/2). + +version(#stun{magic = ?STUN_MAGIC}) -> + new; +version(#stun{}) -> + old. + +reason(300) -> <<"Try Alternate">>; +reason(400) -> <<"Bad Request">>; +reason(401) -> <<"Unauthorized">>; +reason(420) -> <<"Unknown Attribute">>; +reason(438) -> <<"Stale Nonce">>; +reason(500) -> <<"Server Error">>; +reason(_) -> <<"Undefined Error">>. + +%%==================================================================== +%% Internal functions +%%==================================================================== +decode(Type, Magic, TrID, Body) -> + Method = ?STUN_METHOD(Type), + Class = case ?STUN_CLASS(Type) of + 0 -> request; + 1 -> indication; + 2 -> response; + 3 -> error + end, + dec_attrs(Body, #stun{class = Class, + method = Method, + magic = Magic, + trid = TrID}). + +dec_attrs(<>, Msg) -> + PaddLen = padd_len(Len), + <> = Rest, + NewMsg = dec_attr(Type, Val, Msg), + if Type == ?STUN_ATTR_MESSAGE_INTEGRITY -> + NewMsg; + true -> + dec_attrs(Tail, NewMsg) + end; +dec_attrs(<<>>, Msg) -> + Msg. + +enc_attrs(Msg) -> + concat_binary( + [enc_attr(?STUN_ATTR_SOFTWARE, Msg#stun.'SOFTWARE'), + enc_addr(?STUN_ATTR_MAPPED_ADDRESS, Msg#stun.'MAPPED-ADDRESS'), + enc_xor_addr(?STUN_ATTR_XOR_MAPPED_ADDRESS, + Msg#stun.magic, Msg#stun.trid, + Msg#stun.'XOR-MAPPED-ADDRESS'), + enc_addr(?STUN_ATTR_ALTERNATE_SERVER, Msg#stun.'ALTERNATE-SERVER'), + enc_attr(?STUN_ATTR_USERNAME, Msg#stun.'USERNAME'), + enc_attr(?STUN_ATTR_REALM, Msg#stun.'REALM'), + enc_attr(?STUN_ATTR_NONCE, Msg#stun.'NONCE'), + enc_error_code(Msg#stun.'ERROR-CODE'), + enc_unknown_attrs(Msg#stun.'UNKNOWN-ATTRIBUTES')]). + +dec_attr(?STUN_ATTR_MAPPED_ADDRESS, Val, Msg) -> + <<_, Family, Port:16, AddrBin/binary>> = Val, + Addr = dec_addr(Family, AddrBin), + Msg#stun{'MAPPED-ADDRESS' = {Addr, Port}}; +dec_attr(?STUN_ATTR_XOR_MAPPED_ADDRESS, Val, Msg) -> + <<_, Family, XPort:16, XAddr/binary>> = Val, + Magic = Msg#stun.magic, + Port = XPort bxor (Magic bsr 16), + Addr = dec_xor_addr(Family, Magic, Msg#stun.trid, XAddr), + Msg#stun{'XOR-MAPPED-ADDRESS' = {Addr, Port}}; +dec_attr(?STUN_ATTR_SOFTWARE, Val, Msg) -> + Msg#stun{'SOFTWARE' = Val}; +dec_attr(?STUN_ATTR_USERNAME, Val, Msg) -> + Msg#stun{'USERNAME' = Val}; +dec_attr(?STUN_ATTR_REALM, Val, Msg) -> + Msg#stun{'REALM' = Val}; +dec_attr(?STUN_ATTR_NONCE, Val, Msg) -> + Msg#stun{'NONCE' = Val}; +dec_attr(?STUN_ATTR_MESSAGE_INTEGRITY, Val, Msg) -> + Msg#stun{'MESSAGE-INTEGRITY' = Val}; +dec_attr(?STUN_ATTR_ALTERNATE_SERVER, Val, Msg) -> + <<_, Family, Port:16, Address/binary>> = Val, + IP = dec_addr(Family, Address), + Msg#stun{'ALTERNATE-SERVER' = {IP, Port}}; +dec_attr(?STUN_ATTR_ERROR_CODE, Val, Msg) -> + <<_:21, Class:3, Number:8, Reason/binary>> = Val, + if Class >=3, Class =< 6, Number >=0, Number =< 99 -> + Code = Class * 100 + Number, + Msg#stun{'ERROR-CODE' = {Code, Reason}} + end; +dec_attr(?STUN_ATTR_UNKNOWN_ATTRIBUTES, Val, Msg) -> + Attrs = dec_unknown_attrs(Val, []), + Msg#stun{'UNKNOWN-ATTRIBUTES' = Attrs}; +dec_attr(Attr, _Val, #stun{unsupported = Attrs} = Msg) + when Attr =< 16#7fff -> + Msg#stun{unsupported = [Attr|Attrs]}; +dec_attr(_Attr, _Val, Msg) -> + Msg. + +dec_addr(1, <>) -> + {A1, A2, A3, A4}; +dec_addr(2, <>) -> + {A1, A2, A3, A4, A5, A6, A7, A8}. + +dec_xor_addr(1, Magic, _TrID, <>) -> + Addr = XAddr bxor Magic, + dec_addr(1, <>); +dec_xor_addr(2, Magic, TrID, <>) -> + Addr = XAddr bxor ((Magic bsl 96) bor TrID), + dec_addr(2, <>). + +dec_unknown_attrs(<>, Acc) -> + dec_unknown_attrs(Tail, [Attr|Acc]); +dec_unknown_attrs(<<>>, Acc) -> + lists:reverse(Acc). + +enc_attr(_Attr, undefined) -> + <<>>; +enc_attr(Attr, Val) -> + Len = size(Val), + PaddLen = padd_len(Len), + <>. + +enc_addr(_Type, undefined) -> + <<>>; +enc_addr(Type, {{A1, A2, A3, A4}, Port}) -> + enc_attr(Type, <<0, 1, Port:16, A1, A2, A3, A4>>); +enc_addr(Type, {{A1, A2, A3, A4, A5, A6, A7, A8}, Port}) -> + enc_attr(Type, <<0, 2, Port:16, A1:16, A2:16, A3:16, + A4:16, A5:16, A6:16, A7:16, A8:16>>). + +enc_xor_addr(_Type, _Magic, _TrID, undefined) -> + <<>>; +enc_xor_addr(Type, Magic, _TrID, {{A1, A2, A3, A4}, Port}) -> + XPort = Port bxor (Magic bsr 16), + <> = <>, + XAddr = Addr bxor Magic, + enc_attr(Type, <<0, 1, XPort:16, XAddr:32>>); +enc_xor_addr(Type, Magic, TrID, + {{A1, A2, A3, A4, A5, A6, A7, A8}, Port}) -> + XPort = Port bxor (Magic bsr 16), + <> = <>, + XAddr = Addr bxor ((Magic bsl 96) bor TrID), + enc_attr(Type, <<0, 2, XPort:16, XAddr:128>>). + +enc_error_code(undefined) -> + <<>>; +enc_error_code({Code, Reason}) -> + Class = Code div 100, + Number = Code rem 100, + enc_attr(?STUN_ATTR_ERROR_CODE, + <<0:21, Class:3, Number:8, Reason/binary>>). + +enc_unknown_attrs([]) -> + <<>>; +enc_unknown_attrs(Attrs) -> + enc_attr(?STUN_ATTR_UNKNOWN_ATTRIBUTES, + concat_binary([<> || Attr <- Attrs])). + +%%==================================================================== +%% Auxiliary functions +%%==================================================================== +pp(Tag, N) -> + try + pp1(Tag, N) + catch _:_ -> + no + end. + +pp1(stun, N) -> + N = record_info(size, stun) - 1, + record_info(fields, stun); +pp1(_, _) -> + no. + +%% Workaround for stupid clients. +-ifdef(NO_PADDING). +padd_len(_Len) -> + 0. +-else. +padd_len(Len) -> + case Len rem 4 of + 0 -> 0; + N -> 8*(4-N) + end. +-endif. + +%%==================================================================== +%% Test functions +%%==================================================================== +bind_msg() -> + Msg = #stun{method = ?STUN_METHOD_BINDING, + class = request, + trid = random:uniform(1 bsl 96), + 'SOFTWARE' = <<"test">>}, + encode(Msg). + +test_udp(Addr, Port) -> + test(Addr, Port, gen_udp). + +test_tcp(Addr, Port) -> + test(Addr, Port, gen_tcp). + +test_tls(Addr, Port) -> + test(Addr, Port, ssl). + +test(Addr, Port, Mod) -> + Res = case Mod of + gen_udp -> + Mod:open(0, [binary, {active, false}]); + _ -> + Mod:connect(Addr, Port, + [binary, {active, false}], 1000) + end, + case Res of + {ok, Sock} -> + if Mod == gen_udp -> + Mod:send(Sock, Addr, Port, bind_msg()); + true -> + Mod:send(Sock, bind_msg()) + end, + case Mod:recv(Sock, 0, 1000) of + {ok, {_, _, Data}} -> + try_dec(Data); + {ok, Data} -> + try_dec(Data); + Err -> + io:format("err: ~p~n", [Err]) + end, + Mod:close(Sock); + Err -> + io:format("err: ~p~n", [Err]) + end. + +try_dec(Data) -> + case decode(Data) of + {ok, Msg, _} -> + io:format("got:~n~s~n", [pp(Msg)]); + Err -> + io:format("err: ~p~n", [Err]) + end. + +public_servers() -> + [{"stun.ekiga.net", 3478, 3478, 5349}, + {"stun.fwdnet.net", 3478, 3478, 5349}, + {"stun.ideasip.com", 3478, 3478, 5349}, + {"stun01.sipphone.com", 3478, 3478, 5349}, + {"stun.softjoys.com", 3478, 3478, 5349}, + {"stun.voipbuster.com", 3478, 3478, 5349}, + {"stun.voxgratia.org", 3478, 3478, 5349}, + {"stun.xten.com", 3478, 3478, 5349}, + {"stunserver.org", 3478, 3478, 5349}, + {"stun.sipgate.net", 10000, 10000, 5349}, + {"numb.viagenie.ca", 3478, 3478, 5349}, + {"stun.ipshka.com", 3478, 3478, 5349}, + {"localhost", 3478, 5349, 5349}]. + +test_public() -> + ssl:start(), + lists:foreach( + fun({Addr, UDPPort, TCPPort, TLSPort}) -> + io:format("trying ~s:~p on UDP... ", [Addr, UDPPort]), + test_udp(Addr, UDPPort), + io:format("trying ~s:~p on TCP... ", [Addr, TCPPort]), + test_tcp(Addr, TCPPort), + io:format("trying ~s:~p on TLS... ", [Addr, TLSPort]), + test_tls(Addr, TLSPort) + end, public_servers()). From cf90c8176e713a2ef8db6c653f986bf4cb624e1f Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Tue, 11 Aug 2009 13:17:46 +0000 Subject: [PATCH 492/582] updated top supervisor for STUN support SVN Revision: 2459 --- src/ejabberd_sup.erl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ejabberd_sup.erl b/src/ejabberd_sup.erl index 6163dfee0..11c56037c 100644 --- a/src/ejabberd_sup.erl +++ b/src/ejabberd_sup.erl @@ -169,6 +169,14 @@ init([]) -> infinity, supervisor, [ejabberd_tmp_sup]}, + STUNSupervisor = + {ejabberd_stun_sup, + {ejabberd_tmp_sup, start_link, + [ejabberd_stun_sup, ejabberd_stun]}, + permanent, + infinity, + supervisor, + [ejabberd_tmp_sup]}, {ok, {{one_for_one, 10, 1}, [Hooks, NodeGroups, @@ -186,6 +194,7 @@ init([]) -> HTTPSupervisor, HTTPPollSupervisor, IQSupervisor, + STUNSupervisor, FrontendSocketSupervisor, Listener]}}. From 3078c28d1a99e391d369d40296373de15d059dfb Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 11 Aug 2009 13:22:39 +0000 Subject: [PATCH 493/582] Document STUN server (thanks to Evgeniy Khramtsov), and minor doc enhancements. * Add stun listener to example config file, disabled. * Improve enumeration of listeners options SVN Revision: 2460 --- doc/guide.html | 437 +++++++++++++++++++++++---------------- doc/guide.tex | 56 ++++- src/ejabberd.cfg.example | 5 + 3 files changed, 312 insertions(+), 186 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 310abe64a..4770c5308 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -6,7 +6,7 @@ - ejabberd 3.0.0-alpha + ejabberd 2.1.0-alpha Installation and Operation Guide @@ -76,7 +76,7 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}




    - +
    ejabberd 3.0.0-alpha
    ejabberd 2.1.0-alpha
     
    Installation and Operation Guide

    @@ -144,80 +144,81 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}
  • 3.3.5  mod_echo
  • 3.3.6  mod_http_bind
  • 3.3.7  mod_http_fileserver -
  • 3.3.8  mod_last -
  • 3.3.9  mod_muc -
  • 3.3.10  mod_muc_log -
  • 3.3.11  mod_offline -
  • 3.3.12  mod_ping -
  • 3.3.13  mod_privacy -
  • 3.3.14  mod_private -
  • 3.3.15  mod_proxy65 -
  • 3.3.16  mod_pubsub -
  • 3.3.17  mod_register -
  • 3.3.18  mod_roster -
  • 3.3.19  mod_service_log -
  • 3.3.20  mod_shared_roster -
  • 3.3.21  mod_stats -
  • 3.3.22  mod_time -
  • 3.3.23  mod_vcard -
  • 3.3.24  mod_vcard_ldap -
  • 3.3.25  mod_version +
  • 3.3.8  mod_irc +
  • 3.3.9  mod_last +
  • 3.3.10  mod_muc +
  • 3.3.11  mod_muc_log +
  • 3.3.12  mod_offline +
  • 3.3.13  mod_ping +
  • 3.3.14  mod_privacy +
  • 3.3.15  mod_private +
  • 3.3.16  mod_proxy65 +
  • 3.3.17  mod_pubsub +
  • 3.3.18  mod_register +
  • 3.3.19  mod_roster +
  • 3.3.20  mod_service_log +
  • 3.3.21  mod_shared_roster +
  • 3.3.22  mod_stats +
  • 3.3.23  mod_time +
  • 3.3.24  mod_vcard +
  • 3.3.25  mod_vcard_ldap +
  • 3.3.26  mod_version
  • -
  • Chapter 4  Managing an ejabberd Server +
  • Chapter 4  Managing an ejabberd Server -
  • Chapter 5  Securing ejabberd +
  • Chapter 5  Securing ejabberd -
  • Chapter 6  Clustering +
  • Chapter 6  Clustering -
  • Chapter 7  Debugging +
  • Chapter 7  Debugging -
  • Appendix A  Internationalization and Localization -
  • Appendix B  Release Notes -
  • Appendix C  Acknowledgements -
  • Appendix D  Copyright Information +
  • Appendix A  Internationalization and Localization +
  • Appendix B  Release Notes +
  • Appendix C  Acknowledgements +
  • Appendix D  Copyright Information
  • Chapter 1  Introduction

    -

    ejabberd is a free and open source instant messaging server written in Erlang/OTP.

    ejabberd is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.

    ejabberd is designed to be a rock-solid and feature rich XMPP server.

    ejabberd is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.

    +

    ejabberd is a free and open source instant messaging server written in Erlang.

    ejabberd is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.

    ejabberd is designed to be a rock-solid and feature rich XMPP server.

    ejabberd is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.

    1.1  Key Features

    ejabberd is: @@ -268,12 +269,13 @@ Internal Authentication.

  • Others
  • @@ -336,14 +338,16 @@ as long as your system have all the dependencies.

    2.4.2  Download Source Code

    Released versions of ejabberd are available in the ProcessOne ejabberd downloads page: @@ -458,25 +462,31 @@ for example:

    Requirements

    To compile ejabberd on a Microsoft Windows system, you need:

    Compilation

    We assume that we will try to put as much library as possible into C:\sdk\ to make it easier to track what is install for ejabberd.

    1. -Install Erlang emulator (for example, into C:\sdk\erl5.6.5). +Install Erlang emulator (for example, into C:\sdk\erl5.5.5).
    2. Install Expat library into C:\sdk\Expat-2.0.0 directory.

      Copy file C:\sdk\Expat-2.0.0\Libs\libexpat.dll to your Windows system directory (for example, C:\WINNT or C:\WINNT\System32) -Note: instead of copying libexpat.dll to the Windows -directory, you can add the directory C:\sdk\Expat-2.0.0\Libs -to the PATH environment variable. +

    3. Build and install the Iconv library into the directory +C:\sdk\GnuWin32.

      Copy file C:\sdk\GnuWin32\bin\lib*.dll to your +Windows system directory (more installation instructions can be found in the +file README.woe32 in the iconv distribution).

      Note: instead of copying libexpat.dll and iconv.dll to the Windows +directory, you can add the directories +C:\sdk\Expat-2.0.0\Libs and +C:\sdk\GnuWin32\bin to the PATH environment +variable.

    4. Install OpenSSL in C:\sdk\OpenSSL and add C:\sdk\OpenSSL\lib\VC to your path or copy the binaries to your system directory.
    5. Install ZLib in C:\sdk\gnuWin32. Copy -C:\sdk\GnuWin32\bin\zlib1.dll to your system directory. +C:\sdk\GnuWin32\bin\zlib1.dll to your system directory. If you change your path it should already be set after libiconv install.
    6. Make sure the you can access Erlang binaries from your path. For example: set PATH=%PATH%;"C:\sdk\erl5.6.5\bin"
    7. Depending on how you end up actually installing the library you might need to check and tweak the paths in the file configure.erl.
    8. While in the directory ejabberd\src run: @@ -493,7 +503,7 @@ There are two ways to register a Jabber account:
      1. Using ejabberdctl (see section 4.1):
        ejabberdctl register admin1 example.org FgT5bk3
        -
      2. Using a Jabber client and In-Band Registration (see section 3.3.17). +
      3. Using a Jabber client and In-Band Registration (see section 3.3.18).
    9. Edit the ejabberd configuration file to give administration rights to the Jabber account you created:
      {acl, admins, {user, "admin1", "example.org"}}.
      @@ -667,7 +677,7 @@ Handles incoming s2s connections.
      Options: max_stanza_size
    ejabberd_service
    Interacts with an external component -(as defined in the Jabber Component Protocol (XEP-0114).
    +(as defined in the Jabber Component Protocol (XEP-0114).
    Options: access, hosts, shaper, service_check_from
    ejabberd_http
    @@ -685,7 +695,7 @@ To define a certificate file specific for a given domain, use the global option This option can be used with ejabberd_service only. It is used to disable control on the from field on packets send by an external components. The option can be either true or -false. The default value is true which conforms to XEP-0114. +false. The default value is true which conforms to XEP-0114.
    {hosts, [Hostnames], [HostOptions]}
    The external Jabber component that connects to this ejabberd_service can serve one or more hostnames. @@ -698,7 +708,7 @@ as seen in an example below.
    captcha
    Simple web page that allows a user to fill a CAPTCHA challenge (see section 3.1.8).
    http_bind
    -This option enables HTTP Binding (XEP-0124 and XEP-0206) support. HTTP Bind +This option enables HTTP Binding (XEP-0124 and XEP-0206) support. HTTP Bind enables access via HTTP requests to ejabberd from behind firewalls which do not allow outgoing sockets on port 5222.

    Remember that you must also install and enable the module mod_http_bind.

    If HTTP Bind is enabled, it will be available at http://server:port/http-bind/. Be aware that support for HTTP Bind @@ -709,7 +719,7 @@ interesting to host a web-based Jabber client such as embedded local web server or Apache).

    http_poll
    -This option enables HTTP Polling (XEP-0025) support. HTTP Polling +This option enables HTTP Polling (XEP-0025) support. HTTP Polling enables access via HTTP requests to ejabberd from behind firewalls which do not allow outgoing sockets on port 5222.

    If HTTP Polling is enabled, it will be available at http://server:port/http-poll/. Be aware that support for HTTP Polling @@ -735,7 +745,7 @@ and you also want mod_http_bind to serve the URIs /http-bind/, use this option: {request_handlers, [{["a", "b"], mod_foo}, {["http-bind"], mod_http_bind}]}

    {service_check_from, true|false}
    By enabling this option, ejabberd allows the component to send packets with any arbitrary domain in the ’from’ attribute. -Note that XEP-0114 requires that the domain must match the hostname of the component. +Note that XEP-0114 requires that the domain must match the hostname of the component. Only enable this option if you are completely sure you need to enable it. Default value: false.
    {shaper, <access rule>}
    This option defines a @@ -756,7 +766,7 @@ This was the traditional encryption method in the early Jabber software, commonly on port 5223 for client-to-server communications. But this method is nowadays deprecated and not recommended. The preferable encryption method is STARTTLS on port 5222, as defined -RFC 3920: XMPP Core, +RFC 3920: XMPP Core, which can be enabled in ejabberd with the option starttls. If this option is set, you should also set the certfile option.
    web_admin
    This option @@ -765,7 +775,7 @@ at http://server:port/admin/. Login and password are the username a password of one of the registered users who are granted access by the ‘configure’ access rule.
    zlib
    This -option specifies that Zlib stream compression (as defined in XEP-0138) +option specifies that Zlib stream compression (as defined in XEP-0138) is available on connections to the port. Client connections cannot use stream compression and stream encryption simultaneously. Hence, if you specify both starttls (or tls) and zlib, the latter @@ -1216,7 +1226,7 @@ can be seen by Jabber clients. If a Jabber client does not support

    Appendix A provides more details about internationalization and localization.

    3.1.8  CAPTCHA

    Some ejabberd modules can be configured to require a CAPTCHA challenge on certain actions. -If the client does not support CAPTCHA Forms (XEP-0158), +If the client does not support CAPTCHA Forms (XEP-0158), a web link is provided so the user can fill the challenge in a web browser.

    An example script is provided that generates the image using ImageMagick’s Convert program.

    The configurable options are:

    @@ -1616,7 +1626,7 @@ user’s part of a JID. For example, "%u@example.org". The default value is "%u".
    ldap_filter
    -RFC 4515 LDAP filter. The +RFC 2254 LDAP filter. The default is none. Example: "(&(objectClass=shadowAccount)(memberOf=Jabber Users))". Please, do not forget to close brackets and do not use superfluous whitespaces. Also you @@ -1775,37 +1785,38 @@ all entries end with a comma:

    3.3.1  Modules Overview

    The following table lists all modules included in ejabberd.


    - + - + - + - - - + + + + - - - + + + - - - - - + + + + + - - - - - - + + + + + +
    ModuleFeatureDependencies
    mod_adhocAd-Hoc Commands (XEP-0050) 
    mod_adhocAd-Hoc Commands (XEP-0050) 
    mod_announceManage announcementsrecommends mod_adhoc
    mod_capsEntity Capabilities (XEP-0115) 
    mod_capsEntity Capabilities (XEP-0115) 
    mod_configureServer configuration using Ad-Hocmod_adhoc
    mod_discoService Discovery (XEP-0030) 
    mod_discoService Discovery (XEP-0030) 
    mod_echoEchoes Jabber packets 
    mod_lastLast Activity (XEP-0012) 
    mod_last_odbcLast Activity (XEP-0012)supported DB (*)
    mod_mucMulti-User Chat (XEP-0045) 
    mod_ircIRC transport 
    mod_lastLast Activity (XEP-0012) 
    mod_last_odbcLast Activity (XEP-0012)supported DB (*)
    mod_mucMulti-User Chat (XEP-0045) 
    mod_muc_logMulti-User Chat room loggingmod_muc
    mod_offlineOffline message storage (XEP-0160) 
    mod_offline_odbcOffline message storage (XEP-0160)supported DB (*)
    mod_pingXMPP Ping and periodic keepalives (XEP-0199) 
    mod_offlineOffline message storage (XEP-0160) 
    mod_offline_odbcOffline message storage (XEP-0160)supported DB (*)
    mod_pingXMPP Ping and periodic keepalives (XEP-0199) 
    mod_privacyBlocking Communication (XMPP IM) 
    mod_privacy_odbcBlocking Communication (XMPP IM)supported DB (*)
    mod_privatePrivate XML Storage (XEP-0049) 
    mod_private_odbcPrivate XML Storage (XEP-0049)supported DB (*)
    mod_proxy65SOCKS5 Bytestreams (XEP-0065) 
    mod_pubsubPub-Sub (XEP-0060), PEP (XEP-0163)mod_caps
    mod_registerIn-Band Registration (XEP-0077) 
    mod_privatePrivate XML Storage (XEP-0049) 
    mod_private_odbcPrivate XML Storage (XEP-0049)supported DB (*)
    mod_proxy65SOCKS5 Bytestreams (XEP-0065) 
    mod_pubsubPub-Sub (XEP-0060), PEP (XEP-0163)mod_caps
    mod_registerIn-Band Registration (XEP-0077) 
    mod_rosterRoster management (XMPP IM) 
    mod_roster_odbcRoster management (XMPP IM)supported DB (*)
    mod_service_logCopy user messages to logger service 
    mod_shared_rosterShared roster managementmod_roster or
      mod_roster_odbc
    mod_statsStatistics Gathering (XEP-0039) 
    mod_timeEntity Time (XEP-0202) 
    mod_vcardvcard-temp (XEP-0054) 
    mod_vcard_ldapvcard-temp (XEP-0054)LDAP server
    mod_vcard_odbcvcard-temp (XEP-0054)supported DB (*)
    mod_versionSoftware Version (XEP-0092) 
    mod_statsStatistics Gathering (XEP-0039) 
    mod_timeEntity Time (XEP-0202) 
    mod_vcardvcard-temp (XEP-0054) 
    mod_vcard_ldapvcard-temp (XEP-0054)LDAP server
    mod_vcard_odbcvcard-temp (XEP-0054)supported DB (*)
    mod_versionSoftware Version (XEP-0092) 

    • (*) This module requires a supported database. For a list of supported databases, see section 3.2. @@ -1902,7 +1913,7 @@ message is sent to all registered users. If the user is online and connected to several resources, only the resource with the highest priority will receive the message. If the registered user is not connected, the message will be stored offline in assumption that offline storage -(see section 3.3.11) is enabled. +(see section 3.3.12) is enabled.
    example.org/announce/online (example.org/announce/all-hosts/online)
    The message is sent to all connected users. If the user is online and connected to several resources, all resources will receive the message. @@ -1955,11 +1966,11 @@ disabled for instances of ejabberd with hundreds of thousands users.

    This module adds support for Service Discovery (XEP-0030). With +

    This module adds support for Service Discovery (XEP-0030). With this module enabled, services on your server can be discovered by Jabber clients. Note that ejabberd has no modules with support -for the superseded Jabber Browsing (XEP-0011) and Agent Information -(XEP-0094). Accordingly, Jabber clients need to have support for +for the superseded Jabber Browsing (XEP-0011) and Agent Information +(XEP-0094). Accordingly, Jabber clients need to have support for the newer Service Discovery protocol if you want them be able to discover the services you offer.

    Options:

    @@ -1970,7 +1981,7 @@ the processing discipline for Service Discovery (http://jabber.org/protocol/ you can specify a list of extra domains that are added to the Service Discovery item list.
    {server_info, [ {Modules, Field, [Value]} ]}
    Specify additional information about the server, -as described in Contact Addresses for XMPP Services (XEP-0157). +as described in Contact Addresses for XMPP Services (XEP-0157). Modules can be the keyword ‘all’, in which case the information is reported in all the services; or a list of ejabberd modules, @@ -2046,7 +2057,7 @@ of them all?

    3.3.6  mod_http_bind

    This module implements XMPP over Bosh (formerly known as HTTP Binding) -as defined in XEP-0124 and XEP-0206. +as defined in XEP-0124 and XEP-0206. It extends ejabberd’s built in HTTP service with a configurable resource at which this service will be hosted.

    To use HTTP-Binding, enable the module:

    {modules,
    @@ -2154,9 +2165,69 @@ To use this module you must enable it:
       },
       ...
     ]}.
    -

    -

    3.3.8  mod_last

    -

    This module adds support for Last Activity (XEP-0012). It can be used to +

    +

    3.3.8  mod_irc

    +

    This module is an IRC transport that can be used to join channels on IRC +servers.

    End user information: + +

    • +A Jabber client with ‘groupchat 1.0’ support or Multi-User +Chat support (XEP-0045) is necessary to join IRC channels. +
    • An IRC channel can be joined in nearly the same way as joining a +Jabber Multi-User Chat room. The difference is that the room name will +be ‘channel%irc.example.org’ in case irc.example.org is +the IRC server hosting ‘channel’. And of course the host should point +to the IRC transport instead of the Multi-User Chat service. +
    • You can register your nickame by sending ‘IDENTIFY password’ to
      + nickserver!irc.example.org@irc.jabberserver.org. +
    • Entering your password is possible by sending ‘LOGIN nick password’
      + to nickserver!irc.example.org@irc.jabberserver.org. +
    • The IRC transport provides Ad-Hoc Commands (XEP-0050) +to join a channel, and to set custom IRC username and encoding. +
    • When using a popular Jabber server, it can occur that no +connection can be achieved with some IRC servers because they limit the +number of conections from one IP. +

    Options: +

    + +host
    This option defines the Jabber ID of the +service. If the host option is not specified, the Jabber ID will be the +hostname of the virtual host with the prefix ‘irc.’. The keyword "@HOST@" +is replaced at start time with the real virtual host name. + +
    access
    This option can be used to specify who +may use the IRC transport (default value: all). +
    default_encoding
    Set the default IRC encoding (default value: "koi8-r"). +

    Examples: +

    • +In the first example, the IRC transport is available on (all) your +virtual host(s) with the prefix ‘irc.’. Furthermore, anyone is +able to use the transport. The default encoding is set to "iso8859-15". +
      {modules,
      + [
      +  ...
      +  {mod_irc, [{access, all}, {default_encoding, "iso8859-15"}]},
      +  ...
      + ]}.
      +
    • In next example the IRC transport is available with JIDs with prefix irc-t.net. +Moreover, the transport is only accessible to two users +of example.org, and any user of example.com: +
      {acl, paying_customers, {user, "customer1", "example.org"}}.
      +{acl, paying_customers, {user, "customer2", "example.org"}}.
      +{acl, paying_customers, {server, "example.com"}}.
      +
      +{access, irc_users, [{allow, paying_customers}, {deny, all}]}.
      +
      +{modules,
      + [
      +  ...
      +  {mod_irc, [{access, irc_users},
      +             {host, "irc.example.net"}]},
      +  ...
      + ]}.
      +

    +

    3.3.9  mod_last

    +

    This module adds support for Last Activity (XEP-0012). It can be used to discover when a disconnected user last accessed the server, to know when a connected user was last active on the server, or to query the uptime of the ejabberd server.

    Options: @@ -2164,8 +2235,8 @@ connected user was last active on the server, or to query the uptime of the iqdisc

    This specifies the processing discipline for Last activity (jabber:iq:last) IQ queries (see section 3.3.2).

    -

    3.3.9  mod_muc

    -

    This module provides a Multi-User Chat (XEP-0045) service. +

    3.3.10  mod_muc

    +

    This module provides a Multi-User Chat (XEP-0045) service. Users can discover existing rooms, join or create them. Occupants of a room can chat in public or have private chats.

    Some of the features of Multi-User Chat:

    • @@ -2387,7 +2458,7 @@ the newly created rooms have by default those options. ... ]}.

    -

    3.3.10  mod_muc_log

    +

    3.3.11  mod_muc_log

    This module enables optional logging of Multi-User Chat (MUC) public conversations to HTML. Once you enable this module, users can join a room using a MUC capable Jabber client, and if they have enough privileges, they can request the @@ -2397,7 +2468,7 @@ Room details are added on top of each page: room title, JID, author, subject and configuration.

  • The room JID in the generated HTML is a link to join the room (using -XMPP URI). +XMPP URI).
  • Subject and room configuration changes are tracked and displayed.
  • Joins, leaves, nick changes, kicks, bans and ‘/me’ are tracked and displayed, including the reason if available. @@ -2507,8 +2578,8 @@ top link will be the default <a href="/">Home</a>. ... ]}.
  • -

    3.3.11  mod_offline

    -

    This module implements offline message storage (XEP-0160). +

    3.3.12  mod_offline

    +

    This module implements offline message storage (XEP-0160). This means that all messages sent to an offline user will be stored on the server until that user comes online again. Thus it is very similar to how email works. Note that @@ -2539,8 +2610,8 @@ and all the other users up to 100. ... ]}.

    -

    3.3.12  mod_ping

    -

    This module implements support for XMPP Ping (XEP-0199) and periodic keepalives. +

    3.3.13  mod_ping

    +

    This module implements support for XMPP Ping (XEP-0199) and periodic keepalives. When this module is enabled ejabberd responds correctly to ping requests, as defined in the protocol.

    Configuration options:

    @@ -2567,7 +2638,7 @@ and if a client does not answer to the ping in less than 32 seconds, its connect ... ]}.

    -

    3.3.13  mod_privacy

    +

    3.3.14  mod_privacy

    This module implements Blocking Communication (also known as Privacy Rules) as defined in section 10 from XMPP IM. If end users have support for it in their Jabber client, they will be able to: @@ -2589,26 +2660,26 @@ or subscription type (or globally).

  • Allowing or blocking all communications based on JID, group, or subscription type (or globally).
  • -(from http://xmpp.org/specs/rfc3921.html#privacy) +(from http://www.xmpp.org/specs/rfc3921.html#privacy)

    Options:

    iqdisc
    This specifies the processing discipline for Blocking Communication (jabber:iq:privacy) IQ queries (see section 3.3.2).

    -

    3.3.14  mod_private

    -

    This module adds support for Private XML Storage (XEP-0049): +

    3.3.15  mod_private

    +

    This module adds support for Private XML Storage (XEP-0049):

    Using this method, Jabber entities can store private data on the server and retrieve it whenever necessary. The data stored might be anything, as long as it is valid XML. One typical usage for this namespace is the server-side storage -of client-specific preferences; another is Bookmark Storage (XEP-0048). +of client-specific preferences; another is Bookmark Storage (XEP-0048).

    Options:

    iqdisc
    This specifies the processing discipline for Private XML Storage (jabber:iq:private) IQ queries (see section 3.3.2).

    -

    3.3.15  mod_proxy65

    -

    This module implements SOCKS5 Bytestreams (XEP-0065). +

    3.3.16  mod_proxy65

    +

    This module implements SOCKS5 Bytestreams (XEP-0065). It allows ejabberd to act as a file transfer proxy between two XMPP clients.

    Options:

    @@ -2662,10 +2733,10 @@ The simpliest configuration of the module: ... ]}.

    -

    3.3.16  mod_pubsub

    -

    This module offers a Publish-Subscribe Service (XEP-0060). +

    3.3.17  mod_pubsub

    +

    This module offers a Publish-Subscribe Service (XEP-0060). The functionality in mod_pubsub can be extended using plugins. -The plugin that implements PEP (Personal Eventing via Pubsub) (XEP-0163) +The plugin that implements PEP (Personal Eventing via Pubsub) (XEP-0163) is enabled in the default ejabberd configuration file, and it requires mod_caps.

    Options:

    @@ -2708,8 +2779,8 @@ The following example will use node_tune instead of node_pep for every PEP node ... ]}.

    -

    3.3.17  mod_register

    -

    This module adds support for In-Band Registration (XEP-0077). This protocol +

    3.3.18  mod_register

    +

    This module adds support for In-Band Registration (XEP-0077). This protocol enables end users to use a Jabber client to:

    • Register a new account on the server. @@ -2781,10 +2852,10 @@ Also define a registration timeout of one hour: ... ]}.

    -

    3.3.18  mod_roster

    +

    3.3.19  mod_roster

    This module implements roster management as defined in -RFC 3921: XMPP IM. -It also supports Roster Versioning (XEP-0237).

    Options: +RFC 3921: XMPP IM. +It also supports Roster Versioning (XEP-0237).

    Options:

    iqdisc
    This specifies the processing discipline for Roster Management (jabber:iq:roster) IQ queries (see section 3.3.2). @@ -2807,7 +2878,7 @@ Important: if you use mod_shared_roster, you must disable this option. ... ]}.

    -

    3.3.19  mod_service_log

    +

    3.3.20  mod_service_log

    This module adds support for logging end user packets via a Jabber message auditing service such as Bandersnatch. All user @@ -2837,7 +2908,7 @@ To log all end user packets to the Bandersnatch service running on ... ]}.

    -

    3.3.20  mod_shared_roster

    +

    3.3.21  mod_shared_roster

    This module enables you to create shared roster groups. This means that you can create groups of people that can see members from (other) groups in their rosters. The big advantages of this feature are that end users do not need to @@ -2912,8 +2983,8 @@ roster groups as shown in the following table:


    -

    3.3.21  mod_stats

    -

    This module adds support for Statistics Gathering (XEP-0039). This protocol +

    3.3.22  mod_stats

    +

    This module adds support for Statistics Gathering (XEP-0039). This protocol allows you to retrieve next statistics from your ejabberd deployment:

    • Total number of registered users on the current virtual host (users/total). @@ -2944,16 +3015,16 @@ by sending: </query> </iq>

    -

    3.3.22  mod_time

    -

    This module features support for Entity Time (XEP-0202). By using this XEP, +

    3.3.23  mod_time

    +

    This module features support for Entity Time (XEP-0202). By using this XEP, you are able to discover the time at another entity’s location.

    Options:

    iqdisc
    This specifies the processing discipline for Entity Time (jabber:iq:time) IQ queries (see section 3.3.2).

    -

    3.3.23  mod_vcard

    +

    3.3.24  mod_vcard

    This module allows end users to store and retrieve their vCard, and to retrieve -other users vCards, as defined in vcard-temp (XEP-0054). The module also +other users vCards, as defined in vcard-temp (XEP-0054). The module also implements an uncomplicated Jabber User Directory based on the vCards of these users. Moreover, it enables the server to send its vCard when queried.

    Options:

    @@ -3006,7 +3077,7 @@ and that all virtual hosts will be searched instead of only the current one: ... ]}.

    -

    3.3.24  mod_vcard_ldap

    +

    3.3.25  mod_vcard_ldap

    ejabberd can map LDAP attributes to vCard fields. This behaviour is implemented in the mod_vcard_ldap module. This module does not depend on the authentication method (see 3.2.5).

    Note that ejabberd treats LDAP as a read-only storage: @@ -3040,7 +3111,7 @@ all search results are reported. The default value is 30. set the table that maps LDAP attributes to vCard fields. The format is: [Name_of_vCard_field, Pattern, List_of_LDAP_attributes, ...]. Name_of_vcard_field is the type name of the vCard as defined in -RFC 2426. Pattern is a +RFC 2426. Pattern is a string which contains pattern variables "%u", "%d" or "%s". List_of_LDAP_attributes is the list containing LDAP attributes. The pattern variables "%s" will be sequentially replaced @@ -3182,8 +3253,8 @@ searching his info in LDAP.

  • ldap_vcard_map
  • -

    3.3.25  mod_version

    -

    This module implements Software Version (XEP-0092). Consequently, it +

    3.3.26  mod_version

    +

    This module implements Software Version (XEP-0092). Consequently, it answers ejabberd’s version when queried.

    Options:

    show_os
    Should the operating system be revealed or not. @@ -3191,8 +3262,8 @@ The default value is true.
    iqdisc
    This specifies the processing discipline for Software Version (jabber:iq:version) IQ queries (see section 3.3.2).

    -

    Chapter 4  Managing an ejabberd Server

    -

    4.1  ejabberdctl

    With the ejabberdctl command line administration script +

    Chapter 4  Managing an ejabberd Server

    +

    4.1  ejabberdctl

    With the ejabberdctl command line administration script you can execute ejabberdctl commands (described in the next section, 4.1.1) and also many general ejabberd commands (described in section 4.2). This means you can start, stop and perform many other administrative tasks @@ -3204,7 +3275,7 @@ and other codes may be used for specific results. This can be used by other scripts to determine automatically if a command succeeded or failed, for example using: echo $?

    -

    4.1.1  ejabberdctl Commands

    When ejabberdctl is executed without any parameter, +

    4.1.1  ejabberdctl Commands

    When ejabberdctl is executed without any parameter, it displays the available options. If there isn’t an ejabberd server running, the available parameters are:

    @@ -3240,7 +3311,7 @@ robot1 testuser1 testuser2

    -

    4.1.2  Erlang Runtime System

    ejabberd is an Erlang/OTP application that runs inside an Erlang runtime system. +

    4.1.2  Erlang Runtime System

    ejabberd is an Erlang/OTP application that runs inside an Erlang runtime system. This system is configured using environment variables and command line parameters. The ejabberdctl administration script uses many of those possibilities. You can configure some of them with the file ejabberdctl.cfg, @@ -3313,7 +3384,7 @@ Starts the Erlang system detached from the system console.

    Note that some characters need to be escaped when used in shell scripts, for instance " and {}. You can find other options in the Erlang manual page (erl -man erl).

    -

    4.2  ejabberd Commands

    An ejabberd command is an abstract function identified by a name, +

    4.2  ejabberd Commands

    An ejabberd command is an abstract function identified by a name, with a defined number and type of calling arguments and type of result that is registered in the ejabberd_commands service. Those commands can be defined in any Erlang module and executed using any valid frontend.

    ejabberd includes a frontend to execute ejabberd commands: the script ejabberdctl. @@ -3321,7 +3392,7 @@ Other known frontends that can be installed to execute ejabberd commands in diff ejabberd_xmlrpc (XML-RPC service), mod_rest (HTTP POST service), mod_shcommands (ejabberd WebAdmin page).

    -

    4.2.1  List of ejabberd Commands

    ejabberd includes a few ejabberd Commands by default. +

    4.2.1  List of ejabberd Commands

    ejabberd includes a few ejabberd Commands by default. When more modules are installed, new commands may be available in the frontends.

    The easiest way to get a list of the available commands, and get help for them is to use the ejabberdctl script:

    $ ejabberdctl help
    @@ -3356,7 +3427,7 @@ This is not recommended for big databases, as it will consume much time,
     memory and processor. In that case it’s preferable to use backup and install_fallback.
     
    import_piefxis, export_piefxis, export_piefxis_host
    These options can be used to migrate accounts -using XEP-0227 formatted XML files +using XEP-0227 formatted XML files from/to other Jabber/XMPP servers or move users of a vhost to another ejabberd installation. See also @@ -3371,7 +3442,7 @@ There exist tutorials to in offline storage. This might be useful when the number of offline messages is very high.

    -

    4.2.2  Restrict Execution with AccessCommands

    The frontends can be configured to restrict access to certain commands. +

    4.2.2  Restrict Execution with AccessCommands

    The frontends can be configured to restrict access to certain commands. In that case, authentication information must be provided. In each frontend the AccessCommands option is defined in a different place. But in all cases the option syntax is the same: @@ -3417,7 +3488,7 @@ and the provided arguments do not contradict Arguments.

    As an example to u {_bot_reg_test, [register, unregister], [{host, "test.org"}]} ]

    -

    4.3  Web Admin

    +

    4.3  Web Admin

    The ejabberd Web Admin allows to administer most of ejabberd using a web browser.

    This feature is enabled by default: a ejabberd_http listener with the option web_admin (see section 3.1.3) is included in the listening ports. Then you can open @@ -3489,13 +3560,13 @@ The file is searched by default in The directory of the documentation can be specified in the environment variable EJABBERD_DOC_PATH. See section 4.1.2.

    -

    4.4  Ad-hoc Commands

    If you enable mod_configure and mod_adhoc, +

    4.4  Ad-hoc Commands

    If you enable mod_configure and mod_adhoc, you can perform several administrative tasks in ejabberd with a Jabber client. -The client must support Ad-Hoc Commands (XEP-0050), +The client must support Ad-Hoc Commands (XEP-0050), and you must login in the Jabber server with an account with proper privileges.

    -

    4.5  Change Computer Hostname

    ejabberd uses the distributed Mnesia database. +

    4.5  Change Computer Hostname

    ejabberd uses the distributed Mnesia database. Being distributed, Mnesia enforces consistency of its file, so it stores the name of the Erlang node in it (see section 5.4). The name of an Erlang node includes the hostname of the computer. @@ -3532,8 +3603,8 @@ mv /var/lib/ejabberd/*.* /var/lib/ejabberd/oldfiles/

  • Check that the information of the old database is available: accounts, rosters... After you finish, remember to delete the temporary backup files from public directories.
  • -

    Chapter 5  Securing ejabberd

    -

    5.1  Firewall Settings

    +

    Chapter 5  Securing ejabberd

    +

    5.1  Firewall Settings

    You need to take the following TCP ports in mind when configuring your firewall:


    @@ -3544,7 +3615,7 @@ After you finish, remember to delete the temporary backup files from public dire
    PortDescription
    port rangeUsed for connections between Erlang nodes. This range is configurable (see section 5.2).

    -

    5.2  epmd

    epmd (Erlang Port Mapper Daemon) +

    5.2  epmd

    epmd (Erlang Port Mapper Daemon) is a small name server included in Erlang/OTP and used by Erlang programs when establishing distributed Erlang communications. ejabberd needs epmd to use ejabberdctl and also when clustering ejabberd nodes. @@ -3569,7 +3640,7 @@ but can be configured in the file ejabberdctl.cfg. The Erlang command-line parameter used internally is, for example:

    erl ... -kernel inet_dist_listen_min 4370 inet_dist_listen_max 4375
     

    -

    5.3  Erlang Cookie

    The Erlang cookie is a string with numbers and letters. +

    5.3  Erlang Cookie

    The Erlang cookie is a string with numbers and letters. An Erlang node reads the cookie at startup from the command-line parameter -setcookie. If not indicated, the cookie is read from the cookie file $HOME/.erlang.cookie. If this file does not exist, it is created immediately with a random cookie. @@ -3583,7 +3654,7 @@ to prevent unauthorized access or intrusion to an Erlang node. The communication between Erlang nodes are not encrypted, so the cookie could be read sniffing the traffic on the network. The recommended way to secure the Erlang node is to block the port 4369.

    -

    5.4  Erlang Node Name

    An Erlang node may have a node name. +

    5.4  Erlang Node Name

    An Erlang node may have a node name. The name can be short (if indicated with the command-line parameter -sname) or long (if indicated with the parameter -name). Starting an Erlang node with -sname limits the communication between Erlang nodes to the LAN.

    Using the option -sname instead of -name is a simple method @@ -3592,7 +3663,7 @@ However, it is not ultimately effective to prevent access to the Erlang node, because it may be possible to fake the fact that you are on another network using a modified version of Erlang epmd. The recommended way to secure the Erlang node is to block the port 4369.

    -

    5.5  Securing Sensible Files

    ejabberd stores sensible data in the file system either in plain text or binary files. +

    5.5  Securing Sensible Files

    ejabberd stores sensible data in the file system either in plain text or binary files. The file system permissions should be set to only allow the proper user to read, write and execute those files and directories.

    ejabberd configuration file: /etc/ejabberd/ejabberd.cfg
    @@ -3612,9 +3683,9 @@ so it is preferable to secure the whole /var/lib/ejabberd/ directory.
    Erlang cookie file: /var/lib/ejabberd/.erlang.cookie
    See section 5.3.

    -

    Chapter 6  Clustering

    +

    Chapter 6  Clustering

    -

    6.1  How it Works

    +

    6.1  How it Works

    A Jabber domain is served by one or more ejabberd nodes. These nodes can be run on different machines that are connected via a network. They all must have the ability to connect to port 4369 of all another nodes, and must @@ -3628,29 +3699,29 @@ router,

  • session manager,
  • s2s manager.
  • -

    6.1.1  Router

    +

    6.1.1  Router

    This module is the main router of Jabber packets on each node. It routes them based on their destination’s domains. It uses a global routing table. The domain of the packet’s destination is searched in the routing table, and if it is found, the packet is routed to the appropriate process. If not, it is sent to the s2s manager.

    -

    6.1.2  Local Router

    +

    6.1.2  Local Router

    This module routes packets which have a destination domain equal to one of this server’s host names. If the destination JID has a non-empty user part, it is routed to the session manager, otherwise it is processed depending on its content.

    -

    6.1.3  Session Manager

    +

    6.1.3  Session Manager

    This module routes packets to local users. It looks up to which user resource a packet must be sent via a presence table. Then the packet is either routed to the appropriate c2s process, or stored in offline storage, or bounced back.

    -

    6.1.4  s2s Manager

    +

    6.1.4  s2s Manager

    This module routes packets to other Jabber servers. First, it checks if an opened s2s connection from the domain of the packet’s source to the domain of the packet’s destination exists. If that is the case, the s2s manager routes the packet to the process serving this connection, otherwise a new connection is opened.

    -

    6.2  Clustering Setup

    +

    6.2  Clustering Setup

    Suppose you already configured ejabberd on one machine named (first), and you need to setup another one to make an ejabberd cluster. Then do following steps:

    1. @@ -3684,14 +3755,14 @@ the Erlang shell. This probably can take some time if Mnesia has not yet transfered and processed all data it needed from first.
    2. Now run ejabberd on second with a configuration similar as on first: you probably do not need to duplicate ‘acl’ and ‘access’ options because they will be taken from -first. If you installed mod_irc, notice that it should be +first; and mod_irc should be enabled only on one machine in the cluster.

    You can repeat these steps for other machines supposed to serve this domain.

    -

    6.3  Service Load-Balancing

    +

    6.3  Service Load-Balancing

    -

    6.3.1  Components Load-Balancing

    -

    6.3.2  Domain Load-Balancing Algorithm

    +

    6.3.1  Components Load-Balancing

    +

    6.3.2  Domain Load-Balancing Algorithm

    ejabberd includes an algorithm to load balance the components that are plugged on an ejabberd cluster. It means that you can plug one or several instances of the same component on each ejabberd cluster and that the traffic will be automatically distributed.

    The default distribution algorithm try to deliver to a local instance of a component. If several local instances are available, one instance is chosen randomly. If no instance is available locally, one instance is chosen randomly among the remote component instances.

    If you need a different behaviour, you can change the load balancing behaviour with the option domain_balancing. The syntax of the option is the following:

    {domain_balancing, "component.example.com", <balancing_criterium>}.
     

    Several balancing criteria are available:

    • @@ -3700,13 +3771,13 @@ domain.

      -

      6.3.3  Load-Balancing Buckets

      +

      6.3.3  Load-Balancing Buckets

      When there is a risk of failure for a given component, domain balancing can cause service trouble. If one component is failing the service will not work correctly unless the sessions are rebalanced.

      In this case, it is best to limit the problem to the sessions handled by the failing component. This is what the domain_balancing_component_number option does, making the load balancing algorithm not dynamic, but sticky on a fix number of component instances.

      The syntax is the following:

      {domain_balancing_component_number, "component.example.com", N}
       

      -

      Chapter 7  Debugging

      +

      Chapter 7  Debugging

      -

      7.1  Log Files

      An ejabberd node writes two log files: +

      7.1  Log Files

      An ejabberd node writes two log files:

      ejabberd.log
      is the ejabberd service log, with the messages reported by ejabberd code
      sasl.log
      is the Erlang/OTP system log, with the messages reported by Erlang/OTP using SASL (System Architecture Support Libraries) @@ -3728,12 +3799,12 @@ The ejabberdctl command reopen-log (please refer to section 4.1.1) reopens the log files, and also renames the old ones if you didn’t rename them.

      -

      7.2  Debug Console

      The Debug Console is an Erlang shell attached to an already running ejabberd server. +

      7.2  Debug Console

      The Debug Console is an Erlang shell attached to an already running ejabberd server. With this Erlang shell, an experienced administrator can perform complex tasks.

      This shell gives complete control over the ejabberd server, so it is important to use it with extremely care. There are some simple and safe examples in the article Interconnecting Erlang Nodes

      To exit the shell, close the window or press the keys: control+c control+c.

      -

      7.3  Watchdog Alerts

      +

      7.3  Watchdog Alerts

      ejabberd includes a watchdog mechanism that may be useful to developers when troubleshooting a problem related to memory usage. If a process in the ejabberd server consumes more memory than the configured threshold, @@ -3751,7 +3822,7 @@ or in a conversation with the watchdog alert bot.

      Example configuration: To remove all watchdog admins, set the option with an empty list:

      {watchdog_admins, []}.
       

      -

      Appendix A  Internationalization and Localization

      +

      Appendix A  Internationalization and Localization

      The source code of ejabberd supports localization. The translators can edit the gettext .po files @@ -3786,9 +3857,9 @@ HTTP header ‘Accept-Language: ru’


      -

      Appendix B  Release Notes

      +

      Appendix B  Release Notes

      Release notes are available from ejabberd Home Page

      -

      Appendix C  Acknowledgements

      Thanks to all people who contributed to this guide: +

      Appendix C  Acknowledgements

      Thanks to all people who contributed to this guide:

      -

      Appendix D  Copyright Information

      Ejabberd Installation and Operation Guide.
      +

      Appendix D  Copyright Information

      Ejabberd Installation and Operation Guide.
      Copyright © 2003 — 2009 ProcessOne

      This document 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 diff --git a/doc/guide.tex b/doc/guide.tex index cc703fccc..f21af0e4e 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -720,11 +720,11 @@ other different modules for some specific virtual hosts: \makesubsection{listened}{Listening Ports} \ind{options!listen} -The option \option{listen} defines for which addresses and ports \ejabberd{} +The option \option{listen} defines for which ports, addresses and network protocols \ejabberd{} will listen and what services will be run on them. Each element of the list is a tuple with the following elements: \begin{itemize} -\item Port number. Optionally also the IP address. +\item Port number. Optionally also the IP address and/or a transport protocol. \item Listening module that serves this port. \item Options for the TCP socket and for the listening module. \end{itemize} @@ -742,10 +742,12 @@ With the basic syntax the ports will listen on all IPv4 network addresses: It is possible to specify the IP address for a port using the full syntax: \begin{verbatim} {{, }, , []} + {{, }, , []} + {{, , }, , []} \end{verbatim} -\makesubsubsection{listened-port}{Port Number and IP Address} +\makesubsubsection{listened-port}{Port Number, IP Address and Transport Protocol} The port number defines which port to listen for incoming connections. It can be a Jabber/XMPP standard port @@ -769,6 +771,9 @@ Some example values for IP address: \item \verb|{16#fdca, 16#8ab6, 16#a243, 16#75ef, 0, 0, 0, 1}| is the IPv6 address \verb|FDCA:8AB6:A243:75EF::1/128| \end{itemize} +The transport protocol can be \term{tcp} or \term{udp}. +Default is \term{tcp}. + \makesubsubsection{listened-module}{Listening Module} @@ -789,6 +794,10 @@ The available modules, their purpose and the options allowed by each one are: (as defined in the Jabber Component Protocol (\xepref{0114}).\\ Options: \texttt{access}, \texttt{hosts}, \texttt{shaper}, \texttt{service\_check\_from} + \titem{\texttt{ejabberd\_stun}} + Handles STUN Binding requests as defined in + \footahref{http://tools.ietf.org/html/rfc5389}{RFC 5389}.\\ + Options: \texttt{certfile} \titem{\texttt{ejabberd\_http}} Handles incoming HTTP connections.\\ Options: \texttt{captcha}, \texttt{certfile}, \texttt{http\_bind}, \texttt{http\_poll}, @@ -944,6 +953,7 @@ However, the c2s and s2s connections to the domain \term{example.com} use the fi and also allows plain connections for old clients. \item Port 5223 listens for c2s connections with the old SSL. \item Port 5269 listens for s2s connections with STARTTLS. The socket is set for IPv6 instead of IPv4. +\item Port 3478 listens for STUN requests over UDP. \item Port 5280 listens for HTTP requests, and serves the HTTP Poll service. \item Port 5281 listens for HTTP requests, and serves the Web Admin using HTTPS as explained in section~\ref{webadmin}. The socket only listens connections to the IP address 127.0.0.1. @@ -968,6 +978,7 @@ However, the c2s and s2s connections to the domain \term{example.com} use the fi {shaper, s2s_shaper}, {max_stanza_size, 131072} ]}, + {{3478, udp}, ejabberd_stun, []}, {5280, ejabberd_http, [ http_poll ]}, @@ -1548,6 +1559,45 @@ Example configuration: ]}. \end{verbatim} +\makesubsection{stun}{STUN} +\ind{options!stun}\ind{stun} + +\ejabberd{} is able to act as a stand-alone STUN server +(\footahref{http://tools.ietf.org/html/rfc5389}{RFC 5389}). Currently only Binding usage +is supported. In that role \ejabberd{} helps clients with Jingle ICE (\xepref{0176}) support to discover their external addresses and ports. + +You should configure \term{ejabberd\_stun} listening module as described in \ref{listened} section. +If \option{certfile} option is defined, \ejabberd{} multiplexes TCP and +TLS over TCP connections on the same port. Obviously, \option{certfile} option +is defined for \term{tcp} only. Note however that TCP or TLS over TCP +support is not required for Binding usage and is reserved for +\footahref{http://tools.ietf.org/html/draft-ietf-behave-turn-16}{TURN} +functionality. Feel free to configure \term{udp} transport only. + +Example configuration: +\begin{verbatim} +{listen, + [ + ... + {{3478, udp}, ejabberd_stun, []}, + {3478, ejabberd_stun, []}, + {5349, ejabberd_stun, [{certfile, "/etc/ejabberd/server.pem"}]}, + ... + ] +}. +\end{verbatim} + +You also need to configure DNS SRV records properly so clients can easily discover a +STUN server serving your XMPP domain. Refer to section +\footahref{http://tools.ietf.org/html/rfc5389\#section-9}{DNS Discovery of a Server} +of \footahref{http://tools.ietf.org/html/rfc5389}{RFC 5389} for details. + +Example DNS SRV configuration: +\begin{verbatim} +_stun._udp IN SRV 0 0 3478 stun.example.com. +_stun._tcp IN SRV 0 0 3478 stun.example.com. +_stuns._tcp IN SRV 0 0 5349 stun.example.com. +\end{verbatim} \makesubsection{includeconfigfile}{Include Additional Configuration Files} \ind{options!includeconfigfile}\ind{includeconfigfile} diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index a23b714be..a083613a1 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -149,6 +149,11 @@ %% } %% ]}, + %% + %% ejabberd_stun: Handles STUN Binding requests + %% + %%{{3478, udp}, ejabberd_stun, []}, + {5280, ejabberd_http, [ %%{request_handlers, %% [ From a4b2d032f974c6810ec394daddcda24fb9813657 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 11 Aug 2009 18:23:54 +0000 Subject: [PATCH 494/582] Add stun directory to compilation process SVN Revision: 2463 --- src/Makefile.in | 2 +- src/configure | 4842 +++++++++++++++++++--------------------------- src/configure.ac | 1 + 3 files changed, 1991 insertions(+), 2854 deletions(-) diff --git a/src/Makefile.in b/src/Makefile.in index 1faca9d14..5beb5569d 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -63,7 +63,7 @@ endif prefix = @prefix@ exec_prefix = @exec_prefix@ -SUBDIRS = @mod_pubsub@ @mod_muc@ @mod_proxy65@ @eldap@ @pam@ @web@ @tls@ @odbc@ @ejabberd_zlib@ +SUBDIRS = stun @mod_pubsub@ @mod_muc@ @mod_proxy65@ @eldap@ @pam@ @web@ @tls@ @odbc@ @ejabberd_zlib@ ERLSHLIBS = ERLBEHAVS = cyrsasl.erl gen_mod.erl p1_fsm.erl SOURCES_ALL = $(wildcard *.erl) diff --git a/src/configure b/src/configure index 19e618d0c..e3865df33 100755 --- a/src/configure +++ b/src/configure @@ -1,62 +1,83 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.61 for ejabberd.erl version. +# Generated by GNU Autoconf 2.64 for ejabberd.erl version. # # Report bugs to . # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software +# Foundation, Inc. +# # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. -## --------------------- ## -## M4sh Initialization. ## -## --------------------- ## +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else - case `(set -o) 2>/dev/null` in - *posix*) set -o posix ;; + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; esac - fi - - -# PATH needs CR -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conf$$.sh - echo "exit 0" >>conf$$.sh - chmod +x conf$$.sh - if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then - PATH_SEPARATOR=';' - else - PATH_SEPARATOR=: - fi - rm -f conf$$.sh -fi - -# Support unset when possible. -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - as_unset=unset -else - as_unset=false + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } fi @@ -65,20 +86,18 @@ fi # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) -as_nl=' -' IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. -case $0 in +case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break -done + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done IFS=$as_save_IFS ;; @@ -89,32 +108,271 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - { (exit 1); exit 1; } + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 fi -# Work around bugs in pre-3.0 UWIN ksh. -for as_var in ENV MAIL MAILPATH -do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. -for as_var in \ - LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ - LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ - LC_TELEPHONE LC_TIME -do - if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then - eval $as_var=C; export $as_var - else - ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var - fi -done +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and +$0: ejabberd@process-one.net about your system, including +$0: any error possibly output before this message. Then +$0: install a modern shell, or manually run the script +$0: under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error -# Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr @@ -128,13 +386,17 @@ else as_basename=false fi +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi -# Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -echo X/"$0" | +$as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -149,294 +411,19 @@ echo X/"$0" | } s/.*/./; q'` -# CDPATH. -$as_unset CDPATH +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits -if test "x$CONFIG_SHELL" = x; then - if (eval ":") 2>/dev/null; then - as_have_required=yes -else - as_have_required=no -fi - - if test $as_have_required = yes && (eval ": -(as_func_return () { - (exit \$1) -} -as_func_success () { - as_func_return 0 -} -as_func_failure () { - as_func_return 1 -} -as_func_ret_success () { - return 0 -} -as_func_ret_failure () { - return 1 -} - -exitcode=0 -if as_func_success; then - : -else - exitcode=1 - echo as_func_success failed. -fi - -if as_func_failure; then - exitcode=1 - echo as_func_failure succeeded. -fi - -if as_func_ret_success; then - : -else - exitcode=1 - echo as_func_ret_success failed. -fi - -if as_func_ret_failure; then - exitcode=1 - echo as_func_ret_failure succeeded. -fi - -if ( set x; as_func_ret_success y && test x = \"\$1\" ); then - : -else - exitcode=1 - echo positional parameters were not saved. -fi - -test \$exitcode = 0) || { (exit 1); exit 1; } - -( - as_lineno_1=\$LINENO - as_lineno_2=\$LINENO - test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && - test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } -") 2> /dev/null; then - : -else - as_candidate_shells= - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - case $as_dir in - /*) - for as_base in sh bash ksh sh5; do - as_candidate_shells="$as_candidate_shells $as_dir/$as_base" - done;; - esac -done -IFS=$as_save_IFS - - - for as_shell in $as_candidate_shells $SHELL; do - # Try only shells that exist, to save several forks. - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { ("$as_shell") 2> /dev/null <<\_ASEOF -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in - *posix*) set -o posix ;; -esac - -fi - - -: -_ASEOF -}; then - CONFIG_SHELL=$as_shell - as_have_required=yes - if { "$as_shell" 2> /dev/null <<\_ASEOF -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in - *posix*) set -o posix ;; -esac - -fi - - -: -(as_func_return () { - (exit $1) -} -as_func_success () { - as_func_return 0 -} -as_func_failure () { - as_func_return 1 -} -as_func_ret_success () { - return 0 -} -as_func_ret_failure () { - return 1 -} - -exitcode=0 -if as_func_success; then - : -else - exitcode=1 - echo as_func_success failed. -fi - -if as_func_failure; then - exitcode=1 - echo as_func_failure succeeded. -fi - -if as_func_ret_success; then - : -else - exitcode=1 - echo as_func_ret_success failed. -fi - -if as_func_ret_failure; then - exitcode=1 - echo as_func_ret_failure succeeded. -fi - -if ( set x; as_func_ret_success y && test x = "$1" ); then - : -else - exitcode=1 - echo positional parameters were not saved. -fi - -test $exitcode = 0) || { (exit 1); exit 1; } - -( - as_lineno_1=$LINENO - as_lineno_2=$LINENO - test "x$as_lineno_1" != "x$as_lineno_2" && - test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } - -_ASEOF -}; then - break -fi - -fi - - done - - if test "x$CONFIG_SHELL" != x; then - for as_var in BASH_ENV ENV - do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var - done - export CONFIG_SHELL - exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} -fi - - - if test $as_have_required = no; then - echo This script requires a shell more modern than all the - echo shells that I found on your system. Please install a - echo modern shell, or manually run the script under such a - echo shell if you do have one. - { (exit 1); exit 1; } -fi - - -fi - -fi - - - -(eval "as_func_return () { - (exit \$1) -} -as_func_success () { - as_func_return 0 -} -as_func_failure () { - as_func_return 1 -} -as_func_ret_success () { - return 0 -} -as_func_ret_failure () { - return 1 -} - -exitcode=0 -if as_func_success; then - : -else - exitcode=1 - echo as_func_success failed. -fi - -if as_func_failure; then - exitcode=1 - echo as_func_failure succeeded. -fi - -if as_func_ret_success; then - : -else - exitcode=1 - echo as_func_ret_success failed. -fi - -if as_func_ret_failure; then - exitcode=1 - echo as_func_ret_failure succeeded. -fi - -if ( set x; as_func_ret_success y && test x = \"\$1\" ); then - : -else - exitcode=1 - echo positional parameters were not saved. -fi - -test \$exitcode = 0") || { - echo No shell found that supports shell functions. - echo Please tell autoconf@gnu.org about your system, - echo including any error possibly output before this - echo message -} - - - - as_lineno_1=$LINENO - as_lineno_2=$LINENO - test "x$as_lineno_1" != "x$as_lineno_2" && - test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { - - # Create $as_me.lineno as a copy of $as_myself, but with $LINENO - # uniformly replaced by the line number. The first 'sed' inserts a - # line-number line after each line using $LINENO; the second 'sed' - # does the real work. The second script uses 'N' to pair each - # line-number line with the line containing $LINENO, and appends - # trailing '-' during substitution so that $LINENO is not a special - # case at line end. - # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the - # scripts with optimization help from Paolo Bonzini. Blame Lee - # E. McMahon (1931-1989) for sed's syntax. :-) + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= @@ -453,8 +440,7 @@ test \$exitcode = 0") || { s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || - { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 - { (exit 1); exit 1; }; } + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the @@ -464,49 +450,40 @@ test \$exitcode = 0") || { exit } - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in +case `echo -n x` in #((((( -n*) - case `echo 'x\c'` in + case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. - *) ECHO_C='\c';; + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir - mkdir conf$$.dir + mkdir conf$$.dir 2>/dev/null fi -echo >conf$$.file -if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else as_ln_s='cp -p' -elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln + fi else as_ln_s='cp -p' fi @@ -514,7 +491,7 @@ rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then - as_mkdir_p=: + as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false @@ -531,12 +508,12 @@ else as_test_x=' eval sh -c '\'' if test -d "$1"; then - test -d "$1/."; + test -d "$1/."; else - case $1 in - -*)set "./$1";; + case $1 in #( + -*)set "./$1";; esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' @@ -550,7 +527,6 @@ as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - exec 7<&0 &1 # Name of the host. @@ -569,7 +545,6 @@ cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= -SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='ejabberd.erl' @@ -577,6 +552,7 @@ PACKAGE_TARNAME='ejabberd' PACKAGE_VERSION='version' PACKAGE_STRING='ejabberd.erl version' PACKAGE_BUGREPORT='ejabberd@process-one.net' +PACKAGE_URL='' ac_default_prefix=/ # Factoring default headers for most tests. @@ -615,93 +591,116 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='SHELL -PATH_SEPARATOR -PACKAGE_NAME -PACKAGE_TARNAME -PACKAGE_VERSION -PACKAGE_STRING -PACKAGE_BUGREPORT -exec_prefix -prefix -program_transform_name -bindir -sbindir -libexecdir -datarootdir -datadir -sysconfdir -sharedstatedir -localstatedir -includedir -oldincludedir -docdir -infodir -htmldir -dvidir -pdfdir -psdir -libdir -localedir -mandir -DEFS -ECHO_C -ECHO_N -ECHO_T -LIBS -build_alias -host_alias -target_alias -CC -CFLAGS -LDFLAGS -CPPFLAGS -ac_ct_CC -EXEEXT -OBJEXT -SET_MAKE -ERLC -ERL -ERLANG_CFLAGS -ERLANG_LIBS -ERLANG_SSL39 -ERLANG_EXMPP -CPP -GREP -EGREP -LIBOBJS -mod_muc -make_mod_muc -mod_proxy65 -make_mod_proxy65 -mod_pubsub -make_mod_pubsub -eldap -make_eldap -odbc -make_odbc -tls -make_tls -web -make_web -ejabberd_zlib -make_ejabberd_zlib -ZLIB_CFLAGS -ZLIB_LIBS -pam -make_pam -PAM_CFLAGS -PAM_LIBS -hipe -roster_gateway_workaround -db_type -transient_supervisors -full_xml -SSL_LIBS -SSL_CFLAGS +ac_subst_vars='LTLIBOBJS INSTALLUSER -LTLIBOBJS' +SSL_CFLAGS +SSL_LIBS +full_xml +transient_supervisors +db_type +roster_gateway_workaround +hipe +PAM_LIBS +PAM_CFLAGS +make_pam +pam +ZLIB_LIBS +ZLIB_CFLAGS +make_ejabberd_zlib +ejabberd_zlib +make_web +web +make_tls +tls +make_odbc +odbc +make_eldap +eldap +make_mod_pubsub +mod_pubsub +make_mod_proxy65 +mod_proxy65 +make_mod_muc +mod_muc +LIBOBJS +EGREP +GREP +CPP +ERLANG_EXMPP +ERLANG_SSL39 +ERLANG_LIBS +ERLANG_CFLAGS +ERL +ERLC +SET_MAKE +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' ac_subst_files='' +ac_user_opts=' +enable_option_checking +with_erlang +enable_mod_muc +enable_mod_proxy65 +enable_mod_pubsub +enable_eldap +enable_odbc +enable_tls +enable_web +enable_ejabberd_zlib +with_zlib +enable_pam +with_pam +enable_hipe +enable_roster_gateway_workaround +enable_mssql +enable_transient_supervisors +enable_full_xml +with_openssl +enable_user +' ac_precious_vars='build_alias host_alias target_alias @@ -716,6 +715,8 @@ CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null @@ -814,13 +815,20 @@ do datarootdir=$ac_optarg ;; -disable-* | --disable-*) - ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. - expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && - { echo "$as_me: error: invalid feature name: $ac_feature" >&2 - { (exit 1); exit 1; }; } - ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` - eval enable_$ac_feature=no ;; + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; @@ -833,13 +841,20 @@ do dvidir=$ac_optarg ;; -enable-* | --enable-*) - ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. - expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && - { echo "$as_me: error: invalid feature name: $ac_feature" >&2 - { (exit 1); exit 1; }; } - ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` - eval enable_$ac_feature=\$ac_optarg ;; + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ @@ -1030,22 +1045,36 @@ do ac_init_version=: ;; -with-* | --with-*) - ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. - expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && - { echo "$as_me: error: invalid package name: $ac_package" >&2 - { (exit 1); exit 1; }; } - ac_package=`echo $ac_package | sed 's/[-.]/_/g'` - eval with_$ac_package=\$ac_optarg ;; + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) - ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. - expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && - { echo "$as_me: error: invalid package name: $ac_package" >&2 - { (exit 1); exit 1; }; } - ac_package=`echo $ac_package | sed 's/[-.]/_/g'` - eval with_$ac_package=no ;; + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. @@ -1065,25 +1094,25 @@ do | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; - -*) { echo "$as_me: error: unrecognized option: $ac_option -Try \`$0 --help' for more information." >&2 - { (exit 1); exit 1; }; } + -*) as_fn_error "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information." ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. - expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && - { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 - { (exit 1); exit 1; }; } + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error "invalid variable name: \`$ac_envvar'" ;; + esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. - echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; @@ -1092,23 +1121,36 @@ done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` - { echo "$as_me: error: missing argument to $ac_option" >&2 - { (exit 1); exit 1; }; } + as_fn_error "missing argument to $ac_option" fi -# Be sure to have absolute directory names. +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac - { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 - { (exit 1); exit 1; }; } + as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' @@ -1122,7 +1164,7 @@ target=$target_alias if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe - echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes @@ -1138,23 +1180,21 @@ test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - { echo "$as_me: error: Working directory cannot be determined" >&2 - { (exit 1); exit 1; }; } + as_fn_error "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - { echo "$as_me: error: pwd does not report name of working directory" >&2 - { (exit 1); exit 1; }; } + as_fn_error "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$0" || -$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$0" : 'X\(//\)[^/]' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -echo X"$0" | + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -1181,13 +1221,11 @@ else fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 - { (exit 1); exit 1; }; } + as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 - { (exit 1); exit 1; }; } + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then @@ -1235,9 +1273,9 @@ Configuration: Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] + [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] + [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify @@ -1247,25 +1285,25 @@ for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/ejabberd] - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/ejabberd] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF @@ -1279,6 +1317,7 @@ if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-mod_muc enable mod_muc (default: yes) @@ -1302,7 +1341,8 @@ Optional Features: (default: yes) --enable-full-xml use XML features in XMPP stream (ex: CDATA) (default: no, requires XML compliant clients) - --enable-user[=USER] allow this system user to start ejabberd (default: + --enable-user[[[=USER]]] + allow this system user to start ejabberd (default: no) Optional Packages: @@ -1334,15 +1374,17 @@ fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -1378,7 +1420,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix echo && $SHELL "$ac_srcdir/configure" --help=recursive else - echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done @@ -1388,21 +1430,311 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF ejabberd.erl configure version -generated by GNU Autoconf 2.61 +generated by GNU Autoconf 2.64 -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +Copyright (C) 2009 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} +( cat <<\_ASBOX +## --------------------------------------- ## +## Report this to ejabberd@process-one.net ## +## --------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_link cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by ejabberd.erl $as_me version, which was -generated by GNU Autoconf 2.61. Invocation command line was +generated by GNU Autoconf 2.64. Invocation command line was $ $0 $@ @@ -1438,8 +1770,8 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - echo "PATH: $as_dir" -done + $as_echo "PATH: $as_dir" + done IFS=$as_save_IFS } >&5 @@ -1473,12 +1805,12 @@ do | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) - ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in - 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) - ac_configure_args1="$ac_configure_args1 '$ac_arg'" + as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else @@ -1494,13 +1826,13 @@ do -* ) ac_must_keep_next=true ;; esac fi - ac_configure_args="$ac_configure_args '$ac_arg'" + as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done -$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } -$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there @@ -1525,12 +1857,13 @@ _ASBOX case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 -echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( - *) $as_unset $ac_var ;; + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done @@ -1559,9 +1892,9 @@ _ASBOX do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - echo "$ac_var='\''$ac_val'\''" + $as_echo "$ac_var='\''$ac_val'\''" done | sort echo @@ -1576,9 +1909,9 @@ _ASBOX do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - echo "$ac_var='\''$ac_val'\''" + $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi @@ -1594,64 +1927,69 @@ _ASBOX echo fi test "$ac_signal" != 0 && - echo "$as_me: caught signal $ac_signal" - echo "$as_me: exit $exit_status" + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h +$as_echo "/* confdefs.h */" > confdefs.h + # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF - cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF - cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF - cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF - cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + # Let the site file select an alternate cache file if it wants to. -# Prefer explicitly selected file to automatically selected ones. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - set x "$CONFIG_SITE" + ac_site_file1=$CONFIG_SITE elif test "x$prefix" != xNONE; then - set x "$prefix/share/config.site" "$prefix/etc/config.site" + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site else - set x "$ac_default_prefix/share/config.site" \ - "$ac_default_prefix/etc/config.site" + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site fi -shift -for ac_site_file +for ac_site_file in "$ac_site_file1" "$ac_site_file2" do + test "x$ac_site_file" = xNONE && continue if test -r "$ac_site_file"; then - { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 -echo "$as_me: loading site script $ac_site_file" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi @@ -1661,16 +1999,16 @@ if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then - { echo "$as_me:$LINENO: loading cache $cache_file" >&5 -echo "$as_me: loading cache $cache_file" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else - { echo "$as_me:$LINENO: creating cache $cache_file" >&5 -echo "$as_me: creating cache $cache_file" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi @@ -1684,68 +2022,56 @@ for ac_var in $ac_precious_vars; do eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) - { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) - { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 -echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then - { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 -echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 -echo "$as_me: former value: $ac_old_val" >&2;} - { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 -echo "$as_me: current value: $ac_new_val" >&2;} - ac_cache_corrupted=: + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in - *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then - { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 -echo "$as_me: error: changes in the environment can compromise the build" >&2;} - { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 -echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} - { (exit 1); exit 1; }; } + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi - - - - - - - - - - - - - - - - - - - - - - - - +## -------------------- ## +## Main body of script. ## +## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' @@ -1764,10 +2090,10 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. @@ -1777,25 +2103,25 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { echo "$as_me:$LINENO: result: $CC" >&5 -echo "${ECHO_T}$CC" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi @@ -1804,10 +2130,10 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. @@ -1817,25 +2143,25 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 -echo "${ECHO_T}$ac_ct_CC" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then @@ -1843,12 +2169,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -1861,10 +2183,10 @@ if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. @@ -1874,25 +2196,25 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { echo "$as_me:$LINENO: result: $CC" >&5 -echo "${ECHO_T}$CC" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi @@ -1901,10 +2223,10 @@ fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. @@ -1915,18 +2237,18 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then @@ -1945,11 +2267,11 @@ fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { echo "$as_me:$LINENO: result: $CC" >&5 -echo "${ECHO_T}$CC" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi @@ -1960,10 +2282,10 @@ if test -z "$CC"; then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. @@ -1973,25 +2295,25 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { echo "$as_me:$LINENO: result: $CC" >&5 -echo "${ECHO_T}$CC" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi @@ -2004,10 +2326,10 @@ if test -z "$CC"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. @@ -2017,25 +2339,25 @@ for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 -echo "${ECHO_T}$ac_ct_CC" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi @@ -2047,12 +2369,8 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -2062,98 +2380,82 @@ fi fi -test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH -See \`config.log' for more details." >&5 -echo "$as_me: error: no acceptable C compiler found in \$PATH -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "no acceptable C compiler found in \$PATH +See \`config.log' for more details." "$LINENO" 5; } # Provide some information about the compiler. -echo "$as_me:$LINENO: checking for C compiler version" >&5 -ac_compiler=`set X $ac_compile; echo $2` -{ (ac_try="$ac_compiler --version >&5" +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compiler --version >&5") 2>&5 +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (ac_try="$ac_compiler -v >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compiler -v >&5") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } -{ (ac_try="$ac_compiler -V >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compiler -V >&5") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + rm -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - +#include int main () { +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.exe b.out" +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out conftest.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. -{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 -echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; } -ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` -# -# List of possible output files, starting from the most likely. -# The algorithm is not robust to junk in `.', hence go to wildcards (a.*) -# only as a last resort. b.out is created by i960 compilers. -ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' -# -# The IRIX 6 linker writes into existing files which may not be -# executable, retaining their permissions. Remove them first so a -# subsequent execution test works. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + ac_rmfiles= for ac_file in $ac_files do case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles -if { (ac_try="$ac_link_default" +if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, @@ -2163,14 +2465,14 @@ for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi @@ -2189,78 +2491,75 @@ test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi - -{ echo "$as_me:$LINENO: result: $ac_file" >&5 -echo "${ECHO_T}$ac_file" >&6; } -if test -z "$ac_file"; then - echo "$as_me: failed program was:" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +if test -z "$ac_file"; then : + $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { echo "$as_me:$LINENO: error: C compiler cannot create executables -See \`config.log' for more details." >&5 -echo "$as_me: error: C compiler cannot create executables -See \`config.log' for more details." >&2;} - { (exit 77); exit 77; }; } +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "C compiler cannot create executables +See \`config.log' for more details." "$LINENO" 5; }; } fi - ac_exeext=$ac_cv_exeext # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. -{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5 -echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; } -# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } # If not cross compiling, check that we can run a simple program. if test "$cross_compiling" != yes; then if { ac_try='./$ac_file' - { (case "(($ac_try" in + { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else - { { echo "$as_me:$LINENO: error: cannot run C compiled programs. + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot run C compiled programs. If you meant to cross compile, use \`--host'. -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } +See \`config.log' for more details." "$LINENO" 5; } fi fi fi -{ echo "$as_me:$LINENO: result: yes" >&5 -echo "${ECHO_T}yes" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } -rm -f a.out a.exe conftest$ac_cv_exeext b.out +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out conftest.out ac_clean_files=$ac_clean_files_save # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. -{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 -echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } -{ echo "$as_me:$LINENO: result: $cross_compiling" >&5 -echo "${ECHO_T}$cross_compiling" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } -{ echo "$as_me:$LINENO: checking for suffix of executables" >&5 -echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } -if { (ac_try="$ac_link" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with @@ -2268,37 +2567,31 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else - { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." "$LINENO" 5; } fi - rm -f conftest$ac_cv_exeext -{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 -echo "${ECHO_T}$ac_cv_exeext" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT -{ echo "$as_me:$LINENO: checking for suffix of object files" >&5 -echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } -if test "${ac_cv_objext+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if test "${ac_cv_objext+set}" = set; then : + $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2310,51 +2603,46 @@ main () } _ACEOF rm -f conftest.o conftest.obj -if { (ac_try="$ac_compile" +if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; then + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else - echo "$as_me: failed program was:" >&5 + $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile -See \`config.log' for more details." >&5 -echo "$as_me: error: cannot compute suffix of object files: cannot compile -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of object files: cannot compile +See \`config.log' for more details." "$LINENO" 5; } fi - rm -f conftest.$ac_cv_objext conftest.$ac_ext fi -{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 -echo "${ECHO_T}$ac_cv_objext" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT -{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 -echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; } -if test "${ac_cv_c_compiler_gnu+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2368,54 +2656,34 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_compiler_gnu=no + ac_compiler_gnu=no fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi -{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 -echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } -GCC=`test $ac_compiler_gnu = yes && echo yes` +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS -{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 -echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } -if test "${ac_cv_prog_cc_g+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then : + $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2426,34 +2694,11 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - CFLAGS="" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2464,35 +2709,12 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +if ac_fn_c_try_compile "$LINENO"; then : - ac_c_werror_flag=$ac_save_c_werror_flag +else + ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -2503,42 +2725,18 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi -{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 -echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then @@ -2554,18 +2752,14 @@ else CFLAGS= fi fi -{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 -echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } -if test "${ac_cv_prog_cc_c89+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then : + $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -2622,31 +2816,9 @@ for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" - rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then + if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - fi - rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done @@ -2657,17 +2829,19 @@ fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) - { echo "$as_me:$LINENO: result: none needed" >&5 -echo "${ECHO_T}none needed" >&6; } ;; + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; xno) - { echo "$as_me:$LINENO: result: unsupported" >&5 -echo "${ECHO_T}unsupported" >&6; } ;; + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" - { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 -echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac +if test "x$ac_cv_prog_cc_c89" != xno; then : +fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' @@ -2675,11 +2849,12 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 -echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; } -set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` -if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh @@ -2696,12 +2871,12 @@ esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then - { echo "$as_me:$LINENO: result: yes" >&5 -echo "${ECHO_T}yes" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } SET_MAKE= else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi @@ -2713,7 +2888,7 @@ fi #locating erlang # Check whether --with-erlang was given. -if test "${with_erlang+set}" = set; then +if test "${with_erlang+set}" = set; then : withval=$with_erlang; fi @@ -2721,10 +2896,10 @@ fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}erlc", so it can be a program name with args. set dummy ${ac_tool_prefix}erlc; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_path_ERLC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_ERLC+set}" = set; then : + $as_echo_n "(cached) " >&6 else case $ERLC in [\\/]* | ?:[\\/]*) @@ -2737,14 +2912,14 @@ for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_ERLC="$as_dir/$ac_word$ac_exec_ext" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS ;; @@ -2752,11 +2927,11 @@ esac fi ERLC=$ac_cv_path_ERLC if test -n "$ERLC"; then - { echo "$as_me:$LINENO: result: $ERLC" >&5 -echo "${ECHO_T}$ERLC" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ERLC" >&5 +$as_echo "$ERLC" >&6; } else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi @@ -2765,10 +2940,10 @@ if test -z "$ac_cv_path_ERLC"; then ac_pt_ERLC=$ERLC # Extract the first word of "erlc", so it can be a program name with args. set dummy erlc; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_path_ac_pt_ERLC+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_ac_pt_ERLC+set}" = set; then : + $as_echo_n "(cached) " >&6 else case $ac_pt_ERLC in [\\/]* | ?:[\\/]*) @@ -2781,14 +2956,14 @@ for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_ac_pt_ERLC="$as_dir/$ac_word$ac_exec_ext" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS ;; @@ -2796,11 +2971,11 @@ esac fi ac_pt_ERLC=$ac_cv_path_ac_pt_ERLC if test -n "$ac_pt_ERLC"; then - { echo "$as_me:$LINENO: result: $ac_pt_ERLC" >&5 -echo "${ECHO_T}$ac_pt_ERLC" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_ERLC" >&5 +$as_echo "$ac_pt_ERLC" >&6; } else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi if test "x$ac_pt_ERLC" = x; then @@ -2808,12 +2983,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac ERLC=$ac_pt_ERLC @@ -2825,10 +2996,10 @@ fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}erl", so it can be a program name with args. set dummy ${ac_tool_prefix}erl; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_path_ERL+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_ERL+set}" = set; then : + $as_echo_n "(cached) " >&6 else case $ERL in [\\/]* | ?:[\\/]*) @@ -2841,14 +3012,14 @@ for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_ERL="$as_dir/$ac_word$ac_exec_ext" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS ;; @@ -2856,11 +3027,11 @@ esac fi ERL=$ac_cv_path_ERL if test -n "$ERL"; then - { echo "$as_me:$LINENO: result: $ERL" >&5 -echo "${ECHO_T}$ERL" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ERL" >&5 +$as_echo "$ERL" >&6; } else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi @@ -2869,10 +3040,10 @@ if test -z "$ac_cv_path_ERL"; then ac_pt_ERL=$ERL # Extract the first word of "erl", so it can be a program name with args. set dummy erl; ac_word=$2 -{ echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_path_ac_pt_ERL+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_ac_pt_ERL+set}" = set; then : + $as_echo_n "(cached) " >&6 else case $ac_pt_ERL in [\\/]* | ?:[\\/]*) @@ -2885,14 +3056,14 @@ for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do + for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_ac_pt_ERL="$as_dir/$ac_word$ac_exec_ext" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done -done + done IFS=$as_save_IFS ;; @@ -2900,11 +3071,11 @@ esac fi ac_pt_ERL=$ac_cv_path_ac_pt_ERL if test -n "$ac_pt_ERL"; then - { echo "$as_me:$LINENO: result: $ac_pt_ERL" >&5 -echo "${ECHO_T}$ac_pt_ERL" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_ERL" >&5 +$as_echo "$ac_pt_ERL" >&6; } else - { echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi if test "x$ac_pt_ERL" = x; then @@ -2912,12 +3083,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&5 -echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools -whose name does not start with the host triplet. If you think this -configuration is useful to you, please write to autoconf@gnu.org." >&2;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac ERL=$ac_pt_ERL @@ -2928,9 +3095,7 @@ fi if test "z$ERLC" = "z" || test "z$ERL" = "z"; then - { { echo "$as_me:$LINENO: error: erlang not found" >&5 -echo "$as_me: error: erlang not found" >&2;} - { (exit 1); exit 1; }; } + as_fn_error "erlang not found" "$LINENO" 5 fi @@ -2993,21 +3158,15 @@ libpath(App) -> _EOF if ! $ERLC conftest.erl; then - { { echo "$as_me:$LINENO: error: could not compile sample program" >&5 -echo "$as_me: error: could not compile sample program" >&2;} - { (exit 1); exit 1; }; } + as_fn_error "could not compile sample program" "$LINENO" 5 fi if ! $ERL -s conftest -noshell; then - { { echo "$as_me:$LINENO: error: could not run sample program" >&5 -echo "$as_me: error: could not run sample program" >&2;} - { (exit 1); exit 1; }; } + as_fn_error "could not run sample program" "$LINENO" 5 fi if ! test -f conftest.out; then - { { echo "$as_me:$LINENO: error: erlang program was not properly executed, (conftest.out was not produced)" >&5 -echo "$as_me: error: erlang program was not properly executed, (conftest.out was not produced)" >&2;} - { (exit 1); exit 1; }; } + as_fn_error "erlang program was not properly executed, (conftest.out was not produced)" "$LINENO" 5 fi # First line @@ -3034,16 +3193,12 @@ echo "$as_me: error: erlang program was not properly executed, (conftest.out was # Checks for typedefs, structures, and compiler characteristics. -{ echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 -echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6; } -if test "${ac_cv_c_const+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 +$as_echo_n "checking for an ANSI C-conforming const... " >&6; } +if test "${ac_cv_c_const+set}" = set; then : + $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -3103,40 +3258,18 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_c_const=no + ac_cv_c_const=no fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi -{ echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 -echo "${ECHO_T}$ac_cv_c_const" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 +$as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then -cat >>confdefs.h <<\_ACEOF -#define const -_ACEOF +$as_echo "#define const /**/" >>confdefs.h fi @@ -3153,15 +3286,15 @@ ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 -echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then - if test "${ac_cv_prog_CPP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 + if test "${ac_cv_prog_CPP+set}" = set; then : + $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" @@ -3175,11 +3308,7 @@ do # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include @@ -3188,76 +3317,34 @@ cat >>conftest.$ac_ext <<_ACEOF #endif Syntax error _ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +if ac_fn_c_try_cpp "$LINENO"; then : +else # Broken: fails on valid input. continue fi - rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then +if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - # Passes both tests. ac_preproc_ok=: break fi - rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext -if $ac_preproc_ok; then +if $ac_preproc_ok; then : break fi @@ -3269,8 +3356,8 @@ fi else ac_cv_prog_CPP=$CPP fi -{ echo "$as_me:$LINENO: result: $CPP" >&5 -echo "${ECHO_T}$CPP" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do @@ -3280,11 +3367,7 @@ do # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include @@ -3293,83 +3376,40 @@ cat >>conftest.$ac_ext <<_ACEOF #endif Syntax error _ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - : -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 +if ac_fn_c_try_cpp "$LINENO"; then : +else # Broken: fails on valid input. continue fi - rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then +if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - # Passes both tests. ac_preproc_ok=: break fi - rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext -if $ac_preproc_ok; then - : +if $ac_preproc_ok; then : + else - { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details." >&5 -echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details." >&2;} - { (exit 1); exit 1; }; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." "$LINENO" 5; } fi ac_ext=c @@ -3379,45 +3419,40 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 -echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } -if test "${ac_cv_path_GREP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - # Extract the first word of "grep ggrep" to use in msg output -if test -z "$GREP"; then -set dummy grep ggrep; ac_prog_name=$2 -if test "${ac_cv_path_GREP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if test "${ac_cv_path_GREP+set}" = set; then : + $as_echo_n "(cached) " >&6 else + if test -z "$GREP"; then ac_path_GREP_found=false -# Loop through the user's path and test for each of PROGNAME-LIST -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue - # Check for GNU ac_path_GREP and select it if it is found. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 - echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" - echo 'GREP' >> "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - ac_count=`expr $ac_count + 1` + as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" @@ -3429,77 +3464,61 @@ case `"$ac_path_GREP" --version 2>&1` in rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac - - $ac_path_GREP_found && break 3 + $ac_path_GREP_found && break 3 + done + done done -done - -done IFS=$as_save_IFS - - -fi - -GREP="$ac_cv_path_GREP" -if test -z "$GREP"; then - { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 -echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} - { (exit 1); exit 1; }; } -fi - + if test -z "$ac_cv_path_GREP"; then + as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi else ac_cv_path_GREP=$GREP fi - fi -{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 -echo "${ECHO_T}$ac_cv_path_GREP" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" -{ echo "$as_me:$LINENO: checking for egrep" >&5 -echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } -if test "${ac_cv_path_EGREP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then : + $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else - # Extract the first word of "egrep" to use in msg output -if test -z "$EGREP"; then -set dummy egrep; ac_prog_name=$2 -if test "${ac_cv_path_EGREP+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else + if test -z "$EGREP"; then ac_path_EGREP_found=false -# Loop through the user's path and test for each of PROGNAME-LIST -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue - # Check for GNU ac_path_EGREP and select it if it is found. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 - echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" - echo 'EGREP' >> "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - ac_count=`expr $ac_count + 1` + as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" @@ -3511,46 +3530,31 @@ case `"$ac_path_EGREP" --version 2>&1` in rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac - - $ac_path_EGREP_found && break 3 + $ac_path_EGREP_found && break 3 + done + done done -done - -done IFS=$as_save_IFS - - -fi - -EGREP="$ac_cv_path_EGREP" -if test -z "$EGREP"; then - { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 -echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} - { (exit 1); exit 1; }; } -fi - + if test -z "$ac_cv_path_EGREP"; then + as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi else ac_cv_path_EGREP=$EGREP fi - fi fi -{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 -echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" -{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 -echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } -if test "${ac_cv_header_stdc+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then : + $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -3565,47 +3569,23 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_header_stdc=no + ac_cv_header_stdc=no fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then - : + $EGREP "memchr" >/dev/null 2>&1; then : + else ac_cv_header_stdc=no fi @@ -3615,18 +3595,14 @@ fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then - : + $EGREP "free" >/dev/null 2>&1; then : + else ac_cv_header_stdc=no fi @@ -3636,14 +3612,10 @@ fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then + if test "$cross_compiling" = yes; then : : else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -3670,113 +3642,36 @@ main () return 0; } _ACEOF -rm -f conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - : +if ac_fn_c_try_run "$LINENO"; then : + else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -ac_cv_header_stdc=no + ac_cv_header_stdc=no fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext fi - fi fi -{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 -echo "${ECHO_T}$ac_cv_header_stdc" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then -cat >>confdefs.h <<\_ACEOF -#define STDC_HEADERS 1 -_ACEOF +$as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. - - - - - - - - - for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default - -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - eval "$as_ac_Header=yes" -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - eval "$as_ac_Header=no" -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_Header'}'` = yes; then +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +eval as_val=\$$as_ac_Header + if test "x$as_val" = x""yes; then : cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi @@ -3784,164 +3679,27 @@ fi done - for ac_header in stdlib.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - { echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -else - # Is the header compilable? -{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_header_compiler=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_compiler=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6; } - -# Is the header present? -{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <$ac_header> -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi - -rm -f conftest.err conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 -echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 -echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 -echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - ( cat <<\_ASBOX -## --------------------------------------- ## -## Report this to ejabberd@process-one.net ## -## --------------------------------------- ## -_ASBOX - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac -{ echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - eval "$as_ac_Header=\$ac_header_preproc" -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } - -fi -if test `eval echo '${'$as_ac_Header'}'` = yes; then +do : + ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" +if test "x$ac_cv_header_stdlib_h" = x""yes; then : cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +#define HAVE_STDLIB_H 1 _ACEOF fi done -{ echo "$as_me:$LINENO: checking for GNU libc compatible malloc" >&5 -echo $ECHO_N "checking for GNU libc compatible malloc... $ECHO_C" >&6; } -if test "${ac_cv_func_malloc_0_nonnull+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 +$as_echo_n "checking for GNU libc compatible malloc... " >&6; } +if test "${ac_cv_func_malloc_0_nonnull+set}" = set; then : + $as_echo_n "(cached) " >&6 else - if test "$cross_compiling" = yes; then + if test "$cross_compiling" = yes; then : ac_cv_func_malloc_0_nonnull=no else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined STDC_HEADERS || defined HAVE_STDLIB_H # include @@ -3957,52 +3715,24 @@ return ! malloc (0); return 0; } _ACEOF -rm -f conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then +if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_malloc_0_nonnull=yes else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -ac_cv_func_malloc_0_nonnull=no + ac_cv_func_malloc_0_nonnull=no fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext fi - fi -{ echo "$as_me:$LINENO: result: $ac_cv_func_malloc_0_nonnull" >&5 -echo "${ECHO_T}$ac_cv_func_malloc_0_nonnull" >&6; } -if test $ac_cv_func_malloc_0_nonnull = yes; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 +$as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } +if test $ac_cv_func_malloc_0_nonnull = yes; then : -cat >>confdefs.h <<\_ACEOF -#define HAVE_MALLOC 1 -_ACEOF +$as_echo "#define HAVE_MALLOC 1" >>confdefs.h else - cat >>confdefs.h <<\_ACEOF -#define HAVE_MALLOC 0 -_ACEOF + $as_echo "#define HAVE_MALLOC 0" >>confdefs.h case " $LIBOBJS " in *" malloc.$ac_objext "* ) ;; @@ -4011,24 +3741,17 @@ _ACEOF esac -cat >>confdefs.h <<\_ACEOF -#define malloc rpl_malloc -_ACEOF +$as_echo "#define malloc rpl_malloc" >>confdefs.h fi - -{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 -echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } -if test "${ac_cv_header_stdc+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then : + $as_echo_n "(cached) " >&6 else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -4043,47 +3766,23 @@ main () return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then +if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_header_stdc=no + ac_cv_header_stdc=no fi - rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then - : + $EGREP "memchr" >/dev/null 2>&1; then : + else ac_cv_header_stdc=no fi @@ -4093,18 +3792,14 @@ fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then - : + $EGREP "free" >/dev/null 2>&1; then : + else ac_cv_header_stdc=no fi @@ -4114,14 +3809,10 @@ fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then + if test "$cross_compiling" = yes; then : : else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -4148,48 +3839,22 @@ main () return 0; } _ACEOF -rm -f conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - : +if ac_fn_c_try_run "$LINENO"; then : + else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -ac_cv_header_stdc=no + ac_cv_header_stdc=no fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext fi - fi fi -{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 -echo "${ECHO_T}$ac_cv_header_stdc" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then -cat >>confdefs.h <<\_ACEOF -#define STDC_HEADERS 1 -_ACEOF +$as_echo "#define STDC_HEADERS 1" >>confdefs.h fi @@ -4197,10 +3862,10 @@ fi mod_muc= make_mod_muc= -{ echo "$as_me:$LINENO: checking whether build mod_muc" >&5 -echo $ECHO_N "checking whether build mod_muc... $ECHO_C" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build mod_muc" >&5 +$as_echo_n "checking whether build mod_muc... " >&6; } # Check whether --enable-mod_muc was given. -if test "${enable_mod_muc+set}" = set; then +if test "${enable_mod_muc+set}" = set; then : enableval=$enable_mod_muc; mr_enable_mod_muc="$enableval" else mr_enable_mod_muc=yes @@ -4210,8 +3875,8 @@ if test "$mr_enable_mod_muc" = "yes"; then mod_muc=mod_muc make_mod_muc=mod_muc/Makefile fi -{ echo "$as_me:$LINENO: result: $mr_enable_mod_muc" >&5 -echo "${ECHO_T}$mr_enable_mod_muc" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $mr_enable_mod_muc" >&5 +$as_echo "$mr_enable_mod_muc" >&6; } @@ -4219,10 +3884,10 @@ echo "${ECHO_T}$mr_enable_mod_muc" >&6; } mod_proxy65= make_mod_proxy65= -{ echo "$as_me:$LINENO: checking whether build mod_proxy65" >&5 -echo $ECHO_N "checking whether build mod_proxy65... $ECHO_C" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build mod_proxy65" >&5 +$as_echo_n "checking whether build mod_proxy65... " >&6; } # Check whether --enable-mod_proxy65 was given. -if test "${enable_mod_proxy65+set}" = set; then +if test "${enable_mod_proxy65+set}" = set; then : enableval=$enable_mod_proxy65; mr_enable_mod_proxy65="$enableval" else mr_enable_mod_proxy65=yes @@ -4232,8 +3897,8 @@ if test "$mr_enable_mod_proxy65" = "yes"; then mod_proxy65=mod_proxy65 make_mod_proxy65=mod_proxy65/Makefile fi -{ echo "$as_me:$LINENO: result: $mr_enable_mod_proxy65" >&5 -echo "${ECHO_T}$mr_enable_mod_proxy65" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $mr_enable_mod_proxy65" >&5 +$as_echo "$mr_enable_mod_proxy65" >&6; } @@ -4241,10 +3906,10 @@ echo "${ECHO_T}$mr_enable_mod_proxy65" >&6; } mod_pubsub= make_mod_pubsub= -{ echo "$as_me:$LINENO: checking whether build mod_pubsub" >&5 -echo $ECHO_N "checking whether build mod_pubsub... $ECHO_C" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build mod_pubsub" >&5 +$as_echo_n "checking whether build mod_pubsub... " >&6; } # Check whether --enable-mod_pubsub was given. -if test "${enable_mod_pubsub+set}" = set; then +if test "${enable_mod_pubsub+set}" = set; then : enableval=$enable_mod_pubsub; mr_enable_mod_pubsub="$enableval" else mr_enable_mod_pubsub=yes @@ -4254,8 +3919,8 @@ if test "$mr_enable_mod_pubsub" = "yes"; then mod_pubsub=mod_pubsub make_mod_pubsub=mod_pubsub/Makefile fi -{ echo "$as_me:$LINENO: result: $mr_enable_mod_pubsub" >&5 -echo "${ECHO_T}$mr_enable_mod_pubsub" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $mr_enable_mod_pubsub" >&5 +$as_echo "$mr_enable_mod_pubsub" >&6; } @@ -4263,10 +3928,10 @@ echo "${ECHO_T}$mr_enable_mod_pubsub" >&6; } eldap= make_eldap= -{ echo "$as_me:$LINENO: checking whether build eldap" >&5 -echo $ECHO_N "checking whether build eldap... $ECHO_C" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build eldap" >&5 +$as_echo_n "checking whether build eldap... " >&6; } # Check whether --enable-eldap was given. -if test "${enable_eldap+set}" = set; then +if test "${enable_eldap+set}" = set; then : enableval=$enable_eldap; mr_enable_eldap="$enableval" else mr_enable_eldap=yes @@ -4276,8 +3941,8 @@ if test "$mr_enable_eldap" = "yes"; then eldap=eldap make_eldap=eldap/Makefile fi -{ echo "$as_me:$LINENO: result: $mr_enable_eldap" >&5 -echo "${ECHO_T}$mr_enable_eldap" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $mr_enable_eldap" >&5 +$as_echo "$mr_enable_eldap" >&6; } @@ -4285,10 +3950,10 @@ echo "${ECHO_T}$mr_enable_eldap" >&6; } odbc= make_odbc= -{ echo "$as_me:$LINENO: checking whether build odbc" >&5 -echo $ECHO_N "checking whether build odbc... $ECHO_C" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build odbc" >&5 +$as_echo_n "checking whether build odbc... " >&6; } # Check whether --enable-odbc was given. -if test "${enable_odbc+set}" = set; then +if test "${enable_odbc+set}" = set; then : enableval=$enable_odbc; mr_enable_odbc="$enableval" else mr_enable_odbc=no @@ -4298,8 +3963,8 @@ if test "$mr_enable_odbc" = "yes"; then odbc=odbc make_odbc=odbc/Makefile fi -{ echo "$as_me:$LINENO: result: $mr_enable_odbc" >&5 -echo "${ECHO_T}$mr_enable_odbc" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $mr_enable_odbc" >&5 +$as_echo "$mr_enable_odbc" >&6; } @@ -4307,10 +3972,10 @@ echo "${ECHO_T}$mr_enable_odbc" >&6; } tls= make_tls= -{ echo "$as_me:$LINENO: checking whether build tls" >&5 -echo $ECHO_N "checking whether build tls... $ECHO_C" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build tls" >&5 +$as_echo_n "checking whether build tls... " >&6; } # Check whether --enable-tls was given. -if test "${enable_tls+set}" = set; then +if test "${enable_tls+set}" = set; then : enableval=$enable_tls; mr_enable_tls="$enableval" else mr_enable_tls=yes @@ -4320,8 +3985,8 @@ if test "$mr_enable_tls" = "yes"; then tls=tls make_tls=tls/Makefile fi -{ echo "$as_me:$LINENO: result: $mr_enable_tls" >&5 -echo "${ECHO_T}$mr_enable_tls" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $mr_enable_tls" >&5 +$as_echo "$mr_enable_tls" >&6; } @@ -4329,10 +3994,10 @@ echo "${ECHO_T}$mr_enable_tls" >&6; } web= make_web= -{ echo "$as_me:$LINENO: checking whether build web" >&5 -echo $ECHO_N "checking whether build web... $ECHO_C" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build web" >&5 +$as_echo_n "checking whether build web... " >&6; } # Check whether --enable-web was given. -if test "${enable_web+set}" = set; then +if test "${enable_web+set}" = set; then : enableval=$enable_web; mr_enable_web="$enableval" else mr_enable_web=yes @@ -4342,8 +4007,8 @@ if test "$mr_enable_web" = "yes"; then web=web make_web=web/Makefile fi -{ echo "$as_me:$LINENO: result: $mr_enable_web" >&5 -echo "${ECHO_T}$mr_enable_web" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $mr_enable_web" >&5 +$as_echo "$mr_enable_web" >&6; } @@ -4352,10 +4017,10 @@ echo "${ECHO_T}$mr_enable_web" >&6; } ejabberd_zlib= make_ejabberd_zlib= -{ echo "$as_me:$LINENO: checking whether build ejabberd_zlib" >&5 -echo $ECHO_N "checking whether build ejabberd_zlib... $ECHO_C" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build ejabberd_zlib" >&5 +$as_echo_n "checking whether build ejabberd_zlib... " >&6; } # Check whether --enable-ejabberd_zlib was given. -if test "${enable_ejabberd_zlib+set}" = set; then +if test "${enable_ejabberd_zlib+set}" = set; then : enableval=$enable_ejabberd_zlib; mr_enable_ejabberd_zlib="$enableval" else mr_enable_ejabberd_zlib=yes @@ -4365,8 +4030,8 @@ if test "$mr_enable_ejabberd_zlib" = "yes"; then ejabberd_zlib=ejabberd_zlib make_ejabberd_zlib=ejabberd_zlib/Makefile fi -{ echo "$as_me:$LINENO: result: $mr_enable_ejabberd_zlib" >&5 -echo "${ECHO_T}$mr_enable_ejabberd_zlib" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $mr_enable_ejabberd_zlib" >&5 +$as_echo "$mr_enable_ejabberd_zlib" >&6; } @@ -4374,7 +4039,7 @@ echo "${ECHO_T}$mr_enable_ejabberd_zlib" >&6; } #locating zlib # Check whether --with-zlib was given. -if test "${with_zlib+set}" = set; then +if test "${with_zlib+set}" = set; then : withval=$with_zlib; fi @@ -4387,18 +4052,14 @@ if test x"$ejabberd_zlib" != x; then ZLIB_LIBS="-L$with_zlib/lib" fi - { echo "$as_me:$LINENO: checking for gzgets in -lz" >&5 -echo $ECHO_N "checking for gzgets in -lz... $ECHO_C" >&6; } -if test "${ac_cv_lib_z_gzgets+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gzgets in -lz" >&5 +$as_echo_n "checking for gzgets in -lz... " >&6; } +if test "${ac_cv_lib_z_gzgets+set}" = set; then : + $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lz "$ZLIB_LIBS" $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -4416,39 +4077,18 @@ return gzgets (); return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then +if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_z_gzgets=yes else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_z_gzgets=no + ac_cv_lib_z_gzgets=no fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ echo "$as_me:$LINENO: result: $ac_cv_lib_z_gzgets" >&5 -echo "${ECHO_T}$ac_cv_lib_z_gzgets" >&6; } -if test $ac_cv_lib_z_gzgets = yes; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzgets" >&5 +$as_echo "$ac_cv_lib_z_gzgets" >&6; } +if test "x$ac_cv_lib_z_gzgets" = x""yes; then : ZLIB_LIBS="$ZLIB_LIBS -lz" zlib_found=yes else @@ -4456,153 +4096,18 @@ else fi if test $zlib_found = no; then - { { echo "$as_me:$LINENO: error: Could not find development files of zlib library. Install them or disable \`ejabberd_zlib' with: --disable-ejabberd_zlib" >&5 -echo "$as_me: error: Could not find development files of zlib library. Install them or disable \`ejabberd_zlib' with: --disable-ejabberd_zlib" >&2;} - { (exit 1); exit 1; }; } + as_fn_error "Could not find development files of zlib library. Install them or disable \`ejabberd_zlib' with: --disable-ejabberd_zlib" "$LINENO" 5 fi zlib_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $ZLIB_CFLAGS" zlib_save_CPPFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS $ZLIB_CFLAGS" - -for ac_header in zlib.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - { echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -else - # Is the header compilable? -{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_header_compiler=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_compiler=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6; } - -# Is the header present? -{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <$ac_header> -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi - -rm -f conftest.err conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 -echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 -echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 -echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - ( cat <<\_ASBOX -## --------------------------------------- ## -## Report this to ejabberd@process-one.net ## -## --------------------------------------- ## -_ASBOX - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac -{ echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - eval "$as_ac_Header=\$ac_header_preproc" -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } - -fi -if test `eval echo '${'$as_ac_Header'}'` = yes; then + for ac_header in zlib.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" +if test "x$ac_cv_header_zlib_h" = x""yes; then : cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +#define HAVE_ZLIB_H 1 _ACEOF else @@ -4612,9 +4117,7 @@ fi done if test $zlib_found = no; then - { { echo "$as_me:$LINENO: error: Could not find zlib.h. Install it or disable \`ejabberd_zlib' with: --disable-ejabberd_zlib" >&5 -echo "$as_me: error: Could not find zlib.h. Install it or disable \`ejabberd_zlib' with: --disable-ejabberd_zlib" >&2;} - { (exit 1); exit 1; }; } + as_fn_error "Could not find zlib.h. Install it or disable \`ejabberd_zlib' with: --disable-ejabberd_zlib" "$LINENO" 5 fi CFLAGS="$zlib_save_CFLAGS" CPPFLAGS="$zlib_save_CPPFLAGS" @@ -4627,10 +4130,10 @@ fi pam= make_pam= -{ echo "$as_me:$LINENO: checking whether build pam" >&5 -echo $ECHO_N "checking whether build pam... $ECHO_C" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build pam" >&5 +$as_echo_n "checking whether build pam... " >&6; } # Check whether --enable-pam was given. -if test "${enable_pam+set}" = set; then +if test "${enable_pam+set}" = set; then : enableval=$enable_pam; mr_enable_pam="$enableval" else mr_enable_pam=no @@ -4640,8 +4143,8 @@ if test "$mr_enable_pam" = "yes"; then pam=pam make_pam=pam/Makefile fi -{ echo "$as_me:$LINENO: result: $mr_enable_pam" >&5 -echo "${ECHO_T}$mr_enable_pam" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $mr_enable_pam" >&5 +$as_echo "$mr_enable_pam" >&6; } @@ -4649,7 +4152,7 @@ echo "${ECHO_T}$mr_enable_pam" >&6; } #locating PAM # Check whether --with-pam was given. -if test "${with_pam+set}" = set; then +if test "${with_pam+set}" = set; then : withval=$with_pam; fi @@ -4661,18 +4164,14 @@ if test x"$pam" != x; then PAM_LIBS="-L$with_pam/lib" fi - { echo "$as_me:$LINENO: checking for pam_start in -lpam" >&5 -echo $ECHO_N "checking for pam_start in -lpam... $ECHO_C" >&6; } -if test "${ac_cv_lib_pam_pam_start+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pam_start in -lpam" >&5 +$as_echo_n "checking for pam_start in -lpam... " >&6; } +if test "${ac_cv_lib_pam_pam_start+set}" = set; then : + $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpam "$PAM_LIBS" $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -4690,39 +4189,18 @@ return pam_start (); return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then +if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pam_pam_start=yes else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_pam_pam_start=no + ac_cv_lib_pam_pam_start=no fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ echo "$as_me:$LINENO: result: $ac_cv_lib_pam_pam_start" >&5 -echo "${ECHO_T}$ac_cv_lib_pam_pam_start" >&6; } -if test $ac_cv_lib_pam_pam_start = yes; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pam_pam_start" >&5 +$as_echo "$ac_cv_lib_pam_pam_start" >&6; } +if test "x$ac_cv_lib_pam_pam_start" = x""yes; then : PAM_LIBS="$PAM_LIBS -lpam" pam_found=yes else @@ -4730,153 +4208,18 @@ else fi if test $pam_found = no; then - { { echo "$as_me:$LINENO: error: Could not find development files of PAM library. Install them or disable \`pam' with: --disable-pam" >&5 -echo "$as_me: error: Could not find development files of PAM library. Install them or disable \`pam' with: --disable-pam" >&2;} - { (exit 1); exit 1; }; } + as_fn_error "Could not find development files of PAM library. Install them or disable \`pam' with: --disable-pam" "$LINENO" 5 fi pam_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PAM_CFLAGS" pam_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $PAM_CFLAGS" - -for ac_header in security/pam_appl.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - { echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -else - # Is the header compilable? -{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_header_compiler=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_compiler=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6; } - -# Is the header present? -{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <$ac_header> -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi - -rm -f conftest.err conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 -echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 -echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 -echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - ( cat <<\_ASBOX -## --------------------------------------- ## -## Report this to ejabberd@process-one.net ## -## --------------------------------------- ## -_ASBOX - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac -{ echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - eval "$as_ac_Header=\$ac_header_preproc" -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } - -fi -if test `eval echo '${'$as_ac_Header'}'` = yes; then + for ac_header in security/pam_appl.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "security/pam_appl.h" "ac_cv_header_security_pam_appl_h" "$ac_includes_default" +if test "x$ac_cv_header_security_pam_appl_h" = x""yes; then : cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +#define HAVE_SECURITY_PAM_APPL_H 1 _ACEOF else @@ -4886,9 +4229,7 @@ fi done if test $pam_found = no; then - { { echo "$as_me:$LINENO: error: Could not find security/pam_appl.h. Install it or disable \`pam' with: --disable-pam" >&5 -echo "$as_me: error: Could not find security/pam_appl.h. Install it or disable \`pam' with: --disable-pam" >&2;} - { (exit 1); exit 1; }; } + as_fn_error "Could not find security/pam_appl.h. Install it or disable \`pam' with: --disable-pam" "$LINENO" 5 fi CFLAGS="$pam_save_CFLAGS" CPPFLAGS="$pam_save_CPPFLAGS" @@ -4899,13 +4240,11 @@ fi # Check whether --enable-hipe was given. -if test "${enable_hipe+set}" = set; then +if test "${enable_hipe+set}" = set; then : enableval=$enable_hipe; case "${enableval}" in yes) hipe=true ;; no) hipe=false ;; - *) { { echo "$as_me:$LINENO: error: bad value ${enableval} for --enable-hipe" >&5 -echo "$as_me: error: bad value ${enableval} for --enable-hipe" >&2;} - { (exit 1); exit 1; }; } ;; + *) as_fn_error "bad value ${enableval} for --enable-hipe" "$LINENO" 5 ;; esac else hipe=false @@ -4914,13 +4253,11 @@ fi # Check whether --enable-roster_gateway_workaround was given. -if test "${enable_roster_gateway_workaround+set}" = set; then +if test "${enable_roster_gateway_workaround+set}" = set; then : enableval=$enable_roster_gateway_workaround; case "${enableval}" in yes) roster_gateway_workaround=true ;; no) roster_gateway_workaround=false ;; - *) { { echo "$as_me:$LINENO: error: bad value ${enableval} for --enable-roster-gateway-workaround" >&5 -echo "$as_me: error: bad value ${enableval} for --enable-roster-gateway-workaround" >&2;} - { (exit 1); exit 1; }; } ;; + *) as_fn_error "bad value ${enableval} for --enable-roster-gateway-workaround" "$LINENO" 5 ;; esac else roster_gateway_workaround=false @@ -4929,13 +4266,11 @@ fi # Check whether --enable-mssql was given. -if test "${enable_mssql+set}" = set; then +if test "${enable_mssql+set}" = set; then : enableval=$enable_mssql; case "${enableval}" in yes) db_type=mssql ;; no) db_type=generic ;; - *) { { echo "$as_me:$LINENO: error: bad value ${enableval} for --enable-mssql" >&5 -echo "$as_me: error: bad value ${enableval} for --enable-mssql" >&2;} - { (exit 1); exit 1; }; } ;; + *) as_fn_error "bad value ${enableval} for --enable-mssql" "$LINENO" 5 ;; esac else db_type=generic @@ -4944,13 +4279,11 @@ fi # Check whether --enable-transient_supervisors was given. -if test "${enable_transient_supervisors+set}" = set; then +if test "${enable_transient_supervisors+set}" = set; then : enableval=$enable_transient_supervisors; case "${enableval}" in yes) transient_supervisors=true ;; no) transient_supervisors=false ;; - *) { { echo "$as_me:$LINENO: error: bad value ${enableval} for --enable-full-xml" >&5 -echo "$as_me: error: bad value ${enableval} for --enable-full-xml" >&2;} - { (exit 1); exit 1; }; } ;; + *) as_fn_error "bad value ${enableval} for --enable-full-xml" "$LINENO" 5 ;; esac else transient_supervisors=true @@ -4959,13 +4292,11 @@ fi # Check whether --enable-full_xml was given. -if test "${enable_full_xml+set}" = set; then +if test "${enable_full_xml+set}" = set; then : enableval=$enable_full_xml; case "${enableval}" in yes) full_xml=true ;; no) full_xml=false ;; - *) { { echo "$as_me:$LINENO: error: bad value ${enableval} for --enable-full-xml" >&5 -echo "$as_me: error: bad value ${enableval} for --enable-full-xml" >&2;} - { (exit 1); exit 1; }; } ;; + *) as_fn_error "bad value ${enableval} for --enable-full-xml" "$LINENO" 5 ;; esac else full_xml=false @@ -4973,12 +4304,12 @@ fi -ac_config_files="$ac_config_files Makefile $make_mod_muc $make_mod_pubsub $make_mod_proxy65 $make_eldap $make_pam $make_web $make_tls $make_odbc $make_ejabberd_zlib" +ac_config_files="$ac_config_files Makefile $make_mod_muc $make_mod_pubsub $make_mod_proxy65 $make_eldap $make_pam $make_web stun/Makefile $make_tls $make_odbc $make_ejabberd_zlib" #openssl # Check whether --with-openssl was given. -if test "${with_openssl+set}" = set; then +if test "${with_openssl+set}" = set; then : withval=$with_openssl; fi @@ -4990,18 +4321,14 @@ if test x"$tls" != x; then printf "looking for openssl in $ssl_prefix...\n" SSL_CFLAGS="-I$ssl_prefix/include" SSL_LIBS="-L$ssl_prefix/lib -lcrypto" - { echo "$as_me:$LINENO: checking for SSL_new in -lssl" >&5 -echo $ECHO_N "checking for SSL_new in -lssl... $ECHO_C" >&6; } -if test "${ac_cv_lib_ssl_SSL_new+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_new in -lssl" >&5 +$as_echo_n "checking for SSL_new in -lssl... " >&6; } +if test "${ac_cv_lib_ssl_SSL_new+set}" = set; then : + $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lssl $SSL_LIBS $SSL_CFLAGS $LIBS" -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -5019,39 +4346,18 @@ return SSL_new (); return 0; } _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && - $as_test_x conftest$ac_exeext; then +if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ssl_SSL_new=yes else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_cv_lib_ssl_SSL_new=no + ac_cv_lib_ssl_SSL_new=no fi - -rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ echo "$as_me:$LINENO: result: $ac_cv_lib_ssl_SSL_new" >&5 -echo "${ECHO_T}$ac_cv_lib_ssl_SSL_new" >&6; } -if test $ac_cv_lib_ssl_SSL_new = yes; then +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_new" >&5 +$as_echo "$ac_cv_lib_ssl_SSL_new" >&6; } +if test "x$ac_cv_lib_ssl_SSL_new" = x""yes; then : have_openssl=yes else have_openssl=no @@ -5060,145 +4366,12 @@ fi if test x"$have_openssl" = xyes; then save_CPPFLAGS=$CPPFLAGS CPPFLAGS="-I$ssl_prefix/include $CPPFLAGS" - -for ac_header in openssl/ssl.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - { echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -else - # Is the header compilable? -{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include <$ac_header> -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_header_compiler=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_compiler=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6; } - -# Is the header present? -{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <$ac_header> -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi - -rm -f conftest.err conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 -echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 -echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 -echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - ( cat <<\_ASBOX -## --------------------------------------- ## -## Report this to ejabberd@process-one.net ## -## --------------------------------------- ## -_ASBOX - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac -{ echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - eval "$as_ac_Header=\$ac_header_preproc" -fi -ac_res=`eval echo '${'$as_ac_Header'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } - -fi -if test `eval echo '${'$as_ac_Header'}'` = yes; then + for ac_header in openssl/ssl.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default" +if test "x$ac_cv_header_openssl_ssl_h" = x""yes; then : cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +#define HAVE_OPENSSL_SSL_H 1 _ACEOF have_openssl_h=yes fi @@ -5221,9 +4394,7 @@ done fi done if test x${have_openssl} != xyes; then - { { echo "$as_me:$LINENO: error: Could not find development files of OpenSSL library. Install them or disable \`tls' with: --disable-tls" >&5 -echo "$as_me: error: Could not find development files of OpenSSL library. Install them or disable \`tls' with: --disable-tls" >&2;} - { (exit 1); exit 1; }; } + as_fn_error "Could not find development files of OpenSSL library. Install them or disable \`tls' with: --disable-tls" "$LINENO" 5 fi @@ -5243,134 +4414,8 @@ else fi done fi -if test "${ac_cv_header_krb5_h+set}" = set; then - { echo "$as_me:$LINENO: checking for krb5.h" >&5 -echo $ECHO_N "checking for krb5.h... $ECHO_C" >&6; } -if test "${ac_cv_header_krb5_h+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -{ echo "$as_me:$LINENO: result: $ac_cv_header_krb5_h" >&5 -echo "${ECHO_T}$ac_cv_header_krb5_h" >&6; } -else - # Is the header compilable? -{ echo "$as_me:$LINENO: checking krb5.h usability" >&5 -echo $ECHO_N "checking krb5.h usability... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -$ac_includes_default -#include -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then - ac_header_compiler=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_compiler=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6; } - -# Is the header present? -{ echo "$as_me:$LINENO: checking krb5.h presence" >&5 -echo $ECHO_N "checking krb5.h presence... $ECHO_C" >&6; } -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -_ACEOF -if { (ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi - -rm -f conftest.err conftest.$ac_ext -{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { echo "$as_me:$LINENO: WARNING: krb5.h: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: krb5.h: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: krb5.h: proceeding with the compiler's result" >&5 -echo "$as_me: WARNING: krb5.h: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { echo "$as_me:$LINENO: WARNING: krb5.h: present but cannot be compiled" >&5 -echo "$as_me: WARNING: krb5.h: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: krb5.h: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: krb5.h: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: krb5.h: see the Autoconf documentation" >&5 -echo "$as_me: WARNING: krb5.h: see the Autoconf documentation" >&2;} - { echo "$as_me:$LINENO: WARNING: krb5.h: section \"Present But Cannot Be Compiled\"" >&5 -echo "$as_me: WARNING: krb5.h: section \"Present But Cannot Be Compiled\"" >&2;} - { echo "$as_me:$LINENO: WARNING: krb5.h: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: krb5.h: proceeding with the preprocessor's result" >&2;} - { echo "$as_me:$LINENO: WARNING: krb5.h: in the future, the compiler will take precedence" >&5 -echo "$as_me: WARNING: krb5.h: in the future, the compiler will take precedence" >&2;} - ( cat <<\_ASBOX -## --------------------------------------- ## -## Report this to ejabberd@process-one.net ## -## --------------------------------------- ## -_ASBOX - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac -{ echo "$as_me:$LINENO: checking for krb5.h" >&5 -echo $ECHO_N "checking for krb5.h... $ECHO_C" >&6; } -if test "${ac_cv_header_krb5_h+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_cv_header_krb5_h=$ac_header_preproc -fi -{ echo "$as_me:$LINENO: result: $ac_cv_header_krb5_h" >&5 -echo "${ECHO_T}$ac_cv_header_krb5_h" >&6; } +ac_fn_c_check_header_mongrel "$LINENO" "krb5.h" "ac_cv_header_krb5_h" "$ac_includes_default" +if test "x$ac_cv_header_krb5_h" = x""yes; then : fi @@ -5378,7 +4423,7 @@ fi ENABLEUSER="" # Check whether --enable-user was given. -if test "${enable_user+set}" = set; then +if test "${enable_user+set}" = set; then : enableval=$enable_user; case "${enableval}" in yes) ENABLEUSER=`whoami` ;; no) ENABLEUSER="" ;; @@ -5419,12 +4464,13 @@ _ACEOF case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 -echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( - *) $as_unset $ac_var ;; + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done @@ -5432,8 +4478,8 @@ echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes (double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \). + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" @@ -5456,12 +4502,12 @@ echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && - { echo "$as_me:$LINENO: updating cache $cache_file" >&5 -echo "$as_me: updating cache $cache_file" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else - { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 -echo "$as_me: not updating unwritable cache $cache_file" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache @@ -5478,6 +4524,12 @@ test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g @@ -5507,11 +4559,11 @@ ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`echo "$ac_i" | sed "$ac_script"` + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. - ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" - ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs @@ -5520,11 +4572,13 @@ LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} +ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 -echo "$as_me: creating $CONFIG_STATUS" >&6;} -cat >$CONFIG_STATUS <<_ACEOF +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. @@ -5534,59 +4588,79 @@ cat >$CONFIG_STATUS <<_ACEOF debug=false ac_cs_recheck=false ac_cs_silent=false -SHELL=\${CONFIG_SHELL-$SHELL} -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF -## --------------------- ## -## M4sh Initialization. ## -## --------------------- ## +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else - case `(set -o) 2>/dev/null` in - *posix*) set -o posix ;; + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; esac - fi - - -# PATH needs CR -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conf$$.sh - echo "exit 0" >>conf$$.sh - chmod +x conf$$.sh - if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then - PATH_SEPARATOR=';' - else - PATH_SEPARATOR=: - fi - rm -f conf$$.sh -fi - -# Support unset when possible. -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - as_unset=unset -else - as_unset=false + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } fi @@ -5595,20 +4669,18 @@ fi # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) -as_nl=' -' IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. -case $0 in +case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break -done + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done IFS=$as_save_IFS ;; @@ -5619,32 +4691,111 @@ if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - { (exit 1); exit 1; } + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 fi -# Work around bugs in pre-3.0 UWIN ksh. -for as_var in ENV MAIL MAILPATH -do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. -for as_var in \ - LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ - LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ - LC_TELEPHONE LC_TIME -do - if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then - eval $as_var=C; export $as_var - else - ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var - fi -done +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + -# Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr @@ -5658,13 +4809,17 @@ else as_basename=false fi +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi -# Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -echo X/"$0" | +$as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -5679,104 +4834,103 @@ echo X/"$0" | } s/.*/./; q'` -# CDPATH. -$as_unset CDPATH - - - - as_lineno_1=$LINENO - as_lineno_2=$LINENO - test "x$as_lineno_1" != "x$as_lineno_2" && - test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { - - # Create $as_me.lineno as a copy of $as_myself, but with $LINENO - # uniformly replaced by the line number. The first 'sed' inserts a - # line-number line after each line using $LINENO; the second 'sed' - # does the real work. The second script uses 'N' to pair each - # line-number line with the line containing $LINENO, and appends - # trailing '-' during substitution so that $LINENO is not a special - # case at line end. - # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the - # scripts with optimization help from Paolo Bonzini. Blame Lee - # E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 - { (exit 1); exit 1; }; } - - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in +case `echo -n x` in #((((( -n*) - case `echo 'x\c'` in + case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. - *) ECHO_C='\c';; + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir - mkdir conf$$.dir + mkdir conf$$.dir 2>/dev/null fi -echo >conf$$.file -if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else as_ln_s='cp -p' -elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln + fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then - as_mkdir_p=: + as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false @@ -5793,12 +4947,12 @@ else as_test_x=' eval sh -c '\'' if test -d "$1"; then - test -d "$1/."; + test -d "$1/."; else - case $1 in - -*)set "./$1";; + case $1 in #( + -*)set "./$1";; esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' @@ -5813,13 +4967,19 @@ as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 -# Save the log message, to keep $[0] and so on meaningful, and to +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by ejabberd.erl $as_me version, which was -generated by GNU Autoconf 2.61. Invocation command line was +generated by GNU Autoconf 2.64. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -5832,50 +4992,58 @@ on `(hostname || uname -n) 2>/dev/null | sed 1q` _ACEOF -cat >>$CONFIG_STATUS <<_ACEOF +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ -\`$as_me' instantiates files from templates according to the -current configuration. +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. -Usage: $0 [OPTIONS] [FILE]... +Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit - -q, --quiet do not print progress messages + -q, --quiet, --silent + do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE Configuration files: $config_files -Report bugs to ." +Report bugs to ." _ACEOF -cat >>$CONFIG_STATUS <<_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ ejabberd.erl config.status version -configured by $0, generated by GNU Autoconf 2.61, - with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" +configured by $0, generated by GNU Autoconf 2.64, + with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" -Copyright (C) 2006 Free Software Foundation, Inc. +Copyright (C) 2009 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' +test -n "\$AWK" || AWK=awk _ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF -# If no file are specified by the user, then we need to provide default -# value. By we need to know if files were specified by the user. +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do @@ -5897,25 +5065,27 @@ do -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - echo "$ac_cs_version"; exit ;; + $as_echo "$ac_cs_version"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift - CONFIG_FILES="$CONFIG_FILES $ac_optarg" + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) - echo "$ac_cs_usage"; exit ;; + $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. - -*) { echo "$as_me: error: unrecognized option: $1 -Try \`$0 --help' for more information." >&2 - { (exit 1); exit 1; }; } ;; + -*) as_fn_error "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; - *) ac_config_targets="$ac_config_targets $1" + *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac @@ -5930,30 +5100,32 @@ if $ac_cs_silent; then fi _ACEOF -cat >>$CONFIG_STATUS <<_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then - echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 - CONFIG_SHELL=$SHELL + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' export CONFIG_SHELL - exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + exec "\$@" fi _ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX - echo "$ac_log" + $as_echo "$ac_log" } >&5 _ACEOF -cat >>$CONFIG_STATUS <<_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets @@ -5966,13 +5138,12 @@ do "$make_eldap") CONFIG_FILES="$CONFIG_FILES $make_eldap" ;; "$make_pam") CONFIG_FILES="$CONFIG_FILES $make_pam" ;; "$make_web") CONFIG_FILES="$CONFIG_FILES $make_web" ;; + "stun/Makefile") CONFIG_FILES="$CONFIG_FILES stun/Makefile" ;; "$make_tls") CONFIG_FILES="$CONFIG_FILES $make_tls" ;; "$make_odbc") CONFIG_FILES="$CONFIG_FILES $make_odbc" ;; "$make_ejabberd_zlib") CONFIG_FILES="$CONFIG_FILES $make_ejabberd_zlib" ;; - *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 -echo "$as_me: error: invalid argument: $ac_config_target" >&2;} - { (exit 1); exit 1; }; };; + *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done @@ -5997,7 +5168,7 @@ $debug || trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 - trap '{ (exit 1); exit 1; }' 1 2 13 15 + trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. @@ -6008,152 +5179,139 @@ $debug || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") -} || -{ - echo "$me: cannot create a temporary directory in ." >&2 - { (exit 1); exit 1; } -} +} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 -# -# Set up the sed scripts for CONFIG_FILES section. -# - -# No need to generate the scripts if there are no CONFIG_FILES. -# This happens for instance when ./config.status config.h +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF - +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do - cat >conf$$subs.sed <<_ACEOF -SHELL!$SHELL$ac_delim -PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim -PACKAGE_NAME!$PACKAGE_NAME$ac_delim -PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim -PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim -PACKAGE_STRING!$PACKAGE_STRING$ac_delim -PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim -exec_prefix!$exec_prefix$ac_delim -prefix!$prefix$ac_delim -program_transform_name!$program_transform_name$ac_delim -bindir!$bindir$ac_delim -sbindir!$sbindir$ac_delim -libexecdir!$libexecdir$ac_delim -datarootdir!$datarootdir$ac_delim -datadir!$datadir$ac_delim -sysconfdir!$sysconfdir$ac_delim -sharedstatedir!$sharedstatedir$ac_delim -localstatedir!$localstatedir$ac_delim -includedir!$includedir$ac_delim -oldincludedir!$oldincludedir$ac_delim -docdir!$docdir$ac_delim -infodir!$infodir$ac_delim -htmldir!$htmldir$ac_delim -dvidir!$dvidir$ac_delim -pdfdir!$pdfdir$ac_delim -psdir!$psdir$ac_delim -libdir!$libdir$ac_delim -localedir!$localedir$ac_delim -mandir!$mandir$ac_delim -DEFS!$DEFS$ac_delim -ECHO_C!$ECHO_C$ac_delim -ECHO_N!$ECHO_N$ac_delim -ECHO_T!$ECHO_T$ac_delim -LIBS!$LIBS$ac_delim -build_alias!$build_alias$ac_delim -host_alias!$host_alias$ac_delim -target_alias!$target_alias$ac_delim -CC!$CC$ac_delim -CFLAGS!$CFLAGS$ac_delim -LDFLAGS!$LDFLAGS$ac_delim -CPPFLAGS!$CPPFLAGS$ac_delim -ac_ct_CC!$ac_ct_CC$ac_delim -EXEEXT!$EXEEXT$ac_delim -OBJEXT!$OBJEXT$ac_delim -SET_MAKE!$SET_MAKE$ac_delim -ERLC!$ERLC$ac_delim -ERL!$ERL$ac_delim -ERLANG_CFLAGS!$ERLANG_CFLAGS$ac_delim -ERLANG_LIBS!$ERLANG_LIBS$ac_delim -ERLANG_SSL39!$ERLANG_SSL39$ac_delim -ERLANG_EXMPP!$ERLANG_EXMPP$ac_delim -CPP!$CPP$ac_delim -GREP!$GREP$ac_delim -EGREP!$EGREP$ac_delim -LIBOBJS!$LIBOBJS$ac_delim -mod_muc!$mod_muc$ac_delim -make_mod_muc!$make_mod_muc$ac_delim -mod_proxy65!$mod_proxy65$ac_delim -make_mod_proxy65!$make_mod_proxy65$ac_delim -mod_pubsub!$mod_pubsub$ac_delim -make_mod_pubsub!$make_mod_pubsub$ac_delim -eldap!$eldap$ac_delim -make_eldap!$make_eldap$ac_delim -odbc!$odbc$ac_delim -make_odbc!$make_odbc$ac_delim -tls!$tls$ac_delim -make_tls!$make_tls$ac_delim -web!$web$ac_delim -make_web!$make_web$ac_delim -ejabberd_zlib!$ejabberd_zlib$ac_delim -make_ejabberd_zlib!$make_ejabberd_zlib$ac_delim -ZLIB_CFLAGS!$ZLIB_CFLAGS$ac_delim -ZLIB_LIBS!$ZLIB_LIBS$ac_delim -pam!$pam$ac_delim -make_pam!$make_pam$ac_delim -PAM_CFLAGS!$PAM_CFLAGS$ac_delim -PAM_LIBS!$PAM_LIBS$ac_delim -hipe!$hipe$ac_delim -roster_gateway_workaround!$roster_gateway_workaround$ac_delim -db_type!$db_type$ac_delim -transient_supervisors!$transient_supervisors$ac_delim -full_xml!$full_xml$ac_delim -SSL_LIBS!$SSL_LIBS$ac_delim -SSL_CFLAGS!$SSL_CFLAGS$ac_delim -INSTALLUSER!$INSTALLUSER$ac_delim -LTLIBOBJS!$LTLIBOBJS$ac_delim -_ACEOF + . ./conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 86; then + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then - { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 -echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} - { (exit 1); exit 1; }; } + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done +rm -f conf$$subs.sh -ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` -if test -n "$ac_eof"; then - ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` - ac_eof=`expr $ac_eof + 1` -fi - -cat >>$CONFIG_STATUS <<_ACEOF -cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end -_ACEOF -sed ' -s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g -s/^/s,@/; s/!/@,|#_!!_#|/ -:n -t n -s/'"$ac_delim"'$/,g/; t -s/$/\\/; p -N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n -' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF -:end -s/|#_!!_#|//g -CEOF$ac_eof +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\).*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\).*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || as_fn_error "could not setup config files machinery" "$LINENO" 5 +_ACEOF # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and @@ -6170,20 +5328,20 @@ s/^[^=]*=[ ]*$// }' fi -cat >>$CONFIG_STATUS <<\_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" -for ac_tag in :F $CONFIG_FILES +eval set X " :F $CONFIG_FILES " +shift +for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 -echo "$as_me: error: Invalid tag $ac_tag." >&2;} - { (exit 1); exit 1; }; };; + :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac @@ -6211,26 +5369,34 @@ echo "$as_me: error: Invalid tag $ac_tag." >&2;} [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 -echo "$as_me: error: cannot find input file: $ac_f" >&2;} - { (exit 1); exit 1; }; };; + as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac - ac_file_inputs="$ac_file_inputs $ac_f" + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ - configure_input="Generated from "`IFS=: - echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" - { echo "$as_me:$LINENO: creating $ac_file" >&5 -echo "$as_me: creating $ac_file" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac case $ac_tag in - *:-:* | *:-) cat >"$tmp/stdin";; + *:-:* | *:-) cat >"$tmp/stdin" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac @@ -6240,7 +5406,7 @@ $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -echo X"$ac_file" | +$as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -6258,55 +5424,15 @@ echo X"$ac_file" | q } s/.*/./; q'` - { as_dir="$ac_dir" - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 -echo "$as_me: error: cannot create directory $as_dir" >&2;} - { (exit 1); exit 1; }; }; } + as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -6342,12 +5468,12 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix _ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= - -case `sed -n '/datarootdir/ { +ac_sed_dataroot=' +/datarootdir/ { p q } @@ -6355,36 +5481,37 @@ case `sed -n '/datarootdir/ { /@docdir@/p /@infodir@/p /@localedir@/p -/@mandir@/p -' $ac_file_inputs` in +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF -cat >>$CONFIG_STATUS <<_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; + s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? -cat >>$CONFIG_STATUS <<_ACEOF - sed "$ac_vpsub +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub $extrasub _ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s&@configure_input@&$configure_input&;t t +s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t @@ -6393,21 +5520,24 @@ s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack -" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && - { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&5 -echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&2;} rm -f "$tmp/stdin" case $ac_file in - -) cat "$tmp/out"; rm -f "$tmp/out";; - *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; - esac + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; @@ -6417,11 +5547,13 @@ which seems to be undefined. Please make sure it is defined." >&2;} done # for ac_tag -{ (exit 0); exit 0; } +as_fn_exit 0 _ACEOF -chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save +test $ac_write_fail = 0 || + as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 + # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. @@ -6441,6 +5573,10 @@ if test "$no_create" != yes; then exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. - $ac_cs_success || { (exit 1); exit 1; } + $ac_cs_success || as_fn_exit $? +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi diff --git a/src/configure.ac b/src/configure.ac index 7159bd280..7d8f5a85e 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -96,6 +96,7 @@ AC_CONFIG_FILES([Makefile $make_eldap $make_pam $make_web + stun/Makefile $make_tls $make_odbc $make_ejabberd_zlib]) From 14464ab6ccf89e1806562d2d0627970437afe76d Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 11 Aug 2009 18:24:12 +0000 Subject: [PATCH 495/582] Add support in WebAdmin for the new listener network protocol SVN Revision: 2464 --- src/web/ejabberd_web_admin.erl | 47 ++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 132e49836..a9beaf17d 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -2383,13 +2383,14 @@ node_ports_to_xhtml(Ports, Lang) -> [?XE('tr', [?XCT('td', "Port"), ?XCT('td', "IP"), + ?XCT('td', "Prot"), ?XCT('td', "Module"), ?XCT('td', "Options") ])]), ?XE('tbody', lists:map( fun({PortIP, Module, Opts} = _E) -> - {_Port, SPort, _TIP, SIP, SSPort, OptsClean} = + {_Port, SPort, _TIP, SIP, SSPort, NetProt, OptsClean} = get_port_data(PortIP, Opts), SModule = atom_to_list(Module), {NumLines, SOptsClean} = term_to_paragraph(OptsClean, 40), @@ -2397,6 +2398,7 @@ node_ports_to_xhtml(Ports, Lang) -> ?XE('tr', [?XAE('td', [?XMLATTR('size', <<"6">>)], [?C(SPort)]), ?XAE('td', [?XMLATTR('size', <<"15">>)], [?C(SIP)]), + ?XAE('td', [?XMLATTR('size', <<"4">>)], [?C(atom_to_list(NetProt))]), ?XE('td', [?INPUTS("text", "module" ++ SSPort, SModule, "15")]), ?XE('td', [?TEXTAREA("opts" ++ SSPort, integer_to_list(NumLines), "35", SOptsClean)]), @@ -2410,6 +2412,7 @@ node_ports_to_xhtml(Ports, Lang) -> [?XE('tr', [?XE('td', [?INPUTS("text", "portnew", "", "6")]), ?XE('td', [?INPUTS("text", "ipnew", "0.0.0.0", "15")]), + ?XE("td", [make_netprot_html("tcp")]), ?XE('td', [?INPUTS("text", "modulenew", "", "15")]), ?XE('td', [?TEXTAREA("optsnew", "2", "35", "[]")]), ?XAE('td', [?XMLATTR("colspan", "2")], @@ -2418,25 +2421,38 @@ node_ports_to_xhtml(Ports, Lang) -> )] )]). +make_netprot_html(NetProt) -> + ?XAE('select', [?XMLATTR('name', "netprotnew")], + lists:map( + fun(O) -> + Sel = if + O == NetProt -> [?XMLATTR('selected', <<"selected">>)]; + true -> [] + end, + ?XAC('option', + Sel ++ [?XMLATTR('value', O)], + O) + end, ["tcp", "udp"])). + get_port_data(PortIP, Opts) -> - {Port, IPT, IPS, _IPV, OptsClean} = ejabberd_listener:parse_listener_portip(PortIP, Opts), + {Port, IPT, IPS, _IPV, NetProt, OptsClean} = ejabberd_listener:parse_listener_portip(PortIP, Opts), SPort = io_lib:format("~p", [Port]), SSPort = lists:flatten( lists:map( fun(N) -> io_lib:format("~.16b", [N]) end, - binary_to_list(crypto:md5(SPort++IPS)))), - {Port, SPort, IPT, IPS, SSPort, OptsClean}. + binary_to_list(crypto:md5(SPort++IPS++atom_to_list(NetProt))))), + {Port, SPort, IPT, IPS, SSPort, NetProt, OptsClean}. node_ports_parse_query(Node, Ports, Query) -> lists:foreach( - fun({PortIP, Module1, Opts1}) -> - {Port, _SPort, TIP, _SIP, SSPort, _OptsClean} = - get_port_data(PortIP, Opts1), + fun({PortIpNetp, Module1, Opts1}) -> + {Port, _SPort, TIP, _SIP, SSPort, NetProt, _OptsClean} = + get_port_data(PortIpNetp, Opts1), case lists:keysearch("add" ++ SSPort, 1, Query) of {value, _} -> - PortIP2 = {Port, TIP}, + PortIpNetp2 = {Port, TIP, NetProt}, {{value, {_, SModule}}, {value, {_, SOpts}}} = {lists:keysearch("module" ++ SSPort, 1, Query), lists:keysearch("opts" ++ SSPort, 1, Query)}, @@ -2444,15 +2460,15 @@ node_ports_parse_query(Node, Ports, Query) -> {ok, Tokens, _} = erl_scan:string(SOpts ++ "."), {ok, Opts} = erl_parse:parse_term(Tokens), rpc:call(Node, ejabberd_listener, delete_listener, - [PortIP2, Module1]), + [PortIpNetp2, Module1]), R=rpc:call(Node, ejabberd_listener, add_listener, - [PortIP2, Module, Opts]), + [PortIpNetp2, Module, Opts]), throw({is_added, R}); _ -> case lists:keysearch("delete" ++ SSPort, 1, Query) of {value, _} -> rpc:call(Node, ejabberd_listener, delete_listener, - [PortIP, Module1]), + [PortIpNetp, Module1]), throw(submitted); _ -> ok @@ -2463,10 +2479,12 @@ node_ports_parse_query(Node, Ports, Query) -> {value, _} -> {{value, {_, SPort}}, {value, {_, STIP}}, %% It is a string that may represent a tuple + {value, {_, SNetProt}}, {value, {_, SModule}}, {value, {_, SOpts}}} = {lists:keysearch("portnew", 1, Query), lists:keysearch("ipnew", 1, Query), + lists:keysearch("netprotnew", 1, Query), lists:keysearch("modulenew", 1, Query), lists:keysearch("optsnew", 1, Query)}, {ok, Toks, _} = erl_scan:string(SPort ++ "."), @@ -2477,12 +2495,13 @@ node_ports_parse_query(Node, Ports, Query) -> {error, _} -> STIP end, Module = list_to_atom(SModule), + NetProt2 = list_to_atom(SNetProt), {ok, Tokens, _} = erl_scan:string(SOpts ++ "."), {ok, Opts} = erl_parse:parse_term(Tokens), - {Port2, _SPort, IP2, _SIP, _SSPort, OptsClean} = - get_port_data({Port2, STIP2}, Opts), + {Port2, _SPort, IP2, _SIP, _SSPort, NetProt2, OptsClean} = + get_port_data({Port2, STIP2, NetProt2}, Opts), R=rpc:call(Node, ejabberd_listener, add_listener, - [{Port2, IP2}, Module, OptsClean]), + [{Port2, IP2, NetProt2}, Module, OptsClean]), throw({is_added, R}); _ -> ok From 2c25db28c488cb0d7d79014e448350994fc2464d Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 12 Aug 2009 14:18:47 +0000 Subject: [PATCH 496/582] Describe the options syntax, not only the name (EJAB-998) SVN Revision: 2473 --- doc/dev.html | 2 +- doc/features.html | 2 +- doc/guide.html | 960 ++++++++++++++++++++++------------------------ doc/guide.tex | 584 +++++++++++++--------------- 4 files changed, 728 insertions(+), 820 deletions(-) diff --git a/doc/dev.html b/doc/dev.html index ef50b169b..9b001d924 100644 --- a/doc/dev.html +++ b/doc/dev.html @@ -84,7 +84,7 @@ Kevin Smith, Current maintainer of the Psi project +

      ejabberd is a free and open source instant messaging server written in Erlang/OTP.

      ejabberd is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.

      ejabberd is designed to be a rock-solid and feature rich XMPP server.

      ejabberd is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.

      1  Key Features

      ejabberd is: diff --git a/doc/features.html b/doc/features.html index 04487a14f..e751b7c7b 100644 --- a/doc/features.html +++ b/doc/features.html @@ -61,7 +61,7 @@ SPAN{width:20%; float:right; text-align:left; margin-left:auto;}

      I can thoroughly recommend ejabberd for ease of setup – Kevin Smith, Current maintainer of the Psi project

      Introduction

      I just tried out ejabberd and was impressed both by ejabberd itself and the language it is written in, Erlang. — -Joeri

      ejabberd is a free and open source instant messaging server written in Erlang.

      ejabberd is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.

      ejabberd is designed to be a rock-solid and feature rich XMPP server.

      ejabberd is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.

      +Joeri

      ejabberd is a free and open source instant messaging server written in Erlang/OTP.

      ejabberd is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.

      ejabberd is designed to be a rock-solid and feature rich XMPP server.

      ejabberd is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.

      Key Features

      Erlang seems to be tailor-made for writing stable, robust servers. — diff --git a/doc/guide.html b/doc/guide.html index 4770c5308..e360d7628 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -6,7 +6,7 @@ - ejabberd 2.1.0-alpha + ejabberd 3.0.0-alpha Installation and Operation Guide @@ -76,7 +76,7 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}


      - +
      ejabberd 2.1.0-alpha
      ejabberd 3.0.0-alpha
       
      Installation and Operation Guide

      @@ -124,45 +124,45 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}
    • 3.1.6  Shapers
    • 3.1.7  Default Language
    • 3.1.8  CAPTCHA -
    • 3.1.9  Include Additional Configuration Files -
    • 3.1.10  Option Macros in Configuration File +
    • 3.1.9  STUN +
    • 3.1.10  Include Additional Configuration Files +
    • 3.1.11  Option Macros in Configuration File
    -
  • 3.2  Database and LDAP Configuration +
  • 3.2  Database and LDAP Configuration -
  • 3.3  Modules Configuration +
  • 3.3  Modules Configuration
  • Chapter 4  Managing an ejabberd Server @@ -218,7 +218,7 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}
  • Appendix D  Copyright Information
  • Chapter 1  Introduction

    -

    ejabberd is a free and open source instant messaging server written in Erlang.

    ejabberd is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.

    ejabberd is designed to be a rock-solid and feature rich XMPP server.

    ejabberd is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.

    +

    ejabberd is a free and open source instant messaging server written in Erlang/OTP.

    ejabberd is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.

    ejabberd is designed to be a rock-solid and feature rich XMPP server.

    ejabberd is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.

    1.1  Key Features

    ejabberd is: @@ -269,13 +269,12 @@ Internal Authentication.

  • Others
  • @@ -338,16 +337,14 @@ as long as your system have all the dependencies.

    2.4.2  Download Source Code

    Released versions of ejabberd are available in the ProcessOne ejabberd downloads page: @@ -462,31 +459,25 @@ for example:

    Requirements

    To compile ejabberd on a Microsoft Windows system, you need:

    Compilation

    We assume that we will try to put as much library as possible into C:\sdk\ to make it easier to track what is install for ejabberd.

    1. -Install Erlang emulator (for example, into C:\sdk\erl5.5.5). +Install Erlang emulator (for example, into C:\sdk\erl5.6.5).
    2. Install Expat library into C:\sdk\Expat-2.0.0 directory.

      Copy file C:\sdk\Expat-2.0.0\Libs\libexpat.dll to your Windows system directory (for example, C:\WINNT or C:\WINNT\System32) -

    3. Build and install the Iconv library into the directory -C:\sdk\GnuWin32.

      Copy file C:\sdk\GnuWin32\bin\lib*.dll to your -Windows system directory (more installation instructions can be found in the -file README.woe32 in the iconv distribution).

      Note: instead of copying libexpat.dll and iconv.dll to the Windows -directory, you can add the directories -C:\sdk\Expat-2.0.0\Libs and -C:\sdk\GnuWin32\bin to the PATH environment -variable. +Note: instead of copying libexpat.dll to the Windows +directory, you can add the directory C:\sdk\Expat-2.0.0\Libs +to the PATH environment variable.

    4. Install OpenSSL in C:\sdk\OpenSSL and add C:\sdk\OpenSSL\lib\VC to your path or copy the binaries to your system directory.
    5. Install ZLib in C:\sdk\gnuWin32. Copy -C:\sdk\GnuWin32\bin\zlib1.dll to your system directory. If you change your path it should already be set after libiconv install. +C:\sdk\GnuWin32\bin\zlib1.dll to your system directory.
    6. Make sure the you can access Erlang binaries from your path. For example: set PATH=%PATH%;"C:\sdk\erl5.6.5\bin"
    7. Depending on how you end up actually installing the library you might need to check and tweak the paths in the file configure.erl.
    8. While in the directory ejabberd\src run: @@ -503,7 +494,7 @@ There are two ways to register a Jabber account:
      1. Using ejabberdctl (see section 4.1):
        ejabberdctl register admin1 example.org FgT5bk3
        -
      2. Using a Jabber client and In-Band Registration (see section 3.3.18). +
      3. Using a Jabber client and In-Band Registration (see section 3.3.17).
    9. Edit the ejabberd configuration file to give administration rights to the Jabber account you created:
      {acl, admins, {user, "admin1", "example.org"}}.
      @@ -537,7 +528,7 @@ edit the configuration file, or remove all its content.

      The configuration the name of an option, and any further elements are that option’s values. If the configuration file do not contain for instance the ‘hosts’ option, the old host name(s) stored in the database will be used.

      You can override the old values stored in the database by adding next lines to -the configuration file: +the beginning of the configuration file:

      override_global.
       override_local.
       override_acls.
      @@ -546,22 +537,18 @@ cluster), local options (which are specific for this particular ejabberd

      3.1.1  Host Names

      The option hosts defines a list containing one or more domains that -ejabberd will serve.

      Examples: +ejabberd will serve.

      The syntax is: +

      {hosts, [HostName, ...]}.

      Examples:

      • Serving one domain:
        {hosts, ["example.org"]}.
        -
      • Serving one domain, and backwards compatible with older ejabberd -versions: -
        {host, "example.org"}.
        -
      • Serving two domains: -
        {hosts, ["example.net", "example.com"]}.
        +
      • Serving three domains: +
        {hosts, ["example.net", "example.com", "jabber.somesite.org"]}.
         

      3.1.2  Virtual Hosting

      Options can be defined separately for every virtual host using the -host_config option. It has the following -syntax: -

      {host_config, <hostname>, [<option>, <option>, ...]}.
      -

      Examples: +host_config option.

      The syntax is: +

      {host_config, HostName, [Option, ...]}

      Examples:

      • Domain example.net is using the internal authentication method while domain example.com is using the LDAP server running on the @@ -589,11 +576,10 @@ while domain example.com is using the LDAP servers running on the domai
    10. To define specific ejabberd modules in a virtual host, you can define the global modules option with the common modules, and later add specific modules to certain virtual hosts. -To accomplish that, instead of defining each option in host_config with the syntax -

      {<option-name>, <option-value>}
      -

      use this syntax: -

      {{add, <option-name>}, <option-value>}
      -

      In this example three virtual hosts have some similar modules, but there are also +To accomplish that, instead of defining each option in host_config with the general syntax +

      {OptionName, OptionValue}

      +use this syntax: +

      {{add, OptionName}, OptionValue}

      In this example three virtual hosts have some similar modules, but there are also other different modules for some specific virtual hosts:

      %% This ejabberd server has three vhosts:
       {hosts, ["one.example.org", "two.example.org", "three.example.org"]}.
      @@ -629,31 +615,25 @@ other different modules for some specific virtual hosts:
        ]}.
       

      3.1.3  Listening Ports

      -

      The option listen defines for which addresses and ports ejabberd +

      The option listen defines for which ports, addresses and network protocols ejabberd will listen and what services will be run on them. Each element of the list is a tuple with the following elements:

      • -Port number. Optionally also the IP address. +Port number. Optionally also the IP address and/or a transport protocol.
      • Listening module that serves this port.
      • Options for the TCP socket and for the listening module. -

      With the basic syntax the ports will listen on all IPv4 network addresses: -

      {listen, [
      -          {<port-number>, <module>, [<options>]},
      -          {<port-number>, <module>, [<options>]},
      -          ...
      -          {<port-number>, <module>, [<options>]}
      -         ]}.
      -

      It is possible to specify the IP address for a port using the full syntax: -

                {{<port-number>, <ip-address>}, <module>, [<options>]}
      -

      -

      Port Number and IP Address

      The port number defines which port to listen for incoming connections. +

      The option syntax is: +

      {listen, [Listener, ...]}.

      To define a listener there are several syntax. +

      {PortNumber, Module, [Option, ...]}
      {{PortNumber, IPaddress}, Module, [Option, ...]}
      {{PortNumber, TransportProtocol}, Module, [Option, ...]}
      {{PortNumber, IPaddress, TransportProtocol}, Module, [Option, ...]}

      +

      Port Number, IP Address and Transport Protocol

      The port number defines which port to listen for incoming connections. It can be a Jabber/XMPP standard port (see section 5.1) or any other valid port number.

      The IP address can be represented with a string or an Erlang tuple with decimal or hexadecimal numbers. The socket will listen only in that network interface. It is possible to specify a generic address, so ejabberd will listen in all addresses. -Depending in the type of the IP address, IPv4 or IPv6 will be used.

      Some example values for IP address: +Depending in the type of the IP address, IPv4 or IPv6 will be used. +When not specified the IP address, it will listen on all IPv4 network addresses.

      Some example values for IP address:

      • "0.0.0.0" to listen in all IPv4 network interfaces. This is the default value when no IP is specified.
      • "::" to listen in all IPv6 network interfaces @@ -662,7 +642,8 @@ Depending in the type of the IP address, IPv4 or IPv6 will be used.

        Some e

      • {10, 11, 12, 13} is the IPv4 address 10.11.12.13
      • {0, 0, 0, 0, 0, 65535, 32512, 1} is the IPv6 address ::FFFF:127.0.0.1/128
      • {16#fdca, 16#8ab6, 16#a243, 16#75ef, 0, 0, 0, 1} is the IPv6 address FDCA:8AB6:A243:75EF::1/128 -

      +

      The transport protocol can be tcp or udp. +Default is tcp.

      Listening Module

      The available modules, their purpose and the options allowed by each one are:

      @@ -677,9 +658,13 @@ Handles incoming s2s connections.
      Options: max_stanza_size
      ejabberd_service
      Interacts with an external component -(as defined in the Jabber Component Protocol (XEP-0114).
      +(as defined in the Jabber Component Protocol (XEP-0114).
      Options: access, hosts, shaper, service_check_from +
      ejabberd_stun
      +Handles STUN Binding requests as defined in +RFC 5389.
      + Options: certfile
      ejabberd_http
      Handles incoming HTTP connections.
      Options: captcha, certfile, http_bind, http_poll, @@ -687,19 +672,19 @@ Handles incoming HTTP connections.

      Options

      This is a detailed description of each option allowed by the listening modules:

      -{access, <access rule>}
      This option defines +{access, AccessName}
    This option defines access to the port. The default value is all.
    {certfile, Path}
    Full path to a file containing the default SSL certificate. To define a certificate file specific for a given domain, use the global option domain_certfile. -
    service_check_from
    +
    {service_check_from, true|false}
    This option can be used with ejabberd_service only. It is used to disable control on the from field on packets send by an external components. The option can be either true or -false. The default value is true which conforms to XEP-0114. -
    {hosts, [Hostnames], [HostOptions]}
    +false. The default value is true which conforms to XEP-0114. +
    {hosts, [Hostname, ...], [HostOption, ...]}
    The external Jabber component that connects to this ejabberd_service can serve one or more hostnames. -In HostOptions you can define options for the component; +As HostOption you can define options for the component; currently the only allowed option is the password required to the component when attempt to connect to ejabberd: {password, Secret}. Note that you cannot define in a single ejabberd_service components of @@ -708,7 +693,7 @@ as seen in an example below.
    captcha
    Simple web page that allows a user to fill a CAPTCHA challenge (see section 3.1.8).
    http_bind
    -This option enables HTTP Binding (XEP-0124 and XEP-0206) support. HTTP Bind +This option enables HTTP Binding (XEP-0124 and XEP-0206) support. HTTP Bind enables access via HTTP requests to ejabberd from behind firewalls which do not allow outgoing sockets on port 5222.

    Remember that you must also install and enable the module mod_http_bind.

    If HTTP Bind is enabled, it will be available at http://server:port/http-bind/. Be aware that support for HTTP Bind @@ -719,7 +704,7 @@ interesting to host a web-based Jabber client such as embedded local web server or Apache).

    http_poll
    -This option enables HTTP Polling (XEP-0025) support. HTTP Polling +This option enables HTTP Polling (XEP-0025) support. HTTP Polling enables access via HTTP requests to ejabberd from behind firewalls which do not allow outgoing sockets on port 5222.

    If HTTP Polling is enabled, it will be available at http://server:port/http-poll/. Be aware that support for HTTP Polling @@ -738,17 +723,17 @@ value is infinity. Recommended values are 65536 for c2s connections and 131072 for s2s connections. s2s max stanza size must always much higher than c2s limit. Change this value with extreme care as it can cause unwanted disconnect if set too low. -

    {request_handlers, [{Path, Module}]}
    To define one or several handlers that will serve HTTP requests. +
    {request_handlers, [ {Path, Module}, ...]}
    To define one or several handlers that will serve HTTP requests. The Path is a list of strings; so the URIs that start with that Path will be served by Module. For example, if you want mod_foo to serve the URIs that start with /a/b/, and you also want mod_http_bind to serve the URIs /http-bind/, use this option: {request_handlers, [{["a", "b"], mod_foo}, {["http-bind"], mod_http_bind}]}
    {service_check_from, true|false}
    By enabling this option, ejabberd allows the component to send packets with any arbitrary domain in the ’from’ attribute. -Note that XEP-0114 requires that the domain must match the hostname of the component. +Note that XEP-0114 requires that the domain must match the hostname of the component. Only enable this option if you are completely sure you need to enable it. Default value: false. -
    {shaper, <access rule>}
    This option defines a +
    {shaper, none|ShaperName}
    This option defines a shaper for the port (see section 3.1.6). The default value is none.
    starttls
    This option @@ -766,7 +751,7 @@ This was the traditional encryption method in the early Jabber software, commonly on port 5223 for client-to-server communications. But this method is nowadays deprecated and not recommended. The preferable encryption method is STARTTLS on port 5222, as defined -RFC 3920: XMPP Core, +RFC 3920: XMPP Core, which can be enabled in ejabberd with the option starttls. If this option is set, you should also set the certfile option.
    web_admin
    This option @@ -775,7 +760,7 @@ at http://server:port/admin/. Login and password are the username a password of one of the registered users who are granted access by the ‘configure’ access rule.
    zlib
    This -option specifies that Zlib stream compression (as defined in XEP-0138) +option specifies that Zlib stream compression (as defined in XEP-0138) is available on connections to the port. Client connections cannot use stream compression and stream encryption simultaneously. Hence, if you specify both starttls (or tls) and zlib, the latter @@ -793,7 +778,7 @@ Full path to the file containing the SSL certificate for a specific domain. Specify which address families to try, in what order, and connect timeout in milliseconds. By default it first tries connecting with IPv4, if that fails it tries using IPv6, with a timeout of 10000 milliseconds. -
    {s2s_dns_options, [{Property, Value}]}
    +
    {s2s_dns_options, [ {Property, Value}, ...]}
    Define properties to use for DNS resolving. Allowed Properties are: timeout in seconds which default value is 10 and retries which default value is 2. @@ -816,6 +801,7 @@ However, the c2s and s2s connections to the domain example.com use the and also allows plain connections for old clients.
  • Port 5223 listens for c2s connections with the old SSL.
  • Port 5269 listens for s2s connections with STARTTLS. The socket is set for IPv6 instead of IPv4. +
  • Port 3478 listens for STUN requests over UDP.
  • Port 5280 listens for HTTP requests, and serves the HTTP Poll service.
  • Port 5281 listens for HTTP requests, and serves the Web Admin using HTTPS as explained in section 4.3. The socket only listens connections to the IP address 127.0.0.1. @@ -838,6 +824,7 @@ section 4.3. The socket only listens connections to {shaper, s2s_shaper}, {max_stanza_size, 131072} ]}, + {{3478, udp}, ejabberd_stun, []}, {5280, ejabberd_http, [ http_poll ]}, @@ -972,10 +959,9 @@ you have to make the transports log and do XDB by themselves: </xdb>

    3.1.4  Authentication

    -

    The option auth_method defines the authentication method that is used -for user authentication: -

    {auth_method, [<method>]}.
    -

    The following authentication methods are supported by ejabberd: +

    The option auth_method defines the authentication methods that are used +for user authentication. The syntax is: +

    {auth_method, [Method, ...]}.

    The following authentication methods are supported by ejabberd:

    Account creation is only supported by internal and odbc methods.

    Internal

    -

    ejabberd uses its internal Mnesia database as the default authentication method.

    • -auth_method: The value internal will enable the internal -authentication method. -

    Examples: +

    ejabberd uses its internal Mnesia database as the default authentication method. +The value internal will enable the internal authentication method.

    Examples:

    • To use internal authentication on example.org and LDAP authentication on example.net: @@ -1000,25 +984,23 @@ authentication on example.net:
      {auth_method, internal}.
       

    SASL Anonymous and Anonymous Login

    -

    The anonymous authentication method can be configured with the following +

    The value anonymous will enable the internal authentication method.

    The anonymous authentication method can be configured with the following options. Remember that you can use the host_config option to set virtual host specific options (see section 3.1.2). Note that there also is a detailed tutorial regarding SASL -Anonymous and anonymous login configuration.

    • -auth_method: The value anonymous will enable the anonymous -authentication method. -
    • allow_multiple_connections: This value for this option can be -either true or false and is only used when the anonymous mode is +Anonymous and anonymous login configuration.

      +{allow_multiple_connections, false|true}
      This option is only used +when the anonymous mode is enabled. Setting it to true means that the same username can be taken multiple times in anonymous login mode if different resource are used to connect. This option is only useful in very special occasions. The default value is false. -
    • anonymous_protocol: This option can take three values: -sasl_anon, login_anon or both. sasl_anon means +
  • {anonymous_protocol, sasl_anon | login_anon | both}
    +sasl_anon means that the SASL Anonymous method will be used. login_anon means that the anonymous login method will be used. both means that SASL Anonymous and login anonymous are both enabled. -

    Those options are defined for each virtual host with the host_config +

    Those options are defined for each virtual host with the host_config parameter (see section 3.1.2).

    Examples:

    • To enable anonymous login on all virtual hosts: @@ -1049,7 +1031,7 @@ PAM authentication is disabled by default, so you have to configure and compile

      ./configure --enable-pam && make install
       

      Options:

      -pam_service
      This option defines the PAM service name. +{pam_service, Name}
    This option defines the PAM service name. Default is "ejabberd". Refer to the PAM documentation of your operation system for more information.

    Example: @@ -1091,48 +1073,47 @@ then /etc/nssswitch.conf must be configured to use winbind as

    ACL Definition

    Access control in ejabberd is performed via Access Control Lists (ACLs). The declarations of ACLs in the configuration file have the following syntax: -

    {acl, <aclname>, {<acltype>, ...}}.
    -

    <acltype> can be one of the following: +

    {acl, ACLName, ACLValue}.

    ACLValue can be one of the following:

    all
    Matches all JIDs. Example:
    {acl, all, all}.
    -
    {user, <username>}
    Matches the user with the name -<username> at the first virtual host. Example: +
    {user, Username}
    Matches the user with the name +Username at the first virtual host. Example:
    {acl, admin, {user, "yozhik"}}.
    -
    {user, <username>, <server>}
    Matches the user with the JID -<username>@<server> and any resource. Example: +
    {user, Username, Server}
    Matches the user with the JID +Username@Server and any resource. Example:
    {acl, admin, {user, "yozhik", "example.org"}}.
    -
    {server, <server>}
    Matches any JID from server -<server>. Example: +
    {server, Server}
    Matches any JID from server +Server. Example:
    {acl, exampleorg, {server, "example.org"}}.
    -
    {resource, <resource>}
    Matches any JID with a resource -<resource>. Example: +
    {resource, Resource}
    Matches any JID with a resource +Resource. Example:
    {acl, mucklres, {resource, "muckl"}}.
    -
    {shared_group, <groupname>}
    Matches any member of a Shared Roster Group with name <groupname> in the virtual host. Example: +
    {shared_group, Groupname}
    Matches any member of a Shared Roster Group with name Groupname in the virtual host. Example:
    {acl, techgroupmembers, {shared_group, "techteam"}}.
    -
    {shared_group, <groupname>, <server>}
    Matches any member of a Shared Roster Group with name <groupname> in the virtual host <server>. Example: +
    {shared_group, Groupname, Server}
    Matches any member of a Shared Roster Group with name Groupname in the virtual host Server. Example:
    {acl, techgroupmembers, {shared_group, "techteam", "example.org"}}.
    -
    {user_regexp, <regexp>}
    Matches any local user with a name that -matches <regexp> on local virtual hosts. Example: +
    {user_regexp, Regexp}
    Matches any local user with a name that +matches Regexp on local virtual hosts. Example:
    {acl, tests, {user_regexp, "^test[0-9]*$"}}.
    -
    {user_regexp, <regexp>, <server>}
    Matches any user with a name -that matches <regexp> at server <server>. Example: -
    {acl, tests, {user_regexp, "^test", "example.org"}}.
    -
    {server_regexp, <regexp>}
    Matches any JID from the server that -matches <regexp>. Example: +
    {user_regexp, UserRegexp, Server}
    Matches any user with a name +that matches Regexp at server Server. Example: +
    {acl, tests, {user_Userregexp, "^test", "example.org"}}.
    +
    {server_regexp, Regexp}
    Matches any JID from the server that +matches Regexp. Example:
    {acl, icq, {server_regexp, "^icq\\."}}.
    -
    {resource_regexp, <regexp>}
    Matches any JID with a resource that -matches <regexp>. Example: +
    {resource_regexp, Regexp}
    Matches any JID with a resource that +matches Regexp. Example:
    {acl, icq, {resource_regexp, "^laptop\\."}}.
    -
    {node_regexp, <user_regexp>, <server_regexp>}
    Matches any user -with a name that matches <user_regexp> at any server that matches -<server_regexp>. Example: +
    {node_regexp, UserRegexp, ServerRegexp}
    Matches any user +with a name that matches UserRegexp at any server that matches +ServerRegexp. Example:
    {acl, yohzik, {node_regexp, "^yohzik$", "^example.(com|org)$"}}.
    -
    {user_glob, <glob>}
    -
    {user_glob, <glob>, <server>}
    -
    {server_glob, <glob>}
    -
    {resource_glob, <glob>}
    -
    {node_glob, <user_glob>, <server_glob>}
    This is the same as +
    {user_glob, Glob}
    +
    {user_glob, Glob, Server}
    +
    {server_glob, Glob}
    +
    {resource_glob, Glob}
    +
    {node_glob, UserGlob, ServerGlob}
    This is the same as above. However, it uses shell glob patterns instead of regexp. These patterns can have the following special characters:
    @@ -1143,19 +1124,15 @@ ranges are specified by a pair of characters separated by a ‘-’ If the first character after ‘[’ is a ‘!’, any character not enclosed is matched.
    -

    The following ACLs are pre-defined: +

    The following ACLName are pre-defined:

    all
    Matches any JID.
    none
    Matches no JID.

    Access Rights

    -

    An entry allowing or denying access to different services looks similar to -this: -

    {access, <accessname>, [{allow, <aclname>},
    -                        {deny, <aclname>},
    -                        ...
    -                       ]}.
    -

    When a JID is checked to have access to <accessname>, the server +

    An entry allowing or denying access to different services. +The syntax is: +

    {access, AccessName, [ {allow|deny, ACLName}, ...]}.

    When a JID is checked to have access to Accessname, the server sequentially checks if that JID matches any of the ACLs that are named in the second elements of the tuples in the list. If it matches, the first element of the first matched tuple is returned, otherwise the value ‘deny’ is @@ -1163,7 +1140,7 @@ returned.

    Example:

    {access, configure, [{allow, admin}]}.
     {access, something, [{deny, badmans},
                          {allow, all}]}.
    -

    The following access rules are pre-defined: +

    The following AccessName are pre-defined:

    all
    Always returns the value ‘allow’.
    none
    Always returns the value ‘deny’. @@ -1176,35 +1153,27 @@ opened session will be disconnected. The error session replaced will be sent to the disconnected session. The value for this option can be either a number, or infinity. The default value is infinity.

    The syntax is: -

    {access, max_user_sessions, [{<maxnumber>, <aclname>},
    -                             ...
    -                            ]}.
    -

    Examples: -

    • -To limit the number of sessions per user to 10 for all users: -
      {access, max_user_sessions, [{10, all}]}.
      -

    +

    {access, max_user_sessions, [ {MaxNumber, ACLName}, ...]}.

    This example limits the number of sessions per user to 5 for all users, and to 10 for admins: +

    {access, max_user_sessions, [{10, admin}, {5, all}]}.
    +

    Several connections to a remote Jabber server with ACL

    The special access max_s2s_connections specifies how many simultaneus S2S connections can be established to a specific remote Jabber server. The default value is 1. There’s also available the access max_s2s_connections_per_node.

    The syntax is: -

    {access, max_s2s_connections, [{<maxnumber>, <aclname>},
    -                               ...
    -                              ]}.
    -

    Examples: +

    {access, max_s2s_connections, [ {MaxNumber, ACLName}, ...]}.

    Examples:

    • Allow up to 3 connections with each remote server:
      {access, max_s2s_connections, [{3, all}]}.
       

    3.1.6  Shapers

    -

    Shapers enable you to limit connection traffic. The syntax of -shapers is like this: -

    {shaper, <shapername>, <kind>}.
    -

    Currently only one kind of shaper called maxrate is available. It has the +

    Shapers enable you to limit connection traffic. +The syntax is: +

    {shaper, ShaperName, Kind}.

    +Currently only one kind of shaper called maxrate is available. It has the following syntax: -

    {maxrate, <rate>}
    -

    where <rate> stands for the maximum allowed incoming rate in bytes per +

    {maxrate, Rate}

    +where Rate stands for the maximum allowed incoming rate in bytes per second. When a connection exceeds this limit, ejabberd stops reading from the socket until the average rate is again below the allowed maximum.

    Examples: @@ -1219,14 +1188,15 @@ To define a shaper named ‘normal’ with traffic speed limi

    3.1.7  Default Language

    The option language defines the default language of server strings that can be seen by Jabber clients. If a Jabber client does not support -xml:lang, the specified language is used. The default value is -en. In order to take effect there must be a translation file -<language>.msg in ejabberd’s msgs directory.

    For example, to set Russian as default language: +xml:lang, the specified language is used.

    The option syntax is: +

    {language, Language}.

    The default value is en. +In order to take effect there must be a translation file +Language.msg in ejabberd’s msgs directory.

    For example, to set Russian as default language:

    {language, "ru"}.
     

    Appendix A provides more details about internationalization and localization.

    3.1.8  CAPTCHA

    Some ejabberd modules can be configured to require a CAPTCHA challenge on certain actions. -If the client does not support CAPTCHA Forms (XEP-0158), +If the client does not support CAPTCHA Forms (XEP-0158), a web link is provided so the user can fill the challenge in a web browser.

    An example script is provided that generates the image using ImageMagick’s Convert program.

    The configurable options are:

    @@ -1255,21 +1225,47 @@ See section 3.1.3.

    Example configuration: } ]}. +

    +

    3.1.9  STUN

    +

    ejabberd is able to act as a stand-alone STUN server +(RFC 5389). Currently only Binding usage +is supported. In that role ejabberd helps clients with Jingle ICE (XEP-0176) support to discover their external addresses and ports.

    You should configure ejabberd_stun listening module as described in 3.1.3 section. +If certfile option is defined, ejabberd multiplexes TCP and +TLS over TCP connections on the same port. Obviously, certfile option +is defined for tcp only. Note however that TCP or TLS over TCP +support is not required for Binding usage and is reserved for +TURN +functionality. Feel free to configure udp transport only.

    Example configuration: +

    {listen,
    + [
    +  ...
    +  {{3478, udp}, ejabberd_stun, []},
    +  {3478, ejabberd_stun, []},
    +  {5349, ejabberd_stun, [{certfile, "/etc/ejabberd/server.pem"}]},
    +  ...
    + ]
    +}.
    +

    You also need to configure DNS SRV records properly so clients can easily discover a +STUN server serving your XMPP domain. Refer to section +DNS Discovery of a Server +of RFC 5389 for details.

    Example DNS SRV configuration: +

    _stun._udp   IN SRV  0 0 3478 stun.example.com.
    +_stun._tcp   IN SRV  0 0 3478 stun.example.com.
    +_stuns._tcp  IN SRV  0 0 5349 stun.example.com.
     

    -

    3.1.9  Include Additional Configuration Files

    -

    The option include_config_file in a configuration file instructs ejabberd to include other configuration files immediately.

    The basic usage is: -

    {include_config_file, <filename>}.
    -

    It is also possible to specify suboptions: -

    {include_config_file, <filename>, [<suboption>, <suboption>, ...]}.
    -

    The filename can be indicated either as an absolute path, +

    3.1.10  Include Additional Configuration Files

    +

    The option include_config_file in a configuration file instructs ejabberd to include other configuration files immediately.

    The basic syntax is: +

    {include_config_file, Filename}.

    +It is possible to specify suboptions using the full syntax: +

    {include_config_file, Filename, [Suboption, ...]}.

    The filename can be indicated either as an absolute path, or relative to the main ejabberd configuration file. It isn’t possible to use wildcards. The file must exist and be readable.

    The allowed suboptions are:

    -{disallow, [<option>, <option>, ...]}
    Disallows the usage of those options in the included configuration file. +{disallow, [Optionname, ...]}
    Disallows the usage of those options in the included configuration file. The options that match this criteria are not accepted. The default value is an empty list: [] -
    {allow_only, [<option>, <option>, ...]}
    Allows only the usage of those options in the included configuration file. +
    {allow_only, [Optionname, ...]}
    Allows only the usage of those options in the included configuration file. The options that do not match this criteria are not accepted. The default value is: all

    This is a basic example: @@ -1287,12 +1283,12 @@ and later includes another file with additional rules:

    {acl, admin, {user, "bob", "localhost"}}.
     {acl, admin, {user, "jan", "localhost"}}.
     

    -

    3.1.10  Option Macros in Configuration File

    +

    3.1.11  Option Macros in Configuration File

    In the ejabberd configuration file, it is possible to define a macro for a value and later use this macro when defining an option.

    A macro is defined with this syntax: -

    {define_macro, '<MACRO>', <value>}.
    -

    The MACRO must be surrounded by single quotation marks, +

    {define_macro, ’MACRO’, Value}.

    +The MACRO must be surrounded by single quotation marks, and all letters in uppercase; check the examples bellow. The value can be any valid arbitrary Erlang term.

    The first definition of a macro is preserved, and additional definitions of the same macro are forgotten.

    Macros are processed after @@ -1300,17 +1296,17 @@ additional configuration files have been included, so it is possible to use macros that are defined in configuration files included before the usage.

    It isn’t possible to use a macro in the definition of another macro.

    There are two ways to use a macro: -

    ’<MACRO>’
    +

    ’MACRO’
    You can put this instead of a value in an ejabberd option, and will be replaced with the value previously defined. If the macro is not defined previously, -the program will crash and report an error.
    {use_macro, ’<MACRO>’, <defaultvalue>}
    +the program will crash and report an error.
    {use_macro, ’MACRO’, Defaultvalue}
    Use a macro even if it may not be defined. If the macro is not defined previously, the provided defaultvalue is used. This usage behaves as if it were defined and used this way: -
    {define_macro, '<MACRO>', <defaultvalue>}.
    -'<MACRO>'
    +
    {define_macro, 'MACRO', Defaultvalue}.
    +'MACRO'
     

    This example shows the basic usage of a macro:

    {define_macro, 'LOG_LEVEL_NUMBER', 5}.
     {loglevel, 'LOG_LEVEL_NUMBER'}.
    @@ -1336,7 +1332,7 @@ This usage behaves as if it were defined and used this way:
      ]
     }.
     

    -

    3.2  Database and LDAP Configuration

    +

    3.2  Database and LDAP Configuration

    ejabberd uses its internal Mnesia database by default. However, it is possible to use a relational database or an LDAP server to store persistent, @@ -1369,7 +1365,7 @@ For example: {auth_method, [odbc]} ]}.

    -

    3.2.1  MySQL

    +

    3.2.1  MySQL

    Although this section will describe ejabberd’s configuration when you want to use the native MySQL driver, it does not describe MySQL’s installation and database creation. Check the MySQL documentation and the tutorial Using ejabberd with MySQL native driver for information regarding these topics. @@ -1393,17 +1389,13 @@ commands: value is used to define if we want to use ODBC, or one of the two native interface available, PostgreSQL or MySQL.

    To use the native MySQL interface, you can pass a tuple of the following form as parameter: -

    {mysql, "Server", "Database", "Username", "Password"}
    -

    mysql is a keyword that should be kept as is. For example: -

    {odbc_server, {mysql, "localhost", "test", "root", "password"}}.
    -

    Optionally, it is possible to define the MySQL port to use. This +

    {mysql, "Server", "Database", "Username", "Password"}

    mysql is a keyword that should be kept as is. For example: +

    {odbc_server, {mysql, "localhost", "test", "root", "password"}}.

    Optionally, it is possible to define the MySQL port to use. This option is only useful, in very rare cases, when you are not running MySQL with the default port setting. The mysql parameter can thus take the following form: -

    {mysql, "Server", Port, "Database", "Username", "Password"}
    -

    The Port value should be an integer, without quotes. For example: -

    {odbc_server, {mysql, "localhost", Port, "test", "root", "password"}}.
    -

    By default ejabberd opens 10 connections to the database for each virtual host. +

    {mysql, "Server", Port, "Database", "Username", "Password"}

    The Port value should be an integer, without quotes. For example: +

    {odbc_server, {mysql, "localhost", Port, "test", "root", "password"}}.

    By default ejabberd opens 10 connections to the database for each virtual host. Use this option to modify the value:

    {odbc_pool_size, 10}.
     

    You can configure an interval to make a dummy SQL request @@ -1430,7 +1422,7 @@ relational databases like MySQL. To enable storage to your database, just make sure that your database is running well (see previous sections), and replace the suffix-less or ldap module variant with the odbc module variant. Keep in mind that you cannot have several variants of the same module loaded!

    -

    3.2.2  Microsoft SQL Server

    +

    3.2.2  Microsoft SQL Server

    Although this section will describe ejabberd’s configuration when you want to use Microsoft SQL Server, it does not describe Microsoft SQL Server’s installation and database creation. Check the MySQL documentation and the @@ -1468,7 +1460,7 @@ database, just make sure that your database is running well (see previous sections), and replace the suffix-less or ldap module variant with the odbc module variant. Keep in mind that you cannot have several variants of the same module loaded!

    -

    3.2.3  PostgreSQL

    +

    3.2.3  PostgreSQL

    Although this section will describe ejabberd’s configuration when you want to use the native PostgreSQL driver, it does not describe PostgreSQL’s installation and database creation. Check the PostgreSQL documentation and the tutorial Using ejabberd with MySQL native driver for information regarding these topics. @@ -1495,17 +1487,13 @@ using next commands: value is used to define if we want to use ODBC, or one of the two native interface available, PostgreSQL or MySQL.

    To use the native PostgreSQL interface, you can pass a tuple of the following form as parameter: -

    {pgsql, "Server", "Database", "Username", "Password"}
    -

    pgsql is a keyword that should be kept as is. For example: -

    {odbc_server, {pgsql, "localhost", "database", "ejabberd", "password"}}.
    -

    Optionally, it is possible to define the PostgreSQL port to use. This +

    {pgsql, "Server", "Database", "Username", "Password"}

    pgsql is a keyword that should be kept as is. For example: +

    {odbc_server, {pgsql, "localhost", "database", "ejabberd", "password"}}.

    Optionally, it is possible to define the PostgreSQL port to use. This option is only useful, in very rare cases, when you are not running PostgreSQL with the default port setting. The pgsql parameter can thus take the following form: -

    {pgsql, "Server", Port, "Database", "Username", "Password"}
    -

    The Port value should be an integer, without quotes. For example: -

    {odbc_server, {pgsql, "localhost", 5432, "database", "ejabberd", "password"}}.
    -

    By default ejabberd opens 10 connections to the database for each virtual host. +

    {pgsql, "Server", Port, "Database", "Username", "Password"}

    The Port value should be an integer, without quotes. For example: +

    {odbc_server, {pgsql, "localhost", 5432, "database", "ejabberd", "password"}}.

    By default ejabberd opens 10 connections to the database for each virtual host. Use this option to modify the value:

    {odbc_pool_size, 10}.
     

    You can configure an interval to make a dummy SQL request @@ -1529,7 +1517,7 @@ relational databases like PostgreSQL. To enable storage to your database, just make sure that your database is running well (see previous sections), and replace the suffix-less or ldap module variant with the odbc module variant. Keep in mind that you cannot have several variants of the same module loaded!

    -

    3.2.4  ODBC Compatible

    +

    3.2.4  ODBC Compatible

    Although this section will describe ejabberd’s configuration when you want to use the ODBC driver, it does not describe the installation and database creation of your database. Check the documentation of your database. The tutorial Using ejabberd with MySQL native driver also can help you. Note that the tutorial @@ -1574,7 +1562,7 @@ database, just make sure that your database is running well (see previous sections), and replace the suffix-less or ldap module variant with the odbc module variant. Keep in mind that you cannot have several variants of the same module loaded!

    -

    3.2.5  LDAP

    +

    3.2.5  LDAP

    ejabberd has built-in LDAP support. You can authenticate users against LDAP server and use LDAP directory as vCard storage. Shared rosters are not supported yet.

    Note that ejabberd treats LDAP as a read-only storage: @@ -1582,20 +1570,20 @@ it is possible to consult data, but not possible to create accounts, change password or edit vCard that is stored in LDAP.

    Connection

    Parameters:

    -ldap_servers
    List of IP addresses or DNS names of your +{ldap_servers, [Servers, ...]}
    List of IP addresses or DNS names of your LDAP servers. This option is required. -
    ldap_encrypt
    Type of connection encryption to the LDAP server. +
    {ldap_encrypt, none|tls}
    Type of connection encryption to the LDAP server. Allowed values are: none, tls. Note that STARTTLS is not supported. The default value is: none. -
    ldap_port
    Port to connect to your LDAP server. +
    {ldap_port, Number}
    Port to connect to your LDAP server. The default port is 389 if encryption is disabled; and 636 if encryption is enabled. If you configure a value, it is stored in ejabberd’s database. Then, if you remove that value from the configuration file, the value previously stored in the database will be used instead of the default port. -
    ldap_rootdn
    Bind DN. The default value +
    {ldap_rootdn, RootDN}
    Bind DN. The default value is "" which means ‘anonymous connection’. -
    ldap_password
    Bind password. The default +
    {ldap_password, Password}
    Bind password. The default value is "".

    Example:

    {auth_method, ldap}.
    @@ -1606,15 +1594,15 @@ value is "".
     

    Note that current LDAP implementation does not support SSL secured communication and SASL authentication.

    Authentication

    You can authenticate users against an LDAP directory. Available options are:

    -ldap_base
    LDAP base directory which stores +{ldap_base, Base}
    LDAP base directory which stores users accounts. This option is required. -
    ldap_uids
    LDAP attribute which holds a list -of attributes to use as alternatives for getting the JID. The value is of -the form: [{ldap_uidattr}] or [{ldap_uidattr, -ldap_uidattr_format}]. You can use as many comma separated tuples -{ldap_uidattr, ldap_uidattr_format} that is needed. The default -value is [{"uid", "%u"}]. The defaut ldap_uidattr_format -is "%u". The values for ldap_uidattr and +
    {ldap_uids, [ {ldap_uidattr} | {ldap_uidattr, ldap_uidattr_format}, ...]}
    +LDAP attribute which holds a list of attributes to use as alternatives for getting the JID. +The default attributes are [{"uid", "%u"}]. +The attributes are of the form: +[{ldap_uidattr}] or [{ldap_uidattr, ldap_uidattr_format}]. +You can use as many comma separated attributes as needed. +The values for ldap_uidattr and ldap_uidattr_format are described as follow:
    ldap_uidattr
    LDAP attribute which holds @@ -1625,13 +1613,13 @@ only one pattern variable "%u" which will be replaced by the user’s part of a JID. For example, "%u@example.org". The default value is "%u".
    -
    ldap_filter
    -RFC 2254 LDAP filter. The +
    {ldap_filter, Filter}
    +RFC 4515 LDAP filter. The default is none. Example: "(&(objectClass=shadowAccount)(memberOf=Jabber Users))". Please, do not forget to close brackets and do not use superfluous whitespaces. Also you must not use ldap_uidattr attribute in filter because this -attribute will be substituted in LDAP filter automatically.
    ldap_local_filter
    +attribute will be substituted in LDAP filter automatically.
    {ldap_local_filter, Filter}
    If you can’t use ldap_filter due to performance reasons (the LDAP server has many users registered), you can use this local filter. @@ -1760,11 +1748,12 @@ configuration is shown below:

    {auth_method, ldap}.
       ...
      ]}.
     

    -

    3.3  Modules Configuration

    +

    3.3  Modules Configuration

    The option modules defines the list of modules that will be loaded after ejabberd’s startup. Each entry in the list is a tuple in which the first element is the name of a module and the second is a list of options for that -module.

    Examples: +module.

    The syntax is: +

    {modules, [ {ModuleName, ModuleOptions}, ...]}.

    Examples:

    • In this example only the module mod_echo is loaded and no module options are specified between the square brackets: @@ -1782,41 +1771,40 @@ all entries end with a comma: {mod_version, []} ]}.

    -

    3.3.1  Modules Overview

    +

    3.3.1  Modules Overview

    The following table lists all modules included in ejabberd.


    - + - + - + - - - - + + + - - - + + + - - - - - + + + + + - - - - - - + + + + + +
    ModuleFeatureDependencies
    mod_adhocAd-Hoc Commands (XEP-0050) 
    mod_adhocAd-Hoc Commands (XEP-0050) 
    mod_announceManage announcementsrecommends mod_adhoc
    mod_capsEntity Capabilities (XEP-0115) 
    mod_capsEntity Capabilities (XEP-0115) 
    mod_configureServer configuration using Ad-Hocmod_adhoc
    mod_discoService Discovery (XEP-0030) 
    mod_discoService Discovery (XEP-0030) 
    mod_echoEchoes Jabber packets 
    mod_ircIRC transport 
    mod_lastLast Activity (XEP-0012) 
    mod_last_odbcLast Activity (XEP-0012)supported DB (*)
    mod_mucMulti-User Chat (XEP-0045) 
    mod_lastLast Activity (XEP-0012) 
    mod_last_odbcLast Activity (XEP-0012)supported DB (*)
    mod_mucMulti-User Chat (XEP-0045) 
    mod_muc_logMulti-User Chat room loggingmod_muc
    mod_offlineOffline message storage (XEP-0160) 
    mod_offline_odbcOffline message storage (XEP-0160)supported DB (*)
    mod_pingXMPP Ping and periodic keepalives (XEP-0199) 
    mod_offlineOffline message storage (XEP-0160) 
    mod_offline_odbcOffline message storage (XEP-0160)supported DB (*)
    mod_pingXMPP Ping and periodic keepalives (XEP-0199) 
    mod_privacyBlocking Communication (XMPP IM) 
    mod_privacy_odbcBlocking Communication (XMPP IM)supported DB (*)
    mod_privatePrivate XML Storage (XEP-0049) 
    mod_private_odbcPrivate XML Storage (XEP-0049)supported DB (*)
    mod_proxy65SOCKS5 Bytestreams (XEP-0065) 
    mod_pubsubPub-Sub (XEP-0060), PEP (XEP-0163)mod_caps
    mod_registerIn-Band Registration (XEP-0077) 
    mod_privatePrivate XML Storage (XEP-0049) 
    mod_private_odbcPrivate XML Storage (XEP-0049)supported DB (*)
    mod_proxy65SOCKS5 Bytestreams (XEP-0065) 
    mod_pubsubPub-Sub (XEP-0060), PEP (XEP-0163)mod_caps
    mod_registerIn-Band Registration (XEP-0077) 
    mod_rosterRoster management (XMPP IM) 
    mod_roster_odbcRoster management (XMPP IM)supported DB (*)
    mod_service_logCopy user messages to logger service 
    mod_shared_rosterShared roster managementmod_roster or
      mod_roster_odbc
    mod_statsStatistics Gathering (XEP-0039) 
    mod_timeEntity Time (XEP-0202) 
    mod_vcardvcard-temp (XEP-0054) 
    mod_vcard_ldapvcard-temp (XEP-0054)LDAP server
    mod_vcard_odbcvcard-temp (XEP-0054)supported DB (*)
    mod_versionSoftware Version (XEP-0092) 
    mod_statsStatistics Gathering (XEP-0039) 
    mod_timeEntity Time (XEP-0202) 
    mod_vcardvcard-temp (XEP-0054) 
    mod_vcard_ldapvcard-temp (XEP-0054)LDAP server
    mod_vcard_odbcvcard-temp (XEP-0054)supported DB (*)
    mod_versionSoftware Version (XEP-0092) 

    • (*) This module requires a supported database. For a list of supported databases, see section 3.2. @@ -1845,13 +1833,14 @@ Last connection date and time: Use mod_last_odbc instead of ejabberd website. Please remember that these contributions might not work or that they can contain severe bugs and security leaks. Therefore, use them at your own risk!

      -

      3.3.2  Common Options

      The following options are used by many modules. Therefore, they are described in +

      3.3.2  Common Options

      The following options are used by many modules. Therefore, they are described in this separate section.

      iqdisc

      Many modules define handlers for processing IQ queries of different namespaces to this server or to a user (e. g. to example.org or to user@example.org). This option defines processing discipline for -these queries. Possible values are: +these queries.

      The syntax is: +

      {iqdisc, Value}

      Possible Value are:

      no_queue
      All queries of a namespace with this processing discipline are processed immediately. This also means that no other packets can be processed @@ -1878,8 +1867,9 @@ number of processes (32000 by default). ]}.

      host

      -

      This option defines the Jabber ID of a service provided by an ejabberd module. -The keyword "@HOST@" is replaced at start time with the real virtual host string.

      This example configures +

      This option defines the Jabber ID of a service provided by an ejabberd module.

      The syntax is: +

      {host, HostName}

      If you include the keyword "@HOST@" in the HostName, +it is replaced at start time with the real virtual host string.

      This example configures the echo module to provide its echoing service in the Jabber ID mirror.example.org:

      {modules,
      @@ -1897,7 +1887,7 @@ the "@HOST@" keyword must be used:
         ...
        ]}.
       

      -

      3.3.3  mod_announce

      +

      3.3.3  mod_announce

      This module enables configured users to broadcast announcements and to set the message of the day (MOTD). Configured users can perform these actions with a @@ -1913,7 +1903,7 @@ message is sent to all registered users. If the user is online and connected to several resources, only the resource with the highest priority will receive the message. If the registered user is not connected, the message will be stored offline in assumption that offline storage -(see section 3.3.12) is enabled. +(see section 3.3.11) is enabled.

      example.org/announce/online (example.org/announce/all-hosts/online)
      The message is sent to all connected users. If the user is online and connected to several resources, all resources will receive the message. @@ -1928,7 +1918,7 @@ login. The message is not sent to any currently connected user. Any message sent to this JID removes the existing message of the day (MOTD).

      Options:

      -access
      This option specifies who is allowed to +{access, AccessName}
      This option specifies who is allowed to send announcements and to set the message of the day (by default, nobody is able to send such messages).

      Examples: @@ -1961,27 +1951,27 @@ Only administrators can send announcements:

    Note that mod_announce can be resource intensive on large deployments as it can broadcast lot of messages. This module should be disabled for instances of ejabberd with hundreds of thousands users.

    -

    3.3.4  mod_disco

    +

    3.3.4  mod_disco

    -

    This module adds support for Service Discovery (XEP-0030). With +

    This module adds support for Service Discovery (XEP-0030). With this module enabled, services on your server can be discovered by Jabber clients. Note that ejabberd has no modules with support -for the superseded Jabber Browsing (XEP-0011) and Agent Information -(XEP-0094). Accordingly, Jabber clients need to have support for +for the superseded Jabber Browsing (XEP-0011) and Agent Information +(XEP-0094). Accordingly, Jabber clients need to have support for the newer Service Discovery protocol if you want them be able to discover the services you offer.

    Options:

    -iqdisc
    This specifies +{iqdisc, Discipline}
    This specifies the processing discipline for Service Discovery (http://jabber.org/protocol/disco#items and http://jabber.org/protocol/disco#info) IQ queries (see section 3.3.2). -
    {extra_domains, [ Domain ]}
    With this option, +
    {extra_domains, [Domain, ...]}
    With this option, you can specify a list of extra domains that are added to the Service Discovery item list. -
    {server_info, [ {Modules, Field, [Value]} ]}
    +
    {server_info, [ {Modules, Field, [Value, ...]}, ... ]}
    Specify additional information about the server, -as described in Contact Addresses for XMPP Services (XEP-0157). +as described in Contact Addresses for XMPP Services (XEP-0157). Modules can be the keyword ‘all’, in which case the information is reported in all the services; or a list of ejabberd modules, @@ -2035,13 +2025,13 @@ and admin addresses for both the main server and the vJUD service: ... ]}.

    -

    3.3.5  mod_echo

    +

    3.3.5  mod_echo

    This module simply echoes any Jabber packet back to the sender. This mirror can be of interest for ejabberd and Jabber client debugging.

    Options:

    -host
    This option defines the Jabber ID of the +{host, HostName}
    This option defines the Jabber ID of the service. If the host option is not specified, the Jabber ID will be the hostname of the virtual host with the prefix ‘echo.’. The keyword "@HOST@" is replaced at start time with the real virtual host name. @@ -2055,9 +2045,9 @@ of them all? ... ]}.

    -

    3.3.6  mod_http_bind

    +

    3.3.6  mod_http_bind

    This module implements XMPP over Bosh (formerly known as HTTP Binding) -as defined in XEP-0124 and XEP-0206. +as defined in XEP-0124 and XEP-0206. It extends ejabberd’s built in HTTP service with a configurable resource at which this service will be hosted.

    To use HTTP-Binding, enable the module:

    {modules,
    @@ -2095,35 +2085,37 @@ For example:
       },
       ...
     ]}.
    -

    The maximum inactivity period is by default 30 seconds. -This can be configured with the module option max_inactivity. +

    Options: +

    +{max_inactivity, Seconds}
    +Define the maximum inactivity period in seconds. +Default value is 30 seconds. For example, to set 50 seconds: -

    {modules,
    +
    {modules,
      [
       ...
       {mod_http_bind, [ {max_inactivity, 50} ]},
       ...
     ]}.
    -

    -

    3.3.7  mod_http_fileserver

    +

    +

    3.3.7  mod_http_fileserver

    This simple module serves files from the local disk over HTTP.

    Options:

    -docroot
    +{docroot, Path}
    Directory to serve the files. -
    accesslog
    +
    {accesslog, Path}
    File to log accesses using an Apache-like format. No log will be recorded if this option is not specified. -
    directory_indices
    +
    {directory_indices, [Index, ...]}
    Indicate one or more directory index files, similarly to Apache’s DirectoryIndex variable. When a web request hits a directory instead of a regular file, those directory indices are looked in order, and the first one found is returned. -
    content_types
    Specify a mapping of extensions to content types. There are several content types already defined, with this option you can add new definitions, modify or delete existing ones. To delete an existing definition, simply define it with a value: ‘undefined’. -
    default_content_type
    +
    {default_content_type, Type}
    Specify the content type to use for unknown extensions. Default value is ‘application/octet-stream’.

    This example configuration will serve the files from @@ -2165,78 +2157,18 @@ To use this module you must enable it: }, ... ]}. -

    -

    3.3.8  mod_irc

    -

    This module is an IRC transport that can be used to join channels on IRC -servers.

    End user information: - -

    • -A Jabber client with ‘groupchat 1.0’ support or Multi-User -Chat support (XEP-0045) is necessary to join IRC channels. -
    • An IRC channel can be joined in nearly the same way as joining a -Jabber Multi-User Chat room. The difference is that the room name will -be ‘channel%irc.example.org’ in case irc.example.org is -the IRC server hosting ‘channel’. And of course the host should point -to the IRC transport instead of the Multi-User Chat service. -
    • You can register your nickame by sending ‘IDENTIFY password’ to
      - nickserver!irc.example.org@irc.jabberserver.org. -
    • Entering your password is possible by sending ‘LOGIN nick password’
      - to nickserver!irc.example.org@irc.jabberserver.org. -
    • The IRC transport provides Ad-Hoc Commands (XEP-0050) -to join a channel, and to set custom IRC username and encoding. -
    • When using a popular Jabber server, it can occur that no -connection can be achieved with some IRC servers because they limit the -number of conections from one IP. -

    Options: -

    - -host
    This option defines the Jabber ID of the -service. If the host option is not specified, the Jabber ID will be the -hostname of the virtual host with the prefix ‘irc.’. The keyword "@HOST@" -is replaced at start time with the real virtual host name. - -
    access
    This option can be used to specify who -may use the IRC transport (default value: all). -
    default_encoding
    Set the default IRC encoding (default value: "koi8-r"). -

    Examples: -

    • -In the first example, the IRC transport is available on (all) your -virtual host(s) with the prefix ‘irc.’. Furthermore, anyone is -able to use the transport. The default encoding is set to "iso8859-15". -
      {modules,
      - [
      -  ...
      -  {mod_irc, [{access, all}, {default_encoding, "iso8859-15"}]},
      -  ...
      - ]}.
      -
    • In next example the IRC transport is available with JIDs with prefix irc-t.net. -Moreover, the transport is only accessible to two users -of example.org, and any user of example.com: -
      {acl, paying_customers, {user, "customer1", "example.org"}}.
      -{acl, paying_customers, {user, "customer2", "example.org"}}.
      -{acl, paying_customers, {server, "example.com"}}.
      -
      -{access, irc_users, [{allow, paying_customers}, {deny, all}]}.
      -
      -{modules,
      - [
      -  ...
      -  {mod_irc, [{access, irc_users},
      -             {host, "irc.example.net"}]},
      -  ...
      - ]}.
      -

    -

    3.3.9  mod_last

    -

    This module adds support for Last Activity (XEP-0012). It can be used to +

    +

    3.3.8  mod_last

    +

    This module adds support for Last Activity (XEP-0012). It can be used to discover when a disconnected user last accessed the server, to know when a connected user was last active on the server, or to query the uptime of the ejabberd server.

    Options:

    -iqdisc
    This specifies +{iqdisc, Discipline}
    This specifies the processing discipline for Last activity (jabber:iq:last) IQ queries (see section 3.3.2).

    -

    3.3.10  mod_muc

    -

    This module provides a Multi-User Chat (XEP-0045) service. +

    3.3.9  mod_muc

    +

    This module provides a Multi-User Chat (XEP-0045) service. Users can discover existing rooms, join or create them. Occupants of a room can chat in public or have private chats.

    Some of the features of Multi-User Chat:

    • @@ -2257,20 +2189,20 @@ set of rooms goes down, the rooms disappear and they will be recreated on an available node on first connection attempt.

      Module options:

      -host
      This option defines the Jabber ID of the +{host, HostName}
      This option defines the Jabber ID of the service. If the host option is not specified, the Jabber ID will be the hostname of the virtual host with the prefix ‘conference.’. The keyword "@HOST@" is replaced at start time with the real virtual host name. -
      access
      You can specify who is allowed to use +
      {access, AccessName}
      You can specify who is allowed to use the Multi-User Chat service. By default everyone is allowed to use it. -
      access_create
      To configure who is +
      {access_create, AccessName}
      To configure who is allowed to create new rooms at the Multi-User Chat service, this option can be used. By default everybody is allowed to create rooms. -
      access_persistent
      To configure who is +
      {access_persistent, AccessName}
      To configure who is allowed to modify the ’persistent’ room option. By default everybody is allowed to modify that option. -
      access_admin
      This option specifies +
      {access_admin, AccessName}
      This option specifies who is allowed to administrate the Multi-User Chat service. The default value is none, which means that only the room creator can administer his room. @@ -2278,7 +2210,7 @@ The administrators can send a normal message to the service JID, and it will be shown in all active rooms as a service message. The administrators can send a groupchat message to the JID of an active room, and the message will be shown in the room as a service message. -
      history_size
      A small history of +
      {history_size, Size}
      A small history of the current discussion is sent to users when they enter the room. With this option you can define the number of history messages to keep and send to users joining the room. The value is an @@ -2286,35 +2218,35 @@ integer. Setting the value to 0 disables the history feature and, as a result, nothing is kept in memory. The default value is 20. This value is global and thus affects all rooms on the service. -
      max_users
      This option defines at +
      {max_users, Number}
      This option defines at the service level, the maximum number of users allowed per room. It can be lowered in each room configuration but cannot be increased in individual room configuration. The default value is 200. -
      max_users_admin_threshold
      +
      {max_users_admin_threshold, Number}
      This option defines the number of service admins or room owners allowed to enter the room when the maximum number of allowed occupants was reached. The default limit is 5. -
      max_user_conferences
      +
      {max_user_conferences, Number}
      This option defines the maximum number of rooms that any given user can join. The default value is 10. This option is used to prevent possible abuses. Note that this is a soft limit: some users can sometimes join more conferences in cluster configurations. -
      max_room_id
      +
      {max_room_id, Number}
      This option defines the maximum number of characters that Room ID can have when creating a new room. The default value is to not limit: infinite. -
      max_room_name
      +
      {max_room_name, Number}
      This option defines the maximum number of characters that Room Name can have when configuring the room. The default value is to not limit: infinite. -
      max_room_desc
      +
      {max_room_desc, Number}
      This option defines the maximum number of characters that Room Description can have when configuring the room. The default value is to not limit: infinite. -
      min_message_interval
      +
      {min_message_interval, Number}
      This option defines the minimum interval between two messages send by an occupant in seconds. This option is global and valid for all rooms. A decimal value can be used. When this option is not defined, @@ -2324,7 +2256,7 @@ be broadcasted by the service. A good value for this minimum message interval is 0.4 second. If an occupant tries to send messages faster, an error is send back explaining that the message has been discarded and describing the reason why the message is not acceptable. -
      min_presence_interval
      +
      {min_presence_interval, Number}
      This option defines the minimum of time between presence changes coming from a given occupant in seconds. This option is global and valid for all rooms. A @@ -2336,36 +2268,36 @@ presence is cached by ejabberd and only the last presence is broadcasted to all occupants in the room after expiration of the interval delay. Intermediate presence packets are silently discarded. A good value for this option is 4 seconds. -
      default_room_options
      +
      {default_room_options, [ {OptionName, OptionValue}, ...]}
      This module option allows to define the desired default room options. Note that the creator of a room can modify the options of his room at any time using a Jabber client with MUC capability. The available room options and the default values are:
      -{allow_change_subj, true}
      Allow occupants to change the subject. -
      {allow_private_messages, true}
      Occupants can send private messages to other occupants. -
      {allow_query_users, true}
      Occupants can send IQ queries to other occupants. -
      {allow_user_invites, false}
      Allow occupants to send invitations. -
      {allow_visitor_nickchange, true}
      Allow visitors to +{allow_change_subj, true|false}
      Allow occupants to change the subject. +
      {allow_private_messages, true|false}
      Occupants can send private messages to other occupants. +
      {allow_query_users, true|false}
      Occupants can send IQ queries to other occupants. +
      {allow_user_invites, false|true}
      Allow occupants to send invitations. +
      {allow_visitor_nickchange, true|false}
      Allow visitors to change nickname. -
      {allow_visitor_status, true}
      Allow visitors to send +
      {allow_visitor_status, true|false}
      Allow visitors to send status text in presence updates. If disallowed, the status text is stripped before broadcasting the presence update to all the room occupants. -
      {anonymous, true}
      The room is anonymous: +
      {anonymous, true|false}
      The room is anonymous: occupants don’t see the real JIDs of other occupants. Note that the room moderators can always see the real JIDs of the occupants. -
      {logging, false}
      The public messages are logged using mod_muc_log. +
      {logging, false|true}
      The public messages are logged using mod_muc_log.
      {max_users, 200}
      Maximum number of occupants in the room. -
      {members_by_default, true}
      The occupants that enter the room are participants by default, so they have ’voice’. -
      {members_only, false}
      Only members of the room can enter. -
      {moderated, true}
      Only occupants with ’voice’ can send public messages. -
      {password, ""}
      Password of the room. You may want to enable the next option too. -
      {password_protected, false}
      The password is required to enter the room. -
      {persistent, false}
      The room persists even if the last participant leaves. -
      {public, true}
      The room is public in the list of the MUC service, so it can be discovered. -
      {public_list, true}
      The list of participants is public, without requiring to enter the room. -
      {title, ""}
      A human-readable title of the room. +
      {members_by_default, true|false}
      The occupants that enter the room are participants by default, so they have ’voice’. +
      {members_only, false|true}
      Only members of the room can enter. +
      {moderated, true|false}
      Only occupants with ’voice’ can send public messages. +
      {password, "roompass123"}
      Password of the room. You may want to enable the next option too. +
      {password_protected, false|true}
      The password is required to enter the room. +
      {persistent, false|true}
      The room persists even if the last participant leaves. +
      {public, true|false}
      The room is public in the list of the MUC service, so it can be discovered. +
      {public_list, true|false}
      The list of participants is public, without requiring to enter the room. +
      {title, "Room Title"}
      A human-readable title of the room.
      All of those room options can be set to true or false, except password and title which are strings, @@ -2458,7 +2390,7 @@ the newly created rooms have by default those options. ... ]}.

    -

    3.3.11  mod_muc_log

    +

    3.3.10  mod_muc_log

    This module enables optional logging of Multi-User Chat (MUC) public conversations to HTML. Once you enable this module, users can join a room using a MUC capable Jabber client, and if they have enough privileges, they can request the @@ -2468,7 +2400,7 @@ Room details are added on top of each page: room title, JID, author, subject and configuration.

  • The room JID in the generated HTML is a link to join the room (using -XMPP URI). +XMPP URI).
  • Subject and room configuration changes are tracked and displayed.
  • Joins, leaves, nick changes, kicks, bans and ‘/me’ are tracked and displayed, including the reason if available. @@ -2481,53 +2413,52 @@ displayed, including the reason if available.
  • A custom link can be added on top of each page.
  • Options:

    -access_log
    +{access_log, AccessName}
    This option restricts which occupants are allowed to enable or disable room logging. The default value is muc_admin. Note for this default setting you need to have an access rule for muc_admin in order to take effect. -
    cssfile
    +
    {cssfile, false|URL}
    With this option you can set whether the HTML files should have a custom CSS file or if they need to use the embedded CSS file. Allowed values are false and an URL to a CSS file. With the first value, HTML files will include the embedded CSS code. With the latter, you can specify the URL of the -custom CSS file (for example: ‘http://example.com/my.css’). The default value +custom CSS file (for example: "http://example.com/my.css"). The default value is false. -
    dirname
    +
    {dirname, room_jid|room_name}
    Allows to configure the name of the room directory. Allowed values are room_jid and room_name. With the first value, the room directory name will be the full room JID. With the latter, the room directory name will be only the room name, not including the MUC service name. The default value is room_jid. -
    dirtype
    +
    {dirtype, subdirs|plain}
    The type of the created directories can be specified with this option. Allowed values are subdirs and plain. With the first value, subdirectories are created for each year and month. With the latter, the names of the log files contain the full date, and there are no subdirectories. The default value is subdirs. -
    file_format
    +
    {file_format, html|plaintext}
    Define the format of the log files: html stores in HTML format, plaintext stores in plain text. The default value is html. -
    outdir
    +
    {outdir, Path}
    This option sets the full path to the directory in which the HTML files should be stored. Make sure the ejabberd daemon user has write access on that directory. The default value is "www/muc". -
    spam_prevention
    +
    {spam_prevention true|false}
    To prevent spam, the spam_prevention option adds a special attribute to links that prevent their indexation by search engines. The default value is true, which mean that nofollow attributes will be added to user submitted links. -
    timezone
    +
    {timezone, local|universal}
    The time zone for the logs is configurable with this option. Allowed values are local and universal. With the first value, the local time, as reported to Erlang by the operating system, will be used. With the latter, GMT/UTC time will be used. The default value is local. -
    top_link
    +
    {top_link, {URL, Text}}
    With this option you can customize the link on the top right corner of each -log file. The syntax of this option is {"URL", "Text"}. The default -value is {"/", "Home"}. +log file. The default value is {"/", "Home"}.

    Examples:

    • In the first example any room owner can enable logging, and a @@ -2578,14 +2509,14 @@ top link will be the default <a href="/">Home</a>. ... ]}.

    -

    3.3.12  mod_offline

    -

    This module implements offline message storage (XEP-0160). +

    3.3.11  mod_offline

    +

    This module implements offline message storage (XEP-0160). This means that all messages sent to an offline user will be stored on the server until that user comes online again. Thus it is very similar to how email works. Note that ejabberdctl has a command to delete expired messages (see section 4.1).

    -access_max_user_messages
    +{access_max_user_messages, Number}
    This option defines which access rule will be enforced to limit the maximum number of offline messages that a user can have (quota). When a user has too many offline messages, any new messages that he receive are discarded, @@ -2610,12 +2541,12 @@ and all the other users up to 100. ... ]}.

    -

    3.3.13  mod_ping

    -

    This module implements support for XMPP Ping (XEP-0199) and periodic keepalives. +

    3.3.12  mod_ping

    +

    This module implements support for XMPP Ping (XEP-0199) and periodic keepalives. When this module is enabled ejabberd responds correctly to ping requests, as defined in the protocol.

    Configuration options:

    -{send_pings, true | false}
    +{send_pings, true|false}
    If this option is set to true, the server sends pings to connected clients that are not active in a given interval ping_interval. This is useful to keep client connections alive or checking availability. @@ -2625,7 +2556,7 @@ How often to send pings to connected clients, if the previous option is enabled. If a client connection does not send or receive any stanza in this interval, a ping request is sent to the client. The default value is 60 seconds. -
    {timeout_action, none | kill}
    +
    {timeout_action, none|kill}
    What to do when a client does not answer to a server ping request in less than 32 seconds. The default is to do nothing.

    This example enables Ping responses, configures the module to send pings @@ -2638,7 +2569,7 @@ and if a client does not answer to the ping in less than 32 seconds, its connect ... ]}.

    -

    3.3.14  mod_privacy

    +

    3.3.13  mod_privacy

    This module implements Blocking Communication (also known as Privacy Rules) as defined in section 10 from XMPP IM. If end users have support for it in their Jabber client, they will be able to: @@ -2660,47 +2591,50 @@ or subscription type (or globally).

  • Allowing or blocking all communications based on JID, group, or subscription type (or globally).
  • -(from http://www.xmpp.org/specs/rfc3921.html#privacy) +(from http://xmpp.org/specs/rfc3921.html#privacy)

    Options:

    -iqdisc
    This specifies +{iqdisc, Discipline}
    This specifies the processing discipline for Blocking Communication (jabber:iq:privacy) IQ queries (see section 3.3.2).

    -

    3.3.15  mod_private

    -

    This module adds support for Private XML Storage (XEP-0049): +

    3.3.14  mod_private

    +

    This module adds support for Private XML Storage (XEP-0049):

    Using this method, Jabber entities can store private data on the server and retrieve it whenever necessary. The data stored might be anything, as long as it is valid XML. One typical usage for this namespace is the server-side storage -of client-specific preferences; another is Bookmark Storage (XEP-0048). +of client-specific preferences; another is Bookmark Storage (XEP-0048).

    Options:

    -iqdisc
    This specifies +{iqdisc, Discipline}
    This specifies the processing discipline for Private XML Storage (jabber:iq:private) IQ queries (see section 3.3.2).

    -

    3.3.16  mod_proxy65

    -

    This module implements SOCKS5 Bytestreams (XEP-0065). +

    3.3.15  mod_proxy65

    +

    This module implements SOCKS5 Bytestreams (XEP-0065). It allows ejabberd to act as a file transfer proxy between two XMPP clients.

    Options:

    -host
    This option defines the hostname of the service. -If this option is not set, the prefix ‘proxy.’ is added to ejabberd -hostname. -
    name
    Defines Service Discovery name of the service. + +{host, HostName}
    This option defines the Jabber ID of the +service. If the host option is not specified, the Jabber ID will be the +hostname of the virtual host with the prefix ‘proxy.’. The keyword "@HOST@" +is replaced at start time with the real virtual host name. + +
    {name, Text}
    Defines Service Discovery name of the service. Default is "SOCKS5 Bytestreams". -
    ip
    This option specifies which network interface +
    {ip, IPTuple}
    This option specifies which network interface to listen for. Default is an IP address of the service’s DNS name, or, if fails, {127,0,0,1}. -
    port
    This option defines port to listen for +
    {port, Number}
    This option defines port to listen for incoming connections. Default is 7777. -
    auth_type
    SOCKS5 authentication type. +
    {auth_type, anonymous|plain}
    SOCKS5 authentication type. Possible values are anonymous and plain. Default is anonymous. -
    access
    Defines ACL for file transfer initiators. +
    {access, AccessName}
    Defines ACL for file transfer initiators. Default is all. -
    max_connections
    Maximum number of +
    {max_connections, Number}
    Maximum number of active connections per file transfer initiator. No limit by default. -
    shaper
    This option defines shaper for +
    {shaper, none|ShaperName}
    This option defines shaper for the file transfer peers. Shaper with the maximum bandwidth will be selected. Default is none.

    Examples: @@ -2733,38 +2667,38 @@ The simpliest configuration of the module: ... ]}.

    -

    3.3.17  mod_pubsub

    -

    This module offers a Publish-Subscribe Service (XEP-0060). +

    3.3.16  mod_pubsub

    +

    This module offers a Publish-Subscribe Service (XEP-0060). The functionality in mod_pubsub can be extended using plugins. -The plugin that implements PEP (Personal Eventing via Pubsub) (XEP-0163) +The plugin that implements PEP (Personal Eventing via Pubsub) (XEP-0163) is enabled in the default ejabberd configuration file, and it requires mod_caps.

    Options:

    -host
    This option defines the Jabber ID of the +{host, HostName}
    This option defines the Jabber ID of the service. If the host option is not specified, the Jabber ID will be the hostname of the virtual host with the prefix ‘pubsub.’. The keyword "@HOST@" is replaced at start time with the real virtual host name. -
    access_createnode
    +
    {access_createnode, AccessName}
    This option restricts which users are allowed to create pubsub nodes using -ACL and ACCESS. The default value is pubsub_createnode.
    plugins
    +ACL and ACCESS. The default value is pubsub_createnode.
    {plugins, [ Plugin, ...]}
    To specify which pubsub node plugins to use. If not defined, the default pubsub plugin is always used. -
    nodetree
    +
    {nodetree, Name}
    To specify which nodetree to use. If not defined, the default pubsub nodetree is used. Only one nodetree can be used per host, and is shared by all node plugins. -
    pep_sendlast_offline
    +
    {pep_sendlast_offline, false|true}
    To specify whether or not we should get last published PEP items from users in our roster which are offline when we connect. Value is true or false. If not defined, pubsub assumes false so we only get last items of online contacts. -
    last_item_cache
    +
    {last_item_cache, false|true}
    To specify whether or not pubsub should cache last items. Value is true or false. If not defined, pubsub do not cache last items. On systems with not so many nodes, caching last items speeds up pubsub and allows to raise user connection rate. The cost is memory usage, as every item is stored in memory. -
    pep_mapping
    +
    {pep_mapping, [ {Key, Value}, ...]}
    This allow to define a Key-Value list to choose defined node plugins on given PEP namespace. The following example will use node_tune instead of node_pep for every PEP node with tune namespace:
      {mod_pubsub, [{pep_mapping, [{"http://jabber.org/protocol/tune", "tune"}]}]}
    @@ -2779,8 +2713,8 @@ The following example will use node_tune instead of node_pep for every PEP node
       ...
      ]}.
     

    -

    3.3.18  mod_register

    -

    This module adds support for In-Band Registration (XEP-0077). This protocol +

    3.3.17  mod_register

    +

    This module adds support for In-Band Registration (XEP-0077). This protocol enables end users to use a Jabber client to:

    • Register a new account on the server. @@ -2788,17 +2722,17 @@ Register a new account on the server.
    • Delete an existing account on the server.

    Options:

    -access
    This option can be configured to specify +{access, AccessName}
    This option can be configured to specify rules to restrict registration. If a rule returns ‘deny’ on the requested user name, registration for that user name is denied. (there are no restrictions by default). -
    welcome_message
    Set a welcome message that +
    {welcome_message, Message}
    Set a welcome message that is sent to each newly registered account. The first string is the subject, and the second string is the message body. In the body you can set a newline with the characters: \n -
    registration_watchers
    This option defines a +
    {registration_watchers, [ JID, ...]}
    This option defines a list of JIDs which will be notified each time a new account is registered. -
    iqdisc
    This specifies +
    {iqdisc, Discipline}
    This specifies the processing discipline for In-Band Registration (jabber:iq:register) IQ queries (see section 3.3.2).

    This module reads also another option defined globally for the server: {registration_timeout, Timeout}. @@ -2852,17 +2786,17 @@ Also define a registration timeout of one hour: ... ]}.

    -

    3.3.19  mod_roster

    +

    3.3.18  mod_roster

    This module implements roster management as defined in -RFC 3921: XMPP IM. -It also supports Roster Versioning (XEP-0237).

    Options: +RFC 3921: XMPP IM. +It also supports Roster Versioning (XEP-0237).

    Options:

    -iqdisc
    This specifies +{iqdisc, Discipline}
    This specifies the processing discipline for Roster Management (jabber:iq:roster) IQ queries (see section 3.3.2). -
    {versioning, false | true}
    Enables +
    {versioning, false|true}
    Enables Roster Versioning. This option is disabled by default. -
    {store_current_id, false | true}
    +
    {store_current_id, false|true}
    If this option is enabled, the current version number is stored on the database. If disabled, the version number is calculated on the fly each time. Enabling this option reduces the load for both ejabberd and the database. @@ -2878,14 +2812,14 @@ Important: if you use mod_shared_roster, you must disable this option. ... ]}.

    -

    3.3.20  mod_service_log

    +

    3.3.19  mod_service_log

    This module adds support for logging end user packets via a Jabber message auditing service such as Bandersnatch. All user packets are encapsulated in a <route/> element and sent to the specified service(s).

    Options:

    -loggers
    With this option a (list of) service(s) +{loggers, [Names, ...]}
    With this option a (list of) service(s) that will receive the packets can be specified.

    Examples:

    • @@ -2908,7 +2842,7 @@ To log all end user packets to the Bandersnatch service running on ... ]}.

    -

    3.3.21  mod_shared_roster

    +

    3.3.20  mod_shared_roster

    This module enables you to create shared roster groups. This means that you can create groups of people that can see members from (other) groups in their rosters. The big advantages of this feature are that end users do not need to @@ -2983,8 +2917,8 @@ roster groups as shown in the following table:


    -

    3.3.22  mod_stats

    -

    This module adds support for Statistics Gathering (XEP-0039). This protocol +

    3.3.21  mod_stats

    +

    This module adds support for Statistics Gathering (XEP-0039). This protocol allows you to retrieve next statistics from your ejabberd deployment:

    • Total number of registered users on the current virtual host (users/total). @@ -2993,7 +2927,7 @@ Total number of registered users on the current virtual host (users/total).
    • Total number of online users on all virtual hosts (users/all-hosts/online).

    Options:

    -iqdisc
    This specifies +{iqdisc, Discipline}
    This specifies the processing discipline for Statistics Gathering (http://jabber.org/protocol/stats) IQ queries (see section 3.3.2).

    As there are only a small amount of clients (for example Tkabber) and software libraries with @@ -3015,40 +2949,40 @@ by sending: </query> </iq>

    -

    3.3.23  mod_time

    -

    This module features support for Entity Time (XEP-0202). By using this XEP, +

    3.3.22  mod_time

    +

    This module features support for Entity Time (XEP-0202). By using this XEP, you are able to discover the time at another entity’s location.

    Options:

    -iqdisc
    This specifies +{iqdisc, Discipline}
    This specifies the processing discipline for Entity Time (jabber:iq:time) IQ queries (see section 3.3.2).

    -

    3.3.24  mod_vcard

    +

    3.3.23  mod_vcard

    This module allows end users to store and retrieve their vCard, and to retrieve -other users vCards, as defined in vcard-temp (XEP-0054). The module also +other users vCards, as defined in vcard-temp (XEP-0054). The module also implements an uncomplicated Jabber User Directory based on the vCards of these users. Moreover, it enables the server to send its vCard when queried.

    Options:

    -host
    This option defines the Jabber ID of the +{host, HostName}
    This option defines the Jabber ID of the service. If the host option is not specified, the Jabber ID will be the hostname of the virtual host with the prefix ‘vjud.’. The keyword "@HOST@" is replaced at start time with the real virtual host name. -
    iqdisc
    This specifies +
    {iqdisc, Discipline}
    This specifies the processing discipline for vcard-temp IQ queries (see section 3.3.2). -
    search
    This option specifies whether the search -functionality is enabled (value: true) or disabled (value: -false). If disabled, the option host will be ignored and the +
    {search, true|false}
    This option specifies whether the search +functionality is enabled or not +If disabled, the option host will be ignored and the Jabber User Directory service will not appear in the Service Discovery item list. The default value is true. -
    matches
    With this option, the number of reported +
    {matches, infinity|Number}
    With this option, the number of reported search results can be limited. If the option’s value is set to infinity, all search results are reported. The default value is 30. -
    allow_return_all
    This option enables +
    {allow_return_all, false|true}
    This option enables you to specify if search operations with empty input fields should return all users who added some information to their vCard. The default value is false. -
    search_all_hosts
    If this option is set +
    {search_all_hosts, true|false}
    If this option is set to true, search operations will apply to all virtual hosts. Otherwise only the current host will be searched. The default value is true. This option is available in mod_vcard, but not available in mod_vcard_odbc. @@ -3077,7 +3011,7 @@ and that all virtual hosts will be searched instead of only the current one: ... ]}.

    -

    3.3.25  mod_vcard_ldap

    +

    3.3.24  mod_vcard_ldap

    ejabberd can map LDAP attributes to vCard fields. This behaviour is implemented in the mod_vcard_ldap module. This module does not depend on the authentication method (see 3.2.5).

    Note that ejabberd treats LDAP as a read-only storage: @@ -3092,32 +3026,35 @@ about these options. If one of these options is not set, ejabberd will for the top-level option with the same name.

    The second group of parameters consists of the following mod_vcard_ldap-specific options:

    -host
    This option defines the Jabber ID of the +{host, HostName}
    This option defines the Jabber ID of the service. If the host option is not specified, the Jabber ID will be the hostname of the virtual host with the prefix ‘vjud.’. The keyword "@HOST@" is replaced at start time with the real virtual host name. -
    iqdisc
    This specifies +
    {iqdisc, Discipline}
    This specifies the processing discipline for vcard-temp IQ queries (see section 3.3.2). -
    search
    This option specifies whether the search +
    {search, true|false}
    This option specifies whether the search functionality is enabled (value: true) or disabled (value: false). If disabled, the option host will be ignored and the Jabber User Directory service will not appear in the Service Discovery item list. The default value is true. -
    matches
    With this option, the number of reported +
    {matches, infinity|Number}
    With this option, the number of reported search results can be limited. If the option’s value is set to infinity, all search results are reported. The default value is 30. -
    ldap_vcard_map
    With this option you can -set the table that maps LDAP attributes to vCard fields. The format is: -[Name_of_vCard_field, Pattern, List_of_LDAP_attributes, ...]. -Name_of_vcard_field is the type name of the vCard as defined in -RFC 2426. Pattern is a -string which contains pattern variables "%u", "%d" or -"%s". List_of_LDAP_attributes is the list containing LDAP -attributes. The pattern variables "%s" will be sequentially replaced +
    {ldap_vcard_map, [ {Name, Pattern, LDAPattributes}, ...]}
    +With this option you can set the table that maps LDAP attributes to vCard fields. + +Name is the type name of the vCard as defined in +RFC 2426. +Pattern is a string which contains pattern variables +"%u", "%d" or "%s". +LDAPattributes is the list containing LDAP attributes. +The pattern variables +"%s" will be sequentially replaced with the values of LDAP attributes from List_of_LDAP_attributes, -"%u" will be replaced with the user part of a JID, and "%d" -will be replaced with the domain part of a JID. The default is: +"%u" will be replaced with the user part of a JID, +and "%d" will be replaced with the domain part of a JID. +The default is:
    [{"NICKNAME", "%u", []},
      {"FN", "%s", ["displayName"]},
      {"LAST", "%s", ["sn"]},
    @@ -3138,9 +3075,9 @@ will be replaced with the domain part of a JID. The default is:
      {"BDAY", "%s", ["birthDay"]},
      {"ROLE", "%s", ["employeeType"]},
      {"PHOTO", "%s", ["jpegPhoto"]}]
    -
    ldap_search_fields
    This option -defines the search form and the LDAP attributes to search within. The format -is: [Name, Attribute, ...]. Name is the name of a search form +
    {ldap_search_fields, [ {Name, Attribute}, ...]}
    This option +defines the search form and the LDAP attributes to search within. +Name is the name of a search form field which will be automatically translated by using the translation files (see msgs/*.msg for available words). Attribute is the LDAP attribute or the pattern "%u". The default is: @@ -3156,11 +3093,11 @@ LDAP attribute or the pattern "%u". The default is: {"Email", "mail"}, {"Organization Name", "o"}, {"Organization Unit", "ou"}] -
    ldap_search_reported
    This option -defines which search fields should be reported. The format is: -[Name, vCard_Name, ...]. Name is the name of a search form +
    {ldap_search_reported, [ {SearchField, VcardField}, ...]}
    This option +defines which search fields should be reported. +SearchField is the name of a search form field which will be automatically translated by using the translation -files (see msgs/*.msg for available words). vCard_Name is the +files (see msgs/*.msg for available words). VcardField is the vCard field name defined in the ldap_vcard_map option. The default is:
    [{"Full Name", "FN"},
    @@ -3253,13 +3190,13 @@ searching his info in LDAP.

  • ldap_vcard_map
  • -

    3.3.26  mod_version

    -

    This module implements Software Version (XEP-0092). Consequently, it +

    3.3.25  mod_version

    +

    This module implements Software Version (XEP-0092). Consequently, it answers ejabberd’s version when queried.

    Options:

    -show_os
    Should the operating system be revealed or not. +{show_os, true|false}
    Should the operating system be revealed or not. The default value is true. -
    iqdisc
    This specifies +
    {iqdisc, Discipline}
    This specifies the processing discipline for Software Version (jabber:iq:version) IQ queries (see section 3.3.2).

    Chapter 4  Managing an ejabberd Server

    @@ -3427,7 +3364,7 @@ This is not recommended for big databases, as it will consume much time, memory and processor. In that case it’s preferable to use backup and install_fallback.
    import_piefxis, export_piefxis, export_piefxis_host
    These options can be used to migrate accounts -using XEP-0227 formatted XML files +using XEP-0227 formatted XML files from/to other Jabber/XMPP servers or move users of a vhost to another ejabberd installation. See also @@ -3446,11 +3383,11 @@ is very high. In that case, authentication information must be provided. In each frontend the AccessCommands option is defined in a different place. But in all cases the option syntax is the same: -

    AccessCommands = [ {Access, CommandNames, Arguments} ]
    +

    AccessCommands = [ {Access, CommandNames, Arguments}, ...]
     Access = atom()
     CommandNames = all | [CommandName]
     CommandName = atom()
    -Arguments = [{ArgumentName, ArgumentValue}]
    +Arguments = [ {ArgumentName, ArgumentValue}, ...]
     ArgumentName = atom()
     ArgumentValue = any()
     

    The default value is to not define any restriction: []. @@ -3563,7 +3500,7 @@ See section 4.1.2.

    4.4  Ad-hoc Commands

    If you enable mod_configure and mod_adhoc, you can perform several administrative tasks in ejabberd with a Jabber client. -The client must support Ad-Hoc Commands (XEP-0050), +The client must support Ad-Hoc Commands (XEP-0050), and you must login in the Jabber server with an account with proper privileges.

    4.5  Change Computer Hostname

    ejabberd uses the distributed Mnesia database. @@ -3755,7 +3692,7 @@ the Erlang shell. This probably can take some time if Mnesia has not yet transfered and processed all data it needed from first.

  • Now run ejabberd on second with a configuration similar as on first: you probably do not need to duplicate ‘acl’ and ‘access’ options because they will be taken from -first; and mod_irc should be +first. If you installed mod_irc, notice that it should be enabled only on one machine in the cluster.
  • You can repeat these steps for other machines supposed to serve this domain.

    @@ -3763,8 +3700,8 @@ domain.

    6.3.1  Components Load-Balancing

    6.3.2  Domain Load-Balancing Algorithm

    -

    ejabberd includes an algorithm to load balance the components that are plugged on an ejabberd cluster. It means that you can plug one or several instances of the same component on each ejabberd cluster and that the traffic will be automatically distributed.

    The default distribution algorithm try to deliver to a local instance of a component. If several local instances are available, one instance is chosen randomly. If no instance is available locally, one instance is chosen randomly among the remote component instances.

    If you need a different behaviour, you can change the load balancing behaviour with the option domain_balancing. The syntax of the option is the following:

    {domain_balancing, "component.example.com", <balancing_criterium>}.
    -

    Several balancing criteria are available: +

    ejabberd includes an algorithm to load balance the components that are plugged on an ejabberd cluster. It means that you can plug one or several instances of the same component on each ejabberd cluster and that the traffic will be automatically distributed.

    The default distribution algorithm try to deliver to a local instance of a component. If several local instances are available, one instance is chosen randomly. If no instance is available locally, one instance is chosen randomly among the remote component instances.

    If you need a different behaviour, you can change the load balancing behaviour with the option domain_balancing. The syntax of the option is the following: +

    {domain_balancing, "component.example.com", BalancingCriteria}.

    Several balancing criteria are available:

    • destination: the full JID of the packet to attribute is used.
    • source: the full JID of the packet from attribute is used. @@ -3772,17 +3709,16 @@ domain.

      6.3.3  Load-Balancing Buckets

      -

      When there is a risk of failure for a given component, domain balancing can cause service trouble. If one component is failing the service will not work correctly unless the sessions are rebalanced.

      In this case, it is best to limit the problem to the sessions handled by the failing component. This is what the domain_balancing_component_number option does, making the load balancing algorithm not dynamic, but sticky on a fix number of component instances.

      The syntax is the following: -

      {domain_balancing_component_number, "component.example.com", N}
      -

      +

      When there is a risk of failure for a given component, domain balancing can cause service trouble. If one component is failing the service will not work correctly unless the sessions are rebalanced.

      In this case, it is best to limit the problem to the sessions handled by the failing component. This is what the domain_balancing_component_number option does, making the load balancing algorithm not dynamic, but sticky on a fix number of component instances.

      The syntax is: +

      {domain_balancing_component_number, "component.example.com", N}.

      Chapter 7  Debugging

      7.1  Log Files

      An ejabberd node writes two log files:

      ejabberd.log
      is the ejabberd service log, with the messages reported by ejabberd code
      sasl.log
      is the Erlang/OTP system log, with the messages reported by Erlang/OTP using SASL (System Architecture Support Libraries) -

      The option loglevel modifies the verbosity of the file ejabberd.log. -The possible levels are: +

    The option loglevel modifies the verbosity of the file ejabberd.log. The syntax is: +

    {loglevel, Level}.

    The possible Level are:

    0
    No ejabberd log at all (not recommended)
    1
    Critical @@ -3810,12 +3746,14 @@ when troubleshooting a problem related to memory usage. If a process in the ejabberd server consumes more memory than the configured threshold, a message is sent to the Jabber accounts defined with the option watchdog_admins - in the ejabberd configuration file.

    The memory consumed is measured in words: + in the ejabberd configuration file.

    The syntax is: +

    {watchdog_admins, [JID, ...]}.

    The memory consumed is measured in words: a word on 32-bit architecture is 4 bytes, and a word on 64-bit architecture is 8 bytes. The threshold by default is 1000000 words. This value can be configured with the option watchdog_large_heap, -or in a conversation with the watchdog alert bot.

    Example configuration: +or in a conversation with the watchdog alert bot.

    The syntax is: +

    {watchdog_large_heap, Number}.

    Example configuration:

    {watchdog_admins, ["admin2@localhost", "admin2@example.org"]}.
     {watchdog_large_heap, 30000000}.
     

    To remove watchdog admins, remove them in the option. diff --git a/doc/guide.tex b/doc/guide.tex index f21af0e4e..90df674fb 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -59,6 +59,7 @@ \newcommand{\shell}[1]{\texttt{#1}} \newcommand{\ejabberd}{\texttt{ejabberd}} \newcommand{\Jabber}{Jabber} +\newcommand{\esyntax}[1]{\begin{description}\titem{#1}\end{description}} %% Modules \newcommand{\module}[1]{\texttt{#1}} @@ -105,10 +106,10 @@ %\ifthenelse{\boolean{modhttpbind}}{\input{mod_http_bind.tex}}{} %% Common options -\newcommand{\iqdiscitem}[1]{\titem{iqdisc} \ind{options!iqdisc}This specifies +\newcommand{\iqdiscitem}[1]{\titem{\{iqdisc, Discipline\}} \ind{options!iqdisc}This specifies the processing discipline for #1 IQ queries (see section~\ref{modiqdiscoption}).} \newcommand{\hostitem}[1]{ - \titem{host} \ind{options!host} This option defines the Jabber ID of the + \titem{\{host, HostName\}} \ind{options!host} This option defines the Jabber ID of the service. If the \texttt{host} option is not specified, the Jabber ID will be the hostname of the virtual host with the prefix `\jid{#1.}'. The keyword "@HOST@" is replaced at start time with the real virtual host name. @@ -594,7 +595,7 @@ host name(s) stored in the database will be used. You can override the old values stored in the database by adding next lines to -the configuration file: +the beginning of the configuration file: \begin{verbatim} override_global. override_local. @@ -610,20 +611,18 @@ and ACLs will be removed before new ones are added. The option \option{hosts} defines a list containing one or more domains that \ejabberd{} will serve. +The syntax is: +\esyntax{\{hosts, [HostName, ...]\}.} + Examples: \begin{itemize} \item Serving one domain: \begin{verbatim} {hosts, ["example.org"]}. \end{verbatim} -\item Serving one domain, and backwards compatible with older \ejabberd{} - versions: +\item Serving three domains: \begin{verbatim} -{host, "example.org"}. -\end{verbatim} -\item Serving two domains: -\begin{verbatim} -{hosts, ["example.net", "example.com"]}. +{hosts, ["example.net", "example.com", "jabber.somesite.org"]}. \end{verbatim} \end{itemize} @@ -631,11 +630,10 @@ Examples: \ind{virtual hosting}\ind{virtual hosts}\ind{virtual domains} Options can be defined separately for every virtual host using the -\term{host\_config} option.\ind{options!host\_config} It has the following -syntax: -\begin{verbatim} -{host_config, , [

  • The in-band registration of new accounts can be prohibited by changing the -access option. If you really want to disable all In-Band Registration -functionality, that is changing passwords in-band and deleting accounts -in-band, you have to remove mod_register from the modules list. In this -example all In-Band Registration functionality is disabled: +
  • This configuration prohibits usage of In-Band Registration +to create or delete accounts, +but allows existing accounts to change the password:
    {access, register, [{deny, all}]}.
     
     {modules,
    + [
    +  ...
    +  {mod_register, [{access, register}]},
    +  ...
    + ]}.
    +
  • This configuration disables all In-Band Registration +functionality: create, delete accounts and change password: +
    {modules,
      [
       ...
       %% {mod_register, [{access, register}]},
    diff --git a/doc/guide.tex b/doc/guide.tex
    index 90df674fb..0cf446f1a 100644
    --- a/doc/guide.tex
    +++ b/doc/guide.tex
    @@ -3540,14 +3540,23 @@ Examples:
       ...
      ]}.
     \end{verbatim}
    -\item The in-band registration of new accounts can be prohibited by changing the
    -  \option{access} option. If you really want to disable all In-Band Registration
    -  functionality, that is changing passwords in-band and deleting accounts
    -  in-band, you have to remove \modregister{} from the modules list. In this
    -  example all In-Band Registration functionality is disabled:
    +\item This configuration prohibits usage of In-Band Registration
    +  to create or delete accounts,
    +  but allows existing accounts to change the password:
     \begin{verbatim}
     {access, register, [{deny, all}]}.
     
    +{modules,
    + [
    +  ...
    +  {mod_register, [{access, register}]},
    +  ...
    + ]}.
    +\end{verbatim}
    +\item 
    +  This configuration disables all In-Band Registration
    +  functionality: create, delete accounts and change password:
    +\begin{verbatim}
     {modules,
      [
       ...
    
    From 6688b4ea783c76c08bf3ee8a2f28b590eefef939 Mon Sep 17 00:00:00 2001
    From: Evgeniy Khramtsov 
    Date: Fri, 21 Aug 2009 06:07:55 +0000
    Subject: [PATCH 507/582] do not include MAPPED-ADDRESS in new style responses
     since it is not required by the RFC
    
    SVN Revision: 2515
    ---
     src/stun/ejabberd_stun.erl | 1 -
     1 file changed, 1 deletion(-)
    
    diff --git a/src/stun/ejabberd_stun.erl b/src/stun/ejabberd_stun.erl
    index d5085821f..2c27f321d 100644
    --- a/src/stun/ejabberd_stun.erl
    +++ b/src/stun/ejabberd_stun.erl
    @@ -197,7 +197,6 @@ process(Addr, Port, #stun{class = request, unsupported = []} = Msg) ->
     			      'MAPPED-ADDRESS' = {Addr, Port}};
     		new ->
     		    Resp#stun{class = response,
    -			      'MAPPED-ADDRESS' = {Addr, Port},
     			      'XOR-MAPPED-ADDRESS' = {Addr, Port}}
     	    end;
            true ->
    
    From d9a8c89b5a296cfb4e1614331513790f7a9228a5 Mon Sep 17 00:00:00 2001
    From: Badlop 
    Date: Mon, 24 Aug 2009 19:59:17 +0000
    Subject: [PATCH 508/582] Added preliminary template file for ejabberd.init
     (thanks to Christophe Romain)
    
    SVN Revision: 2523
    ---
     src/ejabberd.init.template | 46 ++++++++++++++++++++++++++++++++++++++
     src/ejabberdctl.template   | 33 +++++++++++++++++++++++++++
     2 files changed, 79 insertions(+)
     create mode 100644 src/ejabberd.init.template
    
    diff --git a/src/ejabberd.init.template b/src/ejabberd.init.template
    new file mode 100644
    index 000000000..948e5c4d0
    --- /dev/null
    +++ b/src/ejabberd.init.template
    @@ -0,0 +1,46 @@
    +#! /bin/sh
    +set -o errexit
    +set -o nounset
    +
    +DIR=@@INSTALLDIR@@
    +CTL="$DIR"/bin/ejabberdctl
    +USER=ejabberd
    +
    +test -d "$DIR" || {
    +	echo "ERROR: ejabberd not found: $DIR"
    +	exit 1
    +}
    +grep ^"$USER": /etc/passwd >/dev/null || {
    +	echo "ERROR: System user not found: $USER"
    +	exit 2
    +}
    +
    +export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"
    +
    +case "$1" in
    +  start)
    +    test -x "$CTL" || exit 0
    +    echo "Starting ejabberd..."
    +    su - $USER -c "$CTL start"
    +    su - $USER -c "$CTL started"
    +    echo "done."
    +    ;;
    +  stop)
    +    test -x "$CTL" || exit 0
    +    echo "Stopping ejabberd..."
    +    su - $USER -c "$CTL stop"
    +    su - $USER -c "$CTL stopped"
    +    echo "done."
    +    ;;
    +
    +  force-reload|restart)
    +    "$0" stop
    +    "$0" start
    +    ;;
    +
    +  *)
    +    echo "Usage: $0 {start|stop|restart|force-reload}"
    +    exit 1
    +esac
    +
    +exit 0
    diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template
    index eb85ce266..f6a30bb09 100644
    --- a/src/ejabberdctl.template
    +++ b/src/ejabberdctl.template
    @@ -239,9 +239,42 @@ usage ()
         exit
     }
     
    +# stop epmd if there is no other running node
    +stop_epmd()
    +{
    +    epmd -names | grep -q name || epmd -kill
    +}
    +
    +# allow sync calls
    +wait_for_status()
    +{
    +    # args: status try delay
    +    # return: 0 OK, 1 KO
    +    timeout=$2
    +    status=4
    +    while [ $status -ne $1 ]; do
    +        sleep $3
    +        let timeout=timeout-1
    +        [ $timeout -eq 0 ] && {
    +            status=$1
    +        } || {
    +            ctl status > /dev/null
    +            status=$?
    +        }
    +    done
    +    [ $timeout -eq 0 ] && {
    +        status=1
    +    } || {
    +        status=0
    +    }
    +    return $status
    +}
    +
     case $ARGS in
         ' start') start;;
         ' debug') debug;;
         ' live') live;;
    +    ' started') wait_for_status 0 30 2;; # wait 30x2s before timeout
    +    ' stopped') wait_for_status 3 15 2; stop_epmd;; # wait 15x2s before timeout
         *) ctl $ARGS;;
     esac
    
    From 19355e947e51110783b45f9680387dddface35be Mon Sep 17 00:00:00 2001
    From: Badlop 
    Date: Mon, 24 Aug 2009 19:59:30 +0000
    Subject: [PATCH 509/582] Prepare ejabberd.init when installing ejabberd.
    
    SVN Revision: 2524
    ---
     src/Makefile.in            | 7 +++++++
     src/ejabberd.init.template | 8 ++++----
     2 files changed, 11 insertions(+), 4 deletions(-)
    
    diff --git a/src/Makefile.in b/src/Makefile.in
    index 7b2e20e31..484b1a0d5 100644
    --- a/src/Makefile.in
    +++ b/src/Makefile.in
    @@ -21,11 +21,13 @@ ifeq ($(INSTALLUSER),)
       G_USER=
       CHOWN_COMMAND=echo
       CHOWN_OUTPUT=/dev/null
    +  INIT_USER=root
     else
       O_USER=-o $(INSTALLUSER)
       G_USER=-g $(INSTALLUSER)
       CHOWN_COMMAND=chown
       CHOWN_OUTPUT=&1
    +  INIT_USER=$(INSTALLUSER)
     endif
     
     EFLAGS += -pa .
    @@ -186,6 +188,11 @@ install: all
     	[ -d $(SBINDIR) ] || install -d -m 755 $(SBINDIR)
     	install -m 550 $(G_USER) ejabberdctl.example $(SBINDIR)/ejabberdctl
     	#
    +	# Init script
    +	sed -e "s*@ctlscriptpath@*$(SBINDIR)*" \
    +		-e "s*@installuser@*$(INIT_USER)*" ejabberd.init.template \
    +		> ejabberd.init
    +	#
     	# Binary Erlang files
     	install -d $(BEAMDIR)
     	install -m 644 *.app $(BEAMDIR)
    diff --git a/src/ejabberd.init.template b/src/ejabberd.init.template
    index 948e5c4d0..6659557b6 100644
    --- a/src/ejabberd.init.template
    +++ b/src/ejabberd.init.template
    @@ -2,11 +2,11 @@
     set -o errexit
     set -o nounset
     
    -DIR=@@INSTALLDIR@@
    -CTL="$DIR"/bin/ejabberdctl
    -USER=ejabberd
    +DIR=@ctlscriptpath@
    +CTL="$DIR"/ejabberdctl
    +USER=@installuser@
     
    -test -d "$DIR" || {
    +test -x "$CTL" || {
     	echo "ERROR: ejabberd not found: $DIR"
     	exit 1
     }
    
    From 9769a178665b392c9d7c2cc773012de4a665d31a Mon Sep 17 00:00:00 2001
    From: Badlop 
    Date: Mon, 24 Aug 2009 19:59:44 +0000
    Subject: [PATCH 510/582] Document that the admin can install ejabberd.init
     script (EJAB-755)
    
    SVN Revision: 2525
    ---
     doc/guide.html | 12 ++++++++++--
     doc/guide.tex  | 12 +++++++++++-
     2 files changed, 21 insertions(+), 3 deletions(-)
    
    diff --git a/doc/guide.html b/doc/guide.html
    index d4fdc890a..6b4be6e3a 100644
    --- a/doc/guide.html
    +++ b/doc/guide.html
    @@ -298,7 +298,10 @@ go to the Windows service settings and set ejabberd to be automatically started.
     Note that the Windows service is a feature still in development,
     and for example it doesn’t read the file ejabberdctl.cfg.

    On a *nix system, if you want ejabberd to be started as daemon at boot time, copy ejabberd.init from the ’bin’ directory to something like /etc/init.d/ejabberd -(depending on your distribution) and call /etc/inid.d/ejabberd start to start it.

    If ejabberd doesn’t start correctly in Windows, +(depending on your distribution). +Create a system user called ejabberd; +it will be used by the script to start the server. +Then you can call /etc/inid.d/ejabberd start as root to start the server.

    If ejabberd doesn’t start correctly in Windows, try to start it using the shortcut in desktop or start menu. If the window shows error 14001, the solution is to install: "Microsoft Visual C++ 2005 SP1 Redistributable Package". @@ -434,7 +437,12 @@ You can try starting ejabberd with the command ejabberdctl live to see the error message provided by Erlang and can identify what is exactly the problem.

    Please refer to the section 4.1 for details about ejabberdctl, -and configurable options to fine tune the Erlang runtime system.

    +and configurable options to fine tune the Erlang runtime system.

    If you want ejabberd to be started as daemon at boot time, +copy ejabberd.init to something like /etc/init.d/ejabberd +(depending on your distribution). +Create a system user called ejabberd; +it will be used by the script to start the server. +Then you can call /etc/inid.d/ejabberd start as root to start the server.

    2.4.6  Specific Notes for BSD

    The command to compile ejabberd in BSD systems is:

    gmake
    diff --git a/doc/guide.tex b/doc/guide.tex
    index 0cf446f1a..43110aad9 100644
    --- a/doc/guide.tex
    +++ b/doc/guide.tex
    @@ -240,7 +240,10 @@ and for example it doesn't read the file ejabberdctl.cfg.
     
     On a *nix system, if you want ejabberd to be started as daemon at boot time,
     copy \term{ejabberd.init} from the 'bin' directory to something like \term{/etc/init.d/ejabberd}
    -(depending on your distribution) and call \term{/etc/inid.d/ejabberd start} to start it.
    +(depending on your distribution).
    +Create a system user called \term{ejabberd};
    +it will be used by the script to start the server.
    +Then you can call \term{/etc/inid.d/ejabberd start} as root to start the server.
     
     If \term{ejabberd} doesn't start correctly in Windows,
     try to start it using the shortcut in desktop or start menu.
    @@ -445,6 +448,13 @@ and can identify what is exactly the problem.
     Please refer to the section~\ref{ejabberdctl} for details about \term{ejabberdctl},
     and configurable options to fine tune the Erlang runtime system.
     
    +If you want ejabberd to be started as daemon at boot time,
    +copy \term{ejabberd.init} to something like \term{/etc/init.d/ejabberd}
    +(depending on your distribution).
    +Create a system user called \term{ejabberd};
    +it will be used by the script to start the server.
    +Then you can call \term{/etc/inid.d/ejabberd start} as root to start the server.
    +
     \makesubsection{bsd}{Specific Notes for BSD}
     \ind{install!bsd}
     
    
    From 6470e6cc2588b448d7605b4769cb8add5bb13a3c Mon Sep 17 00:00:00 2001
    From: Badlop 
    Date: Mon, 24 Aug 2009 21:21:39 +0000
    Subject: [PATCH 511/582] Write PID file, path is configurable in
     ejabberdctl.cfg (EJAB-1023)
    
    SVN Revision: 2527
    ---
     doc/guide.html              |  2 ++
     doc/guide.tex               |  2 ++
     src/ejabberd.erl            | 12 ++++++++++++
     src/ejabberd_app.erl        | 33 +++++++++++++++++++++++++++++++++
     src/ejabberdctl.cfg.example | 12 ++++++++++++
     src/ejabberdctl.template    |  1 +
     6 files changed, 62 insertions(+)
    
    diff --git a/doc/guide.html b/doc/guide.html
    index 6b4be6e3a..02c5c94cd 100644
    --- a/doc/guide.html
    +++ b/doc/guide.html
    @@ -3280,6 +3280,8 @@ all the environment variables and command line parameters.

    The environment Path to the directory with binary system libraries.

  • EJABBERD_DOC_PATH
    Path to the directory with ejabberd documentation. +
    EJABBERD_PID_PATH
    + Path to the PID file that ejabberd can create when started.
    HOME
    Path to the directory that is considered ejabberd’s home. This path is used to read the file .erlang.cookie. diff --git a/doc/guide.tex b/doc/guide.tex index 43110aad9..74d6fa8b4 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -4210,6 +4210,8 @@ The environment variables: Path to the directory with binary system libraries. \titem{EJABBERD\_DOC\_PATH} Path to the directory with ejabberd documentation. + \titem{EJABBERD\_PID\_PATH} + Path to the PID file that ejabberd can create when started. \titem{HOME} Path to the directory that is considered \ejabberd{}'s home. This path is used to read the file \term{.erlang.cookie}. diff --git a/src/ejabberd.erl b/src/ejabberd.erl index 0c7c56a2a..228614b93 100644 --- a/src/ejabberd.erl +++ b/src/ejabberd.erl @@ -28,6 +28,7 @@ -author('alexey@process-one.net'). -export([start/0, stop/0, + get_pid_file/0, get_so_path/0, get_bin_path/0]). start() -> @@ -63,3 +64,14 @@ get_bin_path() -> Path -> Path end. + +%% @spec () -> false | string() +get_pid_file() -> + case os:getenv("EJABBERD_PID_PATH") of + false -> + false; + "" -> + false; + Path -> + Path + end. diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index c68199d19..bea1b0b7a 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -40,6 +40,7 @@ start(normal, _Args) -> ejabberd_loglevel:set(4), + write_pid_file(), application:start(sasl), application:start(exmpp), randoms:start(), @@ -81,6 +82,7 @@ prep_stop(State) -> %% All the processes were killed when this function is called stop(_State) -> ?INFO_MSG("ejabberd ~s is stopped in the node ~p", [?VERSION, node()]), + delete_pid_file(), ejabberd_debug:stop(), ok. @@ -182,3 +184,34 @@ add_windows_nameservers() -> IPTs = win32_dns:get_nameservers(), ?INFO_MSG("Adding machine's DNS IPs to Erlang system:~n~p", [IPTs]), lists:foreach(fun(IPT) -> inet_db:add_ns(IPT) end, IPTs). + + +%%% +%%% PID file +%%% + +write_pid_file() -> + case ejabberd:get_pid_file() of + false -> + ok; + PidFilename -> + write_pid_file(os:getpid(), PidFilename) + end. + +write_pid_file(Pid, PidFilename) -> + case file:open(PidFilename, [write]) of + {ok, Fd} -> + io:format(Fd, "~s~n", [Pid]), + file:close(Fd); + {error, Reason} -> + ?ERROR_MSG("Cannot write PID file ~s~nReason: ~p", [PidFilename, Reason]), + throw({cannot_write_pid_file, PidFilename, Reason}) + end. + +delete_pid_file() -> + case ejabberd:get_pid_file() of + false -> + ok; + PidFilename -> + file:delete(PidFilename) + end. diff --git a/src/ejabberdctl.cfg.example b/src/ejabberdctl.cfg.example index 0c8d0c5a6..1ba413fe2 100644 --- a/src/ejabberdctl.cfg.example +++ b/src/ejabberdctl.cfg.example @@ -110,6 +110,18 @@ # #ERLANG_NODE=ejabberd +#. +#' EJABBERD_PID_PATH: ejabberd PID file +# +# Indicate the full path to the ejabberd Process identifier (PID) file. +# If this variable is defined, ejabberd writes the PID file when starts, +# and deletes it when stops. +# Remember to create the directory and grant write permission to ejabberd. +# +# Default: don't write PID file +# +#EJABBERD_PID_PATH=/var/run/ejabberd/ejabberd.pid + #. #' # vim: foldmarker=#',#. foldmethod=marker: diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template index f6a30bb09..48a56ba5b 100644 --- a/src/ejabberdctl.template +++ b/src/ejabberdctl.template @@ -118,6 +118,7 @@ export EJABBERD_LOG_PATH export EJABBERD_SO_PATH export EJABBERD_BIN_PATH export EJABBERD_DOC_PATH +export EJABBERD_PID_PATH export ERL_CRASH_DUMP export ERL_INETRC export ERL_MAX_PORTS From 938a4007b3775c91964c91f120b2ad627a891a44 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Tue, 25 Aug 2009 17:14:30 +0000 Subject: [PATCH 512/582] Initial port of pubsub changes(up to r2444) to exmpp branch. pubsub odbc isn't ported yet. Not tested (only basic node creation and configuration), should still have losts of bugs to discover. SVN Revision: 2533 --- src/mod_pubsub/gen_pubsub_node.erl | 7 +- src/mod_pubsub/mod_pubsub.erl | 719 ++++++++++++++++++++----- src/mod_pubsub/node_buddy.erl | 26 +- src/mod_pubsub/node_club.erl | 28 +- src/mod_pubsub/node_dag.erl | 175 ++++++ src/mod_pubsub/node_dispatch.erl | 35 +- src/mod_pubsub/node_flat.erl | 28 +- src/mod_pubsub/node_hometree.erl | 320 ++++++++--- src/mod_pubsub/node_mb.erl | 25 +- src/mod_pubsub/node_pep.erl | 41 +- src/mod_pubsub/node_private.erl | 26 +- src/mod_pubsub/nodetree_dag.erl | 249 +++++++++ src/mod_pubsub/nodetree_tree.erl | 38 +- src/mod_pubsub/pubsub.hrl | 14 +- src/mod_pubsub/pubsub_subscription.erl | 333 ++++++++++++ 15 files changed, 1756 insertions(+), 308 deletions(-) create mode 100644 src/mod_pubsub/node_dag.erl create mode 100644 src/mod_pubsub/nodetree_dag.erl create mode 100644 src/mod_pubsub/pubsub_subscription.erl diff --git a/src/mod_pubsub/gen_pubsub_node.erl b/src/mod_pubsub/gen_pubsub_node.erl index 78256cd56..3762d4a44 100644 --- a/src/mod_pubsub/gen_pubsub_node.erl +++ b/src/mod_pubsub/gen_pubsub_node.erl @@ -46,7 +46,7 @@ behaviour_info(callbacks) -> {create_node, 2}, {delete_node, 1}, {purge_node, 2}, - {subscribe_node, 7}, + {subscribe_node, 8}, {unsubscribe_node, 4}, {publish_item, 6}, {delete_item, 4}, @@ -57,8 +57,9 @@ behaviour_info(callbacks) -> {set_affiliation, 3}, {get_node_subscriptions, 1}, {get_entity_subscriptions, 2}, - {get_subscription, 2}, - {set_subscription, 3}, + {get_subscriptions, 2}, + {set_subscriptions, 4}, + {get_pending_nodes, 2}, {get_states, 1}, {get_state, 2}, {set_state, 1}, diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index ead9e405f..dfe8ab5a2 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -33,6 +33,14 @@ %%% This module uses version 1.12 of the specification as a base. %%% Most of the specification is implemented. %%% Functions concerning configuration should be rewritten. +%%% +%%% Support for subscription-options and multi-subscribe features was +%%% added by Brian Cully . Subscriptions and options are +%%% stored in the pubsub_subscription table, with a link to them provided +%%% by the subscriptions field of pubsub_state. For information on +%%% subscription-options and mulit-subscribe see XEP-0060 sections 6.1.6, +%%% 6.2.3.1, 6.2.3.5, and 6.3. For information on subscription leases see +%%% XEP-0060 section 12.18. %%% TODO %%% plugin: generate Reply (do not use broadcast atom anymore) @@ -47,6 +55,7 @@ -include_lib("exmpp/include/exmpp.hrl"). -include("ejabberd.hrl"). +-include("adhoc.hrl"). -include("pubsub.hrl"). -define(STDTREE, "tree"). @@ -73,7 +82,7 @@ %% exports for console debug manual use -export([create_node/5, delete_node/3, - subscribe_node/4, + subscribe_node/5, unsubscribe_node/5, publish_item/6, delete_item/4, @@ -81,7 +90,7 @@ get_items/2, get_item/3, get_cached_item/2, - broadcast_stanza/7, + broadcast_stanza/8, get_configure/5, set_configure/5, tree_action/3, @@ -129,6 +138,12 @@ plugins = [?STDNODE], send_loop}). + +%%------------------- Ad hoc commands nodes -------------------------- +-define(NS_PUBSUB_GET_PENDING, "http://jabber.org/protocol/pubsub#get-pending"). +%%-------------------------------------------------------------------- + + %%==================================================================== %% API %%==================================================================== @@ -173,17 +188,17 @@ init([ServerHost, Opts]) -> ServerHostB = list_to_binary(ServerHost), pubsub_index:init(Host, ServerHost, Opts), ets:new(gen_mod:get_module_proc(Host, config), [set, named_table]), - ets:new(gen_mod:get_module_proc(ServerHostB, config), [set, named_table]), + ets:new(gen_mod:get_module_proc(ServerHost, config), [set, named_table]), ets:new(gen_mod:get_module_proc(Host, last_items), [set, named_table]), - ets:new(gen_mod:get_module_proc(ServerHostB, last_items), [set, named_table]), + ets:new(gen_mod:get_module_proc(ServerHost, last_items), [set, named_table]), {Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts), mod_disco:register_feature(ServerHost, ?NS_PUBSUB_s), ets:insert(gen_mod:get_module_proc(Host, config), {nodetree, NodeTree}), ets:insert(gen_mod:get_module_proc(Host, config), {plugins, Plugins}), ets:insert(gen_mod:get_module_proc(Host, config), {last_item_cache, LastItemCache}), - ets:insert(gen_mod:get_module_proc(ServerHostB, config), {nodetree, NodeTree}), - ets:insert(gen_mod:get_module_proc(ServerHostB, config), {plugins, Plugins}), - ets:insert(gen_mod:get_module_proc(ServerHostB, config), {pep_mapping, PepMapping}), + ets:insert(gen_mod:get_module_proc(ServerHost, config), {nodetree, NodeTree}), + ets:insert(gen_mod:get_module_proc(ServerHost, config), {plugins, Plugins}), + ets:insert(gen_mod:get_module_proc(ServerHost, config), {pep_mapping, PepMapping}), ejabberd_hooks:add(disco_sm_identity, ServerHostB, ?MODULE, disco_sm_identity, 75), ejabberd_hooks:add(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), ejabberd_hooks:add(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75), @@ -205,7 +220,9 @@ init([ServerHost, Opts]) -> false -> ok end, - update_database(Host, ServerHost), + ejabberd_router:register_route(Host), + update_node_database(Host, ServerHost), + update_state_database(Host, ServerHost), init_nodes(Host, ServerHost), State = #state{host = Host, server_host = ServerHost, @@ -255,17 +272,17 @@ terminate_plugins(Host, ServerHost, Plugins, TreePlugin) -> TreePlugin:terminate(Host, ServerHost), ok. -init_nodes(Host, ServerHost) -> - create_node(Host, ServerHost, ["home"], service_jid(Host), ?STDNODE), - create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), ?STDNODE), +init_nodes(_Host, _ServerHost) -> + %create_node(Host, ServerHost, ["home"], service_jid(Host), "hometree"), + %create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), "hometree"), ok. -update_database(Host, ServerHost) -> +update_node_database(Host, ServerHost) -> mnesia:del_table_index(pubsub_node, type), mnesia:del_table_index(pubsub_node, parentid), case catch mnesia:table_info(pubsub_node, attributes) of [host_node, host_parent, info] -> - ?INFO_MSG("upgrade pubsub tables",[]), + ?INFO_MSG("upgrade node pubsub tables",[]), F = fun() -> lists:foldl( fun({pubsub_node, NodeId, ParentId, {nodeinfo, Items, Options, Entities}}, {RecList, NodeIdx}) -> @@ -292,11 +309,11 @@ update_database(Host, ServerHost) -> _ -> IAcc end end, [], ItemsList), - mnesia:write( - #pubsub_state{stateid = {JID, NodeIdx}, - items = UsrItems, - affiliation = Aff, - subscription = Sub}), + mnesia:write({pubsub_state, + {JID, NodeIdx}, + UsrItems, + Aff, + Sub}), case Aff of owner -> [JID | Acc]; _ -> Acc @@ -305,7 +322,7 @@ update_database(Host, ServerHost) -> mnesia:delete({pubsub_node, NodeId}), {[#pubsub_node{nodeid = NodeId, id = NodeIdx, - parent = element(2, ParentId), + parents = [element(2, ParentId)], owners = Owners, options = Options} | RecList], NodeIdx + 1} @@ -324,21 +341,23 @@ update_database(Host, ServerHost) -> end, case mnesia:transaction(FNew) of {atomic, Result} -> - ?INFO_MSG("Pubsub tables updated correctly: ~p", [Result]); + ?INFO_MSG("Pubsub node tables updated correctly: ~p", + [Result]); {aborted, Reason} -> - ?ERROR_MSG("Problem updating Pubsub tables:~n~p", [Reason]) + ?ERROR_MSG("Problem updating Pubsub node tables:~n~p", + [Reason]) end; [nodeid, parentid, type, owners, options] -> F = fun({pubsub_node, NodeId, {_, Parent}, Type, Owners, Options}) -> #pubsub_node{ nodeid = NodeId, id = 0, - parent = Parent, + parents = [Parent], type = Type, owners = Owners, options = Options} end, - mnesia:transform_table(pubsub_node, F, [nodeid, id, parent, type, owners, options]), + mnesia:transform_table(pubsub_node, F, [nodeid, id, parents, type, owners, options]), FNew = fun() -> lists:foldl(fun(#pubsub_node{nodeid = NodeId} = PubsubNode, NodeIdx) -> mnesia:write(PubsubNode#pubsub_node{id = NodeIdx}), @@ -364,9 +383,61 @@ update_database(Host, ServerHost) -> end, case mnesia:transaction(FNew) of {atomic, Result} -> - ?INFO_MSG("Pubsub tables updated correctly: ~p", [Result]); + ?INFO_MSG("Pubsub node tables updated correctly: ~p", + [Result]); {aborted, Reason} -> - ?ERROR_MSG("Problem updating Pubsub tables:~n~p", [Reason]) + ?ERROR_MSG("Problem updating Pubsub node tables:~n~p", + [Reason]) + end; + [nodeid, id, parent, type, owners, options] -> + F = fun({pubsub_node, NodeId, Id, Parent, Type, Owners, Options}) -> + #pubsub_node{ + nodeid = NodeId, + id = Id, + parents = [Parent], + type = Type, + owners = Owners, + options = Options} + end, + mnesia:transform_table(pubsub_node, F, [nodeid, id, parents, type, owners, options]); + _ -> + ok + end. + +update_state_database(_Host, _ServerHost) -> + case catch mnesia:table_info(pubsub_state, attributes) of + [stateid, items, affiliation, subscription] -> + ?INFO_MSG("upgrade state pubsub tables", []), + F = fun ({pubsub_state, {JID, NodeID}, Items, Aff, Sub}, Acc) -> + Subs = case Sub of + none -> + []; + _ -> + {result, SubID} = pubsub_subscription:subscribe_node(JID, NodeID, []), + [{Sub, SubID}] + end, + NewState = #pubsub_state{stateid = {JID, NodeID}, + items = Items, + affiliation = Aff, + subscriptions = Subs}, + [NewState | Acc] + end, + {atomic, NewRecs} = mnesia:transaction(fun mnesia:foldl/3, + [F, [], pubsub_state]), + {atomic, ok} = mnesia:delete_table(pubsub_state), + {atomic, ok} = mnesia:create_table(pubsub_state, + [{disc_copies, [node()]}, + {attributes, record_info(fields, pubsub_state)}]), + FNew = fun () -> + lists:foreach(fun mnesia:write/1, NewRecs) + end, + case mnesia:transaction(FNew) of + {atomic, Result} -> + ?INFO_MSG("Pubsub state tables updated correctly: ~p", + [Result]); + {aborted, Reason} -> + ?ERROR_MSG("Problem updating Pubsub state tables:~n~p", + [Reason]) end; _ -> ok @@ -625,7 +696,7 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) -> presence_probe(JID, JID, Pid) -> {U, S, R} = jlib:short_prepd_jid(JID), - Host = S, % exmpp_jid:prep_domain_as_list(JID), + Host = exmpp_jid:prep_domain_as_list(JID), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), gen_server:cast(Proc, {presence, JID, Pid}), gen_server:cast(Proc, {presence, U, S, [R], JID}); @@ -728,7 +799,7 @@ handle_cast({remove_user, LUser, LServer}, State) -> handle_cast({unsubscribe, Subscriber, Owner}, State) -> Host = State#state.host, - BJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + BJID = jlib:short_prepd_bare_jid(Owner), lists:foreach(fun(PType) -> {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), lists:foreach(fun @@ -840,7 +911,7 @@ do_route(ServerHost, Access, Plugins, Host, From, To, Packet) -> QAttrs = SubEl#xmlel.attrs, Node = exmpp_xml:get_attribute_from_list_as_list(QAttrs, 'node', ""), - ServerHostB = exmpp_jid:prep_domain(ServerHost), + ServerHostB = list_to_binary(ServerHost), Info = ejabberd_hooks:run_fold( disco_info, ServerHostB, [], [ServerHost, ?MODULE, <<>>, ""]), @@ -883,6 +954,8 @@ do_route(ServerHost, Access, Plugins, Host, From, To, Packet) -> lang = Lang, payload = SubEl} -> Res = case iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) of + {result, []} -> + exmpp_iq:result(Packet); {result, IQRes} -> exmpp_iq:result(Packet, IQRes); {error, Error} -> @@ -895,6 +968,15 @@ do_route(ServerHost, Access, Plugins, Host, From, To, Packet) -> children = iq_get_vcard(Lang)}, Res = exmpp_iq:result(Packet, VCard), ejabberd_router:route(To, From, Res); + #iq{type = set, ns = ?NS_ADHOC} = IQ -> + Res = case iq_command(Host, ServerHost, From, IQ, Access, Plugins) of + {error, Error} -> + exmpp_iq:error(Packet, Error); + {result, IQRes} -> + exmpp_iq:result(Packet, IQRes) + end, + ejabberd_router:route(To, From, Res); + #iq{} -> Err = exmpp_iq:error(Packet, 'feature-not-implemented'), @@ -1096,7 +1178,7 @@ iq_get_vcard(Lang) -> iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang) -> iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, all, plugins(ServerHost)). -iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) -> +iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) -> WithoutCdata = exmpp_xml:remove_cdata_from_list(SubEl#xmlel.children), Configuration = lists:filter(fun(#xmlel{name = 'configure'}) -> true; (_) -> false @@ -1160,8 +1242,12 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) -> "item-required")} end; {set, 'subscribe'} -> + Config = case Configuration of + [#xmlel{name = 'configure', children = C}] -> C; + _ -> [] + end, JID = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'jid', ""), - subscribe_node(Host, Node, From, JID); + subscribe_node(Host, Node, From, JID, Config); {set, 'unsubscribe'} -> JID = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'jid', ""), SubId = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'subid', ""), @@ -1184,9 +1270,13 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) -> {get, 'affiliations'} -> get_affiliations(Host, From, Plugins); {get, "options"} -> - {error, extended_error('feature-not-implemented', unsupported, "subscription-options")}; + SubID = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'subid', ""), + JID = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'jid', ""), + get_options(Host, Node, JID, SubID, Lang); {set, "options"} -> - {error, extended_error('feature-not-implemented', unsupported, "subscription-options")}; + SubID = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'subid', ""), + JID = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'jid', ""), + set_options(Host, Node, JID, SubID, Els); _ -> {error, 'feature-not-implemented'} end; @@ -1231,6 +1321,146 @@ iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> {error, 'bad-request'} end. +iq_command(Host, ServerHost, From, IQ, Access, Plugins) -> + case adhoc:parse_request(IQ) of + Req when is_record(Req, adhoc_request) -> + case adhoc_request(Host, ServerHost, From, Req, Access, Plugins) of + Resp when is_record(Resp, adhoc_response) -> + {result, [adhoc:produce_response(Req, Resp)]}; + Error -> + Error + end; + Err -> + Err + end. + +%% @doc

    Processes an Ad Hoc Command.

    +adhoc_request(Host, _ServerHost, Owner, + #adhoc_request{node = ?NS_PUBSUB_GET_PENDING, + lang = Lang, + action = "execute", + xdata = false}, + _Access, Plugins) -> + send_pending_node_form(Host, Owner, Lang, Plugins); +adhoc_request(Host, _ServerHost, Owner, + #adhoc_request{node = ?NS_PUBSUB_GET_PENDING, + action = "execute", + xdata = XData}, + _Access, _Plugins) -> + ParseOptions = case XData of + #xmlel{name = 'x'} = XEl -> + case jlib:parse_xdata_submit(XEl) of + invalid -> + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'bad-request')}; + XData2 -> + case set_xoption(XData2, []) of + NewOpts when is_list(NewOpts) -> + {result, NewOpts}; + Err -> + Err + end + end; + _ -> + ?INFO_MSG("Bad XForm: ~p", [XData]), + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'bad-request')} + end, + case ParseOptions of + {result, XForm} -> + case lists:keysearch(node, 1, XForm) of + {value, {_, Node}} -> + send_pending_auth_events(Host, Node, Owner); + false -> + {error, extended_error('bad-request', "bad-payload")} + end; + Error -> + Error + end; +adhoc_request(_Host, _ServerHost, _Owner, Other, _Access, _Plugins) -> + ?DEBUG("Couldn't process ad hoc command:~n~p", [Other]), + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'item-not-found')}. + +%% @spec (Host, Owner, Lang, Plugins) -> iqRes() +%% @doc

    Sends the process pending subscriptions XForm for Host to +%% Owner.

    +send_pending_node_form(Host, Owner, _Lang, Plugins) -> + Filter = + fun (Plugin) -> + lists:member("get-pending", features(Plugin)) + end, + case lists:filter(Filter, Plugins) of + [] -> + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'feature-not-implemented')}; + Ps -> + XOpts = lists:map(fun (Node) -> + #xmlel{ns = ?NS_DATA_FORMS, name='option', + children = [ + #xmlel{ns = ?NS_DATA_FORMS, name = 'value', + children = [ + exmpp_xml:cdata(node_to_string(Node))]}]} + end, get_pending_nodes(Host, Owner, Ps)), + XForm = #xmlel{ns = ?NS_DATA_FORMS, name ='x', attrs = [?XMLATTR('type', <<"form">>)], + children = [ + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', + attrs = [?XMLATTR('type', <<"list-single">>), + ?XMLATTR('var', <<"pubsub#node">>)], + children = lists:usort(XOpts)}]}, + #adhoc_response{status = executing, + defaultaction = "execute", + elements = [XForm]} + end. + +get_pending_nodes(Host, Owner, Plugins) -> + Tr = + fun (Type) -> + case node_call(Type, get_pending_nodes, [Host, Owner]) of + {result, Nodes} -> Nodes; + _ -> [] + end + end, + case transaction(fun () -> {result, lists:flatmap(Tr, Plugins)} end, + sync_dirty) of + {result, Res} -> Res; + Err -> Err + end. + +%% @spec (Host, Node, Owner) -> iqRes() +%% @doc

    Send a subscription approval form to Owner for all pending +%% subscriptions on Host and Node.

    +send_pending_auth_events(Host, Node, Owner) -> + ?DEBUG("Sending pending auth events for ~s on ~s:~s", + [exmpp_jid:jid_to_string(Owner), Host, node_to_string(Node)]), + Action = + fun (#pubsub_node{id = NodeID, type = Type} = N) -> + case lists:member("get-pending", features(Type)) of + true -> + case node_call(Type, get_affiliation, [NodeID, Owner]) of + {result, owner} -> + broadcast_pending_auth_events(N), + {result, ok}; + _ -> + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'forbidden')} + end; + false -> + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'feature-not-implemented')} + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, _} -> + #adhoc_response{}; + Err -> + Err + end. + +broadcast_pending_auth_events(#pubsub_node{type = Type, id = NodeID} = Node) -> + {result, Subscriptions} = node_call(Type, get_node_subscriptions, [NodeID]), + lists:foreach(fun ({J, pending, _SubID}) -> + {U, S, R} = J, + send_authorization_request(Node, exmpp_jid:make(U,S,R)); + ({J, pending}) -> + {U, S, R} = J, + send_authorization_request(Node, exmpp_jid:make(U,S,R)) + end, Subscriptions). + %%% authorization handling send_authorization_request(#pubsub_node{owners = Owners, nodeid = {Host, Node}}, Subscriber) -> @@ -1261,7 +1491,8 @@ send_authorization_request(#pubsub_node{owners = Owners, nodeid = {Host, Node}}, ?XMLATTR('label', translate:translate(Lang, "Allow this Jabber ID to subscribe to this pubsub node?"))], children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"false">>}]}]}]}]}, lists:foreach(fun(Owner) -> - ejabberd_router ! {route, service_jid(Host), jlib:make_jid(Owner), Stanza} + {U, S, R} = Owner, + ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza} end, Owners). find_authorization_response(Packet) -> @@ -1322,19 +1553,14 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> end, Action = fun(#pubsub_node{type = Type, id = NodeId, owners = Owners}) -> IsApprover = lists:member(jlib:short_prepd_bare_jid(From), Owners), - {result, Subscription} = node_call(Type, get_subscription, [NodeId, Subscriber]), + {result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]), if not IsApprover -> {error, 'forbidden'}; - Subscription /= pending -> - {error, 'unexpected-request'}; true -> - NewSubscription = case Allow of - true -> subscribed; - false -> none - end, - send_authorization_approval(Host, Subscriber, SNode, NewSubscription), - node_call(Type, set_subscription, [NodeId, Subscriber, NewSubscription]) + update_auth(Host, SNode, Type, NodeId, + Subscriber, Allow, + Subscriptions) end end, case transaction(Host, Node, Action, sync_dirty) of @@ -1356,6 +1582,26 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> exmpp_stanza:reply_with_error(Packet, 'not-acceptable')) end. +update_auth(Host, Node, Type, NodeId, Subscriber, + Allow, Subscriptions) -> + Subscription = lists:filter(fun({pending, _}) -> true; + (_) -> false + end, Subscriptions), + case Subscription of + [{pending, SubID}] -> %% TODO does not work if several pending + NewSubscription = case Allow of + true -> subscribed; + false -> none + end, + node_call(Type, set_subscriptions, + [NodeId, Subscriber, NewSubscription, SubID]), + send_authorization_approval(Host, Subscriber, Node, + NewSubscription), + {result, ok}; + _ -> + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'unexpected-request')} + end. + -define(XFIELD(Type, Label, Var, Val), #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', Type), ?XMLATTR('label', translate:translate(Lang, Label)), @@ -1372,6 +1618,16 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> -define(STRINGXFIELD(Label, Var, Val), ?XFIELD("text-single", Label, Var, Val)). +-define(STRINGMXFIELD(Label, Var, Vals), + #xmlel{ns = ?NS_DATA_FORMS, + name = 'field', + attrs = [?XMLATTR('type', <<"text-multi">>), + ?XMLATTR('label', translate:translate(Lang, Label)), + ?XMLATTR('var', Var) + ], + children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', + children = [?XMLCDATA(V)]} || V <- Vals]}). + -define(XFIELDOPT(Type, Label, Var, Val, Opts), #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', Type), ?XMLATTR('label', translate:translate(Lang, Label)), @@ -1387,7 +1643,7 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> ?XFIELDOPT("list-single", Label, Var, Val, Opts)). -define(LISTMXFIELD(Label, Var, Vals, Opts), - #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', Type), + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', <<"list-multi">>), ?XMLATTR('label', translate:translate(Lang, Label)), ?XMLATTR('var', Var)], children = lists:map(fun(Opt) -> @@ -1484,8 +1740,8 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> {error, 'forbidden'} end end, - Reply = [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = - [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(Node)}]}], + Reply = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(Node)}]}, case transaction(CreateNode, transaction) of {result, {Result, broadcast}} -> %%Lang = "en", %% TODO: fix @@ -1567,7 +1823,7 @@ delete_node(Host, Node, Owner) -> Error end. -%% @spec (Host, Node, From, JID) -> +%% @spec (Host, Node, From, JID, Configuration) -> %% {error, Reason::stanzaError()} | %% {result, []} %% Host = host() @@ -1589,7 +1845,8 @@ delete_node(Host, Node, Owner) -> %%
  • The node does not support subscriptions.
  • %%
  • The node does not exist.
  • %% -subscribe_node(Host, Node, From, JID) -> +subscribe_node(Host, Node, From, JID, Configuration) -> + {result, SubOpts} = pubsub_subscription:parse_options_xform(Configuration), Subscriber = try jlib:short_prepd_jid(exmpp_jid:parse(JID)) catch @@ -1600,6 +1857,8 @@ subscribe_node(Host, Node, From, JID) -> Action = fun(#pubsub_node{options = Options, owners = [Owner|_], type = Type, id = NodeId}) -> Features = features(Type), SubscribeFeature = lists:member("subscribe", Features), + OptionsFeature = lists:member("subscription-options", Features), + HasOptions = not (SubOpts == []), SubscribeConfig = get_option(Options, subscribe), AccessModel = get_option(Options, access_model), SendLast = get_option(Options, send_last_published_item), @@ -1626,11 +1885,15 @@ subscribe_node(Host, Node, From, JID) -> not SubscribeConfig -> %% Node does not support subscriptions {error, extended_error('feature-not-implemented', unsupported, "subscribe")}; + HasOptions andalso not OptionsFeature -> + %% Node does not support subscription options + {error, extended_error('feature-not-implemented', unsupported, "subscription-options")}; true -> node_call(Type, subscribe_node, [NodeId, From, Subscriber, AccessModel, SendLast, - PresenceSubscription, RosterGroup]) + PresenceSubscription, RosterGroup, + SubOpts]) end end, Reply = fun(Subscription) -> @@ -1639,12 +1902,12 @@ subscribe_node(Host, Node, From, JID) -> [?XMLATTR('node', node_to_string(Node)), ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), ?XMLATTR('subscription', subscription_to_string(Subscription))], - [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = case Subscription of subscribed -> [?XMLATTR('subid', SubId)|Fields]; _ -> Fields - end}]}] + end}]} end, case transaction(Host, Node, Action, sync_dirty) of {result, {TNode, {Result, subscribed, send_last}}} -> @@ -1761,9 +2024,9 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> end end, ejabberd_hooks:run(pubsub_publish_item, ServerHost, [ServerHost, Node, Publisher, service_jid(Host), ItemId, Payload]), - Reply = [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + Reply = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'publish', attrs = nodeAttr(Node), children = - [#xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = itemAttr(ItemId)}]}]}], + [#xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = itemAttr(ItemId)}]}]}, case transaction(Host, Node, Action, sync_dirty) of {result, {TNode, {Result, broadcast, Removed}}} -> NodeId = TNode#pubsub_node.id, @@ -1988,9 +2251,9 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> end, %% Generate the XML response (Item list), limiting the %% number of items sent to MaxItems: - {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + {result, #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = nodeAttr(Node), children = - itemsEls(lists:sublist(SendItems, MaxItems))}]}]}; + itemsEls(lists:sublist(SendItems, MaxItems))}]}}; Error -> Error end @@ -2027,9 +2290,10 @@ send_items(Host, Node, NodeId, Type, LJID, last) -> send_items(Host, Node, NodeId, Type, LJID, 1); LastItem -> Stanza = event_stanza( - [{xmlelement, "items", nodeAttr(Node), - itemsEls([LastItem])}]), - ejabberd_router ! {route, service_jid(Host), jlib:make_jid(LJID), Stanza} + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), + children = itemsEls(LastItem)}]), + {U, S, R} = LJID, + ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza} end; send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of @@ -2078,9 +2342,9 @@ get_affiliations(Host, JID, Plugins) when is_list(Plugins) -> [?XMLATTR('node', node_to_string(Node)), ?XMLATTR('affiliation', affiliation_to_string(Affiliation))]}] end, lists:usort(lists:flatten(Affiliations))), - {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + {result, #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'affiliations', children = - Entities}]}]}; + Entities}]}}; {Error, _} -> Error end; @@ -2111,9 +2375,9 @@ get_affiliations(Host, Node, JID) -> [?XMLATTR('jid', exmpp_jid:to_binary(AU, AS, AR)), ?XMLATTR('affiliation', affiliation_to_string(Affiliation))]}] end, Affiliations), - {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = + {result, #xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'affiliations', attrs = nodeAttr(Node), children = - Entities}]}]}; + Entities}]}}; Error -> Error end. @@ -2186,6 +2450,106 @@ set_affiliations(Host, Node, From, EntitiesEls) -> end end. +get_options(Host, Node, JID, SubID, Lang) -> + Action = fun(#pubsub_node{type = Type, id = NodeID}) -> + case lists:member("subscription-options", features(Type)) of + true -> + get_options_helper(JID, Lang, NodeID, SubID, Type); + false -> + {error, extended_error( + 'feature-not-implemented', + unsupported, "subscription-options")} + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_Node, XForm}} -> {result, [XForm]}; + Error -> Error + end. + +get_options_helper(JID, Lang, NodeID, SubID, Type) -> + Subscriber = try exmpp_jid:parse(JID) of + J -> jlib:short_jid(J) + catch + _ -> + {"", "", ""} %%pablo TODO: "" or <<>> ?. short_jid uses exmpp_jid:node/1, etc. that returns binaries + end, + {result, Subs} = node_call(Type, get_subscriptions, + [NodeID, Subscriber]), + SubIDs = lists:foldl(fun({subscribed, SID}, Acc) -> + [SID | Acc]; + (_, Acc) -> + Acc + end, [], Subs), + case {SubID, SubIDs} of + {_, []} -> + {error, extended_error('not-acceptable', "not-subscribed")}; + {[], [SID]} -> + read_sub(Subscriber, NodeID, SID, Lang); + {[], _} -> + {error, extended_error('not-acceptable', "subid-required")}; + {_, _} -> + read_sub(Subscriber, NodeID, SubID, Lang) + end. + +read_sub(Subscriber, NodeID, SubID, Lang) -> + case pubsub_subscription:get_subscription(Subscriber, NodeID, SubID) of + {error, notfound} -> + {error, extended_error('not-acceptable', "invalid-subid")}; + {result, #pubsub_subscription{options = Options}} -> + pubsub_subscription:get_options_xform(Lang, Options) + end. + +set_options(Host, Node, JID, SubID, Configuration) -> + Action = fun(#pubsub_node{type = Type, id = NodeID}) -> + case lists:member("subscription-options", features(Type)) of + true -> + set_options_helper(Configuration, JID, NodeID, + SubID, Type); + false -> + {error, extended_error( + 'feature-not-implemented', + unsupported, "subscription-options")} + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_Node, Result}} -> {result, Result}; + Error -> Error + end. + +set_options_helper(Configuration, JID, NodeID, SubID, Type) -> + Subscriber = try exmpp_jid:parse(JID) of + J -> jlib:short_jid(J) + catch + _ -> + {"", "", ""} %%pablo TODO: "" or <<>> ?. short_jid uses exmpp_jid:node/1, etc. that returns binaries + end, + {result, SubOpts} = pubsub_subscription:parse_options_xform(Configuration), + {result, Subs} = node_call(Type, get_subscriptions, + [NodeID, Subscriber]), + SubIDs = lists:foldl(fun({subscribed, SID}, Acc) -> + [SID | Acc]; + (_, Acc) -> + Acc + end, [], Subs), + case {SubID, SubIDs} of + {_, []} -> + {error, extended_error('not-acceptable', "not-subscribed")}; + {[], [SID]} -> + write_sub(Subscriber, NodeID, SID, SubOpts); + {[], _} -> + {error, extended_error('not-acceptable', "subid-required")}; + {_, _} -> + write_sub(Subscriber, NodeID, SubID, SubOpts) + end. + +write_sub(Subscriber, NodeID, SubID, Options) -> + case pubsub_subscription:set_subscription(Subscriber, NodeID, SubID, + Options) of + {error, notfound} -> + {error, extended_error('not-acceptable', "invalid-subid")}; + {result, _} -> + {result, []} + end. %% @spec (Host, Node, JID, Plugins) -> {error, Reason} | {result, Response} %% Host = host() @@ -2205,7 +2569,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> %% Service does not support retreive subscriptions {{error, extended_error('feature-not-implemented', unsupported, "retrieve-subscriptions")}, Acc}; true -> - Subscriber = jlib:jid_remove_resource(JID), + Subscriber = exmpp_jid:bare(JID), {result, Subscriptions} = node_action(Host, Type, get_entity_subscriptions, [Host, Subscriber]), {Status, [Subscriptions|Acc]} end @@ -2229,6 +2593,21 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> end; ({_, none, _}) -> []; + ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubID, SubJID}) -> + case Node of + [] -> + [#xmlel{ns = ?NS_PUBSUB, name='subscription', + attrs = [?XMLATTR('jid', exmpp_jid:jid_to_binary(SubJID)), + ?XMLATTR('subid', SubID), + ?XMLATTR('subscription', subscription_to_string(Subscription)) | nodeAttr(SubsNode)]}]; + SubsNode -> + [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', + attrs = [?XMLATTR('jid', exmpp_jid:jid_to_binary(SubJID)), + ?XMLATTR('subid', SubID), + ?XMLATTR('subscription', subscription_to_string(Subscription))]}]; + _ -> + [] + end; ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubJID}) -> case Node of [] -> @@ -2244,9 +2623,9 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> [] end end, lists:usort(lists:flatten(Subscriptions))), - {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + {result, #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'subscriptions', children = - Entities}]}]}; + Entities}]}}; {Error, _} -> Error end. @@ -2282,9 +2661,9 @@ get_subscriptions(Host, Node, JID) -> ?XMLATTR('subscription', subscription_to_string(Subscription)), ?XMLATTR('subid', SubId)]}] end, Subscriptions), - {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = + {result, #xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscriptions', attrs = nodeAttr(Node), children = - Entities}]}]}; + Entities}]}}; Error -> Error end. @@ -2345,9 +2724,10 @@ set_subscriptions(Host, Node, From, EntitiesEls) -> %% @spec (OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, SubscriberResource}, AllowedGroups) %% -> {PresenceSubscription, RosterGroup} get_roster_info(OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, _}, AllowedGroups) -> + OwnerServerB = list_to_binary(OwnerServer), {Subscription, Groups} = ejabberd_hooks:run_fold( - roster_get_jid_info, OwnerServer, + roster_get_jid_info, OwnerServerB, {none, []}, [OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, undefined}]), PresenceSubscription = (Subscription == both) orelse (Subscription == from) @@ -2419,20 +2799,42 @@ service_jid(Host) -> _ -> exmpp_jid:make(Host) end. -%% @spec (LJID, Subscription, PresenceDelivery) -> boolean() +%% @spec (LJID, PresenceDelivery) -> boolean() %% LJID = jid() -%% Subscription = atom() -%% PresenceDelivery = boolean() -%% @doc

    Check if a notification must be delivered or not.

    -is_to_deliver(_, none, _) -> false; -is_to_deliver(_, pending, _) -> false; -is_to_deliver(_, _, false) -> true; -is_to_deliver({User, Server, _}, _, true) -> +%% NotifyType = items | nodes +%% Depth = integer() +%% NodeOptions = [{atom(), term()}] +%% SubOptions = [{atom(), term()}] +%% @doc

    Check if a notification must be delivered or not based on +%% node and subscription options.

    +is_to_deliver(LJID, NotifyType, Depth, NodeOptions, SubOptions) -> + sub_to_deliver(LJID, NotifyType, Depth, SubOptions) + andalso node_to_deliver(LJID, NodeOptions). + +sub_to_deliver(_LJID, NotifyType, Depth, SubOptions) -> + lists:all(fun (Option) -> + sub_option_can_deliver(NotifyType, Depth, Option) + end, SubOptions). + +sub_option_can_deliver(items, _, {subscription_type, nodes}) -> false; +sub_option_can_deliver(nodes, _, {subscription_type, items}) -> false; +sub_option_can_deliver(_, _, {subscription_depth, all}) -> true; +sub_option_can_deliver(_, Depth, {subscription_depth, D}) -> Depth =< D; +sub_option_can_deliver(_, _, {deliver, false}) -> false; +sub_option_can_deliver(_, _, {expire, When}) -> now() < When; +sub_option_can_deliver(_, _, _) -> true. + +node_to_deliver(LJID, NodeOptions) -> + PresenceDelivery = get_option(NodeOptions, presence_based_delivery), + presence_can_deliver(LJID, PresenceDelivery). + +presence_can_deliver(_, false) -> true; +presence_can_deliver({User, Server, _}, true) -> case mnesia:dirty_match_object({session, '_', '_', {User, Server}, '_', '_'}) of [] -> false; Ss -> lists:foldl(fun({session, _, _, _, undefined, _}, Acc) -> Acc; - ({session, _, _, _, _Priority, _}, _Acc) -> true + ({session, _, _, _, _Priority, _}, _Acc) -> true end, false, Ss) end. @@ -2455,10 +2857,11 @@ event_stanza(Els) -> broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, _From, Payload) -> %broadcast(Host, Node, NodeId, Options, none, true, 'items', ItemEls) - case node_action(Host, Type, get_node_subscriptions, [NodeId]) of - {result, []} -> + case get_collection_subscriptions(Host, Node) of + [] -> {result, false}; - {result, Subs} -> + + SubsByDepth when is_list(SubsByDepth) -> Content = case get_option(Options, deliver_payloads) of true -> Payload; false -> [] @@ -2466,7 +2869,7 @@ broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, _From Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = itemAttr(ItemId), children = Content}]}]), - broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza), + broadcast_stanza(Host, Node, NodeId, Type, Options, SubsByDepth, items, Stanza), case Removed of [] -> ok; @@ -2476,7 +2879,7 @@ broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, _From RetractStanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = itemAttr(RId)} || RId <- Removed]}]), - broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, RetractStanza); + broadcast_stanza(Host, Node, NodeId, Type, Options, SubsByDepth, items, RetractStanza); _ -> ok end @@ -2494,14 +2897,15 @@ broadcast_retract_items(Host, Node, NodeId, Type, Options, ItemIds, ForceNotify) %broadcast(Host, Node, NodeId, Options, notify_retract, ForceNotify, 'retract', RetractEls) case (get_option(Options, notify_retract) or ForceNotify) of true -> - case node_action(Host, Type, get_node_subscriptions, [NodeId]) of - {result, []} -> + case get_collection_subscriptions(Host, Node) of + [] -> {result, false}; - {result, Subs} -> + + SubsByDepth when is_list(SubsByDepth)-> Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = itemAttr(ItemId)} || ItemId <- ItemIds]}]), - broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza), + broadcast_stanza(Host, Node, NodeId, Type, Options, SubsByDepth, items, Stanza), {result, true}; _ -> {result, false} @@ -2514,13 +2918,13 @@ broadcast_purge_node(Host, Node, NodeId, Type, Options) -> %broadcast(Host, Node, NodeId, Options, notify_retract, false, 'purge', []) case get_option(Options, notify_retract) of true -> - case node_action(Host, Type, get_node_subscriptions, [NodeId]) of - {result, []} -> + case get_collection_subscriptions(Host, Node) of + [] -> {result, false}; - {result, Subs} -> + SubsByDepth when is_list(SubsByDepth) -> Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'purge', attrs = nodeAttr(Node)}]), - broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza), + broadcast_stanza(Host, Node, NodeId, Type, Options, SubsByDepth, nodes, Stanza), {result, true}; _ -> {result, false} @@ -2539,7 +2943,7 @@ broadcast_removed_node(Host, Node, NodeId, Type, Options, Subs) -> _ -> Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'delete', attrs = nodeAttr(Node)}]), - broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza), + broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, nodes, Stanza), {result, true} end; _ -> @@ -2550,10 +2954,10 @@ broadcast_config_notification(Host, Node, NodeId, Type, Options, Lang) -> %broadcast(Host, Node, NodeId, Options, notify_config, false, 'items', ConfigEls) case get_option(Options, notify_config) of true -> - case node_action(Host, Type, get_node_subscriptions, [NodeId]) of - {result, []} -> + case get_collection_subscriptions(Host, Node) of + [] -> {result, false}; - {result, Subs} -> + SubsByDepth when is_list(SubsByDepth) -> Content = case get_option(Options, deliver_payloads) of true -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = @@ -2565,7 +2969,7 @@ broadcast_config_notification(Host, Node, NodeId, Type, Options, Lang) -> [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = [?XMLATTR('id', <<"configuration">>)], children = Content}]}]), - broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza), + broadcast_stanza(Host, Node, NodeId, Type, Options, SubsByDepth, nodes, Stanza), {result, true}; _ -> {result, false} @@ -2574,6 +2978,28 @@ broadcast_config_notification(Host, Node, NodeId, Type, Options, Lang) -> {result, false} end. +get_collection_subscriptions(Host, Node) -> + lists:map(fun ({Depth, Nodes}) -> + {Depth, [{N, get_node_subs(N)} || N <- Nodes]} + end, tree_action(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)])). + +get_node_subs(#pubsub_node{type = Type, + nodeid = {Host, Node}, + id = NodeID}) -> + case node_action(Host, Type, get_node_subscriptions, [NodeID]) of + {result, Subs} -> + get_options_for_subs(Host, Node, NodeID, Subs); + Other -> + Other + end. + +get_options_for_subs(_Host, Node, NodeID, Subs) -> + lists:foldl(fun({JID, subscribed, SubID}, Acc) -> + {result, #pubsub_subscription{options = Options}} = pubsub_subscription:get_subscription(JID, NodeID, SubID), + [{JID, Node, Options} | Acc]; + (_, Acc) -> + Acc + end, [], Subs). % TODO: merge broadcast code that way %broadcast(Host, Node, NodeId, Type, Options, Feature, Force, ElName, SubEls) -> @@ -2593,29 +3019,27 @@ broadcast_config_notification(Host, Node, NodeId, Type, Options, Lang) -> % {result, false} % end -broadcast_stanza(Host, Node, _NodeId, _Type, Options, Subscriptions, Stanza) -> - %AccessModel = get_option(Options, access_model), - PresenceDelivery = get_option(Options, presence_based_delivery), - BroadcastAll = get_option(Options, broadcast_all_resources), %% XXX this is not standard, but usefull +broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyType, Stanza) -> + %AccessModel = get_option(NodeOptions, access_model), + BroadcastAll = get_option(NodeOptions, broadcast_all_resources), %% XXX this is not standard, but usefull From = service_jid(Host), %% Handles explicit subscriptions - lists:foreach(fun({LJID, Subscription}) -> - case is_to_deliver(LJID, Subscription, PresenceDelivery) of - true -> - LJIDs = case BroadcastAll of - true -> - {U, S, _} = LJID, - [{U, S, R} || R <- user_resources(U, S)]; - false -> - [LJID] - end, - lists:foreach(fun(To) -> - ejabberd_router ! {route, From, jlib:make_jid(To), Stanza} - end, LJIDs); - false -> - ok - end - end, Subscriptions), + FilteredSubsByDepth = depths_to_deliver(NotifyType, SubsByDepth), + NodesByJID = collate_subs_by_jid(FilteredSubsByDepth), + lists:foreach(fun ({LJID, Nodes}) -> + LJIDs = case BroadcastAll of + true -> + {U, S, _} = LJID, + [{U, S, R} || R <- user_resources(U, S)]; + false -> + [LJID] + end, + SHIMStanza = add_headers(Stanza, collection_shim(Node, Nodes)), + lists:foreach(fun(To) -> + {TU, TS, TR} = To, + ejabberd_router ! {route, From, exmpp_jid:make(TU, TS, TR), SHIMStanza} + end, LJIDs) + end, NodesByJID), %% Handles implicit presence subscriptions case Host of {LUser, LServer, LResource} -> @@ -2661,6 +3085,37 @@ broadcast_stanza(Host, Node, _NodeId, _Type, Options, Subscriptions, Stanza) -> _ -> ok end. + +depths_to_deliver(NotifyType, SubsByDepth) -> + NodesToDeliver = + fun (Depth, Node, Subs, Acc) -> + lists:foldl(fun ({LJID, _Node, SubOptions} = S, Acc2) -> + case is_to_deliver(LJID, NotifyType, Depth, + Node#pubsub_node.options, + SubOptions) of + true -> [S | Acc2]; + false -> Acc2 + end + end, Acc, Subs) + end, + + DepthsToDeliver = + fun ({Depth, SubsByNode}, Acc) -> + lists:foldl(fun ({Node, Subs}, Acc2) -> + NodesToDeliver(Depth, Node, Subs, Acc2) + end, Acc, SubsByNode) + end, + + lists:foldl(DepthsToDeliver, [], SubsByDepth). + +collate_subs_by_jid(SubsByDepth) -> + lists:foldl(fun ({JID, Node, _Options}, Acc) -> + OldNodes = case lists:keysearch(JID, 1, Acc) of + {value, {JID, Nodes}} -> Nodes; + false -> [] + end, + lists:keystore(JID, 1, Acc, {JID, [Node | OldNodes]}) + end, [], SubsByDepth). %% If we don't know the resource, just pick first if any %% If no resource available, check if caps anyway (remote online) @@ -2689,19 +3144,20 @@ is_caps_notify(Host, Node, LJID) -> %%
  • The service does not support retrieval of default node configuration.
  • %% get_configure(Host, ServerHost, Node, From, Lang) -> + ServerHostB = list_to_binary(ServerHost), Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> case node_call(Type, get_affiliation, [NodeId, From]) of {result, owner} -> - Groups = ejabberd_hooks:run_fold(roster_groups, ServerHost, [], [ServerHost]), + Groups = ejabberd_hooks:run_fold(roster_groups, ServerHostB, [], [ServerHostB]), {result, - [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = + #xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'configure', attrs = nodeAttr(Node), children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = get_configure_xfields(Type, Options, Lang, Groups) - }]}]}]}; + }]}]}}; _ -> {error, 'forbidden'} end @@ -2714,11 +3170,11 @@ get_configure(Host, ServerHost, Node, From, Lang) -> get_default(Host, Node, _From, Lang) -> Type = select_type(Host, Host, Node), Options = node_options(Type), - {result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = + {result, #xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'default', children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = get_configure_xfields(Type, Options, Lang, []) - }]}]}]}. + }]}]}}. %% Get node option %% The result depend of the node type plugin system. @@ -2793,7 +3249,11 @@ max_items(Options) -> ?LISTMXFIELD(Label, "pubsub#" ++ atom_to_list(Var), get_option(Options, Var), Opts)). -get_configure_xfields(Type, Options, Lang, Groups) -> +-define(NLIST_CONFIG_FIELD(Label, Var), + ?STRINGMXFIELD(Label, "pubsub#" ++ atom_to_list(Var), + [node_to_string(N) || N <- get_option(Options, Var, [])])). + +get_configure_xfields(_Type, Options, Lang, Groups) -> [?XFIELD("hidden", "", "FORM_TYPE", ?NS_PUBSUB_NODE_CONFIG_s), ?BOOL_CONFIG_FIELD("Deliver payloads with event notifications", deliver_payloads), ?BOOL_CONFIG_FIELD("Deliver event notifications", deliver_notifications), @@ -2813,7 +3273,8 @@ get_configure_xfields(Type, Options, Lang, Groups) -> ?INTEGER_CONFIG_FIELD("Max payload size in bytes", max_payload_size), ?ALIST_CONFIG_FIELD("When to send the last published item", send_last_published_item, [never, on_sub, on_sub_and_presence]), - ?BOOL_CONFIG_FIELD("Only deliver notifications to available users", presence_based_delivery) + ?BOOL_CONFIG_FIELD("Only deliver notifications to available users", presence_based_delivery), + ?NLIST_CONFIG_FIELD("The collections with which a node is affiliated", collection) ]. %%

    There are several reasons why the node configuration request might fail:

    @@ -2991,8 +3452,9 @@ get_cached_item(Host, NodeId) -> end. %%%% plugin handling - -plugins(Host) -> +plugins(Host) when is_binary(Host) -> + plugins(binary_to_list(Host)); +plugins(Host) when is_list(Host) -> case ets:lookup(gen_mod:get_module_proc(Host, config), plugins) of [{plugins, []}] -> [?STDNODE]; [{plugins, PL}] -> PL; @@ -3180,3 +3642,12 @@ itemsEls(Items) -> lists:map(fun(#pubsub_item{itemid = {ItemId, _}, payload = Payload}) -> #xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = itemAttr(ItemId), children = Payload} end, Items). + +add_headers(#xmlel{} = El, Headers) -> + exmpp_xml:append_children(El, Headers). + +collection_shim(Node, Nodes) -> + [#xmlel{ns = ?NS_PUBSUB, name ='header', + attrs = [?XMLATTR('name', <<"Collection">>)], + children = [ ?XMLCDATA(node_to_string(N))] + } || N <- Nodes -- [Node]]. diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl index 11d17e78a..2031fe9db 100644 --- a/src/mod_pubsub/node_buddy.erl +++ b/src/mod_pubsub/node_buddy.erl @@ -47,7 +47,7 @@ create_node/2, delete_node/1, purge_node/2, - subscribe_node/7, + subscribe_node/8, unsubscribe_node/4, publish_item/6, delete_item/4, @@ -58,8 +58,9 @@ set_affiliation/3, get_entity_subscriptions/2, get_node_subscriptions/1, - get_subscription/2, - set_subscription/3, + get_subscriptions/2, + set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -79,8 +80,7 @@ terminate(Host, ServerHost) -> node_hometree:terminate(Host, ServerHost). options() -> - [{node_type, buddy}, - {deliver_payloads, true}, + [{deliver_payloads, true}, {notify_config, false}, {notify_delete, false}, {notify_retract, true}, @@ -122,8 +122,8 @@ create_node(NodeId, Owner) -> delete_node(Removed) -> node_hometree:delete_node(Removed). -subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). +subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options) -> + node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options). unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> node_hometree:unsubscribe_node(NodeId, Sender, Subscriber, SubID). @@ -158,11 +158,15 @@ get_entity_subscriptions(Host, Owner) -> get_node_subscriptions(NodeId) -> node_hometree:get_node_subscriptions(NodeId). -get_subscription(NodeId, Owner) -> - node_hometree:get_subscription(NodeId, Owner). +get_subscriptions(NodeId, Owner) -> + node_hometree:get_subscriptions(NodeId, Owner). + +set_subscriptions(NodeId, Owner, Subscription, SubId) -> + node_hometree:set_subscriptions(NodeId, Owner, Subscription, SubId). + +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). -set_subscription(NodeId, Owner, Subscription) -> - node_hometree:set_subscription(NodeId, Owner, Subscription). get_states(NodeId) -> node_hometree:get_states(NodeId). diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl index 9d92365ee..20c4bdf6b 100644 --- a/src/mod_pubsub/node_club.erl +++ b/src/mod_pubsub/node_club.erl @@ -26,9 +26,8 @@ -module(node_club). -author('christophe.romain@process-one.net'). --include_lib("exmpp/include/exmpp.hrl"). - -include("pubsub.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). -behaviour(gen_pubsub_node). @@ -47,7 +46,7 @@ create_node/2, delete_node/1, purge_node/2, - subscribe_node/7, + subscribe_node/8, unsubscribe_node/4, publish_item/6, delete_item/4, @@ -58,8 +57,9 @@ set_affiliation/3, get_entity_subscriptions/2, get_node_subscriptions/1, - get_subscription/2, - set_subscription/3, + get_subscriptions/2, + set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -79,8 +79,7 @@ terminate(Host, ServerHost) -> node_hometree:terminate(Host, ServerHost). options() -> - [{node_type, club}, - {deliver_payloads, true}, + [{deliver_payloads, true}, {notify_config, false}, {notify_delete, false}, {notify_retract, true}, @@ -121,8 +120,8 @@ create_node(NodeId, Owner) -> delete_node(Removed) -> node_hometree:delete_node(Removed). -subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). +subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options) -> + node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options). unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> node_hometree:unsubscribe_node(NodeId, Sender, Subscriber, SubID). @@ -157,11 +156,14 @@ get_entity_subscriptions(Host, Owner) -> get_node_subscriptions(NodeId) -> node_hometree:get_node_subscriptions(NodeId). -get_subscription(NodeId, Owner) -> - node_hometree:get_subscription(NodeId, Owner). +get_subscriptions(NodeId, Owner) -> + node_hometree:get_subscriptions(NodeId, Owner). -set_subscription(NodeId, Owner, Subscription) -> - node_hometree:set_subscription(NodeId, Owner, Subscription). +set_subscriptions(NodeId, Owner, Subscription, SubId) -> + node_hometree:set_subscriptions(NodeId, Owner, Subscription, SubId). + +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). get_states(NodeId) -> node_hometree:get_states(NodeId). diff --git a/src/mod_pubsub/node_dag.erl b/src/mod_pubsub/node_dag.erl new file mode 100644 index 000000000..df654433e --- /dev/null +++ b/src/mod_pubsub/node_dag.erl @@ -0,0 +1,175 @@ +%%% ==================================================================== +%%% ``The contents of this file are subject to the Erlang Public License, +%%% Version 1.1, (the "License"); you may not use this file except in +%%% compliance with the License. You should have received a copy of the +%%% Erlang Public License along with this software. If not, it can be +%%% retrieved via the world wide web at http://www.erlang.org/. +%%% +%%% Software distributed under the License is distributed on an "AS IS" +%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%%% the License for the specific language governing rights and limitations +%%% under the License. +%%% +%%% @author Brian Cully +%%% @version {@vsn}, {@date} {@time} +%%% @end +%%% ==================================================================== + +-module(node_dag). +-author('bjc@kublai.com'). + +-include("pubsub.hrl"). +-include("jlib.hrl"). + +-behaviour(gen_pubsub_node). + +%% API definition +-export([init/3, terminate/2, + options/0, features/0, + create_node_permission/6, + create_node/2, + delete_node/1, + purge_node/2, + subscribe_node/8, + unsubscribe_node/4, + publish_item/6, + delete_item/4, + remove_extra_items/3, + get_entity_affiliations/2, + get_node_affiliations/1, + get_affiliation/2, + set_affiliation/3, + get_entity_subscriptions/2, + get_node_subscriptions/1, + get_subscriptions/2, + set_subscriptions/4, + get_pending_nodes/2, + get_states/1, + get_state/2, + set_state/1, + get_items/6, + get_items/2, + get_item/7, + get_item/2, + set_item/1, + get_item_name/3]). + + +init(Host, ServerHost, Opts) -> + node_hometree:init(Host, ServerHost, Opts). + +terminate(Host, ServerHost) -> + node_hometree:terminate(Host, ServerHost). + +options() -> + [{node_type, leaf} | node_hometree:options()]. + +features() -> + ["multi-collection" | node_hometree:features()]. + +create_node_permission(_Host, _ServerHost, _Node, _ParentNode, + _Owner, _Access) -> + {result, true}. + +create_node(NodeID, Owner) -> + node_hometree:create_node(NodeID, Owner). + +delete_node(Removed) -> + node_hometree:delete_node(Removed). + +subscribe_node(NodeID, Sender, Subscriber, AccessModel, + SendLast, PresenceSubscription, RosterGroup, Options) -> + node_hometree:subscribe_node(NodeID, Sender, Subscriber, AccessModel, + SendLast, PresenceSubscription, RosterGroup, + Options). + +unsubscribe_node(NodeID, Sender, Subscriber, SubID) -> + node_hometree:unsubscribe_node(NodeID, Sender, Subscriber, SubID). + +publish_item(NodeID, Publisher, Model, MaxItems, ItemID, Payload) -> + %% TODO: should look up the NodeTree plugin here. There's no + %% access to the Host of the request at this level, so for now we + %% just use nodetree_dag. + case nodetree_dag:get_node(NodeID) of + #pubsub_node{options = Options} -> + case find_opt(node_type, Options) of + collection -> + {error, mod_pubsub:extended_error('not-allowed', "publish")}; + _ -> + node_hometree:publish_item(NodeID, Publisher, Model, + MaxItems, ItemID, Payload) + end; + Err -> + Err + end. + +find_opt(_, []) -> false; +find_opt(Option, [{Option, Value} | _]) -> Value; +find_opt(Option, [_ | T]) -> find_opt(Option, T). + +remove_extra_items(NodeID, MaxItems, ItemIDs) -> + node_hometree:remove_extra_items(NodeID, MaxItems, ItemIDs). + +delete_item(NodeID, Publisher, PublishModel, ItemID) -> + node_hometree:delete_item(NodeID, Publisher, PublishModel, ItemID). + +purge_node(NodeID, Owner) -> + node_hometree:purge_node(NodeID, Owner). + +get_entity_affiliations(Host, Owner) -> + node_hometree:get_entity_affiliations(Host, Owner). + +get_node_affiliations(NodeID) -> + node_hometree:get_node_affiliations(NodeID). + +get_affiliation(NodeID, Owner) -> + node_hometree:get_affiliation(NodeID, Owner). + +set_affiliation(NodeID, Owner, Affiliation) -> + node_hometree:set_affiliation(NodeID, Owner, Affiliation). + +get_entity_subscriptions(Host, Owner) -> + node_hometree:get_entity_subscriptions(Host, Owner). + +get_node_subscriptions(NodeID) -> + node_hometree:get_node_subscriptions(NodeID). + +get_subscriptions(NodeID, Owner) -> + node_hometree:get_subscriptions(NodeID, Owner). + +set_subscriptions(NodeID, Owner, Subscription, SubID) -> + node_hometree:set_subscriptions(NodeID, Owner, Subscription, SubID). + +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). + +get_states(NodeID) -> + node_hometree:get_states(NodeID). + +get_state(NodeID, JID) -> + node_hometree:get_state(NodeID, JID). + +set_state(State) -> + node_hometree:set_state(State). + +get_items(NodeID, From) -> + node_hometree:get_items(NodeID, From). + +get_items(NodeID, JID, AccessModel, PresenceSubscription, + RosterGroup, SubID) -> + node_hometree:get_items(NodeID, JID, AccessModel, PresenceSubscription, + RosterGroup, SubID). + +get_item(NodeID, ItemID) -> + node_hometree:get_item(NodeID, ItemID). + +get_item(NodeID, ItemID, JID, AccessModel, PresenceSubscription, + RosterGroup, SubID) -> + node_hometree:get_item(NodeID, ItemID, JID, AccessModel, + PresenceSubscription, RosterGroup, SubID). + +set_item(Item) -> + node_hometree:set_item(Item). + +get_item_name(Host, Node, ID) -> + node_hometree:get_item_name(Host, Node, ID). diff --git a/src/mod_pubsub/node_dispatch.erl b/src/mod_pubsub/node_dispatch.erl index 4de366a0d..76aee4891 100644 --- a/src/mod_pubsub/node_dispatch.erl +++ b/src/mod_pubsub/node_dispatch.erl @@ -26,9 +26,8 @@ -module(node_dispatch). -author('christophe.romain@process-one.net'). --include_lib("exmpp/include/exmpp.hrl"). - -include("pubsub.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). -behaviour(gen_pubsub_node). @@ -45,7 +44,7 @@ create_node/2, delete_node/1, purge_node/2, - subscribe_node/7, + subscribe_node/8, unsubscribe_node/4, publish_item/6, delete_item/4, @@ -56,8 +55,9 @@ set_affiliation/3, get_entity_subscriptions/2, get_node_subscriptions/1, - get_subscription/2, - set_subscription/3, + get_subscriptions/2, + set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -77,8 +77,7 @@ terminate(Host, ServerHost) -> node_hometree:terminate(Host, ServerHost). options() -> - [{node_type, dispatch}, - {deliver_payloads, true}, + [{deliver_payloads, true}, {notify_config, false}, {notify_delete, false}, {notify_retract, true}, @@ -119,27 +118,27 @@ delete_node(Removed) -> node_hometree:delete_node(Removed). subscribe_node(_NodeId, _Sender, _Subscriber, _AccessModel, - _SendLast, _PresenceSubscription, _RosterGroup) -> - {error, 'forbidden'}. + _SendLast, _PresenceSubscription, _RosterGroup, _Options) -> + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'forbidden')}. unsubscribe_node(_NodeId, _Sender, _Subscriber, _SubID) -> - {error, 'forbidden'}. + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'forbidden')}. publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> lists:foreach(fun(SubNode) -> node_hometree:publish_item( SubNode#pubsub_node.id, Publisher, Model, MaxItems, ItemId, Payload) - end, nodetree_default:get_subnodes(NodeId, Publisher)). + end, nodetree_tree:get_subnodes(NodeId, Publisher, Publisher)). remove_extra_items(_NodeId, _MaxItems, ItemIds) -> {result, {ItemIds, []}}. delete_item(_NodeId, _Publisher, _PublishModel, _ItemId) -> - {error, 'item-not-found'}. + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'item-not-found')}. purge_node(_NodeId, _Owner) -> - {error, 'forbidden'}. + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'forbidden')}. get_entity_affiliations(_Host, _Owner) -> {result, []}. @@ -161,11 +160,14 @@ get_node_subscriptions(NodeId) -> %% DO NOT REMOVE node_hometree:get_node_subscriptions(NodeId). -get_subscription(_NodeId, _Owner) -> +get_subscriptions(_NodeId, _Owner) -> {result, []}. -set_subscription(NodeId, Owner, Subscription) -> - node_hometree:set_subscription(NodeId, Owner, Subscription). +set_subscriptions(NodeId, Owner, Subscription, SubId) -> + node_hometree:set_subscriptions(NodeId, Owner, Subscription, SubId). + +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). get_states(NodeId) -> node_hometree:get_states(NodeId). @@ -193,3 +195,4 @@ set_item(Item) -> get_item_name(Host, Node, Id) -> node_hometree:get_item_name(Host, Node, Id). + diff --git a/src/mod_pubsub/node_flat.erl b/src/mod_pubsub/node_flat.erl index acab96119..e0bac5ea1 100644 --- a/src/mod_pubsub/node_flat.erl +++ b/src/mod_pubsub/node_flat.erl @@ -25,9 +25,8 @@ -module(node_flat). -author('christophe.romain@process-one.net'). --include_lib("exmpp/include/exmpp.hrl"). - -include("pubsub.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). -behaviour(gen_pubsub_node). @@ -38,7 +37,7 @@ create_node/2, delete_node/1, purge_node/2, - subscribe_node/7, + subscribe_node/8, unsubscribe_node/4, publish_item/6, delete_item/4, @@ -49,8 +48,9 @@ set_affiliation/3, get_entity_subscriptions/2, get_node_subscriptions/1, - get_subscription/2, - set_subscription/3, + get_subscriptions/2, + set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -70,8 +70,7 @@ terminate(Host, ServerHost) -> node_hometree:terminate(Host, ServerHost). options() -> - [{node_type, flat}, - {deliver_payloads, true}, + [{deliver_payloads, true}, {notify_config, false}, {notify_delete, false}, {notify_retract, true}, @@ -109,8 +108,8 @@ create_node(NodeId, Owner) -> delete_node(Removed) -> node_hometree:delete_node(Removed). -subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). +subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options) -> + node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options). unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> node_hometree:unsubscribe_node(NodeId, Sender, Subscriber, SubID). @@ -145,11 +144,14 @@ get_entity_subscriptions(Host, Owner) -> get_node_subscriptions(NodeId) -> node_hometree:get_node_subscriptions(NodeId). -get_subscription(NodeId, Owner) -> - node_hometree:get_subscription(NodeId, Owner). +get_subscriptions(NodeId, Owner) -> + node_hometree:get_subscriptions(NodeId, Owner). -set_subscription(NodeId, Owner, Subscription) -> - node_hometree:set_subscription(NodeId, Owner, Subscription). +set_subscriptions(NodeId, Owner, Subscription, SubId) -> + node_hometree:set_subscriptions(NodeId, Owner, Subscription, SubId). + +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). get_states(NodeId) -> node_hometree:get_states(NodeId). diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index ab6f2c1b5..4eb866cd0 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -41,9 +41,8 @@ -module(node_hometree). -author('christophe.romain@process-one.net'). --include_lib("exmpp/include/exmpp.hrl"). - -include("pubsub.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). -behaviour(gen_pubsub_node). @@ -54,7 +53,7 @@ create_node/2, delete_node/1, purge_node/2, - subscribe_node/7, + subscribe_node/8, unsubscribe_node/4, publish_item/6, delete_item/4, @@ -65,8 +64,9 @@ set_affiliation/3, get_entity_subscriptions/2, get_node_subscriptions/1, - get_subscription/2, - set_subscription/3, + get_subscriptions/2, + set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -92,15 +92,10 @@ %% plugin. It can be used for example by the developer to create the specific %% module database schema if it does not exists yet.

    init(_Host, _ServerHost, _Opts) -> + pubsub_subscription:init(), mnesia:create_table(pubsub_state, [{disc_copies, [node()]}, {attributes, record_info(fields, pubsub_state)}]), - StatesFields = record_info(fields, pubsub_state), - case mnesia:table_info(pubsub_state, attributes) of - StatesFields -> ok; - _ -> - mnesia:transform_table(pubsub_state, ignore, StatesFields) - end, mnesia:create_table(pubsub_item, [{disc_only_copies, [node()]}, {attributes, record_info(fields, pubsub_item)}]), @@ -138,8 +133,7 @@ terminate(_Host, _ServerHost) -> %% {send_last_published_item, never}, %% {presence_based_delivery, false}]''' options() -> - [{node_type, default}, - {deliver_payloads, true}, + [{deliver_payloads, true}, {notify_config, false}, {notify_delete, false}, {notify_retract, true}, @@ -159,11 +153,14 @@ options() -> features() -> ["create-nodes", "auto-create", + "access-authorize", "delete-nodes", "delete-items", + "get-pending", "instant-nodes", "manage-subscriptions", "modify-affiliations", + "multi-subscribe", "outcast-affiliation", "persistent-items", "publish", @@ -173,7 +170,8 @@ features() -> "retrieve-items", "retrieve-subscriptions", "subscribe", - "subscription-notifications" + "subscription-notifications", + "subscription-options" ]. %% @spec (Host, ServerHost, Node, ParentNode, Owner, Access) -> bool() @@ -229,8 +227,10 @@ create_node(NodeId, Owner) -> %% Removed = [mod_pubsub:pubsubNode()] %% @doc

    purge items of deleted nodes after effective deletion.

    delete_node(Removed) -> - Tr = fun(#pubsub_state{stateid = {J, _}, subscription = S}) -> - {J, S} + Tr = fun(#pubsub_state{stateid = {J, _}, subscriptions = Ss}) -> + lists:map(fun(S) -> + {J, S} + end, Ss) end, Reply = lists:map( fun(#pubsub_node{id = NodeId} = PubsubNode) -> @@ -240,7 +240,7 @@ delete_node(Removed) -> del_items(NodeId, Items), del_state(NodeId, LJID) end, States), - {PubsubNode, lists:map(Tr, States)} + {PubsubNode, lists:flatmap(Tr, States)} end, Removed), {result, {default, broadcast, Reply}}. @@ -278,7 +278,7 @@ delete_node(Removed) -> %%

    %%

    In the default plugin module, the record is unchanged.

    subscribe_node(NodeId, Sender, Subscriber, AccessModel, - SendLast, PresenceSubscription, RosterGroup) -> + SendLast, PresenceSubscription, RosterGroup, Options) -> SubKey = jlib:short_prepd_jid(Subscriber), GenKey = jlib:short_prepd_bare_jid(SubKey), Authorized = (jlib:short_prepd_bare_jid(Sender) == GenKey), @@ -288,8 +288,11 @@ subscribe_node(NodeId, Sender, Subscriber, AccessModel, _ -> get_state(NodeId, SubKey) end, Affiliation = GenState#pubsub_state.affiliation, - Subscription = SubState#pubsub_state.subscription, + Subscriptions = SubState#pubsub_state.subscriptions, Whitelisted = lists:member(Affiliation, [member, publisher, owner]), + PendingSubscription = lists:any(fun({pending, _}) -> true; + (_) -> false + end, Subscriptions), if not Authorized -> %% JIDs do not match @@ -297,7 +300,7 @@ subscribe_node(NodeId, Sender, Subscriber, AccessModel, Affiliation == outcast -> %% Requesting entity is blocked {error, 'forbidden'}; - Subscription == pending -> + PendingSubscription -> %% Requesting entity has pending subscription {error, ?ERR_EXTENDED('not-authorized', "pending-subscription")}; (AccessModel == presence) and (not PresenceSubscription) -> @@ -319,36 +322,35 @@ subscribe_node(NodeId, Sender, Subscriber, AccessModel, %% % Requesting entity is anonymous %% {error, 'forbidden'}; true -> - NewSubscription = - if - AccessModel == authorize -> - pending; - %%NeedConfiguration -> - %% unconfigured - true -> - subscribed - end, - set_state(SubState#pubsub_state{subscription = NewSubscription}), - case NewSubscription of - subscribed -> - case SendLast of - never -> {result, {default, NewSubscription}}; - _ -> {result, {default, NewSubscription, send_last}} + case pubsub_subscription:subscribe_node(Subscriber, NodeId, Options) of + {result, SubId} -> + NewSub = case AccessModel of + authorize -> pending; + _ -> subscribed + end, + set_state(SubState#pubsub_state{subscriptions = [{NewSub, SubId} | Subscriptions]}), + case {NewSub, SendLast} of + {subscribed, never} -> + {result, {default, subscribed, SubId}}; + {subscribed, _} -> + {result, {default, subscribed, SubId, send_last}}; + {_, _} -> + {result, {default, pending, SubId}} end; _ -> - {result, {default, NewSubscription}} + {error, 'internal-server-error'} end end. -%% @spec (NodeId, Sender, Subscriber, SubID) -> +%% @spec (NodeId, Sender, Subscriber, SubId) -> %% {error, Reason} | {result, []} %% NodeId = mod_pubsub:pubsubNodeId() %% Sender = mod_pubsub:jid() %% Subscriber = mod_pubsub:jid() -%% SubID = string() +%% SubId = mod_pubsub:subid() %% Reason = mod_pubsub:stanzaError() %% @doc

    Unsubscribe the Subscriber from the Node.

    -unsubscribe_node(NodeId, Sender, Subscriber, _SubId) -> +unsubscribe_node(NodeId, Sender, Subscriber, SubId) -> SubKey = jlib:short_prepd_jid(Subscriber), GenKey = jlib:short_prepd_bare_jid(SubKey), Authorized = (jlib:short_prepd_bare_jid(Sender) == GenKey), @@ -357,28 +359,67 @@ unsubscribe_node(NodeId, Sender, Subscriber, _SubId) -> GenKey -> GenState; _ -> get_state(NodeId, SubKey) end, + Subscriptions = lists:filter(fun({_Sub, _SubId}) -> true; + (_SubId) -> false + end, SubState#pubsub_state.subscriptions), + SubIdExists = case SubId of + [] -> false; + List when is_list(List) -> true; + _ -> false + end, if %% Requesting entity is prohibited from unsubscribing entity not Authorized -> {error, 'forbidden'}; - %% Entity did not specify SubID - %%SubID == "", ?? -> + %% Entity did not specify SubId + %%SubId == "", ?? -> %% {error, ?ERR_EXTENDED('bad-request', "subid-required")}; %% Invalid subscription identifier - %%InvalidSubID -> + %%InvalidSubId -> %% {error, ?ERR_EXTENDED('not-acceptable', "invalid-subid")}; %% Requesting entity is not a subscriber - SubState#pubsub_state.subscription == none -> + Subscriptions == [] -> {error, ?ERR_EXTENDED('unexpected-request', "not-subscribed")}; - %% Was just subscriber, remove the record - SubState#pubsub_state.affiliation == none -> - del_state(NodeId, SubKey), + %% Subid supplied, so use that. + SubIdExists -> + Sub = first_in_list(fun(S) -> + case S of + {_Sub, SubId} -> true; + _ -> false + end + end, SubState#pubsub_state.subscriptions), + case Sub of + {value, S} -> + delete_subscription(SubKey, NodeId, S, SubState), + {result, default}; + false -> + {error, ?ERR_EXTENDED('unexpected-request', + "not-subscribed")} + end; + %% No subid supplied, but there's only one matching + %% subscription, so use that. + length(Subscriptions) == 1 -> + delete_subscription(SubKey, NodeId, hd(Subscriptions), SubState), {result, default}; true -> - set_state(SubState#pubsub_state{subscription = none}), - {result, default} + {error, ?ERR_EXTENDED('bad-request', "subid-required")} end. +delete_subscription(SubKey, NodeID, {Subscription, SubId}, SubState) -> + Affiliation = SubState#pubsub_state.affiliation, + AllSubs = SubState#pubsub_state.subscriptions, + NewSubs = AllSubs -- [{Subscription, SubId}], + pubsub_subscription:unsubscribe_node(SubKey, NodeID, SubId), + case {Affiliation, NewSubs} of + {none, []} -> + % Just a regular subscriber, and this is final item, so + % delete the state. + del_state(NodeID, SubKey); + _ -> + set_state(SubState#pubsub_state{subscriptions = NewSubs}) + end. + + %% @spec (NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload) -> %% {true, PubsubItem} | {result, Reply} %% NodeId = mod_pubsub:pubsubNodeId() @@ -426,13 +467,15 @@ publish_item(NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload) -> _ -> get_state(NodeId, SubKey) end, Affiliation = GenState#pubsub_state.affiliation, - Subscription = SubState#pubsub_state.subscription, + Subscribed = case PublishModel of + subscribers -> is_subscribed(SubState#pubsub_state.subscriptions); + _ -> undefined + end, if not ((PublishModel == open) or ((PublishModel == publishers) and ((Affiliation == owner) or (Affiliation == publisher))) - or ((PublishModel == subscribers) - and (Subscription == subscribed))) -> + or (Subscribed == true)) -> %% Entity does not have sufficient privileges to publish to node {error, 'forbidden'}; true -> @@ -554,7 +597,7 @@ get_entity_affiliations(Host, Owner) -> States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'}), NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of [{nodetree, N}] -> N; - _ -> nodetree_default + _ -> nodetree_tree end, Reply = lists:foldl(fun(#pubsub_state{stateid = {_, N}, affiliation = A}, Acc) -> case NodeTree:get_node(N) of @@ -566,8 +609,8 @@ get_entity_affiliations(Host, Owner) -> get_node_affiliations(NodeId) -> {result, States} = get_states(NodeId), - Tr = fun(#pubsub_state{stateid = {J, {_, _}}, affiliation = A}) -> - {J, A} + Tr = fun(#pubsub_state{stateid = {J, _}, affiliation = A}) -> + {J, A} end, {result, lists:map(Tr, States)}. @@ -579,7 +622,7 @@ get_affiliation(NodeId, Owner) -> set_affiliation(NodeId, Owner, Affiliation) -> GenKey = jlib:short_prepd_bare_jid(Owner), GenState = get_state(NodeId, GenKey), - case {Affiliation, GenState#pubsub_state.subscription} of + case {Affiliation, GenState#pubsub_state.subscriptions} of {none, none} -> del_state(NodeId, GenKey); _ -> @@ -598,7 +641,7 @@ set_affiliation(NodeId, Owner, Affiliation) -> %% pubsub_state table.

    get_entity_subscriptions(Host, Owner) -> {U, D, _} = SubKey = jlib:short_prepd_jid(Owner), - GenKey = jlib:short_prepd_bare_jid(SubKey), + GenKey = jlib:short_prepd_bare_jid(Owner), States = case SubKey of GenKey -> mnesia:match_object( #pubsub_state{stateid = {{U, D, '_'}, '_'}, _ = '_'}); @@ -609,11 +652,16 @@ get_entity_subscriptions(Host, Owner) -> end, NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of [{nodetree, N}] -> N; - _ -> nodetree_default + _ -> nodetree_tree end, - Reply = lists:foldl(fun(#pubsub_state{stateid = {J, N}, subscription = S}, Acc) -> + Reply = lists:foldl(fun(#pubsub_state{stateid = {J, N}, subscriptions = Ss}, Acc) -> case NodeTree:get_node(N) of - #pubsub_node{nodeid = {Host, _}} = Node -> [{Node, S, J}|Acc]; + #pubsub_node{nodeid = {Host, _}} = Node -> + lists:foldl(fun({Sub, SubId}, Acc2) -> + [{Node, Sub, SubId, J} | Acc2]; + (S, Acc2) -> + [{Node, S, J} | Acc2] + end, Acc, Ss); _ -> Acc end end, [], States), @@ -621,26 +669,115 @@ get_entity_subscriptions(Host, Owner) -> get_node_subscriptions(NodeId) -> {result, States} = get_states(NodeId), - Tr = fun(#pubsub_state{stateid = {J, _}, subscription = S}) -> - {J, S} + Tr = fun(#pubsub_state{stateid = {J, _}, subscriptions = Subscriptions}) -> + %% TODO: get rid of cases to handle non-list subscriptions + case Subscriptions of + [_|_] -> + lists:foldl(fun({S, SubId}, Acc) -> + [{J, S, SubId} | Acc]; + (S, Acc) -> + [{J, S} | Acc] + end, [], Subscriptions); + [] -> + []; + _ -> + [{J, none}] + end end, - {result, lists:map(Tr, States)}. + {result, lists:flatmap(Tr, States)}. -get_subscription(NodeId, Owner) -> +get_subscriptions(NodeId, Owner) -> SubKey = jlib:short_prepd_jid(Owner), SubState = get_state(NodeId, SubKey), - {result, SubState#pubsub_state.subscription}. + {result, SubState#pubsub_state.subscriptions}. -set_subscription(NodeId, Owner, Subscription) -> +set_subscriptions(NodeId, Owner, Subscription, SubId) -> SubKey = jlib:short_prepd_jid(Owner), SubState = get_state(NodeId, SubKey), - case {Subscription, SubState#pubsub_state.affiliation} of - {none, none} -> - del_state(NodeId, SubKey); + case {SubId, SubState#pubsub_state.subscriptions} of + {_, []} -> + {error, 'item-not-found'}; + {"", [{_, SID}]} -> + case Subscription of + none -> unsub_with_subid(NodeId, SID, SubState); + _ -> replace_subscription({Subscription, SID}, SubState) + end; + {"", [_|_]} -> + {error, ?ERR_EXTENDED('bad_request', "subid-required")}; _ -> - set_state(SubState#pubsub_state{subscription = Subscription}) - end, - ok. + case Subscription of + none -> unsub_with_subid(NodeId, SubId, SubState); + _ -> replace_subscription({Subscription, SubId}, SubState) + end + end. + +replace_subscription(NewSub, SubState) -> + NewSubs = replace_subscription(NewSub, + SubState#pubsub_state.subscriptions, []), + set_state(SubState#pubsub_state{subscriptions = NewSubs}). + +replace_subscription(_, [], Acc) -> + Acc; +replace_subscription({Sub, SubId}, [{_, SubID} | T], Acc) -> + replace_subscription({Sub, SubId}, T, [{Sub, SubID} | Acc]). + +unsub_with_subid(NodeId, SubId, SubState) -> + pubsub_subscription:unsubscribe_node(SubState#pubsub_state.stateid, + NodeId, SubId), + NewSubs = lists:filter(fun ({_, SID}) -> SubId =/= SID end, + SubState#pubsub_state.subscriptions), + case {NewSubs, SubState#pubsub_state.affiliation} of + {[], none} -> + del_state(NodeId, element(1, SubState#pubsub_state.stateid)); + _ -> + set_state(SubState#pubsub_state{subscriptions = NewSubs}) + end. +%% @spec (Host, Owner) -> {result, [Node]} | {error, Reason} +%% Host = host() +%% Owner = jid() +%% Node = pubsubNode() +%% @doc

    Returns a list of Owner's nodes on Host with pending +%% subscriptions.

    +get_pending_nodes(Host, Owner) -> + GenKey = jlib:jid_remove_resource(jlib:jid_tolower(Owner)), + States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, + affiliation = owner, + _ = '_'}), + NodeIDs = [ID || #pubsub_state{stateid = {_, ID}} <- States], + NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of + [{nodetree, N}] -> N; + _ -> nodetree_tree + end, + Reply = mnesia:foldl(fun(#pubsub_state{stateid = {_, NID}} = S, Acc) -> + case lists:member(NID, NodeIDs) of + true -> + case get_nodes_helper(NodeTree, S) of + {value, Node} -> [Node | Acc]; + false -> Acc + end; + false -> + Acc + end + end, [], pubsub_state), + {result, Reply}. + +get_nodes_helper(NodeTree, + #pubsub_state{stateid = {_, N}, subscriptions = Subs}) -> + HasPending = fun ({pending, _}) -> true; + (pending) -> true; + (_) -> false + end, + case lists:any(HasPending, Subs) of + true -> + case NodeTree:get_node(N) of + #pubsub_node{nodeid = {_, Node}} -> + {value, Node}; + _ -> + false + end; + false -> + false + end. %% @spec (NodeId) -> [States] | [] %% NodeId = mod_pubsub:pubsubNodeId() @@ -655,8 +792,11 @@ set_subscription(NodeId, Owner, Subscription) -> %% ```get_states(NodeId) -> %% node_default:get_states(NodeId).'''

    get_states(NodeId) -> - States = mnesia:match_object( - #pubsub_state{stateid = {'_', NodeId}, _ = '_'}), + States = case catch mnesia:match_object( + #pubsub_state{stateid = {'_', NodeId}, _ = '_'}) of + List when is_list(List) -> List; + _ -> [] + end, {result, States}. %% @spec (NodeId, JID) -> [State] | [] @@ -666,7 +806,7 @@ get_states(NodeId) -> %% @doc

    Returns a state (one state list), given its reference.

    get_state(NodeId, JID) -> StateId = {JID, NodeId}, - case mnesia:read({pubsub_state, StateId}) of + case catch mnesia:read({pubsub_state, StateId}) of [State] when is_record(State, pubsub_state) -> State; _ -> #pubsub_state{stateid=StateId} end. @@ -702,16 +842,18 @@ get_items(NodeId, _From) -> Items = mnesia:match_object(#pubsub_item{itemid = {'_', NodeId}, _ = '_'}), {result, lists:reverse(lists:keysort(#pubsub_item.modification, Items))}. get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> + SubKey = jlib:short_prepd_jid(JID), GenKey = jlib:short_prepd_bare_jid(JID), GenState = get_state(NodeId, GenKey), + SubState = get_state(NodeId, SubKey), Affiliation = GenState#pubsub_state.affiliation, - Subscription = GenState#pubsub_state.subscription, - Whitelisted = can_fetch_item(Affiliation, Subscription), + Subscriptions = SubState#pubsub_state.subscriptions, + Whitelisted = can_fetch_item(Affiliation, Subscriptions), if - %%SubID == "", ?? -> + %%SubId == "", ?? -> %% Entity has multiple subscriptions to the node but does not specify a subscription ID %{error, ?ERR_EXTENDED('bad-request', "subid-required")}; - %%InvalidSubID -> + %%InvalidSubId -> %% Entity is subscribed but specifies an invalid subscription ID %{error, ?ERR_EXTENDED('not-acceptable', "invalid-subid")}; Affiliation == outcast -> @@ -752,10 +894,10 @@ get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _S GenKey = jlib:short_prepd_bare_jid(JID), GenState = get_state(NodeId, GenKey), Affiliation = GenState#pubsub_state.affiliation, - Subscription = GenState#pubsub_state.subscription, - Whitelisted = can_fetch_item(Affiliation, Subscription), + Subscriptions = GenState#pubsub_state.subscriptions, + Whitelisted = can_fetch_item(Affiliation, Subscriptions), if - %%SubID == "", ?? -> + %%SubId == "", ?? -> %% Entity has multiple subscriptions to the node but does not specify a subscription ID %{error, ?ERR_EXTENDED('bad-request', "subid-required")}; %%InvalidSubID -> @@ -816,7 +958,19 @@ can_fetch_item(owner, _) -> true; can_fetch_item(member, _) -> true; can_fetch_item(publisher, _) -> true; can_fetch_item(outcast, _) -> false; -can_fetch_item(none, subscribed) -> true; -can_fetch_item(none, none) -> false; +can_fetch_item(none, Subscriptions) -> is_subscribed(Subscriptions); can_fetch_item(_Affiliation, _Subscription) -> false. +is_subscribed(Subscriptions) -> + lists:any(fun ({subscribed, _SubId}) -> true; + (_) -> false + end, Subscriptions). + +%% Returns the first item where Pred() is true in List +first_in_list(_Pred, []) -> + false; +first_in_list(Pred, [H | T]) -> + case Pred(H) of + true -> {value, H}; + _ -> first_in_list(Pred, T) + end. diff --git a/src/mod_pubsub/node_mb.erl b/src/mod_pubsub/node_mb.erl index 2dc785cfc..8debc41c1 100644 --- a/src/mod_pubsub/node_mb.erl +++ b/src/mod_pubsub/node_mb.erl @@ -50,7 +50,7 @@ create_node/2, delete_node/1, purge_node/2, - subscribe_node/7, + subscribe_node/8, unsubscribe_node/4, publish_item/6, delete_item/4, @@ -61,8 +61,9 @@ set_affiliation/3, get_entity_subscriptions/2, get_node_subscriptions/1, - get_subscription/2, - set_subscription/3, + get_subscriptions/2, + set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -82,8 +83,7 @@ terminate(Host, ServerHost) -> ok. options() -> - [{node_type, pep}, - {deliver_payloads, true}, + [{deliver_payloads, true}, {notify_config, false}, {notify_delete, false}, {notify_retract, false}, @@ -127,10 +127,10 @@ delete_node(Removed) -> node_pep:delete_node(Removed). subscribe_node(NodeId, Sender, Subscriber, AccessModel, - SendLast, PresenceSubscription, RosterGroup) -> + SendLast, PresenceSubscription, RosterGroup, Options) -> node_pep:subscribe_node( NodeId, Sender, Subscriber, AccessModel, SendLast, - PresenceSubscription, RosterGroup). + PresenceSubscription, RosterGroup, Options). unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> node_pep:unsubscribe_node(NodeId, Sender, Subscriber, SubID). @@ -165,11 +165,14 @@ get_entity_subscriptions(Host, Owner) -> get_node_subscriptions(NodeId) -> node_pep:get_node_subscriptions(NodeId). -get_subscription(NodeId, Owner) -> - node_pep:get_subscription(NodeId, Owner). +get_subscriptions(NodeId, Owner) -> + node_pep:get_subscriptions(NodeId, Owner). -set_subscription(NodeId, Owner, Subscription) -> - node_pep:set_subscription(NodeId, Owner, Subscription). +set_subscriptions(NodeId, Owner, Subscription, SubId) -> + node_pep:set_subscriptions(NodeId, Owner, Subscription, SubId). + +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). get_states(NodeId) -> node_pep:get_states(NodeId). diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index c486ac2ac..64e21fac8 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -43,7 +43,7 @@ create_node/2, delete_node/1, purge_node/2, - subscribe_node/7, + subscribe_node/8, unsubscribe_node/4, publish_item/6, delete_item/4, @@ -54,8 +54,9 @@ set_affiliation/3, get_entity_subscriptions/2, get_node_subscriptions/1, - get_subscription/2, - set_subscription/3, + get_subscriptions/2, + set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -77,8 +78,7 @@ terminate(Host, ServerHost) -> ok. options() -> - [{node_type, pep}, - {deliver_payloads, true}, + [{deliver_payloads, true}, {notify_config, false}, {notify_delete, false}, {notify_retract, false}, @@ -146,10 +146,10 @@ delete_node(Removed) -> end. subscribe_node(NodeId, Sender, Subscriber, AccessModel, - SendLast, PresenceSubscription, RosterGroup) -> + SendLast, PresenceSubscription, RosterGroup, Options) -> node_hometree:subscribe_node( NodeId, Sender, Subscriber, AccessModel, SendLast, - PresenceSubscription, RosterGroup). + PresenceSubscription, RosterGroup, Options). unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> case node_hometree:unsubscribe_node(NodeId, Sender, Subscriber, SubID) of @@ -176,7 +176,7 @@ get_entity_affiliations(_Host, Owner) -> States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'}), NodeTree = case ets:lookup(gen_mod:get_module_proc(D, config), nodetree) of [{nodetree, N}] -> N; - _ -> nodetree_default + _ -> nodetree_tree end, Reply = lists:foldl(fun(#pubsub_state{stateid = {_, N}, affiliation = A}, Acc) -> case NodeTree:get_node(N) of @@ -208,11 +208,18 @@ get_entity_subscriptions(_Host, Owner) -> end, NodeTree = case ets:lookup(gen_mod:get_module_proc(D, config), nodetree) of [{nodetree, N}] -> N; - _ -> nodetree_default + _ -> nodetree_tree end, - Reply = lists:foldl(fun(#pubsub_state{stateid = {J, N}, subscription = S}, Acc) -> + Reply = lists:foldl(fun(#pubsub_state{stateid = {J, N}, subscriptions = Ss}, Acc) -> case NodeTree:get_node(N) of - #pubsub_node{nodeid = {{_, D, _}, _}} = Node -> [{Node, S, J}|Acc]; + #pubsub_node{nodeid = {{_, D, _}, _}} = Node -> + lists:foldl(fun({subscribed, SubID}, Acc2) -> + [{Node, subscribed, SubID, J} | Acc2]; + ({pending, _SubID}, Acc2) -> + [{Node, pending, J} | Acc2]; + (S, Acc2) -> + [{Node, S, J} | Acc2] + end, Acc, Ss); _ -> Acc end end, [], States), @@ -226,11 +233,14 @@ get_node_subscriptions(NodeId) -> %% DO NOT REMOVE node_hometree:get_node_subscriptions(NodeId). -get_subscription(NodeId, Owner) -> - node_hometree:get_subscription(NodeId, Owner). +get_subscriptions(NodeId, Owner) -> + node_hometree:get_subscriptions(NodeId, Owner). -set_subscription(NodeId, Owner, Subscription) -> - node_hometree:set_subscription(NodeId, Owner, Subscription). +set_subscriptions(NodeId, Owner, Subscription, SubId) -> + node_hometree:set_subscriptions(NodeId, Owner, Subscription, SubId). + +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). get_states(NodeId) -> node_hometree:get_states(NodeId). @@ -279,4 +289,3 @@ complain_if_modcaps_disabled(ServerHost) -> _ -> ok end. - diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl index d04cff38f..0170ab66a 100644 --- a/src/mod_pubsub/node_private.erl +++ b/src/mod_pubsub/node_private.erl @@ -47,7 +47,7 @@ create_node/2, delete_node/1, purge_node/2, - subscribe_node/7, + subscribe_node/8, unsubscribe_node/4, publish_item/6, delete_item/4, @@ -58,8 +58,9 @@ set_affiliation/3, get_entity_subscriptions/2, get_node_subscriptions/1, - get_subscription/2, - set_subscription/3, + get_subscriptions/2, + set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -79,8 +80,7 @@ terminate(Host, ServerHost) -> node_hometree:terminate(Host, ServerHost). options() -> - [{node_type, private}, - {deliver_payloads, true}, + [{deliver_payloads, true}, {notify_config, false}, {notify_delete, false}, {notify_retract, true}, @@ -123,9 +123,10 @@ delete_node(Removed) -> node_hometree:delete_node(Removed). subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, - PresenceSubscription, RosterGroup) -> + PresenceSubscription, RosterGroup, Options) -> node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, - SendLast, PresenceSubscription, RosterGroup). + SendLast, PresenceSubscription, RosterGroup, + Options). unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> node_hometree:unsubscribe_node(NodeId, Sender, Subscriber, SubID). @@ -160,11 +161,14 @@ get_entity_subscriptions(Host, Owner) -> get_node_subscriptions(NodeId) -> node_hometree:get_node_subscriptions(NodeId). -get_subscription(NodeId, Owner) -> - node_hometree:get_subscription(NodeId, Owner). +get_subscriptions(NodeId, Owner) -> + node_hometree:get_subscriptions(NodeId, Owner). -set_subscription(NodeId, Owner, Subscription) -> - node_hometree:set_subscription(NodeId, Owner, Subscription). +set_subscriptions(NodeId, Owner, Subscription, SubId) -> + node_hometree:set_subscriptions(NodeId, Owner, Subscription, SubId). + +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). get_states(NodeId) -> node_hometree:get_states(NodeId). diff --git a/src/mod_pubsub/nodetree_dag.erl b/src/mod_pubsub/nodetree_dag.erl new file mode 100644 index 000000000..64b4adde1 --- /dev/null +++ b/src/mod_pubsub/nodetree_dag.erl @@ -0,0 +1,249 @@ +%%% ==================================================================== +%%% ``The contents of this file are subject to the Erlang Public License, +%%% Version 1.1, (the "License"); you may not use this file except in +%%% compliance with the License. You should have received a copy of the +%%% Erlang Public License along with this software. If not, it can be +%%% retrieved via the world wide web at http://www.erlang.org/. +%%% +%%% Software distributed under the License is distributed on an "AS IS" +%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%%% the License for the specific language governing rights and limitations +%%% under the License. +%%% +%%% @author Brian Cully +%%% @version {@vsn}, {@date} {@time} +%%% @end +%%% ==================================================================== + +-module(nodetree_dag). +-author('bjc@kublai.com'). + +%% API +-export([init/3, + terminate/2, + options/0, + set_node/1, + get_node/3, + get_node/2, + get_node/1, + get_nodes/2, + get_nodes/1, + get_parentnodes/3, + get_parentnodes_tree/3, + get_subnodes/3, + get_subnodes_tree/3, + create_node/5, + delete_node/2]). + +-include_lib("stdlib/include/qlc.hrl"). + +-include("ejabberd.hrl"). +-include("pubsub.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). + +-behaviour(gen_pubsub_nodetree). + +-define(DEFAULT_NODETYPE, leaf). +-define(DEFAULT_PARENTS, []). +-define(DEFAULT_CHILDREN, []). + +-compile(export_all). + +%%==================================================================== +%% API +%%==================================================================== +init(Host, ServerHost, Opts) -> + nodetree_tree:init(Host, ServerHost, Opts), + mnesia:transaction(fun create_node/5, + [Host, [], "default", service_jid(ServerHost), []]). + +terminate(Host, ServerHost) -> + nodetree_tree:terminate(Host, ServerHost). + +create_node(Key, NodeID, Type, Owner, Options) -> + OwnerJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + case find_node(Key, NodeID) of + false -> + ID = pubsub_index:new(node), + N = #pubsub_node{nodeid = oid(Key, NodeID), + id = ID, + type = Type, + owners = [OwnerJID], + options = Options}, + case set_node(N) of + ok -> {ok, ID}; + Other -> Other + end; + _ -> + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'conflict')} + end. + +set_node(#pubsub_node{nodeid = {Key, _}, + owners = Owners, + options = Options} = Node) -> + Parents = find_opt(collection, ?DEFAULT_PARENTS, Options), + case validate_parentage(Key, Owners, Parents) of + true -> + %% Update parents whenever the config changes. + mnesia:write(Node#pubsub_node{parents = Parents}); + Other -> + Other + end. + +delete_node(Key, NodeID) -> + case find_node(Key, NodeID) of + false -> + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'item-not-found')}; + Node -> + %% Find all of N's children, update their configs to + %% remove N from the collection setting. + lists:foreach(fun (#pubsub_node{options = Opts} = Child) -> + NewOpts = remove_config_parent(NodeID, Opts), + Parents = find_opt(collection, ?DEFAULT_PARENTS, NewOpts), + ok = mnesia:write(pubsub_node, + Child#pubsub_node{ + parents = Parents, + options = NewOpts}, + write) + end, get_subnodes(Key, NodeID)), + + %% Remove and return the requested node. + pubsub_index:free(node, Node#pubsub_node.id), + mnesia:delete_object(pubsub_node, Node, write), + [Node] + end. + +options() -> + nodetree_tree:options(). + +get_node(Host, NodeID, _From) -> + get_node(Host, NodeID). + +get_node(Host, NodeID) -> + case find_node(Host, NodeID) of + false -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'item-not-found')}; + Node -> Node + end. + +get_node(NodeId) -> + nodetree_tree:get_node(NodeId). + +get_nodes(Key, From) -> + nodetree_tree:get_nodes(Key, From). + +get_nodes(Key) -> + nodetree_tree:get_nodes(Key). + +get_parentnodes(Host, NodeID, _From) -> + case find_node(Host, NodeID) of + false -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'item-not-found')}; + #pubsub_node{parents = Parents} -> + Q = qlc:q([N || #pubsub_node{nodeid = {NHost, NNode}} = N <- mnesia:table(pubsub_node), + Parent <- Parents, + Host == NHost, + Parent == NNode]), + qlc:e(Q) + end. + +get_parentnodes_tree(Host, NodeID, _From) -> + Pred = fun (NID, #pubsub_node{nodeid = {_, NNodeID}}) -> + NID == NNodeID + end, + Tr = fun (#pubsub_node{parents = Parents}) -> Parents end, + traversal_helper(Pred, Tr, Host, [NodeID]). + +get_subnodes(Host, NodeID, _From) -> + get_subnodes(Host, NodeID). + +get_subnodes(Host, NodeID) -> + case find_node(Host, NodeID) of + false -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'item-not-found')}; + _ -> + Q = qlc:q([Node || #pubsub_node{nodeid = {NHost, _}, + parents = Parents} = Node <- mnesia:table(pubsub_node), + Host == NHost, + lists:member(NodeID, Parents)]), + qlc:e(Q) + end. + +get_subnodes_tree(Host, NodeID, From) -> + Pred = fun (NID, #pubsub_node{parents = Parents}) -> + lists:member(NID, Parents) + end, + Tr = fun (#pubsub_node{nodeid = {_, N}}) -> [N] end, + traversal_helper(Pred, Tr, 1, Host, [NodeID], + [{0, [get_node(Host, NodeID, From)]}]). + +%%==================================================================== +%% Internal functions +%%==================================================================== +oid(Key, Name) -> {Key, Name}. + +%% Key = jlib:jid() | host() +%% NodeID = string() +find_node(Key, NodeID) -> + case mnesia:read(pubsub_node, oid(Key, NodeID), read) of + [] -> false; + [Node] -> Node + end. + +%% Key = jlib:jid() | host() +%% Default = term() +%% Options = [{Key = atom(), Value = term()}] +find_opt(Key, Default, Options) -> + case lists:keysearch(Key, 1, Options) of + {value, {Key, Val}} -> Val; + _ -> Default + end. + +traversal_helper(Pred, Tr, Host, NodeIDs) -> + traversal_helper(Pred, Tr, 0, Host, NodeIDs, []). + +traversal_helper(_Pred, _Tr, _Depth, _Host, [], Acc) -> + Acc; +traversal_helper(Pred, Tr, Depth, Host, NodeIDs, Acc) -> + Q = qlc:q([Node || #pubsub_node{nodeid = {NHost, _}} = Node <- mnesia:table(pubsub_node), + NodeID <- NodeIDs, + Host == NHost, + Pred(NodeID, Node)]), + Nodes = qlc:e(Q), + IDs = lists:flatmap(Tr, Nodes), + traversal_helper(Pred, Tr, Depth + 1, Host, IDs, [{Depth, Nodes} | Acc]). + +remove_config_parent(NodeID, Options) -> + remove_config_parent(NodeID, Options, []). + +remove_config_parent(_NodeID, [], Acc) -> + lists:reverse(Acc); +remove_config_parent(NodeID, [{collection, Parents} | T], Acc) -> + remove_config_parent(NodeID, T, + [{collection, lists:delete(NodeID, Parents)} | Acc]); +remove_config_parent(NodeID, [H | T], Acc) -> + remove_config_parent(NodeID, T, [H | Acc]). + +validate_parentage(_Key, _Owners, []) -> + true; +validate_parentage(Key, Owners, [[] | T]) -> + validate_parentage(Key, Owners, T); +validate_parentage(Key, Owners, [ParentID | T]) -> + case find_node(Key, ParentID) of + false -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'item_not_found')}; + #pubsub_node{owners = POwners, options = POptions} -> + NodeType = find_opt(node_type, ?DEFAULT_NODETYPE, POptions), + MutualOwners = [O || O <- Owners, PO <- POwners, + O == PO], + case {MutualOwners, NodeType} of + {[], _} -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'forbidden')}; + {_, collection} -> validate_parentage(Key, Owners, T); + {_, _} -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'not-allowed')} + end + end. + +%% @spec (Host) -> jid() +%% Host = host() +%% @doc

    Generate pubsub service JID.

    +service_jid(Host) -> + case Host of + {U,S,_} -> exmpp_jid:make(U, S); + _ -> exmpp_jid:make(Host) + end. diff --git a/src/mod_pubsub/nodetree_tree.erl b/src/mod_pubsub/nodetree_tree.erl index 7600bfed3..012f3f866 100644 --- a/src/mod_pubsub/nodetree_tree.erl +++ b/src/mod_pubsub/nodetree_tree.erl @@ -36,6 +36,7 @@ -module(nodetree_tree). -author('christophe.romain@process-one.net'). +-include_lib("stdlib/include/qlc.hrl"). -include_lib("exmpp/include/exmpp.hrl"). -include("pubsub.hrl"). @@ -51,6 +52,8 @@ get_node/1, get_nodes/2, get_nodes/1, + get_parentnodes/3, + get_parentnodes_tree/3, get_subnodes/3, get_subnodes_tree/3, create_node/5, @@ -125,6 +128,29 @@ get_nodes(Host, _From) -> get_nodes(Host) -> mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, _ = '_'}). +%% @spec (Host, Node, From) -> [{Depth, Record}] | {error, Reason} +%% Host = mod_pubsub:host() | mod_pubsub:jid() +%% Node = mod_pubsub:pubsubNode() +%% From = mod_pubsub:jid() +%% Depth = integer() +%% Record = pubsubNode() +%% @doc

    Default node tree does not handle parents, return empty list.

    +get_parentnodes(_Host, _Node, _From) -> + []. + +%% @spec (Host, Node, From) -> [{Depth, Record}] | {error, Reason} +%% Host = mod_pubsub:host() | mod_pubsub:jid() +%% Node = mod_pubsub:pubsubNode() +%% From = mod_pubsub:jid() +%% Depth = integer() +%% Record = pubsubNode() +%% @doc

    Default node tree does not handle parents, return a list +%% containing just this node.

    +get_parentnodes_tree(Host, Node, From) -> + case get_node(Host, Node, From) of + N when is_record(N, pubsub_node) -> [{0, [N]}]; + Error -> Error + end. %% @spec (Host, Node, From) -> [pubsubNode()] | {error, Reason} %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() @@ -132,9 +158,13 @@ get_nodes(Host) -> get_subnodes(Host, Node, _From) -> get_subnodes(Host, Node). get_subnodes(Host, Node) -> - mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, parent = Node, _ = '_'}). + Q = qlc:q([N || #pubsub_node{nodeid = {NHost, _}, + parents = Parents} = N <- mnesia:table(pubsub_node), + Host == NHost, + lists:member(Node, Parents)]), + qlc:e(Q). -%% @spec (Host, Index) -> [pubsubNode()] | {error, Reason} +%% @spec (Host, Index) -> [pubsubNodeIdx()] | {error, Reason} %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() %% From = mod_pubsub:jid() @@ -172,7 +202,7 @@ create_node(Host, Node, Type, Owner, Options) -> _ -> case mnesia:read({pubsub_node, {Host, Parent}}) of [] -> {Parent, false}; - _ -> {Parent, true} + _ -> {Parent, lists:member(BJID, Parent#pubsub_node.owners)} end end end, @@ -181,7 +211,7 @@ create_node(Host, Node, Type, Owner, Options) -> NodeId = pubsub_index:new(node), mnesia:write(#pubsub_node{nodeid = {Host, Node}, id = NodeId, - parent = ParentNode, + parents = [ParentNode], type = Type, owners = [BJID], options = Options}), diff --git a/src/mod_pubsub/pubsub.hrl b/src/mod_pubsub/pubsub.hrl index b896d4614..3a018188a 100644 --- a/src/mod_pubsub/pubsub.hrl +++ b/src/mod_pubsub/pubsub.hrl @@ -91,7 +91,7 @@ %%%

    The parentid and type fields are indexed.

    -record(pubsub_node, {nodeid, id, - parent, + parents = [], type = "flat", owners = [], options = [] @@ -101,13 +101,13 @@ %%% stateid = {ljid(), nodeidx()}}, %%% items = [ItemId::string()], %%% affiliation = affiliation(), -%%% subscription = subscription()}. +%%% subscriptions = [subscription()]}. %%%

    This is the format of the affiliations table. The type of the %%% table is: set,ram/disc.

    -record(pubsub_state, {stateid, items = [], affiliation = none, - subscription = none + subscriptions = none }). %%% @type pubsubItem() = #pubsub_item{ @@ -123,3 +123,11 @@ payload = [] }). +%% @type pubsubSubscription() = #pubsub_subscription{ +%% subid = string(), +%% state_key = {ljid(), pubsubNodeId()}, +%% options = [{atom(), term()}] +%% }. +%%

    This is the format of the subscriptions table. The type of the +%% table is: set,ram/disc.

    +-record(pubsub_subscription, {subid, options}). diff --git a/src/mod_pubsub/pubsub_subscription.erl b/src/mod_pubsub/pubsub_subscription.erl new file mode 100644 index 000000000..e00dacd37 --- /dev/null +++ b/src/mod_pubsub/pubsub_subscription.erl @@ -0,0 +1,333 @@ +%%% ==================================================================== +%%% ``The contents of this file are subject to the Erlang Public License, +%%% Version 1.1, (the "License"); you may not use this file except in +%%% compliance with the License. You should have received a copy of the +%%% Erlang Public License along with this software. If not, it can be +%%% retrieved via the world wide web at http://www.erlang.org/. +%%% +%%% Software distributed under the License is distributed on an "AS IS" +%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%%% the License for the specific language governing rights and limitations +%%% under the License. +%%% +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne +%%% All Rights Reserved.'' +%%% This software is copyright 2006-2009, ProcessOne. +%%% +%%% @author Brian Cully +%%% @version {@vsn}, {@date} {@time} +%%% @end +%%% ==================================================================== + +-module(pubsub_subscription). +-author("bjc@kublai.com"). + +%% API +-export([init/0, + subscribe_node/3, + unsubscribe_node/3, + get_subscription/3, + set_subscription/4, + get_options_xform/2, + parse_options_xform/1]). + +% Internal function also exported for use in transactional bloc from pubsub plugins +-export([add_subscription/3, + delete_subscription/3, + read_subscription/3, + write_subscription/4]). + +-include_lib("stdlib/include/qlc.hrl"). + +-include("pubsub.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). + +-define(PUBSUB_DELIVER, "pubsub#deliver"). +-define(PUBSUB_DIGEST, "pubsub#digest"). +-define(PUBSUB_DIGEST_FREQUENCY, "pubsub#digest_frequency"). +-define(PUBSUB_EXPIRE, "pubsub#expire"). +-define(PUBSUB_INCLUDE_BODY, "pubsub#include_body"). +-define(PUBSUB_SHOW_VALUES, "pubsub#show-values"). +-define(PUBSUB_SUBSCRIPTION_TYPE, "pubsub#subscription_type"). +-define(PUBSUB_SUBSCRIPTION_DEPTH, "pubsub#subscription_depth"). + +-define(DELIVER_LABEL, + "Whether an entity wants to receive or disable notifications"). +-define(DIGEST_LABEL, + "Whether an entity wants to receive digests (aggregations) of notifications or all notifications individually"). +-define(DIGEST_FREQUENCY_LABEL, + "The minimum number of milliseconds between sending any two notification digests"). +-define(EXPIRE_LABEL, + "The DateTime at which a leased subscription will end or has ended"). +-define(INCLUDE_BODY_LABEL, + "Whether an entity wants to receive an XMPP message body in addition to the payload format"). +-define(SHOW_VALUES_LABEL, + "The presence states for which an entity wants to receive notifications"). +-define(SUBSCRIPTION_TYPE_LABEL, + "Type of notification to receive"). +-define(SUBSCRIPTION_DEPTH_LABEL, + "Depth from subscription for which to receive notifications"). + +-define(SHOW_VALUE_AWAY_LABEL, "XMPP Show Value of Away"). +-define(SHOW_VALUE_CHAT_LABEL, "XMPP Show Value of Chat"). +-define(SHOW_VALUE_DND_LABEL, "XMPP Show Value of DND (Do Not Disturb)"). +-define(SHOW_VALUE_ONLINE_LABEL, "Mere Availability in XMPP (No Show Value)"). +-define(SHOW_VALUE_XA_LABEL, "XMPP Show Value of XA (Extended Away)"). + +-define(SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL, + "Receive notification of new items only"). +-define(SUBSCRIPTION_TYPE_VALUE_NODES_LABEL, + "Receive notification of new nodes only"). + +-define(SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL, + "Receive notification from direct child nodes only"). +-define(SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL, + "Receive notification from all descendent nodes"). + +%%==================================================================== +%% API +%%==================================================================== +init() -> + ok = create_table(). + +subscribe_node(JID, NodeID, Options) -> + try mnesia:sync_dirty(fun add_subscription/3, + [JID, NodeID, Options]) of + Result -> {result, Result} + catch + Error -> Error + end. + +unsubscribe_node(JID, NodeID, SubID) -> + try mnesia:sync_dirty(fun delete_subscription/3, + [JID, NodeID, SubID]) of + Result -> {result, Result} + catch + Error -> Error + end. + +get_subscription(JID, NodeID, SubID) -> + try mnesia:sync_dirty(fun read_subscription/3, + [JID, NodeID, SubID]) of + Result -> {result, Result} + catch + Error -> Error + end. + +set_subscription(JID, NodeID, SubID, Options) -> + try mnesia:sync_dirty(fun write_subscription/4, + [JID, NodeID, SubID, Options]) of + Result -> {result, Result} + catch + Error -> Error + end. + +get_options_xform(Lang, Options) -> + Keys = [deliver, show_values, subscription_type, subscription_depth], + XFields = [get_option_xfield(Lang, Key, Options) || Key <- Keys], + + {result, #xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = + [#xmlel{ns = ?NS_DATA_FORMS, + name = 'field', + attrs = [?XMLATTR('var', <<"FORM_TYPE">>), ?XMLATTR('type', <<"hidden">>)], + children = [#xmlel{ns = ?NS_DATA_FORMS, + name = 'value', + children = [?XMLCDATA(?NS_PUBSUB_SUBSCRIBE_OPTIONS_s)]}]}] ++ XFields}}. + +parse_options_xform(XFields) -> + case exmpp_xml:get_child_elements(XFields) of + [] -> {result, []}; + [#xmlel{name = 'x'} = XEl] -> + case jlib:parse_xdata_submit(XEl) of + XData when is_list(XData) -> + case set_xoption(XData, []) of + Opts when is_list(Opts) -> {result, Opts}; + Other -> Other + end; + Other -> + Other + end; + Other -> + Other + end. + +%%==================================================================== +%% Internal functions +%%==================================================================== +create_table() -> + case mnesia:create_table(pubsub_subscription, + [{disc_copies, [node()]}, + {attributes, record_info(fields, pubsub_subscription)}, + {type, set}]) of + {atomic, ok} -> ok; + {aborted, {already_exists, _}} -> ok; + Other -> Other + end. + +add_subscription(_JID, _NodeID, Options) -> + SubID = make_subid(), + Record = #pubsub_subscription{subid = SubID, options = Options}, + mnesia:write(Record), + SubID. + +delete_subscription(JID, NodeID, SubID) -> + Sub = read_subscription(JID, NodeID, SubID), + mnesia:delete({pubsub_subscription, SubID}), + Sub. + +read_subscription(_JID, _NodeID, SubID) -> + Q = qlc:q([Sub || Sub <- mnesia:table(pubsub_subscription), + Sub#pubsub_subscription.subid == SubID]), + case qlc:e(Q) of + [Sub] -> Sub; + [] -> mnesia:abort({error, notfound}) + end. + +write_subscription(JID, NodeID, SubID, Options) -> + Sub = read_subscription(JID, NodeID, SubID), + mnesia:write(Sub#pubsub_subscription{options = Options}). + +make_subid() -> + {T1, T2, T3} = now(), + lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])). + +%% +%% Subscription XForm processing. +%% + +%% Return processed options, with types converted and so forth, using +%% Opts as defaults. +set_xoption([], Opts) -> + Opts; +set_xoption([{Var, Value} | T], Opts) -> + NewOpts = case var_xfield(Var) of + {error, _} -> + Opts; + Key -> + Val = val_xfield(Key, Value), + lists:keystore(Key, 1, Opts, {Key, Val}) + end, + set_xoption(T, NewOpts). + +%% Return the options list's key for an XForm var. +var_xfield(?PUBSUB_DELIVER) -> deliver; +var_xfield(?PUBSUB_DIGEST) -> digest; +var_xfield(?PUBSUB_DIGEST_FREQUENCY) -> digest_frequency; +var_xfield(?PUBSUB_EXPIRE) -> expire; +var_xfield(?PUBSUB_INCLUDE_BODY) -> include_body; +var_xfield(?PUBSUB_SHOW_VALUES) -> show_values; +var_xfield(?PUBSUB_SUBSCRIPTION_TYPE) -> subscription_type; +var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) -> subscription_depth; +var_xfield(_) -> {error, badarg}. + +%% Convert Values for option list's Key. +val_xfield(deliver, [Val]) -> xopt_to_bool(Val); +val_xfield(digest, [Val]) -> xopt_to_bool(Val); +val_xfield(digest_frequency, [Val]) -> list_to_integer(Val); +val_xfield(expire, [Val]) -> jlib:datetime_string_to_timestamp(Val); +val_xfield(include_body, [Val]) -> xopt_to_bool(Val); +val_xfield(show_values, Vals) -> Vals; +val_xfield(subscription_type, ["items"]) -> items; +val_xfield(subscription_type, ["nodes"]) -> nodes; +val_xfield(subscription_depth, ["all"]) -> all; +val_xfield(subscription_depth, [Depth]) -> + case catch list_to_integer(Depth) of + N when is_integer(N) -> N; + _ -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'not-acceptable')} + end. + +%% Convert XForm booleans to Erlang booleans. +xopt_to_bool("0") -> false; +xopt_to_bool("1") -> true; +xopt_to_bool("false") -> false; +xopt_to_bool("true") -> true; +xopt_to_bool(_) -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'not-acceptable')}. + +%% Return a field for an XForm for Key, with data filled in, if +%% applicable, from Options. +get_option_xfield(Lang, Key, Options) -> + Var = xfield_var(Key), + Label = xfield_label(Key), + {Type, OptEls} = type_and_options(xfield_type(Key), Lang), + Vals = case lists:keysearch(Key, 1, Options) of + {value, {_, Val}} -> + [tr_xfield_values(Vals) || Vals <- xfield_val(Key, Val)]; + false -> + [] + end, + #xmlel{ns = ?NS_DATA_FORMS, + name = 'field', + attrs = [?XMLATTR('var', Var), ?XMLATTR('type', Type), ?XMLATTR('label', translate:translate(Lang, Label))], + children = OptEls ++ Vals}. + +type_and_options({Type, Options}, Lang) -> + {Type, [tr_xfield_options(O, Lang) || O <- Options]}; +type_and_options(Type, _Lang) -> + {Type, []}. + +tr_xfield_options({Value, Label}, Lang) -> + #xmlel{ns = ?NS_DATA_FORMS, + name = 'option', + attrs = [?XMLATTR('label', transalte:translate(Lang, Label))], + children = [#xmlel{ns = ?NS_DATA_FORMS, + name = 'value', + children = [?XMLCDATA(Value)]}]}. + +tr_xfield_values(Value) -> + #xmlel{ns = ?NS_DATA_FORMS, name ='value', children = [?XMLCDATA(Value)]}. + +%% Return the XForm variable name for a subscription option key. +xfield_var(deliver) -> ?PUBSUB_DELIVER; +xfield_var(digest) -> ?PUBSUB_DIGEST; +xfield_var(digest_frequency) -> ?PUBSUB_DIGEST_FREQUENCY; +xfield_var(expire) -> ?PUBSUB_EXPIRE; +xfield_var(include_body) -> ?PUBSUB_INCLUDE_BODY; +xfield_var(show_values) -> ?PUBSUB_SHOW_VALUES; +xfield_var(subscription_type) -> ?PUBSUB_SUBSCRIPTION_TYPE; +xfield_var(subscription_depth) -> ?PUBSUB_SUBSCRIPTION_DEPTH. + +%% Return the XForm variable type for a subscription option key. +xfield_type(deliver) -> "boolean"; +xfield_type(digest) -> "boolean"; +xfield_type(digest_frequency) -> "text-single"; +xfield_type(expire) -> "text-single"; +xfield_type(include_body) -> "boolean"; +xfield_type(show_values) -> + {"list-multi", [{"away", ?SHOW_VALUE_AWAY_LABEL}, + {"chat", ?SHOW_VALUE_CHAT_LABEL}, + {"dnd", ?SHOW_VALUE_DND_LABEL}, + {"online", ?SHOW_VALUE_ONLINE_LABEL}, + {"xa", ?SHOW_VALUE_XA_LABEL}]}; +xfield_type(subscription_type) -> + {"list-single", [{"items", ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL}, + {"nodes", ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]}; +xfield_type(subscription_depth) -> + {"list-single", [{"1", ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL}, + {"all", ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}. + +%% Return the XForm variable label for a subscription option key. +xfield_label(deliver) -> ?DELIVER_LABEL; +xfield_label(digest) -> ?DIGEST_LABEL; +xfield_label(digest_frequency) -> ?DIGEST_FREQUENCY_LABEL; +xfield_label(expire) -> ?EXPIRE_LABEL; +xfield_label(include_body) -> ?INCLUDE_BODY_LABEL; +xfield_label(show_values) -> ?SHOW_VALUES_LABEL; +xfield_label(subscription_type) -> ?SUBSCRIPTION_TYPE_LABEL; +xfield_label(subscription_depth) -> ?SUBSCRIPTION_DEPTH_LABEL. + +%% Return the XForm value for a subscription option key. +xfield_val(deliver, Val) -> [bool_to_xopt(Val)]; +xfield_val(digest, Val) -> [bool_to_xopt(Val)]; +xfield_val(digest_frequency, Val) -> [integer_to_list(Val)]; +xfield_val(expire, Val) -> [jlib:now_to_utc_string(Val)]; +xfield_val(include_body, Val) -> [bool_to_xopt(Val)]; +xfield_val(show_values, Val) -> Val; +xfield_val(subscription_type, items) -> ["items"]; +xfield_val(subscription_type, nodes) -> ["nodes"]; +xfield_val(subscription_depth, all) -> ["all"]; +xfield_val(subscription_depth, N) -> [integer_to_list(N)]. + +%% Convert erlang booleans to XForms. +bool_to_xopt(false) -> "false"; +bool_to_xopt(true) -> "true". From b4f0bb65c6aac7e4d0fd60cb870a10e194024eda Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Tue, 25 Aug 2009 17:23:43 +0000 Subject: [PATCH 513/582] Fix disco#items on pubsub nodes SVN Revision: 2534 --- src/mod_pubsub/mod_pubsub.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index dfe8ab5a2..9d097fa55 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -1029,7 +1029,7 @@ node_disco_info(Host, Node, From, Identity, Features) -> []; true -> Types = - case tree_call(Host, get_subnodes, [NodeId, From]) of + case tree_call(Host, get_subnodes, [Host, Node, From]) of [] -> ["leaf"]; %% No sub-nodes: it's a leaf node _ -> @@ -1117,7 +1117,7 @@ iq_disco_items(Host, Item, From) -> RN = lists:last(SubNode), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), ?XMLATTR('name', RN)]} - end, tree_call(Host, get_subnodes, [NodeId, From])), + end, tree_call(Host, get_subnodes, [Host, Node, From])), Items = lists:map( fun(#pubsub_item{itemid = {RN, _}}) -> SN = node_to_string(Node) ++ "!" ++ RN, From fcf66c2e7537dccd4cc0cb4f61d6ef7ae0fb4fed Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Tue, 25 Aug 2009 17:42:25 +0000 Subject: [PATCH 514/582] Fix affiliation managment Node owner can add/remove affiliations SVN Revision: 2535 --- src/mod_pubsub/mod_pubsub.erl | 6 +++--- src/mod_pubsub/node_hometree.erl | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 9d097fa55..2f4f75b7c 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -2395,7 +2395,7 @@ set_affiliations(Host, Node, From, EntitiesEls) -> #xmlel{name = 'affiliation', attrs = Attrs} -> JID = try exmpp_jid:parse( - exmpp_xml:get_attribute_from_list_as_list(Attrs, 'jid', "")) + exmpp_xml:get_attribute_from_list(Attrs, 'jid', "")) catch _:_ -> error end, @@ -2406,7 +2406,7 @@ set_affiliations(Host, Node, From, EntitiesEls) -> (Affiliation == false) -> error; true -> - [{jlib:short_prepd_jid(JID), Affiliation} | Acc] + [{JID, Affiliation} | Acc] end end end @@ -2420,7 +2420,7 @@ set_affiliations(Host, Node, From, EntitiesEls) -> true -> lists:foreach( fun({JID, Affiliation}) -> - node_call(Type, set_affiliation, [NodeId, JID, Affiliation]), + {result, _} = node_call(Type, set_affiliation, [NodeId, JID, Affiliation]), case Affiliation of owner -> NewOwner = jlib:short_prepd_bare_jid(JID), diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index 4eb866cd0..1fe51b38d 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -619,7 +619,7 @@ get_affiliation(NodeId, Owner) -> GenState = get_state(NodeId, GenKey), {result, GenState#pubsub_state.affiliation}. -set_affiliation(NodeId, Owner, Affiliation) -> +set_affiliation(NodeId, Owner, Affiliation) when ?IS_JID(Owner)-> GenKey = jlib:short_prepd_bare_jid(Owner), GenState = get_state(NodeId, GenKey), case {Affiliation, GenState#pubsub_state.subscriptions} of From a1a6469ed0f4eec23fbc6d972f806639de65ad34 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Tue, 25 Aug 2009 19:54:44 +0000 Subject: [PATCH 515/582] Updated to trunk r2532, fix subscription managment (by owner) SVN Revision: 2536 --- src/mod_pubsub/mod_pubsub.erl | 331 ++++++++++++++++++------------- src/mod_pubsub/node_hometree.erl | 15 +- src/mod_pubsub/pubsub.hrl | 2 +- 3 files changed, 207 insertions(+), 141 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 2f4f75b7c..f3d7a6fa6 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -35,7 +35,7 @@ %%% Functions concerning configuration should be rewritten. %%% %%% Support for subscription-options and multi-subscribe features was -%%% added by Brian Cully . Subscriptions and options are +%%% added by Brian Cully (bjc AT kublai.com). Subscriptions and options are %%% stored in the pubsub_subscription table, with a link to them provided %%% by the subscriptions field of pubsub_state. For information on %%% subscription-options and mulit-subscribe see XEP-0060 sections 6.1.6, @@ -272,9 +272,9 @@ terminate_plugins(Host, ServerHost, Plugins, TreePlugin) -> TreePlugin:terminate(Host, ServerHost), ok. -init_nodes(_Host, _ServerHost) -> - %create_node(Host, ServerHost, ["home"], service_jid(Host), "hometree"), - %create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), "hometree"), +init_nodes(Host, ServerHost) -> + create_node(Host, ServerHost, ["home"], service_jid(Host), "hometree"), + create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), "hometree"), ok. update_node_database(Host, ServerHost) -> @@ -284,7 +284,7 @@ update_node_database(Host, ServerHost) -> [host_node, host_parent, info] -> ?INFO_MSG("upgrade node pubsub tables",[]), F = fun() -> - lists:foldl( + {Result, LastIdx} = lists:foldl( fun({pubsub_node, NodeId, ParentId, {nodeinfo, Items, Options, Entities}}, {RecList, NodeIdx}) -> ItemsList = lists:foldl( @@ -328,7 +328,9 @@ update_node_database(Host, ServerHost) -> RecList], NodeIdx + 1} end, {[], 1}, mnesia:match_object( - {pubsub_node, {Host, '_'}, '_', '_'})) + {pubsub_node, {Host, '_'}, '_', '_'})), + mnesia:write(#pubsub_index{index = node, last = LastIdx, free = []}), + Result end, {atomic, NewRecords} = mnesia:transaction(F), {atomic, ok} = mnesia:delete_table(pubsub_node), @@ -341,11 +343,9 @@ update_node_database(Host, ServerHost) -> end, case mnesia:transaction(FNew) of {atomic, Result} -> - ?INFO_MSG("Pubsub node tables updated correctly: ~p", - [Result]); + ?INFO_MSG("Pubsub node tables updated correctly: ~p", [Result]); {aborted, Reason} -> - ?ERROR_MSG("Problem updating Pubsub node tables:~n~p", - [Reason]) + ?ERROR_MSG("Problem updating Pubsub node tables:~n~p", [Reason]) end; [nodeid, parentid, type, owners, options] -> F = fun({pubsub_node, NodeId, {_, Parent}, Type, Owners, Options}) -> @@ -359,7 +359,7 @@ update_node_database(Host, ServerHost) -> end, mnesia:transform_table(pubsub_node, F, [nodeid, id, parents, type, owners, options]), FNew = fun() -> - lists:foldl(fun(#pubsub_node{nodeid = NodeId} = PubsubNode, NodeIdx) -> + LastIdx = lists:foldl(fun(#pubsub_node{nodeid = NodeId} = PubsubNode, NodeIdx) -> mnesia:write(PubsubNode#pubsub_node{id = NodeIdx}), lists:foreach(fun(#pubsub_state{stateid = StateId} = State) -> {JID, _} = StateId, @@ -379,15 +379,15 @@ update_node_database(Host, ServerHost) -> end, 1, mnesia:match_object( {pubsub_node, {Host, '_'}, '_', '_', '_', '_', '_'}) ++ mnesia:match_object( - {pubsub_node, {{'_', ServerHost, '_'}, '_'}, '_', '_', '_', '_', '_'})) + {pubsub_node, {{'_', ServerHost, '_'}, '_'}, '_', '_', '_', '_', '_'})), + mnesia:write(#pubsub_index{index = node, last = LastIdx, free = []}) end, case mnesia:transaction(FNew) of {atomic, Result} -> - ?INFO_MSG("Pubsub node tables updated correctly: ~p", - [Result]); + rename_default_nodeplugin(), + ?INFO_MSG("Pubsub node tables updated correctly: ~p", [Result]); {aborted, Reason} -> - ?ERROR_MSG("Problem updating Pubsub node tables:~n~p", - [Reason]) + ?ERROR_MSG("Problem updating Pubsub node tables:~n~p", [Reason]) end; [nodeid, id, parent, type, owners, options] -> F = fun({pubsub_node, NodeId, Id, Parent, Type, Owners, Options}) -> @@ -399,10 +399,16 @@ update_node_database(Host, ServerHost) -> owners = Owners, options = Options} end, - mnesia:transform_table(pubsub_node, F, [nodeid, id, parents, type, owners, options]); + mnesia:transform_table(pubsub_node, F, [nodeid, id, parents, type, owners, options]), + rename_default_nodeplugin(); _ -> ok end. + +rename_default_nodeplugin() -> + lists:foreach(fun(Node) -> + mnesia:dirty_write(Node#pubsub_node{type = "hometree"}) + end, mnesia:dirty_match_object(#pubsub_node{type = "default", _ = '_'})). update_state_database(_Host, _ServerHost) -> case catch mnesia:table_info(pubsub_state, attributes) of @@ -467,7 +473,7 @@ send_loop(State) -> lists:foreach(fun(PType) -> {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, JID]), lists:foreach( - fun({Node, subscribed, SubJID}) -> + fun({Node, subscribed, _, SubJID}) -> if (SubJID == LJID) or (SubJID == BJID) -> #pubsub_node{options = Options, type = Type, id = NodeId} = Node, case get_option(Options, send_last_published_item) of @@ -637,13 +643,12 @@ disco_sm_features(Acc, From, To, Node, _Lang) -> end. disco_sm_items(Acc, From, To, <<>>, _Lang) -> - %% TODO, use iq_disco_items(Host, [], From) Host = exmpp_jid:prep_domain_as_list(To), - LJID = jlib:short_prepd_bare_jid(To), case tree_action(Host, get_subnodes, [Host, [], From]) of [] -> Acc; Nodes -> + SBJID = jlib:short_prepd_bare_jid(To), Items = case Acc of {result, I} -> I; _ -> [] @@ -651,8 +656,7 @@ disco_sm_items(Acc, From, To, <<>>, _Lang) -> NodeItems = lists:map( fun(#pubsub_node{nodeid = {_, Node}}) -> #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = - [?XMLATTR('jid', exmpp_jid:to_binary(LJID)), - ?XMLATTR('node', node_to_string(Node))]} + [?XMLATTR('jid', exmpp_jid:to_binary(SBJID)) | nodeAttr(Node)]} end, Nodes), {result, NodeItems ++ Items} end; @@ -675,7 +679,7 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) -> fun(#pubsub_item{itemid = {Id, _}}) -> %% "jid" is required by XEP-0030, and %% "node" is forbidden by XEP-0060. - {result, Name} = node_action(Host, Node, get_item_name, [NodeId, Id]), + {result, Name} = node_call(Type, get_item_name, [Host, Node, Id]), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', exmpp_jid:to_binary(LJID)), ?XMLATTR('name', Name)]} @@ -695,16 +699,16 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) -> %% presence_probe(JID, JID, Pid) -> - {U, S, R} = jlib:short_prepd_jid(JID), + {User, Server, Resource} = jlib:short_prepd_jid(JID), Host = exmpp_jid:prep_domain_as_list(JID), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), gen_server:cast(Proc, {presence, JID, Pid}), - gen_server:cast(Proc, {presence, U, S, [R], JID}); + gen_server:cast(Proc, {presence, User, Server, [Resource], JID}); presence_probe(Peer, JID, _Pid) -> - {U, S, R} = jlib:short_prepd_jid(Peer), + {User, Server, Resource} = jlib:short_prepd_jid(Peer), Host = exmpp_jid:prep_domain_as_list(JID), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), - gen_server:cast(Proc, {presence, U, S, [R], JID}). + gen_server:cast(Proc, {presence, User, Server, [Resource], JID}). %% ------- %% subscription hooks handling functions @@ -782,7 +786,7 @@ handle_cast({remove_user, LUser, LServer}, State) -> lists:foreach(fun(PType) -> {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Owner]), lists:foreach(fun - ({#pubsub_node{nodeid = {H, N}}, subscribed, JID}) -> + ({#pubsub_node{nodeid = {H, N}}, subscribed, _, JID}) -> unsubscribe_node(H, N, Owner, JID, all); (_) -> ok @@ -803,7 +807,7 @@ handle_cast({unsubscribe, Subscriber, Owner}, State) -> lists:foreach(fun(PType) -> {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), lists:foreach(fun - ({Node, subscribed, JID}) -> + ({Node, subscribed, _, JID}) -> #pubsub_node{options = Options, owners = Owners, type = Type, id = NodeId} = Node, case get_option(Options, access_model) of presence -> @@ -909,8 +913,7 @@ do_route(ServerHost, Access, Plugins, Host, From, To, Packet) -> #iq{type = get, ns = ?NS_DISCO_INFO, payload = SubEl, lang = Lang} -> QAttrs = SubEl#xmlel.attrs, - Node = exmpp_xml:get_attribute_from_list_as_list(QAttrs, - 'node', ""), + Node = exmpp_xml:get_attribute_from_list_as_list(QAttrs, 'node', ""), ServerHostB = list_to_binary(ServerHost), Info = ejabberd_hooks:run_fold( disco_info, ServerHostB, [], @@ -1524,15 +1527,20 @@ find_authorization_response(Packet) -> %% Host = mod_pubsub:host() %% JID = jlib:jid() %% SNode = string() -%% Subscription = atom() +%% Subscription = atom() | {atom(), mod_pubsub:subid)} %% Plugins = [Plugin::string()] %% @doc Send a message to JID with the supplied Subscription send_authorization_approval(Host, JID, SNode, Subscription) -> + SubAttrs = case Subscription of + {S, SID} -> [?XMLATTR('subscription', subscription_to_string(S)), + ?XMLATTR('subid', SID)]; + S -> [?XMLATTR('subscription', subscription_to_string(S))] + end, Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'subscription', attrs = [?XMLATTR('node', SNode), - ?XMLATTR('jid', exmpp_jid:to_binary(JID)), - ?XMLATTR('subscription', subscription_to_string(Subscription))]}]), + ?XMLATTR('jid', exmpp_jid:to_binary(JID))] ++ SubAttrs + }]), ejabberd_router ! {route, service_jid(Host), JID, Stanza}. handle_authorization_response(Host, From, To, Packet, XFields) -> @@ -1551,14 +1559,14 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> "true" -> true; _ -> false end, - Action = fun(#pubsub_node{type = Type, id = NodeId, owners = Owners}) -> + Action = fun(#pubsub_node{type = Type, owners = Owners, id = NodeId}) -> IsApprover = lists:member(jlib:short_prepd_bare_jid(From), Owners), {result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]), if not IsApprover -> {error, 'forbidden'}; true -> - update_auth(Host, SNode, Type, NodeId, + update_auth(Host, SNode, Type, NodeId, Subscriber, Allow, Subscriptions) end @@ -1760,8 +1768,8 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> {result, Result}; Error -> %% in case we change transaction to sync_dirty... - %% node_call(Type, delete_node, [NodeId]), - %% tree_call(Host, delete_node, [NodeId]), + %% node_call(Type, delete_node, [Host, Node]), + %% tree_call(Host, delete_node, [Host, Node]), Error end; Error -> @@ -1786,10 +1794,14 @@ delete_node(_Host, [], _Owner) -> {error, 'not-allowed'}; delete_node(Host, Node, Owner) -> Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + SubsByDepth = get_collection_subscriptions(Host, Node), case node_call(Type, get_affiliation, [NodeId, Owner]) of {result, owner} -> - Removed = tree_call(Host, delete_node, [NodeId]), - node_call(Type, delete_node, [Removed]); + Removed = tree_call(Host, delete_node, [Host, Node]), + case node_call(Type, delete_node, [Removed]) of + {result, Res} -> {result, {SubsByDepth, Res}}; + Error -> Error + end; _ -> %% Entity is not an owner {error, 'forbidden'} @@ -1797,27 +1809,27 @@ delete_node(Host, Node, Owner) -> end, Reply = [], case transaction(Host, Node, Action, transaction) of - {result, {_, {Result, broadcast, Removed}}} -> - lists:foreach(fun({RNode, RSubscriptions}) -> + {result, {_, {SubsByDepth, {Result, broadcast, Removed}}}} -> + lists:foreach(fun({RNode, _RSubscriptions}) -> {RH, RN} = RNode#pubsub_node.nodeid, NodeId = RNode#pubsub_node.id, Type = RNode#pubsub_node.type, Options = RNode#pubsub_node.options, - broadcast_removed_node(RH, RN, NodeId, Type, Options, RSubscriptions), + broadcast_removed_node(RH, RN, NodeId, Type, Options, SubsByDepth), unset_cached_item(RH, NodeId) end, Removed), case Result of default -> {result, Reply}; _ -> {result, Result} end; - {result, {_, {Result, _Removed}}} -> + {result, {_, {_, {Result, _Removed}}}} -> case Result of default -> {result, Reply}; _ -> {result, Result} end; - {result, {_, default}} -> + {result, {_, {_, default}}} -> {result, Reply}; - {result, {_, Result}} -> + {result, {_, {_, Result}}} -> {result, Result}; Error -> Error @@ -1858,7 +1870,7 @@ subscribe_node(Host, Node, From, JID, Configuration) -> Features = features(Type), SubscribeFeature = lists:member("subscribe", Features), OptionsFeature = lists:member("subscription-options", Features), - HasOptions = not (SubOpts == []), + HasOptions = not (SubOpts == []), SubscribeConfig = get_option(Options, subscribe), AccessModel = get_option(Options, access_model), SendLast = get_option(Options, send_last_published_item), @@ -1898,35 +1910,37 @@ subscribe_node(Host, Node, From, JID, Configuration) -> end, Reply = fun(Subscription) -> %% TODO, this is subscription-notification, should depends on node features + SubAttrs = case Subscription of + {subscribed, SubId} -> + [{"subscription", subscription_to_string(subscribed)}, + {"subid", SubId}]; + Other -> + [{"subscription", subscription_to_string(Other)}] + end, Fields = - [?XMLATTR('node', node_to_string(Node)), - ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), - ?XMLATTR('subscription', subscription_to_string(Subscription))], + [ ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)) | SubAttrs], #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = - [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = - case Subscription of - subscribed -> [?XMLATTR('subid', SubId)|Fields]; - _ -> Fields - end}]} + [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = Fields}]} end, case transaction(Host, Node, Action, sync_dirty) of - {result, {TNode, {Result, subscribed, send_last}}} -> + {result, {TNode, {Result, subscribed, SubId, send_last}}} -> NodeId = TNode#pubsub_node.id, Type = TNode#pubsub_node.type, send_items(Host, Node, NodeId, Type, Subscriber, last), case Result of - default -> {result, Reply(subscribed)}; - _ -> {result, Result} - end; - {result, {TNode, {Result, Subscription}}} -> - case Subscription of - pending -> send_authorization_request(TNode, Subscriber); - _ -> ok - end, - case Result of - default -> {result, Reply(Subscription)}; + default -> {result, Reply({subscribed, SubId})}; _ -> {result, Result} end; + {result, {_TNode, {default, subscribed, SubId}}} -> + {result, Reply({subscribed, SubId})}; + {result, {_TNode, {Result, subscribed, _SubId}}} -> + {result, Result}; + {result, {TNode, {default, pending, _SubId}}} -> + send_authorization_request(TNode, Subscriber), + {result, Reply(pending)}; + {result, {TNode, {Result, pending}}} -> + send_authorization_request(TNode, Subscriber), + {result, Result}; {result, {_, Result}} -> %% this case should never occure anyway {result, Result}; @@ -1992,7 +2006,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> Features = features(Type), PublishFeature = lists:member("publish", Features), PublishModel = get_option(Options, publish_model), - MaxItems = max_items(Options), + MaxItems = max_items(Host, Options), DeliverPayloads = get_option(Options, deliver_payloads), PersistItems = get_option(Options, persist_items), PayloadCount = payload_xmlelements(Payload), @@ -2276,7 +2290,7 @@ get_item(Host, Node, ItemId) -> end. %% @spec (Host, Node, NodeId, Type, LJID, Number) -> any() -%% Host = host() +%% Host = pubsubHost() %% Node = pubsubNode() %% NodeId = pubsubNodeId() %% Type = pubsubNodeType() @@ -2651,6 +2665,7 @@ get_subscriptions(Host, Node, JID) -> {result, {_, Subscriptions}} -> Entities = lists:flatmap( fun({_, none}) -> []; + ({_, pending, _}) -> []; ({{AU, AS, AR}, Subscription}) -> [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscription', attrs = [?XMLATTR('jid', exmpp_jid:to_binary(AU, AS, AR)), @@ -2681,19 +2696,20 @@ set_subscriptions(Host, Node, From, EntitiesEls) -> #xmlel{name = 'subscription', attrs = Attrs} -> JID = try exmpp_jid:parse( - exmpp_xml:get_attribute_from_list_as_list(Attrs, 'jid', "")) + exmpp_xml:get_attribute_from_list(Attrs, 'jid', "")) catch _:_ -> error end, Subscription = string_to_subscription( exmpp_xml:get_attribute_from_list_as_list(Attrs, 'subscription', false)), + SubId = exmpp_xml:get_attribute_from_list_as_list(Attrs, "subid", false), if (JID == error) or (Subscription == false) -> error; true -> - [{jlib:short_prepd_jid(JID), Subscription} | Acc] + [{JID, Subscription, SubId} | Acc] end end end @@ -2702,18 +2718,38 @@ set_subscriptions(Host, Node, From, EntitiesEls) -> error -> {error, 'bad-request'}; _ -> - Action = fun(#pubsub_node{type = Type, id = NodeId, owners = Owners}) -> - case lists:member(Owner, Owners) of - true -> - lists:foreach( - fun({JID, Subscription}) -> - node_call(Type, set_subscription, [NodeId, JID, Subscription]) - end, Entities), - {result, []}; - _ -> - {error, 'forbidden'} - end - end, + Notify = fun(JID, Sub, _SubId) -> + Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, + name = 'message', + children = + [#xmlel{ns = ?NS_PUBSUB, + name = 'pubsub', + children = + [#xmlel{ns = ?NS_PUBSUB, + name = 'subscription', + attrs = [?XMLATTR('jid', exmpp_jid:to_binary(JID)), + ?XMLATTR('subsription', subscription_to_string(Sub)) | nodeAttr(Node)]}]}]}, + + ejabberd_router ! {route, service_jid(Host), JID, Stanza} + end, + Action = fun(#pubsub_node{owners = Owners, type = Type, id = NodeId}) -> + case lists:member(Owner, Owners) of + true -> + Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> + + case node_call(Type, set_subscriptions, [NodeId, JID, Subscription, SubId]) of + {error, Err} -> [{error, Err} | Acc]; + _ -> Notify(JID, Subscription, SubId), Acc + end + end, [], Entities), + case Result of + [] -> {result, []}; + _ -> {error, 'not-acceptable'} + end; + _ -> + {error, 'forbidden'} + end + end, case transaction(Host, Node, Action, sync_dirty) of {result, {_, Result}} -> {result, Result}; Other -> Other @@ -2799,7 +2835,7 @@ service_jid(Host) -> _ -> exmpp_jid:make(Host) end. -%% @spec (LJID, PresenceDelivery) -> boolean() +%% @spec (LJID, NotifyType, Depth, NodeOptions, SubOptions) -> boolean() %% LJID = jid() %% NotifyType = items | nodes %% Depth = integer() @@ -2889,13 +2925,13 @@ broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, _From {result, false} end. -broadcast_retract_items(Host, Node, NodeId, Type, Options, ItemIds) -> - broadcast_retract_items(Host, Node, NodeId, Type, Options, ItemIds, false). -broadcast_retract_items(_Host, _Node, _NodeId, _Type, _Options, [], _ForceNotify) -> +broadcast_retract_items(Host, Node, NodeId, Type, NodeOptions, ItemIds) -> + broadcast_retract_items(Host, Node, NodeId, Type, NodeOptions, ItemIds, false). +broadcast_retract_items(_Host, _Node, _NodeId, _Type, _NodeOptions, [], _ForceNotify) -> {result, false}; -broadcast_retract_items(Host, Node, NodeId, Type, Options, ItemIds, ForceNotify) -> - %broadcast(Host, Node, NodeId, Options, notify_retract, ForceNotify, 'retract', RetractEls) - case (get_option(Options, notify_retract) or ForceNotify) of +broadcast_retract_items(Host, Node, NodeId, Type, NodeOptions, ItemIds, ForceNotify) -> + %broadcast(Host, Node, NodeId, NodeOptions, notify_retract, ForceNotify, 'retract', RetractEls) + case (get_option(NodeOptions, notify_retract) or ForceNotify) of true -> case get_collection_subscriptions(Host, Node) of [] -> @@ -2905,7 +2941,7 @@ broadcast_retract_items(Host, Node, NodeId, Type, Options, ItemIds, ForceNotify) Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = itemAttr(ItemId)} || ItemId <- ItemIds]}]), - broadcast_stanza(Host, Node, NodeId, Type, Options, SubsByDepth, items, Stanza), + broadcast_stanza(Host, Node, NodeId, Type, NodeOptions, SubsByDepth, items, Stanza), {result, true}; _ -> {result, false} @@ -2914,9 +2950,9 @@ broadcast_retract_items(Host, Node, NodeId, Type, Options, ItemIds, ForceNotify) {result, false} end. -broadcast_purge_node(Host, Node, NodeId, Type, Options) -> - %broadcast(Host, Node, NodeId, Options, notify_retract, false, 'purge', []) - case get_option(Options, notify_retract) of +broadcast_purge_node(Host, Node, NodeId, Type, NodeOptions) -> + %broadcast(Host, Node, NodeId, NodeOptions, notify_retract, false, 'purge', []) + case get_option(NodeOptions, notify_retract) of true -> case get_collection_subscriptions(Host, Node) of [] -> @@ -2924,7 +2960,7 @@ broadcast_purge_node(Host, Node, NodeId, Type, Options) -> SubsByDepth when is_list(SubsByDepth) -> Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'purge', attrs = nodeAttr(Node)}]), - broadcast_stanza(Host, Node, NodeId, Type, Options, SubsByDepth, nodes, Stanza), + broadcast_stanza(Host, Node, NodeId, Type, NodeOptions, SubsByDepth, nodes, Stanza), {result, true}; _ -> {result, false} @@ -2933,43 +2969,43 @@ broadcast_purge_node(Host, Node, NodeId, Type, Options) -> {result, false} end. -broadcast_removed_node(Host, Node, NodeId, Type, Options, Subs) -> - %broadcast(Host, Node, NodeId, Options, notify_delete, false, 'delete', []) - case get_option(Options, notify_delete) of +broadcast_removed_node(Host, Node, NodeId, Type, NodeOptions, SubsByDepth) -> + %broadcast(Host, Node, NodeId, NodeOptions, notify_delete, false, 'delete', []) + case get_option(NodeOptions, notify_delete) of true -> - case Subs of + case SubsByDepth of [] -> {result, false}; _ -> Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'delete', attrs = nodeAttr(Node)}]), - broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, nodes, Stanza), + broadcast_stanza(Host, Node, NodeId, Type, NodeOptions, SubsByDepth, nodes, Stanza), {result, true} end; _ -> {result, false} end. -broadcast_config_notification(Host, Node, NodeId, Type, Options, Lang) -> - %broadcast(Host, Node, NodeId, Options, notify_config, false, 'items', ConfigEls) - case get_option(Options, notify_config) of +broadcast_config_notification(Host, Node, NodeId, Type, NodeOptions, Lang) -> + %broadcast(Host, Node, NodeId, NodeOptions, notify_config, false, 'items', ConfigEls) + case get_option(NodeOptions, notify_config) of true -> case get_collection_subscriptions(Host, Node) of [] -> {result, false}; SubsByDepth when is_list(SubsByDepth) -> - Content = case get_option(Options, deliver_payloads) of + Content = case get_option(NodeOptions, deliver_payloads) of true -> [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = - get_configure_xfields(Type, Options, Lang, [])}]; - false -> - [] + get_configure_xfields(Type, NodeOptions, Lang, [])}]; + false -> + [] end, Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = [?XMLATTR('id', <<"configuration">>)], children = Content}]}]), - broadcast_stanza(Host, Node, NodeId, Type, Options, SubsByDepth, nodes, Stanza), + broadcast_stanza(Host, Node, NodeId, Type, NodeOptions, SubsByDepth, nodes, Stanza), {result, true}; _ -> {result, false} @@ -2995,22 +3031,24 @@ get_node_subs(#pubsub_node{type = Type, get_options_for_subs(_Host, Node, NodeID, Subs) -> lists:foldl(fun({JID, subscribed, SubID}, Acc) -> - {result, #pubsub_subscription{options = Options}} = pubsub_subscription:get_subscription(JID, NodeID, SubID), - [{JID, Node, Options} | Acc]; + case pubsub_subscription:get_subscription(JID, NodeID, SubID) of + {result, #pubsub_subscription{options = Options}} -> [{JID, Node, Options} | Acc]; + _ -> Acc + end; (_, Acc) -> Acc end, [], Subs). % TODO: merge broadcast code that way -%broadcast(Host, Node, NodeId, Type, Options, Feature, Force, ElName, SubEls) -> -% case (get_option(Options, Feature) or Force) of +%broadcast(Host, Node, NodeId, Type, NodeOptions, Feature, Force, ElName, SubEls) -> +% case (get_option(NodeOptions, Feature) or Force) of % true -> % case node_action(Host, Type, get_node_subscriptions, [NodeId]) of % {result, []} -> % {result, false}; % {result, Subs} -> % Stanza = event_stanza([{xmlelement, ElName, [{"node", node_to_string(Node)}], SubEls}]), -% broadcast_stanza(Host, Node, Type, Options, Subs, Stanza), +% broadcast_stanza(Host, Node, Type, NodeOptions, SubOpts, Stanza), % {result, true}; % _ -> % {result, false} @@ -3116,7 +3154,7 @@ collate_subs_by_jid(SubsByDepth) -> end, lists:keystore(JID, 1, Acc, {JID, [Node | OldNodes]}) end, [], SubsByDepth). - + %% If we don't know the resource, just pick first if any %% If no resource available, check if caps anyway (remote online) user_resources(User, Server) -> @@ -3198,7 +3236,8 @@ node_options(Type) -> Result end. -%% @spec (Options) -> MaxItems +%% @spec (Host, Options) -> MaxItems +%% Host = host() %% Options = [Option] %% Option = {Key::atom(), Value::term()} %% MaxItems = integer() | unlimited @@ -3208,7 +3247,7 @@ node_options(Type) -> %% @todo In practice, the current data structure means that we cannot manage %% millions of items on a given node. This should be addressed in a new %% version. -max_items(Options) -> +max_items(Host, Options) -> case get_option(Options, persist_items) of true -> case get_option(Options, max_items) of @@ -3218,8 +3257,13 @@ max_items(Options) -> end; false -> case get_option(Options, send_last_published_item) of - never -> 0; - _ -> 1 + never -> + 0; + _ -> + case is_last_item_cache_enabled(Host) of + true -> 0; + false -> 1 + end end end. @@ -3306,8 +3350,10 @@ set_configure(Host, Node, From, Els, Lang) -> end, case set_xoption(XData, OldOpts) of NewOpts when is_list(NewOpts) -> - tree_call(Host, set_node, [N#pubsub_node{options = NewOpts}]), - {result, ok}; + case tree_call(Host, set_node, [N#pubsub_node{options = NewOpts}]) of + ok -> {result, ok}; + Err -> Err + end; Err -> Err end @@ -3412,35 +3458,45 @@ set_xoption([{"pubsub#type", Value} | Opts], NewOpts) -> ?SET_STRING_XOPT(type, Value); set_xoption([{"pubsub#body_xslt", Value} | Opts], NewOpts) -> ?SET_STRING_XOPT(body_xslt, Value); +set_xoption([{"pubsub#collection", Value} | Opts], NewOpts) -> + NewValue = [string_to_node(V) || V <- Value], + ?SET_LIST_XOPT(collection, NewValue); +set_xoption([{"pubsub#node", [Value]} | Opts], NewOpts) -> + NewValue = string_to_node(Value), + ?SET_LIST_XOPT(node, NewValue); set_xoption([_ | Opts], NewOpts) -> % skip unknown field set_xoption(Opts, NewOpts). %%%% last item cache handling +is_last_item_cache_enabled({_, ServerHost, _}) -> + is_last_item_cache_enabled(ServerHost); +is_last_item_cache_enabled(Host) -> + case ets:lookup(gen_mod:get_module_proc(Host, config), last_item_cache) of + [{last_item_cache, true}] -> true; + _ -> false + end. + set_cached_item({_, ServerHost, _}, NodeId, ItemId, Payload) -> set_cached_item(ServerHost, NodeId, ItemId, Payload); set_cached_item(Host, NodeId, ItemId, Payload) -> - case ets:lookup(gen_mod:get_module_proc(Host, config), last_item_cache) of - [{last_item_cache, true}] -> - ets:insert(gen_mod:get_module_proc(Host, last_items), {NodeId, {ItemId, Payload}}); - _ -> - ok + case is_last_item_cache_enabled(Host) of + true -> ets:insert(gen_mod:get_module_proc(Host, last_items), {NodeId, {ItemId, Payload}}); + _ -> ok end. unset_cached_item({_, ServerHost, _}, NodeId) -> unset_cached_item(ServerHost, NodeId); unset_cached_item(Host, NodeId) -> - case ets:lookup(gen_mod:get_module_proc(Host, config), last_item_cache) of - [{last_item_cache, true}] -> - ets:delete(gen_mod:get_module_proc(Host, last_items), NodeId); - _ -> - ok + case is_last_item_cache_enabled(Host) of + true -> ets:delete(gen_mod:get_module_proc(Host, last_items), NodeId); + _ -> ok end. get_cached_item({_, ServerHost, _}, NodeId) -> get_cached_item(ServerHost, NodeId); get_cached_item(Host, NodeId) -> - case ets:lookup(gen_mod:get_module_proc(Host, config), last_item_cache) of - [{last_item_cache, true}] -> + case is_last_item_cache_enabled(Host) of + true -> case ets:lookup(gen_mod:get_module_proc(Host, last_items), NodeId) of [{NodeId, {ItemId, Payload}}] -> #pubsub_item{itemid = {ItemId, NodeId}, payload = Payload}; @@ -3477,12 +3533,12 @@ select_type(ServerHost, Host, Node, Type) -> true -> SelectedType; false -> hd(ConfiguredTypes) end. -select_type(ServerHost, Host, Node) -> +select_type(ServerHost, Host, Node) -> select_type(ServerHost, Host, Node, hd(plugins(ServerHost))). features() -> [ - %TODO "access-authorize", % OPTIONAL + % see plugin "access-authorize", % OPTIONAL "access-open", % OPTIONAL this relates to access_model option in node_hometree "access-presence", % OPTIONAL this relates to access_model option in node_pep %TODO "access-roster", % OPTIONAL @@ -3496,7 +3552,7 @@ features() -> % see plugin "delete-items", % RECOMMENDED % see plugin "delete-nodes", % RECOMMENDED % see plugin "filtered-notifications", % RECOMMENDED - %TODO "get-pending", % OPTIONAL + % see plugin "get-pending", % OPTIONAL % see plugin "instant-nodes", % RECOMMENDED "item-ids", % RECOMMENDED "last-published", % RECOMMENDED @@ -3506,8 +3562,8 @@ features() -> "member-affiliation", % RECOMMENDED %TODO "meta-data", % RECOMMENDED % see plugin "modify-affiliations", % OPTIONAL - %TODO "multi-collection", % OPTIONAL - %TODO "multi-subscribe", % OPTIONAL + % see plugin "multi-collection", % OPTIONAL + % see plugin "multi-subscribe", % OPTIONAL % see plugin "outcast-affiliation", % RECOMMENDED % see plugin "persistent-items", % RECOMMENDED "presence-notifications", % OPTIONAL @@ -3521,8 +3577,9 @@ features() -> "retrieve-default" % RECOMMENDED % see plugin "retrieve-items", % RECOMMENDED % see plugin "retrieve-subscriptions", % RECOMMENDED + %TODO "shim", % OPTIONAL % see plugin "subscribe", % REQUIRED - %TODO "subscription-options", % OPTIONAL + % see plugin "subscription-options", % OPTIONAL % see plugin "subscription-notifications" % OPTIONAL ]. features(Type) -> diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index 1fe51b38d..c71d9c1ae 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -536,7 +536,7 @@ remove_extra_items(NodeId, MaxItems, ItemIds) -> %% ItemId = string() %% @doc

    Triggers item deletion.

    %%

    Default plugin: The user performing the deletion must be the node owner -%% or a publisher.

    +%% or a publisher, or PublishModel being open.

    delete_item(NodeId, Publisher, PublishModel, ItemId) -> GenKey = jlib:short_prepd_bare_jid(Publisher), GenState = get_state(NodeId, GenKey), @@ -696,7 +696,10 @@ set_subscriptions(NodeId, Owner, Subscription, SubId) -> SubState = get_state(NodeId, SubKey), case {SubId, SubState#pubsub_state.subscriptions} of {_, []} -> - {error, 'item-not-found'}; + case Subscription of + none -> ok; + _ -> new_subscription(NodeId, Owner, Subscription, SubState) + end; {"", [{_, SID}]} -> case Subscription of none -> unsub_with_subid(NodeId, SID, SubState); @@ -721,8 +724,14 @@ replace_subscription(_, [], Acc) -> replace_subscription({Sub, SubId}, [{_, SubID} | T], Acc) -> replace_subscription({Sub, SubId}, T, [{Sub, SubID} | Acc]). +new_subscription(NodeId, Owner, Subscription, SubState) -> + SubId = pubsub_subscription:add_subscription(Owner, NodeId, []), + Subscriptions = SubState#pubsub_state.subscriptions, + set_state(SubState#pubsub_state{subscriptions = [{Subscription, SubId} | Subscriptions]}), + {Subscription, SubId}. + unsub_with_subid(NodeId, SubId, SubState) -> - pubsub_subscription:unsubscribe_node(SubState#pubsub_state.stateid, + pubsub_subscription:delete_subscription(SubState#pubsub_state.stateid, NodeId, SubId), NewSubs = lists:filter(fun ({_, SID}) -> SubId =/= SID end, SubState#pubsub_state.subscriptions), diff --git a/src/mod_pubsub/pubsub.hrl b/src/mod_pubsub/pubsub.hrl index 3a018188a..9d400185a 100644 --- a/src/mod_pubsub/pubsub.hrl +++ b/src/mod_pubsub/pubsub.hrl @@ -107,7 +107,7 @@ -record(pubsub_state, {stateid, items = [], affiliation = none, - subscriptions = none + subscriptions = [] }). %%% @type pubsubItem() = #pubsub_item{ From 4d5bfe2ee8451a76ee951a4aa72b51447ba2709f Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Tue, 25 Aug 2009 20:03:28 +0000 Subject: [PATCH 516/582] Fix pubsub_publish_item_ hook call parameter and jid conversion on node_hometree. published messages are delivered to subscribers (flat nodes). SVN Revision: 2537 --- src/mod_pubsub/mod_pubsub.erl | 3 ++- src/mod_pubsub/node_hometree.erl | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index f3d7a6fa6..2a68aa629 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -2037,7 +2037,8 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> node_call(Type, publish_item, [NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload]) end end, - ejabberd_hooks:run(pubsub_publish_item, ServerHost, [ServerHost, Node, Publisher, service_jid(Host), ItemId, Payload]), + ServerHostB = list_to_binary(ServerHost), + ejabberd_hooks:run(pubsub_publish_item, ServerHostB, [ServerHost, Node, Publisher, service_jid(Host), ItemId, Payload]), Reply = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'publish', attrs = nodeAttr(Node), children = [#xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = itemAttr(ItemId)}]}]}, diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index c71d9c1ae..134ee4894 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -460,7 +460,7 @@ delete_subscription(SubKey, NodeID, {Subscription, SubId}, SubState) -> %%

    In the default plugin module, the record is unchanged.

    publish_item(NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload) -> SubKey = jlib:short_prepd_jid(Publisher), - GenKey = jlib:short_prepd_bare_jid(SubKey), + GenKey = jlib:short_prepd_bare_jid(Publisher), GenState = get_state(NodeId, GenKey), SubState = case SubKey of GenKey -> GenState; From f7c5a4a15b7397733d0ccb71dfd97d5306db6edc Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Tue, 25 Aug 2009 20:33:01 +0000 Subject: [PATCH 517/582] backport trunk commit r2530 SVN Revision: 2538 --- src/mod_pubsub/mod_pubsub.erl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 2a68aa629..6733e8d5e 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -3701,8 +3701,9 @@ itemsEls(Items) -> #xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = itemAttr(ItemId), children = Payload} end, Items). -add_headers(#xmlel{} = El, Headers) -> - exmpp_xml:append_children(El, Headers). +add_headers(#xmlel{} = El, HeaderEls) -> + HeaderEl = #xmlel{ns = ?NS_SHIM, name = 'headers', children = HeaderEls}, + exmpp_xml:prepend_child(El, HeaderEl). collection_shim(Node, Nodes) -> [#xmlel{ns = ?NS_PUBSUB, name ='header', From ba3a45452e35d36e9b253c990075363b65d4d163 Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 26 Aug 2009 04:18:42 +0000 Subject: [PATCH 518/582] check if a room is not persistent before starting a new one with the same name (EJAB-1026) SVN Revision: 2540 --- src/mod_muc/mod_muc.erl | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl index d8de5af3b..6215aff10 100644 --- a/src/mod_muc/mod_muc.erl +++ b/src/mod_muc/mod_muc.erl @@ -454,8 +454,7 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper, AccessCreate, From, Room) of true -> - ?DEBUG("MUC: open new room '~s'~n", [Room]), - {ok, Pid} = mod_muc_room:start( + {ok, Pid} = start_new_room( Host, ServerHost, Access, Room, HistorySize, RoomShaper, From, @@ -527,6 +526,23 @@ load_permanent_rooms(Host, ServerHost, Access, HistorySize, RoomShaper) -> end, Rs) end. +start_new_room(Host, ServerHost, Access, Room, + HistorySize, RoomShaper, From, + Nick, DefRoomOpts) -> + case mnesia:dirty_read(muc_room, {Room, Host}) of + [] -> + ?DEBUG("MUC: open new room '~s'~n", [Room]), + mod_muc_room:start(Host, ServerHost, Access, + Room, HistorySize, + RoomShaper, From, + Nick, DefRoomOpts); + [#muc_room{opts = Opts}|_] -> + ?DEBUG("MUC: restore room '~s'~n", [Room]), + mod_muc_room:start(Host, ServerHost, Access, + Room, HistorySize, + RoomShaper, Opts) + end. + register_room(Host, Room, Pid) when is_binary(Host), is_binary(Room) -> F = fun() -> mnesia:write(#muc_online_room{name_host = {Room, Host}, From 944dd1cc7f81ae8310b5581729062fec557cec16 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Wed, 26 Aug 2009 20:27:57 +0000 Subject: [PATCH 519/582] Port pubsub odbc backend to exmpp. Warning: A work in progress, isn't working yet! SVN Revision: 2541 --- src/mod_pubsub/Makefile.in | 5 +- src/mod_pubsub/mod_pubsub_odbc.erl | 3599 +++++++++++++++++++ src/mod_pubsub/node_flat_odbc.erl | 183 + src/mod_pubsub/node_hometree_odbc.erl | 1324 +++++++ src/mod_pubsub/node_pep_odbc.erl | 327 ++ src/mod_pubsub/nodetree_tree_odbc.erl | 357 ++ src/mod_pubsub/pubsub_db_odbc.erl | 138 + src/mod_pubsub/pubsub_odbc.patch | 672 ++++ src/mod_pubsub/pubsub_subscription_odbc.erl | 294 ++ 9 files changed, 6898 insertions(+), 1 deletion(-) create mode 100644 src/mod_pubsub/mod_pubsub_odbc.erl create mode 100644 src/mod_pubsub/node_flat_odbc.erl create mode 100644 src/mod_pubsub/node_hometree_odbc.erl create mode 100644 src/mod_pubsub/node_pep_odbc.erl create mode 100644 src/mod_pubsub/nodetree_tree_odbc.erl create mode 100644 src/mod_pubsub/pubsub_db_odbc.erl create mode 100644 src/mod_pubsub/pubsub_odbc.patch create mode 100644 src/mod_pubsub/pubsub_subscription_odbc.erl diff --git a/src/mod_pubsub/Makefile.in b/src/mod_pubsub/Makefile.in index 4088303cb..88bf2ba0c 100644 --- a/src/mod_pubsub/Makefile.in +++ b/src/mod_pubsub/Makefile.in @@ -25,7 +25,7 @@ ERLBEHAVBEAMS = $(addprefix $(OUTDIR)/,$(ERLBEHAVS:.erl=.beam)) BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam)) -all: $(ERLBEHAVBEAMS) $(BEAMS) +all: mod_pubsub_odbc.erl $(ERLBEHAVBEAMS) $(BEAMS) $(BEAMS): $(ERLBEHAVBEAMS) @@ -38,6 +38,9 @@ clean: distclean: clean rm -f Makefile +mod_pubsub_odbc.erl: + patch -o mod_pubsub_odbc.erl mod_pubsub.erl pubsub_odbc.patch + TAGS: etags *.erl diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl new file mode 100644 index 000000000..75c593939 --- /dev/null +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -0,0 +1,3599 @@ +%%% ==================================================================== +%%% ``The contents of this file are subject to the Erlang Public License, +%%% Version 1.1, (the "License"); you may not use this file except in +%%% compliance with the License. You should have received a copy of the +%%% Erlang Public License along with this software. If not, it can be +%%% retrieved via the world wide web at http://www.erlang.org/. +%%% +%%% Software distributed under the License is distributed on an "AS IS" +%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%%% the License for the specific language governing rights and limitations +%%% under the License. +%%% +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne +%%% All Rights Reserved.'' +%%% This software is copyright 2006-2009, ProcessOne. +%%% +%%% @copyright 2006-2009 ProcessOne +%%% @author Christophe Romain +%%% [http://www.process-one.net/] +%%% @version {@vsn}, {@date} {@time} +%%% @end +%%% ==================================================================== + + +%%% @doc The module {@module} is the core of the PubSub +%%% extension. It relies on PubSub plugins for a large part of its functions. +%%% +%%% @headerfile "pubsub.hrl" +%%% +%%% @reference See XEP-0060: Pubsub for +%%% the latest version of the PubSub specification. +%%% This module uses version 1.12 of the specification as a base. +%%% Most of the specification is implemented. +%%% Functions concerning configuration should be rewritten. +%%% +%%% Support for subscription-options and multi-subscribe features was +%%% added by Brian Cully (bjc AT kublai.com). Subscriptions and options are +%%% stored in the pubsub_subscription table, with a link to them provided +%%% by the subscriptions field of pubsub_state. For information on +%%% subscription-options and mulit-subscribe see XEP-0060 sections 6.1.6, +%%% 6.2.3.1, 6.2.3.5, and 6.3. For information on subscription leases see +%%% XEP-0060 section 12.18. + +%%% TODO +%%% plugin: generate Reply (do not use broadcast atom anymore) + +-module(mod_pubsub_odbc). +-author('christophe.romain@process-one.net'). +-version('1.12-06'). + +-behaviour(gen_server). +-behaviour(gen_mod). + +-include_lib("exmpp/include/exmpp.hrl"). + +-include("ejabberd.hrl"). +-include("adhoc.hrl"). +-include("pubsub.hrl"). + +-define(STDTREE, "tree_odbc"). +-define(STDNODE, "flat_odbc"). +-define(PEPNODE, "pep_odbc"). + +%% exports for hooks +-export([presence_probe/3, + in_subscription/6, + out_subscription/4, + remove_user/2, + disco_local_identity/5, + disco_local_features/5, + disco_local_items/5, + disco_sm_identity/5, + disco_sm_features/5, + disco_sm_items/5 + ]). +%% exported iq handlers +-export([iq_local/3, + iq_sm/3 + ]). + +%% exports for console debug manual use +-export([create_node/5, + delete_node/3, + subscribe_node/5, + unsubscribe_node/5, + publish_item/6, + delete_item/4, + send_items/6, + get_items/2, + get_item/3, + get_cached_item/2, + broadcast_stanza/8, + get_configure/5, + set_configure/5, + tree_action/3, + node_action/4 + ]). + +%% general helpers for plugins +-export([node_to_string/1, + string_to_node/1, + subscription_to_string/1, + affiliation_to_string/1, + string_to_subscription/1, + string_to_affiliation/1, + extended_error/2, + extended_error/3, + escape/1 + ]). + +%% API and gen_server callbacks +-export([start_link/2, + start/2, + stop/1, + init/1, + handle_call/3, + handle_cast/2, + handle_info/2, + terminate/2, + code_change/3 + ]). + +%% calls for parallel sending of last items +-export([send_loop/1 + ]). + +-define(PROCNAME, ejabberd_mod_pubsub_odbc). +-define(PLUGIN_PREFIX, "node_"). +-define(TREE_PREFIX, "nodetree_"). + +-record(state, {server_host, + host, + access, + pep_mapping = [], + pep_sendlast_offline = false, + last_item_cache = false, + nodetree = ?STDTREE, + plugins = [?STDNODE], + send_loop}). + + +%%------------------- Ad hoc commands nodes -------------------------- +-define(NS_PUBSUB_GET_PENDING, "http://jabber.org/protocol/pubsub#get-pending"). +%%-------------------------------------------------------------------- + + +%%==================================================================== +%% API +%%==================================================================== +%%-------------------------------------------------------------------- +%% Function: start_link() -> {ok,Pid} | ignore | {error,Error} +%% Description: Starts the server +%%-------------------------------------------------------------------- +start_link(Host, Opts) -> + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []). + +start(Host, Opts) -> + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + ChildSpec = {Proc, + {?MODULE, start_link, [Host, Opts]}, + transient, 1000, worker, [?MODULE]}, + supervisor:start_child(ejabberd_sup, ChildSpec). + +stop(Host) -> + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + gen_server:call(Proc, stop), + supervisor:delete_child(ejabberd_sup, Proc). + +%%==================================================================== +%% gen_server callbacks +%%==================================================================== + +%%-------------------------------------------------------------------- +%% Function: init(Args) -> {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%-------------------------------------------------------------------- +init([ServerHost, Opts]) -> + ?DEBUG("pubsub init ~p ~p",[ServerHost,Opts]), + Host = gen_mod:get_opt_host(ServerHost, Opts, "pubsub.@HOST@"), + Access = gen_mod:get_opt(access_createnode, Opts, all), + PepOffline = gen_mod:get_opt(pep_sendlast_offline, Opts, false), + IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), + LastItemCache = gen_mod:get_opt(last_item_cache, Opts, false), + ServerHostB = list_to_binary(ServerHost), + pubsub_index:init(Host, ServerHost, Opts), + ets:new(gen_mod:get_module_proc(Host, config), [set, named_table]), + ets:new(gen_mod:get_module_proc(ServerHost, config), [set, named_table]), + ets:new(gen_mod:get_module_proc(Host, last_items), [set, named_table]), + ets:new(gen_mod:get_module_proc(ServerHost, last_items), [set, named_table]), + {Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts), + mod_disco:register_feature(ServerHost, ?NS_PUBSUB_s), + ets:insert(gen_mod:get_module_proc(Host, config), {nodetree, NodeTree}), + ets:insert(gen_mod:get_module_proc(Host, config), {plugins, Plugins}), + ets:insert(gen_mod:get_module_proc(Host, config), {last_item_cache, LastItemCache}), + ets:insert(gen_mod:get_module_proc(ServerHost, config), {nodetree, NodeTree}), + ets:insert(gen_mod:get_module_proc(ServerHost, config), {plugins, Plugins}), + ets:insert(gen_mod:get_module_proc(ServerHost, config), {pep_mapping, PepMapping}), + ejabberd_hooks:add(disco_sm_identity, ServerHostB, ?MODULE, disco_sm_identity, 75), + ejabberd_hooks:add(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), + ejabberd_hooks:add(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75), + ejabberd_hooks:add(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 80), + ejabberd_hooks:add(roster_in_subscription, ServerHostB, ?MODULE, in_subscription, 50), + ejabberd_hooks:add(roster_out_subscription, ServerHostB, ?MODULE, out_subscription, 50), + ejabberd_hooks:add(remove_user, ServerHostB, ?MODULE, remove_user, 50), + ejabberd_hooks:add(anonymous_purge_hook, ServerHostB, ?MODULE, remove_user, 50), + gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB, ?MODULE, iq_sm, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB_OWNER, ?MODULE, iq_sm, IQDisc), + ejabberd_router:register_route(Host), + case lists:member(?PEPNODE, Plugins) of + true -> + ejabberd_hooks:add(disco_local_identity, ServerHostB, ?MODULE, disco_local_identity, 75), + ejabberd_hooks:add(disco_local_features, ServerHostB, ?MODULE, disco_local_features, 75), + ejabberd_hooks:add(disco_local_items, ServerHostB, ?MODULE, disco_local_items, 75), + gen_iq_handler:add_iq_handler(ejabberd_local, ServerHostB, ?NS_PUBSUB, ?MODULE, iq_local, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_local, ServerHostB, ?NS_PUBSUB_OWNER, ?MODULE, iq_local, IQDisc); + false -> + ok + end, + ejabberd_router:register_route(Host), + init_nodes(Host, ServerHost), + State = #state{host = Host, + server_host = ServerHost, + access = Access, + pep_mapping = PepMapping, + pep_sendlast_offline = PepOffline, + last_item_cache = LastItemCache, + nodetree = NodeTree, + plugins = Plugins}, + SendLoop = spawn(?MODULE, send_loop, [State]), + {ok, State#state{send_loop = SendLoop}}. + +%% @spec (Host, ServerHost, Opts) -> Plugins +%% Host = mod_pubsub:host() Opts = [{Key,Value}] +%% ServerHost = host() +%% Key = atom() +%% Value = term() +%% Plugins = [Plugin::string()] +%% @doc Call the init/1 function for each plugin declared in the config file. +%% The default plugin module is implicit. +%%

    The Erlang code for the plugin is located in a module called +%% node_plugin. The 'node_' prefix is mandatory.

    +%%

    The modules are initialized in alphetical order and the list is checked +%% and sorted to ensure that each module is initialized only once.

    +%%

    See {@link node_hometree:init/1} for an example implementation.

    +init_plugins(Host, ServerHost, Opts) -> + TreePlugin = list_to_atom(?TREE_PREFIX ++ + gen_mod:get_opt(nodetree, Opts, ?STDTREE)), + ?DEBUG("** tree plugin is ~p",[TreePlugin]), + TreePlugin:init(Host, ServerHost, Opts), + Plugins = gen_mod:get_opt(plugins, Opts, [?STDNODE]), + PepMapping = gen_mod:get_opt(pep_mapping, Opts, []), + ?DEBUG("** PEP Mapping : ~p~n",[PepMapping]), + lists:foreach(fun(Name) -> + ?DEBUG("** init ~s plugin",[Name]), + Plugin = list_to_atom(?PLUGIN_PREFIX ++ Name), + Plugin:init(Host, ServerHost, Opts) + end, Plugins), + {Plugins, TreePlugin, PepMapping}. + +terminate_plugins(Host, ServerHost, Plugins, TreePlugin) -> + lists:foreach(fun(Name) -> + ?DEBUG("** terminate ~s plugin",[Name]), + Plugin = list_to_atom(?PLUGIN_PREFIX++Name), + Plugin:terminate(Host, ServerHost) + end, Plugins), + TreePlugin:terminate(Host, ServerHost), + ok. + +init_nodes(Host, ServerHost) -> + create_node(Host, ServerHost, ["home"], service_jid(Host), "hometree"), + create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), "hometree"), + ok. + + + +send_queue(State, Msg) -> + Pid = State#state.send_loop, + case is_process_alive(Pid) of + true -> + Pid ! Msg, + State; + false -> + SendLoop = spawn(?MODULE, send_loop, [State]), + SendLoop ! Msg, + State#state{send_loop = SendLoop} + end. + +send_loop(State) -> + receive + {presence, JID, Pid} -> + Host = State#state.host, + ServerHost = State#state.server_host, + LJID = jlib:short_prepd_jid(JID), + BJID = jlib:short_prepd_bare_jid(JID), + %% for each node From is subscribed to + %% and if the node is so configured, send the last published item to From + lists:foreach(fun(PType) -> + Subscriptions = case catch node_action(Host, PType, get_entity_subscriptions_for_send_last, [Host, JID]) of + {result, S} -> S; + _ -> [] + end, + lists:foreach( + fun({Node, subscribed, _, SubJID}) -> + if (SubJID == LJID) or (SubJID == BJID) -> + #pubsub_node{nodeid = {H, N}, type = Type, id = NodeId} = Node, + send_items(H, N, NodeId, Type, SubJID, last); + true -> + % resource not concerned about that subscription + ok + end; + (_) -> + ok + end, Subscriptions) + end, State#state.plugins), + %% and force send the last PEP events published by its offline and local contacts + %% only if pubsub is explicitely configured for that. + %% this is a hack in a sense that PEP should only be based on presence + %% and is not able to "store" events of remote users (via s2s) + %% this makes that hack only work for local domain by now + if State#state.pep_sendlast_offline -> + {User, Server, Resource} = LJID, + case mod_caps:get_caps({User, Server, Resource}) of + nothing -> + %% we don't have caps, no need to handle PEP items + ok; + _ -> + case catch ejabberd_c2s:get_subscribed(Pid) of + Contacts when is_list(Contacts) -> + lists:foreach( + fun({U, S, R}) -> + case S of + ServerHost -> %% local contacts + case ejabberd_sm:get_user_resources(U, S) of + [] -> %% offline + PeerJID = exmpp_jid:make(U, S, R), + self() ! {presence, User, Server, [Resource], PeerJID}; + _ -> %% online + % this is already handled by presence probe + ok + end; + _ -> %% remote contacts + % we can not do anything in any cases + ok + end + end, Contacts); + _ -> + ok + end + end; + true -> + ok + end, + send_loop(State); + {presence, User, Server, Resources, JID} -> + %% get resources caps and check if processing is needed + spawn(fun() -> + {HasCaps, ResourcesCaps} = lists:foldl(fun(Resource, {R, L}) -> + case mod_caps:get_caps({User, Server, Resource}) of + nothing -> {R, L}; + Caps -> {true, [{Resource, Caps} | L]} + end + end, {false, []}, Resources), + case HasCaps of + true -> + Host = State#state.host, + ServerHost = State#state.server_host, + Owner = jlib:short_prepd_bare_jid(JID), + lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = NodeId, options = Options}) -> + case get_option(Options, send_last_published_item) of + on_sub_and_presence -> + lists:foreach(fun({Resource, Caps}) -> + CapsNotify = case catch mod_caps:get_features(ServerHost, Caps) of + Features when is_list(Features) -> lists:member(Node ++ "+notify", Features); + _ -> false + end, + case CapsNotify of + true -> + LJID = {User, Server, Resource}, + Subscribed = case get_option(Options, access_model) of + open -> true; + presence -> true; + whitelist -> false; % subscribers are added manually + authorize -> false; % likewise + roster -> + Grps = get_option(Options, roster_groups_allowed, []), + {OU, OS, _} = Owner, + element(2, get_roster_info(OU, OS, LJID, Grps)) + end, + if Subscribed -> + send_items(Owner, Node, NodeId, Type, LJID, last); + true -> + ok + end; + false -> + ok + end + end, ResourcesCaps); + _ -> + ok + end + end, tree_action(Host, get_nodes, [Owner, JID])); + false -> + ok + end + end), + send_loop(State); + stop -> + ok + end. + +%% ------- +%% disco hooks handling functions +%% + +identity(Host) -> + Identity = case lists:member(?PEPNODE, plugins(Host)) of + true -> [?XMLATTR('category', <<"pubsub">>), ?XMLATTR('type', <<"pep">>)]; + false -> [?XMLATTR('category', <<"pubsub">>), ?XMLATTR('type', <<"service">>)] + end, + #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = Identity}. + +disco_local_identity(Acc, _From, To, <<>>, _Lang) -> + Acc ++ [identity(exmpp_jid:prep_domain_as_list(To))]; +disco_local_identity(Acc, _From, _To, _Node, _Lang) -> + Acc. + +disco_local_features(Acc, _From, To, <<>>, _Lang) -> + Host = exmpp_jid:prep_domain_as_list(To), + Feats = case Acc of + {result, I} -> I; + _ -> [] + end, + {result, Feats ++ lists:map(fun(Feature) -> + ?NS_PUBSUB_s++"#"++Feature + end, features(Host, []))}; +disco_local_features(Acc, _From, _To, _Node, _Lang) -> + Acc. + +disco_local_items(Acc, _From, _To, <<>>, _Lang) -> + Acc; +disco_local_items(Acc, _From, _To, _Node, _Lang) -> + Acc. + +disco_sm_identity(Acc, _From, To, <<>>, _Lang) -> + Acc ++ [identity(exmpp_jid:prep_domain_as_list(To))]; +disco_sm_identity(Acc, From, To, Node, _Lang) -> + LOwner = jlib:short_prepd_bare_jid(To), + Acc ++ case node_disco_identity(LOwner, From, Node) of + {result, I} -> I; + _ -> [] + end. + +disco_sm_features(Acc, _From, _To, [], _Lang) -> + Acc; +disco_sm_features(Acc, From, To, Node, _Lang) -> + LOwner = jlib:short_prepd_bare_jid(To), + Features = node_disco_features(LOwner, From, Node), + case {Acc, Features} of + {{result, AccFeatures}, {result, AddFeatures}} -> + {result, AccFeatures++AddFeatures}; + {_, {result, AddFeatures}} -> + {result, AddFeatures}; + {_, _} -> + Acc + end. + +disco_sm_items(Acc, From, To, <<>>, _Lang) -> + Host = exmpp_jid:prep_domain_as_list(To), + case tree_action(Host, get_subnodes, [Host, [], From]) of + [] -> + Acc; + Nodes -> + SBJID = jlib:short_prepd_bare_jid(To), + Items = case Acc of + {result, I} -> I; + _ -> [] + end, + NodeItems = lists:map( + fun(#pubsub_node{nodeid = {_, Node}}) -> + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = + [?XMLATTR('jid', exmpp_jid:to_binary(SBJID)) | nodeAttr(Node)]} + end, Nodes), + {result, NodeItems ++ Items} + end; + +disco_sm_items(Acc, From, To, NodeB, _Lang) -> + Node = binary_to_list(NodeB), + %% TODO, use iq_disco_items(Host, Node, From) + Host = exmpp_jid:prep_domain_as_list(To), + LJID = jlib:short_prepd_bare_jid(To), + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + case node_call(Type, get_items, [NodeId, From]) of + {result, []} -> + none; + {result, AllItems} -> + Items = case Acc of + {result, I} -> I; + _ -> [] + end, + NodeItems = lists:map( + fun(#pubsub_item{itemid = {Id, _}}) -> + %% "jid" is required by XEP-0030, and + %% "node" is forbidden by XEP-0060. + {result, Name} = node_call(Type, get_item_name, [Host, Node, Id]), + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = + [?XMLATTR('jid', exmpp_jid:to_binary(LJID)), + ?XMLATTR('name', Name)]} + end, AllItems), + {result, NodeItems ++ Items}; + _ -> + none + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Items}} -> {result, Items}; + _ -> Acc + end. + +%% ------- +%% presence hooks handling functions +%% + +presence_probe(JID, JID, Pid) -> + {User, Server, Resource} = jlib:short_prepd_jid(JID), + Host = exmpp_jid:prep_domain_as_list(JID), + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + gen_server:cast(Proc, {presence, JID, Pid}), + gen_server:cast(Proc, {presence, User, Server, [Resource], JID}); +presence_probe(Peer, JID, _Pid) -> + {User, Server, Resource} = jlib:short_prepd_jid(Peer), + Host = exmpp_jid:prep_domain_as_list(JID), + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + gen_server:cast(Proc, {presence, User, Server, [Resource], JID}). + +%% ------- +%% subscription hooks handling functions +%% + +out_subscription(User, Server, JID, subscribed) -> + Owner = exmpp_jid:make(User, Server, ""), + {U, S, R} = jlib:short_prepd_jid(JID), + Rs = case R of + [] -> user_resources(U, S); + _ -> [R] + end, + Proc = gen_mod:get_module_proc(Server, ?PROCNAME), + gen_server:cast(Proc, {presence, U, S, Rs, Owner}); +out_subscription(_, _, _, _) -> + ok. +in_subscription(_, User, Server, Owner, unsubscribed, _) -> + Subscriber = exmpp_jid:make(User, Server, ""), + Proc = gen_mod:get_module_proc(Server, ?PROCNAME), + gen_server:cast(Proc, {unsubscribe, Subscriber, Owner}); +in_subscription(_, _, _, _, _, _) -> + ok. + +%% ------- +%% user remove hook handling function +%% + +remove_user(User, Server) -> + LUser = exmpp_stringprep:nodeprep(User), + LServer = exmpp_stringprep:nameprep(Server), + Proc = gen_mod:get_module_proc(Server, ?PROCNAME), + gen_server:cast(Proc, {remove_user, LUser, LServer}). + +%%-------------------------------------------------------------------- +%% 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 +%%-------------------------------------------------------------------- +%% @private +handle_call(server_host, _From, State) -> + {reply, State#state.server_host, State}; +handle_call(plugins, _From, State) -> + {reply, State#state.plugins, State}; +handle_call(pep_mapping, _From, State) -> + {reply, State#state.pep_mapping, State}; +handle_call(nodetree, _From, State) -> + {reply, State#state.nodetree, State}; +handle_call(stop, _From, State) -> + {stop, normal, ok, State}. + +%%-------------------------------------------------------------------- +%% Function: handle_cast(Msg, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% Description: Handling cast messages +%%-------------------------------------------------------------------- +%% @private +handle_cast({presence, JID, Pid}, State) -> + %% A new resource is available. send last published items + {noreply, send_queue(State, {presence, JID, Pid})}; + +handle_cast({presence, User, Server, Resources, JID}, State) -> + %% A new resource is available. send last published PEP items + {noreply, send_queue(State, {presence, User, Server, Resources, JID})}; + +handle_cast({remove_user, LUser, LServer}, State) -> + Host = State#state.host, + Owner = exmpp_jid:make(LUser, LServer), + %% remove user's subscriptions + lists:foreach(fun(PType) -> + {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Owner]), + lists:foreach(fun + ({#pubsub_node{nodeid = {H, N}}, subscribed, _, JID}) -> + unsubscribe_node(H, N, Owner, JID, all); + (_) -> + ok + end, Subscriptions), + {result, Affiliations} = node_action(Host, PType, get_entity_affiliations, [Host, Owner]), + lists:foreach(fun + ({#pubsub_node{nodeid = {H, N}}, owner}) -> + delete_node(H, N, Owner); + (_) -> + ok + end, Affiliations) + end, State#state.plugins), + {noreply, State}; + +handle_cast({unsubscribe, Subscriber, Owner}, State) -> + Host = State#state.host, + BJID = jlib:short_prepd_bare_jid(Owner), + lists:foreach(fun(PType) -> + {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), + lists:foreach(fun + ({Node, subscribed, _, JID}) -> + #pubsub_node{options = Options, type = Type, id = NodeId} = Node, + case get_option(Options, access_model) of + presence -> + case lists:member(BJID, node_owners(Host, Type, NodeId)) of + true -> + node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); + false -> + {result, ok} + end; + _ -> + {result, ok} + end; + (_) -> + ok + end, Subscriptions) + end, State#state.plugins), + {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 +%%-------------------------------------------------------------------- +%% @private +handle_info({route, From, To, Packet}, + #state{server_host = ServerHost, + access = Access, + plugins = Plugins} = State) -> + case catch do_route(ServerHost, Access, Plugins, exmpp_jid:prep_domain_as_list(To), From, To, Packet) of + {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); + _ -> ok + end, + {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. +%%-------------------------------------------------------------------- +%% @private +terminate(_Reason, #state{host = Host, + server_host = ServerHost, + nodetree = TreePlugin, + plugins = Plugins, + send_loop = SendLoop}) -> + ejabberd_router:unregister_route(Host), + ServerHostB = list_to_binary(ServerHost), + case lists:member(?PEPNODE, Plugins) of + true -> + ejabberd_hooks:delete(disco_local_identity, ServerHostB, ?MODULE, disco_local_identity, 75), + ejabberd_hooks:delete(disco_local_features, ServerHostB, ?MODULE, disco_local_features, 75), + ejabberd_hooks:delete(disco_local_items, ServerHostB, ?MODULE, disco_local_items, 75), + gen_iq_handler:remove_iq_handler(ejabberd_local, ServerHostB, ?NS_PUBSUB), + gen_iq_handler:remove_iq_handler(ejabberd_local, ServerHostB, ?NS_PUBSUB_OWNER); + false -> + ok + end, + ejabberd_hooks:delete(disco_local_identity, ServerHostB, ?MODULE, disco_local_identity, 75), + ejabberd_hooks:delete(disco_local_features, ServerHostB, ?MODULE, disco_local_features, 75), + ejabberd_hooks:delete(disco_local_items, ServerHostB, ?MODULE, disco_local_items, 75), + ejabberd_hooks:delete(disco_sm_identity, ServerHostB, ?MODULE, disco_sm_identity, 75), + ejabberd_hooks:delete(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), + ejabberd_hooks:delete(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75), + ejabberd_hooks:delete(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 80), + ejabberd_hooks:delete(roster_in_subscription, ServerHostB, ?MODULE, in_subscription, 50), + ejabberd_hooks:delete(roster_out_subscription, ServerHostB, ?MODULE, out_subscription, 50), + ejabberd_hooks:delete(remove_user, ServerHostB, ?MODULE, remove_user, 50), + ejabberd_hooks:delete(anonymous_purge_hook, ServerHostB, ?MODULE, remove_user, 50), + gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB), + gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB_OWNER), + mod_disco:unregister_feature(ServerHost, ?NS_PUBSUB_s), + SendLoop ! stop, + terminate_plugins(Host, ServerHost, Plugins, TreePlugin). + +%%-------------------------------------------------------------------- +%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState} +%% Description: Convert process state when code is changed +%%-------------------------------------------------------------------- +%% @private +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +do_route(ServerHost, Access, Plugins, Host, From, To, Packet) -> + #xmlel{name = Name} = Packet, + LNode = exmpp_jid:prep_node(To), + LRes = exmpp_jid:prep_resource(To), + case {LNode, LRes} of + {undefined, undefined} -> + case Name of + 'iq' -> + case exmpp_iq:xmlel_to_iq(Packet) of + #iq{type = get, ns = ?NS_DISCO_INFO, + payload = SubEl, lang = Lang} -> + QAttrs = SubEl#xmlel.attrs, + Node = exmpp_xml:get_attribute_from_list_as_list(QAttrs, 'node', ""), + ServerHostB = list_to_binary(ServerHost), + Info = ejabberd_hooks:run_fold( + disco_info, ServerHostB, [], + [ServerHost, ?MODULE, <<>>, ""]), + Res = case iq_disco_info(Host, Node, From, Lang) of + {result, IQRes} -> + Result = #xmlel{ns = ?NS_DISCO_INFO, + name = 'query', attrs = QAttrs, + children = IQRes++Info}, + exmpp_iq:result(Packet, Result); + {error, Error} -> + exmpp_iq:error(Packet, Error) + end, + ejabberd_router:route(To, From, Res); + #iq{type = get, ns = ?NS_DISCO_ITEMS, + payload = SubEl} = IQ -> + QAttrs = SubEl#xmlel.attrs, + Node = exmpp_xml:get_attribute_from_list_as_list(QAttrs, + 'node', ""), + Rsm = jlib:rsm_decode(IQ), + Res = case iq_disco_items(Host, Node, From, Rsm) of + {result, IQRes} -> + Result = #xmlel{ns = ?NS_DISCO_ITEMS, + name = 'query', attrs = QAttrs, + children = IQRes}, + exmpp_iq:result(Packet, Result); + {error, Error} -> + exmpp_iq:error(Packet, Error) + end, + ejabberd_router:route(To, From, Res); + #iq{type = IQType, ns = ?NS_PUBSUB, + lang = Lang, payload = SubEl} -> + Res = + case iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) of + {result, IQRes} -> + exmpp_iq:result(Packet, IQRes); + {error, Error} -> + exmpp_iq:error(Packet, Error) + end, + ejabberd_router:route(To, From, Res); + #iq{type = IQType, ns = ?NS_PUBSUB_OWNER, + lang = Lang, payload = SubEl} -> + Res = + case iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) of + {result, []} -> + exmpp_iq:result(Packet); + {result, IQRes} -> + exmpp_iq:result(Packet, IQRes); + {error, Error} -> + exmpp_iq:error(Packet, Error) + end, + ejabberd_router:route(To, From, Res); + #iq{type = get, ns = ?NS_VCARD = XMLNS, + lang = Lang} -> + VCard = #xmlel{ns = XMLNS, name = 'vCard', + children = iq_get_vcard(Lang)}, + Res = exmpp_iq:result(Packet, VCard), + ejabberd_router:route(To, From, Res); + #iq{type = set, ns = ?NS_ADHOC} = IQ -> + Res = case iq_command(Host, ServerHost, From, IQ, Access, Plugins) of + {error, Error} -> + exmpp_iq:error(Packet, Error); + {result, IQRes} -> + exmpp_iq:result(Packet, IQRes) + end, + ejabberd_router:route(To, From, Res); + + #iq{} -> + Err = exmpp_iq:error(Packet, + 'feature-not-implemented'), + ejabberd_router:route(To, From, Err); + _ -> + ok + end; + 'message' -> + case exmpp_stanza:is_stanza_error(Packet) of + true -> + ok; + false -> + case find_authorization_response(Packet) of + none -> + ok; + invalid -> + ejabberd_router:route(To, From, + exmpp_message:error(Packet, 'bad-request')); + XFields -> + handle_authorization_response(Host, From, To, Packet, XFields) + end + end; + _ -> + ok + end; + _ -> + case exmpp_stanza:get_type(Packet) of + <<"error">> -> + ok; + <<"result">> -> + ok; + _ -> + Err = exmpp_stanza:reply_with_error(Packet, + 'item-not-found'), + ejabberd_router:route(To, From, Err) + end + end. + +node_disco_info(Host, Node, From) -> + node_disco_info(Host, Node, From, true, true). +node_disco_identity(Host, Node, From) -> + node_disco_info(Host, Node, From, true, false). +node_disco_features(Host, Node, From) -> + node_disco_info(Host, Node, From, false, true). +node_disco_info(Host, Node, From, Identity, Features) -> + Action = + fun(#pubsub_node{type = Type, id = NodeId}) -> + I = case Identity of + false -> + []; + true -> + Types = + case tree_call(Host, get_subnodes, [Host, Node, From]) of + [] -> + ["leaf"]; %% No sub-nodes: it's a leaf node + _ -> + case node_call(Type, get_items, [NodeId, From, none]) of + {result, []} -> ["collection"]; + {result, _} -> ["leaf", "collection"]; + _ -> [] + end + end, + lists:map(fun(T) -> + #xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [?XMLATTR('category', <<"pubsub">>), + ?XMLATTR('type', T)]} + end, Types) + end, + F = case Features of + false -> + []; + true -> + [#xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]} | + lists:map(fun + ("rsm") -> #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_RSM_s)]}; + (T) -> #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s++"#"++T)]} + end, features(Type))] + end, + %% TODO: add meta-data info (spec section 5.4) + {result, I ++ F} + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Result}} -> {result, Result}; + Other -> Other + end. + +iq_disco_info(Host, SNode, From, Lang) -> + [RealSNode|_] = case SNode of + [] -> [[]]; + _ -> string:tokens(SNode, "!") + end, + Node = string_to_node(RealSNode), + case Node of + [] -> + {result, + [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = + [?XMLATTR('category', "pubsub"), + ?XMLATTR('type', "service"), + ?XMLATTR('name', translate:translate(Lang, "Publish-Subscribe"))]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_DISCO_INFO_s)]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_DISCO_ITEMS_s)]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_VCARD_s)]}] ++ + lists:map(fun + ("rsm") -> #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_RSM_s)]}; + (Feature) -> #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s++"#"++Feature)]} + end, features(Host, Node))}; + _ -> + node_disco_info(Host, Node, From) + end. + +iq_disco_items(Host, [], From, _RSM) -> + {result, lists:map( + fun(#pubsub_node{nodeid = {_, SubNode}}) -> + SN = node_to_string(SubNode), + RN = lists:last(SubNode), + %% remove name attribute + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), + ?XMLATTR('node', SN), + ?XMLATTR('name', RN)]} + end, tree_action(Host, get_subnodes, [Host, [], From]))}; +iq_disco_items(Host, Item, From, RSM) -> + case string:tokens(Item, "!") of + [_SNode, _ItemID] -> + {result, []}; + [SNode] -> + Node = string_to_node(SNode), + %% Note: Multiple Node Discovery not supported (mask on pubsub#type) + %% TODO this code is also back-compatible with pubsub v1.8 (for client issue) + %% TODO make it pubsub v1.12 compliant (breaks client compatibility ?) + %% TODO That is, remove name attribute (or node?, please check for 2.1) + Action = + fun(#pubsub_node{type = Type, id = NodeId}) -> + {NodeItems, RsmOut} = case node_call(Type, get_items, [NodeId, From, RSM]) of + {result, I} -> I; + _ -> {[], none} + end, + Nodes = lists:map( + fun(#pubsub_node{nodeid = {_, SubNode}}) -> + SN = node_to_string(SubNode), + RN = lists:last(SubNode), + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), + ?XMLATTR('name', RN)]} + end, tree_call(Host, get_subnodes, [Host, Node, From])), + Items = lists:map( + fun(#pubsub_item{itemid = {RN, _}}) -> + SN = node_to_string(Node) ++ "!" ++ RN, + {result, Name} = node_call(Type, get_item_name, [NodeId, RN]), + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), + ?XMLATTR('name', Name)]} + end, NodeItems), + {result, Nodes ++ Items ++ jlib:rsm_encode(RsmOut)} + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Result}} -> {result, Result}; + Other -> Other + end + end. + +iq_local(From, To, #iq{type = Type, payload = SubEl, ns = XMLNS, lang = Lang} = IQ_Rec) -> + ServerHost = exmpp_jid:prep_domain_as_list(To), + FromHost = exmpp_jid:prep_domain_as_list(To), + %% Accept IQs to server only from our own users. + if + FromHost /= ServerHost -> + exmpp_iq:error(IQ_Rec, 'forbidden'); + true -> + LOwner = jlib:short_prepd_bare_jid(From), + Res = case XMLNS of + ?NS_PUBSUB -> iq_pubsub(LOwner, ServerHost, From, Type, SubEl, Lang); + ?NS_PUBSUB_OWNER -> iq_pubsub_owner(LOwner, ServerHost, From, Type, SubEl, Lang) + end, + case Res of + {result, []} -> exmpp_iq:result(IQ_Rec); + {result, [IQRes]} -> exmpp_iq:result(IQ_Rec, IQRes); + {error, Error} -> exmpp_iq:error(IQ_Rec, Error) + end + end. + +iq_sm(From, To, #iq{type = Type, payload = SubEl, ns = XMLNS, lang = Lang} = IQ_Rec) -> + ServerHost = exmpp_jid:prep_domain_as_list(To), + LOwner = jlib:short_prepd_bare_jid(To), + Res = case XMLNS of + ?NS_PUBSUB -> iq_pubsub(LOwner, ServerHost, From, Type, SubEl, Lang); + ?NS_PUBSUB_OWNER -> iq_pubsub_owner(LOwner, ServerHost, From, Type, SubEl, Lang) + end, + case Res of + {result, []} -> exmpp_iq:result(IQ_Rec); + {result, [IQRes]} -> exmpp_iq:result(IQ_Rec, IQRes); + {error, Error} -> exmpp_iq:error(IQ_Rec, Error) + end. + +iq_get_vcard(Lang) -> + [#xmlel{ns = ?NS_VCARD, name = 'FN', children = [#xmlcdata{cdata = <<"ejabberd/mod_pubsub">>}]}, + #xmlel{ns = ?NS_VCARD, name = 'URL', children = [#xmlcdata{cdata = list_to_binary(?EJABBERD_URI)}]}, + #xmlel{ns = ?NS_VCARD, name = 'DESC', children = + [#xmlcdata{cdata = list_to_binary( + translate:translate(Lang, + "ejabberd Publish-Subscribe module") ++ + "\nCopyright (c) 2004-2009 Process-One")}]}]. + +iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang) -> + iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, all, plugins(ServerHost)). + +iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) -> + WithoutCdata = exmpp_xml:remove_cdata_from_list(SubEl#xmlel.children), + Configuration = lists:filter(fun(#xmlel{name = 'configure'}) -> true; + (_) -> false + end, WithoutCdata), + Action = WithoutCdata -- Configuration, + case Action of + [#xmlel{name = Name, attrs = Attrs, children = Els}] -> + Node = case Host of + {_, _, _} -> exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false); + _ -> string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false)) + end, + case {IQType, Name} of + {set, 'create'} -> + Config = case Configuration of + [#xmlel{name = 'configure', children = C}] -> C; + _ -> [] + end, + %% Get the type of the node + Type = case exmpp_xml:get_attribute_from_list_as_list(Attrs, 'type', "") of + [] -> hd(Plugins); + T -> T + end, + %% we use Plugins list matching because we do not want to allocate + %% atoms for non existing type, this prevent atom allocation overflow + case lists:member(Type, Plugins) of + false -> + {error, extended_error( + 'feature-not-implemented', + unsupported, "create-nodes")}; + true -> + create_node(Host, ServerHost, Node, From, + Type, Access, Config) + end; + {set, 'publish'} -> + case exmpp_xml:remove_cdata_from_list(Els) of + [#xmlel{name = 'item', attrs = ItemAttrs, children = Payload}] -> + ItemId = exmpp_xml:get_attribute_from_list_as_list(ItemAttrs, 'id', ""), + publish_item(Host, ServerHost, Node, From, ItemId, Payload); + [] -> + %% Publisher attempts to publish to persistent node with no item + {error, extended_error('bad-request', + "item-required")}; + _ -> + %% Entity attempts to publish item with multiple payload elements or namespace does not match + {error, extended_error('bad-request', + "invalid-payload")} + end; + {set, 'retract'} -> + ForceNotify = case exmpp_xml:get_attribute_from_list_as_list(Attrs, 'notify', "") of + "1" -> true; + "true" -> true; + _ -> false + end, + case exmpp_xml:remove_cdata_from_list(Els) of + [#xmlel{name = 'item', attrs = ItemAttrs}] -> + ItemId = exmpp_xml:get_attribute_from_list_as_list(ItemAttrs, 'id', ""), + delete_item(Host, Node, From, ItemId, ForceNotify); + _ -> + %% Request does not specify an item + {error, extended_error('bad-request', + "item-required")} + end; + {set, 'subscribe'} -> + Config = case Configuration of + [#xmlel{name = 'configure', children = C}] -> C; + _ -> [] + end, + JID = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'jid', ""), + subscribe_node(Host, Node, From, JID, Config); + {set, 'unsubscribe'} -> + JID = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'jid', ""), + SubId = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'subid', ""), + unsubscribe_node(Host, Node, From, JID, SubId); + {get, 'items'} -> + MaxItems = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'max_items', ""), + SubId = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'subid', ""), + ItemIDs = lists:foldl(fun + (#xmlel{name = 'item', attrs = ItemAttrs}, Acc) -> + case exmpp_xml:get_attribute_from_list_as_list(ItemAttrs, 'id', "") of + "" -> Acc; + ItemID -> [ItemID|Acc] + end; + (_, Acc) -> + Acc + end, [], exmpp_xml:remove_cdata_from_list(Els)), + RSM = jlib:rsm_decode(SubEl), + get_items(Host, Node, From, SubId, MaxItems, ItemIDs, RSM); + {get, 'subscriptions'} -> + get_subscriptions(Host, Node, From, Plugins); + {get, 'affiliations'} -> + get_affiliations(Host, From, Plugins); + {get, "options"} -> + SubID = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'subid', ""), + JID = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'jid', ""), + get_options(Host, Node, JID, SubID, Lang); + {set, "options"} -> + SubID = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'subid', ""), + JID = exmpp_xml:get_attribute_from_list_as_list(Attrs, 'jid', ""), + set_options(Host, Node, JID, SubID, Els); + _ -> + {error, 'feature-not-implemented'} + end; + _ -> + ?INFO_MSG("Too many actions: ~p", [Action]), + {error, 'bad-request'} + end. + +iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> + SubEls = exmpp_xml:get_child_elements(SubEl), + NoRSM = lists:filter(fun(#xmlel{name = Name}) -> + Name == 'set' + end, SubEls), + Action = SubEls -- NoRSM, %%pablo why not doing it once on lists:filter? + case Action of + [#xmlel{name = Name, attrs = Attrs, children = Els}] -> + Node = case Host of + {_, _, _} -> exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', ""); + _ -> string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', "")) + end, + case {IQType, Name} of + {get, 'configure'} -> + get_configure(Host, ServerHost, Node, From, Lang); + {set, 'configure'} -> + set_configure(Host, Node, From, Els, Lang); + {get, 'default'} -> + get_default(Host, Node, From, Lang); + {set, 'delete'} -> + delete_node(Host, Node, From); + {set, 'purge'} -> + purge_node(Host, Node, From); + {get, 'subscriptions'} -> + get_subscriptions(Host, Node, From); + {set, 'subscriptions'} -> + set_subscriptions(Host, Node, From, exmpp_xml:remove_cdata_from_list(Els)); + {get, 'affiliations'} -> + get_affiliations(Host, Node, From); + {set, 'affiliations'} -> + set_affiliations(Host, Node, From, exmpp_xml:remove_cdata_from_list(Els)); + _ -> + {error, 'feature-not-implemented'} + end; + _ -> + ?INFO_MSG("Too many actions: ~p", [Action]), + {error, 'bad-request'} + end. + +iq_command(Host, ServerHost, From, IQ, Access, Plugins) -> + case adhoc:parse_request(IQ) of + Req when is_record(Req, adhoc_request) -> + case adhoc_request(Host, ServerHost, From, Req, Access, Plugins) of + Resp when is_record(Resp, adhoc_response) -> + {result, [adhoc:produce_response(Req, Resp)]}; + Error -> + Error + end; + Err -> + Err + end. + +%% @doc

    Processes an Ad Hoc Command.

    +adhoc_request(Host, _ServerHost, Owner, + #adhoc_request{node = ?NS_PUBSUB_GET_PENDING, + lang = Lang, + action = "execute", + xdata = false}, + _Access, Plugins) -> + send_pending_node_form(Host, Owner, Lang, Plugins); +adhoc_request(Host, _ServerHost, Owner, + #adhoc_request{node = ?NS_PUBSUB_GET_PENDING, + action = "execute", + xdata = XData}, + _Access, _Plugins) -> + ParseOptions = case XData of + #xmlel{name = 'x'} = XEl -> + case jlib:parse_xdata_submit(XEl) of + invalid -> + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'bad-request')}; + XData2 -> + case set_xoption(XData2, []) of + NewOpts when is_list(NewOpts) -> + {result, NewOpts}; + Err -> + Err + end + end; + _ -> + ?INFO_MSG("Bad XForm: ~p", [XData]), + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'bad-request')} + end, + case ParseOptions of + {result, XForm} -> + case lists:keysearch(node, 1, XForm) of + {value, {_, Node}} -> + send_pending_auth_events(Host, Node, Owner); + false -> + {error, extended_error('bad-request', "bad-payload")} + end; + Error -> + Error + end; +adhoc_request(_Host, _ServerHost, _Owner, Other, _Access, _Plugins) -> + ?DEBUG("Couldn't process ad hoc command:~n~p", [Other]), + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'item-not-found')}. + +%% @spec (Host, Owner, Lang, Plugins) -> iqRes() +%% @doc

    Sends the process pending subscriptions XForm for Host to +%% Owner.

    +send_pending_node_form(Host, Owner, _Lang, Plugins) -> + Filter = + fun (Plugin) -> + lists:member("get-pending", features(Plugin)) + end, + case lists:filter(Filter, Plugins) of + [] -> + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'feature-not-implemented')}; + Ps -> + XOpts = lists:map(fun (Node) -> + #xmlel{ns = ?NS_DATA_FORMS, name='option', + children = [ + #xmlel{ns = ?NS_DATA_FORMS, name = 'value', + children = [ + exmpp_xml:cdata(node_to_string(Node))]}]} + end, get_pending_nodes(Host, Owner, Ps)), + XForm = #xmlel{ns = ?NS_DATA_FORMS, name ='x', attrs = [?XMLATTR('type', <<"form">>)], + children = [ + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', + attrs = [?XMLATTR('type', <<"list-single">>), + ?XMLATTR('var', <<"pubsub#node">>)], + children = lists:usort(XOpts)}]}, + #adhoc_response{status = executing, + defaultaction = "execute", + elements = [XForm]} + end. + +get_pending_nodes(Host, Owner, Plugins) -> + Tr = + fun (Type) -> + case node_call(Type, get_pending_nodes, [Host, Owner]) of + {result, Nodes} -> Nodes; + _ -> [] + end + end, + case transaction(Host, + fun () -> {result, lists:flatmap(Tr, Plugins)} end, + sync_dirty) of + {result, Res} -> Res; + Err -> Err + end. + +%% @spec (Host, Node, Owner) -> iqRes() +%% @doc

    Send a subscription approval form to Owner for all pending +%% subscriptions on Host and Node.

    +send_pending_auth_events(Host, Node, Owner) -> + ?DEBUG("Sending pending auth events for ~s on ~s:~s", + [exmpp_jid:jid_to_string(Owner), Host, node_to_string(Node)]), + Action = + fun (#pubsub_node{id = NodeID, type = Type} = N) -> + case lists:member("get-pending", features(Type)) of + true -> + case node_call(Type, get_affiliation, [NodeID, Owner]) of + {result, owner} -> + broadcast_pending_auth_events(N), + {result, ok}; + _ -> + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'forbidden')} + end; + false -> + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'feature-not-implemented')} + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, _} -> + #adhoc_response{}; + Err -> + Err + end. + +broadcast_pending_auth_events(#pubsub_node{type = Type, id = NodeID} = Node) -> + {result, Subscriptions} = node_call(Type, get_node_subscriptions, [NodeID]), + lists:foreach(fun ({J, pending, _SubID}) -> + {U, S, R} = J, + send_authorization_request(Node, exmpp_jid:make(U,S,R)); + ({J, pending}) -> + {U, S, R} = J, + send_authorization_request(Node, exmpp_jid:make(U,S,R)) + end, Subscriptions). + +%%% authorization handling + +send_authorization_request(#pubsub_node{nodeid = {Host, Node}, type = Type, id = NodeId}, Subscriber) -> + Lang = "en", %% TODO fix + {U, S, R} = Subscriber, + Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children = + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "PubSub subscriber request"))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'instructions', children = + [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Choose whether to approve this entity's subscription."))}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [?XMLATTR('var', <<"FORM_TYPE">>), ?XMLATTR('type', <<"hidden">>)], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(?NS_PUBSUB_SUBSCRIBE_AUTH_s)}]}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [?XMLATTR('var', <<"pubsub#node">>), ?XMLATTR('type', <<"text-single">>), + ?XMLATTR('label', translate:translate(Lang, "Node ID"))], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = + [#xmlcdata{cdata = node_to_string(Node)}]}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('var', <<"pubsub#subscriber_jid">>), + ?XMLATTR('type', <<"jid-single">>), + ?XMLATTR('label', translate:translate(Lang, "Subscriber Address"))], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = + [#xmlcdata{cdata = exmpp_jid:to_binary(U, S, R)}]}]}, + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = + [?XMLATTR('var', <<"pubsub#allow">>), + ?XMLATTR('type', <<"boolean">>), + ?XMLATTR('label', translate:translate(Lang, "Allow this Jabber ID to subscribe to this pubsub node?"))], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"false">>}]}]}]}]}, + lists:foreach(fun(Owner) -> + {U, S, R} = Owner, + ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza} + end, node_owners(Host, Type, NodeId)). + +find_authorization_response(Packet) -> + Els = Packet#xmlel.children, + XData1 = lists:map(fun(#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = XAttrs} = XEl) -> + case exmpp_xml:get_attribute_from_list_as_list(XAttrs, 'type', "") of + "cancel" -> + none; + _ -> + jlib:parse_xdata_submit(XEl) + end; + (_) -> + none + end, exmpp_xml:remove_cdata(Els)), + XData = lists:filter(fun(E) -> E /= none end, XData1), + case XData of + [invalid] -> invalid; + [] -> none; + [XFields] when is_list(XFields) -> + case lists:keysearch("FORM_TYPE", 1, XFields) of + {value, {_, [?NS_PUBSUB_SUBSCRIBE_AUTH_s]}} -> + XFields; + _ -> + invalid + end + end. + +%% @spec (Host, JID, Node, Subscription) -> void +%% Host = mod_pubsub:host() +%% JID = jlib:jid() +%% SNode = string() +%% Subscription = atom() | {atom(), mod_pubsub:subid)} +%% Plugins = [Plugin::string()] +%% @doc Send a message to JID with the supplied Subscription +send_authorization_approval(Host, JID, SNode, Subscription) -> + SubAttrs = case Subscription of + {S, SID} -> [?XMLATTR('subscription', subscription_to_string(S)), + ?XMLATTR('subid', SID)]; + S -> [?XMLATTR('subscription', subscription_to_string(S))] + end, + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'subscription', attrs = + [?XMLATTR('node', SNode), + ?XMLATTR('jid', exmpp_jid:to_binary(JID))] ++ SubAttrs + }]), + ejabberd_router ! {route, service_jid(Host), JID, Stanza}. + +handle_authorization_response(Host, From, To, Packet, XFields) -> + case {lists:keysearch("pubsub#node", 1, XFields), + lists:keysearch("pubsub#subscriber_jid", 1, XFields), + lists:keysearch("pubsub#allow", 1, XFields)} of + {{value, {_, [SNode]}}, {value, {_, [SSubscriber]}}, + {value, {_, [SAllow]}}} -> + Node = case Host of + {_, _, _} -> [SNode]; + _ -> string:tokens(SNode, "/") + end, + Subscriber = exmpp_jid:parse(SSubscriber), + Allow = case SAllow of + "1" -> true; + "true" -> true; + _ -> false + end, + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + IsApprover = lists:member(jlib:short_prepd_bare_jid(From), node_owners_call(Type, NodeId)), + {result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]), + if + not IsApprover -> + {error, 'forbidden'}; + true -> + update_auth(Host, SNode, Type, NodeId, + Subscriber, Allow, + Subscriptions) + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {error, Error} -> + ejabberd_router:route( + To, From, + exmpp_stanza:reply_with_error(Packet, Error)); + {result, _} -> + %% XXX: notify about subscription state change, section 12.11 + ok; + _ -> + ejabberd_router:route( + To, From, + exmpp_stanza:reply_with_error(Packet, 'internal-server-error')) + end; + _ -> + ejabberd_router:route( + To, From, + exmpp_stanza:reply_with_error(Packet, 'not-acceptable')) + end. + +update_auth(Host, Node, Type, NodeId, Subscriber, + Allow, Subscriptions) -> + Subscription = lists:filter(fun({pending, _}) -> true; + (_) -> false + end, Subscriptions), + case Subscription of + [{pending, SubID}] -> %% TODO does not work if several pending + NewSubscription = case Allow of + true -> subscribed; + false -> none + end, + node_call(Type, set_subscriptions, + [NodeId, Subscriber, NewSubscription, SubID]), + send_authorization_approval(Host, Subscriber, Node, + NewSubscription), + {result, ok}; + _ -> + {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'unexpected-request')} + end. + +-define(XFIELD(Type, Label, Var, Val), + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', Type), + ?XMLATTR('label', translate:translate(Lang, Label)), + ?XMLATTR('var', Var)], children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Val)}]}]}). + +-define(BOOLXFIELD(Label, Var, Val), + ?XFIELD("boolean", Label, Var, + case Val of + true -> "1"; + _ -> "0" + end)). + +-define(STRINGXFIELD(Label, Var, Val), + ?XFIELD("text-single", Label, Var, Val)). + +-define(STRINGMXFIELD(Label, Var, Vals), + #xmlel{ns = ?NS_DATA_FORMS, + name = 'field', + attrs = [?XMLATTR('type', <<"text-multi">>), + ?XMLATTR('label', translate:translate(Lang, Label)), + ?XMLATTR('var', Var) + ], + children = [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', + children = [?XMLCDATA(V)]} || V <- Vals]}). + +-define(XFIELDOPT(Type, Label, Var, Val, Opts), + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', Type), + ?XMLATTR('label', translate:translate(Lang, Label)), + ?XMLATTR('var', Var)], children = + lists:map(fun(Opt) -> + #xmlel{ns = ?NS_DATA_FORMS, name = 'option', children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = + [#xmlcdata{cdata = list_to_binary(Opt)}]}]} + end, Opts) ++ + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Val)}]}]}). + +-define(LISTXFIELD(Label, Var, Val, Opts), + ?XFIELDOPT("list-single", Label, Var, Val, Opts)). + +-define(LISTMXFIELD(Label, Var, Vals, Opts), + #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs = [?XMLATTR('type', <<"list-multi">>), + ?XMLATTR('label', translate:translate(Lang, Label)), + ?XMLATTR('var', Var)], children = + lists:map(fun(Opt) -> + #xmlel{ns = ?NS_DATA_FORMS, name = 'option', children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = + [#xmlcdata{cdata = list_to_binary(Opt)}]}]} + end, Opts) ++ + lists:map(fun(Val) -> + #xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = + [#xmlcdata{cdata = list_to_binary(Val)}]} + end, Vals) + }). + +%% @spec (Host::host(), ServerHost::host(), Node::pubsubNode(), Owner::jid(), NodeType::nodeType()) -> +%% {error, Reason::stanzaError()} | +%% {result, []} +%% @doc

    Create new pubsub nodes

    +%%

    In addition to method-specific error conditions, there are several general reasons why the node creation request might fail:

    +%%
      +%%
    • The service does not support node creation.
    • +%%
    • Only entities that are registered with the service are allowed to create nodes but the requesting entity is not registered.
    • +%%
    • The requesting entity does not have sufficient privileges to create nodes.
    • +%%
    • The requested NodeID already exists.
    • +%%
    • The request did not include a NodeID and "instant nodes" are not supported.
    • +%%
    +%%

    ote: node creation is a particular case, error return code is evaluated at many places:

    +%%
      +%%
    • iq_pubsub checks if service supports node creation (type exists)
    • +%%
    • create_node checks if instant nodes are supported
    • +%%
    • create_node asks node plugin if entity have sufficient privilege
    • +%%
    • nodetree create_node checks if nodeid already exists
    • +%%
    • node plugin create_node just sets default affiliation/subscription
    • +%%
    +create_node(Host, ServerHost, Node, Owner, Type) -> + create_node(Host, ServerHost, Node, Owner, Type, all, []). +create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) -> + case lists:member("instant-nodes", features(Type)) of + true -> + {LOU, LOS, _} = jlib:short_prepd_jid(Owner), + HomeNode = ["home", LOS, LOU], + create_node(Host, ServerHost, + HomeNode, Owner, Type, Access, Configuration), + NewNode = HomeNode ++ [randoms:get_string()], + case create_node(Host, ServerHost, + NewNode, Owner, Type, Access, Configuration) of + {result, []} -> + {result, + [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(NewNode)}]}]}; + Error -> Error + end; + false -> + %% Service does not support instant nodes + {error, extended_error('not-acceptable', "nodeid-required")} + end; +create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> + Type = select_type(ServerHost, Host, Node, GivenType), + Parent = lists:sublist(Node, length(Node) - 1), + %% TODO, check/set node_type = Type + ParseOptions = case exmpp_xml:remove_cdata_from_list(Configuration) of + [] -> + {result, node_options(Type)}; + [#xmlel{name = 'x'} = XEl] -> + case jlib:parse_xdata_submit(XEl) of + invalid -> + {error, 'bad-request'}; + XData -> + case set_xoption(XData, node_options(Type)) of + NewOpts when is_list(NewOpts) -> + {result, NewOpts}; + Err -> + Err + end + end; + _ -> + ?INFO_MSG("Node ~p; bad configuration: ~p", [Node, Configuration]), + {error, 'bad-request'} + end, + case ParseOptions of + {result, NodeOptions} -> + CreateNode = + fun() -> + case node_call(Type, create_node_permission, [Host, ServerHost, Node, Parent, Owner, Access]) of + {result, true} -> + case tree_call(Host, create_node, [Host, Node, Type, Owner, NodeOptions]) of + {ok, NodeId} -> + node_call(Type, create_node, [NodeId, Owner]); + {error, {virtual, NodeId}} -> + node_call(Type, create_node, [NodeId, Owner]); + Error -> + Error + end; + _ -> + {error, 'forbidden'} + end + end, + Reply = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(Node)}]}, + case transaction(Host, CreateNode, transaction) of + {result, {Result, broadcast}} -> + %%Lang = "en", %% TODO: fix + %%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), + %%broadcast_publish_item(Host, Node, uniqid(), Owner, + %% [{xmlelement, "x", [{"xmlns", ?NS_DATA_FORMS}, {"type", "result"}], + %% [?XFIELD("hidden", "", "FORM_TYPE", ?NS_PUBSUB_NMI), + %% ?XFIELD("jid-single", "Node Creator", "creator", jlib:jid_to_string(OwnerKey))]}]), + case Result of + default -> {result, Reply}; + _ -> {result, Result} + end; + {result, default} -> + {result, Reply}; + {result, Result} -> + {result, Result}; + Error -> + %% in case we change transaction to sync_dirty... + %% node_call(Type, delete_node, [Host, Node]), + %% tree_call(Host, delete_node, [Host, Node]), + Error + end; + Error -> + Error + end. + +%% @spec (Host, Node, Owner) -> +%% {error, Reason} | {result, []} +%% Host = host() +%% Node = pubsubNode() +%% Owner = jid() +%% Reason = stanzaError() +%% @doc

    Delete specified node and all childs.

    +%%

    There are several reasons why the node deletion request might fail:

    +%%
      +%%
    • The requesting entity does not have sufficient privileges to delete the node.
    • +%%
    • The node is the root collection node, which cannot be deleted.
    • +%%
    • The specified node does not exist.
    • +%%
    +delete_node(_Host, [], _Owner) -> + %% Node is the root + {error, 'not-allowed'}; +delete_node(Host, Node, Owner) -> + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + SubsByDepth = get_collection_subscriptions(Host, Node), + case node_call(Type, get_affiliation, [NodeId, Owner]) of + {result, owner} -> + Removed = tree_call(Host, delete_node, [Host, Node]), + case node_call(Type, delete_node, [Removed]) of + {result, Res} -> {result, {SubsByDepth, Res}}; + Error -> Error + end; + _ -> + %% Entity is not an owner + {error, 'forbidden'} + end + end, + Reply = [], + case transaction(Host, Node, Action, transaction) of + {result, {_, {SubsByDepth, {Result, broadcast, Removed}}}} -> + lists:foreach(fun({RNode, _RSubscriptions}) -> + {RH, RN} = RNode#pubsub_node.nodeid, + NodeId = RNode#pubsub_node.id, + Type = RNode#pubsub_node.type, + Options = RNode#pubsub_node.options, + broadcast_removed_node(RH, RN, NodeId, Type, Options, SubsByDepth), + unset_cached_item(RH, NodeId) + end, Removed), + case Result of + default -> {result, Reply}; + _ -> {result, Result} + end; + {result, {_, {_, {Result, _Removed}}}} -> + case Result of + default -> {result, Reply}; + _ -> {result, Result} + end; + {result, {_, {_, default}}} -> + {result, Reply}; + {result, {_, {_, Result}}} -> + {result, Result}; + Error -> + Error + end. + +%% @spec (Host, Node, From, JID, Configuration) -> +%% {error, Reason::stanzaError()} | +%% {result, []} +%% Host = host() +%% Node = pubsubNode() +%% From = jid() +%% JID = jid() +%% @see node_hometree:subscribe_node/5 +%% @doc

    Accepts or rejects subcription requests on a PubSub node.

    +%%

    There are several reasons why the subscription request might fail:

    +%%
      +%%
    • The bare JID portions of the JIDs do not match.
    • +%%
    • The node has an access model of "presence" and the requesting entity is not subscribed to the owner's presence.
    • +%%
    • The node has an access model of "roster" and the requesting entity is not in one of the authorized roster groups.
    • +%%
    • The node has an access model of "whitelist" and the requesting entity is not on the whitelist.
    • +%%
    • The service requires payment for subscriptions to the node.
    • +%%
    • The requesting entity is anonymous and the service does not allow anonymous entities to subscribe.
    • +%%
    • The requesting entity has a pending subscription.
    • +%%
    • The requesting entity is blocked from subscribing (e.g., because having an affiliation of outcast).
    • +%%
    • The node does not support subscriptions.
    • +%%
    • The node does not exist.
    • +%%
    +subscribe_node(Host, Node, From, JID, Configuration) -> + {result, SubOpts} = pubsub_subscription:parse_options_xform(Configuration), + Subscriber = try + jlib:short_prepd_jid(exmpp_jid:parse(JID)) + catch + _:_ -> + {undefined, undefined, undefined} + end, + SubId = uniqid(), + Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> + Features = features(Type), + SubscribeFeature = lists:member("subscribe", Features), + OptionsFeature = lists:member("subscription-options", Features), + HasOptions = not (SubOpts == []), + SubscribeConfig = get_option(Options, subscribe), + AccessModel = get_option(Options, access_model), + SendLast = get_option(Options, send_last_published_item), + AllowedGroups = get_option(Options, roster_groups_allowed, []), + {PresenceSubscription, RosterGroup} = + case Host of + {OUser, OServer, _} -> + get_roster_info(OUser, OServer, + Subscriber, AllowedGroups); + _ -> + case Subscriber of + {"", "", ""} -> + {false, false}; + _ -> + case node_owners_call(Type, NodeId) of + [{OU, OS, _} | _] -> + get_roster_info(OU, OS, + Subscriber, AllowedGroups); + _ -> + {false, false} + end + end + end, + if + not SubscribeFeature -> + %% Node does not support subscriptions + {error, extended_error('feature-not-implemented', unsupported, "subscribe")}; + not SubscribeConfig -> + %% Node does not support subscriptions + {error, extended_error('feature-not-implemented', unsupported, "subscribe")}; + HasOptions andalso not OptionsFeature -> + %% Node does not support subscription options + {error, extended_error('feature-not-implemented', unsupported, "subscription-options")}; + true -> + node_call(Type, subscribe_node, + [NodeId, From, Subscriber, + AccessModel, SendLast, + PresenceSubscription, RosterGroup, + SubOpts]) + end + end, + Reply = fun(Subscription) -> + %% TODO, this is subscription-notification, should depends on node features + SubAttrs = case Subscription of + {subscribed, SubId} -> + [{"subscription", subscription_to_string(subscribed)}, + {"subid", SubId}]; + Other -> + [{"subscription", subscription_to_string(Other)}] + end, + Fields = + [ ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)) | SubAttrs], + #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = Fields}]} + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {TNode, {Result, subscribed, SubId, send_last}}} -> + NodeId = TNode#pubsub_node.id, + Type = TNode#pubsub_node.type, + send_items(Host, Node, NodeId, Type, Subscriber, last), + case Result of + default -> {result, Reply({subscribed, SubId})}; + _ -> {result, Result} + end; + {result, {_TNode, {default, subscribed, SubId}}} -> + {result, Reply({subscribed, SubId})}; + {result, {_TNode, {Result, subscribed, _SubId}}} -> + {result, Result}; + {result, {TNode, {default, pending, _SubId}}} -> + send_authorization_request(TNode, Subscriber), + {result, Reply(pending)}; + {result, {TNode, {Result, pending}}} -> + send_authorization_request(TNode, Subscriber), + {result, Result}; + {result, {_, Result}} -> + %% this case should never occure anyway + {result, Result}; + Error -> + Error + end. + +%% @spec (Host, Noce, From, JID, SubId) -> {error, Reason} | {result, []} +%% Host = host() +%% Node = pubsubNode() +%% From = jid() +%% JID = string() +%% SubId = string() +%% Reason = stanzaError() +%% @doc

    Unsubscribe JID from the Node.

    +%%

    There are several reasons why the unsubscribe request might fail:

    +%%
      +%%
    • The requesting entity has multiple subscriptions to the node but does not specify a subscription ID.
    • +%%
    • The request does not specify an existing subscriber.
    • +%%
    • The requesting entity does not have sufficient privileges to unsubscribe the specified JID.
    • +%%
    • The node does not exist.
    • +%%
    • The request specifies a subscription ID that is not valid or current.
    • +%%
    +unsubscribe_node(Host, Node, From, JID, SubId) when is_list(JID) -> + Subscriber = try jlib:short_prepd_jid(exmpp_jid:parse(JID)) + catch + _:_ -> + {undefined, undefined, undefined} + end, + unsubscribe_node(Host, Node, From, Subscriber, SubId); +unsubscribe_node(Host, Node, From, Subscriber, SubId) -> + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + node_call(Type, unsubscribe_node, [NodeId, From, Subscriber, SubId]) + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, default}} -> + {result, []}; + {result, {_, Result}} -> + {result, Result}; + Error -> + Error + end. + +%% @spec (Host::host(), ServerHost::host(), JID::jid(), Node::pubsubNode(), ItemId::string(), Payload::term()) -> +%% {error, Reason::stanzaError()} | +%% {result, []} +%% @doc

    Publish item to a PubSub node.

    +%%

    The permission to publish an item must be verified by the plugin implementation.

    +%%

    There are several reasons why the publish request might fail:

    +%%
      +%%
    • The requesting entity does not have sufficient privileges to publish.
    • +%%
    • The node does not support item publication.
    • +%%
    • The node does not exist.
    • +%%
    • The payload size exceeds a service-defined limit.
    • +%%
    • The item contains more than one payload element or the namespace of the root payload element does not match the configured namespace for the node.
    • +%%
    • The request does not match the node configuration.
    • +%%
    +publish_item(Host, ServerHost, Node, Publisher, "", Payload) -> + %% if publisher does not specify an ItemId, the service MUST generate the ItemId + publish_item(Host, ServerHost, Node, Publisher, uniqid(), Payload); +publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> + Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> + Features = features(Type), + PublishFeature = lists:member("publish", Features), + PublishModel = get_option(Options, publish_model), + MaxItems = max_items(Host, Options), + DeliverPayloads = get_option(Options, deliver_payloads), + PersistItems = get_option(Options, persist_items), + PayloadCount = payload_xmlelements(Payload), + PayloadSize = size(term_to_binary(Payload)), + PayloadMaxSize = get_option(Options, max_payload_size), + % pubsub#deliver_payloads true + % pubsub#persist_items true -> 1 item; false -> 0 item + if + not PublishFeature -> + %% Node does not support item publication + {error, extended_error('feature-not-implemented', unsupported, "publish")}; + PayloadSize > PayloadMaxSize -> + %% Entity attempts to publish very large payload + {error, extended_error('not-acceptable', "payload-too-big")}; + (PayloadCount == 0) and (Payload == []) -> + %% Publisher attempts to publish to payload node with no payload + {error, extended_error('bad-request', "payload-required")}; + (PayloadCount > 1) or (PayloadCount == 0) -> + %% Entity attempts to publish item with multiple payload elements + {error, extended_error('bad-request', "invalid-payload")}; + (DeliverPayloads == 0) and (PersistItems == 0) and (PayloadSize > 0) -> + %% Publisher attempts to publish to transient notification node with item + {error, extended_error('bad-request', "item-forbidden")}; + ((DeliverPayloads == 1) or (PersistItems == 1)) and (PayloadSize == 0) -> + %% Publisher attempts to publish to persistent node with no item + {error, extended_error('bad-request', "item-required")}; + true -> + node_call(Type, publish_item, [NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload]) + end + end, + ServerHostB = list_to_binary(ServerHost), + ejabberd_hooks:run(pubsub_publish_item, ServerHostB, [ServerHost, Node, Publisher, service_jid(Host), ItemId, Payload]), + Reply = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB, name = 'publish', attrs = nodeAttr(Node), children = + [#xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = itemAttr(ItemId)}]}]}, + case transaction(Host, Node, Action, sync_dirty) of + {result, {TNode, {Result, broadcast, Removed}}} -> + NodeId = TNode#pubsub_node.id, + Type = TNode#pubsub_node.type, + Options = TNode#pubsub_node.options, + broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, jlib:short_prepd_jid(Publisher), Payload), + set_cached_item(Host, NodeId, ItemId, Payload), + case Result of + default -> {result, Reply}; + _ -> {result, Result} + end; + {result, {TNode, {default, Removed}}} -> + NodeId = TNode#pubsub_node.id, + Type = TNode#pubsub_node.type, + Options = TNode#pubsub_node.options, + broadcast_retract_items(Host, Node, NodeId, Type, Options, Removed), + set_cached_item(Host, NodeId, ItemId, Payload), + {result, Reply}; + {result, {TNode, {Result, Removed}}} -> + NodeId = TNode#pubsub_node.id, + Type = TNode#pubsub_node.type, + Options = TNode#pubsub_node.options, + broadcast_retract_items(Host, Node, NodeId, Type, Options, Removed), + set_cached_item(Host, NodeId, ItemId, Payload), + {result, Result}; + {result, {_, default}} -> + {result, Reply}; + {result, {_, Result}} -> + {result, Result}; + {error, 'item-not-found'} -> + %% handles auto-create feature + %% for automatic node creation. we'll take the default node type: + %% first listed into the plugins configuration option, or pep + Type = select_type(ServerHost, Host, Node), + case lists:member("auto-create", features(Type)) of + true -> + case create_node(Host, ServerHost, Node, Publisher, Type) of + {result, _} -> + publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload); + _ -> + {error, 'item-not-found'} + end; + false -> + {error, 'item-not-found'} + end; + Error -> + Error + end. + +%% @spec (Host::host(), JID::jid(), Node::pubsubNode(), ItemId::string()) -> +%% {error, Reason::stanzaError()} | +%% {result, []} +%% @doc

    Delete item from a PubSub node.

    +%%

    The permission to delete an item must be verified by the plugin implementation.

    +%%

    There are several reasons why the item retraction request might fail:

    +%%
      +%%
    • The publisher does not have sufficient privileges to delete the requested item.
    • +%%
    • The node or item does not exist.
    • +%%
    • The request does not specify a node.
    • +%%
    • The request does not include an element or the element does not specify an ItemId.
    • +%%
    • The node does not support persistent items.
    • +%%
    • The service does not support the deletion of items.
    • +%%
    +delete_item(Host, Node, Publisher, ItemId) -> + delete_item(Host, Node, Publisher, ItemId, false). +delete_item(_, "", _, _, _) -> + %% Request does not specify a node + {error, extended_error('bad-request', "node-required")}; +delete_item(Host, Node, Publisher, ItemId, ForceNotify) -> + Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> + Features = features(Type), + PersistentFeature = lists:member("persistent-items", Features), + DeleteFeature = lists:member("delete-items", Features), + PublishModel = get_option(Options, publish_model), + if + %%-> iq_pubsub just does that matchs + %% %% Request does not specify an item + %% {error, extended_error('bad-request', "item-required")}; + not PersistentFeature -> + %% Node does not support persistent items + {error, extended_error('feature-not-implemented', unsupported, "persistent-items")}; + not DeleteFeature -> + %% Service does not support item deletion + {error, extended_error('feature-not-implemented', unsupported, "delete-items")}; + true -> + node_call(Type, delete_item, [NodeId, Publisher, PublishModel, ItemId]) + end + end, + Reply = [], + case transaction(Host, Node, Action, sync_dirty) of + {result, {TNode, {Result, broadcast}}} -> + NodeId = TNode#pubsub_node.id, + Type = TNode#pubsub_node.type, + Options = TNode#pubsub_node.options, + broadcast_retract_items(Host, Node, NodeId, Type, Options, [ItemId], ForceNotify), + case get_cached_item(Host, NodeId) of + #pubsub_item{itemid = {ItemId, NodeId}, _ = '_'} -> unset_cached_item(Host, NodeId); + _ -> ok + end, + case Result of + default -> {result, Reply}; + _ -> {result, Result} + end; + {result, {_, default}} -> + {result, Reply}; + {result, {_, Result}} -> + {result, Result}; + Error -> + Error + end. + +%% @spec (Host, JID, Node) -> +%% {error, Reason} | {result, []} +%% Host = host() +%% Node = pubsubNode() +%% JID = jid() +%% Reason = stanzaError() +%% @doc

    Delete all items of specified node owned by JID.

    +%%

    There are several reasons why the node purge request might fail:

    +%%
      +%%
    • The node or service does not support node purging.
    • +%%
    • The requesting entity does not have sufficient privileges to purge the node.
    • +%%
    • The node is not configured to persist items.
    • +%%
    • The specified node does not exist.
    • +%%
    +purge_node(Host, Node, Owner) -> + Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> + Features = features(Type), + PurgeFeature = lists:member("purge-nodes", Features), + PersistentFeature = lists:member("persistent-items", Features), + PersistentConfig = get_option(Options, persist_items), + if + not PurgeFeature -> + %% Service does not support node purging + {error, extended_error('feature-not-implemented', unsupported, "purge-nodes")}; + not PersistentFeature -> + %% Node does not support persistent items + {error, extended_error('feature-not-implemented', unsupported, "persistent-items")}; + not PersistentConfig -> + %% Node is not configured for persistent items + {error, extended_error('feature-not-implemented', unsupported, "persistent-items")}; + true -> + node_call(Type, purge_node, [NodeId, Owner]) + end + end, + Reply = [], + case transaction(Host, Node, Action, sync_dirty) of + {result, {TNode, {Result, broadcast}}} -> + NodeId = TNode#pubsub_node.id, + Type = TNode#pubsub_node.type, + Options = TNode#pubsub_node.options, + broadcast_purge_node(Host, Node, NodeId, Type, Options), + unset_cached_item(Host, NodeId), + case Result of + default -> {result, Reply}; + _ -> {result, Result} + end; + {result, {_, default}} -> + {result, Reply}; + {result, {_, Result}} -> + {result, Result}; + Error -> + Error + end. + +%% @doc

    Return the items of a given node.

    +%%

    The number of items to return is limited by MaxItems.

    +%%

    The permission are not checked in this function.

    +%% @todo We probably need to check that the user doing the query has the right +%% to read the items. +get_items(Host, Node, From, SubId, SMaxItems, ItemIDs, RSM) -> + MaxItems = + if + SMaxItems == "" -> ?MAXITEMS; + true -> + case catch list_to_integer(SMaxItems) of + {'EXIT', _} -> {error, 'bad-request'}; + Val -> Val + end + end, + case MaxItems of + {error, Error} -> + {error, Error}; + _ -> + Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> + Features = features(Type), + RetreiveFeature = lists:member("retrieve-items", Features), + PersistentFeature = lists:member("persistent-items", Features), + AccessModel = get_option(Options, access_model), + AllowedGroups = get_option(Options, roster_groups_allowed, []), + {PresenceSubscription, RosterGroup} = + case Host of + {OUser, OServer, _} -> + get_roster_info(OUser, OServer, + jlib:short_prepd_jid(From), AllowedGroups); + _ -> + {true, true} + end, + if + not RetreiveFeature -> + %% Item Retrieval Not Supported + {error, extended_error('feature-not-implemented', unsupported, "retrieve-items")}; + not PersistentFeature -> + %% Persistent Items Not Supported + {error, extended_error('feature-not-implemented', unsupported, "persistent-items")}; + true -> + node_call(Type, get_items, + [NodeId, From, + AccessModel, PresenceSubscription, RosterGroup, + SubId, RSM]) + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Items, RSMOut}} -> + SendItems = case ItemIDs of + [] -> + Items; + _ -> + lists:filter(fun(#pubsub_item{itemid = {ItemId, _}}) -> + lists:member(ItemId, ItemIDs) + end, Items) + end, + %% Generate the XML response (Item list), limiting the + %% number of items sent to MaxItems: + {result, #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = nodeAttr(Node), children = + itemsEls(lists:sublist(SendItems, MaxItems))} | jlib:rsm_encode(RSMOut)]}}; + Error -> + Error + end + end. +get_items(Host, Node) -> + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + node_call(Type, get_items, [NodeId, service_jid(Host)]) + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Items}} -> Items; + Error -> Error + end. +get_item(Host, Node, ItemId) -> + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + node_call(Type, get_item, [NodeId, ItemId]) + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Items}} -> Items; + Error -> Error + end. + +%% @spec (Host, Node, NodeId, Type, LJID, Number) -> any() +%% Host = pubsubHost() +%% Node = pubsubNode() +%% NodeId = pubsubNodeId() +%% Type = pubsubNodeType() +%% LJID = {U, S, []} +%% Number = last | integer() +%% @doc

    Resend the items of a node to the user.

    +%% @todo use cache-last-item feature +send_items(Host, Node, NodeId, Type, LJID, last) -> + Stanza = case get_cached_item(Host, NodeId) of + undefined -> + % special ODBC optimization, works only with node_hometree_odbc, node_flat_odbc and node_pep_odbc + ToSend = case node_action(Host, Type, get_last_items, [NodeId, LJID, 1]) of + {result, []} -> []; + {result, Items} -> Items + end, + event_stanza([#xmlel{ns = ?NS_PUBSUB_EVENT, + name = 'items', + attrs = nodeAttr(Node), + children = itemsEls(ToSend)}]); + LastItem -> + event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), + children = itemsEls(LastItem)}]) + end, + {U, S, R} = LJID, + ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza}; + +send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> + ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of + {result, []} -> + []; + {result, Items} -> + case Number of + N when N > 0 -> lists:sublist(Items, N); + _ -> Items + end; + _ -> + [] + end, + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = + itemsEls(ToSend)}]), + ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(LU, LS, LR), Stanza}. + +%% @spec (Host, JID, Plugins) -> {error, Reason} | {result, Response} +%% Host = host() +%% JID = jid() +%% Plugins = [Plugin::string()] +%% Reason = stanzaError() +%% Response = [pubsubIQResponse()] +%% @doc

    Return the list of affiliations as an XMPP response.

    +get_affiliations(Host, JID, Plugins) when is_list(Plugins) -> + Result = lists:foldl( + fun(Type, {Status, Acc}) -> + Features = features(Type), + RetrieveFeature = lists:member("retrieve-affiliations", Features), + if + not RetrieveFeature -> + %% Service does not support retreive affiliatons + {{error, extended_error('feature-not-implemented', unsupported, "retrieve-affiliations")}, Acc}; + true -> + {result, Affiliations} = node_action(Host, Type, get_entity_affiliations, [Host, JID]), + {Status, [Affiliations|Acc]} + end + end, {ok, []}, Plugins), + case Result of + {ok, Affiliations} -> + Entities = lists:flatmap( + fun({_, none}) -> []; + ({#pubsub_node{nodeid = {_, Node}}, Affiliation}) -> + [#xmlel{ns = ?NS_PUBSUB, name = 'affiliation', attrs = + [?XMLATTR('node', node_to_string(Node)), + ?XMLATTR('affiliation', affiliation_to_string(Affiliation))]}] + end, lists:usort(lists:flatten(Affiliations))), + {result, #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB, name = 'affiliations', children = + Entities}]}}; + {Error, _} -> + Error + end; +get_affiliations(Host, Node, JID) -> + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + Features = features(Type), + RetrieveFeature = lists:member("modify-affiliations", Features), + {result, Affiliation} = node_call(Type, get_affiliation, [NodeId, JID]), + if + not RetrieveFeature -> + %% Service does not support modify affiliations + {error, extended_error('feature-not-implemented', unsupported, "modify-affiliations")}; + Affiliation /= owner -> + %% Entity is not an owner + {error, 'forbidden'}; + true -> + node_call(Type, get_node_affiliations, [NodeId]) + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, []}} -> + {error, 'item-not-found'}; + {result, {_, Affiliations}} -> + Entities = lists:flatmap( + fun({_, none}) -> []; + ({{AU, AS, AR}, Affiliation}) -> + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'affiliation', attrs = + [?XMLATTR('jid', exmpp_jid:to_binary(AU, AS, AR)), + ?XMLATTR('affiliation', affiliation_to_string(Affiliation))]}] + end, Affiliations), + {result, #xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'affiliations', attrs = nodeAttr(Node), children = + Entities}]}}; + Error -> + Error + end. + +set_affiliations(Host, Node, From, EntitiesEls) -> + Owner = jlib:short_prepd_bare_jid(From), + Entities = + lists:foldl( + fun(El, Acc) -> + case Acc of + error -> + error; + _ -> + case El of + #xmlel{name = 'affiliation', attrs = Attrs} -> + JID = try + exmpp_jid:parse( + exmpp_xml:get_attribute_from_list(Attrs, 'jid', "")) + catch + _:_ -> error + end, + Affiliation = string_to_affiliation( + exmpp_xml:get_attribute_from_list_as_list(Attrs, 'affiliation', false)), + if + (JID == error) or + (Affiliation == false) -> + error; + true -> + [{JID, Affiliation} | Acc] + end + end + end + end, [], EntitiesEls), + case Entities of + error -> + {error, 'bad-request'}; + _ -> + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + case lists:member(Owner, node_owners_call(Type, NodeId)) of + true -> + lists:foreach( + fun({JID, Affiliation}) -> + node_call(Type, set_affiliation, [NodeId, JID, Affiliation]) + end, Entities), + {result, []}; + _ -> + {error, 'forbidden'} + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Result}} -> {result, Result}; + Other -> Other + end + end. + +get_options(Host, Node, JID, SubID, Lang) -> + Action = fun(#pubsub_node{type = Type, id = NodeID}) -> + case lists:member("subscription-options", features(Type)) of + true -> + get_options_helper(JID, Lang, NodeID, SubID, Type); + false -> + {error, extended_error( + 'feature-not-implemented', + unsupported, "subscription-options")} + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_Node, XForm}} -> {result, [XForm]}; + Error -> Error + end. + +get_options_helper(JID, Lang, NodeID, SubID, Type) -> + Subscriber = try exmpp_jid:parse(JID) of + J -> jlib:short_jid(J) + catch + _ -> + {"", "", ""} %%pablo TODO: "" or <<>> ?. short_jid uses exmpp_jid:node/1, etc. that returns binaries + end, + {result, Subs} = node_call(Type, get_subscriptions, + [NodeID, Subscriber]), + SubIDs = lists:foldl(fun({subscribed, SID}, Acc) -> + [SID | Acc]; + (_, Acc) -> + Acc + end, [], Subs), + case {SubID, SubIDs} of + {_, []} -> + {error, extended_error('not-acceptable', "not-subscribed")}; + {[], [SID]} -> + read_sub(Subscriber, NodeID, SID, Lang); + {[], _} -> + {error, extended_error('not-acceptable', "subid-required")}; + {_, _} -> + read_sub(Subscriber, NodeID, SubID, Lang) + end. + +read_sub(Subscriber, NodeID, SubID, Lang) -> + case pubsub_subscription:get_subscription(Subscriber, NodeID, SubID) of + {error, notfound} -> + {error, extended_error('not-acceptable', "invalid-subid")}; + {result, #pubsub_subscription{options = Options}} -> + pubsub_subscription:get_options_xform(Lang, Options) + end. + +set_options(Host, Node, JID, SubID, Configuration) -> + Action = fun(#pubsub_node{type = Type, id = NodeID}) -> + case lists:member("subscription-options", features(Type)) of + true -> + set_options_helper(Configuration, JID, NodeID, + SubID, Type); + false -> + {error, extended_error( + 'feature-not-implemented', + unsupported, "subscription-options")} + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_Node, Result}} -> {result, Result}; + Error -> Error + end. + +set_options_helper(Configuration, JID, NodeID, SubID, Type) -> + Subscriber = try exmpp_jid:parse(JID) of + J -> jlib:short_jid(J) + catch + _ -> + {"", "", ""} %%pablo TODO: "" or <<>> ?. short_jid uses exmpp_jid:node/1, etc. that returns binaries + end, + {result, SubOpts} = pubsub_subscription:parse_options_xform(Configuration), + {result, Subs} = node_call(Type, get_subscriptions, + [NodeID, Subscriber]), + SubIDs = lists:foldl(fun({subscribed, SID}, Acc) -> + [SID | Acc]; + (_, Acc) -> + Acc + end, [], Subs), + case {SubID, SubIDs} of + {_, []} -> + {error, extended_error('not-acceptable', "not-subscribed")}; + {[], [SID]} -> + write_sub(Subscriber, NodeID, SID, SubOpts); + {[], _} -> + {error, extended_error('not-acceptable', "subid-required")}; + {_, _} -> + write_sub(Subscriber, NodeID, SubID, SubOpts) + end. + +write_sub(Subscriber, NodeID, SubID, Options) -> + case pubsub_subscription:set_subscription(Subscriber, NodeID, SubID, + Options) of + {error, notfound} -> + {error, extended_error('not-acceptable', "invalid-subid")}; + {result, _} -> + {result, []} + end. + +%% @spec (Host, Node, JID, Plugins) -> {error, Reason} | {result, Response} +%% Host = host() +%% Node = pubsubNode() +%% JID = jid() +%% Plugins = [Plugin::string()] +%% Reason = stanzaError() +%% Response = [pubsubIQResponse()] +%% @doc

    Return the list of subscriptions as an XMPP response.

    +get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> + Result = lists:foldl( + fun(Type, {Status, Acc}) -> + Features = features(Type), + RetrieveFeature = lists:member("retrieve-subscriptions", Features), + if + not RetrieveFeature -> + %% Service does not support retreive subscriptions + {{error, extended_error('feature-not-implemented', unsupported, "retrieve-subscriptions")}, Acc}; + true -> + Subscriber = exmpp_jid:bare(JID), + {result, Subscriptions} = node_action(Host, Type, get_entity_subscriptions, [Host, Subscriber]), + {Status, [Subscriptions|Acc]} + end + end, {ok, []}, Plugins), + case Result of + {ok, Subscriptions} -> + Entities = lists:flatmap( + fun({_, none}) -> + []; + ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription}) -> + case Node of + [] -> + [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = + [?XMLATTR('node', node_to_string(SubsNode)), + ?XMLATTR('subscription', subscription_to_string(Subscription))]}]; + SubsNode -> + [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = + [?XMLATTR('subscription', subscription_to_string(Subscription))]}]; + _ -> + [] + end; + ({_, none, _}) -> + []; + ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubID, SubJID}) -> + case Node of + [] -> + [#xmlel{ns = ?NS_PUBSUB, name='subscription', + attrs = [?XMLATTR('jid', exmpp_jid:jid_to_binary(SubJID)), + ?XMLATTR('subid', SubID), + ?XMLATTR('subscription', subscription_to_string(Subscription)) | nodeAttr(SubsNode)]}]; + SubsNode -> + [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', + attrs = [?XMLATTR('jid', exmpp_jid:jid_to_binary(SubJID)), + ?XMLATTR('subid', SubID), + ?XMLATTR('subscription', subscription_to_string(Subscription))]}]; + _ -> + [] + end; + ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubJID}) -> + case Node of + [] -> + [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = + [?XMLATTR('node', node_to_string(SubsNode)), + ?XMLATTR('jid', exmpp_jid:to_binary(SubJID)), + ?XMLATTR('subscription', subscription_to_string(Subscription))]}]; + SubsNode -> + [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = + [?XMLATTR('jid', exmpp_jid:to_binary(SubJID)), + ?XMLATTR('subscription', subscription_to_string(Subscription))]}]; + _ -> + [] + end + end, lists:usort(lists:flatten(Subscriptions))), + {result, #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB, name = 'subscriptions', children = + Entities}]}}; + {Error, _} -> + Error + end. +get_subscriptions(Host, Node, JID) -> + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + Features = features(Type), + RetrieveFeature = lists:member("manage-subscriptions", Features), + {result, Affiliation} = node_call(Type, get_affiliation, [NodeId, JID]), + if + not RetrieveFeature -> + %% Service does not support manage subscriptions + {error, extended_error('feature-not-implemented', unsupported, "manage-subscriptions")}; + Affiliation /= owner -> + %% Entity is not an owner + {error, 'forbidden'}; + true -> + node_call(Type, get_node_subscriptions, [NodeId]) + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, []}} -> + {error, 'item-not-found'}; + {result, {_, Subscriptions}} -> + Entities = lists:flatmap( + fun({_, none}) -> []; + ({_, pending, _}) -> []; + ({{AU, AS, AR}, Subscription}) -> + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscription', attrs = + [?XMLATTR('jid', exmpp_jid:to_binary(AU, AS, AR)), + ?XMLATTR('subscription', subscription_to_string(Subscription))]}]; + ({{AU, AS, AR}, Subscription, SubId}) -> + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscription', attrs = + [?XMLATTR('jid', exmpp_jid:to_binary(AU, AS, AR)), + ?XMLATTR('subscription', subscription_to_string(Subscription)), + ?XMLATTR('subid', SubId)]}] + end, Subscriptions), + {result, #xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscriptions', attrs = nodeAttr(Node), children = + Entities}]}}; + Error -> + Error + end. + +set_subscriptions(Host, Node, From, EntitiesEls) -> + Owner = jlib:short_prepd_bare_jid(From), + Entities = + lists:foldl( + fun(El, Acc) -> + case Acc of + error -> + error; + _ -> + case El of + #xmlel{name = 'subscription', attrs = Attrs} -> + JID = try + exmpp_jid:parse( + exmpp_xml:get_attribute_from_list(Attrs, 'jid', "")) + catch + _:_ -> + error + end, + Subscription = string_to_subscription( + exmpp_xml:get_attribute_from_list_as_list(Attrs, 'subscription', false)), + SubId = exmpp_xml:get_attribute_from_list_as_list(Attrs, "subid", false), + if + (JID == error) or + (Subscription == false) -> + error; + true -> + [{JID, Subscription, SubId} | Acc] + end + end + end + end, [], EntitiesEls), + case Entities of + error -> + {error, 'bad-request'}; + _ -> + Notify = fun(JID, Sub, _SubId) -> + Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, + name = 'message', + children = + [#xmlel{ns = ?NS_PUBSUB, + name = 'pubsub', + children = + [#xmlel{ns = ?NS_PUBSUB, + name = 'subscription', + attrs = [?XMLATTR('jid', exmpp_jid:to_binary(JID)), + ?XMLATTR('subsription', subscription_to_string(Sub)) | nodeAttr(Node)]}]}]}, + + ejabberd_router ! {route, service_jid(Host), JID, Stanza} + end, + Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + case lists:member(Owner, node_owners_call(Type, NodeId)) of + true -> + Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> + + case node_call(Type, set_subscriptions, [NodeId, JID, Subscription, SubId]) of + {error, Err} -> [{error, Err} | Acc]; + _ -> Notify(JID, Subscription, SubId), Acc + end + end, [], Entities), + case Result of + [] -> {result, []}; + _ -> {error, 'not-acceptable'} + end; + _ -> + {error, 'forbidden'} + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Result}} -> {result, Result}; + Other -> Other + end + end. + + +%% @spec (OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, SubscriberResource}, AllowedGroups) +%% -> {PresenceSubscription, RosterGroup} +get_roster_info(OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, _}, AllowedGroups) -> + OwnerServerB = list_to_binary(OwnerServer), + {Subscription, Groups} = + ejabberd_hooks:run_fold( + roster_get_jid_info, OwnerServerB, + {none, []}, + [OwnerUser, OwnerServer, {SubscriberUser, SubscriberServer, undefined}]), + PresenceSubscription = (Subscription == both) orelse (Subscription == from) + orelse ({OwnerUser, OwnerServer} == {SubscriberUser, SubscriberServer}), + RosterGroup = lists:any(fun(Group) -> + lists:member(Group, AllowedGroups) + end, Groups), + {PresenceSubscription, RosterGroup}. + +%% @spec (AffiliationStr) -> Affiliation +%% AffiliationStr = string() +%% Affiliation = atom() +%% @doc

    Convert an affiliation type from string to atom.

    +string_to_affiliation("owner") -> owner; +string_to_affiliation("publisher") -> publisher; +string_to_affiliation("member") -> member; +string_to_affiliation("outcast") -> outcast; +string_to_affiliation("none") -> none; +string_to_affiliation(_) -> false. + +%% @spec (SubscriptionStr) -> Subscription +%% SubscriptionStr = string() +%% Subscription = atom() +%% @doc

    Convert a subscription type from string to atom.

    +string_to_subscription("subscribed") -> subscribed; +string_to_subscription("pending") -> pending; +string_to_subscription("unconfigured") -> unconfigured; +string_to_subscription("none") -> none; +string_to_subscription(_) -> false. + +%% @spec (Affiliation) -> AffiliationStr +%% Affiliation = atom() +%% AffiliationStr = string() +%% @doc

    Convert an affiliation type from atom to string.

    +affiliation_to_string(owner) -> "owner"; +affiliation_to_string(publisher) -> "publisher"; +affiliation_to_string(member) -> "member"; +affiliation_to_string(outcast) -> "outcast"; +affiliation_to_string(_) -> "none". + +%% @spec (Subscription) -> SubscriptionStr +%% Subscription = atom() +%% SubscriptionStr = string() +%% @doc

    Convert a subscription type from atom to string.

    +subscription_to_string(subscribed) -> "subscribed"; +subscription_to_string(pending) -> "pending"; +subscription_to_string(unconfigured) -> "unconfigured"; +subscription_to_string(_) -> "none". + +%% @spec (Node) -> NodeStr +%% Node = pubsubNode() +%% NodeStr = string() +%% @doc

    Convert a node type from pubsubNode to string.

    +node_to_string([]) -> "/"; +node_to_string(Node) -> + case Node of + [[_ | _] | _] -> string:strip(lists:flatten(["/", lists:map(fun(S) -> [S, "/"] end, Node)]), right, $/); + [Head | _] when is_integer(Head) -> Node + end. +string_to_node(SNode) -> + string:tokens(SNode, "/"). + +%% @spec (Host) -> jid() +%% Host = host() +%% @doc

    Generate pubsub service JID.

    +service_jid(Host) -> + case Host of + {U,S,_} -> exmpp_jid:make(U, S); + _ -> exmpp_jid:make(Host) + end. + +%% @spec (LJID, NotifyType, Depth, NodeOptions, SubOptions) -> boolean() +%% LJID = jid() +%% NotifyType = items | nodes +%% Depth = integer() +%% NodeOptions = [{atom(), term()}] +%% SubOptions = [{atom(), term()}] +%% @doc

    Check if a notification must be delivered or not based on +%% node and subscription options.

    +is_to_deliver(LJID, NotifyType, Depth, NodeOptions, SubOptions) -> + sub_to_deliver(LJID, NotifyType, Depth, SubOptions) + andalso node_to_deliver(LJID, NodeOptions). + +sub_to_deliver(_LJID, NotifyType, Depth, SubOptions) -> + lists:all(fun (Option) -> + sub_option_can_deliver(NotifyType, Depth, Option) + end, SubOptions). + +sub_option_can_deliver(items, _, {subscription_type, nodes}) -> false; +sub_option_can_deliver(nodes, _, {subscription_type, items}) -> false; +sub_option_can_deliver(_, _, {subscription_depth, all}) -> true; +sub_option_can_deliver(_, Depth, {subscription_depth, D}) -> Depth =< D; +sub_option_can_deliver(_, _, {deliver, false}) -> false; +sub_option_can_deliver(_, _, {expire, When}) -> now() < When; +sub_option_can_deliver(_, _, _) -> true. + +node_to_deliver(LJID, NodeOptions) -> + PresenceDelivery = get_option(NodeOptions, presence_based_delivery), + presence_can_deliver(LJID, PresenceDelivery). + +presence_can_deliver(_, false) -> true; +presence_can_deliver({User, Server, _}, true) -> + case mnesia:dirty_match_object({session, '_', '_', {User, Server}, '_', '_'}) of + [] -> false; + Ss -> + lists:foldl(fun({session, _, _, _, undefined, _}, Acc) -> Acc; + ({session, _, _, _, _Priority, _}, _Acc) -> true + end, false, Ss) + end. + +%% @spec (Payload) -> int() +%% Payload = term() +%% @doc

    Count occurence of XML elements in payload.

    +payload_xmlelements(Payload) -> payload_xmlelements(Payload, 0). +payload_xmlelements([], Count) -> Count; +payload_xmlelements([#xmlel{}|Tail], Count) -> payload_xmlelements(Tail, Count+1); +payload_xmlelements([_|Tail], Count) -> payload_xmlelements(Tail, Count). + +%% @spec (Els) -> stanza() +%% Els = [xmlelement()] +%% @doc

    Build pubsub event stanza

    +event_stanza(Els) -> + #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = Els}]}. + +%%%%%% broadcast functions + +broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, _From, Payload) -> + %broadcast(Host, Node, NodeId, Options, none, true, 'items', ItemEls) + case get_collection_subscriptions(Host, Node) of + [] -> + {result, false}; + + SubsByDepth when is_list(SubsByDepth) -> + Content = case get_option(Options, deliver_payloads) of + true -> Payload; + false -> [] + end, + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = itemAttr(ItemId), children = Content}]}]), + broadcast_stanza(Host, Node, NodeId, Type, Options, SubsByDepth, items, Stanza), + case Removed of + [] -> + ok; + _ -> + case get_option(Options, notify_retract) of + true -> + RetractStanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = itemAttr(RId)} || RId <- Removed]}]), + broadcast_stanza(Host, Node, NodeId, Type, Options, SubsByDepth, items, RetractStanza); + _ -> + ok + end + end, + {result, true}; + _ -> + {result, false} + end. + +broadcast_retract_items(Host, Node, NodeId, Type, NodeOptions, ItemIds) -> + broadcast_retract_items(Host, Node, NodeId, Type, NodeOptions, ItemIds, false). +broadcast_retract_items(_Host, _Node, _NodeId, _Type, _NodeOptions, [], _ForceNotify) -> + {result, false}; +broadcast_retract_items(Host, Node, NodeId, Type, NodeOptions, ItemIds, ForceNotify) -> + %broadcast(Host, Node, NodeId, NodeOptions, notify_retract, ForceNotify, 'retract', RetractEls) + case (get_option(NodeOptions, notify_retract) or ForceNotify) of + true -> + case get_collection_subscriptions(Host, Node) of + [] -> + {result, false}; + + SubsByDepth when is_list(SubsByDepth)-> + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = itemAttr(ItemId)} || ItemId <- ItemIds]}]), + broadcast_stanza(Host, Node, NodeId, Type, NodeOptions, SubsByDepth, items, Stanza), + {result, true}; + _ -> + {result, false} + end; + _ -> + {result, false} + end. + +broadcast_purge_node(Host, Node, NodeId, Type, NodeOptions) -> + %broadcast(Host, Node, NodeId, NodeOptions, notify_retract, false, 'purge', []) + case get_option(NodeOptions, notify_retract) of + true -> + case get_collection_subscriptions(Host, Node) of + [] -> + {result, false}; + SubsByDepth when is_list(SubsByDepth) -> + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'purge', attrs = nodeAttr(Node)}]), + broadcast_stanza(Host, Node, NodeId, Type, NodeOptions, SubsByDepth, nodes, Stanza), + {result, true}; + _ -> + {result, false} + end; + _ -> + {result, false} + end. + +broadcast_removed_node(Host, Node, NodeId, Type, NodeOptions, SubsByDepth) -> + %broadcast(Host, Node, NodeId, NodeOptions, notify_delete, false, 'delete', []) + case get_option(NodeOptions, notify_delete) of + true -> + case SubsByDepth of + [] -> + {result, false}; + _ -> + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'delete', attrs = nodeAttr(Node)}]), + broadcast_stanza(Host, Node, NodeId, Type, NodeOptions, SubsByDepth, nodes, Stanza), + {result, true} + end; + _ -> + {result, false} + end. + +broadcast_config_notification(Host, Node, NodeId, Type, NodeOptions, Lang) -> + %broadcast(Host, Node, NodeId, NodeOptions, notify_config, false, 'items', ConfigEls) + case get_option(NodeOptions, notify_config) of + true -> + case get_collection_subscriptions(Host, Node) of + [] -> + {result, false}; + SubsByDepth when is_list(SubsByDepth) -> + Content = case get_option(NodeOptions, deliver_payloads) of + true -> + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = + get_configure_xfields(Type, NodeOptions, Lang, [])}]; + false -> + [] + end, + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = [?XMLATTR('id', <<"configuration">>)], children = + Content}]}]), + broadcast_stanza(Host, Node, NodeId, Type, NodeOptions, SubsByDepth, nodes, Stanza), + {result, true}; + _ -> + {result, false} + end; + _ -> + {result, false} + end. + +get_collection_subscriptions(Host, Node) -> + lists:map(fun ({Depth, Nodes}) -> + {Depth, [{N, get_node_subs(N)} || N <- Nodes]} + end, tree_action(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)])). + +get_node_subs(#pubsub_node{type = Type, + nodeid = {Host, Node}, + id = NodeID}) -> + case node_action(Host, Type, get_node_subscriptions, [NodeID]) of + {result, Subs} -> + get_options_for_subs(Host, Node, NodeID, Subs); + Other -> + Other + end. + +get_options_for_subs(_Host, Node, NodeID, Subs) -> + lists:foldl(fun({JID, subscribed, SubID}, Acc) -> + case pubsub_subscription:get_subscription(JID, NodeID, SubID) of + {result, #pubsub_subscription{options = Options}} -> [{JID, Node, Options} | Acc]; + _ -> Acc + end; + (_, Acc) -> + Acc + end, [], Subs). + +% TODO: merge broadcast code that way +%broadcast(Host, Node, NodeId, Type, NodeOptions, Feature, Force, ElName, SubEls) -> +% case (get_option(NodeOptions, Feature) or Force) of +% true -> +% case node_action(Host, Type, get_node_subscriptions, [NodeId]) of +% {result, []} -> +% {result, false}; +% {result, Subs} -> +% Stanza = event_stanza([{xmlelement, ElName, [{"node", node_to_string(Node)}], SubEls}]), +% broadcast_stanza(Host, Node, Type, NodeOptions, SubOpts, Stanza), +% {result, true}; +% _ -> +% {result, false} +% end; +% _ -> +% {result, false} +% end + +broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyType, Stanza) -> + %AccessModel = get_option(NodeOptions, access_model), + BroadcastAll = get_option(NodeOptions, broadcast_all_resources), %% XXX this is not standard, but usefull + From = service_jid(Host), + %% Handles explicit subscriptions + FilteredSubsByDepth = depths_to_deliver(NotifyType, SubsByDepth), + NodesByJID = collate_subs_by_jid(FilteredSubsByDepth), + lists:foreach(fun ({LJID, Nodes}) -> + LJIDs = case BroadcastAll of + true -> + {U, S, _} = LJID, + [{U, S, R} || R <- user_resources(U, S)]; + false -> + [LJID] + end, + SHIMStanza = add_headers(Stanza, collection_shim(Node, Nodes)), + lists:foreach(fun(To) -> + {TU, TS, TR} = To, + ejabberd_router ! {route, From, exmpp_jid:make(TU, TS, TR), SHIMStanza} + end, LJIDs) + end, NodesByJID), + %% Handles implicit presence subscriptions + case Host of + {LUser, LServer, LResource} -> + SenderResource = case LResource of + [] -> + case user_resources(LUser, LServer) of + [Resource|_] -> Resource; + _ -> "" + end; + _ -> + LResource + end, + case ejabberd_sm:get_session_pid(LUser, LServer, SenderResource) of + C2SPid when is_pid(C2SPid) -> + %% set the from address on the notification to the bare JID of the account owner + %% Also, add "replyto" if entity has presence subscription to the account owner + %% See XEP-0163 1.1 section 4.3.1 + Sender = exmpp_jid:make(LUser, LServer), + %%ReplyTo = jlib:make_jid(LUser, LServer, SenderResource), % This has to be used + case catch ejabberd_c2s:get_subscribed(C2SPid) of + Contacts when is_list(Contacts) -> + lists:foreach(fun({U, S, _}) -> + spawn(fun() -> + Rs = lists:foldl(fun(R, Acc) -> + case is_caps_notify(LServer, Node, {U, S, R}) of + true -> [R | Acc]; + false -> Acc + end + end, [], user_resources(U, S)), + lists:foreach(fun(R) -> + ejabberd_router ! {route, Sender, exmpp_jid:make(U, S, R), Stanza} + end, Rs) + end) + end, Contacts); + _ -> + ok + end, + ok; + _ -> + ?DEBUG("~p@~p has no session; can't deliver ~p to contacts", [LUser, LServer, Stanza]), + ok + end; + _ -> + ok + end. + +depths_to_deliver(NotifyType, SubsByDepth) -> + NodesToDeliver = + fun (Depth, Node, Subs, Acc) -> + lists:foldl(fun ({LJID, _Node, SubOptions} = S, Acc2) -> + case is_to_deliver(LJID, NotifyType, Depth, + Node#pubsub_node.options, + SubOptions) of + true -> [S | Acc2]; + false -> Acc2 + end + end, Acc, Subs) + end, + + DepthsToDeliver = + fun ({Depth, SubsByNode}, Acc) -> + lists:foldl(fun ({Node, Subs}, Acc2) -> + NodesToDeliver(Depth, Node, Subs, Acc2) + end, Acc, SubsByNode) + end, + + lists:foldl(DepthsToDeliver, [], SubsByDepth). + +collate_subs_by_jid(SubsByDepth) -> + lists:foldl(fun ({JID, Node, _Options}, Acc) -> + OldNodes = case lists:keysearch(JID, 1, Acc) of + {value, {JID, Nodes}} -> Nodes; + false -> [] + end, + lists:keystore(JID, 1, Acc, {JID, [Node | OldNodes]}) + end, [], SubsByDepth). + +%% If we don't know the resource, just pick first if any +%% If no resource available, check if caps anyway (remote online) +user_resources(User, Server) -> + case ejabberd_sm:get_user_resources(User, Server) of + [] -> mod_caps:get_user_resources(User, Server); + Rs -> Rs + end. + +is_caps_notify(Host, Node, LJID) -> + case mod_caps:get_caps(LJID) of + nothing -> + false; + Caps -> + case catch mod_caps:get_features(Host, Caps) of + Features when is_list(Features) -> lists:member(Node ++ "+notify", Features); + _ -> false + end + end. + +%%%%%%% Configuration handling + +%%

    There are several reasons why the default node configuration options request might fail:

    +%%
      +%%
    • The service does not support node configuration.
    • +%%
    • The service does not support retrieval of default node configuration.
    • +%%
    +get_configure(Host, ServerHost, Node, From, Lang) -> + ServerHostB = list_to_binary(ServerHost), + Action = + fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> + case node_call(Type, get_affiliation, [NodeId, From]) of + {result, owner} -> + Groups = ejabberd_hooks:run_fold(roster_groups, ServerHostB, [], [ServerHostB]), + {result, + #xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'configure', attrs = + nodeAttr(Node), children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = + [?XMLATTR('type', <<"form">>)], children = + get_configure_xfields(Type, Options, Lang, Groups) + }]}]}}; + _ -> + {error, 'forbidden'} + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Result}} -> {result, Result}; + Other -> Other + end. + +get_default(Host, Node, _From, Lang) -> + Type = select_type(Host, Host, Node), + Options = node_options(Type), + {result, #xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'default', children = + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children = + get_configure_xfields(Type, Options, Lang, []) + }]}]}}. + +%% Get node option +%% The result depend of the node type plugin system. +get_option([], _) -> false; +get_option(Options, Var) -> + get_option(Options, Var, false). +get_option(Options, Var, Def) -> + case lists:keysearch(Var, 1, Options) of + {value, {_Val, Ret}} -> Ret; + _ -> Def + end. + +%% Get default options from the module plugin. +node_options(Type) -> + Module = list_to_atom(?PLUGIN_PREFIX ++ Type), + case catch Module:options() of + {'EXIT',{undef,_}} -> + DefaultModule = list_to_atom(?PLUGIN_PREFIX++?STDNODE), + DefaultModule:options(); + Result -> + Result + end. + +%% @spec (NodeId) -> [ljid()] +%% NodeId = pubsubNodeId() +%% @doc

    Return list of node owners.

    +node_owners(Host, Type, NodeId) -> + case node_action(Host, Type, get_node_affiliations, [NodeId]) of + {result, Affiliations} -> + lists:foldl( + fun({LJID, owner}, Acc) -> [LJID|Acc]; + (_, Acc) -> Acc + end, [], Affiliations); + _ -> + [] + end. +node_owners_call(Type, NodeId) -> + case node_call(Type, get_node_affiliations, [NodeId]) of + {result, Affiliations} -> + lists:foldl( + fun({LJID, owner}, Acc) -> [LJID|Acc]; + (_, Acc) -> Acc + end, [], Affiliations); + _ -> + [] + end. + +%% @spec (Host, Options) -> MaxItems +%% Host = host() +%% Options = [Option] +%% Option = {Key::atom(), Value::term()} +%% MaxItems = integer() | unlimited +%% @doc

    Return the maximum number of items for a given node.

    +%%

    Unlimited means that there is no limit in the number of items that can +%% be stored.

    +%% @todo In practice, the current data structure means that we cannot manage +%% millions of items on a given node. This should be addressed in a new +%% version. +max_items(Host, Options) -> + case get_option(Options, persist_items) of + true -> + case get_option(Options, max_items) of + false -> unlimited; + Result when (Result < 0) -> 0; + Result -> Result + end; + false -> + case get_option(Options, send_last_published_item) of + never -> + 0; + _ -> + case is_last_item_cache_enabled(Host) of + true -> 0; + false -> 1 + end + end + end. + +-define(BOOL_CONFIG_FIELD(Label, Var), + ?BOOLXFIELD(Label, "pubsub#" ++ atom_to_list(Var), + get_option(Options, Var))). + +-define(STRING_CONFIG_FIELD(Label, Var), + ?STRINGXFIELD(Label, "pubsub#" ++ atom_to_list(Var), + get_option(Options, Var, ""))). + +-define(INTEGER_CONFIG_FIELD(Label, Var), + ?STRINGXFIELD(Label, "pubsub#" ++ atom_to_list(Var), + integer_to_list(get_option(Options, Var)))). + +-define(JLIST_CONFIG_FIELD(Label, Var, Opts), + ?LISTXFIELD(Label, "pubsub#" ++ atom_to_list(Var), + exmpp_jid:to_list(get_option(Options, Var)), + [exmpp_jid:to_list(O) || O <- Opts])). + +-define(ALIST_CONFIG_FIELD(Label, Var, Opts), + ?LISTXFIELD(Label, "pubsub#" ++ atom_to_list(Var), + atom_to_list(get_option(Options, Var)), + [atom_to_list(O) || O <- Opts])). + +-define(LISTM_CONFIG_FIELD(Label, Var, Opts), + ?LISTMXFIELD(Label, "pubsub#" ++ atom_to_list(Var), + get_option(Options, Var), Opts)). + +-define(NLIST_CONFIG_FIELD(Label, Var), + ?STRINGMXFIELD(Label, "pubsub#" ++ atom_to_list(Var), + [node_to_string(N) || N <- get_option(Options, Var, [])])). + +get_configure_xfields(_Type, Options, Lang, Groups) -> + [?XFIELD("hidden", "", "FORM_TYPE", ?NS_PUBSUB_NODE_CONFIG_s), + ?BOOL_CONFIG_FIELD("Deliver payloads with event notifications", deliver_payloads), + ?BOOL_CONFIG_FIELD("Deliver event notifications", deliver_notifications), + ?BOOL_CONFIG_FIELD("Notify subscribers when the node configuration changes", notify_config), + ?BOOL_CONFIG_FIELD("Notify subscribers when the node is deleted", notify_delete), + ?BOOL_CONFIG_FIELD("Notify subscribers when items are removed from the node", notify_retract), + ?BOOL_CONFIG_FIELD("Persist items to storage", persist_items), + ?STRING_CONFIG_FIELD("A friendly name for the node", title), + ?INTEGER_CONFIG_FIELD("Max # of items to persist", max_items), + ?BOOL_CONFIG_FIELD("Whether to allow subscriptions", subscribe), + ?ALIST_CONFIG_FIELD("Specify the access model", access_model, + [open, authorize, presence, roster, whitelist]), + %% XXX: change to list-multi, include current roster groups as options + ?LISTM_CONFIG_FIELD("Roster groups allowed to subscribe", roster_groups_allowed, Groups), + ?ALIST_CONFIG_FIELD("Specify the publisher model", publish_model, + [publishers, subscribers, open]), + ?INTEGER_CONFIG_FIELD("Max payload size in bytes", max_payload_size), + ?ALIST_CONFIG_FIELD("When to send the last published item", send_last_published_item, + [never, on_sub, on_sub_and_presence]), + ?BOOL_CONFIG_FIELD("Only deliver notifications to available users", presence_based_delivery), + ?NLIST_CONFIG_FIELD("The collections with which a node is affiliated", collection) + ]. + +%%

    There are several reasons why the node configuration request might fail:

    +%%
      +%%
    • The service does not support node configuration.
    • +%%
    • The requesting entity does not have sufficient privileges to configure the node.
    • +%%
    • The request did not specify a node.
    • +%%
    • The node has no configuration options.
    • +%%
    • The specified node does not exist.
    • +%%
    +set_configure(Host, Node, From, Els, Lang) -> + case exmpp_xml:remove_cdata_from_list(Els) of + [#xmlel{ns = ?NS_DATA_FORMS, name = 'x'} = XEl] -> + case exmpp_xml:get_attribute_as_list(XEl, 'type', undefined) of + "cancel" -> + {result, []}; + "submit" -> + Action = + fun(#pubsub_node{options = Options, type = Type, id = NodeId} = N) -> + case node_call(Type, get_affiliation, [NodeId, From]) of + {result, owner} -> + case jlib:parse_xdata_submit(XEl) of + invalid -> + {error, 'bad-request'}; + XData -> + OldOpts = case Options of + [] -> node_options(Type); + _ -> Options + end, + case set_xoption(XData, OldOpts) of + NewOpts when is_list(NewOpts) -> + case tree_call(Host, set_node, [N#pubsub_node{options = NewOpts}]) of + ok -> {result, ok}; + Err -> Err + end; + Err -> + Err + end + end; + _ -> + {error, 'forbidden'} + end + end, + case transaction(Host, Node, Action, transaction) of + {result, {TNode, ok}} -> + NodeId = TNode#pubsub_node.id, + Type = TNode#pubsub_node.type, + Options = TNode#pubsub_node.options, + broadcast_config_notification(Host, Node, NodeId, Type, Options, Lang), + {result, []}; + Other -> + Other + end; + _ -> + {error, 'bad-request'} + end; + _ -> + {error, 'bad-request'} + end. + +add_opt(Key, Value, Opts) -> + Opts1 = lists:keydelete(Key, 1, Opts), + [{Key, Value} | Opts1]. + +-define(SET_BOOL_XOPT(Opt, Val), + BoolVal = case Val of + "0" -> false; + "1" -> true; + "false" -> false; + "true" -> true; + _ -> error + end, + case BoolVal of + error -> {error, 'not-acceptable'}; + _ -> set_xoption(Opts, add_opt(Opt, BoolVal, NewOpts)) + end). + +-define(SET_STRING_XOPT(Opt, Val), + set_xoption(Opts, add_opt(Opt, Val, NewOpts))). + +-define(SET_INTEGER_XOPT(Opt, Val, Min, Max), + case catch list_to_integer(Val) of + IVal when is_integer(IVal), + IVal >= Min, + IVal =< Max -> + set_xoption(Opts, add_opt(Opt, IVal, NewOpts)); + _ -> + {error, 'not-acceptable'} + end). + +-define(SET_ALIST_XOPT(Opt, Val, Vals), + case lists:member(Val, [atom_to_list(V) || V <- Vals]) of + true -> set_xoption(Opts, add_opt(Opt, list_to_atom(Val), NewOpts)); + false -> {error, 'not-acceptable'} + end). + +-define(SET_LIST_XOPT(Opt, Val), + set_xoption(Opts, add_opt(Opt, Val, NewOpts))). + +set_xoption([], NewOpts) -> + NewOpts; +set_xoption([{"FORM_TYPE", _} | Opts], NewOpts) -> + set_xoption(Opts, NewOpts); +set_xoption([{"pubsub#roster_groups_allowed", Value} | Opts], NewOpts) -> + ?SET_LIST_XOPT(roster_groups_allowed, Value); +set_xoption([{"pubsub#deliver_payloads", [Val]} | Opts], NewOpts) -> + ?SET_BOOL_XOPT(deliver_payloads, Val); +set_xoption([{"pubsub#deliver_notifications", [Val]} | Opts], NewOpts) -> + ?SET_BOOL_XOPT(deliver_notifications, Val); +set_xoption([{"pubsub#notify_config", [Val]} | Opts], NewOpts) -> + ?SET_BOOL_XOPT(notify_config, Val); +set_xoption([{"pubsub#notify_delete", [Val]} | Opts], NewOpts) -> + ?SET_BOOL_XOPT(notify_delete, Val); +set_xoption([{"pubsub#notify_retract", [Val]} | Opts], NewOpts) -> + ?SET_BOOL_XOPT(notify_retract, Val); +set_xoption([{"pubsub#persist_items", [Val]} | Opts], NewOpts) -> + ?SET_BOOL_XOPT(persist_items, Val); +set_xoption([{"pubsub#max_items", [Val]} | Opts], NewOpts) -> + ?SET_INTEGER_XOPT(max_items, Val, 0, ?MAXITEMS); +set_xoption([{"pubsub#subscribe", [Val]} | Opts], NewOpts) -> + ?SET_BOOL_XOPT(subscribe, Val); +set_xoption([{"pubsub#access_model", [Val]} | Opts], NewOpts) -> + ?SET_ALIST_XOPT(access_model, Val, [open, authorize, presence, roster, whitelist]); +set_xoption([{"pubsub#publish_model", [Val]} | Opts], NewOpts) -> + ?SET_ALIST_XOPT(publish_model, Val, [publishers, subscribers, open]); +set_xoption([{"pubsub#node_type", [Val]} | Opts], NewOpts) -> + ?SET_ALIST_XOPT(node_type, Val, [leaf, collection]); +set_xoption([{"pubsub#max_payload_size", [Val]} | Opts], NewOpts) -> + ?SET_INTEGER_XOPT(max_payload_size, Val, 0, ?MAX_PAYLOAD_SIZE); +set_xoption([{"pubsub#send_last_published_item", [Val]} | Opts], NewOpts) -> + ?SET_ALIST_XOPT(send_last_published_item, Val, [never, on_sub, on_sub_and_presence]); +set_xoption([{"pubsub#presence_based_delivery", [Val]} | Opts], NewOpts) -> + ?SET_BOOL_XOPT(presence_based_delivery, Val); +set_xoption([{"pubsub#title", Value} | Opts], NewOpts) -> + ?SET_STRING_XOPT(title, Value); +set_xoption([{"pubsub#type", Value} | Opts], NewOpts) -> + ?SET_STRING_XOPT(type, Value); +set_xoption([{"pubsub#body_xslt", Value} | Opts], NewOpts) -> + ?SET_STRING_XOPT(body_xslt, Value); +set_xoption([{"pubsub#collection", Value} | Opts], NewOpts) -> + NewValue = [string_to_node(V) || V <- Value], + ?SET_LIST_XOPT(collection, NewValue); +set_xoption([{"pubsub#node", [Value]} | Opts], NewOpts) -> + NewValue = string_to_node(Value), + ?SET_LIST_XOPT(node, NewValue); +set_xoption([_ | Opts], NewOpts) -> + % skip unknown field + set_xoption(Opts, NewOpts). + +%%%% last item cache handling + +is_last_item_cache_enabled({_, ServerHost, _}) -> + is_last_item_cache_enabled(ServerHost); +is_last_item_cache_enabled(Host) -> + case ets:lookup(gen_mod:get_module_proc(Host, config), last_item_cache) of + [{last_item_cache, true}] -> true; + _ -> false + end. + +set_cached_item({_, ServerHost, _}, NodeId, ItemId, Payload) -> + set_cached_item(ServerHost, NodeId, ItemId, Payload); +set_cached_item(Host, NodeId, ItemId, Payload) -> + case is_last_item_cache_enabled(Host) of + true -> ets:insert(gen_mod:get_module_proc(Host, last_items), {NodeId, {ItemId, Payload}}); + _ -> ok + end. +unset_cached_item({_, ServerHost, _}, NodeId) -> + unset_cached_item(ServerHost, NodeId); +unset_cached_item(Host, NodeId) -> + case is_last_item_cache_enabled(Host) of + true -> ets:delete(gen_mod:get_module_proc(Host, last_items), NodeId); + _ -> ok + end. +get_cached_item({_, ServerHost, _}, NodeId) -> + get_cached_item(ServerHost, NodeId); +get_cached_item(Host, NodeId) -> + case is_last_item_cache_enabled(Host) of + true -> + case ets:lookup(gen_mod:get_module_proc(Host, last_items), NodeId) of + [{NodeId, {ItemId, Payload}}] -> + #pubsub_item{itemid = {ItemId, NodeId}, payload = Payload}; + _ -> + undefined + end; + _ -> + undefined + end. + +%%%% plugin handling +plugins(Host) when is_binary(Host) -> + plugins(binary_to_list(Host)); +plugins(Host) when is_list(Host) -> + case ets:lookup(gen_mod:get_module_proc(Host, config), plugins) of + [{plugins, []}] -> [?STDNODE]; + [{plugins, PL}] -> PL; + _ -> [?STDNODE] + end. +select_type(ServerHost, Host, Node, Type) when is_list(ServerHost) -> + select_type(list_to_binary(ServerHost), Host, Node, Type); +select_type(ServerHost, Host, Node, Type) -> + SelectedType = case Host of + {_User, _Server, _Resource} -> + case ets:lookup(gen_mod:get_module_proc(ServerHost, config), pep_mapping) of + [{pep_mapping, PM}] -> proplists:get_value(Node, PM, ?PEPNODE); + _ -> ?PEPNODE + end; + _ -> + Type + end, + ConfiguredTypes = plugins(ServerHost), + case lists:member(SelectedType, ConfiguredTypes) of + true -> SelectedType; + false -> hd(ConfiguredTypes) + end. +select_type(ServerHost, Host, Node) -> + select_type(ServerHost, Host, Node, hd(plugins(ServerHost))). + +features() -> + [ + % see plugin "access-authorize", % OPTIONAL + "access-open", % OPTIONAL this relates to access_model option in node_hometree + "access-presence", % OPTIONAL this relates to access_model option in node_pep + %TODO "access-roster", % OPTIONAL + "access-whitelist", % OPTIONAL + % see plugin "auto-create", % OPTIONAL + % see plugin "auto-subscribe", % RECOMMENDED + "collections", % RECOMMENDED + "config-node", % RECOMMENDED + "create-and-configure", % RECOMMENDED + % see plugin "create-nodes", % RECOMMENDED + % see plugin "delete-items", % RECOMMENDED + % see plugin "delete-nodes", % RECOMMENDED + % see plugin "filtered-notifications", % RECOMMENDED + % see plugin "get-pending", % OPTIONAL + % see plugin "instant-nodes", % RECOMMENDED + "item-ids", % RECOMMENDED + "last-published", % RECOMMENDED + %TODO "cache-last-item", + %TODO "leased-subscription", % OPTIONAL + % see plugin "manage-subscriptions", % OPTIONAL + "member-affiliation", % RECOMMENDED + %TODO "meta-data", % RECOMMENDED + % see plugin "modify-affiliations", % OPTIONAL + % see plugin "multi-collection", % OPTIONAL + % see plugin "multi-subscribe", % OPTIONAL + % see plugin "outcast-affiliation", % RECOMMENDED + % see plugin "persistent-items", % RECOMMENDED + "presence-notifications", % OPTIONAL + "presence-subscribe", % RECOMMENDED + % see plugin "publish", % REQUIRED + %TODO "publish-options", % OPTIONAL + "publisher-affiliation", % RECOMMENDED + % see plugin "purge-nodes", % OPTIONAL + % see plugin "retract-items", % OPTIONAL + % see plugin "retrieve-affiliations", % RECOMMENDED + "retrieve-default" % RECOMMENDED + % see plugin "retrieve-items", % RECOMMENDED + % see plugin "retrieve-subscriptions", % RECOMMENDED + %TODO "shim", % OPTIONAL + % see plugin "subscribe", % REQUIRED + % see plugin "subscription-options", % OPTIONAL + % see plugin "subscription-notifications" % OPTIONAL + ]. +features(Type) -> + Module = list_to_atom(?PLUGIN_PREFIX++Type), + features() ++ case catch Module:features() of + {'EXIT', {undef, _}} -> []; + Result -> Result + end. +features(Host, []) -> + lists:usort(lists:foldl(fun(Plugin, Acc) -> + Acc ++ features(Plugin) + end, [], plugins(Host))); +features(Host, Node) -> + Action = fun(#pubsub_node{type = Type}) -> {result, features(Type)} end, + case transaction(Host, Node, Action, sync_dirty) of + {result, Features} -> lists:usort(features() ++ Features); + _ -> features() + end. + +%% @doc

    node tree plugin call.

    +tree_call({_User, Server, _Resource}, Function, Args) -> + tree_call(Server, Function, Args); +tree_call(Host, Function, Args) -> + ?DEBUG("tree_call ~p ~p ~p",[Host, Function, Args]), + Module = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of + [{nodetree, N}] -> N; + _ -> list_to_atom(?TREE_PREFIX ++ ?STDTREE) + end, + catch apply(Module, Function, Args). +tree_action(Host, Function, Args) -> + ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), + Fun = fun() -> tree_call(Host, Function, Args) end, + case catch ejabberd_odbc:sql_bloc(odbc_conn(Host), Fun) of + {atomic, Result} -> + Result; + {aborted, Reason} -> + ?ERROR_MSG("transaction return internal error: ~p~n",[{aborted, Reason}]), + {error, 'internal-server-error'} + end. + +%% @doc

    node plugin call.

    +node_call(Type, Function, Args) -> + ?DEBUG("node_call ~p ~p ~p",[Type, Function, Args]), + Module = list_to_atom(?PLUGIN_PREFIX++Type), + case catch apply(Module, Function, Args) of + {result, Result} -> {result, Result}; + {error, Error} -> {error, Error}; + {'EXIT', {undef, Undefined}} -> + case Type of + ?STDNODE -> {error, {undef, Undefined}}; + _ -> node_call(?STDNODE, Function, Args) + end; + {'EXIT', Reason} -> {error, Reason}; + Result -> {result, Result} %% any other return value is forced as result + end. + +node_action(Host, Type, Function, Args) -> + ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), + transaction(Host, fun() -> + node_call(Type, Function, Args) + end, sync_dirty). + +%% @doc

    plugin transaction handling.

    +transaction(Host, Node, Action, Trans) -> + transaction(Host, fun() -> + case tree_call(Host, get_node, [Host, Node]) of + N when is_record(N, pubsub_node) -> + case Action(N) of + {result, Result} -> {result, {N, Result}}; + {atomic, {result, Result}} -> {result, {N, Result}}; + Other -> Other + end; + Error -> + Error + end + end, Trans). + +transaction(Host, Fun, Trans) -> + transaction_retry(Host, Fun, Trans, 2). + +transaction_retry(Host, Fun, Trans, Count) -> + SqlFun = case Trans of + transaction -> sql_transaction; + _ -> sql_bloc + end, + case catch ejabberd_odbc:SqlFun(odbc_conn(Host), Fun) of + {result, Result} -> {result, Result}; + {error, Error} -> {error, Error}; + {atomic, {result, Result}} -> {result, Result}; + {atomic, {error, Error}} -> {error, Error}; + {aborted, Reason} -> + ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), + {error, 'internal-server-error'}; + {'EXIT', {timeout, _} = Reason} -> + case Count of + 0 -> + ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), + {error, 'internal-server-error'}; + N -> + erlang:yield(), + transaction_retry(Host, Fun, Trans, N-1) + end; + {'EXIT', Reason} -> + ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), + {error, 'internal-server-error'}; + Other -> + ?ERROR_MSG("transaction return internal error: ~p~n", [Other]), + {error, 'internal-server-error'} + end. + +odbc_conn({_U, Host, _R})-> + Host; +odbc_conn(Host) -> + Host--"pubsub.". %% TODO, improve that for custom host + +%% escape value for database storage +escape({_U, _H, _R}=JID)-> + ejabberd_odbc:escape(exmpp_jid:to_list(JID)); +escape(Value)-> + ejabberd_odbc:escape(Value). +%%%% helpers + +%% Add pubsub-specific error element +extended_error(Error, Ext) -> + extended_error(Error, Ext, []). +extended_error(Error, unsupported, Feature) -> + extended_error(Error, unsupported, + [?XMLATTR('feature', Feature)]); +extended_error(Error, Ext, ExtAttrs) -> + Pubsub_Err = #xmlel{ns = ?NS_PUBSUB_ERRORS, name = Ext, attrs = ExtAttrs}, + exmpp_xml:append_child(exmpp_stanza:error(?NS_JABBER_CLIENT, Error), + Pubsub_Err). + +%% Give a uniq identifier +uniqid() -> + {T1, T2, T3} = now(), + lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])). + +% node attributes +nodeAttr(Node) -> + [?XMLATTR('node', node_to_string(Node))]. + +% item attributes +itemAttr([]) -> []; +itemAttr(ItemId) -> [?XMLATTR('id', ItemId)]. + +% build item elements from item list +itemsEls(Items) -> + lists:map(fun(#pubsub_item{itemid = {ItemId, _}, payload = Payload}) -> + #xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = itemAttr(ItemId), children = Payload} + end, Items). + +add_headers(#xmlel{} = El, HeaderEls) -> + HeaderEl = #xmlel{ns = ?NS_SHIM, name = 'headers', children = HeaderEls}, + exmpp_xml:prepend_child(El, HeaderEl). + +collection_shim(Node, Nodes) -> + [#xmlel{ns = ?NS_PUBSUB, name ='header', + attrs = [?XMLATTR('name', <<"Collection">>)], + children = [ ?XMLCDATA(node_to_string(N))] + } || N <- Nodes -- [Node]]. diff --git a/src/mod_pubsub/node_flat_odbc.erl b/src/mod_pubsub/node_flat_odbc.erl new file mode 100644 index 000000000..a5be7a16d --- /dev/null +++ b/src/mod_pubsub/node_flat_odbc.erl @@ -0,0 +1,183 @@ +%%% ==================================================================== +%%% ``The contents of this file are subject to the Erlang Public License, +%%% Version 1.1, (the "License"); you may not use this file except in +%%% compliance with the License. You should have received a copy of the +%%% Erlang Public License along with this software. If not, it can be +%%% retrieved via the world wide web at http://www.erlang.org/. +%%% +%%% Software distributed under the License is distributed on an "AS IS" +%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%%% the License for the specific language governing rights and limitations +%%% under the License. +%%% +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne +%%% All Rights Reserved.'' +%%% This software is copyright 2006-2009, ProcessOne. +%%% +%%% @copyright 2006-2009 ProcessOne +%%% @author Christophe Romain +%%% [http://www.process-one.net/] +%%% @version {@vsn}, {@date} {@time} +%%% @end +%%% ==================================================================== + +-module(node_flat_odbc). +-author('christophe.romain@process-one.net'). + +-include("pubsub.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). + +-behaviour(gen_pubsub_node). + +%% API definition +-export([init/3, terminate/2, + options/0, features/0, + create_node_permission/6, + create_node/2, + delete_node/1, + purge_node/2, + subscribe_node/8, + unsubscribe_node/4, + publish_item/6, + delete_item/4, + remove_extra_items/3, + get_entity_affiliations/2, + get_node_affiliations/1, + get_affiliation/2, + set_affiliation/3, + get_entity_subscriptions/2, + get_node_subscriptions/1, + get_subscriptions/2, + set_subscriptions/4, + get_pending_nodes/2, + get_states/1, + get_state/2, + set_state/1, + get_items/6, + get_items/2, + get_item/7, + get_item/2, + set_item/1, + get_item_name/3 + ]). + + +init(Host, ServerHost, Opts) -> + node_hometree_odbc:init(Host, ServerHost, Opts). + +terminate(Host, ServerHost) -> + node_hometree_odbc:terminate(Host, ServerHost). + +options() -> + [{deliver_payloads, true}, + {notify_config, false}, + {notify_delete, false}, + {notify_retract, true}, + {persist_items, true}, + {max_items, ?MAXITEMS div 2}, + {subscribe, true}, + {access_model, open}, + {roster_groups_allowed, []}, + {publish_model, publishers}, + {max_payload_size, ?MAX_PAYLOAD_SIZE}, + {send_last_published_item, on_sub_and_presence}, + {deliver_notifications, true}, + {presence_based_delivery, false}, + {odbc, true}, + {rsm, true}]. + +features() -> + node_hometree_odbc:features(). + +%% use same code as node_hometree_odbc, but do not limite node to +%% the home/localhost/user/... hierarchy +%% any node is allowed +create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> + LOwner = jlib:short_prepd_jid(Owner), + Allowed = case LOwner of + {undefined, Host, undefined} -> + true; % pubsub service always allowed + _ -> + {LU, LS, LR} = LOwner, + acl:match_rule(ServerHost, Access, exmpp_jid:make(LU, LS, LR)) =:= allow + end, + {result, Allowed}. + +create_node(NodeId, Owner) -> + node_hometree_odbc:create_node(NodeId, Owner). + +delete_node(Removed) -> + node_hometree_odbc:delete_node(Removed). + +subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options) -> + node_hometree_odbc:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options). + +unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> + node_hometree_odbc:unsubscribe_node(NodeId, Sender, Subscriber, SubID). + +publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> + node_hometree_odbc:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). + +remove_extra_items(NodeId, MaxItems, ItemIds) -> + node_hometree_odbc:remove_extra_items(NodeId, MaxItems, ItemIds). + +delete_item(NodeId, Publisher, PublishModel, ItemId) -> + node_hometree_odbc:delete_item(NodeId, Publisher, PublishModel, ItemId). + +purge_node(NodeId, Owner) -> + node_hometree_odbc:purge_node(NodeId, Owner). + +get_entity_affiliations(Host, Owner) -> + node_hometree_odbc:get_entity_affiliations(Host, Owner). + +get_node_affiliations(NodeId) -> + node_hometree_odbc:get_node_affiliations(NodeId). + +get_affiliation(NodeId, Owner) -> + node_hometree_odbc:get_affiliation(NodeId, Owner). + +set_affiliation(NodeId, Owner, Affiliation) -> + node_hometree_odbc:set_affiliation(NodeId, Owner, Affiliation). + +get_entity_subscriptions(Host, Owner) -> + node_hometree_odbc:get_entity_subscriptions(Host, Owner). + +get_node_subscriptions(NodeId) -> + node_hometree_odbc:get_node_subscriptions(NodeId). + +get_subscriptions(NodeId, Owner) -> + node_hometree_odbc:get_subscriptions(NodeId, Owner). + +set_subscriptions(NodeId, Owner, Subscription, SubId) -> + node_hometree_odbc:set_subscriptions(NodeId, Owner, Subscription, SubId). + +get_pending_nodes(Host, Owner) -> + node_hometree_odbc:get_pending_nodes(Host, Owner). + +get_states(NodeId) -> + node_hometree_odbc:get_states(NodeId). + +get_state(NodeId, JID) -> + node_hometree_odbc:get_state(NodeId, JID). + +set_state(State) -> + node_hometree_odbc:set_state(State). + +get_items(NodeId, From) -> + node_hometree_odbc:get_items(NodeId, From). + +get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_hometree_odbc:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + +get_item(NodeId, ItemId) -> + node_hometree_odbc:get_item(NodeId, ItemId). + +get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_hometree_odbc:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + +set_item(Item) -> + node_hometree_odbc:set_item(Item). + +get_item_name(Host, Node, Id) -> + node_hometree_odbc:get_item_name(Host, Node, Id). diff --git a/src/mod_pubsub/node_hometree_odbc.erl b/src/mod_pubsub/node_hometree_odbc.erl new file mode 100644 index 000000000..ebc5943c0 --- /dev/null +++ b/src/mod_pubsub/node_hometree_odbc.erl @@ -0,0 +1,1324 @@ +%%% ==================================================================== +%%% ``The contents of this file are subject to the Erlang Public License, +%%% Version 1.1, (the "License"); you may not use this file except in +%%% compliance with the License. You should have received a copy of the +%%% Erlang Public License along with this software. If not, it can be +%%% retrieved via the world wide web at http://www.erlang.org/. +%%% +%%% Software distributed under the License is distributed on an "AS IS" +%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%%% the License for the specific language governing rights and limitations +%%% under the License. +%%% +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne +%%% All Rights Reserved.'' +%%% This software is copyright 2006-2009, ProcessOne. +%%% +%%% +%%% @copyright 2006-2009 ProcessOne +%%% @author Christophe Romain +%%% [http://www.process-one.net/] +%%% @version {@vsn}, {@date} {@time} +%%% @end +%%% ==================================================================== + +%%% @todo The item table should be handled by the plugin, but plugin that do +%%% not want to manage it should be able to use the default behaviour. +%%% @todo Plugin modules should be able to register to receive presence update +%%% send to pubsub. + +%%% @doc The module {@module} is the default PubSub plugin. +%%%

    It is used as a default for all unknown PubSub node type. It can serve +%%% as a developer basis and reference to build its own custom pubsub node +%%% types.

    +%%%

    PubSub plugin nodes are using the {@link gen_node} behaviour.

    +%%%

    The API isn't stabilized yet. The pubsub plugin +%%% development is still a work in progress. However, the system is already +%%% useable and useful as is. Please, send us comments, feedback and +%%% improvements.

    + +-module(node_hometree_odbc). +-author('christophe.romain@process-one.net'). + +-include("pubsub.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). +-include("jlib.hrl"). %% for rsm_in and rsm_out records definitions + +-define(PUBSUB, mod_pubsub_odbc). + +-behaviour(gen_pubsub_node). + +%% API definition +-export([init/3, terminate/2, + options/0, features/0, + create_node_permission/6, + create_node/2, + delete_node/1, + purge_node/2, + subscribe_node/8, + unsubscribe_node/4, + publish_item/6, + delete_item/4, + remove_extra_items/3, + get_entity_affiliations/2, + get_node_affiliations/1, + get_affiliation/2, + set_affiliation/3, + get_entity_subscriptions/2, + get_entity_subscriptions_for_send_last/2, + get_node_subscriptions/1, + get_subscriptions/2, + set_subscriptions/4, + get_pending_nodes/2, + get_states/1, + get_state/2, + set_state/1, + get_items/6, + get_items/2, + get_item/7, + get_item/2, + set_item/1, + get_item_name/3, + get_last_items/3 + ]). + +-export([ + decode_jid/1, + decode_node/1, + decode_affiliation/1, + decode_subscriptions/1, + encode_jid/1, + encode_affiliation/1, + encode_subscriptions/1 + ]). +%% ================ +%% API definition +%% ================ + +%% @spec (Host, ServerHost, Opts) -> any() +%% Host = mod_pubsub:host() +%% ServerHost = mod_pubsub:host() +%% Opts = list() +%% @doc

    Called during pubsub modules initialisation. Any pubsub plugin must +%% implement this function. It can return anything.

    +%%

    This function is mainly used to trigger the setup task necessary for the +%% plugin. It can be used for example by the developer to create the specific +%% module database schema if it does not exists yet.

    +init(_Host, _ServerHost, _Opts) -> + pubsub_subscription_odbc:init(), + ok. + +%% @spec (Host, ServerHost) -> any() +%% Host = mod_pubsub:host() +%% ServerHost = host() +%% @doc

    Called during pubsub modules termination. Any pubsub plugin must +%% implement this function. It can return anything.

    +terminate(_Host, _ServerHost) -> + ok. + +%% @spec () -> [Option] +%% Option = mod_pubsub:nodeOption() +%% @doc Returns the default pubsub node options. +%%

    Example of function return value:

    +%% ``` +%% [{deliver_payloads, true}, +%% {notify_config, false}, +%% {notify_delete, false}, +%% {notify_retract, true}, +%% {persist_items, true}, +%% {max_items, 10}, +%% {subscribe, true}, +%% {access_model, open}, +%% {publish_model, publishers}, +%% {max_payload_size, 100000}, +%% {send_last_published_item, never}, +%% {presence_based_delivery, false}]''' +options() -> + [{deliver_payloads, true}, + {notify_config, false}, + {notify_delete, false}, + {notify_retract, true}, + {persist_items, true}, + {max_items, ?MAXITEMS div 2}, + {subscribe, true}, + {access_model, open}, + {roster_groups_allowed, []}, + {publish_model, publishers}, + {max_payload_size, ?MAX_PAYLOAD_SIZE}, + {send_last_published_item, on_sub_and_presence}, + {deliver_notifications, true}, + {presence_based_delivery, false}, + {odbc, true}, + {rsm, true}]. + +%% @spec () -> [] +%% @doc Returns the node features +features() -> + ["create-nodes", + "auto-create", + "access-authorize", + "delete-nodes", + "delete-items", + "get-pending", + "instant-nodes", + "manage-subscriptions", + "modify-affiliations", + "multi-subscribe", + "outcast-affiliation", + "persistent-items", + "publish", + "purge-nodes", + "retract-items", + "retrieve-affiliations", + "retrieve-items", + "retrieve-subscriptions", + "subscribe", + "subscription-notifications", + "subscription-options", + "rsm" + ]. + +%% @spec (Host, ServerHost, Node, ParentNode, Owner, Access) -> bool() +%% Host = mod_pubsub:host() +%% ServerHost = mod_pubsub:host() +%% Node = mod_pubsub:pubsubNode() +%% ParentNode = mod_pubsub:pubsubNode() +%% Owner = mod_pubsub:jid() +%% Access = all | atom() +%% @doc Checks if the current user has the permission to create the requested node +%%

    In {@link node_default}, the permission is decided by the place in the +%% hierarchy where the user is creating the node. The access parameter is also +%% checked in the default module. This parameter depends on the value of the +%% access_createnode ACL value in ejabberd config file.

    +%%

    This function also check that node can be created a a children of its +%% parent node

    +%%

    PubSub plugins can redefine the PubSub node creation rights as they +%% which. They can simply delegate this check to the {@link node_default} +%% module by implementing this function like this: +%% ```check_create_user_permission(Host, ServerHost, Node, ParentNode, Owner, Access) -> +%% node_default:check_create_user_permission(Host, ServerHost, Node, ParentNode, Owner, Access).'''

    +create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) -> + LOwner = jlib:short_prepd_jid(Owner), + {User, Server, _Resource} = LOwner, + Allowed = case LOwner of + {undefined, Host, undefined} -> + true; % pubsub service always allowed + _ -> + {LU, LS, LR} = LOwner, + case acl:match_rule(ServerHost, Access, exmpp_jid:make(LU, LS, LR)) of + allow -> + case Node of + ["home", Server, User | _] -> true; + _ -> false + end; + _ -> + false + end + end, + {result, Allowed}. + +%% @spec (NodeId, Owner) -> +%% {result, Result} | exit +%% NodeId = mod_pubsub:pubsubNodeId() +%% Owner = mod_pubsub:jid() +%% @doc

    +create_node(NodeId, Owner) -> + OwnerKey = jlib:short_prepd_bare_jid(Owner), + State = #pubsub_state{stateid = {OwnerKey, NodeId}, affiliation = owner}, + catch ejabberd_odbc:sql_query_t( + ["insert into pubsub_state(nodeid, jid, affiliation, subscriptions) " + "values(", state_to_raw(NodeId, State), ");"]), + {result, {default, broadcast}}. + +%% @spec (Removed) -> ok +%% Removed = [mod_pubsub:pubsubNode()] +%% @doc

    purge items of deleted nodes after effective deletion.

    +delete_node(Removed) -> +%% pablo: TODO, this is present on trunk/node_home_tree but not on trunk/node_home_tree_odbc. +%% check what is the desired behaviour +%% Tr = fun(#pubsub_state{stateid = {J, _}, subscriptions = Ss}) -> +%% lists:map(fun(S) -> +%% {J, S} +%% end, Ss) +%% end, + Reply = lists:map( + fun(#pubsub_node{id = NodeId} = PubsubNode) -> + Subscriptions = case catch ejabberd_odbc:sql_query_t( + ["select jid, subscriptions " + "from pubsub_state " + "where nodeid='", NodeId, ";"]) of + {selected, ["jid", "subscriptions"], RItems} -> + lists:map(fun({SJID, Subscriptions}) -> + {decode_jid(SJID), decode_subscriptions(Subscriptions)} + end, RItems); + _ -> + [] + end, + %% state and item remove already done thanks to DELETE CASCADE + %% but here we get nothing in States, making notify_retract unavailable ! + %% TODO, remove DELETE CASCADE from schema + {PubsubNode, Subscriptions} + end, Removed), + {result, {default, broadcast, Reply}}. + +%% @spec (NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> +%% {error, Reason} | {result, Result} +%% @doc

    Accepts or rejects subcription requests on a PubSub node.

    +%%

    The mechanism works as follow: +%%

      +%%
    • The main PubSub module prepares the subscription and passes the +%% result of the preparation as a record.
    • +%%
    • This function gets the prepared record and several other parameters and +%% can decide to:
        +%%
      • reject the subscription;
      • +%%
      • allow it as is, letting the main module perform the database +%% persistance;
      • +%%
      • allow it, modifying the record. The main module will store the +%% modified record;
      • +%%
      • allow it, but perform the needed persistance operations.
      +%%

    +%%

    The selected behaviour depends on the return parameter: +%%

      +%%
    • {error, Reason}: an IQ error result will be returned. No +%% subscription will actually be performed.
    • +%%
    • true: Subscribe operation is allowed, based on the +%% unmodified record passed in parameter SubscribeResult. If this +%% parameter contains an error, no subscription will be performed.
    • +%%
    • {true, PubsubState}: Subscribe operation is allowed, but +%% the {@link mod_pubsub:pubsubState()} record returned replaces the value +%% passed in parameter SubscribeResult.
    • +%%
    • {true, done}: Subscribe operation is allowed, but the +%% {@link mod_pubsub:pubsubState()} will be considered as already stored and +%% no further persistance operation will be performed. This case is used, +%% when the plugin module is doing the persistance by itself or when it want +%% to completly disable persistance.
    +%%

    +%%

    In the default plugin module, the record is unchanged.

    +subscribe_node(NodeId, Sender, Subscriber, AccessModel, + SendLast, PresenceSubscription, RosterGroup, Options) -> + SubKey = jlib:short_prepd_jid(Subscriber), + GenKey = jlib:short_prepd_bare_jid(SubKey), + Authorized = (jlib:short_prepd_bare_jid(Sender) == GenKey), + {Affiliation, Subscriptions} = select_affiliation_subscriptions(NodeId, GenKey, SubKey), + Whitelisted = lists:member(Affiliation, [member, publisher, owner]), + PendingSubscription = lists:any(fun({pending, _}) -> true; + (_) -> false + end, Subscriptions), + if + not Authorized -> + %% JIDs do not match + {error, ?ERR_EXTENDED('bad-request', "invalid-jid")}; + Affiliation == outcast -> + %% Requesting entity is blocked + {error, 'forbidden'}; + PendingSubscription -> + %% Requesting entity has pending subscription + {error, ?ERR_EXTENDED('not-authorized', "pending-subscription")}; + (AccessModel == presence) and (not PresenceSubscription) -> + %% Entity is not authorized to create a subscription (presence subscription required) + {error, ?ERR_EXTENDED('not-authorized', "presence-subscription-required")}; + (AccessModel == roster) and (not RosterGroup) -> + %% Entity is not authorized to create a subscription (not in roster group) + {error, ?ERR_EXTENDED('not-authorized', "not-in-roster-group")}; + (AccessModel == whitelist) and (not Whitelisted) -> + %% Node has whitelist access model and entity lacks required affiliation + {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; + (AccessModel == authorize) -> % TODO: to be done + %% Node has authorize access model + {error, 'forbidden'}; + %%MustPay -> + %% % Payment is required for a subscription + %% {error, ?ERR_PAYMENT_REQUIRED}; + %%ForbiddenAnonymous -> + %% % Requesting entity is anonymous + %% {error, 'forbidden'}; + true -> + case pubsub_subscription_odbc:subscribe_node(Subscriber, NodeId, Options) of + {result, SubId} -> + NewSub = case AccessModel of + authorize -> pending; + _ -> subscribed + end, + update_subscription(NodeId, SubKey, [{NewSub, SubId} |Subscriptions]), + case {NewSub, SendLast} of + {subscribed, never} -> + {result, {default, subscribed, SubId}}; + {subscribed, _} -> + {result, {default, subscribed, SubId, send_last}}; + {_, _} -> + {result, {default, pending, SubId}} + end; + _ -> + {error, 'internal-server-error'} + end + end. + +%% @spec (NodeId, Sender, Subscriber, SubId) -> +%% {error, Reason} | {result, []} +%% NodeId = mod_pubsub:pubsubNodeId() +%% Sender = mod_pubsub:jid() +%% Subscriber = mod_pubsub:jid() +%% SubId = mod_pubsub:subid() +%% Reason = mod_pubsub:stanzaError() +%% @doc

    Unsubscribe the Subscriber from the Node.

    +unsubscribe_node(NodeId, Sender, Subscriber, SubId) -> + SubKey = jlib:short_prepd_jid(Subscriber), + GenKey = jlib:short_prepd_bare_jid(SubKey), + Authorized = (jlib:short_prepd_bare_jid(Sender) == GenKey), + {Affiliation, Subscriptions} = select_affiliation_subscriptions(NodeId, SubKey), + SubIdExists = case SubId of + [] -> false; + List when is_list(List) -> true; + _ -> false + end, + if + %% Requesting entity is prohibited from unsubscribing entity + not Authorized -> + {error, 'forbidden'}; + %% Entity did not specify SubId + %%SubId == "", ?? -> + %% {error, ?ERR_EXTENDED('bad-request', "subid-required")}; + %% Invalid subscription identifier + %%InvalidSubId -> + %% {error, ?ERR_EXTENDED('not-acceptable', "invalid-subid")}; + %% Requesting entity is not a subscriber + Subscriptions == [] -> + {error, ?ERR_EXTENDED('unexpected-request', "not-subscribed")}; + %% Subid supplied, so use that. + SubIdExists -> + Sub = first_in_list(fun(S) -> + case S of + {_Sub, SubId} -> true; + _ -> false + end + end, Subscriptions), + case Sub of + {value, S} -> + delete_subscription(SubKey, NodeId, S, Affiliation, Subscriptions), + {result, default}; + false -> + {error, ?ERR_EXTENDED('unexpected-request', + "not-subscribed")} + end; + %% No subid supplied, but there's only one matching + %% subscription, so use that. + length(Subscriptions) == 1 -> + delete_subscription(SubKey, NodeId, hd(Subscriptions), Affiliation, Subscriptions), + {result, default}; + true -> + {error, ?ERR_EXTENDED('bad-request', "subid-required")} + end. + +delete_subscription(SubKey, NodeId, {Subscription, SubId}, Affiliation, Subscriptions) -> + NewSubs = Subscriptions -- [{Subscription, SubId}], + pubsub_subscription_odbc:unsubscribe_node(SubKey, NodeId, SubId), + case {Affiliation, NewSubs} of + {none, []} -> + % Just a regular subscriber, and this is final item, so + % delete the state. + del_state(NodeId, SubKey); + _ -> + update_subscription(NodeId, SubKey, NewSubs) + end. + + +%% @spec (NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload) -> +%% {true, PubsubItem} | {result, Reply} +%% NodeId = mod_pubsub:pubsubNodeId() +%% Publisher = mod_pubsub:jid() +%% PublishModel = atom() +%% MaxItems = integer() +%% ItemId = string() +%% Payload = term() +%% @doc

    Publishes the item passed as parameter.

    +%%

    The mechanism works as follow: +%%

      +%%
    • The main PubSub module prepares the item to publish and passes the +%% result of the preparation as a {@link mod_pubsub:pubsubItem()} record.
    • +%%
    • This function gets the prepared record and several other parameters and can decide to:
        +%%
      • reject the publication;
      • +%%
      • allow the publication as is, letting the main module perform the database persistance;
      • +%%
      • allow the publication, modifying the record. The main module will store the modified record;
      • +%%
      • allow it, but perform the needed persistance operations.
      +%%

    +%%

    The selected behaviour depends on the return parameter: +%%

      +%%
    • {error, Reason}: an iq error result will be return. No +%% publication is actually performed.
    • +%%
    • true: Publication operation is allowed, based on the +%% unmodified record passed in parameter Item. If the Item +%% parameter contains an error, no subscription will actually be +%% performed.
    • +%%
    • {true, Item}: Publication operation is allowed, but the +%% {@link mod_pubsub:pubsubItem()} record returned replaces the value passed +%% in parameter Item. The persistance will be performed by the main +%% module.
    • +%%
    • {true, done}: Publication operation is allowed, but the +%% {@link mod_pubsub:pubsubItem()} will be considered as already stored and +%% no further persistance operation will be performed. This case is used, +%% when the plugin module is doing the persistance by itself or when it want +%% to completly disable persistance.
    +%%

    +%%

    In the default plugin module, the record is unchanged.

    +publish_item(NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload) -> + SubKey = jlib:short_prepd_jid(Publisher), + GenKey = jlib:short_prepd_bare_jid(Publisher), + {Affiliation, Subscriptions} = select_affiliation_subscriptions(NodeId, GenKey, SubKey), + Subscribed = case PublishModel of + subscribers -> is_subscribed(Subscriptions); + _ -> undefined + end, + if + not ((PublishModel == open) + or ((PublishModel == publishers) + and ((Affiliation == owner) or (Affiliation == publisher))) + or (Subscribed == true)) -> + %% Entity does not have sufficient privileges to publish to node + {error, 'forbidden'}; + true -> + %% TODO: check creation, presence, roster + if MaxItems > 0 -> + %% Note: this works cause set_item tries an update before + %% the insert, and the update just ignore creation field. + PubId = {now(), SubKey}, + set_item(#pubsub_item{itemid = {ItemId, NodeId}, + creation = {now(), GenKey}, + modification = PubId, + payload = Payload}), + Items = [ItemId | itemids(NodeId, GenKey) -- [ItemId]], + {result, {_, OI}} = remove_extra_items(NodeId, MaxItems, Items), + %% set new item list use useless + {result, {default, broadcast, OI}}; + true -> + {result, {default, broadcast, []}} + end + end. + +%% @spec (NodeId, MaxItems, ItemIds) -> {NewItemIds,OldItemIds} +%% NodeId = mod_pubsub:pubsubNodeId() +%% MaxItems = integer() | unlimited +%% ItemIds = [ItemId::string()] +%% NewItemIds = [ItemId::string()] +%% @doc

    This function is used to remove extra items, most notably when the +%% maximum number of items has been reached.

    +%%

    This function is used internally by the core PubSub module, as no +%% permission check is performed.

    +%%

    In the default plugin module, the oldest items are removed, but other +%% rules can be used.

    +%%

    If another PubSub plugin wants to delegate the item removal (and if the +%% plugin is using the default pubsub storage), it can implements this function like this: +%% ```remove_extra_items(NodeId, MaxItems, ItemIds) -> +%% node_default:remove_extra_items(NodeId, MaxItems, ItemIds).'''

    +remove_extra_items(_NodeId, unlimited, ItemIds) -> + {result, {ItemIds, []}}; +remove_extra_items(NodeId, MaxItems, ItemIds) -> + NewItems = lists:sublist(ItemIds, MaxItems), + OldItems = lists:nthtail(length(NewItems), ItemIds), + %% Remove extra items: + del_items(NodeId, OldItems), + %% Return the new items list: + {result, {NewItems, OldItems}}. + +%% @spec (NodeId, Publisher, PublishModel, ItemId) -> +%% {error, Reason::stanzaError()} | +%% {result, []} +%% NodeId = mod_pubsub:pubsubNodeId() +%% Publisher = mod_pubsub:jid() +%% PublishModel = atom() +%% ItemId = string() +%% @doc

    Triggers item deletion.

    +%%

    Default plugin: The user performing the deletion must be the node owner +%% or a publisher, or PublishModel being open.

    +delete_item(NodeId, Publisher, PublishModel, ItemId) -> + GenKey = jlib:short_prepd_bare_jid(Publisher), + {result, Affiliation} = get_affiliation(NodeId, GenKey), + Allowed = (Affiliation == publisher) orelse (Affiliation == owner) + orelse (PublishModel == open) + orelse case get_item(NodeId, ItemId) of + {result, #pubsub_item{creation = {_, GenKey}}} -> true; + _ -> false + end, + if + not Allowed -> + %% Requesting entity does not have sufficient privileges + {error, 'forbidden'}; + true -> + case del_item(NodeId, ItemId) of + {updated, 1} -> + %% set new item list use useless + {result, {default, broadcast}}; + _ -> + %% Non-existent node or item + {error, 'item-not-found'} + end + end. + +%% @spec (NodeId, Owner) -> +%% {error, Reason::stanzaError()} | +%% {result, {default, broadcast}} +%% NodeId = mod_pubsub:pubsubNodeId() +%% Owner = mod_pubsub:jid() +purge_node(NodeId, Owner) -> + GenKey = jlib:short_prepd_bare_jid(Owner), + GenState = get_state(NodeId, GenKey), + case GenState of + #pubsub_state{items = Items, affiliation = owner} -> + del_items(NodeId, Items), + %% set new item list use useless + {result, {default, broadcast}}; + _ -> + %% Entity is not owner + {error, 'forbidden'} + end. + +%% @spec (Host, JID) -> [{Node,Affiliation}] +%% Host = host() +%% JID = mod_pubsub:jid() +%% @doc

    Return the current affiliations for the given user

    +%%

    The default module reads affiliations in the main Mnesia +%% pubsub_state table. If a plugin stores its data in the same +%% table, it should return an empty list, as the affiliation will be read by +%% the default PubSub module. Otherwise, it should return its own affiliation, +%% that will be added to the affiliation stored in the main +%% pubsub_state table.

    +get_entity_affiliations(Host, Owner) -> + GenKey = jlib:short_prepd_bare_jid(Owner), + H = ?PUBSUB:escape(Host), + J = encode_jid(GenKey), + Reply = case catch ejabberd_odbc:sql_query_t( + ["select node, type, i.nodeid, affiliation " + "from pubsub_state i, pubsub_node n " + "where i.nodeid = n.nodeid " + "and jid='", J, "' " + "and host='", H, "';"]) of + {selected, ["node", "type", "nodeid", "affiliation"], RItems} -> + lists:map(fun({N, T, I, A}) -> + Node = nodetree_tree_odbc:raw_to_node(Host, {N, "", T, I}), + {Node, decode_affiliation(A)} + end, RItems); + _ -> + [] + end, + {result, Reply}. + +get_node_affiliations(NodeId) -> + Reply = case catch ejabberd_odbc:sql_query_t( + ["select jid, affiliation " + "from pubsub_state " + "where nodeid='", NodeId, "';"]) of + {selected, ["jid", "affiliation"], RItems} -> + lists:map(fun({J, A}) -> {decode_jid(J), decode_affiliation(A)} end, RItems); + _ -> + [] + end, + {result, Reply}. + +get_affiliation(NodeId, Owner) -> + GenKey = jlib:short_prepd_bare_jid(Owner), + J = encode_jid(GenKey), + Reply = case catch ejabberd_odbc:sql_query_t( + ["select affiliation from pubsub_state " + "where nodeid='", NodeId, "' and jid='", J, "';"]) of + {selected, ["affiliation"], [{A}]} -> decode_affiliation(A); + _ -> none + end, + {result, Reply}. + +set_affiliation(NodeId, Owner, Affiliation) when ?IS_JID(Owner)-> + GenKey = jlib:short_prepd_bare_jid(Owner), + {_, Subscriptions} = select_affiliation_subscriptions(NodeId, GenKey), + case {Affiliation, Subscriptions} of + {none, none} -> + del_state(NodeId, GenKey); + _ -> + update_affiliation(NodeId, GenKey, Affiliation) + end. + +%% @spec (Host, Owner) -> [{Node,Subscription}] +%% Host = host() +%% Owner = mod_pubsub:jid() +%% @doc

    Return the current subscriptions for the given user

    +%%

    The default module reads subscriptions in the main Mnesia +%% pubsub_state table. If a plugin stores its data in the same +%% table, it should return an empty list, as the affiliation will be read by +%% the default PubSub module. Otherwise, it should return its own affiliation, +%% that will be added to the affiliation stored in the main +%% pubsub_state table.

    +get_entity_subscriptions(Host, Owner) -> + SubKey = jlib:short_prepd_jid(Owner), + GenKey = jlib:short_prepd_bare_jid(Owner), + H = ?PUBSUB:escape(Host), + SJ = encode_jid(SubKey), + GJ = encode_jid(GenKey), + Query = case SubKey of + GenKey -> + ["select node, type, i.nodeid, jid, subscriptions " + "from pubsub_state i, pubsub_node n " + "where i.nodeid = n.nodeid " + "and jid like '", GJ, "%' " + "and host='", H, "';"]; + _ -> + ["select node, type, i.nodeid, jid, subscriptions " + "from pubsub_state i, pubsub_node n " + "where i.nodeid = n.nodeid " + "and jid in ('", SJ, "', '", GJ, "') " + "and host='", H, "';"] + end, + Reply = case catch ejabberd_odbc:sql_query_t(Query) of + {selected, ["node", "type", "nodeid", "jid", "subscriptions"], RItems} -> + lists:map(fun({N, T, I, J, S}) -> + Node = nodetree_tree_odbc:raw_to_node(Host, {N, "", T, I}), + {Node, decode_subscriptions(S), decode_jid(J)} + end, RItems); + _ -> + [] + end, + {result, Reply}. +%% do the same as get_entity_subscriptions but filter result only to +%% nodes having send_last_published_item=on_sub_and_presence +%% as this call avoid seeking node, it must return node and type as well +get_entity_subscriptions_for_send_last(Host, Owner) -> + SubKey = jlib:jid_tolower(Owner), + GenKey = jlib:jid_remove_resource(SubKey), + H = ?PUBSUB:escape(Host), + SJ = encode_jid(SubKey), + GJ = encode_jid(GenKey), + Query = case SubKey of + GenKey -> + ["select node, type, i.nodeid, jid, subscriptions " + "from pubsub_state i, pubsub_node n, pubsub_node_option o " + "where i.nodeid = n.nodeid and n.nodeid = o.nodeid " + "and name='send_last_published_item' and val='on_sub_and_presence' " + "and jid like '", GJ, "%' " + "and host='", H, "';"]; + _ -> + ["select node, type, i.nodeid, jid, subscriptions " + "from pubsub_state i, pubsub_node n, pubsub_node_option o " + "where i.nodeid = n.nodeid and n.nodeid = o.nodeid " + "and name='send_last_published_item' and val='on_sub_and_presence' " + "and jid in ('", SJ, "', '", GJ, "') " + "and host='", H, "';"] + end, + Reply = case catch ejabberd_odbc:sql_query_t(Query) of + {selected, ["node", "type", "nodeid", "jid", "subscriptions"], RItems} -> + lists:map(fun({N, T, I, J, S}) -> + Node = nodetree_tree_odbc:raw_to_node(Host, {N, "", T, I}), + {Node, decode_subscriptions(S), decode_jid(J)} + end, RItems); + _ -> + [] + end, + {result, Reply}. + +get_node_subscriptions(NodeId) -> + Reply = case catch ejabberd_odbc:sql_query_t( + ["select jid, subscriptions " + "from pubsub_state " + "where nodeid='", NodeId, "';"]) of + {selected, ["jid", "subscriptions"], RItems} -> + lists:map(fun({J, S}) -> {decode_jid(J), decode_subscriptions(S)} end, RItems); + % TODO {J, S, SubId} + _ -> + [] + end, + {result, Reply}. + + +get_subscriptions(NodeId, Owner) -> + SubKey = jlib:short_prepd_jid(Owner), + J = encode_jid(SubKey), + Reply = case catch ejabberd_odbc:sql_query_t( + ["select subscriptions from pubsub_state " + "where nodeid='", NodeId, "' and jid='", J, "';"]) of + {selected, ["subscriptions"], [{S}]} -> decode_subscriptions(S); + _ -> none + end, + {result, Reply}. + +set_subscriptions(NodeId, Owner, Subscription, SubId) -> + SubKey = jlib:short_prepd_jid(Owner), + SubState = get_state_without_itemids(NodeId, SubKey), + case {SubId, SubState#pubsub_state.subscriptions} of + {_, []} -> + %% pablo TODO, there seems that commit 2528 was applied to mnesia but not ported to odbc + {error, 'item-not-found'}; + {"", [{_, SID}]} -> + case Subscription of + none -> unsub_with_subid(NodeId, SID, SubState); + _ -> replace_subscription({Subscription, SID}, SubState) + end; + {"", [_|_]} -> + {error, ?ERR_EXTENDED('bad_request', "subid-required")}; + _ -> + case Subscription of + none -> unsub_with_subid(NodeId, SubId, SubState); + _ -> replace_subscription({Subscription, SubId}, SubState) + end + end. + +replace_subscription(NewSub, SubState) -> + NewSubs = replace_subscription(NewSub, + SubState#pubsub_state.subscriptions, []), + set_state(SubState#pubsub_state{subscriptions = NewSubs}). + +replace_subscription(_, [], Acc) -> + Acc; +replace_subscription({Sub, SubId}, [{_, SubID} | T], Acc) -> + replace_subscription({Sub, SubId}, T, [{Sub, SubID} | Acc]). + +unsub_with_subid(NodeId, SubId, SubState) -> + pubsub_subscription_odbc:unsubscribe_node(SubState#pubsub_state.stateid, + NodeId, SubId), + NewSubs = lists:filter(fun ({_, SID}) -> SubId =/= SID end, + SubState#pubsub_state.subscriptions), + case {NewSubs, SubState#pubsub_state.affiliation} of + {[], none} -> + del_state(NodeId, element(1, SubState#pubsub_state.stateid)); + _ -> + set_state(SubState#pubsub_state{subscriptions = NewSubs}) + end. +%% @spec (Host, Owner) -> {result, [Node]} | {error, Reason} +%% Host = host() +%% Owner = jid() +%% Node = pubsubNode() +%% @doc

    Returns a list of Owner's nodes on Host with pending +%% subscriptions.

    +get_pending_nodes(Host, Owner) -> + %% pablo TODO, need to port those jlib:* calls to exmpp. Mnesia? + GenKey = jlib:jid_remove_resource(jlib:jid_tolower(Owner)), + States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, + affiliation = owner, + _ = '_'}), + NodeIDs = [ID || #pubsub_state{stateid = {_, ID}} <- States], + NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of + [{nodetree, N}] -> N; + _ -> nodetree_tree_odbc + end, + Reply = mnesia:foldl(fun(#pubsub_state{stateid = {_, NID}} = S, Acc) -> + case lists:member(NID, NodeIDs) of + true -> + case get_nodes_helper(NodeTree, S) of + {value, Node} -> [Node | Acc]; + false -> Acc + end; + false -> + Acc + end + end, [], pubsub_state), + {result, Reply}. + +get_nodes_helper(NodeTree, + #pubsub_state{stateid = {_, N}, subscriptions = Subs}) -> + HasPending = fun ({pending, _}) -> true; + (pending) -> true; + (_) -> false + end, + case lists:any(HasPending, Subs) of + true -> + case NodeTree:get_node(N) of + #pubsub_node{nodeid = {_, Node}} -> + {value, Node}; + _ -> + false + end; + false -> + false + end. + +%% @spec (NodeId) -> [States] | [] +%% NodeId = mod_pubsub:pubsubNodeId() +%% @doc Returns the list of stored states for a given node. +%%

    For the default PubSub module, states are stored in Mnesia database.

    +%%

    We can consider that the pubsub_state table have been created by the main +%% mod_pubsub module.

    +%%

    PubSub plugins can store the states where they wants (for example in a +%% relational database).

    +%%

    If a PubSub plugin wants to delegate the states storage to the default node, +%% they can implement this function like this: +%% ```get_states(NodeId) -> +%% node_default:get_states(NodeId).'''

    +get_states(NodeId) -> + case catch ejabberd_odbc:sql_query_t( + ["select jid, affiliation, subscriptions " + "from pubsub_state " + "where nodeid='", NodeId, "';"]) of + {selected, ["jid", "affiliation", "subscriptions"], RItems} -> + {result, lists:map(fun({SJID, Affiliation, Subscriptions}) -> + #pubsub_state{stateid = {decode_jid(SJID), NodeId}, + items = itemids(NodeId, SJID), + affiliation = decode_affiliation(Affiliation), + subscriptions = decode_subscriptions(Subscriptions)} + end, RItems)}; + _ -> + {result, []} + end. + + +%% @spec (NodeId, JID) -> [State] | [] +%% NodeId = mod_pubsub:pubsubNodeId() +%% JID = mod_pubsub:jid() +%% State = mod_pubsub:pubsubItems() +%% @doc

    Returns a state (one state list), given its reference.

    +get_state(NodeId, JID) -> + State = get_state_without_itemids(NodeId, JID), + {SJID, _} = State#pubsub_state.stateid, + State#pubsub_state{items = itemids(NodeId, SJID)}. +get_state_without_itemids(NodeId, JID) -> + J = encode_jid(JID), + case catch ejabberd_odbc:sql_query_t( + ["select jid, affiliation, subscriptions " + "from pubsub_state " + "where jid='", J, "' " + "and nodeid='", NodeId, "';"]) of + {selected, ["jid", "affiliation", "subscriptions"], [{SJID, Affiliation, Subscriptions}]} -> + #pubsub_state{stateid = {decode_jid(SJID), NodeId}, + affiliation = decode_affiliation(Affiliation), + subscriptions = decode_subscriptions(Subscriptions)}; + _ -> + #pubsub_state{stateid={JID, NodeId}} + end. + +%% @spec (State) -> ok | {error, Reason::stanzaError()} +%% State = mod_pubsub:pubsubStates() +%% @doc

    Write a state into database.

    +set_state(State) when is_record(State, pubsub_state) -> + {_, NodeId} = State#pubsub_state.stateid, + set_state(NodeId, State). +set_state(NodeId, State) -> + %% NOTE: in odbc version, as we do not handle item list, + %% we just need to update affiliation and subscription + %% cause {JID,NodeId} is the key. if it does not exists, then we insert it. + %% MySQL can be optimized using INSERT ... ON DUPLICATE KEY as well + {JID, _} = State#pubsub_state.stateid, + J = encode_jid(JID), + S = encode_subscriptions(State#pubsub_state.subscriptions), + A = encode_affiliation(State#pubsub_state.affiliation), + case catch ejabberd_odbc:sql_query_t( + ["update pubsub_state " + "set subscriptions='", S, "', affiliation='", A, "' " + "where nodeid='", NodeId, "' and jid='", J, "';"]) of + {updated, 1} -> + ok; + _ -> + catch ejabberd_odbc:sql_query_t( + ["insert into pubsub_state(nodeid, jid, affiliation, subscriptions) " + "values('", NodeId, "', '", J, "', '", A, "', '", S, "');"]) + end, + {result, []}. + +%% @spec (StateId) -> ok | {error, Reason::stanzaError()} +%% StateId = mod_pubsub:pubsubStateId() +%% @doc

    Delete a state from database.

    +del_state(NodeId, JID) -> + J = encode_jid(JID), + catch ejabberd_odbc:sql_query_t( + ["delete from pubsub_state " + "where jid='", J, "' " + "and nodeid='", NodeId, "';"]), + ok. + +%% @spec (NodeId, From) -> {[Items], RsmOut} | [] +%% NodeId = mod_pubsub:pubsubNodeId() +%% Items = mod_pubsub:pubsubItems() +%% @doc Returns the list of stored items for a given node. +%%

    For the default PubSub module, items are stored in Mnesia database.

    +%%

    We can consider that the pubsub_item table have been created by the main +%% mod_pubsub module.

    +%%

    PubSub plugins can store the items where they wants (for example in a +%% relational database), or they can even decide not to persist any items.

    +%%

    If a PubSub plugin wants to delegate the item storage to the default node, +%% they can implement this function like this: +%% ```get_items(NodeId, From) -> +%% node_default:get_items(NodeId, From).'''

    +get_items(NodeId, _From) -> + case catch ejabberd_odbc:sql_query_t( + ["select itemid, publisher, creation, modification, payload " + "from pubsub_item " + "where nodeid='", NodeId, "' " + "order by modification desc;"]) of + {selected, ["itemid", "publisher", "creation", "modification", "payload"], RItems} -> + {result, lists:map(fun(RItem) -> raw_to_item(NodeId, RItem) end, RItems)}; + _ -> + {result, []} + end. +get_items(NodeId, From, none) -> + get_items(NodeId, From, #rsm_in{max = ?MAXITEMS div 2}); +get_items(NodeId, _From, #rsm_in{max=M, direction=Direction, id=I, index=IncIndex})-> + Max = ?PUBSUB:escape(i2l(M)), + + {Way, Order} = case Direction of + aft -> {"<", "desc"}; + before when I == [] -> {"is not", "asc"}; + before -> {">", "asc"}; + _ when IncIndex =/= undefined -> {"<", "desc"}; % using index + _ -> {"is not", "desc"}% Can be better + end, + [AttrName, Id] = case I of + undefined when IncIndex =/= undefined -> + case catch ejabberd_odbc:sql_query_t( + ["select modification from pubsub_item pi " + "where exists ( " + "select count(*) as count1 " + "from pubsub_item " + "where nodeid='", NodeId, "' " + "and modification > pi.modification " + "having count1 = ",?PUBSUB:escape(i2l(IncIndex))," );"]) of + {selected, [_], [{O}]} -> ["modification", "'"++O++"'"]; + _ -> ["modification", "null"] + end; + undefined -> ["modification", "null"]; + [] -> ["modification", "null"]; + I -> [A, B] = string:tokens(?PUBSUB:escape(i2l(I)), "@"), + [A, "'"++B++"'"] + end, + Count= case catch ejabberd_odbc:sql_query_t( + ["select count(*) " + "from pubsub_item " + "where nodeid='", NodeId, "';"]) of + {selected, [_], [{C}]} -> C; + _ -> "0" + end, + + case catch ejabberd_odbc:sql_query_t( + ["select itemid, publisher, creation, modification, payload " + "from pubsub_item " + "where nodeid='", NodeId, "' " + "and ", AttrName," ", Way, " ", Id, " " + "order by ", AttrName," ", Order," limit ", i2l(Max)," ;"]) of + {selected, ["itemid", "publisher", "creation", "modification", "payload"], RItems} -> + case length(RItems) of + 0 -> {result, {[], #rsm_out{count=Count}}}; + _ -> + {_, _, _, F, _} = hd(RItems), + Index = case catch ejabberd_odbc:sql_query_t( + ["select count(*) " + "from pubsub_item " + "where nodeid='", NodeId, "' " + "and ", AttrName," > '", F, "';"]) of + %{selected, [_], [{C}, {In}]} -> [string:strip(C, both, $"), string:strip(In, both, $")]; + {selected, [_], [{In}]} -> In; + _ -> "0" + end, + %{F, _} = string:to_integer(FStr), + {_, _, _, L, _} = lists:last(RItems), + RsmOut = #rsm_out{count=Count, index=Index, first="modification@"++F, last="modification@"++i2l(L)}, + {result, {lists:map(fun(RItem) -> raw_to_item(NodeId, RItem) end, RItems), RsmOut}} + end; + _ -> + {result, {[], none}} + end. +get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, none). +get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId, RSM) -> + SubKey = jlib:short_prepd_jid(JID), + GenKey = jlib:short_prepd_bare_jid(JID), + {Affiliation, Subscriptions} = select_affiliation_subscriptions(NodeId, GenKey, SubKey), + Whitelisted = can_fetch_item(Affiliation, Subscriptions), + if + %%SubId == "", ?? -> + %% Entity has multiple subscriptions to the node but does not specify a subscription ID + %{error, ?ERR_EXTENDED('bad-request', "subid-required")}; + %%InvalidSubId -> + %% Entity is subscribed but specifies an invalid subscription ID + %{error, ?ERR_EXTENDED('not-acceptable', "invalid-subid")}; + Affiliation == outcast -> + %% Requesting entity is blocked + {error, 'forbidden'}; + (AccessModel == presence) and (not PresenceSubscription) -> + %% Entity is not authorized to create a subscription (presence subscription required) + {error, ?ERR_EXTENDED('not-authorized', "presence-subscription-required")}; + (AccessModel == roster) and (not RosterGroup) -> + %% Entity is not authorized to create a subscription (not in roster group) + {error, ?ERR_EXTENDED('not-authorized', "not-in-roster-group")}; + (AccessModel == whitelist) and (not Whitelisted) -> + %% Node has whitelist access model and entity lacks required affiliation + {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; + (AccessModel == authorize) -> % TODO: to be done + %% Node has authorize access model + {error, 'forbidden'}; + %%MustPay -> + %% % Payment is required for a subscription + %% {error, ?ERR_PAYMENT_REQUIRED}; + true -> + get_items(NodeId, JID, RSM) + end. + +get_last_items(NodeId, _From, Count) -> + case catch ejabberd_odbc:sql_query_t( + ["select itemid, publisher, creation, modification, payload " + "from pubsub_item " + "where nodeid='", NodeId, "' " + "order by modification desc limit ", i2l(Count), ";"]) of + {selected, ["itemid", "publisher", "creation", "modification", "payload"], RItems} -> + {result, lists:map(fun(RItem) -> raw_to_item(NodeId, RItem) end, RItems)}; + _ -> + {result, []} + end. + +%% @spec (NodeId, ItemId) -> [Item] | [] +%% NodeId = mod_pubsub:pubsubNodeId() +%% ItemId = string() +%% Item = mod_pubsub:pubsubItems() +%% @doc

    Returns an item (one item list), given its reference.

    +get_item(NodeId, ItemId) -> + I = ?PUBSUB:escape(ItemId), + case catch ejabberd_odbc:sql_query_t( + ["select itemid, publisher, creation, modification, payload " + "from pubsub_item " + "where nodeid='", NodeId, "' " + "and itemid='", I,"';"]) of + {selected, ["itemid", "publisher", "creation", "modification", "payload"], [RItem]} -> + {result, raw_to_item(NodeId, RItem)}; + _ -> + {error, 'item-not-found'} + end. + +get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> + SubKey = jlib:short_prepd_jid(JID), + GenKey = jlib:short_prepd_bare_jid(JID), + {Affiliation, Subscriptions} = select_affiliation_subscriptions(NodeId, GenKey, SubKey), + Whitelisted = can_fetch_item(Affiliation, Subscriptions), + if + %%SubId == "", ?? -> + %% Entity has multiple subscriptions to the node but does not specify a subscription ID + %{error, ?ERR_EXTENDED('bad-request', "subid-required")}; + %%InvalidSubID -> + %% Entity is subscribed but specifies an invalid subscription ID + %{error, ?ERR_EXTENDED('not-acceptable', "invalid-subid")}; + Affiliation == outcast -> + %% Requesting entity is blocked + {error, 'forbidden'}; + (AccessModel == presence) and (not PresenceSubscription) -> + %% Entity is not authorized to create a subscription (presence subscription required) + {error, ?ERR_EXTENDED('not-authorized', "presence-subscription-required")}; + (AccessModel == roster) and (not RosterGroup) -> + %% Entity is not authorized to create a subscription (not in roster group) + {error, ?ERR_EXTENDED('not-authorized', "not-in-roster-group")}; + (AccessModel == whitelist) and (not Whitelisted) -> + %% Node has whitelist access model and entity lacks required affiliation + {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; + (AccessModel == authorize) -> % TODO: to be done + %% Node has authorize access model + {error, 'forbidden'}; + %%MustPay -> + %% % Payment is required for a subscription + %% {error, ?ERR_PAYMENT_REQUIRED}; + true -> + get_item(NodeId, ItemId) + end. + +%% @spec (Item) -> ok | {error, Reason::stanzaError()} +%% Item = mod_pubsub:pubsubItems() +%% @doc

    Write an item into database.

    +set_item(Item) -> + {ItemId, NodeId} = Item#pubsub_item.itemid, + I = ?PUBSUB:escape(ItemId), + {C, _} = Item#pubsub_item.creation, + {M, JID} = Item#pubsub_item.modification, + P = encode_jid(JID), + Payload = Item#pubsub_item.payload, + XML = ?PUBSUB:escape(lists:flatten(lists:map(fun(X) -> xml:element_to_string(X) end, Payload))), + S = fun({T1, T2, T3}) -> + lists:flatten([i2l(T1, 6), ":", i2l(T2, 6), ":", i2l(T3, 6)]) + end, + case catch ejabberd_odbc:sql_query_t( + ["update pubsub_item " + "set publisher='", P, "', modification='", S(M), "', payload='", XML, "' " + "where nodeid='", NodeId, "' and itemid='", I, "';"]) of + {updated, 1} -> + ok; + _ -> + catch ejabberd_odbc:sql_query_t( + ["insert into pubsub_item " + "(nodeid, itemid, publisher, creation, modification, payload) " + "values('", NodeId, "', '", I, "', '", P, "', '", S(C), "', '", S(M), "', '", XML, "');"]) + end, + {result, []}. + +%% @spec (NodeId, ItemId) -> ok | {error, Reason::stanzaError()} +%% NodeId = mod_pubsub:pubsubNodeId() +%% ItemId = string() +%% @doc

    Delete an item from database.

    +del_item(NodeId, ItemId) -> + I = ?PUBSUB:escape(ItemId), + catch ejabberd_odbc:sql_query_t( + ["delete from pubsub_item " + "where itemid='", I, "' " + "and nodeid='", NodeId, "';"]). +del_items(_, []) -> + ok; +del_items(NodeId, [ItemId]) -> + del_item(NodeId, ItemId); +del_items(NodeId, ItemIds) -> + I = string:join([["'", ?PUBSUB:escape(X), "'"] || X <- ItemIds], ","), + catch ejabberd_odbc:sql_query_t( + ["delete from pubsub_item " + "where itemid in (", I, ") " + "and nodeid='", NodeId, "';"]). + +%% @doc

    Return the name of the node if known: Default is to return +%% node id.

    +get_item_name(_Host, _Node, Id) -> + Id. + +%% @spec (Affiliation, Subscription) -> true | false +%% Affiliation = owner | member | publisher | outcast | none +%% Subscription = subscribed | none +%% @doc Determines if the combination of Affiliation and Subscribed +%% are allowed to get items from a node. +can_fetch_item(owner, _) -> true; +can_fetch_item(member, _) -> true; +can_fetch_item(publisher, _) -> true; +can_fetch_item(outcast, _) -> false; +can_fetch_item(none, Subscriptions) -> is_subscribed(Subscriptions); +can_fetch_item(_Affiliation, _Subscription) -> false. + +is_subscribed(Subscriptions) -> + lists:any(fun ({subscribed, _SubId}) -> true; + (_) -> false + end, Subscriptions). + +%% Returns the first item where Pred() is true in List +first_in_list(_Pred, []) -> + false; +first_in_list(Pred, [H | T]) -> + case Pred(H) of + true -> {value, H}; + _ -> first_in_list(Pred, T) + end. + +itemids(NodeId, {U, S, R}) -> + itemids(NodeId, encode_jid({U, S, R})); +itemids(NodeId, SJID) -> + case catch ejabberd_odbc:sql_query_t( + ["select itemid " + "from pubsub_item " + "where nodeid='", NodeId, "' " + "and publisher like '", SJID, "%' " + "order by modification desc;"]) of + {selected, ["itemid"], RItems} -> + lists:map(fun({ItemId}) -> ItemId end, RItems); + _ -> + [] + end. + +select_affiliation_subscriptions(NodeId, JID) -> + J = encode_jid(JID), + case catch ejabberd_odbc:sql_query_t( + ["select affiliation,subscriptions from pubsub_state " + "where nodeid='", NodeId, "' and jid='", J, "';"]) of + {selected, ["affiliation", "subscriptions"], [{A, S}]} -> + {decode_affiliation(A), decode_subscriptions(S)}; + _ -> + {none, none} + end. +select_affiliation_subscriptions(NodeId, JID, JID) -> + select_affiliation_subscriptions(NodeId, JID); +select_affiliation_subscriptions(NodeId, GenKey, SubKey) -> + {result, Affiliation} = get_affiliation(NodeId, GenKey), + {result, Subscriptions} = get_subscriptions(NodeId, SubKey), + {Affiliation, Subscriptions}. + +update_affiliation(NodeId, JID, Affiliation) -> + J = encode_jid(JID), + A = encode_affiliation(Affiliation), + case catch ejabberd_odbc:sql_query_t( + ["update pubsub_state " + "set affiliation='", A, "' " + "where nodeid='", NodeId, "' and jid='", J, "';"]) of + {updated, 1} -> + ok; + _ -> + catch ejabberd_odbc:sql_query_t( + ["insert into pubsub_state(nodeid, jid, affiliation, subscriptions) " + "values('", NodeId, "', '", J, "', '", A, "', '');"]) + end. + +update_subscription(NodeId, JID, Subscription) -> + J = encode_jid(JID), + S = encode_subscriptions(Subscription), + case catch ejabberd_odbc:sql_query_t( + ["update pubsub_state " + "set subscriptions='", S, "' " + "where nodeid='", NodeId, "' and jid='", J, "';"]) of + {updated, 1} -> + ok; + _ -> + catch ejabberd_odbc:sql_query_t( + ["insert into pubsub_state(nodeid, jid, affiliation, subscriptions) " + "values('", NodeId, "', '", J, "', 'n', '", S, "');"]) + end. + +decode_jid(SJID) -> jlib:jid_tolower(jlib:string_to_jid(SJID)). + +decode_node(N) -> ?PUBSUB:string_to_node(N). + +decode_affiliation("o") -> owner; +decode_affiliation("p") -> publisher; +decode_affiliation("c") -> outcast; +decode_affiliation(_) -> none. + +decode_subscription("s") -> subscribed; +decode_subscription("p") -> pending; +decode_subscription("u") -> unconfigured; +decode_subscription(_) -> none. +decode_subscriptions(Subscriptions) -> + lists:foldl(fun(Subscription, Acc) -> + case string:tokens(Subscription, ":") of + [S, SubId] -> [{decode_subscription(S), SubId}|Acc]; + _ -> Acc + end + end, [], string:tokens(Subscriptions, ",")). + +encode_jid(JID) -> ?PUBSUB:escape(jlib:jid_to_string(JID)). + +encode_affiliation(owner) -> "o"; +encode_affiliation(publisher) -> "p"; +encode_affiliation(outcast) -> "c"; +encode_affiliation(_) -> "n". + +encode_subscription(subscribed) -> "s"; +encode_subscription(pending) -> "p"; +encode_subscription(unconfigured) -> "u"; +encode_subscription(_) -> "n". +encode_subscriptions(Subscriptions) -> + string:join(lists:map(fun({S, SubId}) -> + encode_subscription(S)++":"++SubId + end, Subscriptions), ","). + +%%% record getter/setter + +state_to_raw(NodeId, State) -> + {JID, _} = State#pubsub_state.stateid, + J = encode_jid(JID), + A = encode_affiliation(State#pubsub_state.affiliation), + S = encode_subscriptions(State#pubsub_state.subscriptions), + ["'", NodeId, "', '", J, "', '", A, "', '", S, "'"]. + +raw_to_item(NodeId, {ItemId, SJID, Creation, Modification, XML}) -> + JID = decode_jid(SJID), + ToTime = fun(Str) -> + [T1,T2,T3] = string:tokens(Str, ":"), + {l2i(T1), l2i(T2), l2i(T3)} + end, + Payload = case xml_stream:parse_element(XML) of + {error, _Reason} -> []; + El -> [El] + end, + #pubsub_item{itemid = {ItemId, NodeId}, + creation={ToTime(Creation), JID}, + modification={ToTime(Modification), JID}, + payload = Payload}. + +l2i(L) when is_list(L) -> list_to_integer(L); +l2i(I) when is_integer(I) -> I. +i2l(I) when is_integer(I) -> integer_to_list(I); +i2l(L) when is_list(L) -> L. +i2l(I, N) when is_integer(I) -> i2l(i2l(I), N); +i2l(L, N) when is_list(L) -> + case length(L) of + N -> L; + C when C > N -> L; + _ -> i2l([$0|L], N) + end. diff --git a/src/mod_pubsub/node_pep_odbc.erl b/src/mod_pubsub/node_pep_odbc.erl new file mode 100644 index 000000000..6ca622ba6 --- /dev/null +++ b/src/mod_pubsub/node_pep_odbc.erl @@ -0,0 +1,327 @@ +%%% ==================================================================== +%%% ``The contents of this file are subject to the Erlang Public License, +%%% Version 1.1, (the "License"); you may not use this file except in +%%% compliance with the License. You should have received a copy of the +%%% Erlang Public License along with this software. If not, it can be +%%% retrieved via the world wide web at http://www.erlang.org/. +%%% +%%% Software distributed under the License is distributed on an "AS IS" +%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%%% the License for the specific language governing rights and limitations +%%% under the License. +%%% +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne +%%% All Rights Reserved.'' +%%% This software is copyright 2006-2009, ProcessOne. +%%% +%%% +%%% @copyright 2006-2009 ProcessOne +%%% @author Christophe Romain +%%% [http://www.process-one.net/] +%%% @version {@vsn}, {@date} {@time} +%%% @end +%%% ==================================================================== + +%%% @doc The module {@module} is the pep PubSub plugin. +%%%

    PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.

    + +-module(node_pep_odbc). +-author('christophe.romain@process-one.net'). + +-include_lib("exmpp/include/exmpp.hrl"). + +-include("ejabberd.hrl"). +-include("pubsub.hrl"). + +-define(PUBSUB, mod_pubsub_odbc). +-behaviour(gen_pubsub_node). + +%% API definition +-export([init/3, terminate/2, + options/0, features/0, + create_node_permission/6, + create_node/2, + delete_node/1, + purge_node/2, + subscribe_node/8, + unsubscribe_node/4, + publish_item/6, + delete_item/4, + remove_extra_items/3, + get_entity_affiliations/2, + get_node_affiliations/1, + get_affiliation/2, + set_affiliation/3, + get_entity_subscriptions/2, + get_entity_subscriptions_for_send_last/2, + get_node_subscriptions/1, + get_subscriptions/2, + set_subscriptions/4, + get_pending_nodes/2, + get_states/1, + get_state/2, + set_state/1, + get_items/7, + get_items/6, + get_items/3, + get_items/2, + get_item/7, + get_item/2, + set_item/1, + get_item_name/3, + get_last_items/3 + ]). + +init(Host, ServerHost, Opts) -> + node_hometree_odbc:init(Host, ServerHost, Opts), + complain_if_modcaps_disabled(ServerHost), + ok. + +terminate(Host, ServerHost) -> + node_hometree_odbc:terminate(Host, ServerHost), + ok. + +options() -> + [{odbc, true}, + {node_type, pep}, + {deliver_payloads, true}, + {notify_config, false}, + {notify_delete, false}, + {notify_retract, false}, + {persist_items, false}, + {max_items, ?MAXITEMS div 2}, + {subscribe, true}, + {access_model, presence}, + {roster_groups_allowed, []}, + {publish_model, publishers}, + {max_payload_size, ?MAX_PAYLOAD_SIZE}, + {send_last_published_item, on_sub_and_presence}, + {deliver_notifications, true}, + {presence_based_delivery, true}]. + +features() -> + ["create-nodes", %* + "auto-create", %* + "auto-subscribe", %* + "delete-nodes", %* + "delete-items", %* + "filtered-notifications", %* + "modify-affiliations", + "outcast-affiliation", + "persistent-items", + "publish", %* + "purge-nodes", + "retract-items", + "retrieve-affiliations", + "retrieve-items", %* + "retrieve-subscriptions", + "subscribe" %* + ]. + +create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) -> + LOwner = jlib:short_prepd_jid(Owner), + {User, Server, Resource} = LOwner, + Allowed = case LOwner of + {undefined, Host, undefined} -> + true; % pubsub service always allowed + _ -> + JID = exmpp_jid:make(User, Server, Resource), + case acl:match_rule(ServerHost, Access, JID) of + allow -> + case Host of + {User, Server, _} -> true; + _ -> false + end; + E -> + ?DEBUG("Create not allowed : ~p~n", [E]), + false + end + end, + {result, Allowed}. + +create_node(NodeId, Owner) -> + case node_hometree_odbc:create_node(NodeId, Owner) of + {result, _} -> {result, []}; + Error -> Error + end. + +delete_node(Removed) -> + case node_hometree_odbc:delete_node(Removed) of + {result, {_, _, Removed}} -> {result, {[], Removed}}; + Error -> Error + end. + +subscribe_node(NodeId, Sender, Subscriber, AccessModel, + SendLast, PresenceSubscription, RosterGroup, Options) -> + node_hometree_odbc:subscribe_node( + NodeId, Sender, Subscriber, AccessModel, SendLast, + PresenceSubscription, RosterGroup, Options). + +unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> + case node_hometree_odbc:unsubscribe_node(NodeId, Sender, Subscriber, SubID) of + {error, Error} -> {error, Error}; + {result, _} -> {result, []} + end. + +publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) -> + node_hometree_odbc:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload). + +remove_extra_items(NodeId, MaxItems, ItemIds) -> + node_hometree_odbc:remove_extra_items(NodeId, MaxItems, ItemIds). + +delete_item(NodeId, Publisher, PublishModel, ItemId) -> + node_hometree_odbc:delete_item(NodeId, Publisher, PublishModel, ItemId). + +purge_node(NodeId, Owner) -> + node_hometree_odbc:purge_node(NodeId, Owner). + +get_entity_affiliations(_Host, Owner) -> + OwnerKey = jlib:short_prepd_bare_jid(Owner), + node_hometree_odbc:get_entity_affiliations(OwnerKey, Owner). + +get_node_affiliations(NodeId) -> + node_hometree_odbc:get_node_affiliations(NodeId). + +get_affiliation(NodeId, Owner) -> + node_hometree_odbc:get_affiliation(NodeId, Owner). + +set_affiliation(NodeId, Owner, Affiliation) -> + node_hometree_odbc:set_affiliation(NodeId, Owner, Affiliation). + +get_entity_subscriptions(_Host, Owner) -> + SubKey = jlib:short_prepd_jid(Owner), + GenKey = jlib:short_prepd_bare_jid(SubKey), + Host = ?PUBSUB:escape(element(2, SubKey)), + SJ = node_hometree_odbc:encode_jid(SubKey), + GJ = node_hometree_odbc:encode_jid(GenKey), + Query = case SubKey of + GenKey -> + ["select host, node, type, i.nodeid, jid, subscription " + "from pubsub_state i, pubsub_node n " + "where i.nodeid = n.nodeid " + "and jid like '", GJ, "%' " + "and host like '%@", Host, "';"]; + _ -> + ["select host, node, type, i.nodeid, jid, subscription " + "from pubsub_state i, pubsub_node n " + "where i.nodeid = n.nodeid " + "and jid in ('", SJ, "', '", GJ, "') " + "and host like '%@", Host, "';"] + end, + Reply = case catch ejabberd_odbc:sql_query_t(Query) of + {selected, ["host", "node", "type", "nodeid", "jid", "subscription"], RItems} -> + lists:map(fun({H, N, T, I, J, S}) -> + O = node_hometree_odbc:decode_jid(H), + Node = nodetree_odbc:raw_to_node(O, {N, "", T, I}), + {Node, node_hometree_odbc:decode_subscription(S), node_hometree_odbc:decode_jid(J)} + end, RItems); + _ -> + [] + end, + {result, Reply}. +get_entity_subscriptions_for_send_last(_Host, Owner) -> + SubKey = jlib:short_prepd_jid(Owner), + GenKey = jlib:short_prepd_bare_jid(SubKey), + Host = ?PUBSUB:escape(element(2, SubKey)), + SJ = node_hometree_odbc:encode_jid(SubKey), + GJ = node_hometree_odbc:encode_jid(GenKey), + Query = case SubKey of + GenKey -> + ["select host, node, type, i.nodeid, jid, subscription " + "from pubsub_state i, pubsub_node n, pubsub_node_option o " + "where i.nodeid = n.nodeid and n.nodeid = o.nodeid " + "and name='send_last_published_item' and val='on_sub_and_presence' " + "and jid like '", GJ, "%' " + "and host like '%@", Host, "';"]; + _ -> + ["select host, node, type, i.nodeid, jid, subscription " + "from pubsub_state i, pubsub_node n, pubsub_node_option o " + "where i.nodeid = n.nodeid and n.nodeid = o.nodeid " + "and name='send_last_published_item' and val='on_sub_and_presence' " + "and jid in ('", SJ, "', '", GJ, "') " + "and host like '%@", Host, "';"] + end, + Reply = case catch ejabberd_odbc:sql_query_t(Query) of + {selected, ["host", "node", "type", "nodeid", "jid", "subscription"], RItems} -> + lists:map(fun({H, N, T, I, J, S}) -> + O = node_hometree_odbc:decode_jid(H), + Node = nodetree_odbc:raw_to_node(O, {N, "", T, I}), + {Node, node_hometree_odbc:decode_subscription(S), node_hometree_odbc:decode_jid(J)} + end, RItems); + _ -> + [] + end, + {result, Reply}. + + +get_node_subscriptions(NodeId) -> + %% note: get_node_subscriptions is used for broadcasting + %% there should not have any subscriptions + %% but that call returns also all subscription to none + %% and this is required for broadcast to occurs + %% DO NOT REMOVE + node_hometree_odbc:get_node_subscriptions(NodeId). + +get_subscriptions(NodeId, Owner) -> + node_hometree_odbc:get_subscriptions(NodeId, Owner). + +set_subscriptions(NodeId, Owner, Subscription, SubId) -> + node_hometree_odbc:set_subscriptions(NodeId, Owner, Subscription, SubId). + +get_pending_nodes(Host, Owner) -> + node_hometree_odbc:get_pending_nodes(Host, Owner). + +get_states(NodeId) -> + node_hometree_odbc:get_states(NodeId). + +get_state(NodeId, JID) -> + node_hometree_odbc:get_state(NodeId, JID). + +set_state(State) -> + node_hometree_odbc:set_state(State). + +get_items(NodeId, From) -> + node_hometree_odbc:get_items(NodeId, From). +get_items(NodeId, From, RSM) -> + node_hometree_odbc:get_items(NodeId, From, RSM). +get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, none). +get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM) -> + node_hometree_odbc:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId, RSM). + +get_last_items(NodeId, JID, Count) -> + node_hometree_odbc:get_last_items(NodeId, JID, Count). + +get_item(NodeId, ItemId) -> + node_hometree_odbc:get_item(NodeId, ItemId). + +get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) -> + node_hometree_odbc:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId). + +set_item(Item) -> + node_hometree_odbc:set_item(Item). + +get_item_name(Host, Node, Id) -> + node_hometree_odbc:get_item_name(Host, Node, Id). + + +%%% +%%% Internal +%%% + +%% @doc Check mod_caps is enabled, otherwise show warning. +%% The PEP plugin for mod_pubsub requires mod_caps to be enabled in the host. +%% Check that the mod_caps module is enabled in that Jabber Host +%% If not, show a warning message in the ejabberd log file. +complain_if_modcaps_disabled(ServerHost) -> + Modules = ejabberd_config:get_local_option({modules, ServerHost}), + ModCaps = [mod_caps_enabled || {mod_caps, _Opts} <- Modules], + case ModCaps of + [] -> + ?WARNING_MSG("The PEP plugin is enabled in mod_pubsub of host ~p. " + "This plugin requires mod_caps to be enabled, " + "but it isn't.", [ServerHost]); + _ -> + ok + end. diff --git a/src/mod_pubsub/nodetree_tree_odbc.erl b/src/mod_pubsub/nodetree_tree_odbc.erl new file mode 100644 index 000000000..afd934e31 --- /dev/null +++ b/src/mod_pubsub/nodetree_tree_odbc.erl @@ -0,0 +1,357 @@ +%%% ==================================================================== +%%% ``The contents of this file are subject to the Erlang Public License, +%%% Version 1.1, (the "License"); you may not use this file except in +%%% compliance with the License. You should have received a copy of the +%%% Erlang Public License along with this software. If not, it can be +%%% retrieved via the world wide web at http://www.erlang.org/. +%%% +%%% Software distributed under the License is distributed on an "AS IS" +%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%%% the License for the specific language governing rights and limitations +%%% under the License. +%%% +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne +%%% All Rights Reserved.'' +%%% This software is copyright 2006-2009, ProcessOne. +%%% +%%% +%%% @copyright 2006-2009 ProcessOne +%%% @author Christophe Romain +%%% [http://www.process-one.net/] +%%% @version {@vsn}, {@date} {@time} +%%% @end +%%% ==================================================================== + +%%% @doc The module {@module} is the default PubSub node tree plugin. +%%%

    It is used as a default for all unknown PubSub node type. It can serve +%%% as a developer basis and reference to build its own custom pubsub node tree +%%% types.

    +%%%

    PubSub node tree plugins are using the {@link gen_nodetree} behaviour.

    +%%%

    The API isn't stabilized yet. The pubsub plugin +%%% development is still a work in progress. However, the system is already +%%% useable and useful as is. Please, send us comments, feedback and +%%% improvements.

    + +-module(nodetree_tree_odbc). +-author('christophe.romain@process-one.net'). + +-include_lib("stdlib/include/qlc.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). + +-include("pubsub.hrl"). + +-define(PUBSUB, mod_pubsub_odbc). +-define(PLUGIN_PREFIX, "node_"). + +-behaviour(gen_pubsub_nodetree). + +-export([init/3, + terminate/2, + options/0, + set_node/1, + get_node/3, + get_node/2, + get_node/1, + get_nodes/2, + get_nodes/1, + get_parentnodes/3, + get_parentnodes_tree/3, + get_subnodes/3, + get_subnodes_tree/3, + create_node/5, + delete_node/2 + ]). + +-export([raw_to_node/2]). + +%% ================ +%% API definition +%% ================ + +%% @spec (Host, ServerHost, Opts) -> any() +%% Host = mod_pubsub:host() +%% ServerHost = host() +%% Opts = list() +%% @doc

    Called during pubsub modules initialisation. Any pubsub plugin must +%% implement this function. It can return anything.

    +%%

    This function is mainly used to trigger the setup task necessary for the +%% plugin. It can be used for example by the developer to create the specific +%% module database schema if it does not exists yet.

    +init(_Host, _ServerHost, _Opts) -> + ok. +terminate(_Host, _ServerHost) -> + ok. + +%% @spec () -> [Option] +%% Option = mod_pubsub:nodetreeOption() +%% @doc Returns the default pubsub node tree options. +options() -> + [{virtual_tree, false}, + {odbc, true}]. + + +%% @spec (Host, Node) -> pubsubNode() | {error, Reason} +%% Host = mod_pubsub:host() +%% Node = mod_pubsub:pubsubNode() +get_node(Host, Node, _From) -> + get_node(Host, Node). +get_node(Host, Node) -> + H = ?PUBSUB:escape(Host), + N = ?PUBSUB:escape(?PUBSUB:node_to_string(Node)), + case catch ejabberd_odbc:sql_query_t( + ["select node, parent, type, nodeid " + "from pubsub_node " + "where host='", H, "' and node='", N, "';"]) + of + {selected, ["node", "parent", "type", "nodeid"], [RItem]} -> + raw_to_node(Host, RItem); + {'EXIT', _Reason} -> + {error, 'internal_server_error'}; + _ -> + {error, 'item_not_found'} + end. +get_node(NodeId) -> + case catch ejabberd_odbc:sql_query_t( + ["select host, node, parent, type " + "from pubsub_node " + "where nodeid='", NodeId, "';"]) + of + {selected, ["host", "node", "parent", "type"], [{Host, Node, Parent, Type}]} -> + raw_to_node(Host, {Node, Parent, Type, NodeId}); + {'EXIT', _Reason} -> + {error, 'internal_server_error'}; + _ -> + {error, 'item_not_found'} + end. + +%% @spec (Host) -> [pubsubNode()] | {error, Reason} +%% Host = mod_pubsub:host() | mod_pubsub:jid() +get_nodes(Host, _From) -> + get_nodes(Host). +get_nodes(Host) -> + H = ?PUBSUB:escape(Host), + case catch ejabberd_odbc:sql_query_t( + ["select node, parent, type, nodeid " + "from pubsub_node " + "where host='", H, "';"]) + of + {selected, ["node", "parent", "type", "nodeid"], RItems} -> + lists:map(fun(Item) -> raw_to_node(Host, Item) end, RItems); + _ -> + [] + end. + +%% @spec (Host, Node, From) -> [{Depth, Record}] | {error, Reason} +%% Host = mod_pubsub:host() | mod_pubsub:jid() +%% Node = mod_pubsub:pubsubNode() +%% From = mod_pubsub:jid() +%% Depth = integer() +%% Record = pubsubNode() +%% @doc

    Default node tree does not handle parents, return empty list.

    +get_parentnodes(_Host, _Node, _From) -> + []. + +%% @spec (Host, Node, From) -> [{Depth, Record}] | {error, Reason} +%% Host = mod_pubsub:host() | mod_pubsub:jid() +%% Node = mod_pubsub:pubsubNode() +%% From = mod_pubsub:jid() +%% Depth = integer() +%% Record = pubsubNode() +%% @doc

    Default node tree does not handle parents, return a list +%% containing just this node.

    +get_parentnodes_tree(Host, Node, From) -> + case get_node(Host, Node, From) of + N when is_record(N, pubsub_node) -> [{0, [N]}]; + Error -> Error + end. + +get_subnodes(Host, Node, _From) -> + get_subnodes(Host, Node). +get_subnodes(Host, Node) -> + H = ?PUBSUB:escape(Host), + N = ?PUBSUB:escape(?PUBSUB:node_to_string(Node)), + case catch ejabberd_odbc:sql_query_t( + ["select node, parent, type, nodeid " + "from pubsub_node " + "where host='", H, "' and parent='", N, "';"]) + of + {selected, ["node", "parent", "type", "nodeid"], RItems} -> + lists:map(fun(Item) -> raw_to_node(Host, Item) end, RItems); + _ -> + [] + end. + +%% @spec (Host, Index) -> [pubsubNodeIdx()] | {error, Reason} +%% Host = mod_pubsub:host() +%% Node = mod_pubsub:pubsubNode() +%% From = mod_pubsub:jid() +get_subnodes_tree(Host, Node, _From) -> + get_subnodes_tree(Host, Node). +get_subnodes_tree(Host, Node) -> + H = ?PUBSUB:escape(Host), + N = ?PUBSUB:escape(?PUBSUB:node_to_string(Node)), + case catch ejabberd_odbc:sql_query_t( + ["select node, parent, type, nodeid " + "from pubsub_node " + "where host='", H, "' and node like '", N, "%';"]) + of + {selected, ["node", "parent", "type", "nodeid"], RItems} -> + lists:map(fun(Item) -> raw_to_node(Host, Item) end, RItems); + _ -> + [] + end. + +%% @spec (Host, Node, Type, Owner, Options) -> ok | {error, Reason} +%% Host = mod_pubsub:host() | mod_pubsub:jid() +%% Node = mod_pubsub:pubsubNode() +%% NodeType = mod_pubsub:nodeType() +%% Owner = mod_pubsub:jid() +%% Options = list() +create_node(Host, Node, Type, _Owner, Options) -> + case nodeid(Host, Node) of + {error, 'item_not_found'} -> + {ParentNode, ParentExists} = case Host of + {_U, _S, _R} -> + %% This is special case for PEP handling + %% PEP does not uses hierarchy + {[], true}; + _ -> + case lists:sublist(Node, length(Node) - 1) of + [] -> + {[], true}; + Parent -> + case nodeid(Host, Parent) of + {result, _} -> {Parent, true}; + _ -> {Parent, false} + end + end + end, + case ParentExists of + true -> + case set_node(#pubsub_node{ + nodeid={Host, Node}, + parents=[ParentNode], + type=Type, + options=Options}) of + {result, NodeId} -> {ok, NodeId}; + Other -> Other + end; + false -> + %% Requesting entity is prohibited from creating nodes + {error, 'forbidden'} + end; + {result, _} -> + %% NodeID already exists + {error, 'conflict'}; + Error -> + Error + end. + + +%% @spec (Host, Node) -> [mod_pubsub:node()] +%% Host = mod_pubsub:host() | mod_pubsub:jid() +%% Node = mod_pubsub:pubsubNode() +delete_node(Host, Node) -> + H = ?PUBSUB:escape(Host), + N = ?PUBSUB:escape(?PUBSUB:node_to_string(Node)), + Removed = get_subnodes_tree(Host, Node), + catch ejabberd_odbc:sql_query_t( + ["delete from pubsub_node " + "where host='", H, "' and node like '", N, "%';"]), + Removed. + + +%% helpers + +raw_to_node(Host, {Node, Parent, Type, NodeId}) -> + Options = case catch ejabberd_odbc:sql_query_t( + ["select name,val " + "from pubsub_node_option " + "where nodeid='", NodeId, "';"]) + of + {selected, ["name", "val"], ROptions} -> + DbOpts = lists:map(fun({Key, Value}) -> + RKey = list_to_atom(Key), + Tokens = element(2, erl_scan:string(Value++".")), + RValue = element(2, erl_parse:parse_term(Tokens)), + {RKey, RValue} + end, ROptions), + Module = list_to_atom(?PLUGIN_PREFIX++Type), + StdOpts = Module:options(), + lists:foldl(fun({Key, Value}, Acc)-> + lists:keyreplace(Key, 1, Acc, {Key, Value}) + end, StdOpts, DbOpts); + _ -> + [] + end, + #pubsub_node{ + nodeid = {Host, string_to_node(Host, Node)}, + parents = [string_to_node(Host, Parent)], + id = NodeId, + type = Type, + options = Options}. + +%% @spec (NodeRecord) -> ok | {error, Reason} +%% Record = mod_pubsub:pubsub_node() +set_node(Record) -> + {Host, Node} = Record#pubsub_node.nodeid, + [Parent] = Record#pubsub_node.parents, + Type = Record#pubsub_node.type, + H = ?PUBSUB:escape(Host), + N = ?PUBSUB:escape(?PUBSUB:node_to_string(Node)), + P = ?PUBSUB:escape(?PUBSUB:node_to_string(Parent)), + NodeId = case nodeid(Host, Node) of + {result, OldNodeId} -> + catch ejabberd_odbc:sql_query_t( + ["delete from pubsub_node_option " + "where nodeid='", OldNodeId, "';"]), + catch ejabberd_odbc:sql_query_t( + ["update pubsub_node " + "set host='", H, "' " + "node='", N, "' " + "parent='", P, "' " + "type='", Type, "' " + "where nodeid='", OldNodeId, "';"]), + OldNodeId; + _ -> + catch ejabberd_odbc:sql_query_t( + ["insert into pubsub_node(host, node, parent, type) " + "values('", H, "', '", N, "', '", P, "', '", Type, "');"]), + case nodeid(Host, Node) of + {result, NewNodeId} -> NewNodeId; + _ -> none % this should not happen + end + end, + case NodeId of + none -> + {error, 'internal_server_error'}; + _ -> + lists:foreach(fun({Key, Value}) -> + SKey = atom_to_list(Key), + SValue = ?PUBSUB:escape(lists:flatten(io_lib:fwrite("~p",[Value]))), + catch ejabberd_odbc:sql_query_t( + ["insert into pubsub_node_option(nodeid, name, val) " + "values('", NodeId, "', '", SKey, "', '", SValue, "');"]) + end, Record#pubsub_node.options), + {result, NodeId} + end. + +nodeid(Host, Node) -> + H = ?PUBSUB:escape(Host), + N = ?PUBSUB:escape(?PUBSUB:node_to_string(Node)), + case catch ejabberd_odbc:sql_query_t( + ["select nodeid " + "from pubsub_node " + "where host='", H, "' and node='", N, "';"]) + of + {selected, ["nodeid"], [{NodeId}]} -> + {result, NodeId}; + {'EXIT', _Reason} -> + {error, 'internal_server_error'}; + _ -> + {error, 'item_not_found'} + end. + +string_to_node({_, _, _}, Node) -> Node; +string_to_node(_, Node) -> ?PUBSUB:string_to_node(Node). diff --git a/src/mod_pubsub/pubsub_db_odbc.erl b/src/mod_pubsub/pubsub_db_odbc.erl new file mode 100644 index 000000000..f8afb4361 --- /dev/null +++ b/src/mod_pubsub/pubsub_db_odbc.erl @@ -0,0 +1,138 @@ +%%% ==================================================================== +%%% ``The contents of this file are subject to the Erlang Public License, +%%% Version 1.1, (the "License"); you may not use this file except in +%%% compliance with the License. You should have received a copy of the +%%% Erlang Public License along with this software. If not, it can be +%%% retrieved via the world wide web at http://www.erlang.org/. +%%% +%%% Software distributed under the License is distributed on an "AS IS" +%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%%% the License for the specific language governing rights and limitations +%%% under the License. +%%% +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne +%%% All Rights Reserved.'' +%%% This software is copyright 2006-2009, ProcessOne. +%%% +%%% @author Pablo Polvorin +%%% @version {@vsn}, {@date} {@time} +%%% @end +%%% ==================================================================== +-module(pubsub_db_odbc). +-author("pablo.polvorin@process-one.net"). + +-include("pubsub.hrl"). + +-export([add_subscription/1, + read_subscription/1, + delete_subscription/1, + update_subscription/1]). + + +%% Those -spec lines produce errors in old Erlang versions. +%% They can be enabled again in ejabberd 3.0 because it uses R12B or higher. +-spec read_subscription(SubID :: string()) -> {ok, #pubsub_subscription{}} | notfound. +read_subscription(SubID) -> + case ejabberd_odbc:sql_query_t( + ["select opt_name, opt_value " + "from pubsub_subscription_opt " + "where subid = '", ejabberd_odbc:escape(SubID), "'"]) of + {selected, ["opt_name", "opt_value"], []} -> + notfound; + + {selected, ["opt_name", "opt_value"], Options} -> + + {ok, #pubsub_subscription{subid = SubID, + options = lists:map(fun subscription_opt_from_odbc/1, Options)}} + end. + + + +-spec delete_subscription(SubID :: string()) -> ok. +delete_subscription(SubID) -> + ejabberd_odbc:sql_query_t(["delete from pubsub_subscription_opt " + "where subid = '", ejabberd_odbc:escape(SubID), "'"]), + ok. + + +-spec update_subscription(#pubsub_subscription{}) -> ok . +update_subscription(#pubsub_subscription{subid = SubId} = Sub) -> + delete_subscription(SubId), + add_subscription(Sub). + +-spec add_subscription(#pubsub_subscription{}) -> ok. +add_subscription(#pubsub_subscription{subid = SubId, options = Opts}) -> + EscapedSubId = ejabberd_odbc:escape(SubId), + lists:foreach(fun(Opt) -> + {OdbcOptName, OdbcOptValue} = subscription_opt_to_odbc(Opt), + ejabberd_odbc:sql_query_t( + ["insert into pubsub_subscription_opt(subid, opt_name, opt_value)" + "values ('", EscapedSubId, "','", OdbcOptName, "','", OdbcOptValue, "')"]) + end, Opts), + ok. + + + +%% -------------- Internal utilities ----------------------- +subscription_opt_from_odbc({"DELIVER", Value}) -> + {deliver, odbc_to_boolean(Value)}; +subscription_opt_from_odbc({"DIGEST", Value}) -> + {digest, odbc_to_boolean(Value)}; +subscription_opt_from_odbc({"DIGEST_FREQUENCY", Value}) -> + {digest_frequency, odbc_to_integer(Value)}; +subscription_opt_from_odbc({"EXPIRE", Value}) -> + {expire, odbc_to_timestamp(Value)}; +subscription_opt_from_odbc({"INCLUDE_BODY", Value}) -> + {include_body, odbc_to_boolean(Value)}; + +%%TODO: might be > than 1 show_values value??. +%% need to use compact all in only 1 opt. +subscription_opt_from_odbc({"SHOW_VALUES", Value}) -> + {show_values, Value}; +subscription_opt_from_odbc({"SUBSCRIPTION_TYPE", Value}) -> + {subscription_type, case Value of + "items" -> items; + "nodes" -> nodes + end}; + +subscription_opt_from_odbc({"SUBSCRIPTION_DEPTH", Value}) -> + {subscription_depth, case Value of + "all" -> all; + N -> odbc_to_integer(N) + end}. + +subscription_opt_to_odbc({deliver, Bool}) -> + {"DELIVER", boolean_to_odbc(Bool)}; +subscription_opt_to_odbc({digest, Bool}) -> + {"DIGEST", boolean_to_odbc(Bool)}; +subscription_opt_to_odbc({digest_frequency, Int}) -> + {"DIGEST_FREQUENCY", integer_to_odbc(Int)}; +subscription_opt_to_odbc({expire, Timestamp}) -> + {"EXPIRE", timestamp_to_odbc(Timestamp)}; +subscription_opt_to_odbc({include_body, Bool}) -> + {"INCLUDE_BODY", boolean_to_odbc(Bool)}; +subscription_opt_to_odbc({show_values, Values}) -> + {"SHOW_VALUES", Values}; +subscription_opt_to_odbc({subscription_type, Type}) -> + {"SUBSCRIPTION_TYPE", case Type of + items -> "items"; + nodes -> "nodes" + end}; +subscription_opt_to_odbc({subscription_depth, Depth}) -> + {"SUBSCRIPTION_DEPTH", case Depth of + all -> "all"; + N -> integer_to_odbc(N) + end}. + +integer_to_odbc(N) -> + integer_to_list(N). + +boolean_to_odbc(true) -> "1"; +boolean_to_odbc(false) -> "0". +timestamp_to_odbc(T) -> jlib:now_to_utc_string(T). + + +odbc_to_integer(N) -> list_to_integer(N). +odbc_to_boolean(B) -> B == "1". +odbc_to_timestamp(T) -> jlib:datetime_string_to_timestamp(T). diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch new file mode 100644 index 000000000..d87dc2c57 --- /dev/null +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -0,0 +1,672 @@ +--- mod_pubsub.erl 2009-08-25 17:29:57.000000000 -0300 ++++ mod_pubsub_odbc.erl 2009-08-26 12:07:05.000000000 -0300 +@@ -45,7 +45,7 @@ + %%% TODO + %%% plugin: generate Reply (do not use broadcast atom anymore) + +--module(mod_pubsub). ++-module(mod_pubsub_odbc). + -author('christophe.romain@process-one.net'). + -version('1.12-06'). + +@@ -58,9 +58,9 @@ + -include("adhoc.hrl"). + -include("pubsub.hrl"). + +--define(STDTREE, "tree"). +--define(STDNODE, "flat"). +--define(PEPNODE, "pep"). ++-define(STDTREE, "tree_odbc"). ++-define(STDNODE, "flat_odbc"). ++-define(PEPNODE, "pep_odbc"). + + %% exports for hooks + -export([presence_probe/3, +@@ -105,7 +105,8 @@ + string_to_subscription/1, + string_to_affiliation/1, + extended_error/2, +- extended_error/3 ++ extended_error/3, ++ escape/1 + ]). + + %% API and gen_server callbacks +@@ -124,7 +125,7 @@ + -export([send_loop/1 + ]). + +--define(PROCNAME, ejabberd_mod_pubsub). ++-define(PROCNAME, ejabberd_mod_pubsub_odbc). + -define(PLUGIN_PREFIX, "node_"). + -define(TREE_PREFIX, "nodetree_"). + +@@ -221,8 +222,6 @@ + ok + end, + ejabberd_router:register_route(Host), +- update_node_database(Host, ServerHost), +- update_state_database(Host, ServerHost), + init_nodes(Host, ServerHost), + State = #state{host = Host, + server_host = ServerHost, +@@ -277,177 +276,7 @@ + create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), "hometree"), + ok. + +-update_node_database(Host, ServerHost) -> +- mnesia:del_table_index(pubsub_node, type), +- mnesia:del_table_index(pubsub_node, parentid), +- case catch mnesia:table_info(pubsub_node, attributes) of +- [host_node, host_parent, info] -> +- ?INFO_MSG("upgrade node pubsub tables",[]), +- F = fun() -> +- {Result, LastIdx} = lists:foldl( +- fun({pubsub_node, NodeId, ParentId, {nodeinfo, Items, Options, Entities}}, {RecList, NodeIdx}) -> +- ItemsList = +- lists:foldl( +- fun({item, IID, Publisher, Payload}, Acc) -> +- C = {unknown, Publisher}, +- M = {now(), Publisher}, +- mnesia:write( +- #pubsub_item{itemid = {IID, NodeIdx}, +- creation = C, +- modification = M, +- payload = Payload}), +- [{Publisher, IID} | Acc] +- end, [], Items), +- Owners = +- dict:fold( +- fun(JID, {entity, Aff, Sub}, Acc) -> +- UsrItems = +- lists:foldl( +- fun({P, I}, IAcc) -> +- case P of +- JID -> [I | IAcc]; +- _ -> IAcc +- end +- end, [], ItemsList), +- mnesia:write({pubsub_state, +- {JID, NodeIdx}, +- UsrItems, +- Aff, +- Sub}), +- case Aff of +- owner -> [JID | Acc]; +- _ -> Acc +- end +- end, [], Entities), +- mnesia:delete({pubsub_node, NodeId}), +- {[#pubsub_node{nodeid = NodeId, +- id = NodeIdx, +- parents = [element(2, ParentId)], +- owners = Owners, +- options = Options} | +- RecList], NodeIdx + 1} +- end, {[], 1}, +- mnesia:match_object( +- {pubsub_node, {Host, '_'}, '_', '_'})), +- mnesia:write(#pubsub_index{index = node, last = LastIdx, free = []}), +- Result +- end, +- {atomic, NewRecords} = mnesia:transaction(F), +- {atomic, ok} = mnesia:delete_table(pubsub_node), +- {atomic, ok} = mnesia:create_table(pubsub_node, +- [{disc_copies, [node()]}, +- {attributes, record_info(fields, pubsub_node)}]), +- FNew = fun() -> lists:foreach(fun(Record) -> +- mnesia:write(Record) +- end, NewRecords) +- end, +- case mnesia:transaction(FNew) of +- {atomic, Result} -> +- ?INFO_MSG("Pubsub node tables updated correctly: ~p", [Result]); +- {aborted, Reason} -> +- ?ERROR_MSG("Problem updating Pubsub node tables:~n~p", [Reason]) +- end; +- [nodeid, parentid, type, owners, options] -> +- F = fun({pubsub_node, NodeId, {_, Parent}, Type, Owners, Options}) -> +- #pubsub_node{ +- nodeid = NodeId, +- id = 0, +- parents = [Parent], +- type = Type, +- owners = Owners, +- options = Options} +- end, +- mnesia:transform_table(pubsub_node, F, [nodeid, id, parents, type, owners, options]), +- FNew = fun() -> +- LastIdx = lists:foldl(fun(#pubsub_node{nodeid = NodeId} = PubsubNode, NodeIdx) -> +- mnesia:write(PubsubNode#pubsub_node{id = NodeIdx}), +- lists:foreach(fun(#pubsub_state{stateid = StateId} = State) -> +- {JID, _} = StateId, +- mnesia:delete({pubsub_state, StateId}), +- mnesia:write(State#pubsub_state{stateid = {JID, NodeIdx}}) +- end, mnesia:match_object(#pubsub_state{stateid = {'_', NodeId}, _ = '_'})), +- lists:foreach(fun(#pubsub_item{itemid = ItemId} = Item) -> +- {IID, _} = ItemId, +- {M1, M2} = Item#pubsub_item.modification, +- {C1, C2} = Item#pubsub_item.creation, +- mnesia:delete({pubsub_item, ItemId}), +- mnesia:write(Item#pubsub_item{itemid = {IID, NodeIdx}, +- modification = {M2, M1}, +- creation = {C2, C1}}) +- end, mnesia:match_object(#pubsub_item{itemid = {'_', NodeId}, _ = '_'})), +- NodeIdx + 1 +- end, 1, mnesia:match_object( +- {pubsub_node, {Host, '_'}, '_', '_', '_', '_', '_'}) +- ++ mnesia:match_object( +- {pubsub_node, {{'_', ServerHost, '_'}, '_'}, '_', '_', '_', '_', '_'})), +- mnesia:write(#pubsub_index{index = node, last = LastIdx, free = []}) +- end, +- case mnesia:transaction(FNew) of +- {atomic, Result} -> +- rename_default_nodeplugin(), +- ?INFO_MSG("Pubsub node tables updated correctly: ~p", [Result]); +- {aborted, Reason} -> +- ?ERROR_MSG("Problem updating Pubsub node tables:~n~p", [Reason]) +- end; +- [nodeid, id, parent, type, owners, options] -> +- F = fun({pubsub_node, NodeId, Id, Parent, Type, Owners, Options}) -> +- #pubsub_node{ +- nodeid = NodeId, +- id = Id, +- parents = [Parent], +- type = Type, +- owners = Owners, +- options = Options} +- end, +- mnesia:transform_table(pubsub_node, F, [nodeid, id, parents, type, owners, options]), +- rename_default_nodeplugin(); +- _ -> +- ok +- end. + +-rename_default_nodeplugin() -> +- lists:foreach(fun(Node) -> +- mnesia:dirty_write(Node#pubsub_node{type = "hometree"}) +- end, mnesia:dirty_match_object(#pubsub_node{type = "default", _ = '_'})). +- +-update_state_database(_Host, _ServerHost) -> +- case catch mnesia:table_info(pubsub_state, attributes) of +- [stateid, items, affiliation, subscription] -> +- ?INFO_MSG("upgrade state pubsub tables", []), +- F = fun ({pubsub_state, {JID, NodeID}, Items, Aff, Sub}, Acc) -> +- Subs = case Sub of +- none -> +- []; +- _ -> +- {result, SubID} = pubsub_subscription:subscribe_node(JID, NodeID, []), +- [{Sub, SubID}] +- end, +- NewState = #pubsub_state{stateid = {JID, NodeID}, +- items = Items, +- affiliation = Aff, +- subscriptions = Subs}, +- [NewState | Acc] +- end, +- {atomic, NewRecs} = mnesia:transaction(fun mnesia:foldl/3, +- [F, [], pubsub_state]), +- {atomic, ok} = mnesia:delete_table(pubsub_state), +- {atomic, ok} = mnesia:create_table(pubsub_state, +- [{disc_copies, [node()]}, +- {attributes, record_info(fields, pubsub_state)}]), +- FNew = fun () -> +- lists:foreach(fun mnesia:write/1, NewRecs) +- end, +- case mnesia:transaction(FNew) of +- {atomic, Result} -> +- ?INFO_MSG("Pubsub state tables updated correctly: ~p", +- [Result]); +- {aborted, Reason} -> +- ?ERROR_MSG("Problem updating Pubsub state tables:~n~p", +- [Reason]) +- end; +- _ -> +- ok +- end. + + send_queue(State, Msg) -> + Pid = State#state.send_loop, +@@ -471,17 +300,15 @@ + %% for each node From is subscribed to + %% and if the node is so configured, send the last published item to From + lists:foreach(fun(PType) -> +- {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, JID]), ++ Subscriptions = case catch node_action(Host, PType, get_entity_subscriptions_for_send_last, [Host, JID]) of ++ {result, S} -> S; ++ _ -> [] ++ end, + lists:foreach( + fun({Node, subscribed, _, SubJID}) -> + if (SubJID == LJID) or (SubJID == BJID) -> +- #pubsub_node{options = Options, type = Type, id = NodeId} = Node, +- case get_option(Options, send_last_published_item) of +- on_sub_and_presence -> +- send_items(Host, Node, NodeId, Type, SubJID, last); +- _ -> +- ok +- end; ++ #pubsub_node{nodeid = {H, N}, type = Type, id = NodeId} = Node, ++ send_items(H, N, NodeId, Type, SubJID, last); + true -> + % resource not concerned about that subscription + ok +@@ -808,10 +635,10 @@ + {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), + lists:foreach(fun + ({Node, subscribed, _, JID}) -> +- #pubsub_node{options = Options, owners = Owners, type = Type, id = NodeId} = Node, ++ #pubsub_node{options = Options, type = Type, id = NodeId} = Node, + case get_option(Options, access_model) of + presence -> +- case lists:member(BJID, Owners) of ++ case lists:member(BJID, node_owners(Host, Type, NodeId)) of + true -> + node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); + false -> +@@ -929,11 +756,12 @@ + end, + ejabberd_router:route(To, From, Res); + #iq{type = get, ns = ?NS_DISCO_ITEMS, +- payload = SubEl} -> ++ payload = SubEl} = IQ -> + QAttrs = SubEl#xmlel.attrs, + Node = exmpp_xml:get_attribute_from_list_as_list(QAttrs, + 'node', ""), +- Res = case iq_disco_items(Host, Node, From) of ++ Rsm = jlib:rsm_decode(IQ), ++ Res = case iq_disco_items(Host, Node, From, Rsm) of + {result, IQRes} -> + Result = #xmlel{ns = ?NS_DISCO_ITEMS, + name = 'query', attrs = QAttrs, +@@ -1036,7 +864,7 @@ + [] -> + ["leaf"]; %% No sub-nodes: it's a leaf node + _ -> +- case node_call(Type, get_items, [NodeId, From]) of ++ case node_call(Type, get_items, [NodeId, From, none]) of + {result, []} -> ["collection"]; + {result, _} -> ["leaf", "collection"]; + _ -> [] +@@ -1052,8 +880,9 @@ + []; + true -> + [#xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]} | +- lists:map(fun(T) -> +- #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s++"#"++T)]} ++ lists:map(fun ++ ("rsm") -> #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_RSM_s)]}; ++ (T) -> #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s++"#"++T)]} + end, features(Type))] + end, + %% TODO: add meta-data info (spec section 5.4) +@@ -1081,14 +910,15 @@ + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_DISCO_ITEMS_s)]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]}, + #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_VCARD_s)]}] ++ +- lists:map(fun(Feature) -> +- #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s++"#"++Feature)]} ++ lists:map(fun ++ ("rsm") -> #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_RSM_s)]}; ++ (Feature) -> #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s++"#"++Feature)]} + end, features(Host, Node))}; + _ -> + node_disco_info(Host, Node, From) + end. + +-iq_disco_items(Host, [], From) -> ++iq_disco_items(Host, [], From, _RSM) -> + {result, lists:map( + fun(#pubsub_node{nodeid = {_, SubNode}}) -> + SN = node_to_string(SubNode), +@@ -1098,7 +928,7 @@ + ?XMLATTR('node', SN), + ?XMLATTR('name', RN)]} + end, tree_action(Host, get_subnodes, [Host, [], From]))}; +-iq_disco_items(Host, Item, From) -> ++iq_disco_items(Host, Item, From, RSM) -> + case string:tokens(Item, "!") of + [_SNode, _ItemID] -> + {result, []}; +@@ -1110,9 +940,9 @@ + %% TODO That is, remove name attribute (or node?, please check for 2.1) + Action = + fun(#pubsub_node{type = Type, id = NodeId}) -> +- NodeItems = case node_call(Type, get_items, [NodeId, From]) of ++ {NodeItems, RsmOut} = case node_call(Type, get_items, [NodeId, From, RSM]) of + {result, I} -> I; +- _ -> [] ++ _ -> {[], none} + end, + Nodes = lists:map( + fun(#pubsub_node{nodeid = {_, SubNode}}) -> +@@ -1128,7 +958,7 @@ + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), + ?XMLATTR('name', Name)]} + end, NodeItems), +- {result, Nodes ++ Items} ++ {result, Nodes ++ Items ++ jlib:rsm_encode(RsmOut)} + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Result}} -> {result, Result}; +@@ -1267,7 +1097,8 @@ + (_, Acc) -> + Acc + end, [], exmpp_xml:remove_cdata_from_list(Els)), +- get_items(Host, Node, From, SubId, MaxItems, ItemIDs); ++ RSM = jlib:rsm_decode(SubEl), ++ get_items(Host, Node, From, SubId, MaxItems, ItemIDs, RSM); + {get, 'subscriptions'} -> + get_subscriptions(Host, Node, From, Plugins); + {get, 'affiliations'} -> +@@ -1289,8 +1120,11 @@ + end. + + iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> +- SubEls = SubEl#xmlel.children, +- Action = exmpp_xml:remove_cdata_from_list(SubEls), ++ SubEls = exmpp_xml:get_child_elements(SubEl), ++ NoRSM = lists:filter(fun(#xmlel{name = Name}) -> ++ Name == 'set' ++ end, SubEls), ++ Action = SubEls -- NoRSM, %%pablo why not doing it once on lists:filter? + case Action of + [#xmlel{name = Name, attrs = Attrs, children = Els}] -> + Node = case Host of +@@ -1420,7 +1254,8 @@ + _ -> [] + end + end, +- case transaction(fun () -> {result, lists:flatmap(Tr, Plugins)} end, ++ case transaction(Host, ++ fun () -> {result, lists:flatmap(Tr, Plugins)} end, + sync_dirty) of + {result, Res} -> Res; + Err -> Err +@@ -1466,7 +1301,7 @@ + + %%% authorization handling + +-send_authorization_request(#pubsub_node{owners = Owners, nodeid = {Host, Node}}, Subscriber) -> ++send_authorization_request(#pubsub_node{nodeid = {Host, Node}, type = Type, id = NodeId}, Subscriber) -> + Lang = "en", %% TODO fix + {U, S, R} = Subscriber, + Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = +@@ -1496,7 +1331,7 @@ + lists:foreach(fun(Owner) -> + {U, S, R} = Owner, + ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza} +- end, Owners). ++ end, node_owners(Host, Type, NodeId)). + + find_authorization_response(Packet) -> + Els = Packet#xmlel.children, +@@ -1559,8 +1394,8 @@ + "true" -> true; + _ -> false + end, +- Action = fun(#pubsub_node{type = Type, owners = Owners, id = NodeId}) -> +- IsApprover = lists:member(jlib:short_prepd_bare_jid(From), Owners), ++ Action = fun(#pubsub_node{type = Type, id = NodeId}) -> ++ IsApprover = lists:member(jlib:short_prepd_bare_jid(From), node_owners_call(Type, NodeId)), + {result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]), + if + not IsApprover -> +@@ -1750,7 +1585,7 @@ + end, + Reply = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(Node)}]}, +- case transaction(CreateNode, transaction) of ++ case transaction(Host, CreateNode, transaction) of + {result, {Result, broadcast}} -> + %%Lang = "en", %% TODO: fix + %%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), +@@ -1866,7 +1701,7 @@ + {undefined, undefined, undefined} + end, + SubId = uniqid(), +- Action = fun(#pubsub_node{options = Options, owners = [Owner|_], type = Type, id = NodeId}) -> ++ Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> + Features = features(Type), + SubscribeFeature = lists:member("subscribe", Features), + OptionsFeature = lists:member("subscription-options", Features), +@@ -1885,9 +1720,13 @@ + {"", "", ""} -> + {false, false}; + _ -> +- {OU, OS, _} = Owner, +- get_roster_info(OU, OS, +- Subscriber, AllowedGroups) ++ case node_owners_call(Type, NodeId) of ++ [{OU, OS, _} | _] -> ++ get_roster_info(OU, OS, ++ Subscriber, AllowedGroups); ++ _ -> ++ {false, false} ++ end + end + end, + if +@@ -2212,7 +2051,7 @@ + %%

    The permission are not checked in this function.

    + %% @todo We probably need to check that the user doing the query has the right + %% to read the items. +-get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> ++get_items(Host, Node, From, SubId, SMaxItems, ItemIDs, RSM) -> + MaxItems = + if + SMaxItems == "" -> ?MAXITEMS; +@@ -2251,11 +2090,11 @@ + node_call(Type, get_items, + [NodeId, From, + AccessModel, PresenceSubscription, RosterGroup, +- SubId]) ++ SubId, RSM]) + end + end, + case transaction(Host, Node, Action, sync_dirty) of +- {result, {_, Items}} -> ++ {result, {_, Items, RSMOut}} -> + SendItems = case ItemIDs of + [] -> + Items; +@@ -2268,7 +2107,7 @@ + %% number of items sent to MaxItems: + {result, #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = + [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = nodeAttr(Node), children = +- itemsEls(lists:sublist(SendItems, MaxItems))}]}}; ++ itemsEls(lists:sublist(SendItems, MaxItems))} | jlib:rsm_encode(RSMOut)]}}; + Error -> + Error + end +@@ -2300,16 +2139,25 @@ + %% @doc

    Resend the items of a node to the user.

    + %% @todo use cache-last-item feature + send_items(Host, Node, NodeId, Type, LJID, last) -> +- case get_cached_item(Host, NodeId) of ++ Stanza = case get_cached_item(Host, NodeId) of + undefined -> +- send_items(Host, Node, NodeId, Type, LJID, 1); ++ % special ODBC optimization, works only with node_hometree_odbc, node_flat_odbc and node_pep_odbc ++ ToSend = case node_action(Host, Type, get_last_items, [NodeId, LJID, 1]) of ++ {result, []} -> []; ++ {result, Items} -> Items ++ end, ++ event_stanza([#xmlel{ns = ?NS_PUBSUB_EVENT, ++ name = 'items', ++ attrs = nodeAttr(Node), ++ children = itemsEls(ToSend)}]); + LastItem -> +- Stanza = event_stanza( ++ event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), +- children = itemsEls(LastItem)}]), +- {U, S, R} = LJID, +- ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza} +- end; ++ children = itemsEls(LastItem)}]) ++ end, ++ {U, S, R} = LJID, ++ ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza}; ++ + send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> + ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of + {result, []} -> +@@ -2430,29 +2278,12 @@ + error -> + {error, 'bad-request'}; + _ -> +- Action = fun(#pubsub_node{owners = Owners, type = Type, id = NodeId}=N) -> +- case lists:member(Owner, Owners) of ++ Action = fun(#pubsub_node{type = Type, id = NodeId}) -> ++ case lists:member(Owner, node_owners_call(Type, NodeId)) of + true -> + lists:foreach( + fun({JID, Affiliation}) -> +- {result, _} = node_call(Type, set_affiliation, [NodeId, JID, Affiliation]), +- case Affiliation of +- owner -> +- NewOwner = jlib:short_prepd_bare_jid(JID), +- NewOwners = [NewOwner|Owners], +- tree_call(Host, set_node, [N#pubsub_node{owners = NewOwners}]); +- none -> +- OldOwner = jlib:short_prepd_bare_jid(JID), +- case lists:member(OldOwner, Owners) of +- true -> +- NewOwners = Owners--[OldOwner], +- tree_call(Host, set_node, [N#pubsub_node{owners = NewOwners}]); +- _ -> +- ok +- end; +- _ -> +- ok +- end ++ node_call(Type, set_affiliation, [NodeId, JID, Affiliation]) + end, Entities), + {result, []}; + _ -> +@@ -2733,8 +2564,8 @@ + + ejabberd_router ! {route, service_jid(Host), JID, Stanza} + end, +- Action = fun(#pubsub_node{owners = Owners, type = Type, id = NodeId}) -> +- case lists:member(Owner, Owners) of ++ Action = fun(#pubsub_node{type = Type, id = NodeId}) -> ++ case lists:member(Owner, node_owners_call(Type, NodeId)) of + true -> + Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> + +@@ -3237,6 +3068,30 @@ + Result + end. + ++%% @spec (NodeId) -> [ljid()] ++%% NodeId = pubsubNodeId() ++%% @doc

    Return list of node owners.

    ++node_owners(Host, Type, NodeId) -> ++ case node_action(Host, Type, get_node_affiliations, [NodeId]) of ++ {result, Affiliations} -> ++ lists:foldl( ++ fun({LJID, owner}, Acc) -> [LJID|Acc]; ++ (_, Acc) -> Acc ++ end, [], Affiliations); ++ _ -> ++ [] ++ end. ++node_owners_call(Type, NodeId) -> ++ case node_call(Type, get_node_affiliations, [NodeId]) of ++ {result, Affiliations} -> ++ lists:foldl( ++ fun({LJID, owner}, Acc) -> [LJID|Acc]; ++ (_, Acc) -> Acc ++ end, [], Affiliations); ++ _ -> ++ [] ++ end. ++ + %% @spec (Host, Options) -> MaxItems + %% Host = host() + %% Options = [Option] +@@ -3613,7 +3468,13 @@ + tree_action(Host, Function, Args) -> + ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), + Fun = fun() -> tree_call(Host, Function, Args) end, +- catch mnesia:sync_dirty(Fun). ++ case catch ejabberd_odbc:sql_bloc(odbc_conn(Host), Fun) of ++ {atomic, Result} -> ++ Result; ++ {aborted, Reason} -> ++ ?ERROR_MSG("transaction return internal error: ~p~n",[{aborted, Reason}]), ++ {error, 'internal-server-error'} ++ end. + + %% @doc

    node plugin call.

    + node_call(Type, Function, Args) -> +@@ -3633,13 +3494,13 @@ + + node_action(Host, Type, Function, Args) -> + ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), +- transaction(fun() -> ++ transaction(Host, fun() -> + node_call(Type, Function, Args) + end, sync_dirty). + + %% @doc

    plugin transaction handling.

    + transaction(Host, Node, Action, Trans) -> +- transaction(fun() -> ++ transaction(Host, fun() -> + case tree_call(Host, get_node, [Host, Node]) of + N when is_record(N, pubsub_node) -> + case Action(N) of +@@ -3652,8 +3513,15 @@ + end + end, Trans). + +-transaction(Fun, Trans) -> +- case catch mnesia:Trans(Fun) of ++transaction(Host, Fun, Trans) -> ++ transaction_retry(Host, Fun, Trans, 2). ++ ++transaction_retry(Host, Fun, Trans, Count) -> ++ SqlFun = case Trans of ++ transaction -> sql_transaction; ++ _ -> sql_bloc ++ end, ++ case catch ejabberd_odbc:SqlFun(odbc_conn(Host), Fun) of + {result, Result} -> {result, Result}; + {error, Error} -> {error, Error}; + {atomic, {result, Result}} -> {result, Result}; +@@ -3661,6 +3529,15 @@ + {aborted, Reason} -> + ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), + {error, 'internal-server-error'}; ++ {'EXIT', {timeout, _} = Reason} -> ++ case Count of ++ 0 -> ++ ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), ++ {error, 'internal-server-error'}; ++ N -> ++ erlang:yield(), ++ transaction_retry(Host, Fun, Trans, N-1) ++ end; + {'EXIT', Reason} -> + ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), + {error, 'internal-server-error'}; +@@ -3669,6 +3546,16 @@ + {error, 'internal-server-error'} + end. + ++odbc_conn({_U, Host, _R})-> ++ Host; ++odbc_conn(Host) -> ++ Host--"pubsub.". %% TODO, improve that for custom host ++ ++%% escape value for database storage ++escape({_U, _H, _R}=JID)-> ++ ejabberd_odbc:escape(exmpp_jid:to_list(JID)); ++escape(Value)-> ++ ejabberd_odbc:escape(Value). + %%%% helpers + + %% Add pubsub-specific error element diff --git a/src/mod_pubsub/pubsub_subscription_odbc.erl b/src/mod_pubsub/pubsub_subscription_odbc.erl new file mode 100644 index 000000000..50a1ad590 --- /dev/null +++ b/src/mod_pubsub/pubsub_subscription_odbc.erl @@ -0,0 +1,294 @@ +%%% ==================================================================== +%%% ``The contents of this file are subject to the Erlang Public License, +%%% Version 1.1, (the "License"); you may not use this file except in +%%% compliance with the License. You should have received a copy of the +%%% Erlang Public License along with this software. If not, it can be +%%% retrieved via the world wide web at http://www.erlang.org/. +%%% +%%% Software distributed under the License is distributed on an "AS IS" +%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%%% the License for the specific language governing rights and limitations +%%% under the License. +%%% +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne +%%% All Rights Reserved.'' +%%% This software is copyright 2006-2009, ProcessOne. +%%% +%%% @author Pablo Polvorin +%%% @author based on pubsub_subscription.erl by Brian Cully +%%% @version {@vsn}, {@date} {@time} +%%% @end +%%% ==================================================================== + +-module(pubsub_subscription_odbc). +-author("pablo.polvorin@process-one.net"). + +%% API +-export([init/0, + subscribe_node/3, + unsubscribe_node/3, + get_subscription/3, + set_subscription/4, + get_options_xform/2, + parse_options_xform/1]). + + +-include_lib("stdlib/include/qlc.hrl"). + +-include("pubsub.hrl"). +-include_lib("exmpp/include/exmpp.hrl"). + +-define(PUBSUB_DELIVER, "pubsub#deliver"). +-define(PUBSUB_DIGEST, "pubsub#digest"). +-define(PUBSUB_DIGEST_FREQUENCY, "pubsub#digest_frequency"). +-define(PUBSUB_EXPIRE, "pubsub#expire"). +-define(PUBSUB_INCLUDE_BODY, "pubsub#include_body"). +-define(PUBSUB_SHOW_VALUES, "pubsub#show-values"). +-define(PUBSUB_SUBSCRIPTION_TYPE, "pubsub#subscription_type"). +-define(PUBSUB_SUBSCRIPTION_DEPTH, "pubsub#subscription_depth"). + +-define(DELIVER_LABEL, + "Whether an entity wants to receive or disable notifications"). +-define(DIGEST_LABEL, + "Whether an entity wants to receive digests (aggregations) of notifications or all notifications individually"). +-define(DIGEST_FREQUENCY_LABEL, + "The minimum number of milliseconds between sending any two notification digests"). +-define(EXPIRE_LABEL, + "The DateTime at which a leased subscription will end or has ended"). +-define(INCLUDE_BODY_LABEL, + "Whether an entity wants to receive an XMPP message body in addition to the payload format"). +-define(SHOW_VALUES_LABEL, + "The presence states for which an entity wants to receive notifications"). +-define(SUBSCRIPTION_TYPE_LABEL, + "Type of notification to receive"). +-define(SUBSCRIPTION_DEPTH_LABEL, + "Depth from subscription for which to receive notifications"). + +-define(SHOW_VALUE_AWAY_LABEL, "XMPP Show Value of Away"). +-define(SHOW_VALUE_CHAT_LABEL, "XMPP Show Value of Chat"). +-define(SHOW_VALUE_DND_LABEL, "XMPP Show Value of DND (Do Not Disturb)"). +-define(SHOW_VALUE_ONLINE_LABEL, "Mere Availability in XMPP (No Show Value)"). +-define(SHOW_VALUE_XA_LABEL, "XMPP Show Value of XA (Extended Away)"). + +-define(SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL, + "Receive notification of new items only"). +-define(SUBSCRIPTION_TYPE_VALUE_NODES_LABEL, + "Receive notification of new nodes only"). + +-define(SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL, + "Receive notification from direct child nodes only"). +-define(SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL, + "Receive notification from all descendent nodes"). + +-define(DB_MOD, pubsub_db_odbc). + +%%==================================================================== +%% API +%%==================================================================== +init() -> + ok = create_table(). + +subscribe_node(_JID, _NodeID, Options) -> + SubId = make_subid(), + ok = ?DB_MOD:add_subscription(#pubsub_subscription{subid = SubId, options = Options}), + {result, SubId}. + +unsubscribe_node(_JID, _NodeID, SubID) -> + {ok, Sub} = ?DB_MOD:read_subscription(SubID), + ok = ?DB_MOD:delete_subscription(SubID), + {result, Sub}. + +get_subscription(_JID, _NodeID, SubID) -> + case ?DB_MOD:read_subscription(SubID) of + {ok, Sub} -> {result, Sub}; + notfound -> {error, notfound} + end. + +set_subscription(_JID, _NodeID, SubID, Options) -> + case ?DB_MOD:read_subscription(SubID) of + {ok, _} -> + ok = ?DB_MOD:update_subscription(#pubsub_subscription{subid = SubID, options = Options}), + {result, ok}; + notfound -> + {error, notfound} + end. + +get_options_xform(Lang, Options) -> + Keys = [deliver, show_values, subscription_type, subscription_depth], + XFields = [get_option_xfield(Lang, Key, Options) || Key <- Keys], + + {result, #xmlel{ns = ?NS_DATA_FORMS, name = 'x', children = + [#xmlel{ns = ?NS_DATA_FORMS, + name = 'field', + attrs = [?XMLATTR('var', <<"FORM_TYPE">>), ?XMLATTR('type', <<"hidden">>)], + children = [#xmlel{ns = ?NS_DATA_FORMS, + name = 'value', + children = [?XMLCDATA(?NS_PUBSUB_SUBSCRIBE_OPTIONS_s)]}]}] ++ XFields}}. + +parse_options_xform(XFields) -> + case exmpp_xml:get_child_elements(XFields) of + [] -> {result, []}; + [#xmlel{name = 'x'} = XEl] -> + case jlib:parse_xdata_submit(XEl) of + XData when is_list(XData) -> + case set_xoption(XData, []) of + Opts when is_list(Opts) -> {result, Opts}; + Other -> Other + end; + Other -> + Other + end; + Other -> + Other + end. + +%%==================================================================== +%% Internal functions +%%==================================================================== +create_table() -> + ok. + +make_subid() -> + {T1, T2, T3} = now(), + lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])). + +%% +%% Subscription XForm processing. +%% + +%% Return processed options, with types converted and so forth, using +%% Opts as defaults. +set_xoption([], Opts) -> + Opts; +set_xoption([{Var, Value} | T], Opts) -> + NewOpts = case var_xfield(Var) of + {error, _} -> + Opts; + Key -> + Val = val_xfield(Key, Value), + lists:keystore(Key, 1, Opts, {Key, Val}) + end, + set_xoption(T, NewOpts). + +%% Return the options list's key for an XForm var. +var_xfield(?PUBSUB_DELIVER) -> deliver; +var_xfield(?PUBSUB_DIGEST) -> digest; +var_xfield(?PUBSUB_DIGEST_FREQUENCY) -> digest_frequency; +var_xfield(?PUBSUB_EXPIRE) -> expire; +var_xfield(?PUBSUB_INCLUDE_BODY) -> include_body; +var_xfield(?PUBSUB_SHOW_VALUES) -> show_values; +var_xfield(?PUBSUB_SUBSCRIPTION_TYPE) -> subscription_type; +var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) -> subscription_depth; +var_xfield(_) -> {error, badarg}. + +%% Convert Values for option list's Key. +val_xfield(deliver, [Val]) -> xopt_to_bool(Val); +val_xfield(digest, [Val]) -> xopt_to_bool(Val); +val_xfield(digest_frequency, [Val]) -> list_to_integer(Val); +val_xfield(expire, [Val]) -> jlib:datetime_string_to_timestamp(Val); +val_xfield(include_body, [Val]) -> xopt_to_bool(Val); +val_xfield(show_values, Vals) -> Vals; +val_xfield(subscription_type, ["items"]) -> items; +val_xfield(subscription_type, ["nodes"]) -> nodes; +val_xfield(subscription_depth, ["all"]) -> all; +val_xfield(subscription_depth, [Depth]) -> + case catch list_to_integer(Depth) of + N when is_integer(N) -> N; + _ -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'not-acceptable')} + end. + +%% Convert XForm booleans to Erlang booleans. +xopt_to_bool("0") -> false; +xopt_to_bool("1") -> true; +xopt_to_bool("false") -> false; +xopt_to_bool("true") -> true; +xopt_to_bool(_) -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'not-acceptable')}. + +%% Return a field for an XForm for Key, with data filled in, if +%% applicable, from Options. +get_option_xfield(Lang, Key, Options) -> + Var = xfield_var(Key), + Label = xfield_label(Key), + {Type, OptEls} = type_and_options(xfield_type(Key), Lang), + Vals = case lists:keysearch(Key, 1, Options) of + {value, {_, Val}} -> + [tr_xfield_values(Vals) || Vals <- xfield_val(Key, Val)]; + false -> + [] + end, + #xmlel{ns = ?NS_DATA_FORMS, + name = 'field', + attrs = [?XMLATTR('var', Var), ?XMLATTR('type', Type), ?XMLATTR('label', translate:translate(Lang, Label))], + children = OptEls ++ Vals}. + +type_and_options({Type, Options}, Lang) -> + {Type, [tr_xfield_options(O, Lang) || O <- Options]}; +type_and_options(Type, _Lang) -> + {Type, []}. + +tr_xfield_options({Value, Label}, Lang) -> + #xmlel{ns = ?NS_DATA_FORMS, + name = 'option', + attrs = [?XMLATTR('label', transalte:translate(Lang, Label))], + children = [#xmlel{ns = ?NS_DATA_FORMS, + name = 'value', + children = [?XMLCDATA(Value)]}]}. + +tr_xfield_values(Value) -> + #xmlel{ns = ?NS_DATA_FORMS, name ='value', children = [?XMLCDATA(Value)]}. + +%% Return the XForm variable name for a subscription option key. +xfield_var(deliver) -> ?PUBSUB_DELIVER; +xfield_var(digest) -> ?PUBSUB_DIGEST; +xfield_var(digest_frequency) -> ?PUBSUB_DIGEST_FREQUENCY; +xfield_var(expire) -> ?PUBSUB_EXPIRE; +xfield_var(include_body) -> ?PUBSUB_INCLUDE_BODY; +xfield_var(show_values) -> ?PUBSUB_SHOW_VALUES; +xfield_var(subscription_type) -> ?PUBSUB_SUBSCRIPTION_TYPE; +xfield_var(subscription_depth) -> ?PUBSUB_SUBSCRIPTION_DEPTH. + +%% Return the XForm variable type for a subscription option key. +xfield_type(deliver) -> "boolean"; +xfield_type(digest) -> "boolean"; +xfield_type(digest_frequency) -> "text-single"; +xfield_type(expire) -> "text-single"; +xfield_type(include_body) -> "boolean"; +xfield_type(show_values) -> + {"list-multi", [{"away", ?SHOW_VALUE_AWAY_LABEL}, + {"chat", ?SHOW_VALUE_CHAT_LABEL}, + {"dnd", ?SHOW_VALUE_DND_LABEL}, + {"online", ?SHOW_VALUE_ONLINE_LABEL}, + {"xa", ?SHOW_VALUE_XA_LABEL}]}; +xfield_type(subscription_type) -> + {"list-single", [{"items", ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL}, + {"nodes", ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]}; +xfield_type(subscription_depth) -> + {"list-single", [{"1", ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL}, + {"all", ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}. + +%% Return the XForm variable label for a subscription option key. +xfield_label(deliver) -> ?DELIVER_LABEL; +xfield_label(digest) -> ?DIGEST_LABEL; +xfield_label(digest_frequency) -> ?DIGEST_FREQUENCY_LABEL; +xfield_label(expire) -> ?EXPIRE_LABEL; +xfield_label(include_body) -> ?INCLUDE_BODY_LABEL; +xfield_label(show_values) -> ?SHOW_VALUES_LABEL; +xfield_label(subscription_type) -> ?SUBSCRIPTION_TYPE_LABEL; +xfield_label(subscription_depth) -> ?SUBSCRIPTION_DEPTH_LABEL. + +%% Return the XForm value for a subscription option key. +xfield_val(deliver, Val) -> [bool_to_xopt(Val)]; +xfield_val(digest, Val) -> [bool_to_xopt(Val)]; +xfield_val(digest_frequency, Val) -> [integer_to_list(Val)]; +xfield_val(expire, Val) -> [jlib:now_to_utc_string(Val)]; +xfield_val(include_body, Val) -> [bool_to_xopt(Val)]; +xfield_val(show_values, Val) -> Val; +xfield_val(subscription_type, items) -> ["items"]; +xfield_val(subscription_type, nodes) -> ["nodes"]; +xfield_val(subscription_depth, all) -> ["all"]; +xfield_val(subscription_depth, N) -> [integer_to_list(N)]. + +%% Convert erlang booleans to XForms. +bool_to_xopt(false) -> "false"; +bool_to_xopt(true) -> "true". From 3b27670d4d6fbc67a53ef601572e872f1e646fb8 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 27 Aug 2009 07:55:45 +0000 Subject: [PATCH 520/582] update win32 makefile SVN Revision: 2542 --- src/mod_pubsub/Makefile.win32 | 55 ++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/src/mod_pubsub/Makefile.win32 b/src/mod_pubsub/Makefile.win32 index f981329c9..8308f242a 100644 --- a/src/mod_pubsub/Makefile.win32 +++ b/src/mod_pubsub/Makefile.win32 @@ -4,7 +4,7 @@ include ..\Makefile.inc EFLAGS = -I .. -pz .. OUTDIR = .. -BEAMS = ..\gen_pubsub_node.beam ..\gen_pubsub_nodetree.beam ..\mod_pubsub.beam ..\nodetree_default.beam ..\nodetree_virtual.beam ..\node_buddy.beam ..\node_club.beam ..\node_default.beam ..\node_dispatch.beam ..\node_pep.beam ..\node_private.beam ..\node_public.beam +BEAMS = ..\gen_pubsub_node.beam ..\gen_pubsub_nodetree.beam ..\mod_pubsub.beam ..\mod_pubsub_odbc.beam ..\node_buddy.beam ..\node_club.beam ..\node_dag.beam ..\node_dispatch.beam ..\node_flat.beam ..\node_flat_odbc.beam ..\node_hometree.beam ..\node_hometree_odbc.beam ..\node_mb.beam ..\node_pep.beam ..\node_pep_odbc.beam ..\node_private.beam ..\node_public.beam ..\nodetree_dag.beam ..\nodetree_tree.beam ..\nodetree_tree_odbc.beam ..\nodetree_virtual.beam ..\pubsub_db_odbc.beam ..\pubsub_index.beam ..\pubsub_subscription.beam ..\pubsub_subscription_odbc.beam ALL : $(BEAMS) @@ -20,11 +20,8 @@ $(OUTDIR)\gen_pubsub_nodetree.beam : gen_pubsub_nodetree.erl $(OUTDIR)\mod_pubsub.beam : mod_pubsub.erl erlc -W $(EFLAGS) -o $(OUTDIR) mod_pubsub.erl -$(OUTDIR)\nodetree_default.beam : nodetree_default.erl - erlc -W $(EFLAGS) -o $(OUTDIR) nodetree_default.erl - -$(OUTDIR)\nodetree_virtual.beam : nodetree_virtual.erl - erlc -W $(EFLAGS) -o $(OUTDIR) nodetree_virtual.erl +$(OUTDIR)\mod_pubsub_odbc.beam : mod_pubsub_odbc.erl + erlc -W $(EFLAGS) -o $(OUTDIR) mod_pubsub_odbc.erl $(OUTDIR)\node_buddy.beam : node_buddy.erl erlc -W $(EFLAGS) -o $(OUTDIR) node_buddy.erl @@ -32,17 +29,59 @@ $(OUTDIR)\node_buddy.beam : node_buddy.erl $(OUTDIR)\node_club.beam : node_club.erl erlc -W $(EFLAGS) -o $(OUTDIR) node_club.erl -$(OUTDIR)\node_default.beam : node_default.erl - erlc -W $(EFLAGS) -o $(OUTDIR) node_default.erl +$(OUTDIR)\node_dag.beam : node_dag.erl + erlc -W $(EFLAGS) -o $(OUTDIR) node_dag.erl $(OUTDIR)\node_dispatch.beam : node_dispatch.erl erlc -W $(EFLAGS) -o $(OUTDIR) node_dispatch.erl +$(OUTDIR)\node_flat.beam : node_flat.erl + erlc -W $(EFLAGS) -o $(OUTDIR) node_flat.erl + +$(OUTDIR)\node_flat_odbc.beam : node_flat_odbc.erl + erlc -W $(EFLAGS) -o $(OUTDIR) node_flat_odbc.erl + +$(OUTDIR)\node_hometree.beam : node_hometree.erl + erlc -W $(EFLAGS) -o $(OUTDIR) node_hometree.erl + +$(OUTDIR)\node_hometree_odbc.beam : node_hometree_odbc.erl + erlc -W $(EFLAGS) -o $(OUTDIR) node_hometree_odbc.erl + +$(OUTDIR)\node_mb.beam : node_mb.erl + erlc -W $(EFLAGS) -o $(OUTDIR) node_mb.erl + $(OUTDIR)\node_pep.beam : node_pep.erl erlc -W $(EFLAGS) -o $(OUTDIR) node_pep.erl +$(OUTDIR)\node_pep_odbc.beam : node_pep_odbc.erl + erlc -W $(EFLAGS) -o $(OUTDIR) node_pep_odbc.erl + $(OUTDIR)\node_private.beam : node_private.erl erlc -W $(EFLAGS) -o $(OUTDIR) node_private.erl $(OUTDIR)\node_public.beam : node_public.erl erlc -W $(EFLAGS) -o $(OUTDIR) node_public.erl + +$(OUTDIR)\nodetree_dag.beam : nodetree_dag.erl + erlc -W $(EFLAGS) -o $(OUTDIR) nodetree_dag.erl + +$(OUTDIR)\nodetree_tree.beam : nodetree_tree.erl + erlc -W $(EFLAGS) -o $(OUTDIR) nodetree_tree.erl + +$(OUTDIR)\nodetree_tree_odbc.beam : nodetree_tree_odbc.erl + erlc -W $(EFLAGS) -o $(OUTDIR) nodetree_tree_odbc.erl + +$(OUTDIR)\nodetree_virtual.beam : nodetree_virtual.erl + erlc -W $(EFLAGS) -o $(OUTDIR) nodetree_virtual.erl + +$(OUTDIR)\pubsub_db_odbc.beam : pubsub_db_odbc.erl + erlc -W $(EFLAGS) -o $(OUTDIR) pubsub_db_odbc.erl + +$(OUTDIR)\pubsub_index.beam : pubsub_index.erl + erlc -W $(EFLAGS) -o $(OUTDIR) pubsub_index.erl + +$(OUTDIR)\pubsub_subscription.beam : pubsub_subscription.erl + erlc -W $(EFLAGS) -o $(OUTDIR) pubsub_subscription.erl + +$(OUTDIR)\pubsub_subscription_odbc.beam : pubsub_subscription_odbc.erl + erlc -W $(EFLAGS) -o $(OUTDIR) pubsub_subscription_odbc.erl From 71e0d7d8e240c3989a0074b49ec0195d090c9f4e Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 27 Aug 2009 08:26:22 +0000 Subject: [PATCH 521/582] port commit from r2527 to odbc plugin SVN Revision: 2544 --- src/mod_pubsub/node_hometree.erl | 2 +- src/mod_pubsub/node_hometree_odbc.erl | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index 134ee4894..c5ab29367 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -697,7 +697,7 @@ set_subscriptions(NodeId, Owner, Subscription, SubId) -> case {SubId, SubState#pubsub_state.subscriptions} of {_, []} -> case Subscription of - none -> ok; + none -> {error, ?ERR_EXTENDED('bad_request', "not-subscribed")}; _ -> new_subscription(NodeId, Owner, Subscription, SubState) end; {"", [{_, SID}]} -> diff --git a/src/mod_pubsub/node_hometree_odbc.erl b/src/mod_pubsub/node_hometree_odbc.erl index ebc5943c0..1f0cbaa71 100644 --- a/src/mod_pubsub/node_hometree_odbc.erl +++ b/src/mod_pubsub/node_hometree_odbc.erl @@ -741,8 +741,10 @@ set_subscriptions(NodeId, Owner, Subscription, SubId) -> SubState = get_state_without_itemids(NodeId, SubKey), case {SubId, SubState#pubsub_state.subscriptions} of {_, []} -> - %% pablo TODO, there seems that commit 2528 was applied to mnesia but not ported to odbc - {error, 'item-not-found'}; + case Subscription of + none -> {error, ?ERR_EXTENDED('bad_request', "not-subscribed")}; + _ -> new_subscription(NodeId, Owner, Subscription, SubState) + end; {"", [{_, SID}]} -> case Subscription of none -> unsub_with_subid(NodeId, SID, SubState); @@ -767,6 +769,16 @@ replace_subscription(_, [], Acc) -> replace_subscription({Sub, SubId}, [{_, SubID} | T], Acc) -> replace_subscription({Sub, SubId}, T, [{Sub, SubID} | Acc]). +new_subscription(NodeId, Owner, Subscription, SubState) -> + case pubsub_subscription_odbc:subscribe_node(Owner, NodeId, []) of + {result, SubId} -> + Subscriptions = SubState#pubsub_state.subscriptions, + set_state(SubState#pubsub_state{subscriptions = [{Subscription, SubId} | Subscriptions]}), + {Subscription, SubId}; + _ -> + {error, 'internal-server-error'} + end. + unsub_with_subid(NodeId, SubId, SubState) -> pubsub_subscription_odbc:unsubscribe_node(SubState#pubsub_state.stateid, NodeId, SubId), @@ -778,6 +790,7 @@ unsub_with_subid(NodeId, SubId, SubState) -> _ -> set_state(SubState#pubsub_state{subscriptions = NewSubs}) end. + %% @spec (Host, Owner) -> {result, [Node]} | {error, Reason} %% Host = host() %% Owner = jid() From bb08207569b42ff8e5cc1a39a7de9dd8e774b948 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 27 Aug 2009 08:34:16 +0000 Subject: [PATCH 522/582] fix node_public portage SVN Revision: 2545 --- src/mod_pubsub/node_public.erl | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl index c75ba803b..64f87e690 100644 --- a/src/mod_pubsub/node_public.erl +++ b/src/mod_pubsub/node_public.erl @@ -47,7 +47,7 @@ create_node/2, delete_node/1, purge_node/2, - subscribe_node/7, + subscribe_node/8, unsubscribe_node/4, publish_item/6, delete_item/4, @@ -58,8 +58,9 @@ set_affiliation/3, get_entity_subscriptions/2, get_node_subscriptions/1, - get_subscription/2, - set_subscription/3, + get_subscriptions/2, + set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -121,8 +122,8 @@ create_node(NodeId, Owner) -> delete_node(Removed) -> node_hometree:delete_node(Removed). -subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> - node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup). +subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options) -> + node_hometree:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options). unsubscribe_node(NodeId, Sender, Subscriber, SubID) -> node_hometree:unsubscribe_node(NodeId, Sender, Subscriber, SubID). @@ -157,11 +158,14 @@ get_entity_subscriptions(Host, Owner) -> get_node_subscriptions(NodeId) -> node_hometree:get_node_subscriptions(NodeId). -get_subscription(NodeId, Owner) -> - node_hometree:get_subscription(NodeId, Owner). +get_subscriptions(NodeId, Owner) -> + node_hometree:get_subscriptions(NodeId, Owner). -set_subscription(NodeId, Owner, Subscription) -> - node_hometree:set_subscription(NodeId, Owner, Subscription). +set_subscriptions(NodeId, Owner, Subscription, SubId) -> + node_hometree:set_subscription(NodeId, Owner, Subscription, SubId). + +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). get_states(NodeId) -> node_hometree:get_states(NodeId). From f5091aa1ae052d2e1d5a0c8185bda18233c7b36b Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 27 Aug 2009 08:48:21 +0000 Subject: [PATCH 523/582] pubsub now is sync with last trunk SVN Revision: 2546 --- src/mod_pubsub/mod_pubsub.erl | 6 +-- src/mod_pubsub/mod_pubsub_odbc.erl | 3 +- src/mod_pubsub/pubsub_odbc.patch | 79 +++++++++++++++--------------- 3 files changed, 43 insertions(+), 45 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 6733e8d5e..39d5b29fc 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -105,7 +105,8 @@ string_to_subscription/1, string_to_affiliation/1, extended_error/2, - extended_error/3 + extended_error/3, + rename_default_nodeplugin/0 ]). %% API and gen_server callbacks @@ -2720,7 +2721,7 @@ set_subscriptions(Host, Node, From, EntitiesEls) -> {error, 'bad-request'}; _ -> Notify = fun(JID, Sub, _SubId) -> - Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, + Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = [#xmlel{ns = ?NS_PUBSUB, @@ -2730,7 +2731,6 @@ set_subscriptions(Host, Node, From, EntitiesEls) -> name = 'subscription', attrs = [?XMLATTR('jid', exmpp_jid:to_binary(JID)), ?XMLATTR('subsription', subscription_to_string(Sub)) | nodeAttr(Node)]}]}]}, - ejabberd_router ! {route, service_jid(Host), JID, Stanza} end, Action = fun(#pubsub_node{owners = Owners, type = Type, id = NodeId}) -> diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index 75c593939..f837ccb20 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -2551,7 +2551,7 @@ set_subscriptions(Host, Node, From, EntitiesEls) -> {error, 'bad-request'}; _ -> Notify = fun(JID, Sub, _SubId) -> - Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, + Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = [#xmlel{ns = ?NS_PUBSUB, @@ -2561,7 +2561,6 @@ set_subscriptions(Host, Node, From, EntitiesEls) -> name = 'subscription', attrs = [?XMLATTR('jid', exmpp_jid:to_binary(JID)), ?XMLATTR('subsription', subscription_to_string(Sub)) | nodeAttr(Node)]}]}]}, - ejabberd_router ! {route, service_jid(Host), JID, Stanza} end, Action = fun(#pubsub_node{type = Type, id = NodeId}) -> diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index d87dc2c57..dfe6fe435 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,5 +1,5 @@ ---- mod_pubsub.erl 2009-08-25 17:29:57.000000000 -0300 -+++ mod_pubsub_odbc.erl 2009-08-26 12:07:05.000000000 -0300 +--- mod_pubsub.erl 2009-08-27 10:43:45.000000000 +0200 ++++ mod_pubsub_odbc.erl 2009-08-27 10:47:31.000000000 +0200 @@ -45,7 +45,7 @@ %%% TODO %%% plugin: generate Reply (do not use broadcast atom anymore) @@ -22,17 +22,16 @@ %% exports for hooks -export([presence_probe/3, -@@ -105,7 +105,8 @@ - string_to_subscription/1, +@@ -106,7 +106,7 @@ string_to_affiliation/1, extended_error/2, -- extended_error/3 -+ extended_error/3, + extended_error/3, +- rename_default_nodeplugin/0 + escape/1 ]). %% API and gen_server callbacks -@@ -124,7 +125,7 @@ +@@ -125,7 +125,7 @@ -export([send_loop/1 ]). @@ -41,7 +40,7 @@ -define(PLUGIN_PREFIX, "node_"). -define(TREE_PREFIX, "nodetree_"). -@@ -221,8 +222,6 @@ +@@ -222,8 +222,6 @@ ok end, ejabberd_router:register_route(Host), @@ -50,7 +49,7 @@ init_nodes(Host, ServerHost), State = #state{host = Host, server_host = ServerHost, -@@ -277,177 +276,7 @@ +@@ -278,177 +276,7 @@ create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), "hometree"), ok. @@ -228,7 +227,7 @@ send_queue(State, Msg) -> Pid = State#state.send_loop, -@@ -471,17 +300,15 @@ +@@ -472,17 +300,15 @@ %% for each node From is subscribed to %% and if the node is so configured, send the last published item to From lists:foreach(fun(PType) -> @@ -252,7 +251,7 @@ true -> % resource not concerned about that subscription ok -@@ -808,10 +635,10 @@ +@@ -809,10 +635,10 @@ {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), lists:foreach(fun ({Node, subscribed, _, JID}) -> @@ -265,7 +264,7 @@ true -> node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); false -> -@@ -929,11 +756,12 @@ +@@ -930,11 +756,12 @@ end, ejabberd_router:route(To, From, Res); #iq{type = get, ns = ?NS_DISCO_ITEMS, @@ -280,7 +279,7 @@ {result, IQRes} -> Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', attrs = QAttrs, -@@ -1036,7 +864,7 @@ +@@ -1037,7 +864,7 @@ [] -> ["leaf"]; %% No sub-nodes: it's a leaf node _ -> @@ -289,7 +288,7 @@ {result, []} -> ["collection"]; {result, _} -> ["leaf", "collection"]; _ -> [] -@@ -1052,8 +880,9 @@ +@@ -1053,8 +880,9 @@ []; true -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]} | @@ -301,7 +300,7 @@ end, features(Type))] end, %% TODO: add meta-data info (spec section 5.4) -@@ -1081,14 +910,15 @@ +@@ -1082,14 +910,15 @@ #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_DISCO_ITEMS_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_VCARD_s)]}] ++ @@ -320,7 +319,7 @@ {result, lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> SN = node_to_string(SubNode), -@@ -1098,7 +928,7 @@ +@@ -1099,7 +928,7 @@ ?XMLATTR('node', SN), ?XMLATTR('name', RN)]} end, tree_action(Host, get_subnodes, [Host, [], From]))}; @@ -329,7 +328,7 @@ case string:tokens(Item, "!") of [_SNode, _ItemID] -> {result, []}; -@@ -1110,9 +940,9 @@ +@@ -1111,9 +940,9 @@ %% TODO That is, remove name attribute (or node?, please check for 2.1) Action = fun(#pubsub_node{type = Type, id = NodeId}) -> @@ -341,7 +340,7 @@ end, Nodes = lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> -@@ -1128,7 +958,7 @@ +@@ -1129,7 +958,7 @@ #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), ?XMLATTR('name', Name)]} end, NodeItems), @@ -350,7 +349,7 @@ end, case transaction(Host, Node, Action, sync_dirty) of {result, {_, Result}} -> {result, Result}; -@@ -1267,7 +1097,8 @@ +@@ -1268,7 +1097,8 @@ (_, Acc) -> Acc end, [], exmpp_xml:remove_cdata_from_list(Els)), @@ -360,7 +359,7 @@ {get, 'subscriptions'} -> get_subscriptions(Host, Node, From, Plugins); {get, 'affiliations'} -> -@@ -1289,8 +1120,11 @@ +@@ -1290,8 +1120,11 @@ end. iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> @@ -374,7 +373,7 @@ case Action of [#xmlel{name = Name, attrs = Attrs, children = Els}] -> Node = case Host of -@@ -1420,7 +1254,8 @@ +@@ -1421,7 +1254,8 @@ _ -> [] end end, @@ -384,7 +383,7 @@ sync_dirty) of {result, Res} -> Res; Err -> Err -@@ -1466,7 +1301,7 @@ +@@ -1467,7 +1301,7 @@ %%% authorization handling @@ -393,7 +392,7 @@ Lang = "en", %% TODO fix {U, S, R} = Subscriber, Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = -@@ -1496,7 +1331,7 @@ +@@ -1497,7 +1331,7 @@ lists:foreach(fun(Owner) -> {U, S, R} = Owner, ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza} @@ -402,7 +401,7 @@ find_authorization_response(Packet) -> Els = Packet#xmlel.children, -@@ -1559,8 +1394,8 @@ +@@ -1560,8 +1394,8 @@ "true" -> true; _ -> false end, @@ -413,7 +412,7 @@ {result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]), if not IsApprover -> -@@ -1750,7 +1585,7 @@ +@@ -1751,7 +1585,7 @@ end, Reply = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(Node)}]}, @@ -422,7 +421,7 @@ {result, {Result, broadcast}} -> %%Lang = "en", %% TODO: fix %%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), -@@ -1866,7 +1701,7 @@ +@@ -1867,7 +1701,7 @@ {undefined, undefined, undefined} end, SubId = uniqid(), @@ -431,7 +430,7 @@ Features = features(Type), SubscribeFeature = lists:member("subscribe", Features), OptionsFeature = lists:member("subscription-options", Features), -@@ -1885,9 +1720,13 @@ +@@ -1886,9 +1720,13 @@ {"", "", ""} -> {false, false}; _ -> @@ -448,7 +447,7 @@ end end, if -@@ -2212,7 +2051,7 @@ +@@ -2213,7 +2051,7 @@ %%

    The permission are not checked in this function.

    %% @todo We probably need to check that the user doing the query has the right %% to read the items. @@ -457,7 +456,7 @@ MaxItems = if SMaxItems == "" -> ?MAXITEMS; -@@ -2251,11 +2090,11 @@ +@@ -2252,11 +2090,11 @@ node_call(Type, get_items, [NodeId, From, AccessModel, PresenceSubscription, RosterGroup, @@ -471,7 +470,7 @@ SendItems = case ItemIDs of [] -> Items; -@@ -2268,7 +2107,7 @@ +@@ -2269,7 +2107,7 @@ %% number of items sent to MaxItems: {result, #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = nodeAttr(Node), children = @@ -480,7 +479,7 @@ Error -> Error end -@@ -2300,16 +2139,25 @@ +@@ -2301,16 +2139,25 @@ %% @doc

    Resend the items of a node to the user.

    %% @todo use cache-last-item feature send_items(Host, Node, NodeId, Type, LJID, last) -> @@ -513,7 +512,7 @@ send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of {result, []} -> -@@ -2430,29 +2278,12 @@ +@@ -2431,29 +2278,12 @@ error -> {error, 'bad-request'}; _ -> @@ -546,8 +545,8 @@ end, Entities), {result, []}; _ -> -@@ -2733,8 +2564,8 @@ - +@@ -2733,8 +2563,8 @@ + ?XMLATTR('subsription', subscription_to_string(Sub)) | nodeAttr(Node)]}]}]}, ejabberd_router ! {route, service_jid(Host), JID, Stanza} end, - Action = fun(#pubsub_node{owners = Owners, type = Type, id = NodeId}) -> @@ -557,7 +556,7 @@ true -> Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> -@@ -3237,6 +3068,30 @@ +@@ -3237,6 +3067,30 @@ Result end. @@ -588,7 +587,7 @@ %% @spec (Host, Options) -> MaxItems %% Host = host() %% Options = [Option] -@@ -3613,7 +3468,13 @@ +@@ -3613,7 +3467,13 @@ tree_action(Host, Function, Args) -> ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), Fun = fun() -> tree_call(Host, Function, Args) end, @@ -603,7 +602,7 @@ %% @doc

    node plugin call.

    node_call(Type, Function, Args) -> -@@ -3633,13 +3494,13 @@ +@@ -3633,13 +3493,13 @@ node_action(Host, Type, Function, Args) -> ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), @@ -619,7 +618,7 @@ case tree_call(Host, get_node, [Host, Node]) of N when is_record(N, pubsub_node) -> case Action(N) of -@@ -3652,8 +3513,15 @@ +@@ -3652,8 +3512,15 @@ end end, Trans). @@ -637,7 +636,7 @@ {result, Result} -> {result, Result}; {error, Error} -> {error, Error}; {atomic, {result, Result}} -> {result, Result}; -@@ -3661,6 +3529,15 @@ +@@ -3661,6 +3528,15 @@ {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), {error, 'internal-server-error'}; @@ -653,7 +652,7 @@ {'EXIT', Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), {error, 'internal-server-error'}; -@@ -3669,6 +3546,16 @@ +@@ -3669,6 +3545,16 @@ {error, 'internal-server-error'} end. From 35e8b95928676ad11435da53024cbb2263994d47 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 27 Aug 2009 09:49:37 +0000 Subject: [PATCH 524/582] added pubsub odbc tables creation SVN Revision: 2550 --- src/odbc/mysql.sql | 55 ++++++++++++++++++++++++++++++++++++++++++++++ src/odbc/pg.sql | 53 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/src/odbc/mysql.sql b/src/odbc/mysql.sql index dfbf69437..8e1d242c4 100644 --- a/src/odbc/mysql.sql +++ b/src/odbc/mysql.sql @@ -158,3 +158,58 @@ CREATE TABLE roster_version ( -- ALTER TABLE rosterusers ADD COLUMN askmessage text AFTER ask; -- UPDATE rosterusers SET askmessage = ''; -- ALTER TABLE rosterusers ALTER COLUMN askmessage SET NOT NULL; + +CREATE TABLE pubsub_node ( + host text, + node text, + parent text, + type text, + nodeid bigint auto_increment primary key +) CHARACTER SET utf8; +CREATE INDEX i_pubsub_node_parent ON pubsub_node(parent(120)); +CREATE UNIQUE INDEX i_pubsub_node_tuple ON pubsub_node(host(20), node(120)); + +CREATE TABLE pubsub_node_option ( + nodeid bigint, + name text, + val text +) CHARACTER SET utf8; +CREATE INDEX i_pubsub_node_option_nodeid ON pubsub_node_option(nodeid); +ALTER TABLE `pubsub_node_option` ADD FOREIGN KEY (`nodeid`) REFERENCES `ejabberd`.`pubsub_node` (`nodeid`) ON DELETE CASCADE; + +CREATE TABLE pubsub_node_owner ( + nodeid bigint, + owner text +) CHARACTER SET utf8; +CREATE INDEX i_pubsub_node_owner_nodeid ON pubsub_node_owner(nodeid); +ALTER TABLE `pubsub_node_owner` ADD FOREIGN KEY (`nodeid`) REFERENCES `ejabberd`.`pubsub_node` (`nodeid`) ON DELETE CASCADE; + +CREATE TABLE pubsub_state ( + nodeid bigint, + jid text, + affiliation character(1), + subscriptions text, + stateid bigint auto_increment primary key +) CHARACTER SET utf8; +CREATE INDEX i_pubsub_state_jid ON pubsub_state(jid(60)); +CREATE UNIQUE INDEX i_pubsub_state_tuple ON pubsub_state(nodeid, jid(60)); +ALTER TABLE `pubsub_state` ADD FOREIGN KEY (`nodeid`) REFERENCES `ejabberd`.`pubsub_node` (`nodeid`) ON DELETE CASCADE; + +CREATE TABLE pubsub_item ( + nodeid bigint, + itemid text, + publisher text, + creation text, + modification text, + payload text +) CHARACTER SET utf8; +CREATE INDEX i_pubsub_item_itemid ON pubsub_item(itemid(36)); +CREATE UNIQUE INDEX i_pubsub_item_tuple ON pubsub_item(nodeid, itemid(36)); +ALTER TABLE `pubsub_item` ADD FOREIGN KEY (`nodeid`) REFERENCES `ejabberd`.`pubsub_node` (`nodeid`) ON DELETE CASCADE; + +CREATE TABLE pubsub_subscription_opt ( + subid text, + opt_name varchar(32), + opt_value text +); +CREATE UNIQUE INDEX i_pubsub_subscription_opt ON pubsub_subscription_opt(subid(32), opt_name(32)); diff --git a/src/odbc/pg.sql b/src/odbc/pg.sql index 60df5a195..269262672 100644 --- a/src/odbc/pg.sql +++ b/src/odbc/pg.sql @@ -145,10 +145,12 @@ CREATE TABLE private_storage ( CREATE INDEX i_private_storage_username ON private_storage USING btree (username); CREATE UNIQUE INDEX i_private_storage_username_namespace ON private_storage USING btree (username, namespace); + CREATE TABLE roster_version ( username text PRIMARY KEY, version text NOT NULL ); + -- To update from 0.9.8: -- CREATE SEQUENCE spool_seq_seq; -- ALTER TABLE spool ADD COLUMN seq integer; @@ -160,3 +162,54 @@ CREATE TABLE roster_version ( -- ALTER TABLE rosterusers ADD COLUMN askmessage text; -- UPDATE rosterusers SET askmessage = ''; -- ALTER TABLE rosterusers ALTER COLUMN askmessage SET NOT NULL; + +CREATE TABLE pubsub_node ( + host text, + node text, + parent text, + "type" text, + nodeid SERIAL UNIQUE +); +CREATE INDEX i_pubsub_node_parent ON pubsub_node USING btree (parent); +CREATE UNIQUE INDEX i_pubsub_node_tuple ON pubsub_node USING btree (host, node); + +CREATE TABLE pubsub_node_option ( + nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE, + name text, + val text +); +CREATE INDEX i_pubsub_node_option_nodeid ON pubsub_node_option USING btree (nodeid); + +CREATE TABLE pubsub_node_owner ( + nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE, + owner text +); +CREATE INDEX i_pubsub_node_owner_nodeid ON pubsub_node_owner USING btree (nodeid); + +CREATE TABLE pubsub_state ( + nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE, + jid text, + affiliation character(1), + subscriptions text, + stateid SERIAL UNIQUE +); +CREATE INDEX i_pubsub_state_jid ON pubsub_state USING btree (jid); +CREATE UNIQUE INDEX i_pubsub_state_tuple ON pubsub_state USING btree (nodeid, jid); + +CREATE TABLE pubsub_item ( + nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE, + itemid text, + publisher text, + creation text, + modification text, + payload text +); +CREATE INDEX i_pubsub_item_itemid ON pubsub_item USING btree (itemid); +CREATE UNIQUE INDEX i_pubsub_item_tuple ON pubsub_item USING btree (nodeid, itemid); + +CREATE TABLE pubsub_subscription_opt ( + subid text, + opt_name varchar(32), + opt_value text +); +CREATE UNIQUE INDEX i_pubsub_subscription_opt ON pubsub_subscription_opt USING btree (subid, opt_name); From adfca08e437d6c97d68751943b08fae7eae01157 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 27 Aug 2009 22:30:57 +0000 Subject: [PATCH 525/582] remove INFO_MSG call inside sql_query_internal SVN Revision: 2557 --- src/odbc/ejabberd_odbc.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/odbc/ejabberd_odbc.erl b/src/odbc/ejabberd_odbc.erl index 94ae0e69d..fd77decea 100644 --- a/src/odbc/ejabberd_odbc.erl +++ b/src/odbc/ejabberd_odbc.erl @@ -359,7 +359,7 @@ sql_query_internal(Query) -> ?DEBUG("MySQL, Send query~n~p~n", [Query]), R = mysql_to_odbc(mysql_conn:fetch(State#state.db_ref, Query, self())), - ?INFO_MSG("MySQL, Received result~n~p~n", [R]), + %% ?INFO_MSG("MySQL, Received result~n~p~n", [R]), R end, case Res of From fab29f4cf093ae974d97fedfab7719c74a4b3587 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 27 Aug 2009 23:09:20 +0000 Subject: [PATCH 526/582] port all recent fixes from trunk related to odbc subscriptions SVN Revision: 2559 --- src/mod_pubsub/mod_pubsub.erl | 122 ++++++++--------- src/mod_pubsub/mod_pubsub_odbc.erl | 142 +++++++++----------- src/mod_pubsub/node_flat_odbc.erl | 6 +- src/mod_pubsub/node_hometree_odbc.erl | 72 ++++++---- src/mod_pubsub/nodetree_tree.erl | 3 +- src/mod_pubsub/nodetree_tree_odbc.erl | 2 +- src/mod_pubsub/pubsub_odbc.patch | 117 ++++++++++++---- src/mod_pubsub/pubsub_subscription_odbc.erl | 25 ++-- 8 files changed, 285 insertions(+), 204 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 39d5b29fc..03f0095ea 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -1434,12 +1434,21 @@ send_pending_auth_events(Host, Node, Owner) -> ?DEBUG("Sending pending auth events for ~s on ~s:~s", [exmpp_jid:jid_to_string(Owner), Host, node_to_string(Node)]), Action = - fun (#pubsub_node{id = NodeID, type = Type} = N) -> + fun(#pubsub_node{id = NodeID, type = Type}) -> case lists:member("get-pending", features(Type)) of true -> case node_call(Type, get_affiliation, [NodeID, Owner]) of {result, owner} -> - broadcast_pending_auth_events(N), + {result, Subscriptions} = node_call(Type, get_node_subscriptions, [NodeID]), + lists:foreach(fun({J, pending, _SubID}) -> + {U, S, R} = J, + send_authorization_request(Node, exmpp_jid:make(U,S,R)); + ({J, pending}) -> + {U, S, R} = J, + send_authorization_request(Node, exmpp_jid:make(U,S,R)); + (_) -> + ok + end, Subscriptions), {result, ok}; _ -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'forbidden')} @@ -1455,16 +1464,6 @@ send_pending_auth_events(Host, Node, Owner) -> Err end. -broadcast_pending_auth_events(#pubsub_node{type = Type, id = NodeID} = Node) -> - {result, Subscriptions} = node_call(Type, get_node_subscriptions, [NodeID]), - lists:foreach(fun ({J, pending, _SubID}) -> - {U, S, R} = J, - send_authorization_request(Node, exmpp_jid:make(U,S,R)); - ({J, pending}) -> - {U, S, R} = J, - send_authorization_request(Node, exmpp_jid:make(U,S,R)) - end, Subscriptions). - %%% authorization handling send_authorization_request(#pubsub_node{owners = Owners, nodeid = {Host, Node}}, Subscriber) -> @@ -1795,18 +1794,19 @@ delete_node(_Host, [], _Owner) -> {error, 'not-allowed'}; delete_node(Host, Node, Owner) -> Action = fun(#pubsub_node{type = Type, id = NodeId}) -> - SubsByDepth = get_collection_subscriptions(Host, Node), - case node_call(Type, get_affiliation, [NodeId, Owner]) of - {result, owner} -> - Removed = tree_call(Host, delete_node, [Host, Node]), - case node_call(Type, delete_node, [Removed]) of + case node_call(Type, get_affiliation, [NodeId, Owner]) of + {result, owner} -> + ParentTree = tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]), + SubsByDepth = [{Depth, [{N, get_node_subs(N)} || N <- Nodes]} || {Depth, Nodes} <- ParentTree], + Removed = tree_call(Host, delete_node, [Host, Node]), + case node_call(Type, delete_node, [Removed]) of {result, Res} -> {result, {SubsByDepth, Res}}; - Error -> Error - end; - _ -> - %% Entity is not an owner - {error, 'forbidden'} - end + Error -> Error + end; + _ -> + %% Entity is not an owner + {error, 'forbidden'} + end end, Reply = [], case transaction(Host, Node, Action, transaction) of @@ -2559,8 +2559,7 @@ set_options_helper(Configuration, JID, NodeID, SubID, Type) -> end. write_sub(Subscriber, NodeID, SubID, Options) -> - case pubsub_subscription:set_subscription(Subscriber, NodeID, SubID, - Options) of + case pubsub_subscription:set_subscription(Subscriber, NodeID, SubID, Options) of {error, notfound} -> {error, extended_error('not-acceptable', "invalid-subid")}; {result, _} -> @@ -3016,24 +3015,28 @@ broadcast_config_notification(Host, Node, NodeId, Type, NodeOptions, Lang) -> end. get_collection_subscriptions(Host, Node) -> - lists:map(fun ({Depth, Nodes}) -> - {Depth, [{N, get_node_subs(N)} || N <- Nodes]} - end, tree_action(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)])). - -get_node_subs(#pubsub_node{type = Type, - nodeid = {Host, Node}, - id = NodeID}) -> - case node_action(Host, Type, get_node_subscriptions, [NodeID]) of - {result, Subs} -> - get_options_for_subs(Host, Node, NodeID, Subs); - Other -> - Other + Action = fun() -> + {result, lists:map(fun({Depth, Nodes}) -> + {Depth, [{N, get_node_subs(N)} || N <- Nodes]} + end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))} + end, + case transaction(Action, sync_dirty) of + {result, CollSubs} -> CollSubs; + _ -> [] end. -get_options_for_subs(_Host, Node, NodeID, Subs) -> +get_node_subs(#pubsub_node{type = Type, + id = NodeID}) -> + case node_call(Type, get_node_subscriptions, [NodeID]) of + {result, Subs} -> get_options_for_subs(NodeID, Subs); + Other -> Other + end. + +get_options_for_subs(NodeID, Subs) -> lists:foldl(fun({JID, subscribed, SubID}, Acc) -> - case pubsub_subscription:get_subscription(JID, NodeID, SubID) of - {result, #pubsub_subscription{options = Options}} -> [{JID, Node, Options} | Acc]; + case pubsub_subscription:read_subscription(JID, NodeID, SubID) of + {error, notfound} -> [{JID, SubID, []} | Acc]; + #pubsub_subscription{options = Options} -> [{JID, SubID, Options} | Acc]; _ -> Acc end; (_, Acc) -> @@ -3063,8 +3066,7 @@ broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyTyp BroadcastAll = get_option(NodeOptions, broadcast_all_resources), %% XXX this is not standard, but usefull From = service_jid(Host), %% Handles explicit subscriptions - FilteredSubsByDepth = depths_to_deliver(NotifyType, SubsByDepth), - NodesByJID = collate_subs_by_jid(FilteredSubsByDepth), + NodesByJID = subscribed_nodes_by_jid(NotifyType, SubsByDepth), lists:foreach(fun ({LJID, Nodes}) -> LJIDs = case BroadcastAll of true -> @@ -3125,36 +3127,28 @@ broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyTyp ok end. -depths_to_deliver(NotifyType, SubsByDepth) -> - NodesToDeliver = - fun (Depth, Node, Subs, Acc) -> - lists:foldl(fun ({LJID, _Node, SubOptions} = S, Acc2) -> +subscribed_nodes_by_jid(NotifyType, SubsByDepth) -> + NodesToDeliver = fun(Depth, Node, Subs, Acc) -> + NodeId = case Node#pubsub_node.nodeid of + {_, N} -> N; + Other -> Other + end, + NodeOptions = Node#pubsub_node.options, + lists:foldl(fun({LJID, _SubID, SubOptions}, Acc2) -> case is_to_deliver(LJID, NotifyType, Depth, - Node#pubsub_node.options, - SubOptions) of - true -> [S | Acc2]; + NodeOptions, SubOptions) of + true -> [{LJID, NodeId}|Acc2]; false -> Acc2 end end, Acc, Subs) end, - - DepthsToDeliver = - fun ({Depth, SubsByNode}, Acc) -> - lists:foldl(fun ({Node, Subs}, Acc2) -> + DepthsToDeliver = fun({Depth, SubsByNode}, Acc) -> + lists:foldl(fun({Node, Subs}, Acc2) -> NodesToDeliver(Depth, Node, Subs, Acc2) end, Acc, SubsByNode) end, - - lists:foldl(DepthsToDeliver, [], SubsByDepth). - -collate_subs_by_jid(SubsByDepth) -> - lists:foldl(fun ({JID, Node, _Options}, Acc) -> - OldNodes = case lists:keysearch(JID, 1, Acc) of - {value, {JID, Nodes}} -> Nodes; - false -> [] - end, - lists:keystore(JID, 1, Acc, {JID, [Node | OldNodes]}) - end, [], SubsByDepth). + JIDSubs = lists:foldl(DepthsToDeliver, [], SubsByDepth), + [{LJID, proplists:append_values(LJID, JIDSubs)} || LJID <- proplists:get_keys(JIDSubs)]. %% If we don't know the resource, just pick first if any %% If no resource available, check if caps anyway (remote online) diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index f837ccb20..becde6876 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -1120,11 +1120,9 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) -> end. iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> - SubEls = exmpp_xml:get_child_elements(SubEl), - NoRSM = lists:filter(fun(#xmlel{name = Name}) -> - Name == 'set' - end, SubEls), - Action = SubEls -- NoRSM, %%pablo why not doing it once on lists:filter? + Action = lists:filter(fun(#xmlel{name = 'set'}) -> false; + (_) -> true + end, exmpp_xml:get_child_elements(SubEl)), case Action of [#xmlel{name = Name, attrs = Attrs, children = Els}] -> Node = case Host of @@ -1268,12 +1266,21 @@ send_pending_auth_events(Host, Node, Owner) -> ?DEBUG("Sending pending auth events for ~s on ~s:~s", [exmpp_jid:jid_to_string(Owner), Host, node_to_string(Node)]), Action = - fun (#pubsub_node{id = NodeID, type = Type} = N) -> + fun(#pubsub_node{id = NodeID, type = Type}) -> case lists:member("get-pending", features(Type)) of true -> case node_call(Type, get_affiliation, [NodeID, Owner]) of {result, owner} -> - broadcast_pending_auth_events(N), + {result, Subscriptions} = node_call(Type, get_node_subscriptions, [NodeID]), + lists:foreach(fun({J, pending, _SubID}) -> + {U, S, R} = J, + send_authorization_request(Node, exmpp_jid:make(U,S,R)); + ({J, pending}) -> + {U, S, R} = J, + send_authorization_request(Node, exmpp_jid:make(U,S,R)); + (_) -> + ok + end, Subscriptions), {result, ok}; _ -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'forbidden')} @@ -1289,16 +1296,6 @@ send_pending_auth_events(Host, Node, Owner) -> Err end. -broadcast_pending_auth_events(#pubsub_node{type = Type, id = NodeID} = Node) -> - {result, Subscriptions} = node_call(Type, get_node_subscriptions, [NodeID]), - lists:foreach(fun ({J, pending, _SubID}) -> - {U, S, R} = J, - send_authorization_request(Node, exmpp_jid:make(U,S,R)); - ({J, pending}) -> - {U, S, R} = J, - send_authorization_request(Node, exmpp_jid:make(U,S,R)) - end, Subscriptions). - %%% authorization handling send_authorization_request(#pubsub_node{nodeid = {Host, Node}, type = Type, id = NodeId}, Subscriber) -> @@ -1629,18 +1626,19 @@ delete_node(_Host, [], _Owner) -> {error, 'not-allowed'}; delete_node(Host, Node, Owner) -> Action = fun(#pubsub_node{type = Type, id = NodeId}) -> - SubsByDepth = get_collection_subscriptions(Host, Node), - case node_call(Type, get_affiliation, [NodeId, Owner]) of - {result, owner} -> - Removed = tree_call(Host, delete_node, [Host, Node]), - case node_call(Type, delete_node, [Removed]) of + case node_call(Type, get_affiliation, [NodeId, Owner]) of + {result, owner} -> + ParentTree = tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]), + SubsByDepth = [{Depth, [{N, get_node_subs(N)} || N <- Nodes]} || {Depth, Nodes} <- ParentTree], + Removed = tree_call(Host, delete_node, [Host, Node]), + case node_call(Type, delete_node, [Removed]) of {result, Res} -> {result, {SubsByDepth, Res}}; - Error -> Error - end; - _ -> - %% Entity is not an owner - {error, 'forbidden'} - end + Error -> Error + end; + _ -> + %% Entity is not an owner + {error, 'forbidden'} + end end, Reply = [], case transaction(Host, Node, Action, transaction) of @@ -1693,7 +1691,7 @@ delete_node(Host, Node, Owner) -> %%
  • The node does not exist.
  • %% subscribe_node(Host, Node, From, JID, Configuration) -> - {result, SubOpts} = pubsub_subscription:parse_options_xform(Configuration), + {result, SubOpts} = pubsub_subscription_odbc:parse_options_xform(Configuration), Subscriber = try jlib:short_prepd_jid(exmpp_jid:parse(JID)) catch @@ -2338,11 +2336,11 @@ get_options_helper(JID, Lang, NodeID, SubID, Type) -> end. read_sub(Subscriber, NodeID, SubID, Lang) -> - case pubsub_subscription:get_subscription(Subscriber, NodeID, SubID) of + case pubsub_subscription_odbc:get_subscription(Subscriber, NodeID, SubID) of {error, notfound} -> - {error, extended_error('not-acceptable', "invalid-subid")}; + pubsub_subscription_odbc:get_options_xform(Lang, []); {result, #pubsub_subscription{options = Options}} -> - pubsub_subscription:get_options_xform(Lang, Options) + pubsub_subscription_odbc:get_options_xform(Lang, Options) end. set_options(Host, Node, JID, SubID, Configuration) -> @@ -2369,7 +2367,7 @@ set_options_helper(Configuration, JID, NodeID, SubID, Type) -> _ -> {"", "", ""} %%pablo TODO: "" or <<>> ?. short_jid uses exmpp_jid:node/1, etc. that returns binaries end, - {result, SubOpts} = pubsub_subscription:parse_options_xform(Configuration), + {result, SubOpts} = pubsub_subscription_odbc:parse_options_xform(Configuration), {result, Subs} = node_call(Type, get_subscriptions, [NodeID, Subscriber]), SubIDs = lists:foldl(fun({subscribed, SID}, Acc) -> @@ -2389,8 +2387,7 @@ set_options_helper(Configuration, JID, NodeID, SubID, Type) -> end. write_sub(Subscriber, NodeID, SubID, Options) -> - case pubsub_subscription:set_subscription(Subscriber, NodeID, SubID, - Options) of + case pubsub_subscription_odbc:set_subscription(Subscriber, NodeID, SubID, Options) of {error, notfound} -> {error, extended_error('not-acceptable', "invalid-subid")}; {result, _} -> @@ -2846,24 +2843,28 @@ broadcast_config_notification(Host, Node, NodeId, Type, NodeOptions, Lang) -> end. get_collection_subscriptions(Host, Node) -> - lists:map(fun ({Depth, Nodes}) -> - {Depth, [{N, get_node_subs(N)} || N <- Nodes]} - end, tree_action(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)])). - -get_node_subs(#pubsub_node{type = Type, - nodeid = {Host, Node}, - id = NodeID}) -> - case node_action(Host, Type, get_node_subscriptions, [NodeID]) of - {result, Subs} -> - get_options_for_subs(Host, Node, NodeID, Subs); - Other -> - Other + Action = fun() -> + {result, lists:map(fun({Depth, Nodes}) -> + {Depth, [{N, get_node_subs(N)} || N <- Nodes]} + end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))} + end, + case transaction(Host, Action, sync_dirty) of + {result, CollSubs} -> CollSubs; + _ -> [] end. -get_options_for_subs(_Host, Node, NodeID, Subs) -> +get_node_subs(#pubsub_node{type = Type, + id = NodeID}) -> + case node_call(Type, get_node_subscriptions, [NodeID]) of + {result, Subs} -> get_options_for_subs(NodeID, Subs); + Other -> Other + end. + +get_options_for_subs(NodeID, Subs) -> lists:foldl(fun({JID, subscribed, SubID}, Acc) -> - case pubsub_subscription:get_subscription(JID, NodeID, SubID) of - {result, #pubsub_subscription{options = Options}} -> [{JID, Node, Options} | Acc]; + case pubsub_subscription_odbc:get_subscription(JID, NodeID, SubID) of + {error, notfound} -> [{JID, SubID, []} | Acc]; + {result, #pubsub_subscription{options = Options}} -> [{JID, SubID, Options} | Acc]; _ -> Acc end; (_, Acc) -> @@ -2893,8 +2894,7 @@ broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyTyp BroadcastAll = get_option(NodeOptions, broadcast_all_resources), %% XXX this is not standard, but usefull From = service_jid(Host), %% Handles explicit subscriptions - FilteredSubsByDepth = depths_to_deliver(NotifyType, SubsByDepth), - NodesByJID = collate_subs_by_jid(FilteredSubsByDepth), + NodesByJID = subscribed_nodes_by_jid(NotifyType, SubsByDepth), lists:foreach(fun ({LJID, Nodes}) -> LJIDs = case BroadcastAll of true -> @@ -2955,36 +2955,28 @@ broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyTyp ok end. -depths_to_deliver(NotifyType, SubsByDepth) -> - NodesToDeliver = - fun (Depth, Node, Subs, Acc) -> - lists:foldl(fun ({LJID, _Node, SubOptions} = S, Acc2) -> +subscribed_nodes_by_jid(NotifyType, SubsByDepth) -> + NodesToDeliver = fun(Depth, Node, Subs, Acc) -> + NodeId = case Node#pubsub_node.nodeid of + {_, N} -> N; + Other -> Other + end, + NodeOptions = Node#pubsub_node.options, + lists:foldl(fun({LJID, _SubID, SubOptions}, Acc2) -> case is_to_deliver(LJID, NotifyType, Depth, - Node#pubsub_node.options, - SubOptions) of - true -> [S | Acc2]; + NodeOptions, SubOptions) of + true -> [{LJID, NodeId}|Acc2]; false -> Acc2 end end, Acc, Subs) end, - - DepthsToDeliver = - fun ({Depth, SubsByNode}, Acc) -> - lists:foldl(fun ({Node, Subs}, Acc2) -> + DepthsToDeliver = fun({Depth, SubsByNode}, Acc) -> + lists:foldl(fun({Node, Subs}, Acc2) -> NodesToDeliver(Depth, Node, Subs, Acc2) end, Acc, SubsByNode) end, - - lists:foldl(DepthsToDeliver, [], SubsByDepth). - -collate_subs_by_jid(SubsByDepth) -> - lists:foldl(fun ({JID, Node, _Options}, Acc) -> - OldNodes = case lists:keysearch(JID, 1, Acc) of - {value, {JID, Nodes}} -> Nodes; - false -> [] - end, - lists:keystore(JID, 1, Acc, {JID, [Node | OldNodes]}) - end, [], SubsByDepth). + JIDSubs = lists:foldl(DepthsToDeliver, [], SubsByDepth), + [{LJID, proplists:append_values(LJID, JIDSubs)} || LJID <- proplists:get_keys(JIDSubs)]. %% If we don't know the resource, just pick first if any %% If no resource available, check if caps anyway (remote online) @@ -3067,7 +3059,7 @@ node_options(Type) -> Result end. -%% @spec (NodeId) -> [ljid()] +%% @spec (Host, Type, NodeId) -> [ljid()] %% NodeId = pubsubNodeId() %% @doc

    Return list of node owners.

    node_owners(Host, Type, NodeId) -> diff --git a/src/mod_pubsub/node_flat_odbc.erl b/src/mod_pubsub/node_flat_odbc.erl index a5be7a16d..191ca1f8f 100644 --- a/src/mod_pubsub/node_flat_odbc.erl +++ b/src/mod_pubsub/node_flat_odbc.erl @@ -59,7 +59,8 @@ get_item/7, get_item/2, set_item/1, - get_item_name/3 + get_item_name/3, + get_last_items/3 ]). @@ -181,3 +182,6 @@ set_item(Item) -> get_item_name(Host, Node, Id) -> node_hometree_odbc:get_item_name(Host, Node, Id). + +get_last_items(NodeId, From, Count) -> + node_hometree_odbc:get_last_items(NodeId, From, Count). diff --git a/src/mod_pubsub/node_hometree_odbc.erl b/src/mod_pubsub/node_hometree_odbc.erl index 1f0cbaa71..e332c4253 100644 --- a/src/mod_pubsub/node_hometree_odbc.erl +++ b/src/mod_pubsub/node_hometree_odbc.erl @@ -398,8 +398,7 @@ unsubscribe_node(NodeId, Sender, Subscriber, SubId) -> delete_subscription(SubKey, NodeId, S, Affiliation, Subscriptions), {result, default}; false -> - {error, ?ERR_EXTENDED('unexpected-request', - "not-subscribed")} + {error, ?ERR_EXTENDED('unexpected-request', "not-subscribed")} end; %% No subid supplied, but there's only one matching %% subscription, so use that. @@ -652,25 +651,33 @@ get_entity_subscriptions(Host, Owner) -> SJ = encode_jid(SubKey), GJ = encode_jid(GenKey), Query = case SubKey of - GenKey -> - ["select node, type, i.nodeid, jid, subscriptions " - "from pubsub_state i, pubsub_node n " - "where i.nodeid = n.nodeid " - "and jid like '", GJ, "%' " - "and host='", H, "';"]; - _ -> - ["select node, type, i.nodeid, jid, subscriptions " - "from pubsub_state i, pubsub_node n " - "where i.nodeid = n.nodeid " - "and jid in ('", SJ, "', '", GJ, "') " - "and host='", H, "';"] + GenKey -> + ["select node, type, i.nodeid, jid, subscriptions " + "from pubsub_state i, pubsub_node n " + "where i.nodeid = n.nodeid " + "and jid like '", GJ, "%' " + "and host='", H, "';"]; + _ -> + ["select node, type, i.nodeid, jid, subscriptions " + "from pubsub_state i, pubsub_node n " + "where i.nodeid = n.nodeid " + "and jid in ('", SJ, "', '", GJ, "') " + "and host='", H, "';"] end, Reply = case catch ejabberd_odbc:sql_query_t(Query) of {selected, ["node", "type", "nodeid", "jid", "subscriptions"], RItems} -> - lists:map(fun({N, T, I, J, S}) -> + lists:foldl(fun({N, T, I, J, S}, Acc) -> Node = nodetree_tree_odbc:raw_to_node(Host, {N, "", T, I}), - {Node, decode_subscriptions(S), decode_jid(J)} - end, RItems); + Jid = decode_jid(J), + case decode_subscriptions(S) of + [] -> + [{Node, none, Jid}|Acc]; + Subs -> + lists:foldl(fun({Sub, SubId}, Acc2) -> [{Node, Sub, SubId, Jid}|Acc2]; + (Sub, Acc2) -> [{Node, Sub, Jid}|Acc2] + end, Acc, Subs) + end + end, [], RItems); _ -> [] end, @@ -702,10 +709,18 @@ get_entity_subscriptions_for_send_last(Host, Owner) -> end, Reply = case catch ejabberd_odbc:sql_query_t(Query) of {selected, ["node", "type", "nodeid", "jid", "subscriptions"], RItems} -> - lists:map(fun({N, T, I, J, S}) -> + lists:foldl(fun({N, T, I, J, S}, Acc) -> Node = nodetree_tree_odbc:raw_to_node(Host, {N, "", T, I}), - {Node, decode_subscriptions(S), decode_jid(J)} - end, RItems); + Jid = decode_jid(J), + case decode_subscriptions(S) of + [] -> + [{Node, none, Jid}|Acc]; + Subs -> + lists:foldl(fun({Sub, SubId}, Acc2) -> [{Node, Sub, SubId, Jid}|Acc2]; + (Sub, Acc2) -> [{Node, Sub, Jid}|Acc2] + end, Acc, Subs) + end + end, [], RItems); _ -> [] end, @@ -717,8 +732,17 @@ get_node_subscriptions(NodeId) -> "from pubsub_state " "where nodeid='", NodeId, "';"]) of {selected, ["jid", "subscriptions"], RItems} -> - lists:map(fun({J, S}) -> {decode_jid(J), decode_subscriptions(S)} end, RItems); - % TODO {J, S, SubId} + lists:foldl(fun({J, S}, Acc) -> + Jid = decode_jid(J), + case decode_subscriptions(S) of + [] -> + [{Jid, none}|Acc]; + Subs -> + lists:foldl(fun({Sub, SubId}, Acc2) -> [{Jid, Sub, SubId}|Acc2]; + (Sub, Acc2) -> [{Jid, Sub}|Acc2] + end, Acc, Subs) + end + end, [], RItems); _ -> [] end, @@ -732,7 +756,7 @@ get_subscriptions(NodeId, Owner) -> ["select subscriptions from pubsub_state " "where nodeid='", NodeId, "' and jid='", J, "';"]) of {selected, ["subscriptions"], [{S}]} -> decode_subscriptions(S); - _ -> none + _ -> [] end, {result, Reply}. @@ -1224,7 +1248,7 @@ select_affiliation_subscriptions(NodeId, JID) -> {selected, ["affiliation", "subscriptions"], [{A, S}]} -> {decode_affiliation(A), decode_subscriptions(S)}; _ -> - {none, none} + {none, []} end. select_affiliation_subscriptions(NodeId, JID, JID) -> select_affiliation_subscriptions(NodeId, JID); diff --git a/src/mod_pubsub/nodetree_tree.erl b/src/mod_pubsub/nodetree_tree.erl index 012f3f866..16a960430 100644 --- a/src/mod_pubsub/nodetree_tree.erl +++ b/src/mod_pubsub/nodetree_tree.erl @@ -149,8 +149,9 @@ get_parentnodes(_Host, _Node, _From) -> get_parentnodes_tree(Host, Node, From) -> case get_node(Host, Node, From) of N when is_record(N, pubsub_node) -> [{0, [N]}]; - Error -> Error + _Error -> [] end. + %% @spec (Host, Node, From) -> [pubsubNode()] | {error, Reason} %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() diff --git a/src/mod_pubsub/nodetree_tree_odbc.erl b/src/mod_pubsub/nodetree_tree_odbc.erl index afd934e31..04f657fb2 100644 --- a/src/mod_pubsub/nodetree_tree_odbc.erl +++ b/src/mod_pubsub/nodetree_tree_odbc.erl @@ -163,7 +163,7 @@ get_parentnodes(_Host, _Node, _From) -> get_parentnodes_tree(Host, Node, From) -> case get_node(Host, Node, From) of N when is_record(N, pubsub_node) -> [{0, [N]}]; - Error -> Error + _Error -> [] end. get_subnodes(Host, Node, _From) -> diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index dfe6fe435..0a6d6ed67 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,5 +1,5 @@ ---- mod_pubsub.erl 2009-08-27 10:43:45.000000000 +0200 -+++ mod_pubsub_odbc.erl 2009-08-27 10:47:31.000000000 +0200 +--- mod_pubsub.erl 2009-08-28 01:07:30.000000000 +0200 ++++ mod_pubsub_odbc.erl 2009-08-28 01:08:15.000000000 +0200 @@ -45,7 +45,7 @@ %%% TODO %%% plugin: generate Reply (do not use broadcast atom anymore) @@ -359,21 +359,19 @@ {get, 'subscriptions'} -> get_subscriptions(Host, Node, From, Plugins); {get, 'affiliations'} -> -@@ -1290,8 +1120,11 @@ +@@ -1290,8 +1120,9 @@ end. iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> - SubEls = SubEl#xmlel.children, - Action = exmpp_xml:remove_cdata_from_list(SubEls), -+ SubEls = exmpp_xml:get_child_elements(SubEl), -+ NoRSM = lists:filter(fun(#xmlel{name = Name}) -> -+ Name == 'set' -+ end, SubEls), -+ Action = SubEls -- NoRSM, %%pablo why not doing it once on lists:filter? ++ Action = lists:filter(fun(#xmlel{name = 'set'}) -> false; ++ (_) -> true ++ end, exmpp_xml:get_child_elements(SubEl)), case Action of [#xmlel{name = Name, attrs = Attrs, children = Els}] -> Node = case Host of -@@ -1421,7 +1254,8 @@ +@@ -1421,7 +1252,8 @@ _ -> [] end end, @@ -383,7 +381,7 @@ sync_dirty) of {result, Res} -> Res; Err -> Err -@@ -1467,7 +1301,7 @@ +@@ -1466,7 +1298,7 @@ %%% authorization handling @@ -392,7 +390,7 @@ Lang = "en", %% TODO fix {U, S, R} = Subscriber, Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = -@@ -1497,7 +1331,7 @@ +@@ -1496,7 +1328,7 @@ lists:foreach(fun(Owner) -> {U, S, R} = Owner, ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza} @@ -401,7 +399,7 @@ find_authorization_response(Packet) -> Els = Packet#xmlel.children, -@@ -1560,8 +1394,8 @@ +@@ -1559,8 +1391,8 @@ "true" -> true; _ -> false end, @@ -412,7 +410,7 @@ {result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]), if not IsApprover -> -@@ -1751,7 +1585,7 @@ +@@ -1750,7 +1582,7 @@ end, Reply = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(Node)}]}, @@ -421,7 +419,16 @@ {result, {Result, broadcast}} -> %%Lang = "en", %% TODO: fix %%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), -@@ -1867,7 +1701,7 @@ +@@ -1859,7 +1691,7 @@ + %%
  • The node does not exist.
  • + %% + subscribe_node(Host, Node, From, JID, Configuration) -> +- {result, SubOpts} = pubsub_subscription:parse_options_xform(Configuration), ++ {result, SubOpts} = pubsub_subscription_odbc:parse_options_xform(Configuration), + Subscriber = try + jlib:short_prepd_jid(exmpp_jid:parse(JID)) + catch +@@ -1867,7 +1699,7 @@ {undefined, undefined, undefined} end, SubId = uniqid(), @@ -430,7 +437,7 @@ Features = features(Type), SubscribeFeature = lists:member("subscribe", Features), OptionsFeature = lists:member("subscription-options", Features), -@@ -1886,9 +1720,13 @@ +@@ -1886,9 +1718,13 @@ {"", "", ""} -> {false, false}; _ -> @@ -447,7 +454,7 @@ end end, if -@@ -2213,7 +2051,7 @@ +@@ -2213,7 +2049,7 @@ %%

    The permission are not checked in this function.

    %% @todo We probably need to check that the user doing the query has the right %% to read the items. @@ -456,7 +463,7 @@ MaxItems = if SMaxItems == "" -> ?MAXITEMS; -@@ -2252,11 +2090,11 @@ +@@ -2252,11 +2088,11 @@ node_call(Type, get_items, [NodeId, From, AccessModel, PresenceSubscription, RosterGroup, @@ -470,7 +477,7 @@ SendItems = case ItemIDs of [] -> Items; -@@ -2269,7 +2107,7 @@ +@@ -2269,7 +2105,7 @@ %% number of items sent to MaxItems: {result, #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = nodeAttr(Node), children = @@ -479,7 +486,7 @@ Error -> Error end -@@ -2301,16 +2139,25 @@ +@@ -2301,16 +2137,25 @@ %% @doc

    Resend the items of a node to the user.

    %% @todo use cache-last-item feature send_items(Host, Node, NodeId, Type, LJID, last) -> @@ -512,7 +519,7 @@ send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of {result, []} -> -@@ -2431,29 +2278,12 @@ +@@ -2431,29 +2276,12 @@ error -> {error, 'bad-request'}; _ -> @@ -545,7 +552,40 @@ end, Entities), {result, []}; _ -> -@@ -2733,8 +2563,8 @@ +@@ -2508,11 +2336,11 @@ + end. + + read_sub(Subscriber, NodeID, SubID, Lang) -> +- case pubsub_subscription:get_subscription(Subscriber, NodeID, SubID) of ++ case pubsub_subscription_odbc:get_subscription(Subscriber, NodeID, SubID) of + {error, notfound} -> +- {error, extended_error('not-acceptable', "invalid-subid")}; ++ pubsub_subscription_odbc:get_options_xform(Lang, []); + {result, #pubsub_subscription{options = Options}} -> +- pubsub_subscription:get_options_xform(Lang, Options) ++ pubsub_subscription_odbc:get_options_xform(Lang, Options) + end. + + set_options(Host, Node, JID, SubID, Configuration) -> +@@ -2539,7 +2367,7 @@ + _ -> + {"", "", ""} %%pablo TODO: "" or <<>> ?. short_jid uses exmpp_jid:node/1, etc. that returns binaries + end, +- {result, SubOpts} = pubsub_subscription:parse_options_xform(Configuration), ++ {result, SubOpts} = pubsub_subscription_odbc:parse_options_xform(Configuration), + {result, Subs} = node_call(Type, get_subscriptions, + [NodeID, Subscriber]), + SubIDs = lists:foldl(fun({subscribed, SID}, Acc) -> +@@ -2559,7 +2387,7 @@ + end. + + write_sub(Subscriber, NodeID, SubID, Options) -> +- case pubsub_subscription:set_subscription(Subscriber, NodeID, SubID, Options) of ++ case pubsub_subscription_odbc:set_subscription(Subscriber, NodeID, SubID, Options) of + {error, notfound} -> + {error, extended_error('not-acceptable', "invalid-subid")}; + {result, _} -> +@@ -2732,8 +2560,8 @@ ?XMLATTR('subsription', subscription_to_string(Sub)) | nodeAttr(Node)]}]}]}, ejabberd_router ! {route, service_jid(Host), JID, Stanza} end, @@ -556,11 +596,32 @@ true -> Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> -@@ -3237,6 +3067,30 @@ +@@ -3020,7 +2848,7 @@ + {Depth, [{N, get_node_subs(N)} || N <- Nodes]} + end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))} + end, +- case transaction(Action, sync_dirty) of ++ case transaction(Host, Action, sync_dirty) of + {result, CollSubs} -> CollSubs; + _ -> [] + end. +@@ -3034,9 +2862,9 @@ + + get_options_for_subs(NodeID, Subs) -> + lists:foldl(fun({JID, subscribed, SubID}, Acc) -> +- case pubsub_subscription:read_subscription(JID, NodeID, SubID) of ++ case pubsub_subscription_odbc:get_subscription(JID, NodeID, SubID) of + {error, notfound} -> [{JID, SubID, []} | Acc]; +- #pubsub_subscription{options = Options} -> [{JID, SubID, Options} | Acc]; ++ {result, #pubsub_subscription{options = Options}} -> [{JID, SubID, Options} | Acc]; + _ -> Acc + end; + (_, Acc) -> +@@ -3231,6 +3059,30 @@ Result end. -+%% @spec (NodeId) -> [ljid()] ++%% @spec (Host, Type, NodeId) -> [ljid()] +%% NodeId = pubsubNodeId() +%% @doc

    Return list of node owners.

    +node_owners(Host, Type, NodeId) -> @@ -587,7 +648,7 @@ %% @spec (Host, Options) -> MaxItems %% Host = host() %% Options = [Option] -@@ -3613,7 +3467,13 @@ +@@ -3607,7 +3459,13 @@ tree_action(Host, Function, Args) -> ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), Fun = fun() -> tree_call(Host, Function, Args) end, @@ -602,7 +663,7 @@ %% @doc

    node plugin call.

    node_call(Type, Function, Args) -> -@@ -3633,13 +3493,13 @@ +@@ -3627,13 +3485,13 @@ node_action(Host, Type, Function, Args) -> ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), @@ -618,7 +679,7 @@ case tree_call(Host, get_node, [Host, Node]) of N when is_record(N, pubsub_node) -> case Action(N) of -@@ -3652,8 +3512,15 @@ +@@ -3646,8 +3504,15 @@ end end, Trans). @@ -636,7 +697,7 @@ {result, Result} -> {result, Result}; {error, Error} -> {error, Error}; {atomic, {result, Result}} -> {result, Result}; -@@ -3661,6 +3528,15 @@ +@@ -3655,6 +3520,15 @@ {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), {error, 'internal-server-error'}; @@ -652,7 +713,7 @@ {'EXIT', Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), {error, 'internal-server-error'}; -@@ -3669,6 +3545,16 @@ +@@ -3663,6 +3537,16 @@ {error, 'internal-server-error'} end. diff --git a/src/mod_pubsub/pubsub_subscription_odbc.erl b/src/mod_pubsub/pubsub_subscription_odbc.erl index 50a1ad590..4fb459424 100644 --- a/src/mod_pubsub/pubsub_subscription_odbc.erl +++ b/src/mod_pubsub/pubsub_subscription_odbc.erl @@ -90,14 +90,18 @@ init() -> ok = create_table(). subscribe_node(_JID, _NodeID, Options) -> - SubId = make_subid(), - ok = ?DB_MOD:add_subscription(#pubsub_subscription{subid = SubId, options = Options}), - {result, SubId}. + SubID = make_subid(), + ?DB_MOD:add_subscription(#pubsub_subscription{subid = SubID, options = Options}), + {result, SubID}. unsubscribe_node(_JID, _NodeID, SubID) -> - {ok, Sub} = ?DB_MOD:read_subscription(SubID), - ok = ?DB_MOD:delete_subscription(SubID), - {result, Sub}. + case ?DB_MOD:read_subscription(SubID) of + {ok, Sub} -> + ?DB_MOD:delete_subscription(SubID), + {result, Sub}; + notfound -> + {error, notfound} + end. get_subscription(_JID, _NodeID, SubID) -> case ?DB_MOD:read_subscription(SubID) of @@ -108,10 +112,11 @@ get_subscription(_JID, _NodeID, SubID) -> set_subscription(_JID, _NodeID, SubID, Options) -> case ?DB_MOD:read_subscription(SubID) of {ok, _} -> - ok = ?DB_MOD:update_subscription(#pubsub_subscription{subid = SubID, options = Options}), - {result, ok}; - notfound -> - {error, notfound} + ?DB_MOD:update_subscription(#pubsub_subscription{subid = SubID, options = Options}), + {result, ok}; + notfound -> + ?DB_MOD:add_subscription(#pubsub_subscription{subid = SubID, options = Options}), + {result, ok} end. get_options_xform(Lang, Options) -> From de78508f45a1bab9d89fd71eb38e0b5e132e419e Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 28 Aug 2009 00:09:21 +0000 Subject: [PATCH 527/582] fix send last item issue SVN Revision: 2561 --- src/mod_pubsub/mod_pubsub.erl | 4 ++-- src/mod_pubsub/pubsub_odbc.patch | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 03f0095ea..dd2400006 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -476,10 +476,10 @@ send_loop(State) -> lists:foreach( fun({Node, subscribed, _, SubJID}) -> if (SubJID == LJID) or (SubJID == BJID) -> - #pubsub_node{options = Options, type = Type, id = NodeId} = Node, + #pubsub_node{nodeid = {H, N}, type = Type, id = NodeId, options = Options} = Node, case get_option(Options, send_last_published_item) of on_sub_and_presence -> - send_items(Host, Node, NodeId, Type, SubJID, last); + send_items(H, N, NodeId, Type, SubJID, last); _ -> ok end; diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index 0a6d6ed67..c7eec7b9a 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,4 +1,4 @@ ---- mod_pubsub.erl 2009-08-28 01:07:30.000000000 +0200 +--- mod_pubsub.erl 2009-08-28 02:08:43.000000000 +0200 +++ mod_pubsub_odbc.erl 2009-08-28 01:08:15.000000000 +0200 @@ -45,7 +45,7 @@ %%% TODO @@ -239,10 +239,10 @@ lists:foreach( fun({Node, subscribed, _, SubJID}) -> if (SubJID == LJID) or (SubJID == BJID) -> -- #pubsub_node{options = Options, type = Type, id = NodeId} = Node, +- #pubsub_node{nodeid = {H, N}, type = Type, id = NodeId, options = Options} = Node, - case get_option(Options, send_last_published_item) of - on_sub_and_presence -> -- send_items(Host, Node, NodeId, Type, SubJID, last); +- send_items(H, N, NodeId, Type, SubJID, last); - _ -> - ok - end; From 3940a6bab3dd962eb7150e2b23e6e09ddcc5f436 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 28 Aug 2009 16:28:22 +0000 Subject: [PATCH 528/582] secure calls to ets:lookup SVN Revision: 2564 --- src/mod_pubsub/mod_pubsub.erl | 10 +++++----- src/mod_pubsub/mod_pubsub_odbc.erl | 10 +++++----- src/mod_pubsub/node_hometree.erl | 6 +++--- src/mod_pubsub/node_hometree_odbc.erl | 2 +- src/mod_pubsub/node_pep.erl | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index dd2400006..88262c93e 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -3468,7 +3468,7 @@ set_xoption([_ | Opts], NewOpts) -> is_last_item_cache_enabled({_, ServerHost, _}) -> is_last_item_cache_enabled(ServerHost); is_last_item_cache_enabled(Host) -> - case ets:lookup(gen_mod:get_module_proc(Host, config), last_item_cache) of + case catch ets:lookup(gen_mod:get_module_proc(Host, config), last_item_cache) of [{last_item_cache, true}] -> true; _ -> false end. @@ -3492,7 +3492,7 @@ get_cached_item({_, ServerHost, _}, NodeId) -> get_cached_item(Host, NodeId) -> case is_last_item_cache_enabled(Host) of true -> - case ets:lookup(gen_mod:get_module_proc(Host, last_items), NodeId) of + case catch ets:lookup(gen_mod:get_module_proc(Host, last_items), NodeId) of [{NodeId, {ItemId, Payload}}] -> #pubsub_item{itemid = {ItemId, NodeId}, payload = Payload}; _ -> @@ -3506,7 +3506,7 @@ get_cached_item(Host, NodeId) -> plugins(Host) when is_binary(Host) -> plugins(binary_to_list(Host)); plugins(Host) when is_list(Host) -> - case ets:lookup(gen_mod:get_module_proc(Host, config), plugins) of + case catch ets:lookup(gen_mod:get_module_proc(Host, config), plugins) of [{plugins, []}] -> [?STDNODE]; [{plugins, PL}] -> PL; _ -> [?STDNODE] @@ -3516,7 +3516,7 @@ select_type(ServerHost, Host, Node, Type) when is_list(ServerHost) -> select_type(ServerHost, Host, Node, Type) -> SelectedType = case Host of {_User, _Server, _Resource} -> - case ets:lookup(gen_mod:get_module_proc(ServerHost, config), pep_mapping) of + case catch ets:lookup(gen_mod:get_module_proc(ServerHost, config), pep_mapping) of [{pep_mapping, PM}] -> proplists:get_value(Node, PM, ?PEPNODE); _ -> ?PEPNODE end; @@ -3599,7 +3599,7 @@ tree_call({_User, Server, _Resource}, Function, Args) -> tree_call(Server, Function, Args); tree_call(Host, Function, Args) -> ?DEBUG("tree_call ~p ~p ~p",[Host, Function, Args]), - Module = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of + Module = case catch ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of [{nodetree, N}] -> N; _ -> list_to_atom(?TREE_PREFIX ++ ?STDTREE) end, diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index becde6876..d4a53962f 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -3320,7 +3320,7 @@ set_xoption([_ | Opts], NewOpts) -> is_last_item_cache_enabled({_, ServerHost, _}) -> is_last_item_cache_enabled(ServerHost); is_last_item_cache_enabled(Host) -> - case ets:lookup(gen_mod:get_module_proc(Host, config), last_item_cache) of + case catch ets:lookup(gen_mod:get_module_proc(Host, config), last_item_cache) of [{last_item_cache, true}] -> true; _ -> false end. @@ -3344,7 +3344,7 @@ get_cached_item({_, ServerHost, _}, NodeId) -> get_cached_item(Host, NodeId) -> case is_last_item_cache_enabled(Host) of true -> - case ets:lookup(gen_mod:get_module_proc(Host, last_items), NodeId) of + case catch ets:lookup(gen_mod:get_module_proc(Host, last_items), NodeId) of [{NodeId, {ItemId, Payload}}] -> #pubsub_item{itemid = {ItemId, NodeId}, payload = Payload}; _ -> @@ -3358,7 +3358,7 @@ get_cached_item(Host, NodeId) -> plugins(Host) when is_binary(Host) -> plugins(binary_to_list(Host)); plugins(Host) when is_list(Host) -> - case ets:lookup(gen_mod:get_module_proc(Host, config), plugins) of + case catch ets:lookup(gen_mod:get_module_proc(Host, config), plugins) of [{plugins, []}] -> [?STDNODE]; [{plugins, PL}] -> PL; _ -> [?STDNODE] @@ -3368,7 +3368,7 @@ select_type(ServerHost, Host, Node, Type) when is_list(ServerHost) -> select_type(ServerHost, Host, Node, Type) -> SelectedType = case Host of {_User, _Server, _Resource} -> - case ets:lookup(gen_mod:get_module_proc(ServerHost, config), pep_mapping) of + case catch ets:lookup(gen_mod:get_module_proc(ServerHost, config), pep_mapping) of [{pep_mapping, PM}] -> proplists:get_value(Node, PM, ?PEPNODE); _ -> ?PEPNODE end; @@ -3451,7 +3451,7 @@ tree_call({_User, Server, _Resource}, Function, Args) -> tree_call(Server, Function, Args); tree_call(Host, Function, Args) -> ?DEBUG("tree_call ~p ~p ~p",[Host, Function, Args]), - Module = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of + Module = case catch ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of [{nodetree, N}] -> N; _ -> list_to_atom(?TREE_PREFIX ++ ?STDTREE) end, diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index c5ab29367..6c9a668dc 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -595,7 +595,7 @@ purge_node(NodeId, Owner) -> get_entity_affiliations(Host, Owner) -> GenKey = jlib:short_prepd_bare_jid(Owner), States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'}), - NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of + NodeTree = case catch ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of [{nodetree, N}] -> N; _ -> nodetree_tree end, @@ -650,7 +650,7 @@ get_entity_subscriptions(Host, Owner) -> ++ mnesia:match_object( #pubsub_state{stateid = {SubKey, '_'}, _ = '_'}) end, - NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of + NodeTree = case catch ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of [{nodetree, N}] -> N; _ -> nodetree_tree end, @@ -753,7 +753,7 @@ get_pending_nodes(Host, Owner) -> affiliation = owner, _ = '_'}), NodeIDs = [ID || #pubsub_state{stateid = {_, ID}} <- States], - NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of + NodeTree = case catch ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of [{nodetree, N}] -> N; _ -> nodetree_tree end, diff --git a/src/mod_pubsub/node_hometree_odbc.erl b/src/mod_pubsub/node_hometree_odbc.erl index e332c4253..91c9be46f 100644 --- a/src/mod_pubsub/node_hometree_odbc.erl +++ b/src/mod_pubsub/node_hometree_odbc.erl @@ -828,7 +828,7 @@ get_pending_nodes(Host, Owner) -> affiliation = owner, _ = '_'}), NodeIDs = [ID || #pubsub_state{stateid = {_, ID}} <- States], - NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of + NodeTree = case catch ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of [{nodetree, N}] -> N; _ -> nodetree_tree_odbc end, diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index 64e21fac8..e304fe916 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -174,7 +174,7 @@ get_entity_affiliations(_Host, Owner) -> SubKey = jlib:jid_tolower(Owner), GenKey = jlib:jid_remove_resource(SubKey), States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'}), - NodeTree = case ets:lookup(gen_mod:get_module_proc(D, config), nodetree) of + NodeTree = case catch ets:lookup(gen_mod:get_module_proc(D, config), nodetree) of [{nodetree, N}] -> N; _ -> nodetree_tree end, @@ -206,7 +206,7 @@ get_entity_subscriptions(_Host, Owner) -> ++ mnesia:match_object( #pubsub_state{stateid = {SubKey, '_'}, _ = '_'}) end, - NodeTree = case ets:lookup(gen_mod:get_module_proc(D, config), nodetree) of + NodeTree = case catch ets:lookup(gen_mod:get_module_proc(D, config), nodetree) of [{nodetree, N}] -> N; _ -> nodetree_tree end, From 98f93104a7d5a8cbf1ed9c08ada2601b8fb5e872 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 31 Aug 2009 11:03:35 +0000 Subject: [PATCH 529/582] Rename erlang log file sasl.log to erlang.log (EJAB-783) SVN Revision: 2568 --- doc/guide.html | 10 ++++++---- doc/guide.tex | 8 +++++--- src/ejabberdctl.template | 2 +- src/win32/ejabberd.nsi | 4 ++-- tools/ejabberdctl | 2 +- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 02c5c94cd..86dfbe1d6 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -417,7 +417,7 @@ to install ejabberd.

    The files and directories created are, by de

    /var/log/ejabberd/
    Log directory (see section 7.1):
    ejabberd.log
    ejabberd service log -
    sasl.log
    Erlang/OTP system log +
    erlang.log
    Erlang/OTP system log

    2.4.5  Start

    @@ -3320,8 +3320,10 @@ Starts the Erlang system detached from the system console. Tell Erlang runtime system to start the ejabberd application.

    -mnesia dir "/var/lib/ejabberd/"
    Specify the Mnesia database directory. -
    -sasl sasl_error_logger {file, "/var/log/ejabberd/sasl.log"}
    +
    -sasl sasl_error_logger {file, "/var/log/ejabberd/erlang.log"}
    Path to the Erlang/OTP system log file. +SASL here means “System Architecture Support Libraries” +not “Simple Authentication and Security Layer”.
    +K [true|false]
    Kernel polling.
    -smp [auto|enable|disable]
    @@ -3726,13 +3728,13 @@ domain.

    6.3.3  Load-Balancing Buckets

    When there is a risk of failure for a given component, domain balancing can cause service trouble. If one component is failing the service will not work correctly unless the sessions are rebalanced.

    In this case, it is best to limit the problem to the sessions handled by the failing component. This is what the domain_balancing_component_number option does, making the load balancing algorithm not dynamic, but sticky on a fix number of component instances.

    The syntax is: -

    {domain_balancing_component_number, "component.example.com", N}.

    +

    {domain_balancing_component_number, "component.example.com", Number}.

    Chapter 7  Debugging

    7.1  Log Files

    An ejabberd node writes two log files:

    ejabberd.log
    is the ejabberd service log, with the messages reported by ejabberd code -
    sasl.log
    is the Erlang/OTP system log, with the messages reported by Erlang/OTP using SASL (System Architecture Support Libraries) +
    erlang.log
    is the Erlang/OTP system log, with the messages reported by Erlang/OTP using SASL (System Architecture Support Libraries)

    The option loglevel modifies the verbosity of the file ejabberd.log. The syntax is:

    {loglevel, Level}.

    The possible Level are:

    diff --git a/doc/guide.tex b/doc/guide.tex index 74d6fa8b4..8732e4a05 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -415,7 +415,7 @@ The files and directories created are, by default: \titem{/var/log/ejabberd/} Log directory (see section~\ref{logfiles}): \begin{description} \titem{ejabberd.log} ejabberd service log - \titem{sasl.log} Erlang/OTP system log + \titem{erlang.log} Erlang/OTP system log \end{description} \end{description} @@ -4252,8 +4252,10 @@ The command line parameters: Tell Erlang runtime system to start the \ejabberd{} application. \titem{-mnesia dir "/var/lib/ejabberd/"} Specify the Mnesia database directory. - \titem{-sasl sasl\_error\_logger \{file, "/var/log/ejabberd/sasl.log"\}} + \titem{-sasl sasl\_error\_logger \{file, "/var/log/ejabberd/erlang.log"\}} Path to the Erlang/OTP system log file. + SASL here means ``System Architecture Support Libraries'' + not ``Simple Authentication and Security Layer''. \titem{+K [true|false]} Kernel polling. \titem{-smp [auto|enable|disable]} @@ -4884,7 +4886,7 @@ The syntax is: An \ejabberd{} node writes two log files: \begin{description} \titem{ejabberd.log} is the ejabberd service log, with the messages reported by \ejabberd{} code - \titem{sasl.log} is the Erlang/OTP system log, with the messages reported by Erlang/OTP using SASL (System Architecture Support Libraries) + \titem{erlang.log} is the Erlang/OTP system log, with the messages reported by Erlang/OTP using SASL (System Architecture Support Libraries) \end{description} The option \term{loglevel} modifies the verbosity of the file ejabberd.log. The syntax is: diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template index 48a56ba5b..5ebfb5f6f 100644 --- a/src/ejabberdctl.template +++ b/src/ejabberdctl.template @@ -102,7 +102,7 @@ if [ "$EJABBERD_MSGS_PATH" = "" ]; then fi EJABBERD_LOG_PATH=$LOGS_DIR/ejabberd.log -SASL_LOG_PATH=$LOGS_DIR/sasl.log +SASL_LOG_PATH=$LOGS_DIR/erlang.log DATETIME=`date "+%Y%m%d-%H%M%S"` ERL_CRASH_DUMP=$LOGS_DIR/erl_crash_$DATETIME.dump ERL_INETRC=$ETCDIR/inetrc diff --git a/src/win32/ejabberd.nsi b/src/win32/ejabberd.nsi index 8c828bda8..26fdb0618 100644 --- a/src/win32/ejabberd.nsi +++ b/src/win32/ejabberd.nsi @@ -180,7 +180,7 @@ SectionIn 1 RO '-sname ejabberd -pa ebin \ -env EJABBERD_LOG_PATH log/ejabberd.log \ -s ejabberd -kernel inetrc \"./inetrc\" -mnesia dir \"spool\" \ - -sasl sasl_error_logger {file,\"log/sasl.log\"}' \ + -sasl sasl_error_logger {file,\"log/erlang.log\"}' \ $INSTDIR\win32\ejabberd.ico CreateShortCut "$0\Edit Config.lnk" "%SystemRoot%\system32\notepad.exe" \ "$INSTDIR\ejabberd.cfg" @@ -215,7 +215,7 @@ SectionIn 1 RO -args "-s ejabberd -pa ebin \ -kernel inetrc \\\"./inetrc\\\" \ -env EJABBERD_LOG_PATH log/ejabberd.log \ - -sasl sasl_error_logger {file,\\\"log/sasl.log\\\"} \ + -sasl sasl_error_logger {file,\\\"log/erlang.log\\\"} \ -mnesia dir \\\"spool\\\"" -d' Pop $0 diff --git a/tools/ejabberdctl b/tools/ejabberdctl index 033640ecd..80d8702f7 100755 --- a/tools/ejabberdctl +++ b/tools/ejabberdctl @@ -8,7 +8,7 @@ ERL=erl here=`which "$0" 2>/dev/null || echo .` base="`dirname $here`/.." ROOTDIR=`(cd "$base"; echo $PWD)` -SASL_LOG_PATH=$ROOTDIR/sasl.log +SASL_LOG_PATH=$ROOTDIR/erlang.log EJABBERD_DB=$ROOTDIR/database/$NODE EJABBERD_EBIN=$ROOTDIR/src export EJABBERD_LOG_PATH=$ROOTDIR/ejabberd.log From f5eb9e3c9fdd5b47c133bd9ab15bc9367d50b3ae Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 31 Aug 2009 16:30:19 +0000 Subject: [PATCH 530/582] Support zlib compression after STARTTLS (thanks to Aleksey Shchepin)(EJAB-499) Unfortunately, zlib compression doesn't work in this branch, neither in this commit or before it. SVN Revision: 2572 --- doc/guide.html | 5 +---- doc/guide.tex | 5 +---- src/ejabberd_c2s.erl | 19 ++++++++++++++----- src/ejabberd_zlib/ejabberd_zlib.erl | 19 ++++++++++++++++++- src/web/ejabberd_web_admin.erl | 1 + 5 files changed, 35 insertions(+), 14 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 86dfbe1d6..db5244ae0 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -769,10 +769,7 @@ password of one of the registered users who are granted access by the ‘configure’ access rule.
    zlib
    This option specifies that Zlib stream compression (as defined in XEP-0138) -is available on connections to the port. Client connections cannot use -stream compression and stream encryption simultaneously. Hence, if you -specify both starttls (or tls) and zlib, the latter -option will not affect connections (there will be no stream compression). +is available on connections to the port.

    There are some additional global options that can be specified in the ejabberd configuration file (outside listen):

    {s2s_use_starttls, true|false}
    diff --git a/doc/guide.tex b/doc/guide.tex index 8732e4a05..17665a922 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -905,10 +905,7 @@ This is a detailed description of each option allowed by the listening modules: `configure' access rule. \titem{zlib} \ind{options!zlib}\ind{protocols!XEP-0138: Stream Compression}\ind{Zlib}This option specifies that Zlib stream compression (as defined in \xepref{0138}) - is available on connections to the port. Client connections cannot use - stream compression and stream encryption simultaneously. Hence, if you - specify both \option{starttls} (or \option{tls}) and \option{zlib}, the latter - option will not affect connections (there will be no stream compression). + is available on connections to the port. \end{description} There are some additional global options that can be specified in the ejabberd configuration file (outside \term{listen}): diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index b9f19ef3e..bd7a125ac 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -274,7 +274,8 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> Zlib = StateData#state.zlib, CompressFeature = case Zlib andalso - (SockMod == gen_tcp) of + ((SockMod == gen_tcp) orelse + (SockMod == tls)) of true -> [exmpp_server_compression:feature(["zlib"])]; _ -> @@ -578,13 +579,14 @@ wait_for_feature_request({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, tls_enabled = true }); {?NS_COMPRESS, 'compress'} when Zlib == true, - SockMod == gen_tcp -> + ((SockMod == gen_tcp) or + (SockMod == tls)) -> case exmpp_server_compression:selected_method(El) of undefined -> send_element(StateData, - exmpp_server_compression:failure('steup-failed')), + exmpp_server_compression:failure('setup-failed')), fsm_next_state(wait_for_feature_request, StateData); - "zlib" -> + <<"zlib">> -> Socket = StateData#state.socket, ZlibSocket = (StateData#state.sockmod):compress( Socket, @@ -1332,11 +1334,18 @@ get_auth_tags([_ | L], U, P, D, R) -> get_auth_tags([], U, P, D, R) -> {U, P, D, R}. +%% Copied from ejabberd_socket.erl +-record(socket_state, {sockmod, socket, receiver}). + get_conn_type(StateData) -> case (StateData#state.sockmod):get_sockmod(StateData#state.socket) of gen_tcp -> c2s; tls -> c2s_tls; - ejabberd_zlib -> c2s_compressed; + ejabberd_zlib -> + case ejabberd_zlib:get_sockmod((StateData#state.socket)#socket_state.socket) of + gen_tcp -> c2s_compressed; + tls -> c2s_compressed_tls + end; ejabberd_http_poll -> http_poll; ejabberd_http_bind -> http_bind; _ -> unknown diff --git a/src/ejabberd_zlib/ejabberd_zlib.erl b/src/ejabberd_zlib/ejabberd_zlib.erl index 3c3879b71..36beffedc 100644 --- a/src/ejabberd_zlib/ejabberd_zlib.erl +++ b/src/ejabberd_zlib/ejabberd_zlib.erl @@ -35,6 +35,7 @@ recv/2, recv/3, recv_data/2, setopts/2, sockname/1, peername/1, + get_sockmod/1, controlling_process/2, close/1]). @@ -116,7 +117,20 @@ recv(#zlibsock{sockmod = SockMod, socket = Socket} = ZlibSock, Error end. -recv_data(ZlibSock, Packet) -> +recv_data(#zlibsock{sockmod = SockMod, socket = Socket} = ZlibSock, Packet) -> + case SockMod of + gen_tcp -> + recv_data2(ZlibSock, Packet); + _ -> + case SockMod:recv_data(Socket, Packet) of + {ok, Packet2} -> + recv_data2(ZlibSock, Packet2); + Error -> + Error + end + end. + +recv_data2(ZlibSock, Packet) -> case catch recv_data1(ZlibSock, Packet) of {'EXIT', Reason} -> {error, Reason}; @@ -158,6 +172,9 @@ sockname(#zlibsock{sockmod = SockMod, socket = Socket}) -> SockMod:sockname(Socket) end. +get_sockmod(#zlibsock{sockmod = SockMod}) -> + SockMod. + peername(#zlibsock{sockmod = SockMod, socket = Socket}) -> case SockMod of gen_tcp -> diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 97c2d0c48..85a3a2cac 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -1696,6 +1696,7 @@ user_info(User, Server, Query, Lang) -> c2s -> "plain"; c2s_tls -> "tls"; c2s_compressed -> "zlib"; + c2s_compressed_tls -> "tls+zlib"; http_bind -> "http-bind"; http_poll -> "http-poll" end, From 095cd6ce9b3ab5b2c4ef6eba32e822d469841213 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 31 Aug 2009 18:40:25 +0000 Subject: [PATCH 531/582] =?UTF-8?q?BOSH=20module=20optimization=20and=20cl?= =?UTF-8?q?ean-up=20(thanks=20to=20Aleksey=20Shchepin=20and=20Micka=C3=ABl?= =?UTF-8?q?=20R=C3=A9mond)(EJAB-936)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unfortunately, http-bind doesn't work in this branch, neither in this commit or before it. SVN Revision: 2575 --- src/ejabberd_c2s.erl | 171 ++++-- src/ejabberd_receiver.erl | 31 +- src/ejabberd_socket.erl | 42 +- src/web/ejabberd_http_bind.erl | 931 ++++++++++++++++++--------------- 4 files changed, 695 insertions(+), 480 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index bd7a125ac..5a9f6fddc 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -71,6 +71,7 @@ -record(state, {socket, sockmod, socket_monitor, + xml_socket, streamid, sasl_state, access, @@ -124,6 +125,24 @@ -define(DEFAULT_NS, ?NS_JABBER_CLIENT). -define(PREFIXED_NS, [{?NS_XMPP, ?NS_XMPP_pfx}]). +-define(STREAM_HEADER, + "" + "" + ). + +-define(STREAM_TRAILER, ""). + +-define(INVALID_NS_ERR, exmpp_stream:error('invalid-namespace')). +-define(INVALID_XML_ERR, exmpp_stream:error('xml-not-well-formed')). +-define(HOST_UNKNOWN_ERR, exmpp_stream:error('host-unknown')). +-define(SERRT_CONFLICT, exmpp_stream:error('conflict')). +-define(POLICY_VIOLATION_ERR(Lang, Text), + exmpp_stream:error('policy-violation', {Lang, Text})). + +-define(INVALID_FROM, exmpp_stream:error('invalid-from')). + -define(STANZA_ERROR(NS, Condition), exmpp_xml:xmlel_to_xmlelement(exmpp_stanza:error(NS, Condition), [?NS_JABBER_CLIENT], [{?NS_XMPP, "stream"}])). @@ -174,6 +193,11 @@ init([{SockMod, Socket}, Opts]) -> {value, {_, S}} -> S; _ -> none end, + XMLSocket = + case lists:keysearch(xml_socket, 1, Opts) of + {value, {_, XS}} -> XS; + _ -> false + end, Zlib = lists:member(zlib, Opts), StartTLS = lists:member(starttls, Opts), StartTLSRequired = lists:member(starttls_required, Opts), @@ -203,6 +227,7 @@ init([{SockMod, Socket}, Opts]) -> {ok, wait_for_stream, #state{socket = Socket1, sockmod = SockMod, socket_monitor = SocketMonitor, + xml_socket = XMLSocket, zlib = Zlib, tls = TLS, tls_required = StartTLSRequired, @@ -248,7 +273,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> exmpp_jid:make(ServerB)), case exmpp_stream:get_version(Opening) of {1, 0} -> - send_element(StateData, Header), + send_header(StateData, Server, "1.0", DefaultLang), case StateData#state.authenticated of false -> SASLState = @@ -333,6 +358,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> end end; _ -> + send_header(StateData, Server, "", DefaultLang), if (not StateData#state.tls_enabled) and StateData#state.tls_required -> @@ -340,6 +366,7 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> exmpp_xml:append_child(Header, exmpp_stream:error('policy-violation', {"en", "Use of STARTTLS required"}))), + send_trailer(StateData), {stop, normal, StateData}; true -> send_element(StateData, Header), @@ -350,16 +377,15 @@ wait_for_stream({xmlstreamstart, #xmlel{ns = NS} = Opening}, StateData) -> end end; _ -> - Header2 = exmpp_stream:set_initiating_entity(Header, - ?MYNAME), - send_element(StateData, exmpp_xml:append_child(Header2, - exmpp_stream:error('host-unknown'))), + send_header(StateData, ?MYNAME, "", DefaultLang), + send_element(StateData, ?HOST_UNKNOWN_ERR), + send_trailer(StateData), {stop, normal, StateData} end; _ -> - Header2 = exmpp_stream:set_initiating_entity(Header, ?MYNAME), - send_element(StateData, exmpp_xml:append_child(Header2, - exmpp_stream:error('invalid-namespace'))), + send_header(StateData, ?MYNAME, "", DefaultLang), + send_element(StateData, ?INVALID_NS_ERR), + send_trailer(StateData), {stop, normal, StateData} end; @@ -367,21 +393,19 @@ wait_for_stream(timeout, StateData) -> {stop, normal, StateData}; wait_for_stream({xmlstreamelement, _}, StateData) -> - send_element(StateData, exmpp_stream:error('xml-not-well-formed')), - send_element(StateData, exmpp_stream:closing()), + send_element(StateData, ?INVALID_XML_ERR), + send_trailer(StateData), {stop, normal, StateData}; wait_for_stream({xmlstreamend, _}, StateData) -> - send_element(StateData, exmpp_stream:error('xml-not-well-formed')), - send_element(StateData, exmpp_stream:closing()), + send_element(StateData, ?INVALID_XML_ERR), + send_trailer(StateData), {stop, normal, StateData}; wait_for_stream({xmlstreamerror, _}, StateData) -> - Header = exmpp_stream:opening_reply(?MYNAME, 'jabber:client', "1.0", - "none"), - Header1 = exmpp_xml:append_child(Header, - exmpp_stream:error('xml-not-well-formed')), - send_element(StateData, Header1), + send_header(StateData, ?MYNAME, "1.0", ""), + send_element(StateData, ?INVALID_XML_ERR), + send_trailer(StateData), {stop, normal, StateData}; wait_for_stream(closed, StateData) -> @@ -495,12 +519,12 @@ wait_for_auth(timeout, StateData) -> {stop, normal, StateData}; wait_for_auth({xmlstreamend, _Name}, StateData) -> - send_element(StateData, exmpp_stream:closing()), + send_trailer(StateData), {stop, normal, StateData}; wait_for_auth({xmlstreamerror, _}, StateData) -> - send_element(StateData, exmpp_stream:error('xml-not-well-formed')), - send_element(StateData, exmpp_stream:closing()), + send_element(StateData, ?INVALID_XML_ERR), + send_trailer(StateData), {stop, normal, StateData}; wait_for_auth(closed, StateData) -> @@ -604,9 +628,10 @@ wait_for_feature_request({xmlstreamelement, #xmlel{ns = NS, name = Name} = El}, _ -> if (SockMod == gen_tcp) and TLSRequired -> + Lang = StateData#state.lang, send_element(StateData, exmpp_stream:error( - 'policy-violation', {"en", "Use of STARTTLS required"})), - send_element(StateData, exmpp_stream:closing()), + 'policy-violation', {Lang, "Use of STARTTLS required"})), + send_trailer(StateData), {stop, normal, StateData}; true -> process_unauthenticated_stanza(StateData, El), @@ -619,11 +644,12 @@ wait_for_feature_request(timeout, StateData) -> wait_for_feature_request({xmlstreamend, _Name}, StateData) -> send_element(StateData, exmpp_stream:closing()), + send_trailer(StateData), {stop, normal, StateData}; wait_for_feature_request({xmlstreamerror, _}, StateData) -> - send_element(StateData, exmpp_stream:error('xml-not-well-formed')), - send_element(StateData, exmpp_stream:closing()), + send_element(StateData, ?INVALID_XML_ERR), + send_trailer(StateData), {stop, normal, StateData}; wait_for_feature_request(closed, StateData) -> @@ -678,12 +704,12 @@ wait_for_sasl_response(timeout, StateData) -> {stop, normal, StateData}; wait_for_sasl_response({xmlstreamend, _Name}, StateData) -> - send_element(StateData, exmpp_stream:closing()), + send_trailer(StateData), {stop, normal, StateData}; wait_for_sasl_response({xmlstreamerror, _}, StateData) -> - send_element(StateData, exmpp_stream:error('xml-not-well-formed')), - send_element(StateData, exmpp_stream:closing()), + send_element(StateData, ?INVALID_XML_ERR), + send_trailer(StateData), {stop, normal, StateData}; wait_for_sasl_response(closed, StateData) -> @@ -717,12 +743,12 @@ wait_for_bind(timeout, StateData) -> {stop, normal, StateData}; wait_for_bind({xmlstreamend, _Name}, StateData) -> - send_element(StateData, exmpp_stream:closing()), + send_trailer(StateData), {stop, normal, StateData}; wait_for_bind({xmlstreamerror, _}, StateData) -> - send_element(StateData, exmpp_stream:error('xml-not-well-formed')), - send_element(StateData, exmpp_stream:closing()), + send_element(StateData, ?INVALID_XML_ERR), + send_trailer(StateData), {stop, normal, StateData}; wait_for_bind(closed, StateData) -> @@ -791,12 +817,12 @@ wait_for_session(timeout, StateData) -> {stop, normal, StateData}; wait_for_session({xmlstreamend, _Name}, StateData) -> - send_element(StateData, exmpp_stream:closing()), + send_trailer(StateData), {stop, normal, StateData}; wait_for_session({xmlstreamerror, _}, StateData) -> - send_element(StateData, exmpp_stream:error('xml-not-well-formed')), - send_element(StateData, exmpp_stream:closing()), + send_element(StateData, ?INVALID_XML_ERR), + send_trailer(StateData), {stop, normal, StateData}; wait_for_session(closed, StateData) -> @@ -804,10 +830,11 @@ wait_for_session(closed, StateData) -> session_established({xmlstreamelement, El}, StateData) -> + %% Check 'from' attribute in stanza RFC 3920 Section 9.1.2 case check_from(El, StateData#state.jid) of 'invalid-from' -> - send_element(StateData, exmpp_stream:error('invalid-from')), - send_element(StateData, exmpp_stream:closing()), + send_element(StateData, ?INVALID_FROM), + send_trailer(StateData), {stop, normal, StateData}; _ -> session_established2(El, StateData) @@ -823,12 +850,17 @@ session_established(timeout, StateData) -> fsm_next_state(session_established, StateData); session_established({xmlstreamend, _Name}, StateData) -> - send_element(StateData, exmpp_stream:closing()), + send_trailer(StateData), + {stop, normal, StateData}; + +session_established({xmlstreamerror, "XML stanza is too big" = E}, StateData) -> + send_element(StateData, ?POLICY_VIOLATION_ERR(StateData#state.lang, E)), + send_trailer(StateData), {stop, normal, StateData}; session_established({xmlstreamerror, _}, StateData) -> - send_element(StateData, exmpp_stream:error('xml-not-well-formed')), - send_element(StateData, exmpp_stream:closing()), + send_element(StateData, ?INVALID_XML_ERR), + send_trailer(StateData), {stop, normal, StateData}; session_established(closed, StateData) -> @@ -1002,8 +1034,10 @@ handle_info({send_text, Text}, StateName, StateData) -> ejabberd_hooks:run(c2s_loop_debug, [Text]), fsm_next_state(StateName, StateData); handle_info(replaced, _StateName, StateData) -> - send_element(StateData, exmpp_stream:error('conflict')), - send_element(StateData, exmpp_stream:closing()), + _Lang = StateData#state.lang, + send_element(StateData, + ?SERRT_CONFLICT), %% (Lang, "Replaced by new connection")), + send_trailer(StateData), {stop, normal, StateData#state{authenticated = replaced}}; %% Process Packets that are to be send to the user handle_info({route, From, To, Packet}, StateName, StateData) -> @@ -1194,9 +1228,9 @@ handle_info({route, From, To, Packet}, StateName, StateData) -> if Pass == exit -> %% When Pass==exit, NewState contains a string instead of a #state{} - Lang = StateData#state.lang, - catch send_element(StateData, exmpp_stream:error('undefined-condition', {Lang, NewState})), - catch send_element(StateData, exmpp_stream:closing()), + _Lang = StateData#state.lang, + send_element(StateData, ?SERRT_CONFLICT), %% (Lang, NewState)), + send_trailer(StateData), {stop, normal, StateData}; Pass -> Attrs2 = exmpp_stanza:set_sender_in_attrs(NewAttrs, From), @@ -1292,9 +1326,60 @@ send_text(StateData, Text) -> send_element(StateData, #xmlel{ns = ?NS_XMPP, name = 'stream'} = El) -> send_text(StateData, exmpp_stream:to_iolist(El)); +send_element(StateData, El) when StateData#state.xml_socket -> + (StateData#state.sockmod):send_xml(StateData#state.socket, + {xmlstreamelement, El}); send_element(StateData, El) -> send_text(StateData, exmpp_stanza:to_iolist(El)). +send_header(StateData, Server, Version, Lang) + when StateData#state.xml_socket -> + VersionAttr = + case Version of + "" -> []; + _ -> [{"version", Version}] + end, + LangAttr = + case Lang of + "" -> []; + _ -> [{"xml:lang", Lang}] + end, + Header = + {xmlstreamstart, + "stream:stream", + VersionAttr ++ + LangAttr ++ + [{"xmlns", "jabber:client"}, + {"xmlns:stream", "http://etherx.jabber.org/streams"}, + {"id", StateData#state.streamid}, + {"from", Server}]}, + (StateData#state.sockmod):send_xml( + StateData#state.socket, Header); +send_header(StateData, Server, Version, Lang) -> + VersionStr = + case Version of + "" -> ""; + _ -> [" version='", Version, "'"] + end, + LangStr = + case Lang of + "" -> ""; + _ -> [" xml:lang='", Lang, "'"] + end, + Header = io_lib:format(?STREAM_HEADER, + [StateData#state.streamid, + Server, + VersionStr, + LangStr]), + send_text(StateData, Header). + +send_trailer(StateData) when StateData#state.xml_socket -> + (StateData#state.sockmod):send_xml( + StateData#state.socket, + {xmlstreamend, "stream:stream"}); +send_trailer(StateData) -> + send_element(StateData, exmpp_stream:closing()). + new_id() -> randoms:get_string(). diff --git a/src/ejabberd_receiver.erl b/src/ejabberd_receiver.erl index 8d13eb497..6cfc3ae36 100644 --- a/src/ejabberd_receiver.erl +++ b/src/ejabberd_receiver.erl @@ -198,7 +198,7 @@ handle_cast(_Msg, State) -> handle_info({Tag, _TCPSocket, Data}, #state{socket = Socket, sock_mod = SockMod} = State) - when (Tag == tcp) or (Tag == ssl) -> + when (Tag == tcp) or (Tag == ssl) or (Tag == ejabberd_xml) -> case SockMod of tls -> case tls:recv_data(Socket, Data) of @@ -288,6 +288,25 @@ activate_socket(#state{socket = Socket, ok end. +%% Data processing for connectors directly generating xmlelement in +%% Erlang data structure. +%% WARNING: Shaper does not work with Erlang data structure. +process_data([], State) -> + activate_socket(State), + State; +process_data([Element|Els], #state{c2s_pid = C2SPid} = State) + when element(1, Element) == xmlelement; + element(1, Element) == xmlstreamstart; + element(1, Element) == xmlstreamelement; + element(1, Element) == xmlstreamend -> + if + C2SPid == undefined -> + State; + true -> + catch gen_fsm:send_event(C2SPid, element_wrapper(Element)), + process_data(Els, State) + end; +%% Data processing for connectors receivind data as string. process_data(Data, #state{xml_stream_state = XMLStreamState, shaper_state = ShaperState, @@ -310,6 +329,16 @@ process_data(Data, {State#state{xml_stream_state = XMLStreamState1, shaper_state = NewShaperState}, HibTimeout}. +%% Element coming from XML parser are wrapped inside xmlstreamelement +%% When we receive directly xmlelement tuple (from a socket module +%% speaking directly Erlang XML), we wrap it inside the same +%% xmlstreamelement coming from the XML parser. +element_wrapper(XMLElement) + when element(1, XMLElement) == xmlelement -> + {xmlstreamelement, XMLElement}; +element_wrapper(Element) -> + Element. + close_stream(undefined) -> ok; close_stream(XMLStreamState) -> diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl index 566ee1e43..d629a77d9 100644 --- a/src/ejabberd_socket.erl +++ b/src/ejabberd_socket.erl @@ -37,6 +37,7 @@ compress/2, reset_stream/1, send/2, + send_xml/2, change_shaper/2, monitor/1, get_sockmod/1, @@ -62,10 +63,18 @@ start(Module, SockMod, Socket, Opts) -> {value, {_, Size}} -> Size; _ -> infinity end, - Receiver = ejabberd_receiver:start(Socket, SockMod, none, MaxStanzaSize), + {ReceiverMod, Receiver, RecRef} = + case catch SockMod:custom_receiver(Socket) of + {receiver, RecMod, RecPid} -> + {RecMod, RecPid, RecMod}; + _ -> + RecPid = ejabberd_receiver:start( + Socket, SockMod, none, MaxStanzaSize), + {ejabberd_receiver, RecPid, RecPid} + end, SocketData = #socket_state{sockmod = SockMod, socket = Socket, - receiver = Receiver}, + receiver = RecRef}, case Module:start({?MODULE, SocketData}, Opts) of {ok, Pid} -> case SockMod:controlling_process(Socket, Receiver) of @@ -74,7 +83,7 @@ start(Module, SockMod, Socket, Opts) -> {error, _Reason} -> SockMod:close(Socket) end, - ejabberd_receiver:become_controller(Receiver, Pid); + ReceiverMod:become_controller(Receiver, Pid); {error, _Reason} -> SockMod:close(Socket) end; @@ -143,18 +152,33 @@ compress(SocketData, Data) -> send(SocketData, Data), SocketData#socket_state{socket = ZlibSocket, sockmod = ejabberd_zlib}. -reset_stream(SocketData) -> - ejabberd_receiver:reset_stream(SocketData#socket_state.receiver). +reset_stream(SocketData) when is_pid(SocketData#socket_state.receiver) -> + ejabberd_receiver:reset_stream(SocketData#socket_state.receiver); +reset_stream(SocketData) when is_atom(SocketData#socket_state.receiver) -> + (SocketData#socket_state.receiver):reset_stream( + SocketData#socket_state.socket). send(SocketData, Data) -> catch (SocketData#socket_state.sockmod):send( SocketData#socket_state.socket, Data). -change_shaper(SocketData, Shaper) -> - ejabberd_receiver:change_shaper(SocketData#socket_state.receiver, Shaper). +send_xml(SocketData, Data) -> + catch (SocketData#socket_state.sockmod):send_xml( + SocketData#socket_state.socket, Data). -monitor(SocketData) -> - erlang:monitor(process, SocketData#socket_state.receiver). +change_shaper(SocketData, Shaper) + when is_pid(SocketData#socket_state.receiver) -> + ejabberd_receiver:change_shaper(SocketData#socket_state.receiver, Shaper); +change_shaper(SocketData, Shaper) + when is_atom(SocketData#socket_state.receiver) -> + (SocketData#socket_state.receiver):change_shaper( + SocketData#socket_state.socket, Shaper). + +monitor(SocketData) when is_pid(SocketData#socket_state.receiver) -> + erlang:monitor(process, SocketData#socket_state.receiver); +monitor(SocketData) when is_atom(SocketData#socket_state.receiver) -> + (SocketData#socket_state.receiver):monitor( + SocketData#socket_state.socket). get_sockmod(SocketData) -> SocketData#socket_state.sockmod. diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index e37ed4307..885ac9c68 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -4,29 +4,11 @@ %%% Purpose : Implements XMPP over BOSH (XEP-0205) (formerly known as %%% HTTP Binding) %%% Created : 21 Sep 2005 by Stefan Strigler -%%% -%%% -%%% ejabberd, Copyright (C) 2002-2009 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., 59 Temple Place, Suite 330, Boston, MA -%%% 02111-1307 USA -%%% +%%% Modified: may 2009 by Mickael Remond, Alexey Schepin +%%% Id : $Id: ejabberd_http_bind.erl 953 2009-05-07 10:40:40Z alexey $ %%%---------------------------------------------------------------------- -module(ejabberd_http_bind). --author('steve@zeank.in-berlin.de'). -behaviour(gen_fsm). @@ -39,15 +21,19 @@ handle_info/3, terminate/3, send/2, - setopts/2, + send_xml/2, sockname/1, peername/1, + setopts/2, controlling_process/2, + become_controller/2, + custom_receiver/1, + reset_stream/1, + change_shaper/2, + monitor/1, close/1, process_request/2]). --define(ejabberd_debug, true). - -include("ejabberd.hrl"). -include("jlib.hrl"). -include("ejabberd_http.hrl"). @@ -62,7 +48,6 @@ %% http binding request -record(hbr, {rid, key, - in, out}). -record(state, {id, @@ -70,8 +55,10 @@ key, socket, output = "", - input = "", + input = queue:new(), waiting_input = false, + shaper_state, + shaper_timer, last_receiver, last_poll, http_receiver, @@ -79,22 +66,30 @@ ctime = 0, timer, pause=0, - unprocessed_req_list = [], % list of request that have been delayed for proper reordering + unprocessed_req_list = [], % list of request that have been delayed for proper reordering: {Request, PID} req_list = [], % list of requests (cache) max_inactivity, + max_pause, ip = ?NULL_PEER }). +%% Internal request format: +-record(http_put, {rid, + attrs, + payload, + payload_size, + hold, + stream, + ip}). %%-define(DBGFSM, true). - -ifdef(DBGFSM). -define(FSMOPTS, [{debug, [trace]}]). -else. -define(FSMOPTS, []). -endif. --define(BOSH_VERSION, "1.6"). +-define(BOSH_VERSION, "1.8"). -define(NS_CLIENT, "jabber:client"). -define(NS_BOSH, "urn:xmpp:xbosh"). -define(NS_HTTP_BIND, "http://jabber.org/protocol/httpbind"). @@ -131,6 +126,9 @@ start_link(Sid, Key, IP) -> send({http_bind, FsmRef, _IP}, Packet) -> gen_fsm:sync_send_all_state_event(FsmRef, {send, Packet}). +send_xml({http_bind, FsmRef, _IP}, Packet) -> + gen_fsm:sync_send_all_state_event(FsmRef, {send_xml, Packet}). + setopts({http_bind, FsmRef, _IP}, Opts) -> case lists:member({active, once}, Opts) of true -> @@ -142,6 +140,21 @@ setopts({http_bind, FsmRef, _IP}, Opts) -> controlling_process(_Socket, _Pid) -> ok. +custom_receiver({http_bind, FsmRef, _IP}) -> + {receiver, ?MODULE, FsmRef}. + +become_controller(FsmRef, C2SPid) -> + gen_fsm:send_all_state_event(FsmRef, {become_controller, C2SPid}). + +reset_stream({http_bind, _FsmRef, _IP}) -> + ok. + +change_shaper({http_bind, FsmRef, _IP}, Shaper) -> + gen_fsm:send_all_state_event(FsmRef, {change_shaper, Shaper}). + +monitor({http_bind, FsmRef, _IP}) -> + erlang:monitor(process, FsmRef). + close({http_bind, FsmRef, _IP}) -> catch gen_fsm:sync_send_all_state_event(FsmRef, {stop, close}). @@ -151,8 +164,19 @@ sockname(_Socket) -> peername({http_bind, _FsmRef, IP}) -> {ok, IP}. + +%% Entry point for data coming from client through ejabberd HTTP server: process_request(Data, IP) -> - case catch parse_request(Data) of + Opts1 = ejabberd_c2s_config:get_c2s_limits(), + Opts = [{xml_socket, true} | Opts1], + MaxStanzaSize = + case lists:keysearch(max_stanza_size, 1, Opts) of + {value, {_, Size}} -> Size; + _ -> infinity + end, + PayloadSize = iolist_size(Data), + case catch parse_request(Data, PayloadSize, MaxStanzaSize) of + %% No existing session: {ok, {"", Rid, Attrs, Payload}} -> case xml:get_attr_s("to",Attrs) of "" -> @@ -169,11 +193,13 @@ process_request(Data, IP) -> "condition='internal-server-error' " "xmlns='" ++ ?NS_HTTP_BIND ++ "'>BOSH module not started - handle_session_start(Pid, XmppDomain, Sid, Rid, Attrs, Payload, IP) + handle_session_start( + Pid, XmppDomain, Sid, Rid, Attrs, + Payload, PayloadSize, IP) end end; + %% Existing session {ok, {Sid, Rid, Attrs, Payload1}} -> - %% old session StreamStart = case xml:get_attr_s("xmpp:restart",Attrs) of "true" -> @@ -184,17 +210,21 @@ process_request(Data, IP) -> Payload2 = case xml:get_attr_s("type",Attrs) of "terminate" -> %% close stream - Payload1 ++ ""; + Payload1 ++ [{xmlstreamend, "stream:stream"}]; _ -> Payload1 end, - handle_http_put(Sid, Rid, Attrs, Payload2, StreamStart, IP); + handle_http_put(Sid, Rid, Attrs, Payload2, PayloadSize, + StreamStart, IP); + {error, size_limit} -> + {413, ?HEADER, "Request Too Large"}; _ -> - ?ERROR_MSG("Received bad request: ~p", [Data]), + ?DEBUG("Received bad request: ~p", [Data]), {400, ?HEADER, ""} end. -handle_session_start(Pid, XmppDomain, Sid, Rid, Attrs, Payload, IP) -> +handle_session_start(Pid, XmppDomain, Sid, Rid, Attrs, + Payload, PayloadSize, IP) -> ?DEBUG("got pid: ~p", [Pid]), Wait = case string:to_integer(xml:get_attr_s("wait",Attrs)) of {error, _} -> @@ -238,7 +268,7 @@ handle_session_start(Pid, XmppDomain, Sid, Rid, Attrs, Payload, IP) -> version = Version }) end), - handle_http_put(Sid, Rid, Attrs, Payload, true, IP). + handle_http_put(Sid, Rid, Attrs, Payload, PayloadSize, true, IP). %%%---------------------------------------------------------------------- %%% Callback functions from gen_fsm @@ -260,58 +290,46 @@ init([Sid, Key, IP]) -> %% each connector. The default behaviour should be however to use %% the default c2s restrictions if not defined for the current %% connector. - Opts = ejabberd_c2s_config:get_c2s_limits(), + Opts1 = ejabberd_c2s_config:get_c2s_limits(), + Opts = [{xml_socket, true} | Opts1], + Shaper = none, + ShaperState = shaper:new(Shaper), Socket = {http_bind, self(), IP}, ejabberd_socket:start(ejabberd_c2s, ?MODULE, Socket, Opts), Timer = erlang:start_timer(?MAX_INACTIVITY, self(), []), {ok, loop, #state{id = Sid, key = Key, socket = Socket, + shaper_state = ShaperState, max_inactivity = ?MAX_INACTIVITY, + max_pause = ?MAX_PAUSE, timer = Timer}}. -%%---------------------------------------------------------------------- -%% Func: StateName/2 -%% Returns: {next_state, NextStateName, NextStateData} | -%% {next_state, NextStateName, NextStateData, Timeout} | -%% {stop, Reason, NewStateData} -%%---------------------------------------------------------------------- - - -%%---------------------------------------------------------------------- -%% 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({activate, From}, StateName, StateData) -> +handle_event({become_controller, C2SPid}, StateName, StateData) -> case StateData#state.input of - "" -> + cancel -> {next_state, StateName, StateData#state{ - waiting_input = {From, ok}}}; + waiting_input = C2SPid}}; Input -> - Receiver = From, - Receiver ! {tcp, StateData#state.socket, list_to_binary(Input)}, + lists:foreach( + fun(Event) -> + C2SPid ! Event + end, queue:to_list(Input)), {next_state, StateName, StateData#state{ - input = "", - waiting_input = false, - last_receiver = Receiver}} + input = queue:new(), + waiting_input = C2SPid}} end; +handle_event({change_shaper, Shaper}, StateName, StateData) -> + NewShaperState = shaper:new(Shaper), + {next_state, StateName, StateData#state{shaper_state = NewShaperState}}; handle_event(_Event, StateName, StateData) -> {next_state, StateName, StateData}. @@ -324,37 +342,34 @@ handle_event(_Event, StateName, StateData) -> %% {stop, Reason, NewStateData} | %% {stop, Reason, Reply, NewStateData} %%---------------------------------------------------------------------- -handle_sync_event({send, Packet}, _From, StateName, StateData) -> - Output = [StateData#state.output | Packet], - if - StateData#state.http_receiver /= undefined -> - cancel_timer(StateData#state.timer), - Timer = if - StateData#state.pause > 0 -> - erlang:start_timer( - StateData#state.pause*1000, self(), []); - true -> - erlang:start_timer( - StateData#state.max_inactivity, self(), []) - end, - HTTPReply = case Output of - [[]| OutPacket] -> - {ok, OutPacket}; - _ -> - {ok, Output} - end, - gen_fsm:reply(StateData#state.http_receiver, HTTPReply), - cancel_timer(StateData#state.wait_timer), - Reply = ok, - {reply, Reply, StateName, - StateData#state{output = [], - http_receiver = undefined, - wait_timer = undefined, - timer = Timer}}; - true -> - Reply = ok, - {reply, Reply, StateName, StateData#state{output = Output}} - end; +handle_sync_event({send_xml, Packet}, _From, StateName, + #state{http_receiver = undefined} = StateData) -> + Output = [Packet | StateData#state.output], + Reply = ok, + {reply, Reply, StateName, StateData#state{output = Output}}; +handle_sync_event({send_xml, Packet}, _From, StateName, StateData) -> + Output = [Packet | StateData#state.output], + cancel_timer(StateData#state.timer), + Timer = set_inactivity_timer(StateData#state.pause, + StateData#state.max_inactivity), + HTTPReply = {ok, Output}, + gen_fsm:reply(StateData#state.http_receiver, HTTPReply), + cancel_timer(StateData#state.wait_timer), + Rid = StateData#state.rid, + ReqList = [#hbr{rid = Rid, + key = StateData#state.key, + out = Output + } | + [El || El <- StateData#state.req_list, + El#hbr.rid /= Rid ] + ], + Reply = ok, + {reply, Reply, StateName, + StateData#state{output = [], + http_receiver = undefined, + req_list = ReqList, + wait_timer = undefined, + timer = Timer}}; handle_sync_event({stop,close}, _From, _StateName, StateData) -> Reply = ok, @@ -363,130 +378,82 @@ handle_sync_event({stop,stream_closed}, _From, _StateName, StateData) -> Reply = ok, {stop, normal, Reply, StateData}; handle_sync_event({stop,Reason}, _From, _StateName, StateData) -> - ?DEBUG("Closing bind session ~p - Reason: ~p", [StateData#state.id, Reason]), + ?ERROR_MSG("Closing bind session ~p - Reason: ~p", [StateData#state.id, Reason]), Reply = ok, {stop, normal, Reply, StateData}; - %% HTTP PUT: Receive packets from the client -handle_sync_event({http_put, Rid, Attrs, _Payload, Hold, _StreamTo, _IP}=Request, - _From, StateName, StateData) -> - %% Check if Rid valid - RidAllow = - case StateData#state.rid of - none -> - %% First request - nothing saved so far - {true, 0}; - OldRid -> - ?DEBUG("state.rid/cur rid: ~p/~p", [OldRid, Rid]), - if - %% We did not miss any packet, we can process it immediately: - Rid == OldRid + 1 -> - case catch list_to_integer( - xml:get_attr_s("pause", Attrs)) of - {'EXIT', _} -> - {true, 0}; - Pause1 when Pause1 =< ?MAX_PAUSE -> - ?DEBUG("got pause: ~p", [Pause1]), - {true, Pause1}; - _ -> - {true, 0} - end; - %% We have missed packets, we need to cached it to process it later on: - (OldRid < Rid) and - (Rid =< (OldRid + Hold + 1)) -> - buffer; - (Rid =< OldRid) and - (Rid > OldRid - Hold - 1) -> - repeat; - true -> - false - end +handle_sync_event(#http_put{rid = Rid}, + _From, StateName, StateData) + when StateData#state.shaper_timer /= undefined -> + Pause = + case erlang:read_timer(StateData#state.shaper_timer) of + false -> + 0; + P -> P end, + Reply = {wait, Pause}, + ?DEBUG("Shaper timer for RID ~p: ~p", [Rid, Reply]), + {reply, Reply, StateName, StateData}; - %% Check if Rid is in sequence or out of sequence: - case RidAllow of - buffer -> - ?DEBUG("Buffered request: ~p", [Request]), - %% Request is out of sequence: - PendingRequests = StateData#state.unprocessed_req_list, - %% In case an existing RID was already buffered: - Requests = lists:keydelete(Rid, 2, PendingRequests), - {reply, ok, StateName, StateData#state{unprocessed_req_list=[Request|Requests]}}; - _ -> - %% Request is in sequence: - process_http_put(Request, StateName, StateData, RidAllow) - end; +handle_sync_event(#http_put{rid = _Rid, attrs = _Attrs, + payload_size = PayloadSize, + hold = _Hold} = Request, + _From, StateName, StateData) -> + ?DEBUG("New request: ~p",[Request]), + %% Updating trafic shaper + {NewShaperState, NewShaperTimer} = + update_shaper(StateData#state.shaper_state, PayloadSize), + + handle_http_put_event(Request, StateName, + StateData#state{shaper_state = NewShaperState, + shaper_timer = NewShaperTimer}); %% HTTP GET: send packets to the client handle_sync_event({http_get, Rid, Wait, Hold}, From, StateName, StateData) -> %% setup timer - if - StateData#state.http_receiver /= undefined -> - gen_fsm:reply(StateData#state.http_receiver, {ok, empty}); - true -> - ok - end, + send_receiver_reply(StateData#state.http_receiver, {ok, empty}), cancel_timer(StateData#state.wait_timer), - {TMegSec, TSec, TMSec} = now(), - TNow = (TMegSec * 1000000 + TSec) * 1000000 + TMSec, + TNow = tnow(), if (Hold > 0) and - (StateData#state.output == "") and + (StateData#state.output == []) and ((TNow - StateData#state.ctime) < (Wait*1000*1000)) and (StateData#state.rid == Rid) and - (StateData#state.input /= "cancel") and + (StateData#state.input /= cancel) and (StateData#state.pause == 0) -> WaitTimer = erlang:start_timer(Wait * 1000, self(), []), + %% MR: Not sure we should cancel the state timer here. cancel_timer(StateData#state.timer), {next_state, StateName, StateData#state{ http_receiver = From, wait_timer = WaitTimer, timer = undefined}}; - (StateData#state.input == "cancel") -> + (StateData#state.input == cancel) -> cancel_timer(StateData#state.timer), - Timer = if - StateData#state.pause > 0 -> - erlang:start_timer( - StateData#state.pause*1000, self(), []); - true -> - erlang:start_timer( - StateData#state.max_inactivity, self(), []) - end, + Timer = set_inactivity_timer(StateData#state.pause, + StateData#state.max_inactivity), Reply = {ok, cancel}, {reply, Reply, StateName, StateData#state{ - input = "", + input = queue:new(), http_receiver = undefined, wait_timer = undefined, timer = Timer}}; true -> cancel_timer(StateData#state.timer), - Timer = if - StateData#state.pause > 0 -> - erlang:start_timer( - StateData#state.pause*1000, self(), []); - true -> - erlang:start_timer( - StateData#state.max_inactivity, self(), []) - end, - case StateData#state.output of - [[]| OutPacket] -> - Reply = {ok, OutPacket}; - _ -> - Reply = {ok, StateData#state.output} - end, + Timer = set_inactivity_timer(StateData#state.pause, + StateData#state.max_inactivity), + Reply = {ok, StateData#state.output}, %% save request - ReqList = [#hbr{rid=Rid, - key=StateData#state.key, - in=StateData#state.input, - out=StateData#state.output + ReqList = [#hbr{rid = Rid, + key = StateData#state.key, + out = StateData#state.output } | [El || El <- StateData#state.req_list, El#hbr.rid /= Rid ] ], {reply, Reply, StateName, StateData#state{ - input = "", - output = "", + output = [], http_receiver = undefined, wait_timer = undefined, timer = Timer, @@ -510,6 +477,7 @@ code_change(_OldVsn, StateName, StateData, _Extra) -> %% {next_state, NextStateName, NextStateData, Timeout} | %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- +%% We reached the max_inactivity timeout: handle_info({timeout, Timer, _}, _StateName, #state{id=SID, timer = Timer} = StateData) -> ?WARNING_MSG("Session timeout. Closing the HTTP bind session: ~p", [SID]), @@ -520,23 +488,30 @@ handle_info({timeout, WaitTimer, _}, StateName, if StateData#state.http_receiver /= undefined -> cancel_timer(StateData#state.timer), - Timer = if - StateData#state.pause > 0 -> - erlang:start_timer( - StateData#state.pause*1000, self(), []); - true -> - erlang:start_timer( - StateData#state.max_inactivity, self(), []) - end, + Timer = set_inactivity_timer(StateData#state.pause, + StateData#state.max_inactivity), gen_fsm:reply(StateData#state.http_receiver, {ok, empty}), + Rid = StateData#state.rid, + ReqList = [#hbr{rid = Rid, + key = StateData#state.key, + out = [] + } | + [El || El <- StateData#state.req_list, + El#hbr.rid /= Rid ] + ], {next_state, StateName, StateData#state{http_receiver = undefined, + req_list = ReqList, wait_timer = undefined, timer = Timer}}; true -> {next_state, StateName, StateData} end; +handle_info({timeout, ShaperTimer, _}, StateName, + #state{shaper_timer = ShaperTimer} = StateData) -> + {next_state, StateName, StateData#state{shaper_timer = undefined}}; + handle_info(_, StateName, StateData) -> {next_state, StateName, StateData}. @@ -551,19 +526,12 @@ terminate(_Reason, _StateName, StateData) -> fun() -> mnesia:delete({http_bind, StateData#state.id}) end), - if - StateData#state.http_receiver /= undefined -> - gen_fsm:reply(StateData#state.http_receiver, {ok, terminate}); - true -> - ok - end, + send_receiver_reply(StateData#state.http_receiver, {ok, terminate}), case StateData#state.waiting_input of false -> - case StateData#state.last_receiver of - undefined -> ok; - Receiver -> Receiver ! {tcp_closed, StateData#state.socket} - end; - {Receiver, _Tag} -> Receiver ! {tcp_closed, StateData#state.socket} + ok; + C2SPid -> + gen_fsm:send_event(C2SPid, closed) end, ok. @@ -572,8 +540,47 @@ terminate(_Reason, _StateName, StateData) -> %%%---------------------------------------------------------------------- %% PUT / Get processing: -process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, +handle_http_put_event(#http_put{rid = Rid, attrs = Attrs, + hold = Hold} = Request, + StateName, StateData) -> + ?DEBUG("New request: ~p",[Request]), + %% Check if Rid valid + RidAllow = rid_allow(StateData#state.rid, Rid, Attrs, Hold, + StateData#state.max_pause), + + %% Check if Rid is in sequence or out of sequence: + case RidAllow of + buffer -> + ?DEBUG("Buffered request: ~p", [Request]), + %% Request is out of sequence: + PendingRequests = StateData#state.unprocessed_req_list, + %% In case an existing RID was already buffered: + Requests = lists:keydelete(Rid, 2, PendingRequests), + ReqList = [#hbr{rid = Rid, + key = StateData#state.key, + out = [] + } | + [El || El <- StateData#state.req_list, + El#hbr.rid > (Rid - 1 - Hold)] + ], + ?DEBUG("reqlist: ~p", [ReqList]), + UnprocessedReqList = [Request | Requests], + cancel_timer(StateData#state.timer), + Timer = set_inactivity_timer(0, StateData#state.max_inactivity), + {reply, buffered, StateName, + StateData#state{unprocessed_req_list = UnprocessedReqList, + req_list = ReqList, + timer = Timer}}; + _ -> + %% Request is in sequence: + process_http_put(Request, StateName, StateData, RidAllow) + end. + +process_http_put(#http_put{rid = Rid, attrs = Attrs, payload = Payload, + hold = Hold, stream = StreamTo, + ip = IP} = Request, StateName, StateData, RidAllow) -> + ?DEBUG("Actually processing request: ~p", [Request]), %% Check if key valid Key = xml:get_attr_s("key", Attrs), NewKey = xml:get_attr_s("newkey", Attrs), @@ -599,16 +606,15 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, end end end, - {TMegSec, TSec, TMSec} = now(), - TNow = (TMegSec * 1000000 + TSec) * 1000000 + TMSec, + TNow = tnow(), LastPoll = if - Payload == "" -> + Payload == [] -> TNow; true -> 0 end, if - (Payload == "") and + (Payload == []) and (Hold == 0) and (TNow - StateData#state.last_poll < ?MIN_POLLING) -> Reply = {error, polling_too_frequently}, @@ -621,17 +627,15 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, repeat -> ?DEBUG("REPEATING ~p", [Rid]), Reply = case [El#hbr.out || - El <- StateData#state.req_list, + El <- StateData#state.req_list, El#hbr.rid == Rid] of [] -> {error, not_exists}; - [ [[] | Out] | _XS] -> - {repeat, Out}; [Out | _XS] -> - {repeat, Out} - end, - {reply, Reply, StateName, - StateData#state{input = "cancel", last_poll = LastPoll}}; + {repeat, lists:reverse(Out)} + end, + {reply, Reply, StateName, StateData#state{input = cancel, + last_poll = LastPoll}}; {true, Pause} -> SaveKey = if NewKey == "" -> @@ -642,30 +646,33 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, ?DEBUG(" -- SaveKey: ~s~n", [SaveKey]), %% save request - ReqList = [#hbr{rid=Rid, - key=StateData#state.key, - in=StateData#state.input, - out=StateData#state.output - } | - [El || El <- StateData#state.req_list, - El#hbr.rid < Rid, - El#hbr.rid > (Rid - 1 - Hold)] - ], + ReqList1 = + [El || El <- StateData#state.req_list, + El#hbr.rid > (Rid - 1 - Hold)], + ReqList = + case lists:keymember(Rid, #hbr.rid, ReqList1) of + true -> + ReqList1; + false -> + [#hbr{rid = Rid, + key = StateData#state.key, + out = [] + } | + ReqList1 + ] + end, ?DEBUG("reqlist: ~p", [ReqList]), %% setup next timer cancel_timer(StateData#state.timer), - Timer = if - Pause > 0 -> - erlang:start_timer( - Pause*1000, self(), []); - true -> - erlang:start_timer( - StateData#state.max_inactivity, self(), []) - end, + Timer = set_inactivity_timer(Pause, + StateData#state.max_inactivity), case StateData#state.waiting_input of false -> - Input = Payload ++ [StateData#state.input], + Input = + lists:foldl( + fun queue:in/2, + StateData#state.input, Payload), Reply = ok, process_buffered_request(Reply, StateName, StateData#state{input = Input, @@ -678,32 +685,42 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, req_list = ReqList, ip = IP }); - {Receiver, _Tag} -> - SendPacket = - case StreamTo of - {To, ""} -> - [""] - ++ Payload; - {To, Version} -> - [""] - ++ Payload; - _ -> - Payload - end, + C2SPid -> + case StreamTo of + {To, ""} -> + gen_fsm:send_event( + C2SPid, + {xmlstreamstart, "stream:stream", + [{"to", To}, + {"xmlns", ?NS_CLIENT}, + {"xmlns:stream", ?NS_STREAM}]}); + {To, Version} -> + gen_fsm:send_event( + C2SPid, + {xmlstreamstart, "stream:stream", + [{"to", To}, + {"xmlns", ?NS_CLIENT}, + {"version", Version}, + {"xmlns:stream", ?NS_STREAM}]}); + _ -> + ok + end, + MaxInactivity = get_max_inactivity(StreamTo, StateData#state.max_inactivity), - ?DEBUG("really sending now: ~s", [SendPacket]), - Receiver ! {tcp, StateData#state.socket, - list_to_binary(SendPacket)}, + MaxPause = get_max_inactivity(StreamTo, StateData#state.max_pause), + + ?DEBUG("really sending now: ~p", [Payload]), + lists:foreach( + fun({xmlstreamend, End}) -> + gen_fsm:send_event( + C2SPid, {xmlstreamend, End}); + (El) -> + gen_fsm:send_event( + C2SPid, {xmlstreamelement, El}) + end, Payload), Reply = ok, process_buffered_request(Reply, StateName, - StateData#state{waiting_input = false, - last_receiver = Receiver, - input = "", + StateData#state{input = queue:new(), rid = Rid, key = SaveKey, ctime = TNow, @@ -712,6 +729,7 @@ process_http_put({http_put, Rid, Attrs, Payload, Hold, StreamTo, IP}, last_poll = LastPoll, req_list = ReqList, max_inactivity = MaxInactivity, + max_pause = MaxPause, ip = IP }) end @@ -727,29 +745,42 @@ process_buffered_request(Reply, StateName, StateData) -> case lists:keysearch(Rid+1, 2, Requests) of {value, Request} -> ?DEBUG("Processing buffered request: ~p", [Request]), - NewRequests = Requests -- [Request], - handle_sync_event(Request, undefined, StateName, - StateData#state{unprocessed_req_list=NewRequests}); + NewRequests = lists:keydelete(Rid+1, 2, Requests), + handle_http_put_event( + Request, StateName, + StateData#state{unprocessed_req_list = NewRequests}); _ -> {reply, Reply, StateName, StateData} end. -handle_http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) -> - case http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) of +handle_http_put(Sid, Rid, Attrs, Payload, PayloadSize, StreamStart, IP) -> + case http_put(Sid, Rid, Attrs, Payload, PayloadSize, StreamStart, IP) of {error, not_exists} -> - ?DEBUG("no session associated with sid: ~p", [Sid]), + ?ERROR_MSG("no session associated with sid: ~p", [Sid]), {404, ?HEADER, ""}; {{error, Reason}, Sess} -> - ?DEBUG("Error on HTTP put. Reason: ~p", [Reason]), + ?ERROR_MSG("Error on HTTP put. Reason: ~p", [Reason]), handle_http_put_error(Reason, Sess); {{repeat, OutPacket}, Sess} -> ?DEBUG("http_put said 'repeat!' ...~nOutPacket: ~p", [OutPacket]), send_outpacket(Sess, OutPacket); + {{wait, Pause}, _Sess} -> + ?DEBUG("Trafic Shaper: Delaying request ~p", [Rid]), + timer:sleep(Pause), + %{200, ?HEADER, + % xml:element_to_string( + % {xmlelement, "body", + % [{"xmlns", ?NS_HTTP_BIND}, + % {"type", "error"}], []})}; + handle_http_put(Sid, Rid, Attrs, Payload, PayloadSize, + StreamStart, IP); + {buffered, _Sess} -> + {200, ?HEADER, ""}; {ok, Sess} -> prepare_response(Sess, Rid, Attrs, StreamStart) end. -http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) -> +http_put(Sid, Rid, Attrs, Payload, PayloadSize, StreamStart, IP) -> ?DEBUG("Looking for session: ~p", [Sid]), case mnesia:dirty_read({http_bind, Sid}) of [] -> @@ -763,7 +794,9 @@ http_put(Sid, Rid, Attrs, Payload, StreamStart, IP) -> "" end, {gen_fsm:sync_send_all_state_event( - FsmRef, {http_put, Rid, Attrs, Payload, Hold, NewStream, IP}), Sess} + FsmRef, #http_put{rid = Rid, attrs = Attrs, payload = Payload, + payload_size = PayloadSize, hold = Hold, + stream = NewStream, ip = IP}, 30000), Sess} end. handle_http_put_error(Reason, #http_bind{pid=FsmRef, version=Version}) @@ -806,6 +839,46 @@ handle_http_put_error(Reason, #http_bind{pid=FsmRef}) -> {403, ?HEADER, ""} end. +%% Control RID ordering +rid_allow(none, _NewRid, _Attrs, _Hold, _MaxPause) -> + %% First request - nothing saved so far + {true, 0}; +rid_allow(OldRid, NewRid, Attrs, Hold, MaxPause) -> + ?DEBUG("Previous rid / New rid: ~p/~p", [OldRid, NewRid]), + if + %% We did not miss any packet, we can process it immediately: + NewRid == OldRid + 1 -> + case catch list_to_integer( + xml:get_attr_s("pause", Attrs)) of + {'EXIT', _} -> + {true, 0}; + Pause1 when Pause1 =< MaxPause -> + ?DEBUG("got pause: ~p", [Pause1]), + {true, Pause1}; + _ -> + {true, 0} + end; + %% We have missed packets, we need to cached it to process it later on: + (OldRid < NewRid) and + (NewRid =< (OldRid + Hold + 1)) -> + buffer; + (NewRid =< OldRid) and + (NewRid > OldRid - Hold - 1) -> + repeat; + true -> + false + end. + +update_shaper(ShaperState, PayloadSize) -> + {NewShaperState, Pause} = shaper:update(ShaperState, PayloadSize), + if + Pause > 0 -> + ShaperTimer = erlang:start_timer(Pause, self(), activate), %% MR: Seems timer is not needed. Activate is not handled + {NewShaperState, ShaperTimer}; + true -> + {NewShaperState, undefined} + end. + prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold, to=To}=Sess, Rid, _, StreamStart) -> receive after 100 -> ok end, %% TODO: Why is this needed. Argh. Bad programming practice. @@ -819,62 +892,52 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold, to=To}=Sess, {200, ?HEADER, ""}; {ok, terminate} -> {200, ?HEADER, ""}; - {ok, OutPacket} -> - ?DEBUG("OutPacket: ~s", [OutPacket]), + {ok, ROutPacket} -> + OutPacket = lists:reverse(ROutPacket), + ?DEBUG("OutPacket: ~p", [OutPacket]), case StreamStart of false -> send_outpacket(Sess, OutPacket); true -> - OutEls = - case xml_stream:parse_element( - OutPacket++"") of - El when element(1, El) == xmlelement -> - ?DEBUG("~p", [El]), - {xmlelement, _, OutAttrs, Els} = El, - AuthID = xml:get_attr_s("id", OutAttrs), - From = xml:get_attr_s("from", OutAttrs), - Version = xml:get_attr_s("version", OutAttrs), - StreamError = false, - case Els of - [] -> - []; - [{xmlelement, "stream:features", - StreamAttribs, StreamEls} - | StreamTail] -> - [{xmlelement, "stream:features", - [{"xmlns:stream", - ?NS_STREAM} - ] - ++ StreamAttribs, - StreamEls - }] ++ StreamTail; - Xml -> - Xml - end; - {error, _} -> - AuthID = "", - From = "", - Version = "", - StreamError = true, - [] - end, - if - StreamError == true -> - {200, ?HEADER, ""}; - true -> - BOSH_attribs = - [{"authid", AuthID}, - {"xmlns:xmpp", ?NS_BOSH}, - {"xmlns:stream", ?NS_STREAM}] ++ - case OutEls of - [] -> - []; - _ -> - [{"xmpp:version", Version}] - end, - MaxInactivity = get_max_inactivity(To, ?MAX_INACTIVITY), + case OutPacket of + [{xmlstreamstart, _, OutAttrs} | Els] -> + AuthID = xml:get_attr_s("id", OutAttrs), + From = xml:get_attr_s("from", OutAttrs), + Version = xml:get_attr_s("version", OutAttrs), + OutEls = + case Els of + [] -> + []; + [{xmlstreamelement, + {xmlelement, "stream:features", + StreamAttribs, StreamEls}} + | StreamTail] -> + TypedTail = + [check_default_xmlns(OEl) || + {xmlstreamelement, OEl} <- + StreamTail], + [{xmlelement, "stream:features", + [{"xmlns:stream", + ?NS_STREAM}] ++ + StreamAttribs, StreamEls}] ++ + TypedTail; + StreamTail -> + [check_default_xmlns(OEl) || + {xmlstreamelement, OEl} <- + StreamTail] + end, + BOSH_attribs = + [{"authid", AuthID}, + {"xmlns:xmpp", ?NS_BOSH}, + {"xmlns:stream", ?NS_STREAM}] ++ + case OutEls of + [] -> + []; + _ -> + [{"xmpp:version", Version}] + end, + MaxInactivity = get_max_inactivity(To, ?MAX_INACTIVITY), + MaxPause = get_max_pause(To), {200, ?HEADER, xml:element_to_string( {xmlelement,"body", @@ -885,16 +948,20 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold, to=To}=Sess, {"requests", integer_to_list(Hold+1)}, {"inactivity", integer_to_list( - trunc(MaxInactivity/1000))}, - {"maxpause", - integer_to_list(?MAX_PAUSE)}, + trunc(MaxInactivity/1000))}, + {"maxpause", + integer_to_list(MaxPause)}, {"polling", - integer_to_list( - trunc(?MIN_POLLING/1000000))}, - {"ver", ?BOSH_VERSION}, - {"from", From}, - {"secure", "true"} %% we're always being secure - ] ++ BOSH_attribs,OutEls})} + integer_to_list( + trunc(?MIN_POLLING/1000000))}, + {"ver", ?BOSH_VERSION}, + {"from", From}, + {"secure", "true"} %% we're always being secure + ] ++ BOSH_attribs,OutEls})}; + {error, _} -> + {200, ?HEADER, ""} end end; {'EXIT', {shutdown, _}} -> @@ -909,77 +976,85 @@ http_get(#http_bind{pid = FsmRef, wait = Wait, hold = Hold}, Rid) -> send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> case OutPacket of - "" -> + [] -> {200, ?HEADER, ""}; - "" -> + [{xmlstreamend, _}] -> gen_fsm:sync_send_all_state_event(FsmRef,{stop,stream_closed}), {200, ?HEADER, ""}; _ -> - case xml_stream:parse_element("" - ++ OutPacket - ++ "") - of - El when element(1, El) == xmlelement -> - {xmlelement, _, _, OEls} = El, + %% TODO: We parse to add a default namespace to packet, + %% The spec says adding the jabber:client namespace if + %% mandatory, even if some implementation do not do that + %% change on packets. + %% I think this should be an option to avoid modifying + %% packet in most case. + AllElements = + lists:all(fun({xmlstreamelement, + {xmlelement, "stream:error", _, _}}) -> false; + ({xmlstreamelement, _}) -> true; + (_) -> false + end, OutPacket), + case AllElements of + true -> TypedEls = [check_default_xmlns(OEl) || - OEl <- OEls], + {xmlstreamelement, OEl} <- OutPacket], + Body = xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + ?NS_HTTP_BIND}], + TypedEls}), ?DEBUG(" --- outgoing data --- ~n~s~n --- END --- ~n", - [xml:element_to_string( - {xmlelement,"body", - [{"xmlns", - ?NS_HTTP_BIND}], - TypedEls})] - ), - {200, ?HEADER, - xml:element_to_string( - {xmlelement,"body", - [{"xmlns", - ?NS_HTTP_BIND}], - TypedEls})}; - {error, _E} -> - OutEls = case xml_stream:parse_element( - OutPacket++"") of - SEl when element(1, SEl) == xmlelement -> - {xmlelement, _, _OutAttrs, SEls} = SEl, - StreamError = false, - case SEls of - [] -> - []; - [{xmlelement, - "stream:features", - StreamAttribs, StreamEls} | - StreamTail] -> - TypedTail = - [check_default_xmlns(OEl) || - OEl <- StreamTail], - [{xmlelement, - "stream:features", - [{"xmlns:stream", - ?NS_STREAM}] ++ - StreamAttribs, StreamEls}] ++ - TypedTail; - Xml -> - Xml - end; - {error, _} -> - StreamError = true, - [] - end, - if - StreamError -> + [Body]), + {200, ?HEADER, Body}; + false -> + case OutPacket of + [{xmlstreamstart, _, _} | SEls] -> + OutEls = + case SEls of + [{xmlstreamelement, + {xmlelement, + "stream:features", + StreamAttribs, StreamEls}} | + StreamTail] -> + TypedTail = + [check_default_xmlns(OEl) || + {xmlstreamelement, OEl} <- + StreamTail], + [{xmlelement, + "stream:features", + [{"xmlns:stream", + ?NS_STREAM}] ++ + StreamAttribs, StreamEls}] ++ + TypedTail; + StreamTail -> + [check_default_xmlns(OEl) || + {xmlstreamelement, OEl} <- + StreamTail] + end, + {200, ?HEADER, + xml:element_to_string( + {xmlelement,"body", + [{"xmlns", + ?NS_HTTP_BIND}], + OutEls})}; + _ -> + SErrCond = + lists:filter( + fun({xmlstreamelement, + {xmlelement, "stream:error", + _, _}}) -> + true; + (_) -> false + end, OutPacket), StreamErrCond = - case xml_stream:parse_element( - "" ++ OutPacket) of - El when element(1, El) == xmlelement -> - case xml:get_subtag(El, "stream:error") of - false -> - null; - {xmlelement, _, _, _Cond} = StreamErrorTag -> - [StreamErrorTag] - end; - {error, _E} -> - null - end, + case SErrCond of + [] -> + null; + [{xmlstreamelement, + {xmlelement, _, _, _Cond} = + StreamErrorTag} | _] -> + [StreamErrorTag] + end, gen_fsm:sync_send_all_state_event(FsmRef, {stop, {stream_error,OutPacket}}), case StreamErrCond of @@ -996,27 +1071,22 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> "xmlns:stream='"++?NS_STREAM++"'>" ++ elements_to_string(StreamErrCond) ++ ""} - end; - true -> - {200, ?HEADER, - xml:element_to_string( - {xmlelement,"body", - [{"xmlns", - ?NS_HTTP_BIND}], - OutEls})} - end + end + end end end. -parse_request(Data) -> +parse_request(_Data, PayloadSize, MaxStanzaSize) + when PayloadSize > MaxStanzaSize -> + {error, size_limit}; +parse_request(Data, _PayloadSize, _MaxStanzaSize) -> ?DEBUG("--- incoming data --- ~n~s~n --- END --- ", [Data]), + %% MR: I do not think it works if put put several elements in the + %% same body: case xml_stream:parse_element(Data) of - El when element(1, El) == xmlelement -> - {xmlelement, Name, Attrs, Els} = El, + {xmlelement, "body", Attrs, Els} -> Xmlns = xml:get_attr_s("xmlns",Attrs), if - Name /= "body" -> - {error, bad_request}; Xmlns /= ?NS_HTTP_BIND -> {error, bad_request}; true -> @@ -1024,7 +1094,7 @@ parse_request(Data) -> {'EXIT', _} -> {error, bad_request}; Rid -> - %% I guess this is to remove XMLCDATA: + %% I guess this is to remove XMLCDATA: Is it really needed ? FixedEls = lists:filter( fun(I) -> @@ -1035,28 +1105,22 @@ parse_request(Data) -> false end end, Els), - %% MR: I commented this code, because it is not used. -%% lists:map( -%% fun(E) -> -%% EXmlns = xml:get_tag_attr_s("xmlns",E), -%% if -%% EXmlns == ?NS_CLIENT -> -%% remove_tag_attr("xmlns",E); -%% true -> -%% ok -%% end -%% end, FixedEls), - Payload = [xml:element_to_string(E) || E <- FixedEls], Sid = xml:get_attr_s("sid",Attrs), - %% MR: I do not think we need to extract - %% Sid. We should have it somewhere else: - {ok, {Sid, Rid, Attrs, Payload}} + {ok, {Sid, Rid, Attrs, FixedEls}} end end; + {xmlelement, _Name, _Attrs, _Els} -> + {error, bad_request}; {error, _Reason} -> {error, bad_request} end. +send_receiver_reply(undefined, _Reply) -> + ok; +send_receiver_reply(Receiver, Reply) -> + gen_fsm:reply(Receiver, Reply). + + %% Cancel timer and empty message queue. cancel_timer(undefined) -> ok; @@ -1069,6 +1133,15 @@ cancel_timer(Timer) -> ok end. +%% If client asked for a pause (pause > 0), we apply the pause value +%% as inactivity timer: +set_inactivity_timer(Pause, _MaxInactivity) when Pause > 0 -> + erlang:start_timer(Pause*1000, self(), []); +%% Otherwise, we apply the max_inactivity value as inactivity timer: +set_inactivity_timer(_Pause, MaxInactivity) -> + erlang:start_timer(MaxInactivity, self(), []). + + %% TODO: Use tail recursion and list reverse ? elements_to_string([]) -> []; @@ -1087,11 +1160,15 @@ get_max_inactivity({Host, _}, Default) -> get_max_inactivity(_, Default) -> Default. -%% remove_tag_attr(Attr, {xmlelement, Name, Attrs, Els}) -> -%% Attrs1 = lists:keydelete(Attr, 1, Attrs), -%% {xmlelement, Name, Attrs1, Els}; -%% remove_tag_attr(Attr, El) -> -%% El. +get_max_pause({Host, _}) -> + gen_mod:get_module_opt(Host, mod_http_bind, max_pause, ?MAX_PAUSE); +get_max_pause(_) -> + ?MAX_PAUSE. + +%% Current time as integer +tnow() -> + {TMegSec, TSec, TMSec} = now(), + (TMegSec * 1000000 + TSec) * 1000000 + TMSec. check_default_xmlns({xmlelement, Name, Attrs, Els} = El) -> case xml:get_tag_attr_s("xmlns", El) of @@ -1104,6 +1181,6 @@ check_default_xmlns({xmlelement, Name, Attrs, Els} = El) -> check_bind_module(XmppDomain) -> case gen_mod:is_loaded(XmppDomain, mod_http_bind) of true -> ok; - false -> ?ERROR_MSG("You are trying to use HTTP Bind (BOSH), but the module mod_http_bind is not started.~n" + false -> ?ERROR_MSG("You are trying to use BOSH (HTTP Bind), but the module mod_http_bind is not started.~n" "Check your 'modules' section in your ejabberd configuration file.",[]) end. From 81f46446226f81f10e7a188732c7a4c78f461eee Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 1 Sep 2009 08:19:14 +0000 Subject: [PATCH 532/582] Fix missing tag when configuring subscription option (thanks to Clochix) SVN Revision: 2577 --- src/mod_pubsub/mod_pubsub.erl | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 88262c93e..bb86236e7 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -2512,7 +2512,17 @@ read_sub(Subscriber, NodeID, SubID, Lang) -> {error, notfound} -> {error, extended_error('not-acceptable', "invalid-subid")}; {result, #pubsub_subscription{options = Options}} -> - pubsub_subscription:get_options_xform(Lang, Options) + {result, XdataEl} = pubsub_subscription:get_options_xform(Lang, Options), + [N] = mnesia:dirty_match_object({pubsub_node,'_',NodeID,'_','_','_','_'}), + {_, Node} = N#pubsub_node.nodeid, + NodeIDStr = node_to_string(Node), + OptionsEl = #xmlel{ns = ?NS_PUBSUB, name = 'options', + attrs = [?XMLATTR('node', NodeIDStr), + ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), + ?XMLATTR('Subid', SubID)], + children = [XdataEl]}, + PubsubEl = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [OptionsEl]}, + {result, PubsubEl} end. set_options(Host, Node, JID, SubID, Configuration) -> From fa23b83dbbd563fb573b2a34d04eadaf07bca70a Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 1 Sep 2009 13:23:19 +0000 Subject: [PATCH 533/582] improve previous patch SVN Revision: 2579 --- src/mod_pubsub/mod_pubsub.erl | 15 +++++------ src/mod_pubsub/mod_pubsub_odbc.erl | 21 ++++++++++----- src/mod_pubsub/pubsub_odbc.patch | 41 +++++++++++++++--------------- 3 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index bb86236e7..a275c334c 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -2470,7 +2470,7 @@ get_options(Host, Node, JID, SubID, Lang) -> Action = fun(#pubsub_node{type = Type, id = NodeID}) -> case lists:member("subscription-options", features(Type)) of true -> - get_options_helper(JID, Lang, NodeID, SubID, Type); + get_options_helper(JID, Lang, Node, NodeID, SubID, Type); false -> {error, extended_error( 'feature-not-implemented', @@ -2482,7 +2482,7 @@ get_options(Host, Node, JID, SubID, Lang) -> Error -> Error end. -get_options_helper(JID, Lang, NodeID, SubID, Type) -> +get_options_helper(JID, Lang, Node, NodeID, SubID, Type) -> Subscriber = try exmpp_jid:parse(JID) of J -> jlib:short_jid(J) catch @@ -2500,24 +2500,21 @@ get_options_helper(JID, Lang, NodeID, SubID, Type) -> {_, []} -> {error, extended_error('not-acceptable', "not-subscribed")}; {[], [SID]} -> - read_sub(Subscriber, NodeID, SID, Lang); + read_sub(Subscriber, Node, NodeID, SID, Lang); {[], _} -> {error, extended_error('not-acceptable', "subid-required")}; {_, _} -> - read_sub(Subscriber, NodeID, SubID, Lang) + read_sub(Subscriber, Node, NodeID, SubID, Lang) end. -read_sub(Subscriber, NodeID, SubID, Lang) -> +read_sub(Subscriber, Node, NodeID, SubID, Lang) -> case pubsub_subscription:get_subscription(Subscriber, NodeID, SubID) of {error, notfound} -> {error, extended_error('not-acceptable', "invalid-subid")}; {result, #pubsub_subscription{options = Options}} -> {result, XdataEl} = pubsub_subscription:get_options_xform(Lang, Options), - [N] = mnesia:dirty_match_object({pubsub_node,'_',NodeID,'_','_','_','_'}), - {_, Node} = N#pubsub_node.nodeid, - NodeIDStr = node_to_string(Node), OptionsEl = #xmlel{ns = ?NS_PUBSUB, name = 'options', - attrs = [?XMLATTR('node', NodeIDStr), + attrs = [?XMLATTR('node', node_to_string(Node)), ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), ?XMLATTR('Subid', SubID)], children = [XdataEl]}, diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index d4a53962f..9195447f8 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -2298,7 +2298,7 @@ get_options(Host, Node, JID, SubID, Lang) -> Action = fun(#pubsub_node{type = Type, id = NodeID}) -> case lists:member("subscription-options", features(Type)) of true -> - get_options_helper(JID, Lang, NodeID, SubID, Type); + get_options_helper(JID, Lang, Node, NodeID, SubID, Type); false -> {error, extended_error( 'feature-not-implemented', @@ -2310,7 +2310,7 @@ get_options(Host, Node, JID, SubID, Lang) -> Error -> Error end. -get_options_helper(JID, Lang, NodeID, SubID, Type) -> +get_options_helper(JID, Lang, Node, NodeID, SubID, Type) -> Subscriber = try exmpp_jid:parse(JID) of J -> jlib:short_jid(J) catch @@ -2328,19 +2328,26 @@ get_options_helper(JID, Lang, NodeID, SubID, Type) -> {_, []} -> {error, extended_error('not-acceptable', "not-subscribed")}; {[], [SID]} -> - read_sub(Subscriber, NodeID, SID, Lang); + read_sub(Subscriber, Node, NodeID, SID, Lang); {[], _} -> {error, extended_error('not-acceptable', "subid-required")}; {_, _} -> - read_sub(Subscriber, NodeID, SubID, Lang) + read_sub(Subscriber, Node, NodeID, SubID, Lang) end. -read_sub(Subscriber, NodeID, SubID, Lang) -> +read_sub(Subscriber, Node, NodeID, SubID, Lang) -> case pubsub_subscription_odbc:get_subscription(Subscriber, NodeID, SubID) of {error, notfound} -> - pubsub_subscription_odbc:get_options_xform(Lang, []); + {error, extended_error('not-acceptable', "invalid-subid")}; {result, #pubsub_subscription{options = Options}} -> - pubsub_subscription_odbc:get_options_xform(Lang, Options) + {result, XdataEl} = pubsub_subscription_odbc:get_options_xform(Lang, Options), + OptionsEl = #xmlel{ns = ?NS_PUBSUB, name = 'options', + attrs = [?XMLATTR('node', node_to_string(Node)), + ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), + ?XMLATTR('Subid', SubID)], + children = [XdataEl]}, + PubsubEl = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [OptionsEl]}, + {result, PubsubEl} end. set_options(Host, Node, JID, SubID, Configuration) -> diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index c7eec7b9a..370f94bac 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,5 +1,5 @@ ---- mod_pubsub.erl 2009-08-28 02:08:43.000000000 +0200 -+++ mod_pubsub_odbc.erl 2009-08-28 01:08:15.000000000 +0200 +--- mod_pubsub.erl 2009-09-01 15:20:44.000000000 +0200 ++++ mod_pubsub_odbc.erl 2009-09-01 15:22:27.000000000 +0200 @@ -45,7 +45,7 @@ %%% TODO %%% plugin: generate Reply (do not use broadcast atom anymore) @@ -555,19 +555,18 @@ @@ -2508,11 +2336,11 @@ end. - read_sub(Subscriber, NodeID, SubID, Lang) -> + read_sub(Subscriber, Node, NodeID, SubID, Lang) -> - case pubsub_subscription:get_subscription(Subscriber, NodeID, SubID) of + case pubsub_subscription_odbc:get_subscription(Subscriber, NodeID, SubID) of {error, notfound} -> -- {error, extended_error('not-acceptable', "invalid-subid")}; -+ pubsub_subscription_odbc:get_options_xform(Lang, []); + {error, extended_error('not-acceptable', "invalid-subid")}; {result, #pubsub_subscription{options = Options}} -> -- pubsub_subscription:get_options_xform(Lang, Options) -+ pubsub_subscription_odbc:get_options_xform(Lang, Options) - end. - - set_options(Host, Node, JID, SubID, Configuration) -> -@@ -2539,7 +2367,7 @@ +- {result, XdataEl} = pubsub_subscription:get_options_xform(Lang, Options), ++ {result, XdataEl} = pubsub_subscription_odbc:get_options_xform(Lang, Options), + OptionsEl = #xmlel{ns = ?NS_PUBSUB, name = 'options', + attrs = [?XMLATTR('node', node_to_string(Node)), + ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), +@@ -2546,7 +2374,7 @@ _ -> {"", "", ""} %%pablo TODO: "" or <<>> ?. short_jid uses exmpp_jid:node/1, etc. that returns binaries end, @@ -576,7 +575,7 @@ {result, Subs} = node_call(Type, get_subscriptions, [NodeID, Subscriber]), SubIDs = lists:foldl(fun({subscribed, SID}, Acc) -> -@@ -2559,7 +2387,7 @@ +@@ -2566,7 +2394,7 @@ end. write_sub(Subscriber, NodeID, SubID, Options) -> @@ -585,7 +584,7 @@ {error, notfound} -> {error, extended_error('not-acceptable', "invalid-subid")}; {result, _} -> -@@ -2732,8 +2560,8 @@ +@@ -2739,8 +2567,8 @@ ?XMLATTR('subsription', subscription_to_string(Sub)) | nodeAttr(Node)]}]}]}, ejabberd_router ! {route, service_jid(Host), JID, Stanza} end, @@ -596,7 +595,7 @@ true -> Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> -@@ -3020,7 +2848,7 @@ +@@ -3027,7 +2855,7 @@ {Depth, [{N, get_node_subs(N)} || N <- Nodes]} end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))} end, @@ -605,7 +604,7 @@ {result, CollSubs} -> CollSubs; _ -> [] end. -@@ -3034,9 +2862,9 @@ +@@ -3041,9 +2869,9 @@ get_options_for_subs(NodeID, Subs) -> lists:foldl(fun({JID, subscribed, SubID}, Acc) -> @@ -617,7 +616,7 @@ _ -> Acc end; (_, Acc) -> -@@ -3231,6 +3059,30 @@ +@@ -3238,6 +3066,30 @@ Result end. @@ -648,7 +647,7 @@ %% @spec (Host, Options) -> MaxItems %% Host = host() %% Options = [Option] -@@ -3607,7 +3459,13 @@ +@@ -3614,7 +3466,13 @@ tree_action(Host, Function, Args) -> ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), Fun = fun() -> tree_call(Host, Function, Args) end, @@ -663,7 +662,7 @@ %% @doc

    node plugin call.

    node_call(Type, Function, Args) -> -@@ -3627,13 +3485,13 @@ +@@ -3634,13 +3492,13 @@ node_action(Host, Type, Function, Args) -> ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), @@ -679,7 +678,7 @@ case tree_call(Host, get_node, [Host, Node]) of N when is_record(N, pubsub_node) -> case Action(N) of -@@ -3646,8 +3504,15 @@ +@@ -3653,8 +3511,15 @@ end end, Trans). @@ -697,7 +696,7 @@ {result, Result} -> {result, Result}; {error, Error} -> {error, Error}; {atomic, {result, Result}} -> {result, Result}; -@@ -3655,6 +3520,15 @@ +@@ -3662,6 +3527,15 @@ {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), {error, 'internal-server-error'}; @@ -713,7 +712,7 @@ {'EXIT', Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), {error, 'internal-server-error'}; -@@ -3663,6 +3537,16 @@ +@@ -3670,6 +3544,16 @@ {error, 'internal-server-error'} end. From 330a4c94520e8ae164b04833df5d8ff9bb4bfd69 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 2 Sep 2009 14:25:42 +0000 Subject: [PATCH 534/582] Small fix exmpp related code SVN Revision: 2581 --- src/acl.erl | 6 ++++-- src/mod_configure.erl | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/acl.erl b/src/acl.erl index 8ab703514..7287a0ba4 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -298,9 +298,11 @@ match_acl(ACLName, JID, Host) -> end. %% @spec (String, RegExp) -> bool() -%% String = string() +%% String = string() | undefined %% RegExp = string() +is_regexp_match(undefined, RegExp) -> + false; is_regexp_match(String, RegExp) -> case regexp:first_match(String, RegExp) of nomatch -> @@ -315,7 +317,7 @@ is_regexp_match(String, RegExp) -> end. %% @spec (String, Glob) -> bool() -%% String = string() +%% String = string() | undefined %% Glob = string() is_glob_match(String, Glob) -> diff --git a/src/mod_configure.erl b/src/mod_configure.erl index b947e7424..dd8040eca 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -325,7 +325,7 @@ adhoc_local_items(Acc, From, To, Lang) -> Lang), Nodes1 = lists:filter( fun(N) -> - Nd = exmpp_xml:get_attribute_as_list(N, 'node', ""), + Nd = exmpp_xml:get_attribute_as_binary(N, 'node', ""), F = get_local_features([], From, To, Nd, Lang), case F of {result, [?NS_ADHOC_s]} -> From 29b2da42f5c25c5f9169edf64ba0e5190a66d213 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 2 Sep 2009 14:26:01 +0000 Subject: [PATCH 535/582] Replace calls from 'regexp' to the OTP R12 new module 're' (EJAB-921) SVN Revision: 2582 --- .../extract_translations.erl | 8 ++--- src/acl.erl | 17 ++++++----- src/ejabberd_ctl.erl | 10 +++---- src/ejabberd_s2s_in.erl | 8 ++--- src/eldap/eldap_filter.erl | 28 +++++++++-------- src/eldap/eldap_utils.erl | 4 +-- src/gen_mod.erl | 4 +-- src/mod_configure.erl | 2 +- src/mod_muc/mod_muc_log.erl | 30 +++++++++++-------- src/mod_shared_roster.erl | 10 +++---- src/web/ejabberd_web_admin.erl | 6 ++-- 11 files changed, 67 insertions(+), 60 deletions(-) diff --git a/contrib/extract_translations/extract_translations.erl b/contrib/extract_translations/extract_translations.erl index 488357ba6..ea1d1c76b 100644 --- a/contrib/extract_translations/extract_translations.erl +++ b/contrib/extract_translations/extract_translations.erl @@ -281,14 +281,14 @@ build_additional_translators(List) -> List). print_translation(File, Line, Str, StrT) -> - {ok, StrQ, _} = regexp:gsub(Str, "\"", "\\\""), - {ok, StrTQ, _} = regexp:gsub(StrT, "\"", "\\\""), + StrQ = re:replace(Str, "\"", "\\\"", [global, {return, list}]), + StrTQ = re:replace(StrT, "\"", "\\\"", [global, {return, list}]), io:format("#: ~s:~p~nmsgid \"~s\"~nmsgstr \"~s\"~n~n", [File, Line, StrQ, StrTQ]). print_translation_obsolete(Str, StrT) -> File = "unknown.erl", Line = 1, - {ok, StrQ, _} = regexp:gsub(Str, "\"", "\\\""), - {ok, StrTQ, _} = regexp:gsub(StrT, "\"", "\\\""), + StrQ = re:replace(Str, "\"", "\\\"", [global, {return, list}]), + StrTQ = re:replace(StrT, "\"", "\\\"", [global, {return, list}]), io:format("#: ~s:~p~n#~~ msgid \"~s\"~n#~~ msgstr \"~s\"~n~n", [File, Line, StrQ, StrTQ]). diff --git a/src/acl.erl b/src/acl.erl index 7287a0ba4..40231b010 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -301,18 +301,19 @@ match_acl(ACLName, JID, Host) -> %% String = string() | undefined %% RegExp = string() -is_regexp_match(undefined, RegExp) -> +is_regexp_match(undefined, _RegExp) -> false; is_regexp_match(String, RegExp) -> - case regexp:first_match(String, RegExp) of + try re:run(String, RegExp, [{capture, none}]) of nomatch -> false; - {match, _, _} -> - true; - {error, ErrDesc} -> + match -> + true + catch + _:ErrDesc -> ?ERROR_MSG( - "Wrong regexp ~p in ACL: ~p", - [RegExp, lists:flatten(regexp:format_error(ErrDesc))]), + "Wrong regexp ~p in ACL:~n~p", + [RegExp, ErrDesc]), false end. @@ -321,6 +322,6 @@ is_regexp_match(String, RegExp) -> %% Glob = string() is_glob_match(String, Glob) -> - is_regexp_match(String, regexp:sh_to_awk(Glob)). + is_regexp_match(String, xmerl_regexp:sh_to_awk(Glob)). diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl index 7919986ae..9e398f8c3 100644 --- a/src/ejabberd_ctl.erl +++ b/src/ejabberd_ctl.erl @@ -277,7 +277,7 @@ try_call_command(Args, Auth, AccessCommands) -> %% @spec (Args::[string()], Auth, AccessCommands) -> string() | integer() | {string(), integer()} | {error, ErrorType} call_command([CmdString | Args], Auth, AccessCommands) -> - {ok, CmdStringU, _} = regexp:gsub(CmdString, "-", "_"), + CmdStringU = re:replace(CmdString, "-", "_", [global,{return,list}]), Command = list_to_atom(CmdStringU), case ejabberd_commands:get_command_format(Command) of {error, command_unknown} -> @@ -673,13 +673,13 @@ filter_commands(All, SubString) -> end. filter_commands_regexp(All, Glob) -> - RegExp = regexp:sh_to_awk(Glob), + RegExp = xmerl_regexp:sh_to_awk(Glob), lists:filter( fun(Command) -> - case regexp:first_match(Command, RegExp) of - {match, _, _} -> + case re:run(Command, RegExp, [{capture, none}]) of + match -> true; - _ -> + nomatch -> false end end, diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 6a84e2202..590b322f8 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -735,11 +735,11 @@ match_labels([DL | DLabels], [PL | PLabels]) -> orelse (C == $-) orelse (C == $*) end, PL) of true -> - Regexp = regexp:sh_to_awk(PL), - case regexp:match(DL, Regexp) of - {match, _, _} -> + Regexp = xmerl_regexp:sh_to_awk(PL), + case re:run(DL, Regexp, [{capture, none}]) of + match -> match_labels(DLabels, PLabels); - _ -> + nomatch -> false end; false -> diff --git a/src/eldap/eldap_filter.erl b/src/eldap/eldap_filter.erl index 46510e0d6..d0c795958 100644 --- a/src/eldap/eldap_filter.erl +++ b/src/eldap/eldap_filter.erl @@ -182,7 +182,7 @@ parse_attr(less, {Name, Value}, ListOfSubValues) -> eldap:lessOrEqual(Name, NewValue); parse_attr(equal, {Name, Value}, ListOfSubValues) -> - {ok, RegSList} = regexp:split(remove_extra_asterisks(Value), "[*]"), + RegSList = re:split(remove_extra_asterisks(Value), "[*]", [{return, list}]), Pattern = case [do_sub(X, ListOfSubValues) || X <- RegSList] of [Head | Tail] when Tail /= [] -> {Head, lists:sublist(Tail, length(Tail)-1), lists:last(Tail)}; @@ -228,14 +228,15 @@ do_sub(S, [{RegExp, New, Times} | T]) -> do_sub(Result, T). do_sub(S, {RegExp, New}, Iter) -> - case regexp:sub(S, RegExp, New) of - {ok, NewS, 0} -> + try re:replace(S, RegExp, New, [{return, list}]) of + NewS when NewS == S -> NewS; - {ok, NewS, _} when Iter =< ?MAX_RECURSION -> + NewS when Iter =< ?MAX_RECURSION -> do_sub(NewS, {RegExp, New}, Iter+1); - {ok, _, _} when Iter > ?MAX_RECURSION -> - throw({regexp, max_substitute_recursion}); - _ -> + _ when Iter > ?MAX_RECURSION -> + throw({regexp, max_substitute_recursion}) + catch + _:_ -> throw({regexp, bad_regexp}) end; @@ -243,14 +244,15 @@ do_sub(S, {_, _, N}, _) when N<1 -> S; do_sub(S, {RegExp, New, Times}, Iter) -> - case regexp:sub(S, RegExp, New) of - {ok, NewS, 0} -> + try re:replace(S, RegExp, New, [{return, list}]) of + NewS when NewS == S -> NewS; - {ok, NewS, _} when Iter < Times -> + NewS when Iter < Times -> do_sub(NewS, {RegExp, New, Times}, Iter+1); - {ok, NewS, _} -> - NewS; - _ -> + NewS -> + NewS + catch + _:_ -> throw({regexp, bad_regexp}) end. diff --git a/src/eldap/eldap_utils.erl b/src/eldap/eldap_utils.erl index bf9cf1567..0459bee05 100644 --- a/src/eldap/eldap_utils.erl +++ b/src/eldap/eldap_utils.erl @@ -89,8 +89,8 @@ get_user_part(String, Pattern) -> {'EXIT', _} -> {error, badmatch}; Result -> - case regexp:sub(Pattern, "%u", Result) of - {ok, String, _} -> {ok, Result}; + case re:replace(Pattern, "%u", Result, [{return, list}]) of + String -> {ok, Result}; _ -> {error, badmatch} end end. diff --git a/src/gen_mod.erl b/src/gen_mod.erl index a37ec51e6..df1ccf0ea 100644 --- a/src/gen_mod.erl +++ b/src/gen_mod.erl @@ -173,11 +173,11 @@ get_module_opt(Host, Module, Opt, Default) -> get_module_opt_host(Host, Module, Default) -> Val = get_module_opt(Host, Module, host, Default), - element(2, regexp:gsub(Val, "@HOST@", Host)). + re:replace(Val, "@HOST@", Host, [global,{return,list}]). get_opt_host(Host, Opts, Default) -> Val = get_opt(host, Opts, Default), - element(2, regexp:gsub(Val, "@HOST@", Host)). + re:replace(Val, "@HOST@", Host, [global,{return,list}]). loaded_modules(Host) -> ets:select(ejabberd_modules, diff --git a/src/mod_configure.erl b/src/mod_configure.erl index dd8040eca..4f39ccd49 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -524,7 +524,7 @@ get_local_items({_, Host}, ["all users", [$@ | Diap]], _Server, _Lang) -> Users -> SUsers = lists:sort([{S, U} || {U, S} <- Users]), case catch begin - {ok, [S1, S2]} = regexp:split(Diap, "-"), + [S1, S2] = re:split(Diap, "-", [{return, list}]), N1 = list_to_integer(S1), N2 = list_to_integer(S2), Sub = lists:sublist(SUsers, N1, N2 - N1 + 1), diff --git a/src/mod_muc/mod_muc_log.erl b/src/mod_muc/mod_muc_log.erl index 2456c1324..1dbd27474 100644 --- a/src/mod_muc/mod_muc_log.erl +++ b/src/mod_muc/mod_muc_log.erl @@ -415,11 +415,11 @@ add_message_to_log(Nick1, Message, RoomJID, Opts, State) -> io_lib:format("~s~s~s
    ", [Nick, ?T(" has set the subject to: "), htmlize(T,NoFollow,FileFormat)]); {body, T} -> - case {regexp:first_match(T, "^/me\s"), Nick} of + case {re:run(T, "^/me\s", [{capture, none}]), Nick} of {_, ""} -> io_lib:format("~s
    ", [htmlize(T,NoFollow,FileFormat)]); - {{match, _, _}, _} -> + {match, _} -> io_lib:format("~s ~s
    ", [Nick, string:substr(htmlize(T,FileFormat), 5)]); {nomatch, _} -> @@ -664,8 +664,7 @@ fw(F, S, O, FileFormat) -> html -> S1; plaintext -> - {ok, Res, _} = regexp:gsub(S1, "<[^>]*>", ""), - Res + re:replace(S1, "<[^>]*>", "", [global,{return,list}]) end, io:format(F, S2, []). @@ -794,15 +793,20 @@ htmlize(S1, NoFollow, _FileFormat) -> S2_list). htmlize2(S1, NoFollow) -> - S2 = element(2, regexp:gsub(S1, "\\&", "\\&")), - S3 = element(2, regexp:gsub(S2, "<", "\\<")), - S4 = element(2, regexp:gsub(S3, ">", "\\>")), - S5 = element(2, regexp:gsub(S4, "((http|https|ftp)://|(mailto|xmpp):)[^] )\'\"}]+", - link_regexp(NoFollow))), - %% Remove 'right-to-left override' unicode character 0x202e - S6 = element(2, regexp:gsub(S5, " ", "\\ \\ ")), - S7 = element(2, regexp:gsub(S6, "\\t", "\\ \\ \\ \\ ")), - element(2, regexp:gsub(S7, [226,128,174], "[RLO]")). + ReplacementRules = + [{"\\&", "\\&"}, + {"<", "\\<"}, + {">", "\\>"}, + {"((http|https|ftp)://|(mailto|xmpp):)[^] )\'\"}]+", link_regexp(NoFollow)}, + {" ", "\\ \\ "}, + {"\\t", "\\ \\ \\ \\ "}, + {[226,128,174], "[RLO]"}], %% Remove 'right-to-left override' unicode character 0x202e + lists:foldl( + fun({RegExp, Replace}, Acc) -> + re:replace(Acc, RegExp, Replace) + end, + S1, + ReplacementRules). %% Regexp link %% Add the nofollow rel attribute when required diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index da7b72357..6d577be58 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -561,8 +561,8 @@ is_user_in_group({_U, S} = US, Group, Host) -> %% @spec (Host::string(), {User::string(), Server::string()}, Group::string()) -> {atomic, ok} add_user_to_group(Host, US, Group) -> {LUser, LServer} = US, - case regexp:match(LUser, "^@.+@$") of - {match,_,_} -> + case re:run(LUser, "^@.+@$", [{capture, none}]) of + match -> GroupOpts = mod_shared_roster:get_group_opts(Host, Group), AllUsersOpt = case LUser == "@all@" of @@ -593,8 +593,8 @@ push_displayed_to_user(LUser, LServer, Group, Host, Subscription) -> remove_user_from_group(Host, US, Group) -> GroupHost = {Group, Host}, {LUser, LServer} = US, - case regexp:match(LUser, "^@.+@$") of - {match,_,_} -> + case re:run(LUser, "^@.+@$", [{capture, none}]) of + match -> GroupOpts = mod_shared_roster:get_group_opts(Host, Group), NewGroupOpts = case LUser of @@ -856,7 +856,7 @@ shared_roster_group(Host, Group, Query, Lang) -> [] end ++ [[us_to_list(Member), $\n] || Member <- Members], FDisplayedGroups = [[DG, $\n] || DG <- DisplayedGroups], - DescNL = length(element(2, regexp:split(Description, "\n"))), + DescNL = length(re:split(Description, "\n", [{return, list}])), FGroup = ?XAE("table", [?XMLATTR('class', <<"withtextareas">>)], [?XE("tbody", diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 85a3a2cac..1f47c42e8 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -1232,13 +1232,13 @@ acl_spec_select(ID, Opt) -> term_to_string(T) -> StringParagraph = lists:flatten(io_lib:format("~1000000p", [T])), %% Remove from the string all the carriage returns characters - {ok, StringLine, _} = regexp:gsub(StringParagraph, "\\n ", ""), + StringLine = re:replace(StringParagraph, "\\n ", "", [global,{return,list}]), StringLine. %% @spec (T::any(), Cols::integer()) -> {NumLines::integer(), Paragraph::string()} term_to_paragraph(T, Cols) -> Paragraph = erl_prettypr:format(erl_syntax:abstract(T), [{paper, Cols}]), - {ok, FieldList} = regexp:split(Paragraph, "\n"), + FieldList = re:split(Paragraph, "\n", [{return, list}]), NumLines = length(FieldList), {NumLines, Paragraph}. @@ -1563,7 +1563,7 @@ list_users_parse_query(Query, Host) -> list_users_in_diapason(Host, Diap, Lang, URLFunc) -> Users = ejabberd_auth:get_vh_registered_users(Host), SUsers = lists:sort([{S, U} || {U, S} <- Users]), - {ok, [S1, S2]} = regexp:split(Diap, "-"), + [S1, S2] = re:split(Diap, "-", [{return, list}]), N1 = list_to_integer(S1), N2 = list_to_integer(S2), Sub = lists:sublist(SUsers, N1, N2 - N1 + 1), From 283aa52b3127f83b68b6094edd84f90f549ad131 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Fri, 4 Sep 2009 21:33:30 +0000 Subject: [PATCH 536/582] Port #2583 from trunk Use the local (target) domain for firing the s2s_receive_packet hook. It was using the external server domain (LFrom) instead of the local domain (LTo). This might have impact on mod_caps in s2s scenarios, needs further attention. SVN Revision: 2584 --- src/ejabberd_s2s_in.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 590b322f8..5ba3ecb49 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -399,7 +399,7 @@ stream_established({xmlstreamelement, El}, StateData) -> (Name == 'presence')) -> ejabberd_hooks:run( s2s_receive_packet, - exmpp_jid:prep_domain(From), + exmpp_jid:prep_domain(To), [From, To, El]), ejabberd_router:route( From, To, El); @@ -419,7 +419,7 @@ stream_established({xmlstreamelement, El}, StateData) -> (Name == 'presence')) -> ejabberd_hooks:run( s2s_receive_packet, - exmpp_jid:prep_domain(From), + exmpp_jid:prep_domain(To), [From, To, El]), ejabberd_router:route( From, To, El); From 75dbcd5c686a3a7deecb62f7d784d955f88f4a1e Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 4 Sep 2009 23:34:05 +0000 Subject: [PATCH 537/582] fix minor timestamp shift between item creation and modification SVN Revision: 2586 --- src/mod_pubsub/node_hometree.erl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index 6c9a668dc..1fe14b14b 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -481,14 +481,15 @@ publish_item(NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload) -> true -> %% TODO: check creation, presence, roster if MaxItems > 0 -> - PubId = {now(), SubKey}, + Now = now(), + PubId = {Now, SubKey}, Item = case get_item(NodeId, ItemId) of {result, OldItem} -> OldItem#pubsub_item{modification = PubId, payload = Payload}; _ -> #pubsub_item{itemid = {ItemId, NodeId}, - creation = {now(), GenKey}, + creation = {Now, GenKey}, modification = PubId, payload = Payload} end, From 04e86829e3d86317017956d91d4953375d196d0f Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 7 Sep 2009 14:31:34 +0000 Subject: [PATCH 538/582] Change some error messages. SVN Revision: 2588 --- src/ejabberd_s2s_out.erl | 6 ++++-- src/web/ejabberd_http_bind.erl | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 2f0501425..85f6a0618 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -1005,8 +1005,10 @@ srv_lookup(Server, Timeout, Retries) -> {error, _Reason} -> case inet_res:getbyname("_jabber._tcp." ++ Server, srv, Timeout) of {error, timeout} -> - ?ERROR_MSG("Couldn't resolve SRV records for ~p via nameservers ~p.", - [Server, inet_db:res_option(nameserver)]), + ?ERROR_MSG("The DNS servers~n ~p~ntimed out on request" + " for ~p IN SRV." + " You should check your DNS configuration.", + [inet_db:res_option(nameserver), Server]), srv_lookup(Server, Timeout, Retries - 1); R -> R end; diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 885ac9c68..ddd53cccc 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -180,7 +180,7 @@ process_request(Data, IP) -> {ok, {"", Rid, Attrs, Payload}} -> case xml:get_attr_s("to",Attrs) of "" -> - ?ERROR_MSG("Session not created (Improper addressing)", []), + ?INFO_MSG("Session not created (Improper addressing).~nAttributes: ~p", [Attrs]), {200, ?HEADER, ""}; From 376741c9a1e1d42f80c747bd051ea78ad961df09 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Wed, 9 Sep 2009 21:49:23 +0000 Subject: [PATCH 539/582] fix delete item to allow owner being able to remove all publisher items, and also fix EJAB-1036 SVN Revision: 2591 --- src/mod_pubsub/mod_pubsub.erl | 2 + src/mod_pubsub/mod_pubsub_odbc.erl | 2 + src/mod_pubsub/node_hometree.erl | 38 ++++++++++--- src/mod_pubsub/node_hometree_odbc.erl | 9 ++- src/mod_pubsub/pubsub_odbc.patch | 76 +++++++++++++------------- src/mod_pubsub/pubsub_subscription.erl | 41 +++++++------- 6 files changed, 100 insertions(+), 68 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index a275c334c..3aa758006 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -668,6 +668,7 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) -> Host = exmpp_jid:prep_domain_as_list(To), LJID = jlib:short_prepd_bare_jid(To), Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + % TODO call get_items/6 instead for access control (EJAB-1033) case node_call(Type, get_items, [NodeId, From]) of {result, []} -> none; @@ -1111,6 +1112,7 @@ iq_disco_items(Host, Item, From) -> %% TODO That is, remove name attribute (or node?, please check for 2.1) Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + % TODO call get_items/6 instead for access control (EJAB-1033) NodeItems = case node_call(Type, get_items, [NodeId, From]) of {result, I} -> I; _ -> [] diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index 9195447f8..901fac0c3 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -494,6 +494,7 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) -> Host = exmpp_jid:prep_domain_as_list(To), LJID = jlib:short_prepd_bare_jid(To), Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + % TODO call get_items/6 instead for access control (EJAB-1033) case node_call(Type, get_items, [NodeId, From]) of {result, []} -> none; @@ -940,6 +941,7 @@ iq_disco_items(Host, Item, From, RSM) -> %% TODO That is, remove name attribute (or node?, please check for 2.1) Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + %% TODO call get_items/6 instead for access control (EJAB-1033) {NodeItems, RsmOut} = case node_call(Type, get_items, [NodeId, From, RSM]) of {result, I} -> I; _ -> {[], none} diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index 1fe14b14b..1cb017c4c 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -556,12 +556,30 @@ delete_item(NodeId, Publisher, PublishModel, ItemId) -> case lists:member(ItemId, Items) of true -> del_item(NodeId, ItemId), - NewItems = lists:delete(ItemId, Items), - set_state(GenState#pubsub_state{items = NewItems}), + set_state(GenState#pubsub_state{items = lists:delete(ItemId, Items)}), {result, {default, broadcast}}; false -> - %% Non-existent node or item - {error, 'item-not-found'} + case Affiliation of + owner -> + %% Owner can delete other publishers items as well + {result, States} = get_states(NodeId), + lists:foldl( + fun(#pubsub_state{items = PI, affiliation = publisher} = S, Res) -> + case lists:member(ItemId, PI) of + true -> + del_item(NodeId, ItemId), + set_state(S#pubsub_state{items = lists:delete(ItemId, PI)}), + {result, {default, broadcast}}; + false -> + Res + end; + (_, Res) -> + Res + end, {error, 'item-not-found'}, States); + _ -> + %% Non-existent node or item + {error, 'item-not-found'} + end end end. @@ -574,9 +592,15 @@ purge_node(NodeId, Owner) -> GenKey = jlib:short_prepd_bare_jid(Owner), GenState = get_state(NodeId, GenKey), case GenState of - #pubsub_state{items = Items, affiliation = owner} -> - del_items(NodeId, Items), - set_state(GenState#pubsub_state{items = []}), + #pubsub_state{affiliation = owner} -> + {result, States} = get_states(NodeId), + lists:foreach( + fun(#pubsub_state{items = []}) -> + ok; + (#pubsub_state{items = Items} = S) -> + del_items(NodeId, Items), + set_state(S#pubsub_state{items = []}) + end, States), {result, {default, broadcast}}; _ -> %% Entity is not owner diff --git a/src/mod_pubsub/node_hometree_odbc.erl b/src/mod_pubsub/node_hometree_odbc.erl index 91c9be46f..801141b3b 100644 --- a/src/mod_pubsub/node_hometree_odbc.erl +++ b/src/mod_pubsub/node_hometree_odbc.erl @@ -562,9 +562,12 @@ purge_node(NodeId, Owner) -> GenKey = jlib:short_prepd_bare_jid(Owner), GenState = get_state(NodeId, GenKey), case GenState of - #pubsub_state{items = Items, affiliation = owner} -> - del_items(NodeId, Items), - %% set new item list use useless + #pubsub_state{affiliation = owner} -> + {result, States} = get_states(NodeId), + lists:foreach( + fun(#pubsub_state{items = []}) -> ok; + (#pubsub_state{items = Items}) -> del_items(NodeId, Items) + end, States), {result, {default, broadcast}}; _ -> %% Entity is not owner diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index 370f94bac..39fa40205 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,5 +1,5 @@ ---- mod_pubsub.erl 2009-09-01 15:20:44.000000000 +0200 -+++ mod_pubsub_odbc.erl 2009-09-01 15:22:27.000000000 +0200 +--- mod_pubsub.erl 2009-09-09 23:42:26.000000000 +0200 ++++ mod_pubsub_odbc.erl 2009-09-09 23:42:26.000000000 +0200 @@ -45,7 +45,7 @@ %%% TODO %%% plugin: generate Reply (do not use broadcast atom anymore) @@ -251,7 +251,7 @@ true -> % resource not concerned about that subscription ok -@@ -809,10 +635,10 @@ +@@ -810,10 +636,10 @@ {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), lists:foreach(fun ({Node, subscribed, _, JID}) -> @@ -264,7 +264,7 @@ true -> node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); false -> -@@ -930,11 +756,12 @@ +@@ -931,11 +757,12 @@ end, ejabberd_router:route(To, From, Res); #iq{type = get, ns = ?NS_DISCO_ITEMS, @@ -279,7 +279,7 @@ {result, IQRes} -> Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', attrs = QAttrs, -@@ -1037,7 +864,7 @@ +@@ -1038,7 +865,7 @@ [] -> ["leaf"]; %% No sub-nodes: it's a leaf node _ -> @@ -288,7 +288,7 @@ {result, []} -> ["collection"]; {result, _} -> ["leaf", "collection"]; _ -> [] -@@ -1053,8 +880,9 @@ +@@ -1054,8 +881,9 @@ []; true -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]} | @@ -300,7 +300,7 @@ end, features(Type))] end, %% TODO: add meta-data info (spec section 5.4) -@@ -1082,14 +910,15 @@ +@@ -1083,14 +911,15 @@ #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_DISCO_ITEMS_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_VCARD_s)]}] ++ @@ -319,7 +319,7 @@ {result, lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> SN = node_to_string(SubNode), -@@ -1099,7 +928,7 @@ +@@ -1100,7 +929,7 @@ ?XMLATTR('node', SN), ?XMLATTR('name', RN)]} end, tree_action(Host, get_subnodes, [Host, [], From]))}; @@ -328,11 +328,13 @@ case string:tokens(Item, "!") of [_SNode, _ItemID] -> {result, []}; -@@ -1111,9 +940,9 @@ +@@ -1112,10 +941,10 @@ %% TODO That is, remove name attribute (or node?, please check for 2.1) Action = fun(#pubsub_node{type = Type, id = NodeId}) -> +- % TODO call get_items/6 instead for access control (EJAB-1033) - NodeItems = case node_call(Type, get_items, [NodeId, From]) of ++ %% TODO call get_items/6 instead for access control (EJAB-1033) + {NodeItems, RsmOut} = case node_call(Type, get_items, [NodeId, From, RSM]) of {result, I} -> I; - _ -> [] @@ -340,7 +342,7 @@ end, Nodes = lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> -@@ -1129,7 +958,7 @@ +@@ -1131,7 +960,7 @@ #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), ?XMLATTR('name', Name)]} end, NodeItems), @@ -349,7 +351,7 @@ end, case transaction(Host, Node, Action, sync_dirty) of {result, {_, Result}} -> {result, Result}; -@@ -1268,7 +1097,8 @@ +@@ -1270,7 +1099,8 @@ (_, Acc) -> Acc end, [], exmpp_xml:remove_cdata_from_list(Els)), @@ -359,7 +361,7 @@ {get, 'subscriptions'} -> get_subscriptions(Host, Node, From, Plugins); {get, 'affiliations'} -> -@@ -1290,8 +1120,9 @@ +@@ -1292,8 +1122,9 @@ end. iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> @@ -371,7 +373,7 @@ case Action of [#xmlel{name = Name, attrs = Attrs, children = Els}] -> Node = case Host of -@@ -1421,7 +1252,8 @@ +@@ -1423,7 +1254,8 @@ _ -> [] end end, @@ -381,7 +383,7 @@ sync_dirty) of {result, Res} -> Res; Err -> Err -@@ -1466,7 +1298,7 @@ +@@ -1468,7 +1300,7 @@ %%% authorization handling @@ -390,7 +392,7 @@ Lang = "en", %% TODO fix {U, S, R} = Subscriber, Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = -@@ -1496,7 +1328,7 @@ +@@ -1498,7 +1330,7 @@ lists:foreach(fun(Owner) -> {U, S, R} = Owner, ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza} @@ -399,7 +401,7 @@ find_authorization_response(Packet) -> Els = Packet#xmlel.children, -@@ -1559,8 +1391,8 @@ +@@ -1561,8 +1393,8 @@ "true" -> true; _ -> false end, @@ -410,7 +412,7 @@ {result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]), if not IsApprover -> -@@ -1750,7 +1582,7 @@ +@@ -1752,7 +1584,7 @@ end, Reply = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(Node)}]}, @@ -419,7 +421,7 @@ {result, {Result, broadcast}} -> %%Lang = "en", %% TODO: fix %%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), -@@ -1859,7 +1691,7 @@ +@@ -1861,7 +1693,7 @@ %%
  • The node does not exist.
  • %% subscribe_node(Host, Node, From, JID, Configuration) -> @@ -428,7 +430,7 @@ Subscriber = try jlib:short_prepd_jid(exmpp_jid:parse(JID)) catch -@@ -1867,7 +1699,7 @@ +@@ -1869,7 +1701,7 @@ {undefined, undefined, undefined} end, SubId = uniqid(), @@ -437,7 +439,7 @@ Features = features(Type), SubscribeFeature = lists:member("subscribe", Features), OptionsFeature = lists:member("subscription-options", Features), -@@ -1886,9 +1718,13 @@ +@@ -1888,9 +1720,13 @@ {"", "", ""} -> {false, false}; _ -> @@ -454,7 +456,7 @@ end end, if -@@ -2213,7 +2049,7 @@ +@@ -2215,7 +2051,7 @@ %%

    The permission are not checked in this function.

    %% @todo We probably need to check that the user doing the query has the right %% to read the items. @@ -463,7 +465,7 @@ MaxItems = if SMaxItems == "" -> ?MAXITEMS; -@@ -2252,11 +2088,11 @@ +@@ -2254,11 +2090,11 @@ node_call(Type, get_items, [NodeId, From, AccessModel, PresenceSubscription, RosterGroup, @@ -477,7 +479,7 @@ SendItems = case ItemIDs of [] -> Items; -@@ -2269,7 +2105,7 @@ +@@ -2271,7 +2107,7 @@ %% number of items sent to MaxItems: {result, #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = nodeAttr(Node), children = @@ -486,7 +488,7 @@ Error -> Error end -@@ -2301,16 +2137,25 @@ +@@ -2303,16 +2139,25 @@ %% @doc

    Resend the items of a node to the user.

    %% @todo use cache-last-item feature send_items(Host, Node, NodeId, Type, LJID, last) -> @@ -519,7 +521,7 @@ send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of {result, []} -> -@@ -2431,29 +2276,12 @@ +@@ -2433,29 +2278,12 @@ error -> {error, 'bad-request'}; _ -> @@ -552,7 +554,7 @@ end, Entities), {result, []}; _ -> -@@ -2508,11 +2336,11 @@ +@@ -2510,11 +2338,11 @@ end. read_sub(Subscriber, Node, NodeID, SubID, Lang) -> @@ -566,7 +568,7 @@ OptionsEl = #xmlel{ns = ?NS_PUBSUB, name = 'options', attrs = [?XMLATTR('node', node_to_string(Node)), ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), -@@ -2546,7 +2374,7 @@ +@@ -2548,7 +2376,7 @@ _ -> {"", "", ""} %%pablo TODO: "" or <<>> ?. short_jid uses exmpp_jid:node/1, etc. that returns binaries end, @@ -575,7 +577,7 @@ {result, Subs} = node_call(Type, get_subscriptions, [NodeID, Subscriber]), SubIDs = lists:foldl(fun({subscribed, SID}, Acc) -> -@@ -2566,7 +2394,7 @@ +@@ -2568,7 +2396,7 @@ end. write_sub(Subscriber, NodeID, SubID, Options) -> @@ -584,7 +586,7 @@ {error, notfound} -> {error, extended_error('not-acceptable', "invalid-subid")}; {result, _} -> -@@ -2739,8 +2567,8 @@ +@@ -2741,8 +2569,8 @@ ?XMLATTR('subsription', subscription_to_string(Sub)) | nodeAttr(Node)]}]}]}, ejabberd_router ! {route, service_jid(Host), JID, Stanza} end, @@ -595,7 +597,7 @@ true -> Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> -@@ -3027,7 +2855,7 @@ +@@ -3029,7 +2857,7 @@ {Depth, [{N, get_node_subs(N)} || N <- Nodes]} end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))} end, @@ -604,7 +606,7 @@ {result, CollSubs} -> CollSubs; _ -> [] end. -@@ -3041,9 +2869,9 @@ +@@ -3043,9 +2871,9 @@ get_options_for_subs(NodeID, Subs) -> lists:foldl(fun({JID, subscribed, SubID}, Acc) -> @@ -616,7 +618,7 @@ _ -> Acc end; (_, Acc) -> -@@ -3238,6 +3066,30 @@ +@@ -3240,6 +3068,30 @@ Result end. @@ -647,7 +649,7 @@ %% @spec (Host, Options) -> MaxItems %% Host = host() %% Options = [Option] -@@ -3614,7 +3466,13 @@ +@@ -3616,7 +3468,13 @@ tree_action(Host, Function, Args) -> ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), Fun = fun() -> tree_call(Host, Function, Args) end, @@ -662,7 +664,7 @@ %% @doc

    node plugin call.

    node_call(Type, Function, Args) -> -@@ -3634,13 +3492,13 @@ +@@ -3636,13 +3494,13 @@ node_action(Host, Type, Function, Args) -> ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), @@ -678,7 +680,7 @@ case tree_call(Host, get_node, [Host, Node]) of N when is_record(N, pubsub_node) -> case Action(N) of -@@ -3653,8 +3511,15 @@ +@@ -3655,8 +3513,15 @@ end end, Trans). @@ -696,7 +698,7 @@ {result, Result} -> {result, Result}; {error, Error} -> {error, Error}; {atomic, {result, Result}} -> {result, Result}; -@@ -3662,6 +3527,15 @@ +@@ -3664,6 +3529,15 @@ {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), {error, 'internal-server-error'}; @@ -712,7 +714,7 @@ {'EXIT', Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), {error, 'internal-server-error'}; -@@ -3670,6 +3544,16 @@ +@@ -3672,6 +3546,16 @@ {error, 'internal-server-error'} end. diff --git a/src/mod_pubsub/pubsub_subscription.erl b/src/mod_pubsub/pubsub_subscription.erl index e00dacd37..eacc63d16 100644 --- a/src/mod_pubsub/pubsub_subscription.erl +++ b/src/mod_pubsub/pubsub_subscription.erl @@ -38,8 +38,6 @@ read_subscription/3, write_subscription/4]). --include_lib("stdlib/include/qlc.hrl"). - -include("pubsub.hrl"). -include_lib("exmpp/include/exmpp.hrl"). @@ -94,30 +92,34 @@ init() -> subscribe_node(JID, NodeID, Options) -> try mnesia:sync_dirty(fun add_subscription/3, [JID, NodeID, Options]) of - Result -> {result, Result} - catch - Error -> Error + {error, Error} -> {error, Error}; + Result -> {result, Result} + catch + Error -> Error end. unsubscribe_node(JID, NodeID, SubID) -> try mnesia:sync_dirty(fun delete_subscription/3, [JID, NodeID, SubID]) of + {error, Error} -> {error, Error}; Result -> {result, Result} catch - Error -> Error + Error -> Error end. get_subscription(JID, NodeID, SubID) -> try mnesia:sync_dirty(fun read_subscription/3, [JID, NodeID, SubID]) of - Result -> {result, Result} + {error, Error} -> {error, Error}; + Result -> {result, Result} catch - Error -> Error + Error -> Error end. set_subscription(JID, NodeID, SubID, Options) -> try mnesia:sync_dirty(fun write_subscription/4, [JID, NodeID, SubID, Options]) of + {error, Error} -> {error, Error}; Result -> {result, Result} catch Error -> Error @@ -167,26 +169,23 @@ create_table() -> add_subscription(_JID, _NodeID, Options) -> SubID = make_subid(), - Record = #pubsub_subscription{subid = SubID, options = Options}, - mnesia:write(Record), + mnesia:write(#pubsub_subscription{subid = SubID, options = Options}), SubID. -delete_subscription(JID, NodeID, SubID) -> - Sub = read_subscription(JID, NodeID, SubID), - mnesia:delete({pubsub_subscription, SubID}), - Sub. +delete_subscription(_JID, _NodeID, SubID) -> + mnesia:delete({pubsub_subscription, SubID}). read_subscription(_JID, _NodeID, SubID) -> - Q = qlc:q([Sub || Sub <- mnesia:table(pubsub_subscription), - Sub#pubsub_subscription.subid == SubID]), - case qlc:e(Q) of - [Sub] -> Sub; - [] -> mnesia:abort({error, notfound}) + case mnesia:read({pubsub_subscription, SubID}) of + [Sub] -> Sub; + _ -> {error, notfound} end. write_subscription(JID, NodeID, SubID, Options) -> - Sub = read_subscription(JID, NodeID, SubID), - mnesia:write(Sub#pubsub_subscription{options = Options}). + case read_subscription(JID, NodeID, SubID) of + {error, notfound} -> {error, notfound}; + Sub -> mnesia:write(Sub#pubsub_subscription{options = Options}) + end. make_subid() -> {T1, T2, T3} = now(), From b4c161e04ae85b23cb78ad36e429ec545f67777f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Sautret?= Date: Thu, 10 Sep 2009 16:59:58 +0000 Subject: [PATCH 540/582] Merge r2592 and r2593 from trunk: Fix pubsub tables constraints in MySQL schema creation script. Add a "created_at" column to some tables in the MySQL schema to store a timestamp (thanks to Pedro Melo, EJAB-376). SVN Revision: 2594 --- src/odbc/mysql.sql | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/odbc/mysql.sql b/src/odbc/mysql.sql index 8e1d242c4..a7732ba45 100644 --- a/src/odbc/mysql.sql +++ b/src/odbc/mysql.sql @@ -10,7 +10,7 @@ -- 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., 59 Temple Place, Suite 330, Boston, MA @@ -22,7 +22,8 @@ SET table_type=InnoDB; CREATE TABLE users ( username varchar(250) PRIMARY KEY, - password text NOT NULL + password text NOT NULL, + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ) CHARACTER SET utf8; @@ -42,7 +43,8 @@ CREATE TABLE rosterusers ( askmessage text NOT NULL, server character(1) NOT NULL, subscribe text NOT NULL, - type text + type text, + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ) CHARACTER SET utf8; CREATE UNIQUE INDEX i_rosteru_user_jid ON rosterusers(username(75), jid(75)); @@ -61,7 +63,8 @@ CREATE INDEX pk_rosterg_user_jid ON rostergroups(username(75), jid(75)); CREATE TABLE spool ( username varchar(250) NOT NULL, xml text NOT NULL, - seq BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE + seq BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE, + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ) CHARACTER SET utf8; CREATE INDEX i_despool USING BTREE ON spool(username); @@ -69,7 +72,8 @@ CREATE INDEX i_despool USING BTREE ON spool(username); CREATE TABLE vcard ( username varchar(250) PRIMARY KEY, - vcard text NOT NULL + vcard text NOT NULL, + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ) CHARACTER SET utf8; @@ -120,7 +124,8 @@ CREATE TABLE privacy_default_list ( CREATE TABLE privacy_list ( username varchar(250) NOT NULL, name varchar(250) NOT NULL, - id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE, + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ) CHARACTER SET utf8; CREATE INDEX i_privacy_list_username USING BTREE ON privacy_list(username); @@ -142,7 +147,8 @@ CREATE TABLE privacy_list_data ( CREATE TABLE private_storage ( username varchar(250) NOT NULL, namespace varchar(250) NOT NULL, - data text NOT NULL + data text NOT NULL, + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ) CHARACTER SET utf8; CREATE INDEX i_private_storage_username USING BTREE ON private_storage(username); @@ -175,14 +181,14 @@ CREATE TABLE pubsub_node_option ( val text ) CHARACTER SET utf8; CREATE INDEX i_pubsub_node_option_nodeid ON pubsub_node_option(nodeid); -ALTER TABLE `pubsub_node_option` ADD FOREIGN KEY (`nodeid`) REFERENCES `ejabberd`.`pubsub_node` (`nodeid`) ON DELETE CASCADE; +ALTER TABLE `pubsub_node_option` ADD FOREIGN KEY (`nodeid`) REFERENCES `pubsub_node` (`nodeid`) ON DELETE CASCADE; CREATE TABLE pubsub_node_owner ( nodeid bigint, owner text ) CHARACTER SET utf8; CREATE INDEX i_pubsub_node_owner_nodeid ON pubsub_node_owner(nodeid); -ALTER TABLE `pubsub_node_owner` ADD FOREIGN KEY (`nodeid`) REFERENCES `ejabberd`.`pubsub_node` (`nodeid`) ON DELETE CASCADE; +ALTER TABLE `pubsub_node_owner` ADD FOREIGN KEY (`nodeid`) REFERENCES `pubsub_node` (`nodeid`) ON DELETE CASCADE; CREATE TABLE pubsub_state ( nodeid bigint, @@ -193,11 +199,11 @@ CREATE TABLE pubsub_state ( ) CHARACTER SET utf8; CREATE INDEX i_pubsub_state_jid ON pubsub_state(jid(60)); CREATE UNIQUE INDEX i_pubsub_state_tuple ON pubsub_state(nodeid, jid(60)); -ALTER TABLE `pubsub_state` ADD FOREIGN KEY (`nodeid`) REFERENCES `ejabberd`.`pubsub_node` (`nodeid`) ON DELETE CASCADE; +ALTER TABLE `pubsub_state` ADD FOREIGN KEY (`nodeid`) REFERENCES `pubsub_node` (`nodeid`) ON DELETE CASCADE; CREATE TABLE pubsub_item ( nodeid bigint, - itemid text, + itemid text, publisher text, creation text, modification text, @@ -205,7 +211,7 @@ CREATE TABLE pubsub_item ( ) CHARACTER SET utf8; CREATE INDEX i_pubsub_item_itemid ON pubsub_item(itemid(36)); CREATE UNIQUE INDEX i_pubsub_item_tuple ON pubsub_item(nodeid, itemid(36)); -ALTER TABLE `pubsub_item` ADD FOREIGN KEY (`nodeid`) REFERENCES `ejabberd`.`pubsub_node` (`nodeid`) ON DELETE CASCADE; +ALTER TABLE `pubsub_item` ADD FOREIGN KEY (`nodeid`) REFERENCES `pubsub_node` (`nodeid`) ON DELETE CASCADE; CREATE TABLE pubsub_subscription_opt ( subid text, From bb1fca058de471395791df747b4d0839ed39b6a3 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 18 Sep 2009 13:33:12 +0000 Subject: [PATCH 541/582] Return terminal binding condition on max stanza size limit (thanks to Aleksey) SVN Revision: 2602 --- src/web/ejabberd_http_bind.erl | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index ddd53cccc..9e379c66a 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -180,7 +180,7 @@ process_request(Data, IP) -> {ok, {"", Rid, Attrs, Payload}} -> case xml:get_attr_s("to",Attrs) of "" -> - ?INFO_MSG("Session not created (Improper addressing).~nAttributes: ~p", [Attrs]), + ?ERROR_MSG("Session not created (Improper addressing)", []), {200, ?HEADER, ""}; @@ -216,8 +216,16 @@ process_request(Data, IP) -> end, handle_http_put(Sid, Rid, Attrs, Payload2, PayloadSize, StreamStart, IP); - {error, size_limit} -> - {413, ?HEADER, "Request Too Large"}; + {size_limit, Sid} -> + case mnesia:dirty_read({http_bind, Sid}) of + [] -> + {404, ?HEADER, ""}; + [#http_bind{pid = FsmRef}] -> + gen_fsm:sync_send_all_state_event(FsmRef, {stop, close}), + {200, ?HEADER, "Request Too Large"} + end; _ -> ?DEBUG("Received bad request: ~p", [Data]), {400, ?HEADER, ""} @@ -396,9 +404,7 @@ handle_sync_event(#http_put{rid = Rid}, ?DEBUG("Shaper timer for RID ~p: ~p", [Rid, Reply]), {reply, Reply, StateName, StateData}; -handle_sync_event(#http_put{rid = _Rid, attrs = _Attrs, - payload_size = PayloadSize, - hold = _Hold} = Request, +handle_sync_event(#http_put{payload_size = PayloadSize} = Request, _From, StateName, StateData) -> ?DEBUG("New request: ~p",[Request]), %% Updating trafic shaper @@ -1076,10 +1082,7 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> end end. -parse_request(_Data, PayloadSize, MaxStanzaSize) - when PayloadSize > MaxStanzaSize -> - {error, size_limit}; -parse_request(Data, _PayloadSize, _MaxStanzaSize) -> +parse_request(Data, PayloadSize, MaxStanzaSize) -> ?DEBUG("--- incoming data --- ~n~s~n --- END --- ", [Data]), %% MR: I do not think it works if put put several elements in the %% same body: @@ -1106,7 +1109,12 @@ parse_request(Data, _PayloadSize, _MaxStanzaSize) -> end end, Els), Sid = xml:get_attr_s("sid",Attrs), - {ok, {Sid, Rid, Attrs, FixedEls}} + if + PayloadSize =< MaxStanzaSize -> + {ok, {Sid, Rid, Attrs, FixedEls}}; + true -> + {size_limit, Sid} + end end end; {xmlelement, _Name, _Attrs, _Els} -> From 36676f0719d6852685199abe00b99aeab62e5ca5 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 18 Sep 2009 13:44:12 +0000 Subject: [PATCH 542/582] fix missing member affiliation on odbc plugin SVN Revision: 2604 --- src/mod_pubsub/node_hometree_odbc.erl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mod_pubsub/node_hometree_odbc.erl b/src/mod_pubsub/node_hometree_odbc.erl index 801141b3b..9b5500493 100644 --- a/src/mod_pubsub/node_hometree_odbc.erl +++ b/src/mod_pubsub/node_hometree_odbc.erl @@ -1296,6 +1296,7 @@ decode_node(N) -> ?PUBSUB:string_to_node(N). decode_affiliation("o") -> owner; decode_affiliation("p") -> publisher; +decode_affiliation("m") -> member; decode_affiliation("c") -> outcast; decode_affiliation(_) -> none. @@ -1315,6 +1316,7 @@ encode_jid(JID) -> ?PUBSUB:escape(jlib:jid_to_string(JID)). encode_affiliation(owner) -> "o"; encode_affiliation(publisher) -> "p"; +encode_affiliation(member) -> "m"; encode_affiliation(outcast) -> "c"; encode_affiliation(_) -> "n". From 6bdf4aa960654150b416f00c7eeb00bb064bab9d Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Sun, 20 Sep 2009 08:14:24 +0000 Subject: [PATCH 543/582] improve configure parsing in iq_pubsub (sync with ejabberd 2.1.0) SVN Revision: 2605 --- src/mod_pubsub/mod_pubsub.erl | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 3aa758006..700cc7674 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -1185,20 +1185,15 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang) -> iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, all, plugins(ServerHost)). iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) -> - WithoutCdata = exmpp_xml:remove_cdata_from_list(SubEl#xmlel.children), - Configuration = lists:filter(fun(#xmlel{name = 'configure'}) -> true; - (_) -> false - end, WithoutCdata), - Action = WithoutCdata -- Configuration, - case Action of - [#xmlel{name = Name, attrs = Attrs, children = Els}] -> + case exmpp_xml:remove_cdata_from_list(SubEl#xmlel.children) of + [#xmlel{name = Name, attrs = Attrs, children = Els} | Rest] -> Node = case Host of {_, _, _} -> exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false); _ -> string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false)) end, case {IQType, Name} of {set, 'create'} -> - Config = case Configuration of + Config = case Rest of [#xmlel{name = 'configure', children = C}] -> C; _ -> [] end, From 169a0471b95e2fb307f800b1e1e7ddc23bbef169 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 21 Sep 2009 10:14:06 +0000 Subject: [PATCH 544/582] Document more ejabberd commands in the Guide (EJAB-1041) SVN Revision: 2609 --- doc/guide.html | 7 ++++--- doc/guide.tex | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index db5244ae0..cd7257aa1 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -3354,10 +3354,8 @@ Available commands in this ejabberd node: backup file Store the database to backup file connected_users List all established sessions connected_users_number Get the number of established sessions - delete_expired_messages Delete expired offline messages from database - delete_old_messages days Delete offline messages older than DAYS ... -

    The more interesting ones are: +

    The most interesting ones are:

    reopen_log
    Reopen the log files after they were renamed. If the old files were not renamed before calling this command, @@ -3393,6 +3391,9 @@ There exist tutorials to
    delete_expired_messages
    This option can be used to delete old messages in offline storage. This might be useful when the number of offline messages is very high. +
    delete_old_messages days
    Delete offline messages older than the given days. +
    register user host password
    Register an account in that domain with the given password. +
    unregister user host
    Unregister the given account.

    4.2.2  Restrict Execution with AccessCommands

    The frontends can be configured to restrict access to certain commands. In that case, authentication information must be provided. diff --git a/doc/guide.tex b/doc/guide.tex index 17665a922..47cf54eb0 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -4297,12 +4297,10 @@ Available commands in this ejabberd node: backup file Store the database to backup file connected_users List all established sessions connected_users_number Get the number of established sessions - delete_expired_messages Delete expired offline messages from database - delete_old_messages days Delete offline messages older than DAYS ... \end{verbatim} -The more interesting ones are: +The most interesting ones are: \begin{description} \titem{reopen\_log} Reopen the log files after they were renamed. If the old files were not renamed before calling this command, @@ -4340,6 +4338,9 @@ The more interesting ones are: \titem{delete\_expired\_messages} This option can be used to delete old messages in offline storage. This might be useful when the number of offline messages is very high. +\titem{delete\_old\_messages days} Delete offline messages older than the given days. +\titem{register user host password} Register an account in that domain with the given password. +\titem{unregister user host} Unregister the given account. \end{description} \makesubsection{accesscommands}{Restrict Execution with AccessCommands} From 4ce2890af0ed6c92d820825db8b23424e1bb7443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20R=C3=A9mond?= Date: Wed, 23 Sep 2009 12:37:58 +0000 Subject: [PATCH 545/582] Replaced Jabber references in config file with XMPP, official name of the protocol SVN Revision: 2612 --- src/ejabberd.cfg.example | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index a083613a1..27111252d 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -74,7 +74,7 @@ %% %% watchdog_admins: Only useful for developers: if an ejabberd process -%% consumes a lot of memory, send live notifications to these Jabber +%% consumes a lot of memory, send live notifications to these XMPP %% accounts. %% %%{watchdog_admins, ["bob@example.com"]}. @@ -91,9 +91,9 @@ {hosts, ["localhost"]}. %% -%% route_subdomains: Delegate subdomains to other Jabber server. +%% route_subdomains: Delegate subdomains to other XMPP server. %% For example, if this ejabberd serves example.org and you want -%% to allow communication with a Jabber server called im.example.org. +%% to allow communication with a XMPP server called im.example.org. %% %%{route_subdomains, s2s}. @@ -348,7 +348,7 @@ %%%' ACCESS CONTROL LISTS %% -%% The 'admin' ACL grants administrative privileges to Jabber accounts. +%% The 'admin' ACL grants administrative privileges to XMPP accounts. %% You can put as many accounts as you want. %% %%{acl, admin, {user, "aleksey", "localhost"}}. @@ -515,11 +515,11 @@ %% a message with this subject and body. %% {welcome_message, {"Welcome!", - "Hi.\nWelcome to this Jabber server."}}, + "Hi.\nWelcome to this XMPP server."}}, %% %% When a user registers, send a notification to - %% these Jabber accounts. + %% these XMPP accounts. %% %%{registration_watchers, ["admin1@example.org"]}, From bac5c30380e4187e3d7111038591625f6235ff6d Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 23 Sep 2009 15:29:34 +0000 Subject: [PATCH 546/582] =?UTF-8?q?Replace=20several=20mentions=20of=20Jab?= =?UTF-8?q?ber=20to=20XMPP=20(thanks=20to=20Nicolas=20V=C3=A9rit=C3=A9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SVN Revision: 2614 --- doc/dev.html | 6 ++-- doc/dev.tex | 7 ++-- doc/features.tex | 4 +-- doc/guide.html | 86 ++++++++++++++++++++++---------------------- doc/guide.tex | 93 ++++++++++++++++++++++++------------------------ 5 files changed, 99 insertions(+), 97 deletions(-) diff --git a/doc/dev.html b/doc/dev.html index 9b001d924..2df7e42f1 100644 --- a/doc/dev.html +++ b/doc/dev.html @@ -145,7 +145,7 @@ Support for virtual hosting.

    3  How it Works

    -

    A Jabber domain is served by one or more ejabberd nodes. These nodes can +

    A XMPP domain is served by one or more ejabberd nodes. These nodes can be run on different machines that are connected via a network. They all must have the ability to connect to port 4369 of all another nodes, and must have the same magic cookie (see Erlang/OTP documentation, in other words the file @@ -158,7 +158,7 @@ router;

  • session manager;
  • S2S manager;
  • -

    3.1  Router

    This module is the main router of Jabber packets on each node. It routes +

    3.1  Router

    This module is the main router of XMPP packets on each node. It routes them based on their destinations domains. It has two tables: local and global routes. First, domain of packet destination searched in local table, and if it found, then the packet is routed to appropriate process. If no, then it @@ -172,7 +172,7 @@ session manager, else it is processed depending on it’s content.

    -

    3.4  S2S Manager

    This module routes packets to other Jabber servers. First, it checks if an +

    3.4  S2S Manager

    This module routes packets to other XMPP servers. First, it checks if an open S2S connection from the domain of the packet source to the domain of packet destination already exists. If it is open on another node, then it routes the packet to S2S manager on that node, if it is open on this node, then diff --git a/doc/dev.tex b/doc/dev.tex index e94c6b708..f597d591e 100644 --- a/doc/dev.tex +++ b/doc/dev.tex @@ -26,6 +26,7 @@ \newcommand{\ns}[1]{\texttt{#1}} \newcommand{\ejabberd}{\texttt{ejabberd}} \newcommand{\Jabber}{Jabber} +\newcommand{\XMPP}{XMPP} %% Modules \newcommand{\module}[1]{\texttt{#1}} @@ -100,7 +101,7 @@ \label{howitworks} -A \Jabber{} domain is served by one or more \ejabberd{} nodes. These nodes can +A \XMPP{} domain is served by one or more \ejabberd{} nodes. These nodes can be run on different machines that are connected via a network. They all must have the ability to connect to port 4369 of all another nodes, and must have the same magic cookie (see Erlang/OTP documentation, in other words the file @@ -121,7 +122,7 @@ Each \ejabberd{} node have following modules: \subsection{Router} -This module is the main router of \Jabber{} packets on each node. It routes +This module is the main router of \XMPP{} packets on each node. It routes them based on their destinations domains. It has two tables: local and global routes. First, domain of packet destination searched in local table, and if it found, then the packet is routed to appropriate process. If no, then it @@ -147,7 +148,7 @@ the packet is sent to session manager on that node. \subsection{S2S Manager} -This module routes packets to other \Jabber{} servers. First, it checks if an +This module routes packets to other \XMPP{} servers. First, it checks if an open S2S connection from the domain of the packet source to the domain of packet destination already exists. If it is open on another node, then it routes the packet to S2S manager on that node, if it is open on this node, then diff --git a/doc/features.tex b/doc/features.tex index 8b677a81f..1a512571f 100644 --- a/doc/features.tex +++ b/doc/features.tex @@ -70,7 +70,7 @@ %% Fancy header \fancyhf{} \pagestyle{fancy} -\rhead{\textcolor{ejblue}{The Expandable Jabber Daemon.}} +\rhead{\textcolor{ejblue}{The Expandable Jabber/XMPP Daemon.}} \renewcommand{\headrule}{{\color{ejblue}% \hrule width\headwidth height\headrulewidth \vskip-\headrulewidth}} \lhead{\setlength{\unitlength}{-6mm} @@ -133,4 +133,4 @@ % "What I find interesting is that *no* XMPP servers truly provide clustering. This includes all the commercial % servers. The one partial exception appears to be ejabberd, which can cluster certain data such as sessions, % but not all services such as MUC." -% * try it today: links to migration tutorials \ No newline at end of file +% * try it today: links to migration tutorials diff --git a/doc/guide.html b/doc/guide.html index cd7257aa1..762ed968d 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -109,7 +109,7 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}

  • 2.4.7  Specific Notes for Sun Solaris
  • 2.4.8  Specific Notes for Microsoft Windows
  • -
  • 2.5  Create a Jabber Account for Administration +
  • 2.5  Create a XMPP Account for Administration
  • 2.6  Upgrading ejabberd
  • Chapter 3  Configuring ejabberd @@ -381,7 +381,7 @@ To get the full list run the command: See section 3.2 for more information.

  • --enable-full-xml
    Enable the use of XML based optimisations. It will for example use CDATA to escape characters in the XMPP stream. - Use this option only if you are sure your Jabber clients include a fully compliant XML parser.

    --disable-transient-supervisors
    + Use this option only if you are sure your XMPP clients include a fully compliant XML parser.

    --disable-transient-supervisors
    Disable the use of Erlang/OTP supervision for transient processes.

    2.4.4  Install

    @@ -493,22 +493,22 @@ to the PATH environment variable. nmake -f Makefile.win32

  • Edit the file ejabberd\src\ejabberd.cfg and run
    werl -s ejabberd -name ejabberd
    -
  • -

    2.5  Create a Jabber Account for Administration

    You need a Jabber account and grant him administrative privileges +

    +

    2.5  Create a XMPP Account for Administration

    You need a XMPP account and grant him administrative privileges to enter the ejabberd Web Admin:

    1. -Register a Jabber account on your ejabberd server, for example admin1@example.org. -There are two ways to register a Jabber account: +Register a XMPP account on your ejabberd server, for example admin1@example.org. +There are two ways to register a XMPP account:
      1. Using ejabberdctl (see section 4.1):
        ejabberdctl register admin1 example.org FgT5bk3
        -
      2. Using a Jabber client and In-Band Registration (see section 3.3.17). +
      3. Using a XMPP client and In-Band Registration (see section 3.3.17).
      -
    2. Edit the ejabberd configuration file to give administration rights to the Jabber account you created: +
    3. Edit the ejabberd configuration file to give administration rights to the XMPP account you created:
      {acl, admins, {user, "admin1", "example.org"}}.
       {access, configure, [{allow, admins}]}.
      -
      You can grant administrative privileges to many Jabber accounts, -and also to accounts in other Jabber servers. +You can grant administrative privileges to many XMPP accounts, +and also to accounts in other XMPP servers.
    4. Restart ejabberd to load the new configuration.
    5. Open the Web Admin (http://server:port/admin/) in your favourite browser. Make sure to enter the full JID as username (in this @@ -705,8 +705,8 @@ This option enables HTTP Binding (JWChat (check the tutorials to install JWChat with ejabberd and an embedded local web server @@ -716,8 +716,8 @@ This option enables HTTP Polling (JWChat.

      The maximum period of time to keep a client session active without an incoming POST request can be configured with the global option http_poll_timeout. The default value is five minutes. @@ -788,7 +788,7 @@ Define properties to use for DNS resolving. Allowed Properties are: timeout in seconds which default value is 10 and retries which default value is 2.

    {s2s_default_policy, allow|deny}
    -The default policy for incoming and outgoing s2s connections to other Jabber servers. +The default policy for incoming and outgoing s2s connections to other XMPP servers. The default value is allow.
    {{s2s_host, Host}, allow|deny}
    Defines if incoming and outgoing s2s connections with a specific remote host are allowed or denied. @@ -849,7 +849,7 @@ on port 5223 (SSL, IP 192.168.0.1 and fdca:8ab6:a243:75ef::1) and denied for the user called ‘bad’.
  • s2s connections are listened for on port 5269 (all IPv4 addresses) with STARTTLS for secured traffic enabled. -Incoming and outgoing connections of remote Jabber servers are denied, +Incoming and outgoing connections of remote XMPP servers are denied, only two servers can connect: "jabber.example.org" and "example.com".
  • Port 5280 is serving the Web Admin and the HTTP Polling service in all the IPv4 addresses. Note @@ -947,7 +947,7 @@ you have to make the transports log and do XDB by themselves: </log> <!-- - Some Jabber server implementations do not provide + Some XMPP server implementations do not provide XDB services (for example, jabberd2 and ejabberd). xdb_file.so is loaded in to handle all XDB requests. --> @@ -1160,10 +1160,10 @@ can be either a number, or infinity. The default value is infinity.

    The syntax is:

    {access, max_user_sessions, [ {MaxNumber, ACLName}, ...]}.

    This example limits the number of sessions per user to 5 for all users, and to 10 for admins:

    {access, max_user_sessions, [{10, admin}, {5, all}]}.
    -

    -

    Several connections to a remote Jabber server with ACL

    +

    +

    Several connections to a remote XMPP server with ACL

    The special access max_s2s_connections specifies how many -simultaneus S2S connections can be established to a specific remote Jabber server. +simultaneus S2S connections can be established to a specific remote XMPP server. The default value is 1. There’s also available the access max_s2s_connections_per_node.

    The syntax is:

    {access, max_s2s_connections, [ {MaxNumber, ACLName}, ...]}.

    Examples: @@ -1192,7 +1192,7 @@ To define a shaper named ‘normal’ with traffic speed limi

  • 3.1.7  Default Language

    The option language defines the default language of server strings that -can be seen by Jabber clients. If a Jabber client does not support +can be seen by XMPP clients. If a XMPP client does not support xml:lang, the specified language is used.

    The option syntax is:

    {language, Language}.

    The default value is en. In order to take effect there must be a translation file @@ -1896,7 +1896,7 @@ the "@HOST@" keyword must be used:

    This module enables configured users to broadcast announcements and to set the message of the day (MOTD). Configured users can perform these actions with a -Jabber client either using Ad-hoc commands +XMPP client either using Ad-hoc commands or sending messages to specific JIDs.

    The Ad-hoc commands are listed in the Server Discovery. For this feature to work, mod_adhoc must be enabled.

    The specific JIDs where messages can be sent are listed bellow. The first JID in each entry will apply only to the specified virtual host @@ -1963,9 +1963,9 @@ disabled for instances of ejabberd with hundreds of thousands users.

    This module adds support for Service Discovery (XEP-0030). With this module enabled, services on your server can be discovered by -Jabber clients. Note that ejabberd has no modules with support +XMPP clients. Note that ejabberd has no modules with support for the superseded Jabber Browsing (XEP-0011) and Agent Information -(XEP-0094). Accordingly, Jabber clients need to have support for +(XEP-0094). Accordingly, XMPP clients need to have support for the newer Service Discovery protocol if you want them be able to discover the services you offer.

    Options:

    @@ -2031,9 +2031,9 @@ and admin addresses for both the main server and the vJUD service: ]}.

    3.3.5  mod_echo

    -

    This module simply echoes any Jabber +

    This module simply echoes any XMPP packet back to the sender. This mirror can be of interest for -ejabberd and Jabber client debugging.

    Options: +ejabberd and XMPP client debugging.

    Options:

    {host, HostName}
    This option defines the Jabber ID of the @@ -2076,7 +2076,7 @@ resource at which this service will be hosted.

    To use HTTP-Binding, enable

    With this configuration, the module will serve the requests sent to http://example.org:5280/http-bind/ Remember that this page is not designed to be used by web browsers, -it is used by Jabber clients that support XMPP over Bosh.

    If you want to set the service in a different URI path or use a different module, +it is used by XMPP clients that support XMPP over Bosh.

    If you want to set the service in a different URI path or use a different module, you can configure it manually using the option request_handlers. For example:

    {listen, 
    @@ -2185,7 +2185,7 @@ Sending public and private messages to room occupants.
     

    The MUC service allows any Jabber ID to register a nickname, so nobody else can use that nickname in any room in the MUC service. To register a nickname, open the Service Discovery in your -Jabber client and register in the MUC service.

    This module supports clustering and load +XMPP client and register in the MUC service.

    This module supports clustering and load balancing. One module can be started per cluster node. Rooms are distributed at creation time on all available MUC module instances. The multi-user chat module is clustered but the rooms @@ -2276,7 +2276,7 @@ discarded. A good value for this option is 4 seconds.

    {default_room_options, [ {OptionName, OptionValue}, ...]}
    This module option allows to define the desired default room options. Note that the creator of a room can modify the options of his room -at any time using a Jabber client with MUC capability. +at any time using a XMPP client with MUC capability. The available room options and the default values are:
    {allow_change_subj, true|false}
    Allow occupants to change the subject. @@ -2313,7 +2313,7 @@ In the first example everyone is allowed to use the Multi-User Chat service. Everyone will also be able to create new rooms but only the user admin@example.org is allowed to administrate any room. In this example he is also a global administrator. When admin@example.org -sends a message such as ‘Tomorrow, the Jabber server will be moved +sends a message such as ‘Tomorrow, the XMPP server will be moved to new hardware. This will involve service breakdowns around 23:00 UMT. We apologise for this inconvenience.’ to conference.example.org, it will be displayed in all active rooms. In this example the history @@ -2398,7 +2398,7 @@ the newly created rooms have by default those options.

    3.3.10  mod_muc_log

    This module enables optional logging of Multi-User Chat (MUC) public conversations to HTML. Once you enable this module, users can join a room using a MUC capable -Jabber client, and if they have enough privileges, they can request the +XMPP client, and if they have enough privileges, they can request the configuration form in which they can set the option to enable room logging.

    Features:

    • Room details are added on top of each page: room title, JID, @@ -2577,7 +2577,7 @@ and if a client does not answer to the ping in less than 32 seconds, its connect

      3.3.13  mod_privacy

      This module implements Blocking Communication (also known as Privacy Rules) as defined in section 10 from XMPP IM. If end users have support for it in -their Jabber client, they will be able to: +their XMPP client, they will be able to:

      • Retrieving one’s privacy lists. @@ -2605,7 +2605,7 @@ the processing discipline for Blocking Communication (jabber:iq:privacy

        3.3.14  mod_private

        This module adds support for Private XML Storage (XEP-0049):

        -Using this method, Jabber entities can store private data on the server and +Using this method, XMPP entities can store private data on the server and retrieve it whenever necessary. The data stored might be anything, as long as it is valid XML. One typical usage for this namespace is the server-side storage of client-specific preferences; another is Bookmark Storage (XEP-0048). @@ -2720,7 +2720,7 @@ The following example will use node_tune instead of node_pep for every PEP node

        3.3.17  mod_register

        This module adds support for In-Band Registration (XEP-0077). This protocol -enables end users to use a Jabber client to: +enables end users to use a XMPP client to:

        • Register a new account on the server.
        • Change the password from an existing account on the server. @@ -2824,7 +2824,7 @@ Important: if you use mod_shared_roster, you must disable this option. ]}.

          3.3.19  mod_service_log

          -

          This module adds support for logging end user packets via a Jabber message +

          This module adds support for logging end user packets via a XMPP message auditing service such as Bandersnatch. All user packets are encapsulated in a <route/> element and sent to the specified @@ -2859,7 +2859,7 @@ create groups of people that can see members from (other) groups in their rosters. The big advantages of this feature are that end users do not need to manually add all users to their rosters, and that they cannot permanently delete users from the shared roster groups. -A shared roster group can have members from any Jabber server, +A shared roster group can have members from any XMPP server, but the presence will only be available from and to members of the same virtual host where the group is created.

          Shared roster groups can be edited only via the Web Admin. Each group has a unique identification and the following parameters: @@ -3409,7 +3409,7 @@ ArgumentValue = any()

          The default value is to not define any restriction: []. If at least one restriction is defined, then the frontend expects that authentication information is provided when executing a command. -The authentication information is Username, Hostname and Password of a local Jabber account +The authentication information is Username, Hostname and Password of a local XMPP account that has permission to execute the corresponding command. This means that the account must be registered in the local ejabberd, because the information will be verified. @@ -3515,9 +3515,9 @@ the environment variable EJABBERD_DOC_PATH. See section 4.1.2.

          4.4  Ad-hoc Commands

          If you enable mod_configure and mod_adhoc, you can perform several administrative tasks in ejabberd -with a Jabber client. +with a XMPP client. The client must support Ad-Hoc Commands (XEP-0050), -and you must login in the Jabber server with +and you must login in the XMPP server with an account with proper privileges.

          4.5  Change Computer Hostname

          ejabberd uses the distributed Mnesia database. Being distributed, Mnesia enforces consistency of its file, @@ -3639,7 +3639,7 @@ See section 5.3.

          Chapter 6  Clustering

          6.1  How it Works

          -

          A Jabber domain is served by one or more ejabberd nodes. These nodes can +

          A XMPP domain is served by one or more ejabberd nodes. These nodes can be run on different machines that are connected via a network. They all must have the ability to connect to port 4369 of all another nodes, and must have the same magic cookie (see Erlang/OTP documentation, in other words the @@ -3653,7 +3653,7 @@ router,

        • s2s manager.

        6.1.1  Router

        -

        This module is the main router of Jabber packets on each node. It +

        This module is the main router of XMPP packets on each node. It routes them based on their destination’s domains. It uses a global routing table. The domain of the packet’s destination is searched in the routing table, and if it is found, the packet is routed to the @@ -3669,7 +3669,7 @@ resource a packet must be sent via a presence table. Then the packet is either routed to the appropriate c2s process, or stored in offline storage, or bounced back.

        6.1.4  s2s Manager

        -

        This module routes packets to other Jabber servers. First, it +

        This module routes packets to other XMPP servers. First, it checks if an opened s2s connection from the domain of the packet’s source to the domain of the packet’s destination exists. If that is the case, the s2s manager routes the packet to the process @@ -3760,7 +3760,7 @@ There are some simple and safe examples in the article

        ejabberd includes a watchdog mechanism that may be useful to developers when troubleshooting a problem related to memory usage. If a process in the ejabberd server consumes more memory than the configured threshold, -a message is sent to the Jabber accounts defined with the option +a message is sent to the XMPP accounts defined with the option watchdog_admins in the ejabberd configuration file.

        The syntax is:

        {watchdog_admins, [JID, ...]}.

        The memory consumed is measured in words: diff --git a/doc/guide.tex b/doc/guide.tex index 47cf54eb0..73491c6fc 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -59,6 +59,7 @@ \newcommand{\shell}[1]{\texttt{#1}} \newcommand{\ejabberd}{\texttt{ejabberd}} \newcommand{\Jabber}{Jabber} +\newcommand{\XMPP}{XMPP} \newcommand{\esyntax}[1]{\begin{description}\titem{#1}\end{description}} %% Modules @@ -369,7 +370,7 @@ Some options that you may be interested in modifying: \titem{--enable-full-xml} Enable the use of XML based optimisations. It will for example use CDATA to escape characters in the XMPP stream. - Use this option only if you are sure your Jabber clients include a fully compliant XML parser. + Use this option only if you are sure your XMPP clients include a fully compliant XML parser. \titem{--disable-transient-supervisors} Disable the use of Erlang/OTP supervision for transient processes. @@ -540,27 +541,27 @@ werl -s ejabberd -name ejabberd %TODO: how to compile database support on windows? -\makesection{initialadmin}{Create a Jabber Account for Administration} +\makesection{initialadmin}{Create a XMPP Account for Administration} -You need a Jabber account and grant him administrative privileges +You need a XMPP account and grant him administrative privileges to enter the \ejabberd{} Web Admin: \begin{enumerate} -\item Register a Jabber account on your \ejabberd{} server, for example \term{admin1@example.org}. - There are two ways to register a Jabber account: +\item Register a XMPP account on your \ejabberd{} server, for example \term{admin1@example.org}. + There are two ways to register a XMPP account: \begin{enumerate} \item Using \term{ejabberdctl}\ind{ejabberdctl} (see section~\ref{ejabberdctl}): \begin{verbatim} ejabberdctl register admin1 example.org FgT5bk3 \end{verbatim} - \item Using a Jabber client and In-Band Registration (see section~\ref{modregister}). + \item Using a XMPP client and In-Band Registration (see section~\ref{modregister}). \end{enumerate} -\item Edit the \ejabberd{} configuration file to give administration rights to the Jabber account you created: +\item Edit the \ejabberd{} configuration file to give administration rights to the XMPP account you created: \begin{verbatim} {acl, admins, {user, "admin1", "example.org"}}. {access, configure, [{allow, admins}]}. \end{verbatim} - You can grant administrative privileges to many Jabber accounts, - and also to accounts in other Jabber servers. + You can grant administrative privileges to many XMPP accounts, + and also to accounts in other XMPP servers. \item Restart \ejabberd{} to load the new configuration. \item Open the Web Admin (\verb|http://server:port/admin/|) in your favourite browser. Make sure to enter the \emph{full} JID as username (in this @@ -826,7 +827,7 @@ This is a detailed description of each option allowed by the listening modules: as seen in an example below. \titem{captcha} \ind{options!http-captcha} Simple web page that allows a user to fill a CAPTCHA challenge (see section \ref{captcha}). - \titem{http\_bind} \ind{options!http\_bind}\ind{protocols!XEP-0206: HTTP Binding}\ind{JWChat}\ind{web-based Jabber client} + \titem{http\_bind} \ind{options!http\_bind}\ind{protocols!XEP-0206: HTTP Binding}\ind{JWChat}\ind{web-based XMPP client} This option enables HTTP Binding (\xepref{0124} and \xepref{0206}) support. HTTP Bind enables access via HTTP requests to \ejabberd{} from behind firewalls which do not allow outgoing sockets on port 5222. @@ -835,21 +836,21 @@ This is a detailed description of each option allowed by the listening modules: If HTTP Bind is enabled, it will be available at \verb|http://server:port/http-bind/|. Be aware that support for HTTP Bind - is also needed in the \Jabber{} client. Remark also that HTTP Bind can be - interesting to host a web-based \Jabber{} client such as + is also needed in the \XMPP{} client. Remark also that HTTP Bind can be + interesting to host a web-based \XMPP{} client such as \footahref{http://jwchat.sourceforge.net/}{JWChat} (check the tutorials to install JWChat with ejabberd and an \footahref{http://www.ejabberd.im/jwchat-localserver}{embedded local web server} or \footahref{http://www.ejabberd.im/jwchat-apache}{Apache}). - \titem{http\_poll} \ind{options!http\_poll}\ind{protocols!XEP-0025: HTTP Polling}\ind{JWChat}\ind{web-based Jabber client} + \titem{http\_poll} \ind{options!http\_poll}\ind{protocols!XEP-0025: HTTP Polling}\ind{JWChat}\ind{web-based XMPP client} This option enables HTTP Polling (\xepref{0025}) support. HTTP Polling enables access via HTTP requests to \ejabberd{} from behind firewalls which do not allow outgoing sockets on port 5222. If HTTP Polling is enabled, it will be available at \verb|http://server:port/http-poll/|. Be aware that support for HTTP Polling - is also needed in the \Jabber{} client. Remark also that HTTP Polling can be - interesting to host a web-based \Jabber{} client such as + is also needed in the \XMPP{} client. Remark also that HTTP Polling can be + interesting to host a web-based \XMPP{} client such as \footahref{http://jwchat.sourceforge.net/}{JWChat}. The maximum period of time to keep a client session active without @@ -926,7 +927,7 @@ There are some additional global options that can be specified in the ejabberd c Allowed Properties are: \term{timeout} in seconds which default value is \term{10} and \term{retries} which default value is \term{2}. \titem{\{s2s\_default\_policy, allow|deny\}} - The default policy for incoming and outgoing s2s connections to other Jabber servers. + The default policy for incoming and outgoing s2s connections to other XMPP servers. The default value is \term{allow}. \titem{\{\{s2s\_host, Host\}, allow|deny\}} Defines if incoming and outgoing s2s connections with a specific remote host are allowed or denied. @@ -994,7 +995,7 @@ In this example, the following configuration defines that: for the user called `\term{bad}'. \item s2s connections are listened for on port 5269 (all IPv4 addresses) with STARTTLS for secured traffic enabled. - Incoming and outgoing connections of remote Jabber servers are denied, + Incoming and outgoing connections of remote XMPP servers are denied, only two servers can connect: "jabber.example.org" and "example.com". \item Port 5280 is serving the Web Admin and the HTTP Polling service in all the IPv4 addresses. Note @@ -1096,7 +1097,7 @@ you have to make the transports log and do \ind{XDB}XDB by themselves: @@ -1419,11 +1420,11 @@ This example limits the number of sessions per user to 5 for all users, and to 1 {access, max_user_sessions, [{10, admin}, {5, all}]}. \end{verbatim} -\makesubsubsection{configmaxs2sconns}{Several connections to a remote Jabber server with ACL} +\makesubsubsection{configmaxs2sconns}{Several connections to a remote XMPP server with ACL} \ind{options!max\_s2s\_connections} The special access \term{max\_s2s\_connections} specifies how many -simultaneus S2S connections can be established to a specific remote Jabber server. +simultaneus S2S connections can be established to a specific remote XMPP server. The default value is \term{1}. There's also available the access \term{max\_s2s\_connections\_per\_node}. @@ -1470,7 +1471,7 @@ Examples: \ind{options!language}\ind{language} The option \option{language} defines the default language of server strings that -can be seen by \Jabber{} clients. If a \Jabber{} client does not support +can be seen by \XMPP{} clients. If a \XMPP{} client does not support \option{xml:lang}, the specified language is used. The option syntax is: @@ -2527,7 +2528,7 @@ the "@HOST@" keyword must be used: This module enables configured users to broadcast announcements and to set the message of the day (MOTD). Configured users can perform these actions with a -\Jabber{} client either using Ad-hoc commands +\XMPP{} client either using Ad-hoc commands or sending messages to specific JIDs. The Ad-hoc commands are listed in the Server Discovery. @@ -2611,9 +2612,9 @@ disabled for instances of \ejabberd{} with hundreds of thousands users. This module adds support for Service Discovery (\xepref{0030}). With this module enabled, services on your server can be discovered by -\Jabber{} clients. Note that \ejabberd{} has no modules with support +\XMPP{} clients. Note that \ejabberd{} has no modules with support for the superseded Jabber Browsing (\xepref{0011}) and Agent Information -(\xepref{0094}). Accordingly, \Jabber{} clients need to have support for +(\xepref{0094}). Accordingly, \XMPP{} clients need to have support for the newer Service Discovery protocol if you want them be able to discover the services you offer. @@ -2693,9 +2694,9 @@ and admin addresses for both the main server and the vJUD service: \makesubsection{modecho}{\modecho{}} \ind{modules!\modecho{}}\ind{debugging} -This module simply echoes any \Jabber{} +This module simply echoes any \XMPP{} packet back to the sender. This mirror can be of interest for -\ejabberd{} and \Jabber{} client debugging. +\ejabberd{} and \XMPP{} client debugging. Options: \begin{description} @@ -2747,7 +2748,7 @@ and add \verb|http_bind| in the HTTP service. For example: With this configuration, the module will serve the requests sent to \verb|http://example.org:5280/http-bind/| Remember that this page is not designed to be used by web browsers, -it is used by Jabber clients that support XMPP over Bosh. +it is used by XMPP clients that support XMPP over Bosh. If you want to set the service in a different URI path or use a different module, you can configure it manually using the option \verb|request_handlers|. @@ -2890,7 +2891,7 @@ Some of the features of Multi-User Chat: The MUC service allows any Jabber ID to register a nickname, so nobody else can use that nickname in any room in the MUC service. To register a nickname, open the Service Discovery in your -Jabber client and register in the MUC service. +XMPP client and register in the MUC service. This module supports clustering and load balancing. One module can be started per cluster node. Rooms are @@ -2980,7 +2981,7 @@ Module options: \titem{\{default\_room\_options, [ \{OptionName, OptionValue\}, ...]\}} \ind{options!default\_room\_options} This module option allows to define the desired default room options. Note that the creator of a room can modify the options of his room - at any time using a Jabber client with MUC capability. + at any time using a XMPP client with MUC capability. The available room options and the default values are: \begin{description} \titem{\{allow\_change\_subj, true|false\}} Allow occupants to change the subject. @@ -3019,7 +3020,7 @@ Examples: service. Everyone will also be able to create new rooms but only the user \jid{admin@example.org} is allowed to administrate any room. In this example he is also a global administrator. When \jid{admin@example.org} - sends a message such as `Tomorrow, the \Jabber{} server will be moved + sends a message such as `Tomorrow, the \XMPP{} server will be moved to new hardware. This will involve service breakdowns around 23:00 UMT. We apologise for this inconvenience.' to \jid{conference.example.org}, it will be displayed in all active rooms. In this example the history @@ -3119,7 +3120,7 @@ defined, but some user restriction could be added as well: This module enables optional logging of Multi-User Chat (MUC) public conversations to HTML. Once you enable this module, users can join a room using a MUC capable -Jabber client, and if they have enough privileges, they can request the +XMPP client, and if they have enough privileges, they can request the configuration form in which they can set the option to enable room logging. Features: @@ -3329,7 +3330,7 @@ and if a client does not answer to the ping in less than 32 seconds, its connect This module implements Blocking Communication (also known as Privacy Rules) as defined in section 10 from XMPP IM. If end users have support for it in -their \Jabber{} client, they will be able to: +their \XMPP{} client, they will be able to: \begin{quote} \begin{itemize} \item Retrieving one's privacy lists. @@ -3361,7 +3362,7 @@ Options: This module adds support for Private XML Storage (\xepref{0049}): \begin{quote} -Using this method, Jabber entities can store private data on the server and +Using this method, XMPP entities can store private data on the server and retrieve it whenever necessary. The data stored might be anything, as long as it is valid XML. One typical usage for this namespace is the server-side storage of client-specific preferences; another is Bookmark Storage (\xepref{0048}). @@ -3495,7 +3496,7 @@ Example: \ind{modules!\modregister{}}\ind{protocols!XEP-0077: In-Band Registration}\ind{public registration} This module adds support for In-Band Registration (\xepref{0077}). This protocol -enables end users to use a \Jabber{} client to: +enables end users to use a \XMPP{} client to: \begin{itemize} \item Register a new account on the server. \item Change the password from an existing account on the server. @@ -3624,7 +3625,7 @@ This example configuration enables Roster Versioning with storage of current id: \makesubsection{modservicelog}{\modservicelog{}} \ind{modules!\modservicelog{}}\ind{message auditing}\ind{Bandersnatch} -This module adds support for logging end user packets via a \Jabber{} message +This module adds support for logging end user packets via a \XMPP{} message auditing service such as \footahref{http://www.funkypenguin.info/project/bandersnatch/}{Bandersnatch}. All user packets are encapsulated in a \verb|| element and sent to the specified @@ -3670,7 +3671,7 @@ create groups of people that can see members from (other) groups in their rosters. The big advantages of this feature are that end users do not need to manually add all users to their rosters, and that they cannot permanently delete users from the shared roster groups. -A shared roster group can have members from any Jabber server, +A shared roster group can have members from any XMPP server, but the presence will only be available from and to members of the same virtual host where the group is created. @@ -4325,14 +4326,14 @@ The most interesting ones are: \titem{import\_piefxis, export\_piefxis, export\_piefxis\_host} \ind{migrate between servers} These options can be used to migrate accounts using \xepref{0227} formatted XML files - from/to other \Jabber{}/XMPP servers + from/to other Jabber/XMPP servers or move users of a vhost to another ejabberd installation. See also \footahref{https://support.process-one.net/doc/display/P1/ejabberd+migration+kit}{ejabberd migration kit}. \titem{import\_file, import\_dir} \ind{migration from other software} These options can be used to migrate accounts using jabberd1.4 formatted XML files. - from other \Jabber{}/XMPP servers + from other Jabber/XMPP servers There exist tutorials to \footahref{http://www.ejabberd.im/migrate-to-ejabberd}{migrate from other software to ejabberd}. \titem{delete\_expired\_messages} This option can be used to delete old messages @@ -4362,7 +4363,7 @@ ArgumentValue = any() The default value is to not define any restriction: \term{[]}. If at least one restriction is defined, then the frontend expects that authentication information is provided when executing a command. -The authentication information is Username, Hostname and Password of a local Jabber account +The authentication information is Username, Hostname and Password of a local XMPP account that has permission to execute the corresponding command. This means that the account must be registered in the local ejabberd, because the information will be verified. @@ -4495,9 +4496,9 @@ See section \ref{erlangconfiguration}. If you enable \modconfigure\ and \modadhoc, you can perform several administrative tasks in \ejabberd{} -with a Jabber client. +with a XMPP client. The client must support Ad-Hoc Commands (\xepref{0050}), -and you must login in the Jabber server with +and you must login in the XMPP server with an account with proper privileges. @@ -4696,7 +4697,7 @@ write and execute those files and directories. \makesection{howitworks}{How it Works} \ind{clustering!how it works} -A \Jabber{} domain is served by one or more \ejabberd{} nodes. These nodes can +A \XMPP{} domain is served by one or more \ejabberd{} nodes. These nodes can be run on different machines that are connected via a network. They all must have the ability to connect to port 4369 of all another nodes, and must have the same magic cookie (see Erlang/OTP documentation, in other words the @@ -4715,7 +4716,7 @@ Each \ejabberd{} node has the following modules: \makesubsection{router}{Router} \ind{clustering!router} -This module is the main router of \Jabber{} packets on each node. It +This module is the main router of \XMPP{} packets on each node. It routes them based on their destination's domains. It uses a global routing table. The domain of the packet's destination is searched in the routing table, and if it is found, the packet is routed to the @@ -4740,7 +4741,7 @@ storage, or bounced back. \makesubsection{s2smanager}{s2s Manager} \ind{clustering!s2s manager} -This module routes packets to other \Jabber{} servers. First, it +This module routes packets to other \XMPP{} servers. First, it checks if an opened s2s connection from the domain of the packet's source to the domain of the packet's destination exists. If that is the case, the s2s manager routes the packet to the process @@ -4931,7 +4932,7 @@ To exit the shell, close the window or press the keys: control+c control+c. \ejabberd{} includes a watchdog mechanism that may be useful to developers when troubleshooting a problem related to memory usage. If a process in the \ejabberd{} server consumes more memory than the configured threshold, -a message is sent to the Jabber accounts defined with the option +a message is sent to the XMPP accounts defined with the option \term{watchdog\_admins} \ind{options!watchdog\_admins} in the \ejabberd{} configuration file. @@ -5075,7 +5076,7 @@ Street, Fifth Floor, Boston, MA 02110-1301, USA. %\titem{Regular Expression} %\titem{ACL} (Access Control List) %\titem{IPv6} -%\titem{Jabber} +%\titem{XMPP} %\titem{LDAP} (Lightweight Directory Access Protocol) %\titem{ODBC} (Open Database Connectivity) %\titem{Virtual Hosting} From b3955fca3a986eb6fe9c11ad39eff068e143ff89 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Wed, 23 Sep 2009 16:32:06 +0000 Subject: [PATCH 547/582] fix EJAB-1048 and EJAB-819, thanks to badlop SVN Revision: 2616 --- doc/guide.tex | 3 + src/mod_pubsub/mod_pubsub.erl | 117 ++++++++++++-------- src/mod_pubsub/mod_pubsub_odbc.erl | 151 +++++++++++++++----------- src/mod_pubsub/node.template | 2 +- src/mod_pubsub/node_buddy.erl | 2 +- src/mod_pubsub/node_club.erl | 2 +- src/mod_pubsub/node_dispatch.erl | 2 +- src/mod_pubsub/node_flat.erl | 2 +- src/mod_pubsub/node_flat_odbc.erl | 2 +- src/mod_pubsub/node_hometree.erl | 2 +- src/mod_pubsub/node_hometree_odbc.erl | 18 ++- src/mod_pubsub/node_pep.erl | 2 +- src/mod_pubsub/node_pep_odbc.erl | 2 +- src/mod_pubsub/node_private.erl | 2 +- src/mod_pubsub/node_public.erl | 2 +- src/mod_pubsub/pubsub.hrl | 4 +- src/mod_pubsub/pubsub_odbc.patch | 114 +++++++++---------- 17 files changed, 254 insertions(+), 175 deletions(-) diff --git a/doc/guide.tex b/doc/guide.tex index 73491c6fc..297fe7e74 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -3452,6 +3452,9 @@ Options: \titem{\{access\_createnode, AccessName\}} \ind{options!access\_createnode} This option restricts which users are allowed to create pubsub nodes using ACL and ACCESS. The default value is \term{pubsub\_createnode}. % Not clear enough + do not use abbreviations. +\titem{\{max\_items\_node, MaxItems\}} \ind{options!max\_items\_node} + Define the maximum number of items that can be stored in a node. + Default value is 10. \titem{\{plugins, [ Plugin, ...]\}} \ind{options!plugins} To specify which pubsub node plugins to use. If not defined, the default pubsub plugin is always used. diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 700cc7674..1c581e7d0 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -135,6 +135,7 @@ pep_mapping = [], pep_sendlast_offline = false, last_item_cache = false, + max_items_node = ?MAXITEMS, nodetree = ?STDTREE, plugins = [?STDNODE], send_loop}). @@ -186,6 +187,7 @@ init([ServerHost, Opts]) -> PepOffline = gen_mod:get_opt(pep_sendlast_offline, Opts, false), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), LastItemCache = gen_mod:get_opt(last_item_cache, Opts, false), + MaxItemsNode = gen_mod:get_opt(max_items_node, Opts, ?MAXITEMS), ServerHostB = list_to_binary(ServerHost), pubsub_index:init(Host, ServerHost, Opts), ets:new(gen_mod:get_module_proc(Host, config), [set, named_table]), @@ -197,6 +199,7 @@ init([ServerHost, Opts]) -> ets:insert(gen_mod:get_module_proc(Host, config), {nodetree, NodeTree}), ets:insert(gen_mod:get_module_proc(Host, config), {plugins, Plugins}), ets:insert(gen_mod:get_module_proc(Host, config), {last_item_cache, LastItemCache}), + ets:insert(gen_mod:get_module_proc(Host, config), {max_items_node, MaxItemsNode}), ets:insert(gen_mod:get_module_proc(ServerHost, config), {nodetree, NodeTree}), ets:insert(gen_mod:get_module_proc(ServerHost, config), {plugins, Plugins}), ets:insert(gen_mod:get_module_proc(ServerHost, config), {pep_mapping, PepMapping}), @@ -231,6 +234,7 @@ init([ServerHost, Opts]) -> pep_mapping = PepMapping, pep_sendlast_offline = PepOffline, last_item_cache = LastItemCache, + max_items_node = MaxItemsNode, nodetree = NodeTree, plugins = Plugins}, SendLoop = spawn(?MODULE, send_loop, [State]), @@ -1243,7 +1247,7 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) -> "item-required")} end; {set, 'subscribe'} -> - Config = case Configuration of + Config = case Rest of [#xmlel{name = 'configure', children = C}] -> C; _ -> [] end, @@ -1281,8 +1285,8 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) -> _ -> {error, 'feature-not-implemented'} end; - _ -> - ?INFO_MSG("Too many actions: ~p", [Action]), + Other -> + ?INFO_MSG("Too many actions: ~p", [Other]), {error, 'bad-request'} end. @@ -1354,7 +1358,7 @@ adhoc_request(Host, _ServerHost, Owner, invalid -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'bad-request')}; XData2 -> - case set_xoption(XData2, []) of + case set_xoption(Host, XData2, []) of NewOpts when is_list(NewOpts) -> {result, NewOpts}; Err -> @@ -1716,7 +1720,7 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> invalid -> {error, 'bad-request'}; XData -> - case set_xoption(XData, node_options(Type)) of + case set_xoption(Host, XData, node_options(Type)) of NewOpts when is_list(NewOpts) -> {result, NewOpts}; Err -> @@ -2213,7 +2217,7 @@ purge_node(Host, Node, Owner) -> get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> MaxItems = if - SMaxItems == "" -> ?MAXITEMS; + SMaxItems == "" -> get_max_items_node(Host); true -> case catch list_to_integer(SMaxItems) of {'EXIT', _} -> {error, 'bad-request'}; @@ -2302,9 +2306,10 @@ send_items(Host, Node, NodeId, Type, LJID, last) -> undefined -> send_items(Host, Node, NodeId, Type, LJID, 1); LastItem -> - Stanza = event_stanza( + {ModifNow, ModifLjid} = LastItem#pubsub_item.modification, + Stanza = event_stanza_with_delay( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), - children = itemsEls(LastItem)}]), + children = itemsEls(LastItem)}], ModifNow, ModifLjid), {U, S, R} = LJID, ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza} end; @@ -2320,9 +2325,17 @@ send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> _ -> [] end, - Stanza = event_stanza( + Stanza = case ToSend of + [LastItem] -> + {ModifNow, ModifLjid} = LastItem#pubsub_item.modification, + event_stanza_with_delay( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = - itemsEls(ToSend)}]), + itemsEls(ToSend)}], ModifNow, ModifLjid); + _ -> + event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = + itemsEls(ToSend)}]) + end, ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(LU, LS, LR), Stanza}. %% @spec (Host, JID, Plugins) -> {error, Reason} | {result, Response} @@ -2890,8 +2903,17 @@ payload_xmlelements([_|Tail], Count) -> payload_xmlelements(Tail, Count). %% Els = [xmlelement()] %% @doc

        Build pubsub event stanza

        event_stanza(Els) -> + event_stanza_withmoreels(Els, []). + + +event_stanza_with_delay(Els, ModifNow, ModifLjid) -> + DateTime = calendar:now_to_datetime(ModifNow), + MoreEls = [jlib:timestamp_to_xml(DateTime, utc, ModifLjid, "")], + event_stanza_withmoreels(Els, MoreEls). + +event_stanza_withmoreels(Els, MoreEls) -> #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = Els}]}. + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = Els} | MoreEls]}. %%%%%% broadcast functions @@ -3347,7 +3369,7 @@ set_configure(Host, Node, From, Els, Lang) -> [] -> node_options(Type); _ -> Options end, - case set_xoption(XData, OldOpts) of + case set_xoption(Host, XData, OldOpts) of NewOpts when is_list(NewOpts) -> case tree_call(Host, set_node, [N#pubsub_node{options = NewOpts}]) of ok -> {result, ok}; @@ -3392,80 +3414,89 @@ add_opt(Key, Value, Opts) -> end, case BoolVal of error -> {error, 'not-acceptable'}; - _ -> set_xoption(Opts, add_opt(Opt, BoolVal, NewOpts)) + _ -> set_xoption(Host, Opts, add_opt(Opt, BoolVal, NewOpts)) end). -define(SET_STRING_XOPT(Opt, Val), - set_xoption(Opts, add_opt(Opt, Val, NewOpts))). + set_xoption(Host, Opts, add_opt(Opt, Val, NewOpts))). -define(SET_INTEGER_XOPT(Opt, Val, Min, Max), case catch list_to_integer(Val) of IVal when is_integer(IVal), IVal >= Min, IVal =< Max -> - set_xoption(Opts, add_opt(Opt, IVal, NewOpts)); + set_xoption(Host, Opts, add_opt(Opt, IVal, NewOpts)); _ -> {error, 'not-acceptable'} end). -define(SET_ALIST_XOPT(Opt, Val, Vals), case lists:member(Val, [atom_to_list(V) || V <- Vals]) of - true -> set_xoption(Opts, add_opt(Opt, list_to_atom(Val), NewOpts)); + true -> set_xoption(Host, Opts, add_opt(Opt, list_to_atom(Val), NewOpts)); false -> {error, 'not-acceptable'} end). -define(SET_LIST_XOPT(Opt, Val), - set_xoption(Opts, add_opt(Opt, Val, NewOpts))). + set_xoption(Host, Opts, add_opt(Opt, Val, NewOpts))). -set_xoption([], NewOpts) -> +set_xoption(_Host, [], NewOpts) -> NewOpts; -set_xoption([{"FORM_TYPE", _} | Opts], NewOpts) -> - set_xoption(Opts, NewOpts); -set_xoption([{"pubsub#roster_groups_allowed", Value} | Opts], NewOpts) -> +set_xoption(Host, [{"FORM_TYPE", _} | Opts], NewOpts) -> + set_xoption(Host, Opts, NewOpts); +set_xoption(Host, [{"pubsub#roster_groups_allowed", Value} | Opts], NewOpts) -> ?SET_LIST_XOPT(roster_groups_allowed, Value); -set_xoption([{"pubsub#deliver_payloads", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#deliver_payloads", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(deliver_payloads, Val); -set_xoption([{"pubsub#deliver_notifications", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#deliver_notifications", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(deliver_notifications, Val); -set_xoption([{"pubsub#notify_config", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#notify_config", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(notify_config, Val); -set_xoption([{"pubsub#notify_delete", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#notify_delete", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(notify_delete, Val); -set_xoption([{"pubsub#notify_retract", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#notify_retract", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(notify_retract, Val); -set_xoption([{"pubsub#persist_items", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#persist_items", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(persist_items, Val); -set_xoption([{"pubsub#max_items", [Val]} | Opts], NewOpts) -> - ?SET_INTEGER_XOPT(max_items, Val, 0, ?MAXITEMS); -set_xoption([{"pubsub#subscribe", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#max_items", [Val]} | Opts], NewOpts) -> + MaxItems = get_max_items_node(Host), + ?SET_INTEGER_XOPT(max_items, Val, 0, MaxItems); +set_xoption(Host, [{"pubsub#subscribe", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(subscribe, Val); -set_xoption([{"pubsub#access_model", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#access_model", [Val]} | Opts], NewOpts) -> ?SET_ALIST_XOPT(access_model, Val, [open, authorize, presence, roster, whitelist]); -set_xoption([{"pubsub#publish_model", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#publish_model", [Val]} | Opts], NewOpts) -> ?SET_ALIST_XOPT(publish_model, Val, [publishers, subscribers, open]); -set_xoption([{"pubsub#node_type", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#node_type", [Val]} | Opts], NewOpts) -> ?SET_ALIST_XOPT(node_type, Val, [leaf, collection]); -set_xoption([{"pubsub#max_payload_size", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#max_payload_size", [Val]} | Opts], NewOpts) -> ?SET_INTEGER_XOPT(max_payload_size, Val, 0, ?MAX_PAYLOAD_SIZE); -set_xoption([{"pubsub#send_last_published_item", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#send_last_published_item", [Val]} | Opts], NewOpts) -> ?SET_ALIST_XOPT(send_last_published_item, Val, [never, on_sub, on_sub_and_presence]); -set_xoption([{"pubsub#presence_based_delivery", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#presence_based_delivery", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(presence_based_delivery, Val); -set_xoption([{"pubsub#title", Value} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#title", Value} | Opts], NewOpts) -> ?SET_STRING_XOPT(title, Value); -set_xoption([{"pubsub#type", Value} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#type", Value} | Opts], NewOpts) -> ?SET_STRING_XOPT(type, Value); -set_xoption([{"pubsub#body_xslt", Value} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#body_xslt", Value} | Opts], NewOpts) -> ?SET_STRING_XOPT(body_xslt, Value); -set_xoption([{"pubsub#collection", Value} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#collection", Value} | Opts], NewOpts) -> NewValue = [string_to_node(V) || V <- Value], ?SET_LIST_XOPT(collection, NewValue); -set_xoption([{"pubsub#node", [Value]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#node", [Value]} | Opts], NewOpts) -> NewValue = string_to_node(Value), ?SET_LIST_XOPT(node, NewValue); -set_xoption([_ | Opts], NewOpts) -> +set_xoption(Host, [_ | Opts], NewOpts) -> % skip unknown field - set_xoption(Opts, NewOpts). + set_xoption(Host, Opts, NewOpts). + +get_max_items_node({_, ServerHost, _}) -> + get_max_items_node(ServerHost); +get_max_items_node(Host) -> + case catch ets:lookup(gen_mod:get_module_proc(Host, config), max_items_node) of + [{max_items_node, Integer}] -> Integer; + _ -> ?MAXITEMS + end. %%%% last item cache handling diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index 901fac0c3..37825535f 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -135,6 +135,7 @@ pep_mapping = [], pep_sendlast_offline = false, last_item_cache = false, + max_items_node = ?MAXITEMS, nodetree = ?STDTREE, plugins = [?STDNODE], send_loop}). @@ -186,6 +187,7 @@ init([ServerHost, Opts]) -> PepOffline = gen_mod:get_opt(pep_sendlast_offline, Opts, false), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), LastItemCache = gen_mod:get_opt(last_item_cache, Opts, false), + MaxItemsNode = gen_mod:get_opt(max_items_node, Opts, ?MAXITEMS), ServerHostB = list_to_binary(ServerHost), pubsub_index:init(Host, ServerHost, Opts), ets:new(gen_mod:get_module_proc(Host, config), [set, named_table]), @@ -197,6 +199,7 @@ init([ServerHost, Opts]) -> ets:insert(gen_mod:get_module_proc(Host, config), {nodetree, NodeTree}), ets:insert(gen_mod:get_module_proc(Host, config), {plugins, Plugins}), ets:insert(gen_mod:get_module_proc(Host, config), {last_item_cache, LastItemCache}), + ets:insert(gen_mod:get_module_proc(Host, config), {max_items_node, MaxItemsNode}), ets:insert(gen_mod:get_module_proc(ServerHost, config), {nodetree, NodeTree}), ets:insert(gen_mod:get_module_proc(ServerHost, config), {plugins, Plugins}), ets:insert(gen_mod:get_module_proc(ServerHost, config), {pep_mapping, PepMapping}), @@ -229,6 +232,7 @@ init([ServerHost, Opts]) -> pep_mapping = PepMapping, pep_sendlast_offline = PepOffline, last_item_cache = LastItemCache, + max_items_node = MaxItemsNode, nodetree = NodeTree, plugins = Plugins}, SendLoop = spawn(?MODULE, send_loop, [State]), @@ -1014,20 +1018,15 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang) -> iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, all, plugins(ServerHost)). iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) -> - WithoutCdata = exmpp_xml:remove_cdata_from_list(SubEl#xmlel.children), - Configuration = lists:filter(fun(#xmlel{name = 'configure'}) -> true; - (_) -> false - end, WithoutCdata), - Action = WithoutCdata -- Configuration, - case Action of - [#xmlel{name = Name, attrs = Attrs, children = Els}] -> + case exmpp_xml:remove_cdata_from_list(SubEl#xmlel.children) of + [#xmlel{name = Name, attrs = Attrs, children = Els} | Rest] -> Node = case Host of {_, _, _} -> exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false); _ -> string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false)) end, case {IQType, Name} of {set, 'create'} -> - Config = case Configuration of + Config = case Rest of [#xmlel{name = 'configure', children = C}] -> C; _ -> [] end, @@ -1077,7 +1076,7 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) -> "item-required")} end; {set, 'subscribe'} -> - Config = case Configuration of + Config = case Rest of [#xmlel{name = 'configure', children = C}] -> C; _ -> [] end, @@ -1116,8 +1115,8 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) -> _ -> {error, 'feature-not-implemented'} end; - _ -> - ?INFO_MSG("Too many actions: ~p", [Action]), + Other -> + ?INFO_MSG("Too many actions: ~p", [Other]), {error, 'bad-request'} end. @@ -1190,7 +1189,7 @@ adhoc_request(Host, _ServerHost, Owner, invalid -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'bad-request')}; XData2 -> - case set_xoption(XData2, []) of + case set_xoption(Host, XData2, []) of NewOpts when is_list(NewOpts) -> {result, NewOpts}; Err -> @@ -1553,7 +1552,7 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> invalid -> {error, 'bad-request'}; XData -> - case set_xoption(XData, node_options(Type)) of + case set_xoption(Host, XData, node_options(Type)) of NewOpts when is_list(NewOpts) -> {result, NewOpts}; Err -> @@ -2054,7 +2053,7 @@ purge_node(Host, Node, Owner) -> get_items(Host, Node, From, SubId, SMaxItems, ItemIDs, RSM) -> MaxItems = if - SMaxItems == "" -> ?MAXITEMS; + SMaxItems == "" -> get_max_items_node(Host); true -> case catch list_to_integer(SMaxItems) of {'EXIT', _} -> {error, 'bad-request'}; @@ -2142,22 +2141,26 @@ send_items(Host, Node, NodeId, Type, LJID, last) -> Stanza = case get_cached_item(Host, NodeId) of undefined -> % special ODBC optimization, works only with node_hometree_odbc, node_flat_odbc and node_pep_odbc - ToSend = case node_action(Host, Type, get_last_items, [NodeId, LJID, 1]) of - {result, []} -> []; - {result, Items} -> Items - end, - event_stanza([#xmlel{ns = ?NS_PUBSUB_EVENT, - name = 'items', - attrs = nodeAttr(Node), - children = itemsEls(ToSend)}]); + case node_action(Host, Type, get_last_items, [NodeId, LJID, 1]) of + {result, [LastItem]} -> + {ModifNow, ModifLjid} = LastItem#pubsub_item.modification, + event_stanza_with_delay([#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', + attrs = nodeAttr(Node), + children = itemsEls([])}], + ModifNow, ModifLjid); + _ -> + event_stanza([#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', + attrs = nodeAttr(Node), + children = itemsEls([])}]) + end; LastItem -> - event_stanza( + {ModifNow, ModifLjid} = LastItem#pubsub_item.modification, + event_stanza_with_delay( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), - children = itemsEls(LastItem)}]) + children = itemsEls(LastItem)}], ModifNow, ModifLjid) end, {U, S, R} = LJID, - ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza}; - + ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza}; send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of {result, []} -> @@ -2170,9 +2173,17 @@ send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> _ -> [] end, - Stanza = event_stanza( + Stanza = case ToSend of + [LastItem] -> + {ModifNow, ModifLjid} = LastItem#pubsub_item.modification, + event_stanza_with_delay( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = - itemsEls(ToSend)}]), + itemsEls(ToSend)}], ModifNow, ModifLjid); + _ -> + event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = + itemsEls(ToSend)}]) + end, ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(LU, LS, LR), Stanza}. %% @spec (Host, JID, Plugins) -> {error, Reason} | {result, Response} @@ -2723,8 +2734,17 @@ payload_xmlelements([_|Tail], Count) -> payload_xmlelements(Tail, Count). %% Els = [xmlelement()] %% @doc

        Build pubsub event stanza

        event_stanza(Els) -> + event_stanza_withmoreels(Els, []). + + +event_stanza_with_delay(Els, ModifNow, ModifLjid) -> + DateTime = calendar:now_to_datetime(ModifNow), + MoreEls = [jlib:timestamp_to_xml(DateTime, utc, ModifLjid, "")], + event_stanza_withmoreels(Els, MoreEls). + +event_stanza_withmoreels(Els, MoreEls) -> #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = - [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = Els}]}. + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'event', children = Els} | MoreEls]}. %%%%%% broadcast functions @@ -3204,7 +3224,7 @@ set_configure(Host, Node, From, Els, Lang) -> [] -> node_options(Type); _ -> Options end, - case set_xoption(XData, OldOpts) of + case set_xoption(Host, XData, OldOpts) of NewOpts when is_list(NewOpts) -> case tree_call(Host, set_node, [N#pubsub_node{options = NewOpts}]) of ok -> {result, ok}; @@ -3249,80 +3269,89 @@ add_opt(Key, Value, Opts) -> end, case BoolVal of error -> {error, 'not-acceptable'}; - _ -> set_xoption(Opts, add_opt(Opt, BoolVal, NewOpts)) + _ -> set_xoption(Host, Opts, add_opt(Opt, BoolVal, NewOpts)) end). -define(SET_STRING_XOPT(Opt, Val), - set_xoption(Opts, add_opt(Opt, Val, NewOpts))). + set_xoption(Host, Opts, add_opt(Opt, Val, NewOpts))). -define(SET_INTEGER_XOPT(Opt, Val, Min, Max), case catch list_to_integer(Val) of IVal when is_integer(IVal), IVal >= Min, IVal =< Max -> - set_xoption(Opts, add_opt(Opt, IVal, NewOpts)); + set_xoption(Host, Opts, add_opt(Opt, IVal, NewOpts)); _ -> {error, 'not-acceptable'} end). -define(SET_ALIST_XOPT(Opt, Val, Vals), case lists:member(Val, [atom_to_list(V) || V <- Vals]) of - true -> set_xoption(Opts, add_opt(Opt, list_to_atom(Val), NewOpts)); + true -> set_xoption(Host, Opts, add_opt(Opt, list_to_atom(Val), NewOpts)); false -> {error, 'not-acceptable'} end). -define(SET_LIST_XOPT(Opt, Val), - set_xoption(Opts, add_opt(Opt, Val, NewOpts))). + set_xoption(Host, Opts, add_opt(Opt, Val, NewOpts))). -set_xoption([], NewOpts) -> +set_xoption(_Host, [], NewOpts) -> NewOpts; -set_xoption([{"FORM_TYPE", _} | Opts], NewOpts) -> - set_xoption(Opts, NewOpts); -set_xoption([{"pubsub#roster_groups_allowed", Value} | Opts], NewOpts) -> +set_xoption(Host, [{"FORM_TYPE", _} | Opts], NewOpts) -> + set_xoption(Host, Opts, NewOpts); +set_xoption(Host, [{"pubsub#roster_groups_allowed", Value} | Opts], NewOpts) -> ?SET_LIST_XOPT(roster_groups_allowed, Value); -set_xoption([{"pubsub#deliver_payloads", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#deliver_payloads", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(deliver_payloads, Val); -set_xoption([{"pubsub#deliver_notifications", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#deliver_notifications", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(deliver_notifications, Val); -set_xoption([{"pubsub#notify_config", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#notify_config", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(notify_config, Val); -set_xoption([{"pubsub#notify_delete", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#notify_delete", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(notify_delete, Val); -set_xoption([{"pubsub#notify_retract", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#notify_retract", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(notify_retract, Val); -set_xoption([{"pubsub#persist_items", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#persist_items", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(persist_items, Val); -set_xoption([{"pubsub#max_items", [Val]} | Opts], NewOpts) -> - ?SET_INTEGER_XOPT(max_items, Val, 0, ?MAXITEMS); -set_xoption([{"pubsub#subscribe", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#max_items", [Val]} | Opts], NewOpts) -> + MaxItems = get_max_items_node(Host), + ?SET_INTEGER_XOPT(max_items, Val, 0, MaxItems); +set_xoption(Host, [{"pubsub#subscribe", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(subscribe, Val); -set_xoption([{"pubsub#access_model", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#access_model", [Val]} | Opts], NewOpts) -> ?SET_ALIST_XOPT(access_model, Val, [open, authorize, presence, roster, whitelist]); -set_xoption([{"pubsub#publish_model", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#publish_model", [Val]} | Opts], NewOpts) -> ?SET_ALIST_XOPT(publish_model, Val, [publishers, subscribers, open]); -set_xoption([{"pubsub#node_type", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#node_type", [Val]} | Opts], NewOpts) -> ?SET_ALIST_XOPT(node_type, Val, [leaf, collection]); -set_xoption([{"pubsub#max_payload_size", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#max_payload_size", [Val]} | Opts], NewOpts) -> ?SET_INTEGER_XOPT(max_payload_size, Val, 0, ?MAX_PAYLOAD_SIZE); -set_xoption([{"pubsub#send_last_published_item", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#send_last_published_item", [Val]} | Opts], NewOpts) -> ?SET_ALIST_XOPT(send_last_published_item, Val, [never, on_sub, on_sub_and_presence]); -set_xoption([{"pubsub#presence_based_delivery", [Val]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#presence_based_delivery", [Val]} | Opts], NewOpts) -> ?SET_BOOL_XOPT(presence_based_delivery, Val); -set_xoption([{"pubsub#title", Value} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#title", Value} | Opts], NewOpts) -> ?SET_STRING_XOPT(title, Value); -set_xoption([{"pubsub#type", Value} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#type", Value} | Opts], NewOpts) -> ?SET_STRING_XOPT(type, Value); -set_xoption([{"pubsub#body_xslt", Value} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#body_xslt", Value} | Opts], NewOpts) -> ?SET_STRING_XOPT(body_xslt, Value); -set_xoption([{"pubsub#collection", Value} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#collection", Value} | Opts], NewOpts) -> NewValue = [string_to_node(V) || V <- Value], ?SET_LIST_XOPT(collection, NewValue); -set_xoption([{"pubsub#node", [Value]} | Opts], NewOpts) -> +set_xoption(Host, [{"pubsub#node", [Value]} | Opts], NewOpts) -> NewValue = string_to_node(Value), ?SET_LIST_XOPT(node, NewValue); -set_xoption([_ | Opts], NewOpts) -> +set_xoption(Host, [_ | Opts], NewOpts) -> % skip unknown field - set_xoption(Opts, NewOpts). + set_xoption(Host, Opts, NewOpts). + +get_max_items_node({_, ServerHost, _}) -> + get_max_items_node(ServerHost); +get_max_items_node(Host) -> + case catch ets:lookup(gen_mod:get_module_proc(Host, config), max_items_node) of + [{max_items_node, Integer}] -> Integer; + _ -> ?MAXITEMS + end. %%%% last item cache handling diff --git a/src/mod_pubsub/node.template b/src/mod_pubsub/node.template index ff3cc2209..a83408110 100644 --- a/src/mod_pubsub/node.template +++ b/src/mod_pubsub/node.template @@ -81,7 +81,7 @@ options() -> {notify_delete, false}, {notify_retract, true}, {persist_items, true}, - {max_items, ?MAXITEMS div 2}, + {max_items, ?MAXITEMS}, {subscribe, true}, {access_model, open}, {roster_groups_allowed, []}, diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl index 2031fe9db..0639e1dee 100644 --- a/src/mod_pubsub/node_buddy.erl +++ b/src/mod_pubsub/node_buddy.erl @@ -85,7 +85,7 @@ options() -> {notify_delete, false}, {notify_retract, true}, {persist_items, true}, - {max_items, ?MAXITEMS div 2}, + {max_items, ?MAXITEMS}, {subscribe, true}, {access_model, presence}, {roster_groups_allowed, []}, diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl index 20c4bdf6b..579ba7ba2 100644 --- a/src/mod_pubsub/node_club.erl +++ b/src/mod_pubsub/node_club.erl @@ -84,7 +84,7 @@ options() -> {notify_delete, false}, {notify_retract, true}, {persist_items, true}, - {max_items, ?MAXITEMS div 2}, + {max_items, ?MAXITEMS}, {subscribe, true}, {access_model, authorize}, {roster_groups_allowed, []}, diff --git a/src/mod_pubsub/node_dispatch.erl b/src/mod_pubsub/node_dispatch.erl index 76aee4891..ad6778f31 100644 --- a/src/mod_pubsub/node_dispatch.erl +++ b/src/mod_pubsub/node_dispatch.erl @@ -82,7 +82,7 @@ options() -> {notify_delete, false}, {notify_retract, true}, {persist_items, true}, - {max_items, ?MAXITEMS div 2}, + {max_items, ?MAXITEMS}, {subscribe, true}, {access_model, open}, {roster_groups_allowed, []}, diff --git a/src/mod_pubsub/node_flat.erl b/src/mod_pubsub/node_flat.erl index e0bac5ea1..b6bf4d1c9 100644 --- a/src/mod_pubsub/node_flat.erl +++ b/src/mod_pubsub/node_flat.erl @@ -75,7 +75,7 @@ options() -> {notify_delete, false}, {notify_retract, true}, {persist_items, true}, - {max_items, ?MAXITEMS div 2}, + {max_items, ?MAXITEMS}, {subscribe, true}, {access_model, open}, {roster_groups_allowed, []}, diff --git a/src/mod_pubsub/node_flat_odbc.erl b/src/mod_pubsub/node_flat_odbc.erl index 191ca1f8f..4a7d360fd 100644 --- a/src/mod_pubsub/node_flat_odbc.erl +++ b/src/mod_pubsub/node_flat_odbc.erl @@ -76,7 +76,7 @@ options() -> {notify_delete, false}, {notify_retract, true}, {persist_items, true}, - {max_items, ?MAXITEMS div 2}, + {max_items, ?MAXITEMS}, {subscribe, true}, {access_model, open}, {roster_groups_allowed, []}, diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index 1cb017c4c..e707ceaea 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -138,7 +138,7 @@ options() -> {notify_delete, false}, {notify_retract, true}, {persist_items, true}, - {max_items, ?MAXITEMS div 2}, + {max_items, ?MAXITEMS}, {subscribe, true}, {access_model, open}, {roster_groups_allowed, []}, diff --git a/src/mod_pubsub/node_hometree_odbc.erl b/src/mod_pubsub/node_hometree_odbc.erl index 9b5500493..75cb0f10f 100644 --- a/src/mod_pubsub/node_hometree_odbc.erl +++ b/src/mod_pubsub/node_hometree_odbc.erl @@ -140,7 +140,7 @@ options() -> {notify_delete, false}, {notify_retract, true}, {persist_items, true}, - {max_items, ?MAXITEMS div 2}, + {max_items, ?MAXITEMS}, {subscribe, true}, {access_model, open}, {roster_groups_allowed, []}, @@ -978,12 +978,22 @@ get_items(NodeId, _From) -> "where nodeid='", NodeId, "' " "order by modification desc;"]) of {selected, ["itemid", "publisher", "creation", "modification", "payload"], RItems} -> - {result, lists:map(fun(RItem) -> raw_to_item(NodeId, RItem) end, RItems)}; + {result, lists:map(fun(RItem) -> raw_to_item(NodeId, RItem) end, RItems)}; _ -> - {result, []} + {result, []} end. get_items(NodeId, From, none) -> - get_items(NodeId, From, #rsm_in{max = ?MAXITEMS div 2}); + MaxItems = case catch ejabberd_odbc:sql_query_t( + ["select val from pubsub_node_option " + "where nodeid='", NodeId, "' " + "and name='max_items';"]) of + {selected, ["val"], [{Value}]} -> + Tokens = element(2, erl_scan:string(Value++".")), + element(2, erl_parse:parse_term(Tokens)); + _ -> + ?MAXITEMS + end, + get_items(NodeId, From, #rsm_in{max=MaxItems}); get_items(NodeId, _From, #rsm_in{max=M, direction=Direction, id=I, index=IncIndex})-> Max = ?PUBSUB:escape(i2l(M)), diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index e304fe916..0a153fc1a 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -83,7 +83,7 @@ options() -> {notify_delete, false}, {notify_retract, false}, {persist_items, false}, - {max_items, ?MAXITEMS div 2}, + {max_items, ?MAXITEMS}, {subscribe, true}, {access_model, presence}, {roster_groups_allowed, []}, diff --git a/src/mod_pubsub/node_pep_odbc.erl b/src/mod_pubsub/node_pep_odbc.erl index 6ca622ba6..e297f5822 100644 --- a/src/mod_pubsub/node_pep_odbc.erl +++ b/src/mod_pubsub/node_pep_odbc.erl @@ -90,7 +90,7 @@ options() -> {notify_delete, false}, {notify_retract, false}, {persist_items, false}, - {max_items, ?MAXITEMS div 2}, + {max_items, ?MAXITEMS}, {subscribe, true}, {access_model, presence}, {roster_groups_allowed, []}, diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl index 0170ab66a..e6d605089 100644 --- a/src/mod_pubsub/node_private.erl +++ b/src/mod_pubsub/node_private.erl @@ -85,7 +85,7 @@ options() -> {notify_delete, false}, {notify_retract, true}, {persist_items, true}, - {max_items, ?MAXITEMS div 2}, + {max_items, ?MAXITEMS}, {subscribe, true}, {access_model, whitelist}, {roster_groups_allowed, []}, diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl index 64f87e690..75112e905 100644 --- a/src/mod_pubsub/node_public.erl +++ b/src/mod_pubsub/node_public.erl @@ -86,7 +86,7 @@ options() -> {notify_delete, false}, {notify_retract, true}, {persist_items, true}, - {max_items, ?MAXITEMS div 2}, + {max_items, ?MAXITEMS}, {subscribe, true}, {access_model, open}, {roster_groups_allowed, []}, diff --git a/src/mod_pubsub/pubsub.hrl b/src/mod_pubsub/pubsub.hrl index 9d400185a..1fa8af397 100644 --- a/src/mod_pubsub/pubsub.hrl +++ b/src/mod_pubsub/pubsub.hrl @@ -25,9 +25,11 @@ %% Pubsub constants -define(ERR_EXTENDED(E,C), mod_pubsub:extended_error(E,C)). +%% The actual limit can be configured with mod_pubsub's option max_items_node +-define(MAXITEMS, 10). + %% this is currently a hard limit. %% Would be nice to have it configurable. --define(MAXITEMS, 20). -define(MAX_PAYLOAD_SIZE, 60000). %% ------------------------------- diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index 39fa40205..40104ed62 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,5 +1,5 @@ ---- mod_pubsub.erl 2009-09-09 23:42:26.000000000 +0200 -+++ mod_pubsub_odbc.erl 2009-09-09 23:42:26.000000000 +0200 +--- mod_pubsub.erl 2009-09-23 18:18:35.000000000 +0200 ++++ mod_pubsub_odbc.erl 2009-09-23 18:26:41.000000000 +0200 @@ -45,7 +45,7 @@ %%% TODO %%% plugin: generate Reply (do not use broadcast atom anymore) @@ -40,7 +40,7 @@ -define(PLUGIN_PREFIX, "node_"). -define(TREE_PREFIX, "nodetree_"). -@@ -222,8 +222,6 @@ +@@ -225,8 +225,6 @@ ok end, ejabberd_router:register_route(Host), @@ -49,7 +49,7 @@ init_nodes(Host, ServerHost), State = #state{host = Host, server_host = ServerHost, -@@ -278,177 +276,7 @@ +@@ -282,177 +280,7 @@ create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), "hometree"), ok. @@ -227,7 +227,7 @@ send_queue(State, Msg) -> Pid = State#state.send_loop, -@@ -472,17 +300,15 @@ +@@ -476,17 +304,15 @@ %% for each node From is subscribed to %% and if the node is so configured, send the last published item to From lists:foreach(fun(PType) -> @@ -251,7 +251,7 @@ true -> % resource not concerned about that subscription ok -@@ -810,10 +636,10 @@ +@@ -814,10 +640,10 @@ {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), lists:foreach(fun ({Node, subscribed, _, JID}) -> @@ -264,7 +264,7 @@ true -> node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); false -> -@@ -931,11 +757,12 @@ +@@ -935,11 +761,12 @@ end, ejabberd_router:route(To, From, Res); #iq{type = get, ns = ?NS_DISCO_ITEMS, @@ -279,7 +279,7 @@ {result, IQRes} -> Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', attrs = QAttrs, -@@ -1038,7 +865,7 @@ +@@ -1042,7 +869,7 @@ [] -> ["leaf"]; %% No sub-nodes: it's a leaf node _ -> @@ -288,7 +288,7 @@ {result, []} -> ["collection"]; {result, _} -> ["leaf", "collection"]; _ -> [] -@@ -1054,8 +881,9 @@ +@@ -1058,8 +885,9 @@ []; true -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]} | @@ -300,7 +300,7 @@ end, features(Type))] end, %% TODO: add meta-data info (spec section 5.4) -@@ -1083,14 +911,15 @@ +@@ -1087,14 +915,15 @@ #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_DISCO_ITEMS_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_VCARD_s)]}] ++ @@ -319,7 +319,7 @@ {result, lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> SN = node_to_string(SubNode), -@@ -1100,7 +929,7 @@ +@@ -1104,7 +933,7 @@ ?XMLATTR('node', SN), ?XMLATTR('name', RN)]} end, tree_action(Host, get_subnodes, [Host, [], From]))}; @@ -328,7 +328,7 @@ case string:tokens(Item, "!") of [_SNode, _ItemID] -> {result, []}; -@@ -1112,10 +941,10 @@ +@@ -1116,10 +945,10 @@ %% TODO That is, remove name attribute (or node?, please check for 2.1) Action = fun(#pubsub_node{type = Type, id = NodeId}) -> @@ -342,7 +342,7 @@ end, Nodes = lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> -@@ -1131,7 +960,7 @@ +@@ -1135,7 +964,7 @@ #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), ?XMLATTR('name', Name)]} end, NodeItems), @@ -351,7 +351,7 @@ end, case transaction(Host, Node, Action, sync_dirty) of {result, {_, Result}} -> {result, Result}; -@@ -1270,7 +1099,8 @@ +@@ -1269,7 +1098,8 @@ (_, Acc) -> Acc end, [], exmpp_xml:remove_cdata_from_list(Els)), @@ -361,7 +361,7 @@ {get, 'subscriptions'} -> get_subscriptions(Host, Node, From, Plugins); {get, 'affiliations'} -> -@@ -1292,8 +1122,9 @@ +@@ -1291,8 +1121,9 @@ end. iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> @@ -373,7 +373,7 @@ case Action of [#xmlel{name = Name, attrs = Attrs, children = Els}] -> Node = case Host of -@@ -1423,7 +1254,8 @@ +@@ -1422,7 +1253,8 @@ _ -> [] end end, @@ -383,7 +383,7 @@ sync_dirty) of {result, Res} -> Res; Err -> Err -@@ -1468,7 +1300,7 @@ +@@ -1467,7 +1299,7 @@ %%% authorization handling @@ -392,7 +392,7 @@ Lang = "en", %% TODO fix {U, S, R} = Subscriber, Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = -@@ -1498,7 +1330,7 @@ +@@ -1497,7 +1329,7 @@ lists:foreach(fun(Owner) -> {U, S, R} = Owner, ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza} @@ -401,7 +401,7 @@ find_authorization_response(Packet) -> Els = Packet#xmlel.children, -@@ -1561,8 +1393,8 @@ +@@ -1560,8 +1392,8 @@ "true" -> true; _ -> false end, @@ -412,7 +412,7 @@ {result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]), if not IsApprover -> -@@ -1752,7 +1584,7 @@ +@@ -1751,7 +1583,7 @@ end, Reply = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(Node)}]}, @@ -421,7 +421,7 @@ {result, {Result, broadcast}} -> %%Lang = "en", %% TODO: fix %%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), -@@ -1861,7 +1693,7 @@ +@@ -1860,7 +1692,7 @@ %%
      • The node does not exist.
      • %%
      subscribe_node(Host, Node, From, JID, Configuration) -> @@ -430,7 +430,7 @@ Subscriber = try jlib:short_prepd_jid(exmpp_jid:parse(JID)) catch -@@ -1869,7 +1701,7 @@ +@@ -1868,7 +1700,7 @@ {undefined, undefined, undefined} end, SubId = uniqid(), @@ -439,7 +439,7 @@ Features = features(Type), SubscribeFeature = lists:member("subscribe", Features), OptionsFeature = lists:member("subscription-options", Features), -@@ -1888,9 +1720,13 @@ +@@ -1887,9 +1719,13 @@ {"", "", ""} -> {false, false}; _ -> @@ -456,7 +456,7 @@ end end, if -@@ -2215,7 +2051,7 @@ +@@ -2214,7 +2050,7 @@ %%

      The permission are not checked in this function.

      %% @todo We probably need to check that the user doing the query has the right %% to read the items. @@ -464,8 +464,8 @@ +get_items(Host, Node, From, SubId, SMaxItems, ItemIDs, RSM) -> MaxItems = if - SMaxItems == "" -> ?MAXITEMS; -@@ -2254,11 +2090,11 @@ + SMaxItems == "" -> get_max_items_node(Host); +@@ -2253,11 +2089,11 @@ node_call(Type, get_items, [NodeId, From, AccessModel, PresenceSubscription, RosterGroup, @@ -479,7 +479,7 @@ SendItems = case ItemIDs of [] -> Items; -@@ -2271,7 +2107,7 @@ +@@ -2270,7 +2106,7 @@ %% number of items sent to MaxItems: {result, #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = nodeAttr(Node), children = @@ -488,7 +488,7 @@ Error -> Error end -@@ -2303,16 +2139,25 @@ +@@ -2302,17 +2138,29 @@ %% @doc

      Resend the items of a node to the user.

      %% @todo use cache-last-item feature send_items(Host, Node, NodeId, Type, LJID, last) -> @@ -497,31 +497,35 @@ undefined -> - send_items(Host, Node, NodeId, Type, LJID, 1); + % special ODBC optimization, works only with node_hometree_odbc, node_flat_odbc and node_pep_odbc -+ ToSend = case node_action(Host, Type, get_last_items, [NodeId, LJID, 1]) of -+ {result, []} -> []; -+ {result, Items} -> Items -+ end, -+ event_stanza([#xmlel{ns = ?NS_PUBSUB_EVENT, -+ name = 'items', -+ attrs = nodeAttr(Node), -+ children = itemsEls(ToSend)}]); ++ case node_action(Host, Type, get_last_items, [NodeId, LJID, 1]) of ++ {result, [LastItem]} -> ++ {ModifNow, ModifLjid} = LastItem#pubsub_item.modification, ++ event_stanza_with_delay([#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', ++ attrs = nodeAttr(Node), ++ children = itemsEls([])}], ++ ModifNow, ModifLjid); ++ _ -> ++ event_stanza([#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', ++ attrs = nodeAttr(Node), ++ children = itemsEls([])}]) ++ end; LastItem -> -- Stanza = event_stanza( -+ event_stanza( + {ModifNow, ModifLjid} = LastItem#pubsub_item.modification, +- Stanza = event_stanza_with_delay( ++ event_stanza_with_delay( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), -- children = itemsEls(LastItem)}]), +- children = itemsEls(LastItem)}], ModifNow, ModifLjid), - {U, S, R} = LJID, - ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza} - end; -+ children = itemsEls(LastItem)}]) ++ children = itemsEls(LastItem)}], ModifNow, ModifLjid) + end, + {U, S, R} = LJID, -+ ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza}; -+ ++ ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza}; send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of {result, []} -> -@@ -2433,29 +2278,12 @@ +@@ -2441,29 +2289,12 @@ error -> {error, 'bad-request'}; _ -> @@ -554,7 +558,7 @@ end, Entities), {result, []}; _ -> -@@ -2510,11 +2338,11 @@ +@@ -2518,11 +2349,11 @@ end. read_sub(Subscriber, Node, NodeID, SubID, Lang) -> @@ -568,7 +572,7 @@ OptionsEl = #xmlel{ns = ?NS_PUBSUB, name = 'options', attrs = [?XMLATTR('node', node_to_string(Node)), ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), -@@ -2548,7 +2376,7 @@ +@@ -2556,7 +2387,7 @@ _ -> {"", "", ""} %%pablo TODO: "" or <<>> ?. short_jid uses exmpp_jid:node/1, etc. that returns binaries end, @@ -577,7 +581,7 @@ {result, Subs} = node_call(Type, get_subscriptions, [NodeID, Subscriber]), SubIDs = lists:foldl(fun({subscribed, SID}, Acc) -> -@@ -2568,7 +2396,7 @@ +@@ -2576,7 +2407,7 @@ end. write_sub(Subscriber, NodeID, SubID, Options) -> @@ -586,7 +590,7 @@ {error, notfound} -> {error, extended_error('not-acceptable', "invalid-subid")}; {result, _} -> -@@ -2741,8 +2569,8 @@ +@@ -2749,8 +2580,8 @@ ?XMLATTR('subsription', subscription_to_string(Sub)) | nodeAttr(Node)]}]}]}, ejabberd_router ! {route, service_jid(Host), JID, Stanza} end, @@ -597,7 +601,7 @@ true -> Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> -@@ -3029,7 +2857,7 @@ +@@ -3046,7 +2877,7 @@ {Depth, [{N, get_node_subs(N)} || N <- Nodes]} end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))} end, @@ -606,7 +610,7 @@ {result, CollSubs} -> CollSubs; _ -> [] end. -@@ -3043,9 +2871,9 @@ +@@ -3060,9 +2891,9 @@ get_options_for_subs(NodeID, Subs) -> lists:foldl(fun({JID, subscribed, SubID}, Acc) -> @@ -618,7 +622,7 @@ _ -> Acc end; (_, Acc) -> -@@ -3240,6 +3068,30 @@ +@@ -3257,6 +3088,30 @@ Result end. @@ -649,7 +653,7 @@ %% @spec (Host, Options) -> MaxItems %% Host = host() %% Options = [Option] -@@ -3616,7 +3468,13 @@ +@@ -3642,7 +3497,13 @@ tree_action(Host, Function, Args) -> ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), Fun = fun() -> tree_call(Host, Function, Args) end, @@ -664,7 +668,7 @@ %% @doc

      node plugin call.

      node_call(Type, Function, Args) -> -@@ -3636,13 +3494,13 @@ +@@ -3662,13 +3523,13 @@ node_action(Host, Type, Function, Args) -> ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), @@ -680,7 +684,7 @@ case tree_call(Host, get_node, [Host, Node]) of N when is_record(N, pubsub_node) -> case Action(N) of -@@ -3655,8 +3513,15 @@ +@@ -3681,8 +3542,15 @@ end end, Trans). @@ -698,7 +702,7 @@ {result, Result} -> {result, Result}; {error, Error} -> {error, Error}; {atomic, {result, Result}} -> {result, Result}; -@@ -3664,6 +3529,15 @@ +@@ -3690,6 +3558,15 @@ {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), {error, 'internal-server-error'}; @@ -714,7 +718,7 @@ {'EXIT', Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), {error, 'internal-server-error'}; -@@ -3672,6 +3546,16 @@ +@@ -3698,6 +3575,16 @@ {error, 'internal-server-error'} end. From b12b18d59f35d5990e0025d1b921c6610b459453 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 23 Sep 2009 17:27:09 +0000 Subject: [PATCH 548/582] Fix wrong XEP number to XEP-0227 SVN Revision: 2618 --- src/web/ejabberd_web_admin.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 1f47c42e8..697b03cfd 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -2029,21 +2029,21 @@ get_node(global, Node, ["backup"], Query, Lang) -> "OK")]) ]), ?XE("tr", - [?XCT("td", "Import users data from a PIEFXIS file (XEP-0277):"), + [?XCT("td", "Import users data from a PIEFXIS file (XEP-0227):"), ?XE("td", [?INPUT("text", "import_piefxis_filepath", filename:join(HomeDir, "users.xml"))]), ?XE("td", [?INPUTT("submit", "import_piefxis_file", "OK")]) ]), ?XE("tr", - [?XCT("td", "Export data of all users in the server to PIEFXIS files (XEP-0277):"), + [?XCT("td", "Export data of all users in the server to PIEFXIS files (XEP-0227):"), ?XE("td", [?INPUT("text", "export_piefxis_dirpath", HomeDir)]), ?XE("td", [?INPUTT("submit", "export_piefxis_dir", "OK")]) ]), ?XE("tr", - [?XE("td", [?CT("Export data of users in a host to PIEFXIS files (XEP-0277):"), + [?XE("td", [?CT("Export data of users in a host to PIEFXIS files (XEP-0227):"), ?C(" "), ?INPUT("text", "export_piefxis_host_dirhost", ?MYNAME)]), ?XE("td", [?INPUT("text", "export_piefxis_host_dirpath", HomeDir)]), From 479b04a6a3ac1eb5c719cf55fea616dc3c49b701 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Wed, 23 Sep 2009 21:12:44 +0000 Subject: [PATCH 549/582] fix Makefile.win32 for including stun (thanks to neustradamus) SVN Revision: 2620 --- src/Makefile.win32 | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Makefile.win32 b/src/Makefile.win32 index b866f11ff..d10c45ca8 100644 --- a/src/Makefile.win32 +++ b/src/Makefile.win32 @@ -63,6 +63,9 @@ release : build release_clean copy stringprep\*.erl $(SRC_DIR)\stringprep copy stringprep\*.c $(SRC_DIR)\stringprep copy stringprep\*.tcl $(SRC_DIR)\stringprep + mkdir $(SRC_DIR)\stun + copy stun\*.erl $(SRC_DIR)\stun + copy stun\*.hrl $(SRC_DIR)\stun mkdir $(SRC_DIR)\tls copy tls\*.erl $(SRC_DIR)\tls copy tls\*.c $(SRC_DIR)\tls @@ -96,6 +99,8 @@ all-recursive : nmake -nologo -f Makefile.win32 cd ..\stringprep nmake -nologo -f Makefile.win32 + cd ..\stun + nmake -nologo -f Makefile.win32 cd ..\tls nmake -nologo -f Makefile.win32 cd ..\ejabberd_zlib @@ -135,6 +140,8 @@ clean-recursive : nmake -nologo -f Makefile.win32 clean cd ..\stringprep nmake -nologo -f Makefile.win32 clean + cd ..\stun + nmake -nologo -f Makefile.win32 clean cd ..\tls nmake -nologo -f Makefile.win32 clean cd ..\ejabberd_zlib @@ -159,5 +166,4 @@ $(DLL) : $(OBJECT) $(LD) $(LD_FLAGS) -out:$(DLL) $(OBJECT) $(OBJECT) : $(SOURCE) - $(CC) $(CC_FLAGS) -c -Fo$(OBJECT) $(SOURCE) - + $(CC) $(CC_FLAGS) -c -Fo$(OBJECT) $(SOURCE) From e5a26b388f2e461efd23be77418dab45ecefd3a6 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Wed, 23 Sep 2009 22:00:53 +0000 Subject: [PATCH 550/582] rename pep_sendlast_offline option to ignore_pep_from_offline (EJAB-1047) SVN Revision: 2623 --- doc/guide.tex | 4 ++-- src/ejabberd.cfg.example | 2 +- src/mod_pubsub/mod_pubsub.erl | 8 ++++---- src/mod_pubsub/mod_pubsub_odbc.erl | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/guide.tex b/doc/guide.tex index 297fe7e74..e3e18c401 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -3462,10 +3462,10 @@ Options: To specify which nodetree to use. If not defined, the default pubsub nodetree is used. Only one nodetree can be used per host, and is shared by all node plugins. -\titem{\{pep\_sendlast\_offline, false|true\}} \ind{options!pep\_sendlast\_offline} +\titem{\{ignore\_pep\_from\_offline, false|true\}} \ind{options!ignore\_pep\_from\_offline} To specify whether or not we should get last published PEP items from users in our roster which are offline when we connect. Value is true or false. - If not defined, pubsub assumes false so we only get last items of online contacts. + If not defined, pubsub assumes true so we only get last items of online contacts. \titem{\{last\_item\_cache, false|true\}} \ind{options!last\_item\_cache} To specify whether or not pubsub should cache last items. Value is true or false. If not defined, pubsub do not cache last items. On systems with not so many nodes, diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index 27111252d..785ad3748 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -505,7 +505,7 @@ %%{mod_proxy65,[]}, {mod_pubsub, [ {access_createnode, pubsub_createnode}, - {pep_sendlast_offline, false}, + {ignore_pep_from_offline, true}, {last_item_cache, false}, {plugins, ["flat", "pep"]} % pep requires mod_caps ]}, diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 1c581e7d0..d58dd7f3e 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -133,7 +133,7 @@ host, access, pep_mapping = [], - pep_sendlast_offline = false, + ignore_pep_from_offline = true, last_item_cache = false, max_items_node = ?MAXITEMS, nodetree = ?STDTREE, @@ -184,7 +184,7 @@ init([ServerHost, Opts]) -> ?DEBUG("pubsub init ~p ~p",[ServerHost,Opts]), Host = gen_mod:get_opt_host(ServerHost, Opts, "pubsub.@HOST@"), Access = gen_mod:get_opt(access_createnode, Opts, all), - PepOffline = gen_mod:get_opt(pep_sendlast_offline, Opts, false), + PepOffline = gen_mod:get_opt(ignore_pep_from_offline, Opts, true), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), LastItemCache = gen_mod:get_opt(last_item_cache, Opts, false), MaxItemsNode = gen_mod:get_opt(max_items_node, Opts, ?MAXITEMS), @@ -232,7 +232,7 @@ init([ServerHost, Opts]) -> server_host = ServerHost, access = Access, pep_mapping = PepMapping, - pep_sendlast_offline = PepOffline, + ignore_pep_from_offline = PepOffline, last_item_cache = LastItemCache, max_items_node = MaxItemsNode, nodetree = NodeTree, @@ -500,7 +500,7 @@ send_loop(State) -> %% this is a hack in a sense that PEP should only be based on presence %% and is not able to "store" events of remote users (via s2s) %% this makes that hack only work for local domain by now - if State#state.pep_sendlast_offline -> + if not State#state.ignore_pep_from_offline -> {User, Server, Resource} = LJID, case mod_caps:get_caps({User, Server, Resource}) of nothing -> diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index 37825535f..21d7f5ba7 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -133,7 +133,7 @@ host, access, pep_mapping = [], - pep_sendlast_offline = false, + ignore_pep_from_offline = true, last_item_cache = false, max_items_node = ?MAXITEMS, nodetree = ?STDTREE, @@ -184,7 +184,7 @@ init([ServerHost, Opts]) -> ?DEBUG("pubsub init ~p ~p",[ServerHost,Opts]), Host = gen_mod:get_opt_host(ServerHost, Opts, "pubsub.@HOST@"), Access = gen_mod:get_opt(access_createnode, Opts, all), - PepOffline = gen_mod:get_opt(pep_sendlast_offline, Opts, false), + PepOffline = gen_mod:get_opt(ignore_pep_from_offline, Opts, true), IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), LastItemCache = gen_mod:get_opt(last_item_cache, Opts, false), MaxItemsNode = gen_mod:get_opt(max_items_node, Opts, ?MAXITEMS), @@ -230,7 +230,7 @@ init([ServerHost, Opts]) -> server_host = ServerHost, access = Access, pep_mapping = PepMapping, - pep_sendlast_offline = PepOffline, + ignore_pep_from_offline = PepOffline, last_item_cache = LastItemCache, max_items_node = MaxItemsNode, nodetree = NodeTree, @@ -326,7 +326,7 @@ send_loop(State) -> %% this is a hack in a sense that PEP should only be based on presence %% and is not able to "store" events of remote users (via s2s) %% this makes that hack only work for local domain by now - if State#state.pep_sendlast_offline -> + if not State#state.ignore_pep_from_offline -> {User, Server, Resource} = LJID, case mod_caps:get_caps({User, Server, Resource}) of nothing -> From 667fc07ec62140ffca039706db8f38939a0e4c0f Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 24 Sep 2009 13:36:48 +0000 Subject: [PATCH 551/582] Recomppile guide. SVN Revision: 2624 --- doc/guide.html | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 762ed968d..25ad209d3 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -2687,17 +2687,20 @@ is replaced at start time with the real virtual host name.
    {access_createnode, AccessName}
    This option restricts which users are allowed to create pubsub nodes using -ACL and ACCESS. The default value is pubsub_createnode.
    {plugins, [ Plugin, ...]}
    +ACL and ACCESS. The default value is pubsub_createnode.
    {max_items_node, MaxItems}
    +Define the maximum number of items that can be stored in a node. +Default value is 10. +
    {plugins, [ Plugin, ...]}
    To specify which pubsub node plugins to use. If not defined, the default pubsub plugin is always used.
    {nodetree, Name}
    To specify which nodetree to use. If not defined, the default pubsub nodetree is used. Only one nodetree can be used per host, and is shared by all node plugins. -
    {pep_sendlast_offline, false|true}
    +
    {ignore_pep_from_offline, false|true}
    To specify whether or not we should get last published PEP items from users in our roster which are offline when we connect. Value is true or false. -If not defined, pubsub assumes false so we only get last items of online contacts. +If not defined, pubsub assumes true so we only get last items of online contacts.
    {last_item_cache, false|true}
    To specify whether or not pubsub should cache last items. Value is true or false. If not defined, pubsub do not cache last items. On systems with not so many nodes, From b168cd7cf236e907a3b688390266c1b7de720199 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 24 Sep 2009 19:47:01 +0000 Subject: [PATCH 552/582] fix EJAB-1044 and EJAB-1055 SVN Revision: 2628 --- src/mod_pubsub/mod_pubsub.erl | 19 +++++++++++++---- src/mod_pubsub/mod_pubsub_odbc.erl | 27 +++++++++++++++++------- src/mod_pubsub/node.template | 1 + src/mod_pubsub/node_buddy.erl | 1 + src/mod_pubsub/node_club.erl | 1 + src/mod_pubsub/node_dispatch.erl | 1 + src/mod_pubsub/node_flat.erl | 1 + src/mod_pubsub/node_flat_odbc.erl | 1 + src/mod_pubsub/node_hometree.erl | 1 + src/mod_pubsub/node_hometree_odbc.erl | 1 + src/mod_pubsub/node_mb.erl | 1 + src/mod_pubsub/node_pep.erl | 1 + src/mod_pubsub/node_pep_odbc.erl | 1 + src/mod_pubsub/node_private.erl | 1 + src/mod_pubsub/node_public.erl | 1 + src/mod_pubsub/pubsub_odbc.patch | 30 +++++++++++++-------------- 16 files changed, 62 insertions(+), 27 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index d58dd7f3e..53c4e8569 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -47,7 +47,7 @@ -module(mod_pubsub). -author('christophe.romain@process-one.net'). --version('1.12-06'). +-version('1.13-0'). -behaviour(gen_server). -behaviour(gen_mod). @@ -483,7 +483,7 @@ send_loop(State) -> #pubsub_node{nodeid = {H, N}, type = Type, id = NodeId, options = Options} = Node, case get_option(Options, send_last_published_item) of on_sub_and_presence -> - send_items(H, N, NodeId, Type, SubJID, last); + send_items(H, N, NodeId, Type, LJID, last); _ -> ok end; @@ -3087,10 +3087,14 @@ get_options_for_subs(NodeID, Subs) -> % {result, false} % end -broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyType, Stanza) -> - %AccessModel = get_option(NodeOptions, access_model), +broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza) -> + NotificationType = get_option(NodeOptions, notification_type), BroadcastAll = get_option(NodeOptions, broadcast_all_resources), %% XXX this is not standard, but usefull From = service_jid(Host), + Stanza = case NotificationType of + normal -> BaseStanza; + MsgType -> add_message_type(BaseStanza, atom_to_list(MsgType)) + end, %% Handles explicit subscriptions NodesByJID = subscribed_nodes_by_jid(NotifyType, SubsByDepth), lists:foreach(fun ({LJID, Nodes}) -> @@ -3335,6 +3339,8 @@ get_configure_xfields(_Type, Options, Lang, Groups) -> ?LISTM_CONFIG_FIELD("Roster groups allowed to subscribe", roster_groups_allowed, Groups), ?ALIST_CONFIG_FIELD("Specify the publisher model", publish_model, [publishers, subscribers, open]), + ?ALIST_CONFIG_FIELD("Specify the event message type", notification_type, + [headline, normal]), ?INTEGER_CONFIG_FIELD("Max payload size in bytes", max_payload_size), ?ALIST_CONFIG_FIELD("When to send the last published item", send_last_published_item, [never, on_sub, on_sub_and_presence]), @@ -3466,6 +3472,8 @@ set_xoption(Host, [{"pubsub#access_model", [Val]} | Opts], NewOpts) -> ?SET_ALIST_XOPT(access_model, Val, [open, authorize, presence, roster, whitelist]); set_xoption(Host, [{"pubsub#publish_model", [Val]} | Opts], NewOpts) -> ?SET_ALIST_XOPT(publish_model, Val, [publishers, subscribers, open]); +set_xoption(Host, [{"pubsub#notification_type", [Val]} | Opts], NewOpts) -> + ?SET_ALIST_XOPT(notification_type, Val, [headline, normal]); set_xoption(Host, [{"pubsub#node_type", [Val]} | Opts], NewOpts) -> ?SET_ALIST_XOPT(node_type, Val, [leaf, collection]); set_xoption(Host, [{"pubsub#max_payload_size", [Val]} | Opts], NewOpts) -> @@ -3730,6 +3738,9 @@ itemsEls(Items) -> #xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = itemAttr(ItemId), children = Payload} end, Items). +add_message_type(#xmlel{name='message'} = El, Type) -> exmpp_stanza:set_type(El, Type); +add_message_type(El, _Type) -> El. + add_headers(#xmlel{} = El, HeaderEls) -> HeaderEl = #xmlel{ns = ?NS_SHIM, name = 'headers', children = HeaderEls}, exmpp_xml:prepend_child(El, HeaderEl). diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index 21d7f5ba7..303fd0cfc 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -47,7 +47,7 @@ -module(mod_pubsub_odbc). -author('christophe.romain@process-one.net'). --version('1.12-06'). +-version('1.13-0'). -behaviour(gen_server). -behaviour(gen_mod). @@ -305,14 +305,14 @@ send_loop(State) -> %% and if the node is so configured, send the last published item to From lists:foreach(fun(PType) -> Subscriptions = case catch node_action(Host, PType, get_entity_subscriptions_for_send_last, [Host, JID]) of - {result, S} -> S; - _ -> [] - end, + {result, S} -> S; + _ -> [] + end, lists:foreach( fun({Node, subscribed, _, SubJID}) -> if (SubJID == LJID) or (SubJID == BJID) -> - #pubsub_node{nodeid = {H, N}, type = Type, id = NodeId} = Node, - send_items(H, N, NodeId, Type, SubJID, last); + #pubsub_node{nodeid = {H, N}, type = Type, id = NodeId} = Node, + send_items(H, N, NodeId, Type, LJID, last); true -> % resource not concerned about that subscription ok @@ -2918,10 +2918,14 @@ get_options_for_subs(NodeID, Subs) -> % {result, false} % end -broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyType, Stanza) -> - %AccessModel = get_option(NodeOptions, access_model), +broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza) -> + NotificationType = get_option(NodeOptions, notification_type), BroadcastAll = get_option(NodeOptions, broadcast_all_resources), %% XXX this is not standard, but usefull From = service_jid(Host), + Stanza = case NotificationType of + normal -> BaseStanza; + MsgType -> add_message_type(BaseStanza, atom_to_list(MsgType)) + end, %% Handles explicit subscriptions NodesByJID = subscribed_nodes_by_jid(NotifyType, SubsByDepth), lists:foreach(fun ({LJID, Nodes}) -> @@ -3190,6 +3194,8 @@ get_configure_xfields(_Type, Options, Lang, Groups) -> ?LISTM_CONFIG_FIELD("Roster groups allowed to subscribe", roster_groups_allowed, Groups), ?ALIST_CONFIG_FIELD("Specify the publisher model", publish_model, [publishers, subscribers, open]), + ?ALIST_CONFIG_FIELD("Specify the event message type", notification_type, + [headline, normal]), ?INTEGER_CONFIG_FIELD("Max payload size in bytes", max_payload_size), ?ALIST_CONFIG_FIELD("When to send the last published item", send_last_published_item, [never, on_sub, on_sub_and_presence]), @@ -3321,6 +3327,8 @@ set_xoption(Host, [{"pubsub#access_model", [Val]} | Opts], NewOpts) -> ?SET_ALIST_XOPT(access_model, Val, [open, authorize, presence, roster, whitelist]); set_xoption(Host, [{"pubsub#publish_model", [Val]} | Opts], NewOpts) -> ?SET_ALIST_XOPT(publish_model, Val, [publishers, subscribers, open]); +set_xoption(Host, [{"pubsub#notification_type", [Val]} | Opts], NewOpts) -> + ?SET_ALIST_XOPT(notification_type, Val, [headline, normal]); set_xoption(Host, [{"pubsub#node_type", [Val]} | Opts], NewOpts) -> ?SET_ALIST_XOPT(node_type, Val, [leaf, collection]); set_xoption(Host, [{"pubsub#max_payload_size", [Val]} | Opts], NewOpts) -> @@ -3617,6 +3625,9 @@ itemsEls(Items) -> #xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = itemAttr(ItemId), children = Payload} end, Items). +add_message_type(#xmlel{name='message'} = El, Type) -> exmpp_stanza:set_type(El, Type); +add_message_type(El, _Type) -> El. + add_headers(#xmlel{} = El, HeaderEls) -> HeaderEl = #xmlel{ns = ?NS_SHIM, name = 'headers', children = HeaderEls}, exmpp_xml:prepend_child(El, HeaderEl). diff --git a/src/mod_pubsub/node.template b/src/mod_pubsub/node.template index a83408110..a6c8a9477 100644 --- a/src/mod_pubsub/node.template +++ b/src/mod_pubsub/node.template @@ -86,6 +86,7 @@ options() -> {access_model, open}, {roster_groups_allowed, []}, {publish_model, publishers}, + {notification_type, headline}, {max_payload_size, ?MAX_PAYLOAD_SIZE}, {send_last_published_item, on_sub_and_presence}, {deliver_notifications, true}, diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl index 0639e1dee..0d672a748 100644 --- a/src/mod_pubsub/node_buddy.erl +++ b/src/mod_pubsub/node_buddy.erl @@ -90,6 +90,7 @@ options() -> {access_model, presence}, {roster_groups_allowed, []}, {publish_model, publishers}, + {notification_type, headline}, {max_payload_size, ?MAX_PAYLOAD_SIZE}, {send_last_published_item, never}, {deliver_notifications, true}, diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl index 579ba7ba2..3e27e2013 100644 --- a/src/mod_pubsub/node_club.erl +++ b/src/mod_pubsub/node_club.erl @@ -89,6 +89,7 @@ options() -> {access_model, authorize}, {roster_groups_allowed, []}, {publish_model, publishers}, + {notification_type, headline}, {max_payload_size, ?MAX_PAYLOAD_SIZE}, {send_last_published_item, never}, {deliver_notifications, true}, diff --git a/src/mod_pubsub/node_dispatch.erl b/src/mod_pubsub/node_dispatch.erl index ad6778f31..2dc1d3f30 100644 --- a/src/mod_pubsub/node_dispatch.erl +++ b/src/mod_pubsub/node_dispatch.erl @@ -87,6 +87,7 @@ options() -> {access_model, open}, {roster_groups_allowed, []}, {publish_model, publishers}, + {notification_type, headline}, {max_payload_size, ?MAX_PAYLOAD_SIZE}, {send_last_published_item, never}, {deliver_notifications, true}, diff --git a/src/mod_pubsub/node_flat.erl b/src/mod_pubsub/node_flat.erl index b6bf4d1c9..6e5c2372a 100644 --- a/src/mod_pubsub/node_flat.erl +++ b/src/mod_pubsub/node_flat.erl @@ -80,6 +80,7 @@ options() -> {access_model, open}, {roster_groups_allowed, []}, {publish_model, publishers}, + {notification_type, headline}, {max_payload_size, ?MAX_PAYLOAD_SIZE}, {send_last_published_item, on_sub_and_presence}, {deliver_notifications, true}, diff --git a/src/mod_pubsub/node_flat_odbc.erl b/src/mod_pubsub/node_flat_odbc.erl index 4a7d360fd..08d818a41 100644 --- a/src/mod_pubsub/node_flat_odbc.erl +++ b/src/mod_pubsub/node_flat_odbc.erl @@ -81,6 +81,7 @@ options() -> {access_model, open}, {roster_groups_allowed, []}, {publish_model, publishers}, + {notification_type, headline}, {max_payload_size, ?MAX_PAYLOAD_SIZE}, {send_last_published_item, on_sub_and_presence}, {deliver_notifications, true}, diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index e707ceaea..11b076a92 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -143,6 +143,7 @@ options() -> {access_model, open}, {roster_groups_allowed, []}, {publish_model, publishers}, + {notification_type, headline}, {max_payload_size, ?MAX_PAYLOAD_SIZE}, {send_last_published_item, on_sub_and_presence}, {deliver_notifications, true}, diff --git a/src/mod_pubsub/node_hometree_odbc.erl b/src/mod_pubsub/node_hometree_odbc.erl index 75cb0f10f..c3ee1cf28 100644 --- a/src/mod_pubsub/node_hometree_odbc.erl +++ b/src/mod_pubsub/node_hometree_odbc.erl @@ -145,6 +145,7 @@ options() -> {access_model, open}, {roster_groups_allowed, []}, {publish_model, publishers}, + {notification_type, headline}, {max_payload_size, ?MAX_PAYLOAD_SIZE}, {send_last_published_item, on_sub_and_presence}, {deliver_notifications, true}, diff --git a/src/mod_pubsub/node_mb.erl b/src/mod_pubsub/node_mb.erl index 8debc41c1..6fdebef43 100644 --- a/src/mod_pubsub/node_mb.erl +++ b/src/mod_pubsub/node_mb.erl @@ -93,6 +93,7 @@ options() -> {access_model, presence}, {roster_groups_allowed, []}, {publish_model, publishers}, + {notification_type, headline}, {max_payload_size, ?MAX_PAYLOAD_SIZE}, {send_last_published_item, on_sub_and_presence}, {deliver_notifications, true}, diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index 0a153fc1a..00d0c4095 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -88,6 +88,7 @@ options() -> {access_model, presence}, {roster_groups_allowed, []}, {publish_model, publishers}, + {notification_type, headline}, {max_payload_size, ?MAX_PAYLOAD_SIZE}, {send_last_published_item, on_sub_and_presence}, {deliver_notifications, true}, diff --git a/src/mod_pubsub/node_pep_odbc.erl b/src/mod_pubsub/node_pep_odbc.erl index e297f5822..0b16eaa60 100644 --- a/src/mod_pubsub/node_pep_odbc.erl +++ b/src/mod_pubsub/node_pep_odbc.erl @@ -95,6 +95,7 @@ options() -> {access_model, presence}, {roster_groups_allowed, []}, {publish_model, publishers}, + {notification_type, headline}, {max_payload_size, ?MAX_PAYLOAD_SIZE}, {send_last_published_item, on_sub_and_presence}, {deliver_notifications, true}, diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl index e6d605089..1cff4c11b 100644 --- a/src/mod_pubsub/node_private.erl +++ b/src/mod_pubsub/node_private.erl @@ -90,6 +90,7 @@ options() -> {access_model, whitelist}, {roster_groups_allowed, []}, {publish_model, publishers}, + {notification_type, headline}, {max_payload_size, ?MAX_PAYLOAD_SIZE}, {send_last_published_item, never}, {deliver_notifications, false}, diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl index 75112e905..d227f6b89 100644 --- a/src/mod_pubsub/node_public.erl +++ b/src/mod_pubsub/node_public.erl @@ -91,6 +91,7 @@ options() -> {access_model, open}, {roster_groups_allowed, []}, {publish_model, publishers}, + {notification_type, headline}, {max_payload_size, ?MAX_PAYLOAD_SIZE}, {send_last_published_item, never}, {deliver_notifications, true}, diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index 40104ed62..f5d5d2895 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,5 +1,5 @@ ---- mod_pubsub.erl 2009-09-23 18:18:35.000000000 +0200 -+++ mod_pubsub_odbc.erl 2009-09-23 18:26:41.000000000 +0200 +--- mod_pubsub.erl 2009-09-24 21:40:32.000000000 +0200 ++++ mod_pubsub_odbc.erl 2009-09-24 21:46:01.000000000 +0200 @@ -45,7 +45,7 @@ %%% TODO %%% plugin: generate Reply (do not use broadcast atom anymore) @@ -7,7 +7,7 @@ --module(mod_pubsub). +-module(mod_pubsub_odbc). -author('christophe.romain@process-one.net'). - -version('1.12-06'). + -version('1.13-0'). @@ -58,9 +58,9 @@ -include("adhoc.hrl"). @@ -233,21 +233,21 @@ lists:foreach(fun(PType) -> - {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, JID]), + Subscriptions = case catch node_action(Host, PType, get_entity_subscriptions_for_send_last, [Host, JID]) of -+ {result, S} -> S; -+ _ -> [] -+ end, ++ {result, S} -> S; ++ _ -> [] ++ end, lists:foreach( fun({Node, subscribed, _, SubJID}) -> if (SubJID == LJID) or (SubJID == BJID) -> - #pubsub_node{nodeid = {H, N}, type = Type, id = NodeId, options = Options} = Node, - case get_option(Options, send_last_published_item) of - on_sub_and_presence -> -- send_items(H, N, NodeId, Type, SubJID, last); +- send_items(H, N, NodeId, Type, LJID, last); - _ -> - ok - end; -+ #pubsub_node{nodeid = {H, N}, type = Type, id = NodeId} = Node, -+ send_items(H, N, NodeId, Type, SubJID, last); ++ #pubsub_node{nodeid = {H, N}, type = Type, id = NodeId} = Node, ++ send_items(H, N, NodeId, Type, LJID, last); true -> % resource not concerned about that subscription ok @@ -622,7 +622,7 @@ _ -> Acc end; (_, Acc) -> -@@ -3257,6 +3088,30 @@ +@@ -3261,6 +3092,30 @@ Result end. @@ -653,7 +653,7 @@ %% @spec (Host, Options) -> MaxItems %% Host = host() %% Options = [Option] -@@ -3642,7 +3497,13 @@ +@@ -3650,7 +3505,13 @@ tree_action(Host, Function, Args) -> ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), Fun = fun() -> tree_call(Host, Function, Args) end, @@ -668,7 +668,7 @@ %% @doc

    node plugin call.

    node_call(Type, Function, Args) -> -@@ -3662,13 +3523,13 @@ +@@ -3670,13 +3531,13 @@ node_action(Host, Type, Function, Args) -> ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), @@ -684,7 +684,7 @@ case tree_call(Host, get_node, [Host, Node]) of N when is_record(N, pubsub_node) -> case Action(N) of -@@ -3681,8 +3542,15 @@ +@@ -3689,8 +3550,15 @@ end end, Trans). @@ -702,7 +702,7 @@ {result, Result} -> {result, Result}; {error, Error} -> {error, Error}; {atomic, {result, Result}} -> {result, Result}; -@@ -3690,6 +3558,15 @@ +@@ -3698,6 +3566,15 @@ {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), {error, 'internal-server-error'}; @@ -718,7 +718,7 @@ {'EXIT', Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), {error, 'internal-server-error'}; -@@ -3698,6 +3575,16 @@ +@@ -3706,6 +3583,16 @@ {error, 'internal-server-error'} end. From 2f5211ab74665220c4e34f6304da545ae4b1edb8 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 24 Sep 2009 19:52:46 +0000 Subject: [PATCH 553/582] improve waiting caps clean (EJAB-1054) SVN Revision: 2629 --- src/mod_caps.erl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 218d3ba1a..6614160c3 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -142,6 +142,8 @@ get_user_resources(U, S) -> note_caps(Host, From, Caps) -> case Caps of nothing -> + BJID = exmpp_jid:to_binary(From), + catch mnesia:dirty_delete({user_caps, BJID}), ok; _ -> Proc = gen_mod:get_module_proc(Host, ?PROCNAME), @@ -352,9 +354,8 @@ handle_cast({note_caps, From, Stanza = exmpp_iq:get(?NS_JABBER_CLIENT, Query, ID), ejabberd_local:register_iq_response_handler (list_to_binary(Host), ID, ?MODULE, handle_disco_response), - ejabberd_router:route(exmpp_jid:make(Host), - From, Stanza), - timer:send_after(?CAPS_QUERY_TIMEOUT, self(), {disco_timeout, ID}), + ejabberd_router:route(exmpp_jid:make(Host), From, Stanza), + timer:send_after(?CAPS_QUERY_TIMEOUT, self(), {disco_timeout, ID, BJID}), ?DICT:store(ID, node_to_binary(Node, SubNode), Dict) end, Requests, Missing), {noreply, State#state{disco_requests = NewRequests}} @@ -399,10 +400,11 @@ handle_cast({disco_response, From, _To, #iq{id = ID, type = Type, payload = Payl end, NewRequests = ?DICT:erase(ID, Requests), {noreply, State#state{disco_requests = NewRequests}}; -handle_cast({disco_timeout, ID}, #state{host = Host, disco_requests = Requests} = State) -> +handle_cast({disco_timeout, ID, BJID}, #state{host = Host, disco_requests = Requests} = State) -> %% do not wait a response anymore for this IQ, client certainly will never answer NewRequests = case ?DICT:is_key(ID, Requests) of true -> + catch mnesia:dirty_delete({user_caps, BJID}), ejabberd_local:unregister_iq_response_handler(list_to_binary(Host), ID), ?DICT:erase(ID, Requests); false -> From 24afead423bdaf28760839effbd643a3017f1300 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 25 Sep 2009 12:48:10 +0000 Subject: [PATCH 554/582] fix EJAB-1054 (thanks to Evgeniy Khramtsov) SVN Revision: 2633 --- src/mod_caps.erl | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 6614160c3..1ac6bbd92 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -140,15 +140,8 @@ get_user_resources(U, S) -> %% information. Host is the host that asks, From is the full JID that %% sent the caps packet, and Caps is what read_caps returned. note_caps(Host, From, Caps) -> - case Caps of - nothing -> - BJID = exmpp_jid:to_binary(From), - catch mnesia:dirty_delete({user_caps, BJID}), - ok; - _ -> - Proc = gen_mod:get_module_proc(Host, ?PROCNAME), - gen_server:cast(Proc, {note_caps, From, Caps}) - end. + Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + gen_server:cast(Proc, {note_caps, From, Caps}). %% wait_caps should be called just before note_caps %% it allows to lock get_caps usage for code using presence_probe @@ -310,6 +303,10 @@ handle_call({get_features, Caps}, From, State) -> handle_call(stop, _From, State) -> {stop, normal, ok, State}. +handle_cast({note_caps, From, nothing}, State) -> + BJID = exmpp_jid:to_binary(From), + catch mnesia:dirty_delete({user_caps, BJID}), + {noreply, State}; handle_cast({note_caps, From, #caps{node = Node, version = Version, exts = Exts} = Caps}, #state{host = Host, disco_requests = Requests} = State) -> From 53edf861e05bdce4c0a6fc6aa5ee6aaadc626cdb Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 25 Sep 2009 13:14:59 +0000 Subject: [PATCH 555/582] do not create hometree base when hometree not configured as plugin SVN Revision: 2635 --- src/mod_pubsub/mod_pubsub.erl | 15 ++++-- src/mod_pubsub/mod_pubsub_odbc.erl | 15 ++++-- src/mod_pubsub/pubsub_odbc.patch | 84 +++++++++++++++--------------- 3 files changed, 62 insertions(+), 52 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 53c4e8569..a46d19dce 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -227,7 +227,7 @@ init([ServerHost, Opts]) -> ejabberd_router:register_route(Host), update_node_database(Host, ServerHost), update_state_database(Host, ServerHost), - init_nodes(Host, ServerHost), + init_nodes(Host, ServerHost, NodeTree, Plugins), State = #state{host = Host, server_host = ServerHost, access = Access, @@ -277,10 +277,15 @@ terminate_plugins(Host, ServerHost, Plugins, TreePlugin) -> TreePlugin:terminate(Host, ServerHost), ok. -init_nodes(Host, ServerHost) -> - create_node(Host, ServerHost, ["home"], service_jid(Host), "hometree"), - create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), "hometree"), - ok. +init_nodes(Host, ServerHost, _NodeTree, Plugins) -> + %% TODO, this call should be done PLugin side + case lists:member("hometree", Plugins) of + true -> + create_node(Host, ServerHost, ["home"], service_jid(Host), "hometree"), + create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), "hometree"); + false -> + ok + end. update_node_database(Host, ServerHost) -> mnesia:del_table_index(pubsub_node, type), diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index 303fd0cfc..2f2c7375c 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -225,7 +225,7 @@ init([ServerHost, Opts]) -> ok end, ejabberd_router:register_route(Host), - init_nodes(Host, ServerHost), + init_nodes(Host, ServerHost, NodeTree, Plugins), State = #state{host = Host, server_host = ServerHost, access = Access, @@ -275,10 +275,15 @@ terminate_plugins(Host, ServerHost, Plugins, TreePlugin) -> TreePlugin:terminate(Host, ServerHost), ok. -init_nodes(Host, ServerHost) -> - create_node(Host, ServerHost, ["home"], service_jid(Host), "hometree"), - create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), "hometree"), - ok. +init_nodes(Host, ServerHost, _NodeTree, Plugins) -> + %% TODO, this call should be done PLugin side + case lists:member("hometree", Plugins) of + true -> + create_node(Host, ServerHost, ["home"], service_jid(Host), "hometree"), + create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), "hometree"); + false -> + ok + end. diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index f5d5d2895..64549f073 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,5 +1,5 @@ ---- mod_pubsub.erl 2009-09-24 21:40:32.000000000 +0200 -+++ mod_pubsub_odbc.erl 2009-09-24 21:46:01.000000000 +0200 +--- mod_pubsub.erl 2009-09-25 15:13:13.000000000 +0200 ++++ mod_pubsub_odbc.erl 2009-09-25 15:13:50.000000000 +0200 @@ -45,7 +45,7 @@ %%% TODO %%% plugin: generate Reply (do not use broadcast atom anymore) @@ -46,12 +46,12 @@ ejabberd_router:register_route(Host), - update_node_database(Host, ServerHost), - update_state_database(Host, ServerHost), - init_nodes(Host, ServerHost), + init_nodes(Host, ServerHost, NodeTree, Plugins), State = #state{host = Host, server_host = ServerHost, -@@ -282,177 +280,7 @@ - create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), "hometree"), - ok. +@@ -287,177 +285,7 @@ + ok + end. -update_node_database(Host, ServerHost) -> - mnesia:del_table_index(pubsub_node, type), @@ -227,7 +227,7 @@ send_queue(State, Msg) -> Pid = State#state.send_loop, -@@ -476,17 +304,15 @@ +@@ -481,17 +309,15 @@ %% for each node From is subscribed to %% and if the node is so configured, send the last published item to From lists:foreach(fun(PType) -> @@ -251,7 +251,7 @@ true -> % resource not concerned about that subscription ok -@@ -814,10 +640,10 @@ +@@ -819,10 +645,10 @@ {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), lists:foreach(fun ({Node, subscribed, _, JID}) -> @@ -264,7 +264,7 @@ true -> node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); false -> -@@ -935,11 +761,12 @@ +@@ -940,11 +766,12 @@ end, ejabberd_router:route(To, From, Res); #iq{type = get, ns = ?NS_DISCO_ITEMS, @@ -279,7 +279,7 @@ {result, IQRes} -> Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', attrs = QAttrs, -@@ -1042,7 +869,7 @@ +@@ -1047,7 +874,7 @@ [] -> ["leaf"]; %% No sub-nodes: it's a leaf node _ -> @@ -288,7 +288,7 @@ {result, []} -> ["collection"]; {result, _} -> ["leaf", "collection"]; _ -> [] -@@ -1058,8 +885,9 @@ +@@ -1063,8 +890,9 @@ []; true -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]} | @@ -300,7 +300,7 @@ end, features(Type))] end, %% TODO: add meta-data info (spec section 5.4) -@@ -1087,14 +915,15 @@ +@@ -1092,14 +920,15 @@ #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_DISCO_ITEMS_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_VCARD_s)]}] ++ @@ -319,7 +319,7 @@ {result, lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> SN = node_to_string(SubNode), -@@ -1104,7 +933,7 @@ +@@ -1109,7 +938,7 @@ ?XMLATTR('node', SN), ?XMLATTR('name', RN)]} end, tree_action(Host, get_subnodes, [Host, [], From]))}; @@ -328,7 +328,7 @@ case string:tokens(Item, "!") of [_SNode, _ItemID] -> {result, []}; -@@ -1116,10 +945,10 @@ +@@ -1121,10 +950,10 @@ %% TODO That is, remove name attribute (or node?, please check for 2.1) Action = fun(#pubsub_node{type = Type, id = NodeId}) -> @@ -342,7 +342,7 @@ end, Nodes = lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> -@@ -1135,7 +964,7 @@ +@@ -1140,7 +969,7 @@ #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), ?XMLATTR('name', Name)]} end, NodeItems), @@ -351,7 +351,7 @@ end, case transaction(Host, Node, Action, sync_dirty) of {result, {_, Result}} -> {result, Result}; -@@ -1269,7 +1098,8 @@ +@@ -1274,7 +1103,8 @@ (_, Acc) -> Acc end, [], exmpp_xml:remove_cdata_from_list(Els)), @@ -361,7 +361,7 @@ {get, 'subscriptions'} -> get_subscriptions(Host, Node, From, Plugins); {get, 'affiliations'} -> -@@ -1291,8 +1121,9 @@ +@@ -1296,8 +1126,9 @@ end. iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> @@ -373,7 +373,7 @@ case Action of [#xmlel{name = Name, attrs = Attrs, children = Els}] -> Node = case Host of -@@ -1422,7 +1253,8 @@ +@@ -1427,7 +1258,8 @@ _ -> [] end end, @@ -383,7 +383,7 @@ sync_dirty) of {result, Res} -> Res; Err -> Err -@@ -1467,7 +1299,7 @@ +@@ -1472,7 +1304,7 @@ %%% authorization handling @@ -392,7 +392,7 @@ Lang = "en", %% TODO fix {U, S, R} = Subscriber, Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = -@@ -1497,7 +1329,7 @@ +@@ -1502,7 +1334,7 @@ lists:foreach(fun(Owner) -> {U, S, R} = Owner, ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza} @@ -401,7 +401,7 @@ find_authorization_response(Packet) -> Els = Packet#xmlel.children, -@@ -1560,8 +1392,8 @@ +@@ -1565,8 +1397,8 @@ "true" -> true; _ -> false end, @@ -412,7 +412,7 @@ {result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]), if not IsApprover -> -@@ -1751,7 +1583,7 @@ +@@ -1756,7 +1588,7 @@ end, Reply = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(Node)}]}, @@ -421,7 +421,7 @@ {result, {Result, broadcast}} -> %%Lang = "en", %% TODO: fix %%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), -@@ -1860,7 +1692,7 @@ +@@ -1865,7 +1697,7 @@ %%
  • The node does not exist.
  • %% subscribe_node(Host, Node, From, JID, Configuration) -> @@ -430,7 +430,7 @@ Subscriber = try jlib:short_prepd_jid(exmpp_jid:parse(JID)) catch -@@ -1868,7 +1700,7 @@ +@@ -1873,7 +1705,7 @@ {undefined, undefined, undefined} end, SubId = uniqid(), @@ -439,7 +439,7 @@ Features = features(Type), SubscribeFeature = lists:member("subscribe", Features), OptionsFeature = lists:member("subscription-options", Features), -@@ -1887,9 +1719,13 @@ +@@ -1892,9 +1724,13 @@ {"", "", ""} -> {false, false}; _ -> @@ -456,7 +456,7 @@ end end, if -@@ -2214,7 +2050,7 @@ +@@ -2219,7 +2055,7 @@ %%

    The permission are not checked in this function.

    %% @todo We probably need to check that the user doing the query has the right %% to read the items. @@ -465,7 +465,7 @@ MaxItems = if SMaxItems == "" -> get_max_items_node(Host); -@@ -2253,11 +2089,11 @@ +@@ -2258,11 +2094,11 @@ node_call(Type, get_items, [NodeId, From, AccessModel, PresenceSubscription, RosterGroup, @@ -479,7 +479,7 @@ SendItems = case ItemIDs of [] -> Items; -@@ -2270,7 +2106,7 @@ +@@ -2275,7 +2111,7 @@ %% number of items sent to MaxItems: {result, #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = nodeAttr(Node), children = @@ -488,7 +488,7 @@ Error -> Error end -@@ -2302,17 +2138,29 @@ +@@ -2307,17 +2143,29 @@ %% @doc

    Resend the items of a node to the user.

    %% @todo use cache-last-item feature send_items(Host, Node, NodeId, Type, LJID, last) -> @@ -525,7 +525,7 @@ send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of {result, []} -> -@@ -2441,29 +2289,12 @@ +@@ -2446,29 +2294,12 @@ error -> {error, 'bad-request'}; _ -> @@ -558,7 +558,7 @@ end, Entities), {result, []}; _ -> -@@ -2518,11 +2349,11 @@ +@@ -2523,11 +2354,11 @@ end. read_sub(Subscriber, Node, NodeID, SubID, Lang) -> @@ -572,7 +572,7 @@ OptionsEl = #xmlel{ns = ?NS_PUBSUB, name = 'options', attrs = [?XMLATTR('node', node_to_string(Node)), ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), -@@ -2556,7 +2387,7 @@ +@@ -2561,7 +2392,7 @@ _ -> {"", "", ""} %%pablo TODO: "" or <<>> ?. short_jid uses exmpp_jid:node/1, etc. that returns binaries end, @@ -581,7 +581,7 @@ {result, Subs} = node_call(Type, get_subscriptions, [NodeID, Subscriber]), SubIDs = lists:foldl(fun({subscribed, SID}, Acc) -> -@@ -2576,7 +2407,7 @@ +@@ -2581,7 +2412,7 @@ end. write_sub(Subscriber, NodeID, SubID, Options) -> @@ -590,7 +590,7 @@ {error, notfound} -> {error, extended_error('not-acceptable', "invalid-subid")}; {result, _} -> -@@ -2749,8 +2580,8 @@ +@@ -2754,8 +2585,8 @@ ?XMLATTR('subsription', subscription_to_string(Sub)) | nodeAttr(Node)]}]}]}, ejabberd_router ! {route, service_jid(Host), JID, Stanza} end, @@ -601,7 +601,7 @@ true -> Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> -@@ -3046,7 +2877,7 @@ +@@ -3051,7 +2882,7 @@ {Depth, [{N, get_node_subs(N)} || N <- Nodes]} end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))} end, @@ -610,7 +610,7 @@ {result, CollSubs} -> CollSubs; _ -> [] end. -@@ -3060,9 +2891,9 @@ +@@ -3065,9 +2896,9 @@ get_options_for_subs(NodeID, Subs) -> lists:foldl(fun({JID, subscribed, SubID}, Acc) -> @@ -622,7 +622,7 @@ _ -> Acc end; (_, Acc) -> -@@ -3261,6 +3092,30 @@ +@@ -3266,6 +3097,30 @@ Result end. @@ -653,7 +653,7 @@ %% @spec (Host, Options) -> MaxItems %% Host = host() %% Options = [Option] -@@ -3650,7 +3505,13 @@ +@@ -3655,7 +3510,13 @@ tree_action(Host, Function, Args) -> ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), Fun = fun() -> tree_call(Host, Function, Args) end, @@ -668,7 +668,7 @@ %% @doc

    node plugin call.

    node_call(Type, Function, Args) -> -@@ -3670,13 +3531,13 @@ +@@ -3675,13 +3536,13 @@ node_action(Host, Type, Function, Args) -> ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), @@ -684,7 +684,7 @@ case tree_call(Host, get_node, [Host, Node]) of N when is_record(N, pubsub_node) -> case Action(N) of -@@ -3689,8 +3550,15 @@ +@@ -3694,8 +3555,15 @@ end end, Trans). @@ -702,7 +702,7 @@ {result, Result} -> {result, Result}; {error, Error} -> {error, Error}; {atomic, {result, Result}} -> {result, Result}; -@@ -3698,6 +3566,15 @@ +@@ -3703,6 +3571,15 @@ {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), {error, 'internal-server-error'}; @@ -718,7 +718,7 @@ {'EXIT', Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), {error, 'internal-server-error'}; -@@ -3706,6 +3583,16 @@ +@@ -3711,6 +3588,16 @@ {error, 'internal-server-error'} end. From e36c530732019c905510db0e74e51542fc78a73c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20R=C3=A9mond?= Date: Sun, 27 Sep 2009 14:31:52 +0000 Subject: [PATCH 556/582] Describe how to compile ejabberd on Mac OS X Snow Leopard with Erlang R13B-2 SVN Revision: 2637 --- doc/guide.tex | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/guide.tex b/doc/guide.tex index e3e18c401..5f9755b84 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -376,6 +376,20 @@ Some options that you may be interested in modifying: Disable the use of Erlang/OTP supervision for transient processes. \end{description} +\makesubsection{snowleopard}{Compiling ejabberd under Snow Leopard with Erlang R13B} +\ind{install!snowleopard} + +Erl Interface, the library to link Erlang with C code, is compiled as +32-bits code in Erlang R13B-2. Mac OS X Snow Leopard is a 64-bits +system and will try compiling ejabberd C code in 64-bits as a default. + +To compile ejabberd on Mac OS X Snow Leopard with Erlang R13B-2, you +need to force C code to be compiled with 32-bits. This is done with +the following configure command: + +\begin{verbatim} +CC='gcc -m32' CFLAGS=-m32 LDFLAGS=-m32 ./configure +\end{verbatim} \makesubsection{install}{Install} \ind{install!install} From 75793f7cf43e70ea4490033dce82d90ec42cbc5d Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 2 Oct 2009 15:04:16 +0000 Subject: [PATCH 557/582] New CAPTCHA script since previous one has been broken (thanks to Evgeniy Khramtsov)(merged from trunk@2631) SVN Revision: 2639 --- tools/captcha.sh | 63 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/tools/captcha.sh b/tools/captcha.sh index 2b18d93ad..4d405673a 100644 --- a/tools/captcha.sh +++ b/tools/captcha.sh @@ -1,21 +1,52 @@ #!/bin/sh -SIGN=$(($RANDOM % 2)) +INPUT=$1 -R1=$(($RANDOM % 20)) -R2=$(($RANDOM % 10 + 40)) +WAVE1_AMPLITUDE=$((2 + $RANDOM % 5)) +WAVE1_LENGTH=$((50 + $RANDOM % 25)) +WAVE2_AMPLITUDE=$((2 + $RANDOM % 5)) +WAVE2_LENGTH=$((50 + $RANDOM % 25)) +WAVE3_AMPLITUDE=$((2 + $RANDOM % 5)) +WAVE3_LENGTH=$((50 + $RANDOM % 25)) +W1_LINE_START_Y=$((10 + $RANDOM % 40)) +W1_LINE_STOP_Y=$((10 + $RANDOM % 40)) +W2_LINE_START_Y=$((10 + $RANDOM % 40)) +W2_LINE_STOP_Y=$((10 + $RANDOM % 40)) +W3_LINE_START_Y=$((10 + $RANDOM % 40)) +W3_LINE_STOP_Y=$((10 + $RANDOM % 40)) -if [ $SIGN -eq "0" ]; then - S1=$(( -1*($RANDOM % 20 + 50) )) - S2=$(( $RANDOM % 20 + 50 )) -else - S2=$(( -1*($RANDOM % 20 + 50) )) - S1=$(( $RANDOM % 20 + 50 )) -fi +B1_LINE_START_Y=$(($RANDOM % 40)) +B1_LINE_STOP_Y=$(($RANDOM % 40)) +B2_LINE_START_Y=$(($RANDOM % 40)) +B2_LINE_STOP_Y=$(($RANDOM % 40)) +#B3_LINE_START_Y=$(($RANDOM % 40)) +#B3_LINE_STOP_Y=$(($RANDOM % 40)) -convert -size 140x60 xc:white \ - -pointsize 30 -draw "text 20,30 '$1'" \ - -roll -$R2+$R1 -swirl $S1 \ - -roll +$R2-$R1 -swirl $S2 \ - +repage -resize 120x60 \ - -quality 90 -depth 8 png:- +B1_LINE_START_X=$(($RANDOM % 20)) +B1_LINE_STOP_X=$((100 + $RANDOM % 40)) +B2_LINE_START_X=$(($RANDOM % 20)) +B2_LINE_STOP_X=$((100 + $RANDOM % 40)) +#B3_LINE_START_X=$(($RANDOM % 20)) +#B3_LINE_STOP_X=$((100 + $RANDOM % 40)) + +ROLL_X=$(($RANDOM % 40)) + +convert -size 180x60 xc:none -pointsize 40 \ + \( -clone 0 -fill white \ + -stroke black -strokewidth 4 -annotate +0+40 "$INPUT" \ + -stroke white -strokewidth 2 -annotate +0+40 "$INPUT" \ + -roll +$ROLL_X+0 \ + -wave "$WAVE1_AMPLITUDE"x"$WAVE1_LENGTH" \ + -roll -$ROLL_X+0 \) \ + \( -clone 0 -stroke black \ + -strokewidth 1 -draw \ + "line $B1_LINE_START_X,$B1_LINE_START_Y $B1_LINE_STOP_X,$B1_LINE_STOP_Y" \ + -strokewidth 1 -draw \ + "line $B2_LINE_START_X,$B2_LINE_START_Y $B2_LINE_STOP_X,$B2_LINE_STOP_Y" \ + -wave "$WAVE2_AMPLITUDE"x"$WAVE2_LENGTH" \) \ + \( -clone 0 -stroke white \ + -strokewidth 2 -draw "line 0,$W1_LINE_START_Y 140,$W1_LINE_STOP_Y" \ + -strokewidth 2 -draw "line 0,$W2_LINE_START_Y 140,$W2_LINE_STOP_Y" \ + -strokewidth 2 -draw "line 0,$W3_LINE_START_Y 140,$W3_LINE_STOP_Y" \ + -wave "$WAVE3_AMPLITUDE"x"$WAVE3_LENGTH" \) \ + -flatten -crop 140x60 +repage -quality 90 -depth 8 png:- From f4e35033e7b84efd7f7491e42c82bdae53d6780c Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 6 Oct 2009 10:05:10 +0000 Subject: [PATCH 558/582] Improve stream error stanza when receives invalid handshake from component. SVN Revision: 2641 --- src/ejabberd_service.erl | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 1fe22afae..3f0620558 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -198,9 +198,23 @@ wait_for_handshake({xmlstreamelement, El}, StateData) -> end, StateData#state.hosts), {next_state, stream_established, StateData}; _ -> - send_element(StateData, - #xmlel{ns = ?NS_XMPP, name = 'error', children = [ - #xmlcdata{cdata = <<"Invalid Handshake">>}]}), + TextEl = + #xmlel{ns = ?NS_STANZA_ERRORS, + name = 'text', + children = + [#xmlcdata{cdata = <<"Invalid Handshake">>}] + }, + NotAuthorizedEl = + #xmlel{ns = ?NS_STANZA_ERRORS, + name = 'not-authorized', + children = [TextEl] + }, + InvalidHandshakeEl = + #xmlel{ns = ?NS_XMPP, + name = 'error', + children = [NotAuthorizedEl] + }, + send_element(StateData, InvalidHandshakeEl), send_element(StateData, exmpp_stream:closing()), {stop, normal, StateData} end; From 65926460b22cb291bbae30a939d03bca6a4e5c8f Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 6 Oct 2009 15:22:02 +0000 Subject: [PATCH 559/582] allow max_items_node use on pep SVN Revision: 2643 --- src/mod_pubsub/mod_pubsub.erl | 2 + src/mod_pubsub/mod_pubsub_odbc.erl | 2 + src/mod_pubsub/pubsub_odbc.patch | 80 +++++++++++++++--------------- 3 files changed, 44 insertions(+), 40 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index a46d19dce..9e5f98ade 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -202,6 +202,8 @@ init([ServerHost, Opts]) -> ets:insert(gen_mod:get_module_proc(Host, config), {max_items_node, MaxItemsNode}), ets:insert(gen_mod:get_module_proc(ServerHost, config), {nodetree, NodeTree}), ets:insert(gen_mod:get_module_proc(ServerHost, config), {plugins, Plugins}), + ets:insert(gen_mod:get_module_proc(ServerHost, config), {last_item_cache, LastItemCache}), + ets:insert(gen_mod:get_module_proc(ServerHost, config), {max_items_node, MaxItemsNode}), ets:insert(gen_mod:get_module_proc(ServerHost, config), {pep_mapping, PepMapping}), ejabberd_hooks:add(disco_sm_identity, ServerHostB, ?MODULE, disco_sm_identity, 75), ejabberd_hooks:add(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index 2f2c7375c..d8a2ea66f 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -202,6 +202,8 @@ init([ServerHost, Opts]) -> ets:insert(gen_mod:get_module_proc(Host, config), {max_items_node, MaxItemsNode}), ets:insert(gen_mod:get_module_proc(ServerHost, config), {nodetree, NodeTree}), ets:insert(gen_mod:get_module_proc(ServerHost, config), {plugins, Plugins}), + ets:insert(gen_mod:get_module_proc(ServerHost, config), {last_item_cache, LastItemCache}), + ets:insert(gen_mod:get_module_proc(ServerHost, config), {max_items_node, MaxItemsNode}), ets:insert(gen_mod:get_module_proc(ServerHost, config), {pep_mapping, PepMapping}), ejabberd_hooks:add(disco_sm_identity, ServerHostB, ?MODULE, disco_sm_identity, 75), ejabberd_hooks:add(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75), diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index 64549f073..49cc8405a 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,5 +1,5 @@ ---- mod_pubsub.erl 2009-09-25 15:13:13.000000000 +0200 -+++ mod_pubsub_odbc.erl 2009-09-25 15:13:50.000000000 +0200 +--- mod_pubsub.erl 2009-10-06 17:21:15.000000000 +0200 ++++ mod_pubsub_odbc.erl 2009-10-06 17:21:35.000000000 +0200 @@ -45,7 +45,7 @@ %%% TODO %%% plugin: generate Reply (do not use broadcast atom anymore) @@ -40,7 +40,7 @@ -define(PLUGIN_PREFIX, "node_"). -define(TREE_PREFIX, "nodetree_"). -@@ -225,8 +225,6 @@ +@@ -227,8 +227,6 @@ ok end, ejabberd_router:register_route(Host), @@ -49,7 +49,7 @@ init_nodes(Host, ServerHost, NodeTree, Plugins), State = #state{host = Host, server_host = ServerHost, -@@ -287,177 +285,7 @@ +@@ -289,177 +287,7 @@ ok end. @@ -227,7 +227,7 @@ send_queue(State, Msg) -> Pid = State#state.send_loop, -@@ -481,17 +309,15 @@ +@@ -483,17 +311,15 @@ %% for each node From is subscribed to %% and if the node is so configured, send the last published item to From lists:foreach(fun(PType) -> @@ -251,7 +251,7 @@ true -> % resource not concerned about that subscription ok -@@ -819,10 +645,10 @@ +@@ -821,10 +647,10 @@ {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), lists:foreach(fun ({Node, subscribed, _, JID}) -> @@ -264,7 +264,7 @@ true -> node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); false -> -@@ -940,11 +766,12 @@ +@@ -942,11 +768,12 @@ end, ejabberd_router:route(To, From, Res); #iq{type = get, ns = ?NS_DISCO_ITEMS, @@ -279,7 +279,7 @@ {result, IQRes} -> Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', attrs = QAttrs, -@@ -1047,7 +874,7 @@ +@@ -1049,7 +876,7 @@ [] -> ["leaf"]; %% No sub-nodes: it's a leaf node _ -> @@ -288,7 +288,7 @@ {result, []} -> ["collection"]; {result, _} -> ["leaf", "collection"]; _ -> [] -@@ -1063,8 +890,9 @@ +@@ -1065,8 +892,9 @@ []; true -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]} | @@ -300,7 +300,7 @@ end, features(Type))] end, %% TODO: add meta-data info (spec section 5.4) -@@ -1092,14 +920,15 @@ +@@ -1094,14 +922,15 @@ #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_DISCO_ITEMS_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_VCARD_s)]}] ++ @@ -319,7 +319,7 @@ {result, lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> SN = node_to_string(SubNode), -@@ -1109,7 +938,7 @@ +@@ -1111,7 +940,7 @@ ?XMLATTR('node', SN), ?XMLATTR('name', RN)]} end, tree_action(Host, get_subnodes, [Host, [], From]))}; @@ -328,7 +328,7 @@ case string:tokens(Item, "!") of [_SNode, _ItemID] -> {result, []}; -@@ -1121,10 +950,10 @@ +@@ -1123,10 +952,10 @@ %% TODO That is, remove name attribute (or node?, please check for 2.1) Action = fun(#pubsub_node{type = Type, id = NodeId}) -> @@ -342,7 +342,7 @@ end, Nodes = lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> -@@ -1140,7 +969,7 @@ +@@ -1142,7 +971,7 @@ #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), ?XMLATTR('name', Name)]} end, NodeItems), @@ -351,7 +351,7 @@ end, case transaction(Host, Node, Action, sync_dirty) of {result, {_, Result}} -> {result, Result}; -@@ -1274,7 +1103,8 @@ +@@ -1276,7 +1105,8 @@ (_, Acc) -> Acc end, [], exmpp_xml:remove_cdata_from_list(Els)), @@ -361,7 +361,7 @@ {get, 'subscriptions'} -> get_subscriptions(Host, Node, From, Plugins); {get, 'affiliations'} -> -@@ -1296,8 +1126,9 @@ +@@ -1298,8 +1128,9 @@ end. iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> @@ -373,7 +373,7 @@ case Action of [#xmlel{name = Name, attrs = Attrs, children = Els}] -> Node = case Host of -@@ -1427,7 +1258,8 @@ +@@ -1429,7 +1260,8 @@ _ -> [] end end, @@ -383,7 +383,7 @@ sync_dirty) of {result, Res} -> Res; Err -> Err -@@ -1472,7 +1304,7 @@ +@@ -1474,7 +1306,7 @@ %%% authorization handling @@ -392,7 +392,7 @@ Lang = "en", %% TODO fix {U, S, R} = Subscriber, Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = -@@ -1502,7 +1334,7 @@ +@@ -1504,7 +1336,7 @@ lists:foreach(fun(Owner) -> {U, S, R} = Owner, ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza} @@ -401,7 +401,7 @@ find_authorization_response(Packet) -> Els = Packet#xmlel.children, -@@ -1565,8 +1397,8 @@ +@@ -1567,8 +1399,8 @@ "true" -> true; _ -> false end, @@ -412,7 +412,7 @@ {result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]), if not IsApprover -> -@@ -1756,7 +1588,7 @@ +@@ -1758,7 +1590,7 @@ end, Reply = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(Node)}]}, @@ -421,7 +421,7 @@ {result, {Result, broadcast}} -> %%Lang = "en", %% TODO: fix %%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), -@@ -1865,7 +1697,7 @@ +@@ -1867,7 +1699,7 @@ %%
  • The node does not exist.
  • %% subscribe_node(Host, Node, From, JID, Configuration) -> @@ -430,7 +430,7 @@ Subscriber = try jlib:short_prepd_jid(exmpp_jid:parse(JID)) catch -@@ -1873,7 +1705,7 @@ +@@ -1875,7 +1707,7 @@ {undefined, undefined, undefined} end, SubId = uniqid(), @@ -439,7 +439,7 @@ Features = features(Type), SubscribeFeature = lists:member("subscribe", Features), OptionsFeature = lists:member("subscription-options", Features), -@@ -1892,9 +1724,13 @@ +@@ -1894,9 +1726,13 @@ {"", "", ""} -> {false, false}; _ -> @@ -456,7 +456,7 @@ end end, if -@@ -2219,7 +2055,7 @@ +@@ -2221,7 +2057,7 @@ %%

    The permission are not checked in this function.

    %% @todo We probably need to check that the user doing the query has the right %% to read the items. @@ -465,7 +465,7 @@ MaxItems = if SMaxItems == "" -> get_max_items_node(Host); -@@ -2258,11 +2094,11 @@ +@@ -2260,11 +2096,11 @@ node_call(Type, get_items, [NodeId, From, AccessModel, PresenceSubscription, RosterGroup, @@ -479,7 +479,7 @@ SendItems = case ItemIDs of [] -> Items; -@@ -2275,7 +2111,7 @@ +@@ -2277,7 +2113,7 @@ %% number of items sent to MaxItems: {result, #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = nodeAttr(Node), children = @@ -488,7 +488,7 @@ Error -> Error end -@@ -2307,17 +2143,29 @@ +@@ -2309,17 +2145,29 @@ %% @doc

    Resend the items of a node to the user.

    %% @todo use cache-last-item feature send_items(Host, Node, NodeId, Type, LJID, last) -> @@ -525,7 +525,7 @@ send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of {result, []} -> -@@ -2446,29 +2294,12 @@ +@@ -2448,29 +2296,12 @@ error -> {error, 'bad-request'}; _ -> @@ -558,7 +558,7 @@ end, Entities), {result, []}; _ -> -@@ -2523,11 +2354,11 @@ +@@ -2525,11 +2356,11 @@ end. read_sub(Subscriber, Node, NodeID, SubID, Lang) -> @@ -572,7 +572,7 @@ OptionsEl = #xmlel{ns = ?NS_PUBSUB, name = 'options', attrs = [?XMLATTR('node', node_to_string(Node)), ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), -@@ -2561,7 +2392,7 @@ +@@ -2563,7 +2394,7 @@ _ -> {"", "", ""} %%pablo TODO: "" or <<>> ?. short_jid uses exmpp_jid:node/1, etc. that returns binaries end, @@ -581,7 +581,7 @@ {result, Subs} = node_call(Type, get_subscriptions, [NodeID, Subscriber]), SubIDs = lists:foldl(fun({subscribed, SID}, Acc) -> -@@ -2581,7 +2412,7 @@ +@@ -2583,7 +2414,7 @@ end. write_sub(Subscriber, NodeID, SubID, Options) -> @@ -590,7 +590,7 @@ {error, notfound} -> {error, extended_error('not-acceptable', "invalid-subid")}; {result, _} -> -@@ -2754,8 +2585,8 @@ +@@ -2756,8 +2587,8 @@ ?XMLATTR('subsription', subscription_to_string(Sub)) | nodeAttr(Node)]}]}]}, ejabberd_router ! {route, service_jid(Host), JID, Stanza} end, @@ -601,7 +601,7 @@ true -> Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> -@@ -3051,7 +2882,7 @@ +@@ -3053,7 +2884,7 @@ {Depth, [{N, get_node_subs(N)} || N <- Nodes]} end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))} end, @@ -610,7 +610,7 @@ {result, CollSubs} -> CollSubs; _ -> [] end. -@@ -3065,9 +2896,9 @@ +@@ -3067,9 +2898,9 @@ get_options_for_subs(NodeID, Subs) -> lists:foldl(fun({JID, subscribed, SubID}, Acc) -> @@ -622,7 +622,7 @@ _ -> Acc end; (_, Acc) -> -@@ -3266,6 +3097,30 @@ +@@ -3268,6 +3099,30 @@ Result end. @@ -653,7 +653,7 @@ %% @spec (Host, Options) -> MaxItems %% Host = host() %% Options = [Option] -@@ -3655,7 +3510,13 @@ +@@ -3657,7 +3512,13 @@ tree_action(Host, Function, Args) -> ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), Fun = fun() -> tree_call(Host, Function, Args) end, @@ -668,7 +668,7 @@ %% @doc

    node plugin call.

    node_call(Type, Function, Args) -> -@@ -3675,13 +3536,13 @@ +@@ -3677,13 +3538,13 @@ node_action(Host, Type, Function, Args) -> ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), @@ -684,7 +684,7 @@ case tree_call(Host, get_node, [Host, Node]) of N when is_record(N, pubsub_node) -> case Action(N) of -@@ -3694,8 +3555,15 @@ +@@ -3696,8 +3557,15 @@ end end, Trans). @@ -702,7 +702,7 @@ {result, Result} -> {result, Result}; {error, Error} -> {error, Error}; {atomic, {result, Result}} -> {result, Result}; -@@ -3703,6 +3571,15 @@ +@@ -3705,6 +3573,15 @@ {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), {error, 'internal-server-error'}; @@ -718,7 +718,7 @@ {'EXIT', Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), {error, 'internal-server-error'}; -@@ -3711,6 +3588,16 @@ +@@ -3713,6 +3590,16 @@ {error, 'internal-server-error'} end. From a2bb22a0e72b484be3fe512c6b844534ae6ae92f Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 8 Oct 2009 11:33:18 +0000 Subject: [PATCH 560/582] Use queue to reduced quadratic time effort on selective receive (thanks to Alexey Shchepin) Merged from trunk@2644 SVN Revision: 2646 --- src/ejabberd_service.erl | 12 ++- src/p1_fsm.erl | 164 +++++++++++++++++++++++++++------------ 2 files changed, 125 insertions(+), 51 deletions(-) diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 3f0620558..6379de19d 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -27,7 +27,9 @@ -module(ejabberd_service). -author('alexey@process-one.net'). --behaviour(gen_fsm). +-define(GEN_FSM, p1_fsm). + +-behaviour(?GEN_FSM). %% External exports -export([start/2, @@ -68,6 +70,11 @@ -define(DEFAULT_NS, ?NS_COMPONENT_ACCEPT). -define(PREFIXED_NS, [{?NS_XMPP, ?NS_XMPP_pfx}]). +%% Only change this value if you now what your are doing: +-define(FSMLIMITS,[]). +%% -define(FSMLIMITS, [{max_queue, 2000}]). + + %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- @@ -75,7 +82,8 @@ start(SockData, Opts) -> supervisor:start_child(ejabberd_service_sup, [SockData, Opts]). start_link(SockData, Opts) -> - gen_fsm:start_link(ejabberd_service, [SockData, Opts], ?FSMOPTS). + ?GEN_FSM:start_link( + ejabberd_service, [SockData, Opts], ?FSMLIMITS ++ ?FSMOPTS). socket_type() -> xml_stream. diff --git a/src/p1_fsm.erl b/src/p1_fsm.erl index c4de9faa4..dec999266 100644 --- a/src/p1_fsm.erl +++ b/src/p1_fsm.erl @@ -21,7 +21,7 @@ %% terminate immediatetly. If the fsm trap_exit process flag has been %% set to true, the FSM terminate function will called. %% - You can pass the gen_fsm options to control resource usage. -%% {max_messages, N} will exit the process with priority_shutdown +%% {max_queue, N} will exit the process with priority_shutdown %% - You can limit the time processing a message (TODO): If the %% message processing does not return in a given period of time, the %% process will be terminated. @@ -123,7 +123,7 @@ sync_send_all_state_event/2, sync_send_all_state_event/3, reply/2, start_timer/2,send_event_after/2,cancel_timer/1, - enter_loop/4, enter_loop/5, enter_loop/6]). + enter_loop/4, enter_loop/5, enter_loop/6, wake_hib/7]). -export([behaviour_info/1]). @@ -273,8 +273,11 @@ enter_loop(Mod, Options, StateName, StateData, ServerName, Timeout) -> Name = get_proc_name(ServerName), Parent = get_parent(), Debug = gen:debug_options(Options), - Limits= limit_options(Options), - loop(Parent, Name, StateName, StateData, Mod, Timeout, Debug, Limits). + Limits = limit_options(Options), + Queue = queue:new(), + QueueLen = 0, + loop(Parent, Name, StateName, StateData, Mod, Timeout, Debug, + Limits, Queue, QueueLen). get_proc_name(Pid) when is_pid(Pid) -> Pid; @@ -329,16 +332,19 @@ name_to_pid(Name) -> %%% --------------------------------------------------- init_it(Starter, self, Name, Mod, Args, Options) -> init_it(Starter, self(), Name, Mod, Args, Options); -init_it(Starter, Parent, Name, Mod, Args, Options) -> +init_it(Starter, Parent, Name0, Mod, Args, Options) -> + Name = name(Name0), Debug = gen:debug_options(Options), - Limits= limit_options(Options), + Limits = limit_options(Options), + Queue = queue:new(), + QueueLen = 0, case catch Mod:init(Args) of {ok, StateName, StateData} -> proc_lib:init_ack(Starter, {ok, self()}), - loop(Parent, Name, StateName, StateData, Mod, infinity, Debug, Limits); + loop(Parent, Name, StateName, StateData, Mod, infinity, Debug, Limits, Queue, QueueLen); {ok, StateName, StateData, Timeout} -> proc_lib:init_ack(Starter, {ok, self()}), - loop(Parent, Name, StateName, StateData, Mod, Timeout, Debug, Limits); + loop(Parent, Name, StateName, StateData, Mod, Timeout, Debug, Limits, Queue, QueueLen); {stop, Reason} -> proc_lib:init_ack(Starter, {error, Reason}), exit(Reason); @@ -354,13 +360,35 @@ init_it(Starter, Parent, Name, Mod, Args, Options) -> exit(Error) end. +name({local,Name}) -> Name; +name({global,Name}) -> Name; +name(Pid) when is_pid(Pid) -> Pid. + %%----------------------------------------------------------------- %% The MAIN loop %%----------------------------------------------------------------- +loop(Parent, Name, StateName, StateData, Mod, hibernate, Debug, + Limits, Queue, QueueLen) + when QueueLen > 0 -> + case queue:out(Queue) of + {{value, Msg}, Queue1} -> + decode_msg(Msg, Parent, Name, StateName, StateData, Mod, hibernate, + Debug, Limits, Queue1, QueueLen - 1, false); + {empty, _} -> + Reason = internal_queue_error, + error_info(Reason, Name, hibernate, StateName, StateData, Debug), + exit(Reason) + end; +loop(Parent, Name, StateName, StateData, Mod, hibernate, Debug, + Limits, _Queue, _QueueLen) -> + proc_lib:hibernate(?MODULE,wake_hib, + [Parent, Name, StateName, StateData, Mod, + Debug, Limits]); %% First we test if we have reach a defined limit ... -loop(Parent, Name, StateName, StateData, Mod, Time, Debug, Limits) -> +loop(Parent, Name, StateName, StateData, Mod, Time, Debug, + Limits, Queue, QueueLen) -> try - message_queue_len(Limits) + message_queue_len(Limits, QueueLen) %% TODO: We can add more limit checking here... catch {process_limit, Limit} -> @@ -369,54 +397,89 @@ loop(Parent, Name, StateName, StateData, Mod, Time, Debug, Limits) -> terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug) end, process_message(Parent, Name, StateName, StateData, - Mod, Time, Debug, Limits). + Mod, Time, Debug, Limits, Queue, QueueLen). %% ... then we can process a new message: -process_message(Parent, Name, StateName, StateData, Mod, Time, Debug, Limits) -> +process_message(Parent, Name, StateName, StateData, Mod, Time, Debug, + Limits, Queue, QueueLen) -> + {Msg, Queue1, QueueLen1} = collect_messages(Queue, QueueLen, Time), + decode_msg(Msg,Parent, Name, StateName, StateData, Mod, Time, + Debug, Limits, Queue1, QueueLen1, false). + +collect_messages(Queue, QueueLen, Time) -> + receive + Input -> + case Input of + {'EXIT', _Parent, priority_shutdown} -> + {Input, Queue, QueueLen}; + _ -> + collect_messages( + queue:in(Input, Queue), QueueLen + 1, Time) + end + after 0 -> + case queue:out(Queue) of + {{value, Msg}, Queue1} -> + {Msg, Queue1, QueueLen - 1}; + {empty, _} -> + receive + Input -> + {Input, Queue, QueueLen} + after Time -> + {{'$gen_event', timeout}, Queue, QueueLen} + end + end + end. + + +wake_hib(Parent, Name, StateName, StateData, Mod, Debug, + Limits) -> Msg = receive - {'EXIT', Parent, priority_shutdown} -> - {'EXIT', Parent, priority_shutdown} - after 0 -> - receive - Input -> - Input - after Time -> - {'$gen_event', timeout} - end + Input -> + Input end, + Queue = queue:new(), + QueueLen = 0, + decode_msg(Msg, Parent, Name, StateName, StateData, Mod, hibernate, + Debug, Limits, Queue, QueueLen, true). + +decode_msg(Msg,Parent, Name, StateName, StateData, Mod, Time, Debug, + Limits, Queue, QueueLen, Hib) -> + put('$internal_queue_len', QueueLen), case Msg of {system, From, Req} -> sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug, [Name, StateName, StateData, - Mod, Time, Limits]); + Mod, Time, Limits, Queue, QueueLen], Hib); {'EXIT', Parent, Reason} -> terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug); _Msg when Debug == [] -> handle_msg(Msg, Parent, Name, StateName, StateData, - Mod, Time, Limits); + Mod, Time, Limits, Queue, QueueLen); _Msg -> Debug1 = sys:handle_debug(Debug, {?MODULE, print_event}, {Name, StateName}, {in, Msg}), handle_msg(Msg, Parent, Name, StateName, StateData, - Mod, Time, Debug1, Limits) + Mod, Time, Debug1, Limits, Queue, QueueLen) end. %%----------------------------------------------------------------- %% Callback functions for system messages handling. %%----------------------------------------------------------------- -%% TODO: Fix me system_continue(Parent, Debug, [Name, StateName, StateData, - Mod, Time, Limits]) -> - loop(Parent, Name, StateName, StateData, Mod, Time, Debug, Limits). + Mod, Time, Limits, Queue, QueueLen]) -> + loop(Parent, Name, StateName, StateData, Mod, Time, Debug, + Limits, Queue, QueueLen). system_terminate(Reason, _Parent, Debug, [Name, StateName, StateData, Mod, _Time, _Limits]) -> terminate(Reason, Name, [], Mod, StateName, StateData, Debug). -system_code_change([Name, StateName, StateData, Mod, Time, Limits], +system_code_change([Name, StateName, StateData, Mod, Time, + Limits, Queue, QueueLen], _Module, OldVsn, Extra) -> case catch Mod:code_change(OldVsn, StateName, StateData, Extra) of {ok, NewStateName, NewStateData} -> - {ok, [Name, NewStateName, NewStateData, Mod, Time, Limits]}; + {ok, [Name, NewStateName, NewStateData, Mod, Time, + Limits, Queue, QueueLen]}; Else -> Else end. @@ -453,24 +516,27 @@ print_event(Dev, return, {Name, StateName}) -> io:format(Dev, "*DBG* ~p switched to state ~w~n", [Name, StateName]). -handle_msg(Msg, Parent, Name, StateName, StateData, Mod, _Time, Limits) -> %No debug here +handle_msg(Msg, Parent, Name, StateName, StateData, Mod, _Time, + Limits, Queue, QueueLen) -> %No debug here From = from(Msg), case catch dispatch(Msg, Mod, StateName, StateData) of {next_state, NStateName, NStateData} -> loop(Parent, Name, NStateName, NStateData, - Mod, infinity, [], Limits); + Mod, infinity, [], Limits, Queue, QueueLen); {next_state, NStateName, NStateData, Time1} -> - loop(Parent, Name, NStateName, NStateData, Mod, Time1, [], Limits); - {reply, Reply, NStateName, NStateData} when From /= undefined -> + loop(Parent, Name, NStateName, NStateData, Mod, Time1, [], + Limits, Queue, QueueLen); + {reply, Reply, NStateName, NStateData} when From =/= undefined -> reply(From, Reply), loop(Parent, Name, NStateName, NStateData, - Mod, infinity, [], Limits); - {reply, Reply, NStateName, NStateData, Time1} when From /= undefined -> + Mod, infinity, [], Limits, Queue, QueueLen); + {reply, Reply, NStateName, NStateData, Time1} when From =/= undefined -> reply(From, Reply), - loop(Parent, Name, NStateName, NStateData, Mod, Time1, [], Limits); + loop(Parent, Name, NStateName, NStateData, Mod, Time1, [], + Limits, Queue, QueueLen); {stop, Reason, NStateData} -> terminate(Reason, Name, Msg, Mod, StateName, NStateData, []); - {stop, Reason, Reply, NStateData} when From /= undefined -> + {stop, Reason, Reply, NStateData} when From =/= undefined -> {'EXIT', R} = (catch terminate(Reason, Name, Msg, Mod, StateName, NStateData, [])), reply(From, Reply), @@ -483,30 +549,30 @@ handle_msg(Msg, Parent, Name, StateName, StateData, Mod, _Time, Limits) -> %No d end. handle_msg(Msg, Parent, Name, StateName, StateData, - Mod, _Time, Debug, Limits) -> + Mod, _Time, Debug, Limits, Queue, QueueLen) -> From = from(Msg), case catch dispatch(Msg, Mod, StateName, StateData) of {next_state, NStateName, NStateData} -> Debug1 = sys:handle_debug(Debug, {?MODULE, print_event}, {Name, NStateName}, return), loop(Parent, Name, NStateName, NStateData, - Mod, infinity, Debug1, Limits); + Mod, infinity, Debug1, Limits, Queue, QueueLen); {next_state, NStateName, NStateData, Time1} -> Debug1 = sys:handle_debug(Debug, {?MODULE, print_event}, {Name, NStateName}, return), loop(Parent, Name, NStateName, NStateData, - Mod, Time1, Debug1, Limits); - {reply, Reply, NStateName, NStateData} when From /= undefined -> + Mod, Time1, Debug1, Limits, Queue, QueueLen); + {reply, Reply, NStateName, NStateData} when From =/= undefined -> Debug1 = reply(Name, From, Reply, Debug, NStateName), loop(Parent, Name, NStateName, NStateData, - Mod, infinity, Debug1, Limits); - {reply, Reply, NStateName, NStateData, Time1} when From /= undefined -> + Mod, infinity, Debug1, Limits, Queue, QueueLen); + {reply, Reply, NStateName, NStateData, Time1} when From =/= undefined -> Debug1 = reply(Name, From, Reply, Debug, NStateName), loop(Parent, Name, NStateName, NStateData, - Mod, Time1, Debug1, Limits); + Mod, Time1, Debug1, Limits, Queue, QueueLen); {stop, Reason, NStateData} -> terminate(Reason, Name, Msg, Mod, StateName, NStateData, Debug); - {stop, Reason, Reply, NStateData} when From /= undefined -> + {stop, Reason, Reply, NStateData} when From =/= undefined -> {'EXIT', R} = (catch terminate(Reason, Name, Msg, Mod, StateName, NStateData, Debug)), reply(Name, From, Reply, Debug, StateName), @@ -671,13 +737,13 @@ limit_options([_|Options], Limits) -> %% Throw max_queue if we have reach the max queue size %% Returns ok otherwise -message_queue_len(#limits{max_queue = undefined}) -> +message_queue_len(#limits{max_queue = undefined}, _QueueLen) -> ok; -message_queue_len(#limits{max_queue = MaxQueue}) -> +message_queue_len(#limits{max_queue = MaxQueue}, QueueLen) -> Pid = self(), case process_info(Pid, message_queue_len) of - {message_queue_len, N} when N > MaxQueue -> - throw({process_limit, {max_queue, N}}); + {message_queue_len, N} when N + QueueLen > MaxQueue -> + throw({process_limit, {max_queue, N + QueueLen}}); _ -> ok end. From 036095f37d9a11a364c7dcded93b30334f6e5b87 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 8 Oct 2009 11:33:32 +0000 Subject: [PATCH 561/582] New option added: max_fsm_queue. Removed hardcoded FSMLIMITS. (thanks to Evgeniy Khramtsov) Merged from trunk@2645 SVN Revision: 2647 --- src/ejabberd_config.erl | 2 ++ src/ejabberd_s2s_out.erl | 15 ++++++++++----- src/ejabberd_service.erl | 22 +++++++++++++++------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index eba01159f..c980da477 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -387,6 +387,8 @@ process_term(Term, State) -> {loglevel, Loglevel} -> ejabberd_loglevel:set(Loglevel), State; + {max_fsm_queue, N} -> + add_option(max_fsm_queue, N, State); {_Opt, _Val} -> lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end, State, State#state.hosts) diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 85f6a0618..cb5bcbf91 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -85,15 +85,12 @@ %% Module start with or without supervisor: -ifdef(NO_TRANSIENT_SUPERVISORS). -define(SUPERVISOR_START, p1_fsm:start(ejabberd_s2s_out, [From, Host, Type], - ?FSMLIMITS ++ ?FSMOPTS)). + fsm_limit_opts() ++ ?FSMOPTS)). -else. -define(SUPERVISOR_START, supervisor:start_child(ejabberd_s2s_out_sup, [From, Host, Type])). -endif. -%% Only change this value if you now what your are doing: --define(FSMLIMITS,[]). -%% -define(FSMLIMITS, [{max_queue, 2000}]). -define(FSMTIMEOUT, 30000). %% We do not block on send anymore. @@ -121,7 +118,7 @@ start(From, Host, Type) -> start_link(From, Host, Type) -> p1_fsm:start_link(ejabberd_s2s_out, [From, Host, Type], - ?FSMLIMITS ++ ?FSMOPTS). + fsm_limit_opts() ++ ?FSMOPTS). start_connection(Pid) -> p1_fsm:send_event(Pid, init). @@ -1147,3 +1144,11 @@ terminate_if_waiting_delay(From, To) -> Pid ! terminate_if_waiting_before_retry end, Pids). + +fsm_limit_opts() -> + case ejabberd_config:get_local_option(max_fsm_queue) of + N when is_integer(N) -> + [{max_queue, N}]; + _ -> + [] + end. diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 6379de19d..f06d7cc23 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -70,11 +70,6 @@ -define(DEFAULT_NS, ?NS_COMPONENT_ACCEPT). -define(PREFIXED_NS, [{?NS_XMPP, ?NS_XMPP_pfx}]). -%% Only change this value if you now what your are doing: --define(FSMLIMITS,[]). -%% -define(FSMLIMITS, [{max_queue, 2000}]). - - %%%---------------------------------------------------------------------- %%% API %%%---------------------------------------------------------------------- @@ -82,8 +77,8 @@ start(SockData, Opts) -> supervisor:start_child(ejabberd_service_sup, [SockData, Opts]). start_link(SockData, Opts) -> - ?GEN_FSM:start_link( - ejabberd_service, [SockData, Opts], ?FSMLIMITS ++ ?FSMOPTS). + ?GEN_FSM:start_link(ejabberd_service, [SockData, Opts], + fsm_limit_opts(Opts) ++ ?FSMOPTS). socket_type() -> xml_stream. @@ -390,3 +385,16 @@ send_element(StateData, El) -> new_id() -> randoms:get_string(). + +fsm_limit_opts(Opts) -> + case lists:keysearch(max_fsm_queue, 1, Opts) of + {value, {_, N}} when is_integer(N) -> + [{max_queue, N}]; + _ -> + case ejabberd_config:get_local_option(max_fsm_queue) of + N when is_integer(N) -> + [{max_queue, N}]; + _ -> + [] + end + end. From 2d41c81890bc44a43c9c988cc164995f48867c53 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 8 Oct 2009 14:34:32 +0000 Subject: [PATCH 562/582] Document new option max_fsm_queue. SVN Revision: 2649 --- doc/guide.html | 379 ++++++++++++++++++++++++++----------------------- doc/guide.tex | 19 ++- 2 files changed, 219 insertions(+), 179 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 25ad209d3..416bb71ce 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -103,119 +103,120 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;} 2.4.1  Requirements
  • 2.4.2  Download Source Code
  • 2.4.3  Compile -
  • 2.4.4  Install -
  • 2.4.5  Start -
  • 2.4.6  Specific Notes for BSD -
  • 2.4.7  Specific Notes for Sun Solaris -
  • 2.4.8  Specific Notes for Microsoft Windows +
  • 2.4.4  Compiling ejabberd under Snow Leopard with Erlang R13B +
  • 2.4.5  Install +
  • 2.4.6  Start +
  • 2.4.7  Specific Notes for BSD +
  • 2.4.8  Specific Notes for Sun Solaris +
  • 2.4.9  Specific Notes for Microsoft Windows
  • -
  • 2.5  Create a XMPP Account for Administration -
  • 2.6  Upgrading ejabberd +
  • 2.5  Create a XMPP Account for Administration +
  • 2.6  Upgrading ejabberd
  • -
  • Chapter 3  Configuring ejabberd +
  • Chapter 3  Configuring ejabberd -
  • Chapter 4  Managing an ejabberd Server +
  • Chapter 4  Managing an ejabberd Server -
  • Chapter 5  Securing ejabberd +
  • Chapter 5  Securing ejabberd -
  • Chapter 6  Clustering +
  • Chapter 6  Clustering -
  • Chapter 7  Debugging +
  • Chapter 7  Debugging -
  • Appendix A  Internationalization and Localization -
  • Appendix B  Release Notes -
  • Appendix C  Acknowledgements -
  • Appendix D  Copyright Information +
  • Appendix A  Internationalization and Localization +
  • Appendix B  Release Notes +
  • Appendix C  Acknowledgements +
  • Appendix D  Copyright Information
  • Chapter 1  Introduction

    ejabberd is a free and open source instant messaging server written in Erlang/OTP.

    ejabberd is cross-platform, distributed, fault-tolerant, and based on open standards to achieve real-time communication.

    ejabberd is designed to be a rock-solid and feature rich XMPP server.

    ejabberd is suitable for small deployments, whether they need to be scalable or not, as well as extremely big deployments.

    @@ -383,8 +384,15 @@ To get the full list run the command: It will for example use CDATA to escape characters in the XMPP stream. Use this option only if you are sure your XMPP clients include a fully compliant XML parser.

    --disable-transient-supervisors
    Disable the use of Erlang/OTP supervision for transient processes. -

    -

    2.4.4  Install

    +

    +

    2.4.4  Compiling ejabberd under Snow Leopard with Erlang R13B

    +

    Erl Interface, the library to link Erlang with C code, is compiled as +32-bits code in Erlang R13B-2. Mac OS X Snow Leopard is a 64-bits +system and will try compiling ejabberd C code in 64-bits as a default.

    To compile ejabberd on Mac OS X Snow Leopard with Erlang R13B-2, you +need to force C code to be compiled with 32-bits. This is done with +the following configure command:

    CC='gcc -m32' CFLAGS=-m32 LDFLAGS=-m32 ./configure
    +

    +

    2.4.5  Install

    To install ejabberd in the destination directories, run the command:

    make install
     

    Note that you probably need administrative privileges in the system @@ -420,7 +428,7 @@ to install ejabberd.

    The files and directories created are, by de

    erlang.log
    Erlang/OTP system log

    -

    2.4.5  Start

    +

    2.4.6  Start

    You can use the ejabberdctl command line administration script to start and stop ejabberd. If you provided the configure option --enable-user=USER (see 2.4.3), you can execute ejabberdctl with either that system account or root.

    Usage example: @@ -443,11 +451,11 @@ copy ejabberd.init to something like /etc/init.d/ejabberd Create a system user called ejabberd; it will be used by the script to start the server. Then you can call /etc/inid.d/ejabberd start as root to start the server.

    -

    2.4.6  Specific Notes for BSD

    +

    2.4.7  Specific Notes for BSD

    The command to compile ejabberd in BSD systems is:

    gmake
     

    -

    2.4.7  Specific Notes for Sun Solaris

    +

    2.4.8  Specific Notes for Sun Solaris

    You need to have GNU install, but it isn’t included in Solaris. It can be easily installed if your Solaris system @@ -462,7 +470,7 @@ for example:

    And finally install ejabberd with:

    gmake -f Makefile.gi ginstall
     

    -

    2.4.8  Specific Notes for Microsoft Windows

    +

    2.4.9  Specific Notes for Microsoft Windows

    Requirements

    To compile ejabberd on a Microsoft Windows system, you need:

    • @@ -494,7 +502,7 @@ nmake -f Makefile.win32
    • Edit the file ejabberd\src\ejabberd.cfg and run
      werl -s ejabberd -name ejabberd
       
    • -

      2.5  Create a XMPP Account for Administration

      You need a XMPP account and grant him administrative privileges +

      2.5  Create a XMPP Account for Administration

      You need a XMPP account and grant him administrative privileges to enter the ejabberd Web Admin:

      1. Register a XMPP account on your ejabberd server, for example admin1@example.org. @@ -515,16 +523,16 @@ favourite browser. Make sure to enter the full JID as username (in this example: admin1@example.org. The reason that you also need to enter the suffix, is because ejabberd’s virtual hosting support.

      -

      2.6  Upgrading ejabberd

      To upgrade an ejabberd installation to a new version, +

      2.6  Upgrading ejabberd

      To upgrade an ejabberd installation to a new version, simply uninstall the old version, and then install the new one. Of course, it is important that the configuration file and Mnesia database spool directory are not removed.

      ejabberd automatically updates the Mnesia table definitions at startup when needed. If you also use an external database for storage of some modules, check if the release notes of the new ejabberd version indicates you need to also update those tables.

      -

      Chapter 3  Configuring ejabberd

      +

      Chapter 3  Configuring ejabberd

      -

      3.1  Basic Configuration

      The configuration file will be loaded the first time you start ejabberd. The +

      3.1  Basic Configuration

      The configuration file will be loaded the first time you start ejabberd. The content from this file will be parsed and stored in the internal ejabberd database. Subsequently the configuration will be loaded from the database and any commands in the configuration file are appended to the entries in the database.

      Note that ejabberd never edits the configuration file. @@ -543,7 +551,7 @@ override_acls.

      With these lines the old global options (shared between all ejabberd nodes in a cluster), local options (which are specific for this particular ejabberd node) and ACLs will be removed before new ones are added.

      -

      3.1.1  Host Names

      +

      3.1.1  Host Names

      The option hosts defines a list containing one or more domains that ejabberd will serve.

      The syntax is:

      {hosts, [HostName, ...]}.

      Examples: @@ -553,7 +561,7 @@ Serving one domain:

    • Serving three domains:
      {hosts, ["example.net", "example.com", "jabber.somesite.org"]}.
       

    -

    3.1.2  Virtual Hosting

    +

    3.1.2  Virtual Hosting

    Options can be defined separately for every virtual host using the host_config option.

    The syntax is:

    {host_config, HostName, [Option, ...]}

    Examples: @@ -622,7 +630,7 @@ other different modules for some specific virtual hosts: } ]}.

    -

    3.1.3  Listening Ports

    +

    3.1.3  Listening Ports

    The option listen defines for which ports, addresses and network protocols ejabberd will listen and what services will be run on them. Each element of the list is a tuple with the following elements: @@ -667,7 +675,7 @@ Handles incoming s2s connections.

    ejabberd_service
    Interacts with an external component (as defined in the Jabber Component Protocol (XEP-0114).
    - Options: access, hosts, + Options: access, hosts, max_fsm_queue, shaper, service_check_from
    ejabberd_stun
    Handles STUN Binding requests as defined in @@ -722,7 +730,16 @@ interesting to host a web-based XMPP client such as an incoming POST request can be configured with the global option http_poll_timeout. The default value is five minutes. The option can be defined in ejabberd.cfg, expressing the time -in seconds: {http_poll_timeout, 300}.

    {max_stanza_size, Size}
    +in seconds: {http_poll_timeout, 300}. +

    {max_fsm_queue, Size}
    +This option specifies the maximum number of elements in the queue of the FSM. +This option can be specified for an ejabberd_service listener, +or also globally for ejabberd_s2s_out. +If the option is not specified for an ejabberd_service listener, +the globally configured value is used. +The allowed values are integers and ’undefined’. +Default value: ’undefined’. +
    {max_stanza_size, Size}
    This option specifies an approximate maximum size in bytes of XML stanzas. Approximate, because it is calculated with the precision of one block of readed @@ -797,6 +814,14 @@ with a small list of trusted servers, or to block some specific servers.
    {s2s_max_retry_delay, Seconds}
    The maximum allowed delay for retry to connect after a failed connection attempt. Specified in seconds. The default value is 300 seconds (5 minutes). +
    {max_fsm_queue, Size}
    +This option specifies the maximum number of elements in the queue of the FSM. +This option can be specified for an ejabberd_service listener, +or also globally for ejabberd_s2s_out. +If the option is not specified for an ejabberd_service listener, +the globally configured value is used. +The allowed values are integers and ’undefined’. +Default value: ’undefined’.

    Examples

    For example, the following simple configuration defines:

    • @@ -963,7 +988,7 @@ you have to make the transports log and do XDB by themselves: </xdb_file> </xdb>

      -

      3.1.4  Authentication

      +

      3.1.4  Authentication

      The option auth_method defines the authentication methods that are used for user authentication. The syntax is:

      {auth_method, [Method, ...]}.

      The following authentication methods are supported by ejabberd: @@ -1073,7 +1098,7 @@ module provides such functionality.

    • If you use pam_winbind to authorise against a Windows Active Directory, then /etc/nssswitch.conf must be configured to use winbind as well.

    -

    3.1.5  Access Rules

    +

    3.1.5  Access Rules

    ACL Definition

    Access control in ejabberd is performed via Access Control Lists (ACLs). The @@ -1171,7 +1196,7 @@ There’s also available the access max_s2s_connections_per_node.< Allow up to 3 connections with each remote server:

    {access, max_s2s_connections, [{3, all}]}.
     

    -

    3.1.6  Shapers

    +

    3.1.6  Shapers

    Shapers enable you to limit connection traffic. The syntax is:

    {shaper, ShaperName, Kind}.

    @@ -1190,7 +1215,7 @@ To define a shaper named ‘normal’ with traffic speed limi 50,000 bytes/second:

    {shaper, fast, {maxrate, 50000}}.
     

    -

    3.1.7  Default Language

    +

    3.1.7  Default Language

    The option language defines the default language of server strings that can be seen by XMPP clients. If a XMPP client does not support xml:lang, the specified language is used.

    The option syntax is: @@ -1199,7 +1224,7 @@ In order to take effect there must be a translation file Language.msg in ejabberd’s msgs directory.

    For example, to set Russian as default language:

    {language, "ru"}.
     

    Appendix A provides more details about internationalization and localization.

    -

    3.1.8  CAPTCHA

    +

    3.1.8  CAPTCHA

    Some ejabberd modules can be configured to require a CAPTCHA challenge on certain actions. If the client does not support CAPTCHA Forms (XEP-0158), a web link is provided so the user can fill the challenge in a web browser.

    An example script is provided that generates the image @@ -1231,7 +1256,7 @@ See section 3.1.3.

    Example configuration: ]}.

    -

    3.1.9  STUN

    +

    3.1.9  STUN

    ejabberd is able to act as a stand-alone STUN server (RFC 5389). Currently only Binding usage is supported. In that role ejabberd helps clients with Jingle ICE (XEP-0176) support to discover their external addresses and ports.

    You should configure ejabberd_stun listening module as described in 3.1.3 section. @@ -1258,7 +1283,7 @@ of RFC 5389 for details.

    _stun._tcp IN SRV 0 0 3478 stun.example.com. _stuns._tcp IN SRV 0 0 5349 stun.example.com.

    -

    3.1.10  Include Additional Configuration Files

    +

    3.1.10  Include Additional Configuration Files

    The option include_config_file in a configuration file instructs ejabberd to include other configuration files immediately.

    The basic syntax is:

    {include_config_file, Filename}.

    It is possible to specify suboptions using the full syntax: @@ -1288,7 +1313,7 @@ and later includes another file with additional rules:

    {acl, admin, {user, "bob", "localhost"}}.
     {acl, admin, {user, "jan", "localhost"}}.
     

    -

    3.1.11  Option Macros in Configuration File

    +

    3.1.11  Option Macros in Configuration File

    In the ejabberd configuration file, it is possible to define a macro for a value and later use this macro when defining an option.

    A macro is defined with this syntax: @@ -1337,7 +1362,7 @@ This usage behaves as if it were defined and used this way: ] }.

    -

    3.2  Database and LDAP Configuration

    +

    3.2  Database and LDAP Configuration

    ejabberd uses its internal Mnesia database by default. However, it is possible to use a relational database or an LDAP server to store persistent, @@ -1370,7 +1395,7 @@ For example: {auth_method, [odbc]} ]}.

    -

    3.2.1  MySQL

    +

    3.2.1  MySQL

    Although this section will describe ejabberd’s configuration when you want to use the native MySQL driver, it does not describe MySQL’s installation and database creation. Check the MySQL documentation and the tutorial Using ejabberd with MySQL native driver for information regarding these topics. @@ -1427,7 +1452,7 @@ relational databases like MySQL. To enable storage to your database, just make sure that your database is running well (see previous sections), and replace the suffix-less or ldap module variant with the odbc module variant. Keep in mind that you cannot have several variants of the same module loaded!

    -

    3.2.2  Microsoft SQL Server

    +

    3.2.2  Microsoft SQL Server

    Although this section will describe ejabberd’s configuration when you want to use Microsoft SQL Server, it does not describe Microsoft SQL Server’s installation and database creation. Check the MySQL documentation and the @@ -1465,7 +1490,7 @@ database, just make sure that your database is running well (see previous sections), and replace the suffix-less or ldap module variant with the odbc module variant. Keep in mind that you cannot have several variants of the same module loaded!

    -

    3.2.3  PostgreSQL

    +

    3.2.3  PostgreSQL

    Although this section will describe ejabberd’s configuration when you want to use the native PostgreSQL driver, it does not describe PostgreSQL’s installation and database creation. Check the PostgreSQL documentation and the tutorial Using ejabberd with MySQL native driver for information regarding these topics. @@ -1522,7 +1547,7 @@ relational databases like PostgreSQL. To enable storage to your database, just make sure that your database is running well (see previous sections), and replace the suffix-less or ldap module variant with the odbc module variant. Keep in mind that you cannot have several variants of the same module loaded!

    -

    3.2.4  ODBC Compatible

    +

    3.2.4  ODBC Compatible

    Although this section will describe ejabberd’s configuration when you want to use the ODBC driver, it does not describe the installation and database creation of your database. Check the documentation of your database. The tutorial Using ejabberd with MySQL native driver also can help you. Note that the tutorial @@ -1567,7 +1592,7 @@ database, just make sure that your database is running well (see previous sections), and replace the suffix-less or ldap module variant with the odbc module variant. Keep in mind that you cannot have several variants of the same module loaded!

    -

    3.2.5  LDAP

    +

    3.2.5  LDAP

    ejabberd has built-in LDAP support. You can authenticate users against LDAP server and use LDAP directory as vCard storage. Shared rosters are not supported yet.

    Note that ejabberd treats LDAP as a read-only storage: @@ -1753,7 +1778,7 @@ configuration is shown below:

    {auth_method, ldap}.
       ...
      ]}.
     

    -

    3.3  Modules Configuration

    +

    3.3  Modules Configuration

    The option modules defines the list of modules that will be loaded after ejabberd’s startup. Each entry in the list is a tuple in which the first element is the name of a module and the second is a list of options for that @@ -1776,7 +1801,7 @@ all entries end with a comma: {mod_version, []} ]}.

    -

    3.3.1  Modules Overview

    +

    3.3.1  Modules Overview

    The following table lists all modules included in ejabberd.


    @@ -1838,7 +1863,7 @@ Last connection date and time: Use mod_last_odbc instead of ejabberd website. Please remember that these contributions might not work or that they can contain severe bugs and security leaks. Therefore, use them at your own risk!

    -

    3.3.2  Common Options

    The following options are used by many modules. Therefore, they are described in +

    3.3.2  Common Options

    The following options are used by many modules. Therefore, they are described in this separate section.

    iqdisc

    Many modules define handlers for processing IQ queries of different namespaces @@ -1892,7 +1917,7 @@ the "@HOST@" keyword must be used: ... ]}.

    -

    3.3.3  mod_announce

    +

    3.3.3  mod_announce

    This module enables configured users to broadcast announcements and to set the message of the day (MOTD). Configured users can perform these actions with a @@ -1956,7 +1981,7 @@ Only administrators can send announcements:

    Note that mod_announce can be resource intensive on large deployments as it can broadcast lot of messages. This module should be disabled for instances of ejabberd with hundreds of thousands users.

    -

    3.3.4  mod_disco

    +

    3.3.4  mod_disco

    @@ -2030,7 +2055,7 @@ and admin addresses for both the main server and the vJUD service: ... ]}.

    -

    3.3.5  mod_echo

    +

    3.3.5  mod_echo

    This module simply echoes any XMPP packet back to the sender. This mirror can be of interest for ejabberd and XMPP client debugging.

    Options: @@ -2050,7 +2075,7 @@ of them all? ... ]}.

    -

    3.3.6  mod_http_bind

    +

    3.3.6  mod_http_bind

    This module implements XMPP over Bosh (formerly known as HTTP Binding) as defined in XEP-0124 and XEP-0206. It extends ejabberd’s built in HTTP service with a configurable @@ -2103,7 +2128,7 @@ For example, to set 50 seconds: ... ]}.

    -

    3.3.7  mod_http_fileserver

    +

    3.3.7  mod_http_fileserver

    This simple module serves files from the local disk over HTTP.

    Options:

    {docroot, Path}
    @@ -2163,7 +2188,7 @@ To use this module you must enable it: ... ]}.

    -

    3.3.8  mod_last

    +

    3.3.8  mod_last

    This module adds support for Last Activity (XEP-0012). It can be used to discover when a disconnected user last accessed the server, to know when a connected user was last active on the server, or to query the uptime of the @@ -2172,7 +2197,7 @@ connected user was last active on the server, or to query the uptime of the {iqdisc, Discipline}

    This specifies the processing discipline for Last activity (jabber:iq:last) IQ queries (see section 3.3.2).

    -

    3.3.9  mod_muc

    +

    3.3.9  mod_muc

    This module provides a Multi-User Chat (XEP-0045) service. Users can discover existing rooms, join or create them. Occupants of a room can chat in public or have private chats.

    Some of the features of Multi-User Chat: @@ -2395,7 +2420,7 @@ the newly created rooms have by default those options. ... ]}.

    -

    3.3.10  mod_muc_log

    +

    3.3.10  mod_muc_log

    This module enables optional logging of Multi-User Chat (MUC) public conversations to HTML. Once you enable this module, users can join a room using a MUC capable XMPP client, and if they have enough privileges, they can request the @@ -2514,7 +2539,7 @@ top link will be the default <a href="/">Home</a>. ... ]}.

    -

    3.3.11  mod_offline

    +

    3.3.11  mod_offline

    This module implements offline message storage (XEP-0160). This means that all messages sent to an offline user will be stored on the server until that user comes @@ -2546,7 +2571,7 @@ and all the other users up to 100. ... ]}.

    -

    3.3.12  mod_ping

    +

    3.3.12  mod_ping

    This module implements support for XMPP Ping (XEP-0199) and periodic keepalives. When this module is enabled ejabberd responds correctly to ping requests, as defined in the protocol.

    Configuration options: @@ -2574,7 +2599,7 @@ and if a client does not answer to the ping in less than 32 seconds, its connect ... ]}.

    -

    3.3.13  mod_privacy

    +

    3.3.13  mod_privacy

    This module implements Blocking Communication (also known as Privacy Rules) as defined in section 10 from XMPP IM. If end users have support for it in their XMPP client, they will be able to: @@ -2602,7 +2627,7 @@ subscription type (or globally). {iqdisc, Discipline}

    This specifies the processing discipline for Blocking Communication (jabber:iq:privacy) IQ queries (see section 3.3.2).

    -

    3.3.14  mod_private

    +

    3.3.14  mod_private

    This module adds support for Private XML Storage (XEP-0049):

    Using this method, XMPP entities can store private data on the server and @@ -2614,7 +2639,7 @@ of client-specific preferences; another is Bookmark Storage ( This specifies the processing discipline for Private XML Storage (jabber:iq:private) IQ queries (see section 3.3.2).

    -

    3.3.15  mod_proxy65

    +

    3.3.15  mod_proxy65

    This module implements SOCKS5 Bytestreams (XEP-0065). It allows ejabberd to act as a file transfer proxy between two XMPP clients.

    Options: @@ -2672,7 +2697,7 @@ The simpliest configuration of the module: ... ]}.

    -

    3.3.16  mod_pubsub

    +

    3.3.16  mod_pubsub

    This module offers a Publish-Subscribe Service (XEP-0060). The functionality in mod_pubsub can be extended using plugins. The plugin that implements PEP (Personal Eventing via Pubsub) (XEP-0163) @@ -2721,7 +2746,7 @@ The following example will use node_tune instead of node_pep for every PEP node ... ]}.

    -

    3.3.17  mod_register

    +

    3.3.17  mod_register

    This module adds support for In-Band Registration (XEP-0077). This protocol enables end users to use a XMPP client to:

    • @@ -2800,7 +2825,7 @@ Also define a registration timeout of one hour: ... ]}.

    -

    3.3.18  mod_roster

    +

    3.3.18  mod_roster

    This module implements roster management as defined in RFC 3921: XMPP IM. It also supports Roster Versioning (XEP-0237).

    Options: @@ -2826,7 +2851,7 @@ Important: if you use mod_shared_roster, you must disable this option. ... ]}.

    -

    3.3.19  mod_service_log

    +

    3.3.19  mod_service_log

    This module adds support for logging end user packets via a XMPP message auditing service such as Bandersnatch. All user @@ -2856,7 +2881,7 @@ To log all end user packets to the Bandersnatch service running on ... ]}.

    -

    3.3.20  mod_shared_roster

    +

    3.3.20  mod_shared_roster

    This module enables you to create shared roster groups. This means that you can create groups of people that can see members from (other) groups in their rosters. The big advantages of this feature are that end users do not need to @@ -2931,7 +2956,7 @@ roster groups as shown in the following table:

    ModuleFeatureDependencies
    mod_adhocAd-Hoc Commands (XEP-0050) 

    -

    3.3.21  mod_stats

    +

    3.3.21  mod_stats

    This module adds support for Statistics Gathering (XEP-0039). This protocol allows you to retrieve next statistics from your ejabberd deployment:

    • @@ -2963,14 +2988,14 @@ by sending: </query> </iq>

    -

    3.3.22  mod_time

    +

    3.3.22  mod_time

    This module features support for Entity Time (XEP-0202). By using this XEP, you are able to discover the time at another entity’s location.

    Options:

    {iqdisc, Discipline}
    This specifies the processing discipline for Entity Time (jabber:iq:time) IQ queries (see section 3.3.2).

    -

    3.3.23  mod_vcard

    +

    3.3.23  mod_vcard

    This module allows end users to store and retrieve their vCard, and to retrieve other users vCards, as defined in vcard-temp (XEP-0054). The module also implements an uncomplicated Jabber User Directory based on the vCards of @@ -3025,7 +3050,7 @@ and that all virtual hosts will be searched instead of only the current one: ... ]}.

    -

    3.3.24  mod_vcard_ldap

    +

    3.3.24  mod_vcard_ldap

    ejabberd can map LDAP attributes to vCard fields. This behaviour is implemented in the mod_vcard_ldap module. This module does not depend on the authentication method (see 3.2.5).

    Note that ejabberd treats LDAP as a read-only storage: @@ -3204,7 +3229,7 @@ searching his info in LDAP.

  • ldap_vcard_map
  • -

    3.3.25  mod_version

    +

    3.3.25  mod_version

    This module implements Software Version (XEP-0092). Consequently, it answers ejabberd’s version when queried.

    Options:

    @@ -3213,8 +3238,8 @@ The default value is true.
    {iqdisc, Discipline}
    This specifies the processing discipline for Software Version (jabber:iq:version) IQ queries (see section 3.3.2).

    -

    Chapter 4  Managing an ejabberd Server

    -

    4.1  ejabberdctl

    With the ejabberdctl command line administration script +

    Chapter 4  Managing an ejabberd Server

    +

    4.1  ejabberdctl

    With the ejabberdctl command line administration script you can execute ejabberdctl commands (described in the next section, 4.1.1) and also many general ejabberd commands (described in section 4.2). This means you can start, stop and perform many other administrative tasks @@ -3226,7 +3251,7 @@ and other codes may be used for specific results. This can be used by other scripts to determine automatically if a command succeeded or failed, for example using: echo $?

    -

    4.1.1  ejabberdctl Commands

    When ejabberdctl is executed without any parameter, +

    4.1.1  ejabberdctl Commands

    When ejabberdctl is executed without any parameter, it displays the available options. If there isn’t an ejabberd server running, the available parameters are:

    @@ -3262,7 +3287,7 @@ robot1 testuser1 testuser2

    -

    4.1.2  Erlang Runtime System

    ejabberd is an Erlang/OTP application that runs inside an Erlang runtime system. +

    4.1.2  Erlang Runtime System

    ejabberd is an Erlang/OTP application that runs inside an Erlang runtime system. This system is configured using environment variables and command line parameters. The ejabberdctl administration script uses many of those possibilities. You can configure some of them with the file ejabberdctl.cfg, @@ -3339,7 +3364,7 @@ not “Simple Authentication and Security Layer”.

    Note that some characters need to be escaped when used in shell scripts, for instance " and {}. You can find other options in the Erlang manual page (erl -man erl).

    -

    4.2  ejabberd Commands

    An ejabberd command is an abstract function identified by a name, +

    4.2  ejabberd Commands

    An ejabberd command is an abstract function identified by a name, with a defined number and type of calling arguments and type of result that is registered in the ejabberd_commands service. Those commands can be defined in any Erlang module and executed using any valid frontend.

    ejabberd includes a frontend to execute ejabberd commands: the script ejabberdctl. @@ -3347,7 +3372,7 @@ Other known frontends that can be installed to execute ejabberd commands in diff ejabberd_xmlrpc (XML-RPC service), mod_rest (HTTP POST service), mod_shcommands (ejabberd WebAdmin page).

    -

    4.2.1  List of ejabberd Commands

    ejabberd includes a few ejabberd Commands by default. +

    4.2.1  List of ejabberd Commands

    ejabberd includes a few ejabberd Commands by default. When more modules are installed, new commands may be available in the frontends.

    The easiest way to get a list of the available commands, and get help for them is to use the ejabberdctl script:

    $ ejabberdctl help
    @@ -3398,7 +3423,7 @@ is very high.
     
    register user host password
    Register an account in that domain with the given password.
    unregister user host
    Unregister the given account.

    -

    4.2.2  Restrict Execution with AccessCommands

    The frontends can be configured to restrict access to certain commands. +

    4.2.2  Restrict Execution with AccessCommands

    The frontends can be configured to restrict access to certain commands. In that case, authentication information must be provided. In each frontend the AccessCommands option is defined in a different place. But in all cases the option syntax is the same: @@ -3444,7 +3469,7 @@ and the provided arguments do not contradict Arguments.

    As an example to u {_bot_reg_test, [register, unregister], [{host, "test.org"}]} ]

    -

    4.3  Web Admin

    +

    4.3  Web Admin

    The ejabberd Web Admin allows to administer most of ejabberd using a web browser.

    This feature is enabled by default: a ejabberd_http listener with the option web_admin (see section 3.1.3) is included in the listening ports. Then you can open @@ -3516,13 +3541,13 @@ The file is searched by default in The directory of the documentation can be specified in the environment variable EJABBERD_DOC_PATH. See section 4.1.2.

    -

    4.4  Ad-hoc Commands

    If you enable mod_configure and mod_adhoc, +

    4.4  Ad-hoc Commands

    If you enable mod_configure and mod_adhoc, you can perform several administrative tasks in ejabberd with a XMPP client. The client must support Ad-Hoc Commands (XEP-0050), and you must login in the XMPP server with an account with proper privileges.

    -

    4.5  Change Computer Hostname

    ejabberd uses the distributed Mnesia database. +

    4.5  Change Computer Hostname

    ejabberd uses the distributed Mnesia database. Being distributed, Mnesia enforces consistency of its file, so it stores the name of the Erlang node in it (see section 5.4). The name of an Erlang node includes the hostname of the computer. @@ -3559,8 +3584,8 @@ mv /var/lib/ejabberd/*.* /var/lib/ejabberd/oldfiles/

  • Check that the information of the old database is available: accounts, rosters... After you finish, remember to delete the temporary backup files from public directories.
  • -

    Chapter 5  Securing ejabberd

    -

    5.1  Firewall Settings

    +

    Chapter 5  Securing ejabberd

    +

    5.1  Firewall Settings

    You need to take the following TCP ports in mind when configuring your firewall:


    @@ -3571,7 +3596,7 @@ After you finish, remember to delete the temporary backup files from public dire
    PortDescription
    port rangeUsed for connections between Erlang nodes. This range is configurable (see section 5.2).

    -

    5.2  epmd

    epmd (Erlang Port Mapper Daemon) +

    5.2  epmd

    epmd (Erlang Port Mapper Daemon) is a small name server included in Erlang/OTP and used by Erlang programs when establishing distributed Erlang communications. ejabberd needs epmd to use ejabberdctl and also when clustering ejabberd nodes. @@ -3596,7 +3621,7 @@ but can be configured in the file ejabberdctl.cfg. The Erlang command-line parameter used internally is, for example:

    erl ... -kernel inet_dist_listen_min 4370 inet_dist_listen_max 4375
     

    -

    5.3  Erlang Cookie

    The Erlang cookie is a string with numbers and letters. +

    5.3  Erlang Cookie

    The Erlang cookie is a string with numbers and letters. An Erlang node reads the cookie at startup from the command-line parameter -setcookie. If not indicated, the cookie is read from the cookie file $HOME/.erlang.cookie. If this file does not exist, it is created immediately with a random cookie. @@ -3610,7 +3635,7 @@ to prevent unauthorized access or intrusion to an Erlang node. The communication between Erlang nodes are not encrypted, so the cookie could be read sniffing the traffic on the network. The recommended way to secure the Erlang node is to block the port 4369.

    -

    5.4  Erlang Node Name

    An Erlang node may have a node name. +

    5.4  Erlang Node Name

    An Erlang node may have a node name. The name can be short (if indicated with the command-line parameter -sname) or long (if indicated with the parameter -name). Starting an Erlang node with -sname limits the communication between Erlang nodes to the LAN.

    Using the option -sname instead of -name is a simple method @@ -3619,7 +3644,7 @@ However, it is not ultimately effective to prevent access to the Erlang node, because it may be possible to fake the fact that you are on another network using a modified version of Erlang epmd. The recommended way to secure the Erlang node is to block the port 4369.

    -

    5.5  Securing Sensible Files

    ejabberd stores sensible data in the file system either in plain text or binary files. +

    5.5  Securing Sensible Files

    ejabberd stores sensible data in the file system either in plain text or binary files. The file system permissions should be set to only allow the proper user to read, write and execute those files and directories.

    ejabberd configuration file: /etc/ejabberd/ejabberd.cfg
    @@ -3639,9 +3664,9 @@ so it is preferable to secure the whole /var/lib/ejabberd/ directory.
    Erlang cookie file: /var/lib/ejabberd/.erlang.cookie
    See section 5.3.

    -

    Chapter 6  Clustering

    +

    Chapter 6  Clustering

    -

    6.1  How it Works

    +

    6.1  How it Works

    A XMPP domain is served by one or more ejabberd nodes. These nodes can be run on different machines that are connected via a network. They all must have the ability to connect to port 4369 of all another nodes, and must @@ -3655,29 +3680,29 @@ router,

  • session manager,
  • s2s manager.
  • -

    6.1.1  Router

    +

    6.1.1  Router

    This module is the main router of XMPP packets on each node. It routes them based on their destination’s domains. It uses a global routing table. The domain of the packet’s destination is searched in the routing table, and if it is found, the packet is routed to the appropriate process. If not, it is sent to the s2s manager.

    -

    6.1.2  Local Router

    +

    6.1.2  Local Router

    This module routes packets which have a destination domain equal to one of this server’s host names. If the destination JID has a non-empty user part, it is routed to the session manager, otherwise it is processed depending on its content.

    -

    6.1.3  Session Manager

    +

    6.1.3  Session Manager

    This module routes packets to local users. It looks up to which user resource a packet must be sent via a presence table. Then the packet is either routed to the appropriate c2s process, or stored in offline storage, or bounced back.

    -

    6.1.4  s2s Manager

    +

    6.1.4  s2s Manager

    This module routes packets to other XMPP servers. First, it checks if an opened s2s connection from the domain of the packet’s source to the domain of the packet’s destination exists. If that is the case, the s2s manager routes the packet to the process serving this connection, otherwise a new connection is opened.

    -

    6.2  Clustering Setup

    +

    6.2  Clustering Setup

    Suppose you already configured ejabberd on one machine named (first), and you need to setup another one to make an ejabberd cluster. Then do following steps:

    1. @@ -3715,10 +3740,10 @@ and ‘access’ options because they will be taken from enabled only on one machine in the cluster.

    You can repeat these steps for other machines supposed to serve this domain.

    -

    6.3  Service Load-Balancing

    +

    6.3  Service Load-Balancing

    -

    6.3.1  Components Load-Balancing

    -

    6.3.2  Domain Load-Balancing Algorithm

    +

    6.3.1  Components Load-Balancing

    +

    6.3.2  Domain Load-Balancing Algorithm

    ejabberd includes an algorithm to load balance the components that are plugged on an ejabberd cluster. It means that you can plug one or several instances of the same component on each ejabberd cluster and that the traffic will be automatically distributed.

    The default distribution algorithm try to deliver to a local instance of a component. If several local instances are available, one instance is chosen randomly. If no instance is available locally, one instance is chosen randomly among the remote component instances.

    If you need a different behaviour, you can change the load balancing behaviour with the option domain_balancing. The syntax of the option is the following:

    {domain_balancing, "component.example.com", BalancingCriteria}.

    Several balancing criteria are available:

    • @@ -3727,12 +3752,12 @@ domain.

      -

      6.3.3  Load-Balancing Buckets

      +

      6.3.3  Load-Balancing Buckets

      When there is a risk of failure for a given component, domain balancing can cause service trouble. If one component is failing the service will not work correctly unless the sessions are rebalanced.

      In this case, it is best to limit the problem to the sessions handled by the failing component. This is what the domain_balancing_component_number option does, making the load balancing algorithm not dynamic, but sticky on a fix number of component instances.

      The syntax is:

      {domain_balancing_component_number, "component.example.com", Number}.

      -

      Chapter 7  Debugging

      +

      Chapter 7  Debugging

      -

      7.1  Log Files

      An ejabberd node writes two log files: +

      7.1  Log Files

      An ejabberd node writes two log files:

      ejabberd.log
      is the ejabberd service log, with the messages reported by ejabberd code
      erlang.log
      is the Erlang/OTP system log, with the messages reported by Erlang/OTP using SASL (System Architecture Support Libraries) @@ -3754,12 +3779,12 @@ The ejabberdctl command reopen-log (please refer to section 4.1.1) reopens the log files, and also renames the old ones if you didn’t rename them.

      -

      7.2  Debug Console

      The Debug Console is an Erlang shell attached to an already running ejabberd server. +

      7.2  Debug Console

      The Debug Console is an Erlang shell attached to an already running ejabberd server. With this Erlang shell, an experienced administrator can perform complex tasks.

      This shell gives complete control over the ejabberd server, so it is important to use it with extremely care. There are some simple and safe examples in the article Interconnecting Erlang Nodes

      To exit the shell, close the window or press the keys: control+c control+c.

      -

      7.3  Watchdog Alerts

      +

      7.3  Watchdog Alerts

      ejabberd includes a watchdog mechanism that may be useful to developers when troubleshooting a problem related to memory usage. If a process in the ejabberd server consumes more memory than the configured threshold, @@ -3779,7 +3804,7 @@ or in a conversation with the watchdog alert bot.

      The syntax is: To remove all watchdog admins, set the option with an empty list:

      {watchdog_admins, []}.
       

      -

      Appendix A  Internationalization and Localization

      +

      Appendix A  Internationalization and Localization

      The source code of ejabberd supports localization. The translators can edit the gettext .po files @@ -3814,9 +3839,9 @@ HTTP header ‘Accept-Language: ru’


      -

      Appendix B  Release Notes

      +

      Appendix B  Release Notes

      Release notes are available from ejabberd Home Page

      -

      Appendix C  Acknowledgements

      Thanks to all people who contributed to this guide: +

      Appendix C  Acknowledgements

      Thanks to all people who contributed to this guide:

      -

      Appendix D  Copyright Information

      Ejabberd Installation and Operation Guide.
      +

      Appendix D  Copyright Information

      Ejabberd Installation and Operation Guide.
      Copyright © 2003 — 2009 ProcessOne

      This document 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 diff --git a/doc/guide.tex b/doc/guide.tex index 5f9755b84..a720d7231 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -804,7 +804,7 @@ The available modules, their purpose and the options allowed by each one are: \titem{\texttt{ejabberd\_service}} Interacts with an \footahref{http://www.ejabberd.im/tutorials-transports}{external component} (as defined in the Jabber Component Protocol (\xepref{0114}).\\ - Options: \texttt{access}, \texttt{hosts}, + Options: \texttt{access}, \texttt{hosts}, \texttt{max\_fsm\_queue}, \texttt{shaper}, \texttt{service\_check\_from} \titem{\texttt{ejabberd\_stun}} Handles STUN Binding requests as defined in @@ -872,7 +872,14 @@ This is a detailed description of each option allowed by the listening modules: \term{http\_poll\_timeout}. The default value is five minutes. The option can be defined in \term{ejabberd.cfg}, expressing the time in seconds: \verb|{http_poll_timeout, 300}.| - + \titem{\{max\_fsm\_queue, Size\}} + This option specifies the maximum number of elements in the queue of the FSM. + This option can be specified for an \term{ejabberd\_service} listener, + or also globally for \term{ejabberd\_s2s\_out}. + If the option is not specified for an \term{ejabberd\_service} listener, + the globally configured value is used. + The allowed values are integers and 'undefined'. + Default value: 'undefined'. \titem{\{max\_stanza\_size, Size\}} \ind{options!max\_stanza\_size}This option specifies an approximate maximum size in bytes of XML stanzas. Approximate, @@ -950,6 +957,14 @@ There are some additional global options that can be specified in the ejabberd c \titem{\{s2s\_max\_retry\_delay, Seconds\}} \ind{options!s2s\_max\_retry\_delay} The maximum allowed delay for retry to connect after a failed connection attempt. Specified in seconds. The default value is 300 seconds (5 minutes). + \titem{\{max\_fsm\_queue, Size\}} + This option specifies the maximum number of elements in the queue of the FSM. + This option can be specified for an \term{ejabberd\_service} listener, + or also globally for \term{ejabberd\_s2s\_out}. + If the option is not specified for an \term{ejabberd\_service} listener, + the globally configured value is used. + The allowed values are integers and 'undefined'. + Default value: 'undefined'. \end{description} \makesubsubsection{listened-examples}{Examples} From 503defac737868f1ea921e84646acedd616976c7 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 9 Oct 2009 12:01:30 +0000 Subject: [PATCH 563/582] Fix regression for authorize node subscription (thanks to Brian Cully)(EJAB-1060) SVN Revision: 2652 --- src/mod_pubsub/node_hometree.erl | 3 --- src/mod_pubsub/node_hometree_odbc.erl | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index 11b076a92..53835ab39 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -313,9 +313,6 @@ subscribe_node(NodeId, Sender, Subscriber, AccessModel, (AccessModel == whitelist) and (not Whitelisted) -> %% Node has whitelist access model and entity lacks required affiliation {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; - (AccessModel == authorize) -> % TODO: to be done - %% Node has authorize access model - {error, 'forbidden'}; %%MustPay -> %% % Payment is required for a subscription %% {error, ?ERR_PAYMENT_REQUIRED}; diff --git a/src/mod_pubsub/node_hometree_odbc.erl b/src/mod_pubsub/node_hometree_odbc.erl index c3ee1cf28..acc92ab52 100644 --- a/src/mod_pubsub/node_hometree_odbc.erl +++ b/src/mod_pubsub/node_hometree_odbc.erl @@ -325,9 +325,6 @@ subscribe_node(NodeId, Sender, Subscriber, AccessModel, (AccessModel == whitelist) and (not Whitelisted) -> %% Node has whitelist access model and entity lacks required affiliation {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; - (AccessModel == authorize) -> % TODO: to be done - %% Node has authorize access model - {error, 'forbidden'}; %%MustPay -> %% % Payment is required for a subscription %% {error, ?ERR_PAYMENT_REQUIRED}; From 13a231f6fa836644054367d1018afd92fa2a9461 Mon Sep 17 00:00:00 2001 From: Badlop Date: Fri, 9 Oct 2009 12:01:43 +0000 Subject: [PATCH 564/582] Add debug message on command execution Merged from trunk@2650. SVN Revision: 2653 --- src/ejabberd_commands.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ejabberd_commands.erl b/src/ejabberd_commands.erl index db6999a02..0be1edcb6 100644 --- a/src/ejabberd_commands.erl +++ b/src/ejabberd_commands.erl @@ -311,6 +311,7 @@ execute_command(AccessCommands, Auth, Name, Arguments) -> execute_command2(Command, Arguments) -> Module = Command#ejabberd_commands.module, Function = Command#ejabberd_commands.function, + ?DEBUG("Executing command ~p:~p with Args=~p", [Module, Function, Arguments]), apply(Module, Function, Arguments). %% @spec () -> [{Tag::string(), [CommandName::string()]}] From 2042ab090dc4f6206f08260d60bc0bcd8343b836 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Mon, 12 Oct 2009 09:06:37 +0000 Subject: [PATCH 565/582] Default pubsub messages to headline if nothing is configured (thanks to Brian Cully) (EJAB-1061) SVN Revision: 2655 --- src/mod_pubsub/mod_pubsub.erl | 2 +- src/mod_pubsub/mod_pubsub_odbc.erl | 2 +- src/mod_pubsub/pubsub_odbc.patch | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 9e5f98ade..6b83e9c08 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -3095,7 +3095,7 @@ get_options_for_subs(NodeID, Subs) -> % end broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza) -> - NotificationType = get_option(NodeOptions, notification_type), + NotificationType = get_option(NodeOptions, notification_type, headline), BroadcastAll = get_option(NodeOptions, broadcast_all_resources), %% XXX this is not standard, but usefull From = service_jid(Host), Stanza = case NotificationType of diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index d8a2ea66f..cbe6b5d75 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -2926,7 +2926,7 @@ get_options_for_subs(NodeID, Subs) -> % end broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza) -> - NotificationType = get_option(NodeOptions, notification_type), + NotificationType = get_option(NodeOptions, notification_type, headline), BroadcastAll = get_option(NodeOptions, broadcast_all_resources), %% XXX this is not standard, but usefull From = service_jid(Host), Stanza = case NotificationType of diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index 49cc8405a..ad1a49153 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,5 +1,5 @@ ---- mod_pubsub.erl 2009-10-06 17:21:15.000000000 +0200 -+++ mod_pubsub_odbc.erl 2009-10-06 17:21:35.000000000 +0200 +--- mod_pubsub.erl 2009-10-12 11:05:54.000000000 +0200 ++++ mod_pubsub_odbc.erl 2009-10-12 11:06:09.000000000 +0200 @@ -45,7 +45,7 @@ %%% TODO %%% plugin: generate Reply (do not use broadcast atom anymore) From c3303ce3643c7f7242c58413bafd0e6e3295d0db Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Mon, 12 Oct 2009 10:23:51 +0000 Subject: [PATCH 566/582] return invalid-options on badly formed subscription options SVN Revision: 2657 --- src/mod_pubsub/mod_pubsub.erl | 24 +++++++---- src/mod_pubsub/mod_pubsub_odbc.erl | 24 +++++++---- src/mod_pubsub/pubsub_odbc.patch | 66 +++++++++++++++--------------- 3 files changed, 67 insertions(+), 47 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 6b83e9c08..929c393cf 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -1867,7 +1867,10 @@ delete_node(Host, Node, Owner) -> %%

    • The node does not exist.
    • %%
    subscribe_node(Host, Node, From, JID, Configuration) -> - {result, SubOpts} = pubsub_subscription:parse_options_xform(Configuration), + SubOpts = case pubsub_subscription:parse_options_xform(Configuration) of + {result, GoodSubOpts} -> GoodSubOpts; + _ -> invalid + end, Subscriber = try jlib:short_prepd_jid(exmpp_jid:parse(JID)) catch @@ -1907,8 +1910,11 @@ subscribe_node(Host, Node, From, JID, Configuration) -> %% Node does not support subscriptions {error, extended_error('feature-not-implemented', unsupported, "subscribe")}; HasOptions andalso not OptionsFeature -> - %% Node does not support subscription options - {error, extended_error('feature-not-implemented', unsupported, "subscription-options")}; + %% Node does not support subscription options + {error, extended_error('feature-not-implemented', unsupported, "subscription-options")}; + SubOpts == invalid -> + %% Passed invalit options submit form + {error, extended_error('bad-request', "invalid-options")}; true -> node_call(Type, subscribe_node, [NodeId, From, Subscriber, @@ -2557,13 +2563,15 @@ set_options(Host, Node, JID, SubID, Configuration) -> end. set_options_helper(Configuration, JID, NodeID, SubID, Type) -> + SubOpts = case pubsub_subscription:parse_options_xform(Configuration) of + {result, GoodSubOpts} -> GoodSubOpts; + _ -> invalid + end, Subscriber = try exmpp_jid:parse(JID) of - J -> jlib:short_jid(J) + J -> jlib:short_jid(J) catch - _ -> - {"", "", ""} %%pablo TODO: "" or <<>> ?. short_jid uses exmpp_jid:node/1, etc. that returns binaries + _ -> {"", "", ""} %%pablo TODO: "" or <<>> ?. short_jid uses exmpp_jid:node/1, etc. that returns binaries end, - {result, SubOpts} = pubsub_subscription:parse_options_xform(Configuration), {result, Subs} = node_call(Type, get_subscriptions, [NodeID, Subscriber]), SubIDs = lists:foldl(fun({subscribed, SID}, Acc) -> @@ -2582,6 +2590,8 @@ set_options_helper(Configuration, JID, NodeID, SubID, Type) -> write_sub(Subscriber, NodeID, SubID, SubOpts) end. +write_sub(_Subscriber, _NodeID, _SubID, invalid) -> + {error, extended_error('bad-request', "invalid-options")}; write_sub(Subscriber, NodeID, SubID, Options) -> case pubsub_subscription:set_subscription(Subscriber, NodeID, SubID, Options) of {error, notfound} -> diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index cbe6b5d75..38653579d 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -1699,7 +1699,10 @@ delete_node(Host, Node, Owner) -> %%
  • The node does not exist.
  • %% subscribe_node(Host, Node, From, JID, Configuration) -> - {result, SubOpts} = pubsub_subscription_odbc:parse_options_xform(Configuration), + SubOpts = case pubsub_subscription_odbc:parse_options_xform(Configuration) of + {result, GoodSubOpts} -> GoodSubOpts; + _ -> invalid + end, Subscriber = try jlib:short_prepd_jid(exmpp_jid:parse(JID)) catch @@ -1743,8 +1746,11 @@ subscribe_node(Host, Node, From, JID, Configuration) -> %% Node does not support subscriptions {error, extended_error('feature-not-implemented', unsupported, "subscribe")}; HasOptions andalso not OptionsFeature -> - %% Node does not support subscription options - {error, extended_error('feature-not-implemented', unsupported, "subscription-options")}; + %% Node does not support subscription options + {error, extended_error('feature-not-implemented', unsupported, "subscription-options")}; + SubOpts == invalid -> + %% Passed invalit options submit form + {error, extended_error('bad-request', "invalid-options")}; true -> node_call(Type, subscribe_node, [NodeId, From, Subscriber, @@ -2388,13 +2394,15 @@ set_options(Host, Node, JID, SubID, Configuration) -> end. set_options_helper(Configuration, JID, NodeID, SubID, Type) -> + SubOpts = case pubsub_subscription_odbc:parse_options_xform(Configuration) of + {result, GoodSubOpts} -> GoodSubOpts; + _ -> invalid + end, Subscriber = try exmpp_jid:parse(JID) of - J -> jlib:short_jid(J) + J -> jlib:short_jid(J) catch - _ -> - {"", "", ""} %%pablo TODO: "" or <<>> ?. short_jid uses exmpp_jid:node/1, etc. that returns binaries + _ -> {"", "", ""} %%pablo TODO: "" or <<>> ?. short_jid uses exmpp_jid:node/1, etc. that returns binaries end, - {result, SubOpts} = pubsub_subscription_odbc:parse_options_xform(Configuration), {result, Subs} = node_call(Type, get_subscriptions, [NodeID, Subscriber]), SubIDs = lists:foldl(fun({subscribed, SID}, Acc) -> @@ -2413,6 +2421,8 @@ set_options_helper(Configuration, JID, NodeID, SubID, Type) -> write_sub(Subscriber, NodeID, SubID, SubOpts) end. +write_sub(_Subscriber, _NodeID, _SubID, invalid) -> + {error, extended_error('bad-request', "invalid-options")}; write_sub(Subscriber, NodeID, SubID, Options) -> case pubsub_subscription_odbc:set_subscription(Subscriber, NodeID, SubID, Options) of {error, notfound} -> diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index ad1a49153..f5044d5fd 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,5 +1,5 @@ ---- mod_pubsub.erl 2009-10-12 11:05:54.000000000 +0200 -+++ mod_pubsub_odbc.erl 2009-10-12 11:06:09.000000000 +0200 +--- mod_pubsub.erl 2009-10-12 12:21:54.000000000 +0200 ++++ mod_pubsub_odbc.erl 2009-10-12 12:23:13.000000000 +0200 @@ -45,7 +45,7 @@ %%% TODO %%% plugin: generate Reply (do not use broadcast atom anymore) @@ -425,12 +425,12 @@ %%
  • The node does not exist.
  • %% subscribe_node(Host, Node, From, JID, Configuration) -> -- {result, SubOpts} = pubsub_subscription:parse_options_xform(Configuration), -+ {result, SubOpts} = pubsub_subscription_odbc:parse_options_xform(Configuration), - Subscriber = try - jlib:short_prepd_jid(exmpp_jid:parse(JID)) - catch -@@ -1875,7 +1707,7 @@ +- SubOpts = case pubsub_subscription:parse_options_xform(Configuration) of ++ SubOpts = case pubsub_subscription_odbc:parse_options_xform(Configuration) of + {result, GoodSubOpts} -> GoodSubOpts; + _ -> invalid + end, +@@ -1878,7 +1710,7 @@ {undefined, undefined, undefined} end, SubId = uniqid(), @@ -439,7 +439,7 @@ Features = features(Type), SubscribeFeature = lists:member("subscribe", Features), OptionsFeature = lists:member("subscription-options", Features), -@@ -1894,9 +1726,13 @@ +@@ -1897,9 +1729,13 @@ {"", "", ""} -> {false, false}; _ -> @@ -456,7 +456,7 @@ end end, if -@@ -2221,7 +2057,7 @@ +@@ -2227,7 +2063,7 @@ %%

    The permission are not checked in this function.

    %% @todo We probably need to check that the user doing the query has the right %% to read the items. @@ -465,7 +465,7 @@ MaxItems = if SMaxItems == "" -> get_max_items_node(Host); -@@ -2260,11 +2096,11 @@ +@@ -2266,11 +2102,11 @@ node_call(Type, get_items, [NodeId, From, AccessModel, PresenceSubscription, RosterGroup, @@ -479,7 +479,7 @@ SendItems = case ItemIDs of [] -> Items; -@@ -2277,7 +2113,7 @@ +@@ -2283,7 +2119,7 @@ %% number of items sent to MaxItems: {result, #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = nodeAttr(Node), children = @@ -488,7 +488,7 @@ Error -> Error end -@@ -2309,17 +2145,29 @@ +@@ -2315,17 +2151,29 @@ %% @doc

    Resend the items of a node to the user.

    %% @todo use cache-last-item feature send_items(Host, Node, NodeId, Type, LJID, last) -> @@ -525,7 +525,7 @@ send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of {result, []} -> -@@ -2448,29 +2296,12 @@ +@@ -2454,29 +2302,12 @@ error -> {error, 'bad-request'}; _ -> @@ -558,7 +558,7 @@ end, Entities), {result, []}; _ -> -@@ -2525,11 +2356,11 @@ +@@ -2531,11 +2362,11 @@ end. read_sub(Subscriber, Node, NodeID, SubID, Lang) -> @@ -573,24 +573,24 @@ attrs = [?XMLATTR('node', node_to_string(Node)), ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), @@ -2563,7 +2394,7 @@ - _ -> - {"", "", ""} %%pablo TODO: "" or <<>> ?. short_jid uses exmpp_jid:node/1, etc. that returns binaries - end, -- {result, SubOpts} = pubsub_subscription:parse_options_xform(Configuration), -+ {result, SubOpts} = pubsub_subscription_odbc:parse_options_xform(Configuration), - {result, Subs} = node_call(Type, get_subscriptions, - [NodeID, Subscriber]), - SubIDs = lists:foldl(fun({subscribed, SID}, Acc) -> -@@ -2583,7 +2414,7 @@ end. + set_options_helper(Configuration, JID, NodeID, SubID, Type) -> +- SubOpts = case pubsub_subscription:parse_options_xform(Configuration) of ++ SubOpts = case pubsub_subscription_odbc:parse_options_xform(Configuration) of + {result, GoodSubOpts} -> GoodSubOpts; + _ -> invalid + end, +@@ -2593,7 +2424,7 @@ + write_sub(_Subscriber, _NodeID, _SubID, invalid) -> + {error, extended_error('bad-request', "invalid-options")}; write_sub(Subscriber, NodeID, SubID, Options) -> - case pubsub_subscription:set_subscription(Subscriber, NodeID, SubID, Options) of + case pubsub_subscription_odbc:set_subscription(Subscriber, NodeID, SubID, Options) of {error, notfound} -> {error, extended_error('not-acceptable', "invalid-subid")}; {result, _} -> -@@ -2756,8 +2587,8 @@ +@@ -2766,8 +2597,8 @@ ?XMLATTR('subsription', subscription_to_string(Sub)) | nodeAttr(Node)]}]}]}, ejabberd_router ! {route, service_jid(Host), JID, Stanza} end, @@ -601,7 +601,7 @@ true -> Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> -@@ -3053,7 +2884,7 @@ +@@ -3063,7 +2894,7 @@ {Depth, [{N, get_node_subs(N)} || N <- Nodes]} end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))} end, @@ -610,7 +610,7 @@ {result, CollSubs} -> CollSubs; _ -> [] end. -@@ -3067,9 +2898,9 @@ +@@ -3077,9 +2908,9 @@ get_options_for_subs(NodeID, Subs) -> lists:foldl(fun({JID, subscribed, SubID}, Acc) -> @@ -622,7 +622,7 @@ _ -> Acc end; (_, Acc) -> -@@ -3268,6 +3099,30 @@ +@@ -3278,6 +3109,30 @@ Result end. @@ -653,7 +653,7 @@ %% @spec (Host, Options) -> MaxItems %% Host = host() %% Options = [Option] -@@ -3657,7 +3512,13 @@ +@@ -3667,7 +3522,13 @@ tree_action(Host, Function, Args) -> ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), Fun = fun() -> tree_call(Host, Function, Args) end, @@ -668,7 +668,7 @@ %% @doc

    node plugin call.

    node_call(Type, Function, Args) -> -@@ -3677,13 +3538,13 @@ +@@ -3687,13 +3548,13 @@ node_action(Host, Type, Function, Args) -> ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), @@ -684,7 +684,7 @@ case tree_call(Host, get_node, [Host, Node]) of N when is_record(N, pubsub_node) -> case Action(N) of -@@ -3696,8 +3557,15 @@ +@@ -3706,8 +3567,15 @@ end end, Trans). @@ -702,7 +702,7 @@ {result, Result} -> {result, Result}; {error, Error} -> {error, Error}; {atomic, {result, Result}} -> {result, Result}; -@@ -3705,6 +3573,15 @@ +@@ -3715,6 +3583,15 @@ {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), {error, 'internal-server-error'}; @@ -718,7 +718,7 @@ {'EXIT', Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), {error, 'internal-server-error'}; -@@ -3713,6 +3590,16 @@ +@@ -3723,6 +3600,16 @@ {error, 'internal-server-error'} end. From 74cd5ffb024315c0dda5e7680ff28618dbd147f5 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 12 Oct 2009 12:59:07 +0000 Subject: [PATCH 567/582] Autodetect compilation parameters for Mac OS X Snow Leopard (EJAB-1056) SVN Revision: 2659 --- src/config.guess | 1533 +++++++++++++++++++++++++++++++++++++++++ src/config.sub | 1693 ++++++++++++++++++++++++++++++++++++++++++++++ src/configure | 357 +++++++++- src/configure.ac | 27 + src/install-sh | 520 ++++++++++++++ 5 files changed, 4129 insertions(+), 1 deletion(-) create mode 100644 src/config.guess create mode 100644 src/config.sub create mode 100644 src/install-sh diff --git a/src/config.guess b/src/config.guess new file mode 100644 index 000000000..e3a2116a7 --- /dev/null +++ b/src/config.guess @@ -0,0 +1,1533 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-06-10' + +# This file 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. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:[3456]*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T | authenticamd | genuineintel) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/src/config.sub b/src/config.sub new file mode 100644 index 000000000..eb0389a69 --- /dev/null +++ b/src/config.sub @@ -0,0 +1,1693 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-06-11' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/src/configure b/src/configure index 2c0d75ea6..02530cb4c 100755 --- a/src/configure +++ b/src/configure @@ -592,6 +592,19 @@ ac_includes_default="\ #endif" ac_subst_vars='LTLIBOBJS +ERLCFLAGS +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build INSTALLUSER SSL_CFLAGS SSL_LIBS @@ -708,7 +721,9 @@ CFLAGS LDFLAGS LIBS CPPFLAGS -CPP' +CPP +ERLC +ERLCFLAGS' # Initialize some variables set by options. @@ -1306,6 +1321,11 @@ Fine tuning of the installation directories: _ACEOF cat <<\_ACEOF + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi @@ -1361,6 +1381,8 @@ Some influential environment variables: CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor + ERLC Erlang/OTP compiler command [autodetected] + ERLCFLAGS Erlang/OTP compiler flags [none] Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. @@ -1728,6 +1750,48 @@ fi return $ac_retval } # ac_fn_c_try_link + +# ac_fn_erl_try_run LINENO +# ------------------------ +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_erl_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_erl_try_run cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. @@ -4426,6 +4490,297 @@ if test "$ENABLEUSER" != ""; then fi +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + for ac_t in install-sh install.sh shtool; do + if test -f "$ac_dir/$ac_t"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/$ac_t -c" + break 2 + fi + done +done +if test -z "$ac_aux_dir"; then + as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if test "${ac_cv_build+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if test "${ac_cv_host+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +$as_echo_n "checking target system type... " >&6; } +if test "${ac_cv_target+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +$as_echo "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +#AC_DEFINE_UNQUOTED(CPU_VENDOR_OS, "$target") +#AC_SUBST(target_os) + + +case "$target_os" in + *darwin10*) + echo "Target OS is 'Darwin10'" + ac_ext=erl +ac_compile='$ERLC $ERLCFLAGS -b beam conftest.$ac_ext >&5' +ac_link='$ERLC $ERLCFLAGS -b beam conftest.$ac_ext >&5 ; echo "#!/bin/sh" > conftest$ac_exeext ; $as_echo "\"$ERL\" -run conftest start -run init stop -noshell" >> conftest$ac_exeext ; chmod +x conftest$ac_exeext' + + if test -n "$ERLC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for erlc" >&5 +$as_echo_n "checking for erlc... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ERLC" >&5 +$as_echo "$ERLC" >&6; } +else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}erlc", so it can be a program name with args. +set dummy ${ac_tool_prefix}erlc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_ERLC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $ERLC in + [\\/]* | ?:[\\/]*) + ac_cv_path_ERLC="$ERLC" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_ERLC="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ERLC=$ac_cv_path_ERLC +if test -n "$ERLC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ERLC" >&5 +$as_echo "$ERLC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_ERLC"; then + ac_pt_ERLC=$ERLC + # Extract the first word of "erlc", so it can be a program name with args. +set dummy erlc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_ac_pt_ERLC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $ac_pt_ERLC in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_ERLC="$ac_pt_ERLC" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_ac_pt_ERLC="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_ERLC=$ac_cv_path_ac_pt_ERLC +if test -n "$ac_pt_ERLC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_ERLC" >&5 +$as_echo "$ac_pt_ERLC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_pt_ERLC" = x; then + ERLC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + ERLC=$ac_pt_ERLC + fi +else + ERLC="$ac_cv_path_ERLC" +fi + +fi + + +if test "$cross_compiling" = yes; then : + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot run test program while cross compiling +See \`config.log' for more details." "$LINENO" 5; } +else + cat > conftest.$ac_ext <<_ACEOF +-module(conftest). +-export([start/0]). + +start() -> + halt(case erlang:system_info(wordsize) of + 8 -> 0; 4 -> 1 end) +. + +_ACEOF +if ac_fn_erl_try_run "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: found 64-bit Erlang" >&5 +$as_echo "$as_me: found 64-bit Erlang" >&6;} + CBIT=-m64 +else + { $as_echo "$as_me:${as_lineno-$LINENO}: found 32-bit Erlang" >&5 +$as_echo "$as_me: found 32-bit Erlang" >&6;} + CBIT=-m32 +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + ;; + *) + echo "Target OS is '$target_os'" + CBIT="" + ;; +esac +CFLAGS="$CFLAGS $CBIT" +LD_SHARED="$LD_SHARED $CBIT" +echo "CBIT is set to '$CBIT'" + cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure diff --git a/src/configure.ac b/src/configure.ac index 7d8f5a85e..44cf75185 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -132,4 +132,31 @@ if test "$ENABLEUSER" != ""; then AC_SUBST([INSTALLUSER], [$ENABLEUSER]) fi +AC_CANONICAL_SYSTEM +#AC_DEFINE_UNQUOTED(CPU_VENDOR_OS, "$target") +#AC_SUBST(target_os) + + +case "$target_os" in + *darwin10*) + echo "Target OS is 'Darwin10'" + AC_LANG(Erlang) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([],[dnl + halt(case erlang:system_info(wordsize) of + 8 -> 0; 4 -> 1 end)])], + [AC_MSG_NOTICE(found 64-bit Erlang) + CBIT=-m64], + [AC_MSG_NOTICE(found 32-bit Erlang) + CBIT=-m32]) + ;; + *) + echo "Target OS is '$target_os'" + CBIT="" + ;; +esac +CFLAGS="$CFLAGS $CBIT" +LD_SHARED="$LD_SHARED $CBIT" +echo "CBIT is set to '$CBIT'" + AC_OUTPUT diff --git a/src/install-sh b/src/install-sh new file mode 100644 index 000000000..6781b987b --- /dev/null +++ b/src/install-sh @@ -0,0 +1,520 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2009-04-28.21; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + trap '(exit $?); exit' 1 2 13 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dst_arg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + -*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: From 2565a670b14723679f4e6229b7c749f7fc2de971 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Mon, 12 Oct 2009 15:25:00 +0000 Subject: [PATCH 568/582] fix get_item issue on authorize access model (thanks to brian cully) (EJAB-1060) SVN Revision: 2661 --- src/mod_pubsub/node_hometree.erl | 4 ++-- src/mod_pubsub/node_hometree_odbc.erl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index 53835ab39..d8d933e4c 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -900,7 +900,7 @@ get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) - (AccessModel == whitelist) and (not Whitelisted) -> %% Node has whitelist access model and entity lacks required affiliation {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; - (AccessModel == authorize) -> % TODO: to be done + (AccessModel == authorize) and (not Whitelisted) -> %% Node has authorize access model {error, 'forbidden'}; %%MustPay -> @@ -947,7 +947,7 @@ get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _S (AccessModel == whitelist) and (not Whitelisted) -> %% Node has whitelist access model and entity lacks required affiliation {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; - (AccessModel == authorize) -> % TODO: to be done + (AccessModel == authorize) and (not Whitelisted) -> %% Node has authorize access model {error, 'forbidden'}; %%MustPay -> diff --git a/src/mod_pubsub/node_hometree_odbc.erl b/src/mod_pubsub/node_hometree_odbc.erl index acc92ab52..74d2ffd71 100644 --- a/src/mod_pubsub/node_hometree_odbc.erl +++ b/src/mod_pubsub/node_hometree_odbc.erl @@ -1082,7 +1082,7 @@ get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId, R (AccessModel == whitelist) and (not Whitelisted) -> %% Node has whitelist access model and entity lacks required affiliation {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; - (AccessModel == authorize) -> % TODO: to be done + (AccessModel == authorize) and (not Whitelisted) -> %% Node has authorize access model {error, 'forbidden'}; %%MustPay -> @@ -1146,7 +1146,7 @@ get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _S (AccessModel == whitelist) and (not Whitelisted) -> %% Node has whitelist access model and entity lacks required affiliation {error, ?ERR_EXTENDED('not-allowed', "closed-node")}; - (AccessModel == authorize) -> % TODO: to be done + (AccessModel == authorize) and (not Whitelisted) -> %% Node has authorize access model {error, 'forbidden'}; %%MustPay -> From e5fb89731c7302cd16103ff97e9c67468b844773 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 12 Oct 2009 22:51:53 +0000 Subject: [PATCH 569/582] If s2s fails due to namespace mismatch, show differences to help debugging the problem. SVN Revision: 2663 --- src/ejabberd_s2s_out.erl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index cb5bcbf91..c5024c05d 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -285,10 +285,12 @@ wait_for_stream({xmlstreamstart, Opening}, StateData) -> {next_state, wait_for_features, StateData, ?FSMTIMEOUT}; {?NS_JABBER_SERVER, false, true} when StateData#state.use_v10 -> {next_state, wait_for_features, StateData#state{db_enabled = false}, ?FSMTIMEOUT}; - _ -> + {NSProvided, _, _} -> send_element(StateData, exmpp_stream:error('invalid-namespace')), - ?INFO_MSG("Closing s2s connection: ~s -> ~s (invalid namespace)", - [StateData#state.myname, StateData#state.server]), + ?INFO_MSG("Closing s2s connection: ~s -> ~s (invalid namespace)~n" + "Namespace provided: ~p~nNamespace expected: ~p", + [StateData#state.myname, StateData#state.server, + NSProvided, ?NS_JABBER_SERVER]), {stop, normal, StateData} end; From 861cc872725ecfab2f91d8a9b1fcb89e188bb942 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 13 Oct 2009 16:42:13 +0000 Subject: [PATCH 570/582] prevent remove_user from blocking gen_server, and allow plugin to change broadcasted payload on publish SVN Revision: 2665 --- src/mod_pubsub/mod_pubsub.erl | 98 +++++++++++++------------ src/mod_pubsub/mod_pubsub_odbc.erl | 98 +++++++++++++------------ src/mod_pubsub/pubsub_odbc.patch | 114 ++++++++++++++--------------- 3 files changed, 161 insertions(+), 149 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 929c393cf..2918ae17d 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -42,9 +42,6 @@ %%% 6.2.3.1, 6.2.3.5, and 6.3. For information on subscription leases see %%% XEP-0060 section 12.18. -%%% TODO -%%% plugin: generate Reply (do not use broadcast atom anymore) - -module(mod_pubsub). -author('christophe.romain@process-one.net'). -version('1.13-0'). @@ -793,50 +790,54 @@ handle_cast({presence, User, Server, Resources, JID}, State) -> {noreply, send_queue(State, {presence, User, Server, Resources, JID})}; handle_cast({remove_user, LUser, LServer}, State) -> - Host = State#state.host, - Owner = exmpp_jid:make(LUser, LServer), - %% remove user's subscriptions - lists:foreach(fun(PType) -> - {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Owner]), - lists:foreach(fun - ({#pubsub_node{nodeid = {H, N}}, subscribed, _, JID}) -> - unsubscribe_node(H, N, Owner, JID, all); - (_) -> - ok - end, Subscriptions), - {result, Affiliations} = node_action(Host, PType, get_entity_affiliations, [Host, Owner]), - lists:foreach(fun - ({#pubsub_node{nodeid = {H, N}}, owner}) -> - delete_node(H, N, Owner); - (_) -> - ok - end, Affiliations) - end, State#state.plugins), + spawn(fun() -> + Host = State#state.host, + Owner = exmpp_jid:make(LUser, LServer), + %% remove user's subscriptions + lists:foreach(fun(PType) -> + {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Owner]), + lists:foreach(fun + ({#pubsub_node{nodeid = {H, N}}, subscribed, _, JID}) -> + unsubscribe_node(H, N, Owner, JID, all); + (_) -> + ok + end, Subscriptions), + {result, Affiliations} = node_action(Host, PType, get_entity_affiliations, [Host, Owner]), + lists:foreach(fun + ({#pubsub_node{nodeid = {H, N}}, owner}) -> + delete_node(H, N, Owner); + (_) -> + ok + end, Affiliations) + end, State#state.plugins) + end), {noreply, State}; handle_cast({unsubscribe, Subscriber, Owner}, State) -> - Host = State#state.host, - BJID = jlib:short_prepd_bare_jid(Owner), - lists:foreach(fun(PType) -> - {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), - lists:foreach(fun - ({Node, subscribed, _, JID}) -> - #pubsub_node{options = Options, owners = Owners, type = Type, id = NodeId} = Node, - case get_option(Options, access_model) of - presence -> - case lists:member(BJID, Owners) of - true -> - node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); - false -> - {result, ok} - end; - _ -> - {result, ok} - end; - (_) -> - ok - end, Subscriptions) - end, State#state.plugins), + spawn(fun() -> + Host = State#state.host, + BJID = jlib:short_prepd_bare_jid(Owner), + lists:foreach(fun(PType) -> + {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), + lists:foreach(fun + ({Node, subscribed, _, JID}) -> + #pubsub_node{options = Options, owners = Owners, type = Type, id = NodeId} = Node, + case get_option(Options, access_model) of + presence -> + case lists:member(BJID, Owners) of + true -> + node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); + false -> + {result, ok} + end; + _ -> + {result, ok} + end; + (_) -> + ok + end, Subscriptions) + end, State#state.plugins) + end), {noreply, State}; handle_cast(_Msg, State) -> @@ -2058,11 +2059,16 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> [#xmlel{ns = ?NS_PUBSUB, name = 'publish', attrs = nodeAttr(Node), children = [#xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = itemAttr(ItemId)}]}]}, case transaction(Host, Node, Action, sync_dirty) of - {result, {TNode, {Result, broadcast, Removed}}} -> + {result, {TNode, {Result, Broadcast, Removed}}} -> NodeId = TNode#pubsub_node.id, Type = TNode#pubsub_node.type, Options = TNode#pubsub_node.options, - broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, jlib:short_prepd_jid(Publisher), Payload), + BroadcastPayload = case Broadcast of + default -> Payload; + broadcast -> Payload; + PluginPayload -> PluginPayload + end, + broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, jlib:short_prepd_jid(Publisher), BroadcastPayload), set_cached_item(Host, NodeId, ItemId, Payload), case Result of default -> {result, Reply}; diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index 38653579d..dbed3e0b0 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -42,9 +42,6 @@ %%% 6.2.3.1, 6.2.3.5, and 6.3. For information on subscription leases see %%% XEP-0060 section 12.18. -%%% TODO -%%% plugin: generate Reply (do not use broadcast atom anymore) - -module(mod_pubsub_odbc). -author('christophe.romain@process-one.net'). -version('1.13-0'). @@ -619,50 +616,54 @@ handle_cast({presence, User, Server, Resources, JID}, State) -> {noreply, send_queue(State, {presence, User, Server, Resources, JID})}; handle_cast({remove_user, LUser, LServer}, State) -> - Host = State#state.host, - Owner = exmpp_jid:make(LUser, LServer), - %% remove user's subscriptions - lists:foreach(fun(PType) -> - {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Owner]), - lists:foreach(fun - ({#pubsub_node{nodeid = {H, N}}, subscribed, _, JID}) -> - unsubscribe_node(H, N, Owner, JID, all); - (_) -> - ok - end, Subscriptions), - {result, Affiliations} = node_action(Host, PType, get_entity_affiliations, [Host, Owner]), - lists:foreach(fun - ({#pubsub_node{nodeid = {H, N}}, owner}) -> - delete_node(H, N, Owner); - (_) -> - ok - end, Affiliations) - end, State#state.plugins), + spawn(fun() -> + Host = State#state.host, + Owner = exmpp_jid:make(LUser, LServer), + %% remove user's subscriptions + lists:foreach(fun(PType) -> + {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Owner]), + lists:foreach(fun + ({#pubsub_node{nodeid = {H, N}}, subscribed, _, JID}) -> + unsubscribe_node(H, N, Owner, JID, all); + (_) -> + ok + end, Subscriptions), + {result, Affiliations} = node_action(Host, PType, get_entity_affiliations, [Host, Owner]), + lists:foreach(fun + ({#pubsub_node{nodeid = {H, N}}, owner}) -> + delete_node(H, N, Owner); + (_) -> + ok + end, Affiliations) + end, State#state.plugins) + end), {noreply, State}; handle_cast({unsubscribe, Subscriber, Owner}, State) -> - Host = State#state.host, - BJID = jlib:short_prepd_bare_jid(Owner), - lists:foreach(fun(PType) -> - {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), - lists:foreach(fun - ({Node, subscribed, _, JID}) -> - #pubsub_node{options = Options, type = Type, id = NodeId} = Node, - case get_option(Options, access_model) of - presence -> - case lists:member(BJID, node_owners(Host, Type, NodeId)) of - true -> - node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); - false -> - {result, ok} - end; - _ -> - {result, ok} - end; - (_) -> - ok - end, Subscriptions) - end, State#state.plugins), + spawn(fun() -> + Host = State#state.host, + BJID = jlib:short_prepd_bare_jid(Owner), + lists:foreach(fun(PType) -> + {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), + lists:foreach(fun + ({Node, subscribed, _, JID}) -> + #pubsub_node{options = Options, type = Type, id = NodeId} = Node, + case get_option(Options, access_model) of + presence -> + case lists:member(BJID, node_owners(Host, Type, NodeId)) of + true -> + node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); + false -> + {result, ok} + end; + _ -> + {result, ok} + end; + (_) -> + ok + end, Subscriptions) + end, State#state.plugins) + end), {noreply, State}; handle_cast(_Msg, State) -> @@ -1894,11 +1895,16 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) -> [#xmlel{ns = ?NS_PUBSUB, name = 'publish', attrs = nodeAttr(Node), children = [#xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = itemAttr(ItemId)}]}]}, case transaction(Host, Node, Action, sync_dirty) of - {result, {TNode, {Result, broadcast, Removed}}} -> + {result, {TNode, {Result, Broadcast, Removed}}} -> NodeId = TNode#pubsub_node.id, Type = TNode#pubsub_node.type, Options = TNode#pubsub_node.options, - broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, jlib:short_prepd_jid(Publisher), Payload), + BroadcastPayload = case Broadcast of + default -> Payload; + broadcast -> Payload; + PluginPayload -> PluginPayload + end, + broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, jlib:short_prepd_jid(Publisher), BroadcastPayload), set_cached_item(Host, NodeId, ItemId, Payload), case Result of default -> {result, Reply}; diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index f5044d5fd..cb16e8f75 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,15 +1,15 @@ ---- mod_pubsub.erl 2009-10-12 12:21:54.000000000 +0200 -+++ mod_pubsub_odbc.erl 2009-10-12 12:23:13.000000000 +0200 -@@ -45,7 +45,7 @@ - %%% TODO - %%% plugin: generate Reply (do not use broadcast atom anymore) +--- mod_pubsub.erl 2009-10-13 18:39:11.000000000 +0200 ++++ mod_pubsub_odbc.erl 2009-10-13 18:40:32.000000000 +0200 +@@ -42,7 +42,7 @@ + %%% 6.2.3.1, 6.2.3.5, and 6.3. For information on subscription leases see + %%% XEP-0060 section 12.18. --module(mod_pubsub). +-module(mod_pubsub_odbc). -author('christophe.romain@process-one.net'). -version('1.13-0'). -@@ -58,9 +58,9 @@ +@@ -55,9 +55,9 @@ -include("adhoc.hrl"). -include("pubsub.hrl"). @@ -22,7 +22,7 @@ %% exports for hooks -export([presence_probe/3, -@@ -106,7 +106,7 @@ +@@ -103,7 +103,7 @@ string_to_affiliation/1, extended_error/2, extended_error/3, @@ -31,7 +31,7 @@ ]). %% API and gen_server callbacks -@@ -125,7 +125,7 @@ +@@ -122,7 +122,7 @@ -export([send_loop/1 ]). @@ -40,7 +40,7 @@ -define(PLUGIN_PREFIX, "node_"). -define(TREE_PREFIX, "nodetree_"). -@@ -227,8 +227,6 @@ +@@ -224,8 +224,6 @@ ok end, ejabberd_router:register_route(Host), @@ -49,7 +49,7 @@ init_nodes(Host, ServerHost, NodeTree, Plugins), State = #state{host = Host, server_host = ServerHost, -@@ -289,177 +287,7 @@ +@@ -286,177 +284,7 @@ ok end. @@ -227,7 +227,7 @@ send_queue(State, Msg) -> Pid = State#state.send_loop, -@@ -483,17 +311,15 @@ +@@ -480,17 +308,15 @@ %% for each node From is subscribed to %% and if the node is so configured, send the last published item to From lists:foreach(fun(PType) -> @@ -252,19 +252,19 @@ % resource not concerned about that subscription ok @@ -821,10 +647,10 @@ - {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), - lists:foreach(fun - ({Node, subscribed, _, JID}) -> -- #pubsub_node{options = Options, owners = Owners, type = Type, id = NodeId} = Node, -+ #pubsub_node{options = Options, type = Type, id = NodeId} = Node, - case get_option(Options, access_model) of - presence -> -- case lists:member(BJID, Owners) of -+ case lists:member(BJID, node_owners(Host, Type, NodeId)) of - true -> - node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); - false -> -@@ -942,11 +768,12 @@ + {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), + lists:foreach(fun + ({Node, subscribed, _, JID}) -> +- #pubsub_node{options = Options, owners = Owners, type = Type, id = NodeId} = Node, ++ #pubsub_node{options = Options, type = Type, id = NodeId} = Node, + case get_option(Options, access_model) of + presence -> +- case lists:member(BJID, Owners) of ++ case lists:member(BJID, node_owners(Host, Type, NodeId)) of + true -> + node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); + false -> +@@ -943,11 +769,12 @@ end, ejabberd_router:route(To, From, Res); #iq{type = get, ns = ?NS_DISCO_ITEMS, @@ -279,7 +279,7 @@ {result, IQRes} -> Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', attrs = QAttrs, -@@ -1049,7 +876,7 @@ +@@ -1050,7 +877,7 @@ [] -> ["leaf"]; %% No sub-nodes: it's a leaf node _ -> @@ -288,7 +288,7 @@ {result, []} -> ["collection"]; {result, _} -> ["leaf", "collection"]; _ -> [] -@@ -1065,8 +892,9 @@ +@@ -1066,8 +893,9 @@ []; true -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]} | @@ -300,7 +300,7 @@ end, features(Type))] end, %% TODO: add meta-data info (spec section 5.4) -@@ -1094,14 +922,15 @@ +@@ -1095,14 +923,15 @@ #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_DISCO_ITEMS_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_VCARD_s)]}] ++ @@ -319,7 +319,7 @@ {result, lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> SN = node_to_string(SubNode), -@@ -1111,7 +940,7 @@ +@@ -1112,7 +941,7 @@ ?XMLATTR('node', SN), ?XMLATTR('name', RN)]} end, tree_action(Host, get_subnodes, [Host, [], From]))}; @@ -328,7 +328,7 @@ case string:tokens(Item, "!") of [_SNode, _ItemID] -> {result, []}; -@@ -1123,10 +952,10 @@ +@@ -1124,10 +953,10 @@ %% TODO That is, remove name attribute (or node?, please check for 2.1) Action = fun(#pubsub_node{type = Type, id = NodeId}) -> @@ -342,7 +342,7 @@ end, Nodes = lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> -@@ -1142,7 +971,7 @@ +@@ -1143,7 +972,7 @@ #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), ?XMLATTR('name', Name)]} end, NodeItems), @@ -351,7 +351,7 @@ end, case transaction(Host, Node, Action, sync_dirty) of {result, {_, Result}} -> {result, Result}; -@@ -1276,7 +1105,8 @@ +@@ -1277,7 +1106,8 @@ (_, Acc) -> Acc end, [], exmpp_xml:remove_cdata_from_list(Els)), @@ -361,7 +361,7 @@ {get, 'subscriptions'} -> get_subscriptions(Host, Node, From, Plugins); {get, 'affiliations'} -> -@@ -1298,8 +1128,9 @@ +@@ -1299,8 +1129,9 @@ end. iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> @@ -373,7 +373,7 @@ case Action of [#xmlel{name = Name, attrs = Attrs, children = Els}] -> Node = case Host of -@@ -1429,7 +1260,8 @@ +@@ -1430,7 +1261,8 @@ _ -> [] end end, @@ -383,7 +383,7 @@ sync_dirty) of {result, Res} -> Res; Err -> Err -@@ -1474,7 +1306,7 @@ +@@ -1475,7 +1307,7 @@ %%% authorization handling @@ -392,7 +392,7 @@ Lang = "en", %% TODO fix {U, S, R} = Subscriber, Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = -@@ -1504,7 +1336,7 @@ +@@ -1505,7 +1337,7 @@ lists:foreach(fun(Owner) -> {U, S, R} = Owner, ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza} @@ -401,7 +401,7 @@ find_authorization_response(Packet) -> Els = Packet#xmlel.children, -@@ -1567,8 +1399,8 @@ +@@ -1568,8 +1400,8 @@ "true" -> true; _ -> false end, @@ -412,7 +412,7 @@ {result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]), if not IsApprover -> -@@ -1758,7 +1590,7 @@ +@@ -1759,7 +1591,7 @@ end, Reply = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(Node)}]}, @@ -421,7 +421,7 @@ {result, {Result, broadcast}} -> %%Lang = "en", %% TODO: fix %%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), -@@ -1867,7 +1699,7 @@ +@@ -1868,7 +1700,7 @@ %%
  • The node does not exist.
  • %% subscribe_node(Host, Node, From, JID, Configuration) -> @@ -430,7 +430,7 @@ {result, GoodSubOpts} -> GoodSubOpts; _ -> invalid end, -@@ -1878,7 +1710,7 @@ +@@ -1879,7 +1711,7 @@ {undefined, undefined, undefined} end, SubId = uniqid(), @@ -439,7 +439,7 @@ Features = features(Type), SubscribeFeature = lists:member("subscribe", Features), OptionsFeature = lists:member("subscription-options", Features), -@@ -1897,9 +1729,13 @@ +@@ -1898,9 +1730,13 @@ {"", "", ""} -> {false, false}; _ -> @@ -456,7 +456,7 @@ end end, if -@@ -2227,7 +2063,7 @@ +@@ -2233,7 +2069,7 @@ %%

    The permission are not checked in this function.

    %% @todo We probably need to check that the user doing the query has the right %% to read the items. @@ -465,7 +465,7 @@ MaxItems = if SMaxItems == "" -> get_max_items_node(Host); -@@ -2266,11 +2102,11 @@ +@@ -2272,11 +2108,11 @@ node_call(Type, get_items, [NodeId, From, AccessModel, PresenceSubscription, RosterGroup, @@ -479,7 +479,7 @@ SendItems = case ItemIDs of [] -> Items; -@@ -2283,7 +2119,7 @@ +@@ -2289,7 +2125,7 @@ %% number of items sent to MaxItems: {result, #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = nodeAttr(Node), children = @@ -488,7 +488,7 @@ Error -> Error end -@@ -2315,17 +2151,29 @@ +@@ -2321,17 +2157,29 @@ %% @doc

    Resend the items of a node to the user.

    %% @todo use cache-last-item feature send_items(Host, Node, NodeId, Type, LJID, last) -> @@ -525,7 +525,7 @@ send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of {result, []} -> -@@ -2454,29 +2302,12 @@ +@@ -2460,29 +2308,12 @@ error -> {error, 'bad-request'}; _ -> @@ -558,7 +558,7 @@ end, Entities), {result, []}; _ -> -@@ -2531,11 +2362,11 @@ +@@ -2537,11 +2368,11 @@ end. read_sub(Subscriber, Node, NodeID, SubID, Lang) -> @@ -572,7 +572,7 @@ OptionsEl = #xmlel{ns = ?NS_PUBSUB, name = 'options', attrs = [?XMLATTR('node', node_to_string(Node)), ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), -@@ -2563,7 +2394,7 @@ +@@ -2569,7 +2400,7 @@ end. set_options_helper(Configuration, JID, NodeID, SubID, Type) -> @@ -581,7 +581,7 @@ {result, GoodSubOpts} -> GoodSubOpts; _ -> invalid end, -@@ -2593,7 +2424,7 @@ +@@ -2599,7 +2430,7 @@ write_sub(_Subscriber, _NodeID, _SubID, invalid) -> {error, extended_error('bad-request', "invalid-options")}; write_sub(Subscriber, NodeID, SubID, Options) -> @@ -590,7 +590,7 @@ {error, notfound} -> {error, extended_error('not-acceptable', "invalid-subid")}; {result, _} -> -@@ -2766,8 +2597,8 @@ +@@ -2772,8 +2603,8 @@ ?XMLATTR('subsription', subscription_to_string(Sub)) | nodeAttr(Node)]}]}]}, ejabberd_router ! {route, service_jid(Host), JID, Stanza} end, @@ -601,7 +601,7 @@ true -> Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> -@@ -3063,7 +2894,7 @@ +@@ -3069,7 +2900,7 @@ {Depth, [{N, get_node_subs(N)} || N <- Nodes]} end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))} end, @@ -610,7 +610,7 @@ {result, CollSubs} -> CollSubs; _ -> [] end. -@@ -3077,9 +2908,9 @@ +@@ -3083,9 +2914,9 @@ get_options_for_subs(NodeID, Subs) -> lists:foldl(fun({JID, subscribed, SubID}, Acc) -> @@ -622,7 +622,7 @@ _ -> Acc end; (_, Acc) -> -@@ -3278,6 +3109,30 @@ +@@ -3284,6 +3115,30 @@ Result end. @@ -653,7 +653,7 @@ %% @spec (Host, Options) -> MaxItems %% Host = host() %% Options = [Option] -@@ -3667,7 +3522,13 @@ +@@ -3673,7 +3528,13 @@ tree_action(Host, Function, Args) -> ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), Fun = fun() -> tree_call(Host, Function, Args) end, @@ -668,7 +668,7 @@ %% @doc

    node plugin call.

    node_call(Type, Function, Args) -> -@@ -3687,13 +3548,13 @@ +@@ -3693,13 +3554,13 @@ node_action(Host, Type, Function, Args) -> ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), @@ -684,7 +684,7 @@ case tree_call(Host, get_node, [Host, Node]) of N when is_record(N, pubsub_node) -> case Action(N) of -@@ -3706,8 +3567,15 @@ +@@ -3712,8 +3573,15 @@ end end, Trans). @@ -702,7 +702,7 @@ {result, Result} -> {result, Result}; {error, Error} -> {error, Error}; {atomic, {result, Result}} -> {result, Result}; -@@ -3715,6 +3583,15 @@ +@@ -3721,6 +3589,15 @@ {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), {error, 'internal-server-error'}; @@ -718,7 +718,7 @@ {'EXIT', Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), {error, 'internal-server-error'}; -@@ -3723,6 +3600,16 @@ +@@ -3729,6 +3606,16 @@ {error, 'internal-server-error'} end. From f1b9f1fb63bb35a2424a913bd4167459a6fcc823 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 13 Oct 2009 21:36:32 +0000 Subject: [PATCH 571/582] Fix EDoc compilation errors. SVN Revision: 2667 --- src/mod_pubsub/mod_pubsub.erl | 2 +- src/mod_pubsub/mod_pubsub_odbc.erl | 2 +- src/mod_pubsub/node_hometree.erl | 6 +++--- src/mod_pubsub/node_hometree_odbc.erl | 6 +++--- src/mod_pubsub/nodetree_tree.erl | 6 +++--- src/mod_pubsub/nodetree_tree_odbc.erl | 6 +++--- src/mod_pubsub/nodetree_virtual.erl | 8 ++++---- src/mod_pubsub/pubsub.hrl | 9 +++++---- 8 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 2918ae17d..444175548 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -1536,7 +1536,7 @@ find_authorization_response(Packet) -> %% Host = mod_pubsub:host() %% JID = jlib:jid() %% SNode = string() -%% Subscription = atom() | {atom(), mod_pubsub:subid)} +%% Subscription = atom() | {atom(), mod_pubsub:subid()} %% Plugins = [Plugin::string()] %% @doc Send a message to JID with the supplied Subscription send_authorization_approval(Host, JID, SNode, Subscription) -> diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index dbed3e0b0..93e07c172 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -1368,7 +1368,7 @@ find_authorization_response(Packet) -> %% Host = mod_pubsub:host() %% JID = jlib:jid() %% SNode = string() -%% Subscription = atom() | {atom(), mod_pubsub:subid)} +%% Subscription = atom() | {atom(), mod_pubsub:subid()} %% Plugins = [Plugin::string()] %% @doc Send a message to JID with the supplied Subscription send_authorization_approval(Host, JID, SNode, Subscription) -> diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index d8d933e4c..c3fa6e293 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -245,7 +245,7 @@ delete_node(Removed) -> end, Removed), {result, {default, broadcast, Reply}}. -%% @spec (NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> +%% @spec (NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options) -> %% {error, Reason} | {result, Result} %% @doc

    Accepts or rejects subcription requests on a PubSub node.

    %%

    The mechanism works as follow: @@ -851,8 +851,8 @@ set_state(State) when is_record(State, pubsub_state) -> set_state(_) -> {error, 'internal-server-error'}. -%% @spec (StateId) -> ok | {error, Reason::stanzaError()} -%% StateId = mod_pubsub:pubsubStateId() +%% @spec (NodeId, JID) -> ok | {error, Reason::stanzaError()} +%% NodeId = mod_pubsub:pubsubNodeId() %% @doc

    Delete a state from database.

    del_state(NodeId, JID) -> mnesia:delete({pubsub_state, {JID, NodeId}}). diff --git a/src/mod_pubsub/node_hometree_odbc.erl b/src/mod_pubsub/node_hometree_odbc.erl index 74d2ffd71..4bac466db 100644 --- a/src/mod_pubsub/node_hometree_odbc.erl +++ b/src/mod_pubsub/node_hometree_odbc.erl @@ -263,7 +263,7 @@ delete_node(Removed) -> end, Removed), {result, {default, broadcast, Reply}}. -%% @spec (NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) -> +%% @spec (NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup, Options) -> %% {error, Reason} | {result, Result} %% @doc

    Accepts or rejects subcription requests on a PubSub node.

    %%

    The mechanism works as follow: @@ -945,8 +945,8 @@ set_state(NodeId, State) -> end, {result, []}. -%% @spec (StateId) -> ok | {error, Reason::stanzaError()} -%% StateId = mod_pubsub:pubsubStateId() +%% @spec (NodeId, JID) -> ok | {error, Reason::stanzaError()} +%% NodeId = mod_pubsub:pubsubNodeId() %% @doc

    Delete a state from database.

    del_state(NodeId, JID) -> J = encode_jid(JID), diff --git a/src/mod_pubsub/nodetree_tree.erl b/src/mod_pubsub/nodetree_tree.erl index 16a960430..9ea51658e 100644 --- a/src/mod_pubsub/nodetree_tree.erl +++ b/src/mod_pubsub/nodetree_tree.erl @@ -103,7 +103,7 @@ set_node(Record) when is_record(Record, pubsub_node) -> set_node(_) -> {error, 'internal-server-error'}. -%% @spec (Host, Node) -> pubsubNode() | {error, Reason} +%% @spec (Host, Node, From) -> pubsubNode() | {error, Reason} %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() get_node(Host, Node, _From) -> @@ -121,7 +121,7 @@ get_node(NodeId) -> Error -> Error end. -%% @spec (Host) -> [pubsubNode()] | {error, Reason} +%% @spec (Host, From) -> [pubsubNode()] | {error, Reason} %% Host = mod_pubsub:host() | mod_pubsub:jid() get_nodes(Host, _From) -> get_nodes(Host). @@ -165,7 +165,7 @@ get_subnodes(Host, Node) -> lists:member(Node, Parents)]), qlc:e(Q). -%% @spec (Host, Index) -> [pubsubNodeIdx()] | {error, Reason} +%% @spec (Host, Index, From) -> [pubsubNodeIdx()] | {error, Reason} %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() %% From = mod_pubsub:jid() diff --git a/src/mod_pubsub/nodetree_tree_odbc.erl b/src/mod_pubsub/nodetree_tree_odbc.erl index 04f657fb2..4d1995f1f 100644 --- a/src/mod_pubsub/nodetree_tree_odbc.erl +++ b/src/mod_pubsub/nodetree_tree_odbc.erl @@ -91,7 +91,7 @@ options() -> {odbc, true}]. -%% @spec (Host, Node) -> pubsubNode() | {error, Reason} +%% @spec (Host, Node, From) -> pubsubNode() | {error, Reason} %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() get_node(Host, Node, _From) -> @@ -125,7 +125,7 @@ get_node(NodeId) -> {error, 'item_not_found'} end. -%% @spec (Host) -> [pubsubNode()] | {error, Reason} +%% @spec (Host, From) -> [pubsubNode()] | {error, Reason} %% Host = mod_pubsub:host() | mod_pubsub:jid() get_nodes(Host, _From) -> get_nodes(Host). @@ -182,7 +182,7 @@ get_subnodes(Host, Node) -> [] end. -%% @spec (Host, Index) -> [pubsubNodeIdx()] | {error, Reason} +%% @spec (Host, Index, From) -> [pubsubNodeIdx()] | {error, Reason} %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() %% From = mod_pubsub:jid() diff --git a/src/mod_pubsub/nodetree_virtual.erl b/src/mod_pubsub/nodetree_virtual.erl index bd9b74713..6285d724c 100644 --- a/src/mod_pubsub/nodetree_virtual.erl +++ b/src/mod_pubsub/nodetree_virtual.erl @@ -26,7 +26,7 @@ %%% @doc The module {@module} is the PubSub node tree plugin that %%% allow virtual nodes handling. %%%

    PubSub node tree plugins are using the {@link gen_nodetree} behaviour.

    -%%% This plugin development is still a work in progress. Due to optimizations in +%%%

    The development of this plugin is still a work in progress. Due to optimizations in %%% mod_pubsub, this plugin can not work anymore without altering functioning. %%% Please, send us comments, feedback and improvements.

    @@ -84,7 +84,7 @@ options() -> set_node(_NodeRecord) -> ok. -%% @spec (Host, Node) -> pubsubNode() +%% @spec (Host, Node, From) -> pubsubNode() %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() %% @doc

    Virtual node tree does not handle a node database. Any node is considered @@ -96,7 +96,7 @@ get_node(Host, Node) -> get_node({Host, _} = NodeId) -> #pubsub_node{nodeid = NodeId, id = NodeId, owners = [{undefined, list_to_binary(Host), undefined}]}. -%% @spec (Host) -> [pubsubNode()] +%% @spec (Host, From) -> [pubsubNode()] %% Host = mod_pubsub:host() | mod_pubsub:jid() %% @doc

    Virtual node tree does not handle a node database. Any node is considered %% as existing. Nodes list can not be determined.

    @@ -115,7 +115,7 @@ get_subnodes(Host, Node, _From) -> get_subnodes(_Host, _Node) -> []. -%% @spec (Host, Index) -> [pubsubNode()] +%% @spec (Host, Index, From) -> [pubsubNode()] %% Host = mod_pubsub:host() %% Node = mod_pubsub:pubsubNode() %% @doc

    Virtual node tree does not handle parent/child. Child list is empty.

    diff --git a/src/mod_pubsub/pubsub.hrl b/src/mod_pubsub/pubsub.hrl index 1fa8af397..e437c979c 100644 --- a/src/mod_pubsub/pubsub.hrl +++ b/src/mod_pubsub/pubsub.hrl @@ -85,12 +85,13 @@ %%% @type pubsubNode() = #pubsub_node{ %%% nodeid = {Host::host(), Node::pubsubNode()}, %%% parentid = Node::pubsubNode(), -%%% nodeidx = int(). % can be anything you want +%%% nodeidx = int(), %%% type = nodeType(), -%%% options = [nodeOption()]} +%%% options = [nodeOption()]}. %%%

    This is the format of the nodes table. The type of the table %%% is: set,ram/disc.

    %%%

    The parentid and type fields are indexed.

    +%%%

    nodeidx can be anything you want.

    -record(pubsub_node, {nodeid, id, parents = [], @@ -100,7 +101,7 @@ }). %%% @type pubsubState() = #pubsub_state{ -%%% stateid = {ljid(), nodeidx()}}, +%%% stateid = {ljid(), nodeidx()}, %%% items = [ItemId::string()], %%% affiliation = affiliation(), %%% subscriptions = [subscription()]}. @@ -113,7 +114,7 @@ }). %%% @type pubsubItem() = #pubsub_item{ -%%% itemid = {ItemId::string(), nodeidx()}}, +%%% itemid = {ItemId::string(), nodeidx()}, %%% creation = {now(), ljid()}, %%% modification = {now(), ljid()}, %%% payload = XMLContent::string()}. From 13b89406063eefa9e350c27c2ec95e8947c96b5c Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 13 Oct 2009 22:31:06 +0000 Subject: [PATCH 572/582] Fixed more gcc signedness warnings SVN Revision: 2669 --- src/pam/epam.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pam/epam.c b/src/pam/epam.c index db82c825a..1c429c1dc 100644 --- a/src/pam/epam.c +++ b/src/pam/epam.c @@ -144,7 +144,7 @@ static int write_cmd(char *buf, int len) { byte hd[2]; enc_int16(len, hd); - if (write_buf(1, hd, 2) != 2) + if (write_buf(1, (char *)hd, 2) != 2) return 0; if (write_buf(1, buf, len) != len) return 0; @@ -167,7 +167,7 @@ static int process_reply(ETERM *pid, int cmd, int res) len = erl_term_len(result); buf = erl_malloc(len); erl_encode(result, buf); - retval = write_cmd(buf, len); + retval = write_cmd((char *)buf, len); erl_free_term(result); erl_free(buf); return retval; From 162fbc2ef8c4bb4e5c981ac53bb00d96b8280bcb Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 15 Oct 2009 22:46:50 +0000 Subject: [PATCH 573/582] Small fix in RSM decoding (thanks to Alexander Tsvyashchenko)(EJAB-1066) SVN Revision: 2670 --- src/jlib.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jlib.erl b/src/jlib.erl index 4729cd067..abe4ff869 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -92,7 +92,7 @@ rsm_decode(#xmlel{}=SubEl)-> case exmpp_xml:get_element(SubEl, 'set') of undefined -> none; - #xmlelement{name = 'set', children = SubEls}-> + #xmlel{name = 'set', children = SubEls}-> lists:foldl(fun rsm_parse_element/2, #rsm_in{}, SubEls) end. From dce7b1430bfc0ad1f5eb77f0b8bc815fc843c13e Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 19 Oct 2009 10:42:19 +0000 Subject: [PATCH 574/582] Start mnesia as a permanent application (thanks to Brian Cully)(EJAB-1068) SVN Revision: 2674 --- src/ejabberd_app.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index bea1b0b7a..2942ef076 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -110,7 +110,7 @@ db_init() -> _ -> ok end, - mnesia:start(), + application:start(mnesia, permanent), mnesia:wait_for_tables(mnesia:system_info(local_tables), infinity). %% Start all the modules in all the hosts From 9a6c869cb8e4de1bdcd6bc678ec9dd3779f57001 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 19 Oct 2009 10:50:00 +0000 Subject: [PATCH 575/582] Fix word Sensible with Sensitive (thanks to Marcin Owsiany)(EJAB-1071) SVN Revision: 2676 --- doc/guide.html | 6 +++--- doc/guide.tex | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 416bb71ce..ca79772d5 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -188,7 +188,7 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}
  • 5.2  epmd
  • 5.3  Erlang Cookie
  • 5.4  Erlang Node Name -
  • 5.5  Securing Sensible Files +
  • 5.5  Securing Sensitive Files
  • Chapter 6  Clustering
    • @@ -3643,8 +3643,8 @@ to difficult unauthorized access to your Erlang node. However, it is not ultimately effective to prevent access to the Erlang node, because it may be possible to fake the fact that you are on another network using a modified version of Erlang epmd. -The recommended way to secure the Erlang node is to block the port 4369.

      -

      5.5  Securing Sensible Files

      ejabberd stores sensible data in the file system either in plain text or binary files. +The recommended way to secure the Erlang node is to block the port 4369.

      +

      5.5  Securing Sensitive Files

      ejabberd stores sensitive data in the file system either in plain text or binary files. The file system permissions should be set to only allow the proper user to read, write and execute those files and directories.

      ejabberd configuration file: /etc/ejabberd/ejabberd.cfg
      diff --git a/doc/guide.tex b/doc/guide.tex index a720d7231..4a34e4601 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -4697,9 +4697,9 @@ using a modified version of Erlang \term{epmd}. The recommended way to secure the Erlang node is to block the port 4369. -\makesection{secure-files}{Securing Sensible Files} +\makesection{secure-files}{Securing Sensitive Files} -\ejabberd{} stores sensible data in the file system either in plain text or binary files. +\ejabberd{} stores sensitive data in the file system either in plain text or binary files. The file system permissions should be set to only allow the proper user to read, write and execute those files and directories. From 227514c20c309522debe437b894d5409cb8363bf Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 19 Oct 2009 13:24:13 +0000 Subject: [PATCH 576/582] Support ejabberd_listener option 'backlog' to increase TCP backlog (thanks to Janusz Dziemidowicz)(EJAB-1063) SVN Revision: 2679 --- doc/guide.html | 6 ++++++ doc/guide.tex | 6 ++++++ src/ejabberd_listener.erl | 1 + 3 files changed, 13 insertions(+) diff --git a/doc/guide.html b/doc/guide.html index ca79772d5..60d233f43 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -690,6 +690,12 @@ Handles incoming HTTP connections.

      {access, AccessName}
      This option defines access to the port. The default value is all. +
      {backlog, Value}
      The backlog value +defines the maximum length that the queue of pending connections may +grow to. This should be increased if the server is going to handle +lots of new incoming connections as they may be dropped if there is +no space in the queue (and ejabberd was not able to accept them +immediately). Default value is 5.
      {certfile, Path}
      Full path to a file containing the default SSL certificate. To define a certificate file specific for a given domain, use the global option domain_certfile.
      {service_check_from, true|false}
      diff --git a/doc/guide.tex b/doc/guide.tex index 4a34e4601..2f3c2171a 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -823,6 +823,12 @@ This is a detailed description of each option allowed by the listening modules: \begin{description} \titem{\{access, AccessName\}} \ind{options!access}This option defines access to the port. The default value is \term{all}. + \titem{\{backlog, Value\}} \ind{options!backlog}The backlog value + defines the maximum length that the queue of pending connections may + grow to. This should be increased if the server is going to handle + lots of new incoming connections as they may be dropped if there is + no space in the queue (and ejabberd was not able to accept them + immediately). Default value is 5. \titem{\{certfile, Path\}} Full path to a file containing the default SSL certificate. To define a certificate file specific for a given domain, use the global option \term{domain\_certfile}. \titem{\{service\_check\_from, true|false\}} \ind{options!service\_check\_from} diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 26167351f..fa1209626 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -104,6 +104,7 @@ init(PortIP, Module, RawOpts) -> SockOpts = lists:filter(fun({ip, _}) -> true; (inet6) -> true; (inet) -> true; + ({backlog, _}) -> true; (_) -> false end, Opts), if Proto == udp -> From 372658d2998a473bd41acd4647b2e1c11ce33118 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 19 Oct 2009 14:53:21 +0000 Subject: [PATCH 577/582] Merged from trunk SVN r2671: Support gen_tcp send timeout: Close the connection if the other end has disconnected ungracefully or cannot keep up with the rate at which we are sending data (EJAB-926) SVN Revision: 2681 --- src/ejabberd_listener.erl | 1 + src/ejabberd_s2s_out.erl | 1 + src/ejabberd_socket.erl | 22 ++++++++++++++++++---- src/web/ejabberd_http.erl | 15 +++++++++++---- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index fa1209626..7d5ca2fa8 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -133,6 +133,7 @@ init_tcp(PortIP, Module, Opts, SockOpts, Port, IPS) -> {reuseaddr, true}, {nodelay, true}, {send_timeout, ?TCP_SEND_TIMEOUT}, + {send_timeout_close, true}, {keepalive, true} | SockOpts]), case Res of diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index c5024c05d..e601ff03f 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -260,6 +260,7 @@ open_socket2(Type, Addr, Port) -> case (catch ejabberd_socket:connect(Addr, Port, [binary, {packet, 0}, {send_timeout, ?TCP_SEND_TIMEOUT}, + {send_timeout_close, true}, {active, false}, Type], Timeout)) of {ok, _Socket} = R -> R; diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl index d629a77d9..a3c008c97 100644 --- a/src/ejabberd_socket.erl +++ b/src/ejabberd_socket.erl @@ -46,13 +46,15 @@ close/1, sockname/1, peername/1]). +-include("ejabberd.hrl"). + -record(socket_state, {sockmod, socket, receiver}). %%==================================================================== %% API %%==================================================================== %%-------------------------------------------------------------------- -%% Function: +%% Function: %% Description: %%-------------------------------------------------------------------- start(Module, SockMod, Socket, Opts) -> @@ -67,7 +69,7 @@ start(Module, SockMod, Socket, Opts) -> case catch SockMod:custom_receiver(Socket) of {receiver, RecMod, RecPid} -> {RecMod, RecPid, RecMod}; - _ -> + _ -> RecPid = ejabberd_receiver:start( Socket, SockMod, none, MaxStanzaSize), {ejabberd_receiver, RecPid, RecPid} @@ -158,10 +160,22 @@ reset_stream(SocketData) when is_atom(SocketData#socket_state.receiver) -> (SocketData#socket_state.receiver):reset_stream( SocketData#socket_state.socket). +%% sockmod=gen_tcp|tls|ejabberd_zlib send(SocketData, Data) -> - catch (SocketData#socket_state.sockmod):send( - SocketData#socket_state.socket, Data). + case catch (SocketData#socket_state.sockmod):send( + SocketData#socket_state.socket, Data) of + ok -> ok; + {error, timeout} -> + ?INFO_MSG("Timeout on ~p:send",[SocketData#socket_state.sockmod]), + exit(normal); + Error -> + ?DEBUG("Error in ~p:send: ~p",[SocketData#socket_state.sockmod, Error]), + exit(normal) + end. +%% Can only be called when in c2s StateData#state.xml_socket is true +%% This function is used for HTTP bind +%% sockmod=ejabberd_http_poll|ejabberd_http_bind or any custom module send_xml(SocketData, Data) -> catch (SocketData#socket_state.sockmod):send_xml( SocketData#socket_state.socket, Data). diff --git a/src/web/ejabberd_http.erl b/src/web/ejabberd_http.erl index 820f5646a..54ee37563 100644 --- a/src/web/ejabberd_http.erl +++ b/src/web/ejabberd_http.erl @@ -105,7 +105,7 @@ start_link({SockMod, Socket}, Opts) -> end, %% XXX bard: for backward compatibility, expand in Opts: - %% web_admin -> {["admin"], ejabberd_web_admin} + %% web_admin -> {["admin"], ejabberd_web_admin} %% http_bind -> {["http-bind"], mod_http_bind} %% http_poll -> {["http-poll"], ejabberd_http_poll} @@ -147,8 +147,15 @@ socket_type() -> raw. send_text(State, Text) -> - (State#state.sockmod):send(State#state.socket, Text). - + case catch (State#state.sockmod):send(State#state.socket, Text) of + ok -> ok; + {error, timeout} -> + ?INFO_MSG("Timeout on ~p:send",[State#state.sockmod]), + exit(normal); + Error -> + ?DEBUG("Error in ~p:send: ~p",[State#state.sockmod, Error]), + exit(normal) + end. receive_headers(State) -> SockMod = State#state.sockmod, @@ -605,7 +612,7 @@ start_dir(N, Path, "./" ++ T ) -> start_dir(N , Path, T); start_dir(N, Path, "../" ++ T ) -> start_dir(N + 1, Path, T); start_dir(N, Path, T ) -> rest_dir (N , Path, T). -rest_dir (_N, Path, [] ) -> case Path of +rest_dir (_N, Path, [] ) -> case Path of [] -> "/"; _ -> Path end; From 0095f4fbf9c97dad563d999e5fa13afcb478f893 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 19 Oct 2009 14:53:39 +0000 Subject: [PATCH 578/582] Provide send_timeout_close option in TCP only in R13B or higher (EJAB-926) SVN Revision: 2682 --- src/ejabberd_listener.erl | 7 +++++-- src/ejabberd_s2s_out.erl | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index 7d5ca2fa8..bfed0e336 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -127,15 +127,18 @@ init_udp(PortIP, Module, Opts, SockOpts, Port, IPS) -> end. init_tcp(PortIP, Module, Opts, SockOpts, Port, IPS) -> + SockOpts2 = case erlang:system_info(otp_release) >= "R13B" of + true -> [{send_timeout_close, true} | SockOpts]; + false -> [] + end, Res = gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}, {reuseaddr, true}, {nodelay, true}, {send_timeout, ?TCP_SEND_TIMEOUT}, - {send_timeout_close, true}, {keepalive, true} | - SockOpts]), + SockOpts2]), case Res of {ok, ListenSocket} -> %% Inform my parent that this port was opened succesfully diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index e601ff03f..261562f8c 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -257,11 +257,15 @@ open_socket1(Host, Port) -> open_socket2(Type, Addr, Port) -> ?DEBUG("s2s_out: connecting to ~p:~p~n", [Addr, Port]), Timeout = outgoing_s2s_timeout(), + SockOpts = case erlang:system_info(otp_release) >= "R13B" of + true -> [{send_timeout_close, true}]; + false -> [] + end, case (catch ejabberd_socket:connect(Addr, Port, [binary, {packet, 0}, {send_timeout, ?TCP_SEND_TIMEOUT}, {send_timeout_close, true}, - {active, false}, Type], + {active, false}, Type | SockOpts], Timeout)) of {ok, _Socket} = R -> R; {error, Reason} = R -> From 6b4651fad6e241c849b76464204e2c9335ec4720 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 19 Oct 2009 17:05:13 +0000 Subject: [PATCH 579/582] In default config, only local accounts can create rooms and pubsub nodes. SVN Revision: 2684 --- doc/guide.html | 10 ++++++---- doc/guide.tex | 9 +++++---- src/ejabberd.cfg.example | 11 +++++++---- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 60d233f43..9520f4b70 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -2233,11 +2233,11 @@ is replaced at start time with the real virtual host name.
      {access, AccessName}
      You can specify who is allowed to use the Multi-User Chat service. By default everyone is allowed to use it.
      {access_create, AccessName}
      To configure who is -allowed to create new rooms at the Multi-User Chat service, this option -can be used. By default everybody is allowed to create rooms. +allowed to create new rooms at the Multi-User Chat service, this option can be used. +By default any account in the local ejabberd server is allowed to create rooms.
      {access_persistent, AccessName}
      To configure who is allowed to modify the ’persistent’ room option. -By default everybody is allowed to modify that option. +By default any account in the local ejabberd server is allowed to modify that option.
      {access_admin, AccessName}
      This option specifies who is allowed to administrate the Multi-User Chat service. The default value is none, which means that only the room creator can @@ -2718,7 +2718,9 @@ is replaced at start time with the real virtual host name.
      {access_createnode, AccessName}
      This option restricts which users are allowed to create pubsub nodes using -ACL and ACCESS. The default value is pubsub_createnode.
      {max_items_node, MaxItems}
      +ACL and ACCESS. +By default any account in the local ejabberd server is allowed to create pubsub nodes. +
      {max_items_node, MaxItems}
      Define the maximum number of items that can be stored in a node. Default value is 10.
      {plugins, [ Plugin, ...]}
      diff --git a/doc/guide.tex b/doc/guide.tex index 2f3c2171a..ca72e2982 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -2942,11 +2942,11 @@ Module options: \titem{\{access, AccessName\}} \ind{options!access}You can specify who is allowed to use the Multi-User Chat service. By default everyone is allowed to use it. \titem{\{access\_create, AccessName\}} \ind{options!access\_create}To configure who is - allowed to create new rooms at the Multi-User Chat service, this option - can be used. By default everybody is allowed to create rooms. + allowed to create new rooms at the Multi-User Chat service, this option can be used. + By default any account in the local ejabberd server is allowed to create rooms. \titem{\{access\_persistent, AccessName\}} \ind{options!access\_persistent}To configure who is allowed to modify the 'persistent' room option. - By default everybody is allowed to modify that option. + By default any account in the local ejabberd server is allowed to modify that option. \titem{\{access\_admin, AccessName\}} \ind{options!access\_admin}This option specifies who is allowed to administrate the Multi-User Chat service. The default value is \term{none}, which means that only the room creator can @@ -3486,7 +3486,8 @@ Options: \hostitem{pubsub} \titem{\{access\_createnode, AccessName\}} \ind{options!access\_createnode} This option restricts which users are allowed to create pubsub nodes using - ACL and ACCESS. The default value is \term{pubsub\_createnode}. % Not clear enough + do not use abbreviations. + ACL and ACCESS. + By default any account in the local ejabberd server is allowed to create pubsub nodes. \titem{\{max\_items\_node, MaxItems\}} \ind{options!max\_items\_node} Define the maximum number of items that can be stored in a node. Default value is 10. diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index 785ad3748..29a1fb1df 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -415,11 +415,14 @@ %% Admins of this server are also admins of MUC service: {access, muc_admin, [{allow, admin}]}. +%% Only accounts of the local ejabberd server can create rooms: +{access, muc_create, [{allow, local}]}. + %% All users are allowed to use MUC service: {access, muc, [{allow, all}]}. -%% Everybody can create pubsub nodes -{access, pubsub_createnode, [{allow, all}]}. +%% Only accounts in the local ejabberd server can create Pubsub nodes: +{access, pubsub_createnode, [{allow, local}]}. %% In-band registration allows registration of any possible username. %% To disable in-band registration, replace 'allow' with 'deny'. @@ -493,8 +496,8 @@ {mod_muc, [ %%{host, "conference.@HOST@"}, {access, muc}, - {access_create, muc}, - {access_persistent, muc}, + {access_create, muc_create}, + {access_persistent, muc_create}, {access_admin, muc_admin} ]}, %%{mod_muc_log,[]}, From 12573ed8d2aa2084bf4be55dbd7fcb7af8de1b59 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 20 Oct 2009 09:56:51 +0000 Subject: [PATCH 580/582] Body tag not properly closed in HTTP-Bind (thanks to Janusz Dziemidowicz)(EJAB-1075) SVN Revision: 2686 --- src/web/ejabberd_http_bind.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/ejabberd_http_bind.erl b/src/web/ejabberd_http_bind.erl index 9e379c66a..1fa05f007 100644 --- a/src/web/ejabberd_http_bind.erl +++ b/src/web/ejabberd_http_bind.erl @@ -191,7 +191,7 @@ process_request(Data, IP) -> {error, _} -> {200, ?HEADER, "BOSH module not startedBOSH module not started"}; {ok, Pid} -> handle_session_start( Pid, XmppDomain, Sid, Rid, Attrs, From 306cff729c88c016fb0637d7b55b2e829d11c296 Mon Sep 17 00:00:00 2001 From: Pablo Polvorin Date: Tue, 20 Oct 2009 22:09:43 +0000 Subject: [PATCH 581/582] Merge with trunk #2687 (EJAB-667) (untested) SVN Revision: 2690 --- src/mod_pubsub/gen_pubsub_node.erl | 4 +- src/mod_pubsub/gen_pubsub_nodetree.erl | 2 +- src/mod_pubsub/mod_pubsub.erl | 136 ++++++++++++------------- src/mod_pubsub/mod_pubsub_odbc.erl | 117 +++++++++------------ src/mod_pubsub/node_buddy.erl | 10 +- src/mod_pubsub/node_club.erl | 10 +- src/mod_pubsub/node_dag.erl | 10 +- src/mod_pubsub/node_dispatch.erl | 9 +- src/mod_pubsub/node_flat.erl | 17 +++- src/mod_pubsub/node_flat_odbc.erl | 17 +++- src/mod_pubsub/node_hometree.erl | 15 ++- src/mod_pubsub/node_hometree_odbc.erl | 14 ++- src/mod_pubsub/node_mb.erl | 9 +- src/mod_pubsub/node_pep.erl | 10 +- src/mod_pubsub/node_pep_odbc.erl | 9 +- src/mod_pubsub/node_private.erl | 10 +- src/mod_pubsub/node_public.erl | 10 +- src/mod_pubsub/nodetree_dag.erl | 9 +- src/mod_pubsub/nodetree_tree.erl | 54 ++++++---- src/mod_pubsub/nodetree_tree_odbc.erl | 49 +++++---- src/mod_pubsub/nodetree_virtual.erl | 4 +- 21 files changed, 327 insertions(+), 198 deletions(-) diff --git a/src/mod_pubsub/gen_pubsub_node.erl b/src/mod_pubsub/gen_pubsub_node.erl index 3762d4a44..64464bcac 100644 --- a/src/mod_pubsub/gen_pubsub_node.erl +++ b/src/mod_pubsub/gen_pubsub_node.erl @@ -68,7 +68,9 @@ behaviour_info(callbacks) -> {get_item, 7}, {get_item, 2}, {set_item, 1}, - {get_item_name, 3} + {get_item_name, 3}, + {node_to_path, 1}, + {path_to_node, 1} ]; behaviour_info(_Other) -> undefined. diff --git a/src/mod_pubsub/gen_pubsub_nodetree.erl b/src/mod_pubsub/gen_pubsub_nodetree.erl index f012b3d0b..480b7e60b 100644 --- a/src/mod_pubsub/gen_pubsub_nodetree.erl +++ b/src/mod_pubsub/gen_pubsub_nodetree.erl @@ -49,7 +49,7 @@ behaviour_info(callbacks) -> {get_nodes, 1}, {get_subnodes, 3}, {get_subnodes_tree, 3}, - {create_node, 5}, + {create_node, 6}, {delete_node, 2} ]; behaviour_info(_Other) -> diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 444175548..cce677b29 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -277,11 +277,11 @@ terminate_plugins(Host, ServerHost, Plugins, TreePlugin) -> ok. init_nodes(Host, ServerHost, _NodeTree, Plugins) -> - %% TODO, this call should be done PLugin side + %% TODO, this call should be done plugin side case lists:member("hometree", Plugins) of true -> - create_node(Host, ServerHost, ["home"], service_jid(Host), "hometree"), - create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), "hometree"); + create_node(Host, ServerHost, string_to_node("/home"), service_jid(Host), "hometree"), + create_node(Host, ServerHost, string_to_node("/home" ++ ServerHost), service_jid(Host), "hometree"); false -> ok end. @@ -412,8 +412,29 @@ update_node_database(Host, ServerHost) -> rename_default_nodeplugin(); _ -> ok - end. - + end, + mnesia:transaction(fun() -> + case catch mnesia:first(pubsub_node) of + {_, L} when is_list(L) -> + lists:foreach( + fun({H, N}) when is_list(N) -> + [Node] = mnesia:read({pubsub_node, {H, N}}), + Type = Node#pubsub_node.type, + BN = element(2, node_call(Type, path_to_node, [N])), + BP = case [element(2, node_call(Type, path_to_node, [P])) || P <- Node#pubsub_node.parents] of + [<<>>] -> []; + Parents -> Parents + end, + mnesia:write(Node#pubsub_node{nodeid={H, BN}, parents=BP}), + mnesia:delete({pubsub_node, {H, N}}); + (_) -> + ok + end, mnesia:all_keys(pubsub_node)); + _ -> + ok + end + end). + rename_default_nodeplugin() -> lists:foreach(fun(Node) -> mnesia:dirty_write(Node#pubsub_node{type = "hometree"}) @@ -557,7 +578,7 @@ send_loop(State) -> on_sub_and_presence -> lists:foreach(fun({Resource, Caps}) -> CapsNotify = case catch mod_caps:get_features(ServerHost, Caps) of - Features when is_list(Features) -> lists:member(Node ++ "+notify", Features); + Features when is_list(Features) -> lists:member(node_to_string(Node) ++ "+notify", Features); _ -> false end, case CapsNotify of @@ -653,7 +674,7 @@ disco_sm_features(Acc, From, To, Node, _Lang) -> disco_sm_items(Acc, From, To, <<>>, _Lang) -> Host = exmpp_jid:prep_domain_as_list(To), - case tree_action(Host, get_subnodes, [Host, [], From]) of + case tree_action(Host, get_subnodes, [Host, <<>>, From]) of [] -> Acc; Nodes -> @@ -671,7 +692,8 @@ disco_sm_items(Acc, From, To, <<>>, _Lang) -> end; disco_sm_items(Acc, From, To, NodeB, _Lang) -> - Node = binary_to_list(NodeB), + SNode = binary_to_list(NodeB), + Node = string_to_node(SNode), %% TODO, use iq_disco_items(Host, Node, From) Host = exmpp_jid:prep_domain_as_list(To), LJID = jlib:short_prepd_bare_jid(To), @@ -687,8 +709,6 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) -> end, NodeItems = lists:map( fun(#pubsub_item{itemid = {Id, _}}) -> - %% "jid" is required by XEP-0030, and - %% "node" is forbidden by XEP-0060. {result, Name} = node_call(Type, get_item_name, [Host, Node, Id]), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', exmpp_jid:to_binary(LJID)), @@ -1085,7 +1105,7 @@ iq_disco_info(Host, SNode, From, Lang) -> end, Node = string_to_node(RealSNode), case Node of - [] -> + <<>> -> {result, [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [?XMLATTR('category', "pubsub"), @@ -1104,13 +1124,11 @@ iq_disco_info(Host, SNode, From, Lang) -> iq_disco_items(Host, [], From) -> {result, lists:map( - fun(#pubsub_node{nodeid = {_, SubNode}}) -> - SN = node_to_string(SubNode), - RN = lists:last(SubNode), - %% remove name attribute + fun(#pubsub_node{nodeid = {_, SubNode}, type = Type}) -> + {result, Path} = node_call(Type, node_to_path, [SubNode]), + [Name | _] = lists:reverse(Path), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), - ?XMLATTR('node', SN), - ?XMLATTR('name', RN)]} + ?XMLATTR('name', Name) | nodeAttr(SubNode)]} end, tree_action(Host, get_subnodes, [Host, [], From]))}; iq_disco_items(Host, Item, From) -> case string:tokens(Item, "!") of @@ -1118,10 +1136,6 @@ iq_disco_items(Host, Item, From) -> {result, []}; [SNode] -> Node = string_to_node(SNode), - %% Note: Multiple Node Discovery not supported (mask on pubsub#type) - %% TODO this code is also back-compatible with pubsub v1.8 (for client issue) - %% TODO make it pubsub v1.12 compliant (breaks client compatibility ?) - %% TODO That is, remove name attribute (or node?, please check for 2.1) Action = fun(#pubsub_node{type = Type, id = NodeId}) -> % TODO call get_items/6 instead for access control (EJAB-1033) @@ -1131,17 +1145,12 @@ iq_disco_items(Host, Item, From) -> end, Nodes = lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> - SN = node_to_string(SubNode), - RN = lists:last(SubNode), - #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), - ?XMLATTR('name', RN)]} + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host) | nodeAttr(SubNode)]} end, tree_call(Host, get_subnodes, [Host, Node, From])), Items = lists:map( fun(#pubsub_item{itemid = {RN, _}}) -> - SN = node_to_string(Node) ++ "!" ++ RN, - {result, Name} = node_call(Type, get_item_name, [NodeId, RN]), - #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), - ?XMLATTR('name', Name)]} + {result, Name} = node_call(Type, get_item_name, [Host, Node, RN]), + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('name', Name)]} end, NodeItems), {result, Nodes ++ Items} end, @@ -1199,10 +1208,7 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang) -> iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) -> case exmpp_xml:remove_cdata_from_list(SubEl#xmlel.children) of [#xmlel{name = Name, attrs = Attrs, children = Els} | Rest] -> - Node = case Host of - {_, _, _} -> exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false); - _ -> string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false)) - end, + Node = string_to_node(exmpp_xml:get_attribute_from_list_as_list(attrs, 'node', false)), case {IQType, Name} of {set, 'create'} -> Config = case Rest of @@ -1303,10 +1309,7 @@ iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> Action = exmpp_xml:remove_cdata_from_list(SubEls), case Action of [#xmlel{name = Name, attrs = Attrs, children = Els}] -> - Node = case Host of - {_, _, _} -> exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', ""); - _ -> string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', "")) - end, + Node = string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', "")), case {IQType, Name} of {get, 'configure'} -> get_configure(Host, ServerHost, Node, From, Lang); @@ -1547,8 +1550,7 @@ send_authorization_approval(Host, JID, SNode, Subscription) -> end, Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'subscription', attrs = - [?XMLATTR('node', SNode), - ?XMLATTR('jid', exmpp_jid:to_binary(JID))] ++ SubAttrs + [ ?XMLATTR('jid', exmpp_jid:to_binary(JID)) | nodeAttr(SNode)] ++ SubAttrs }]), ejabberd_router ! {route, service_jid(Host), JID, Stanza}. @@ -1558,10 +1560,7 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> lists:keysearch("pubsub#allow", 1, XFields)} of {{value, {_, [SNode]}}, {value, {_, [SSubscriber]}}, {value, {_, [SAllow]}}} -> - Node = case Host of - {_, _, _} -> [SNode]; - _ -> string:tokens(SNode, "/") - end, + Node = string_to_node(SNode), Subscriber = exmpp_jid:parse(SSubscriber), Allow = case SAllow of "1" -> true; @@ -1696,21 +1695,18 @@ update_auth(Host, Node, Type, NodeId, Subscriber, %%
    create_node(Host, ServerHost, Node, Owner, Type) -> create_node(Host, ServerHost, Node, Owner, Type, all, []). -create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) -> +create_node(Host, ServerHost, <<>>, Owner, Type, Access, Configuration) -> case lists:member("instant-nodes", features(Type)) of true -> - {LOU, LOS, _} = jlib:short_prepd_jid(Owner), - HomeNode = ["home", LOS, LOU], - create_node(Host, ServerHost, - HomeNode, Owner, Type, Access, Configuration), - NewNode = HomeNode ++ [randoms:get_string()], + NewNode = string_to_node(randoms:get_string()), case create_node(Host, ServerHost, NewNode, Owner, Type, Access, Configuration) of {result, []} -> {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(NewNode)}]}]}; - Error -> Error + Error -> + Error end; false -> %% Service does not support instant nodes @@ -1718,7 +1714,6 @@ create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) -> end; create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> Type = select_type(ServerHost, Host, Node, GivenType), - Parent = lists:sublist(Node, length(Node) - 1), %% TODO, check/set node_type = Type ParseOptions = case exmpp_xml:remove_cdata_from_list(Configuration) of [] -> @@ -1743,9 +1738,18 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> {result, NodeOptions} -> CreateNode = fun() -> + SNode = node_to_string(Node), + Parent = case node_call(Type, node_to_path, [Node]) of + {result, [SNode]} -> <<>>; + {result, Path} -> element(2, node_call(Type, path_to_node, [lists:sublist(Path, length(Path)-1)])) + end, + Parents = case Parent of + <<>> -> []; + _ -> [Parent] + end, case node_call(Type, create_node_permission, [Host, ServerHost, Node, Parent, Owner, Access]) of {result, true} -> - case tree_call(Host, create_node, [Host, Node, Type, Owner, NodeOptions]) of + case tree_call(Host, create_node, [Host, Node, Type, Owner, NodeOptions, Parents]) of {ok, NodeId} -> node_call(Type, create_node, [NodeId, Owner]); {error, {virtual, NodeId}} -> @@ -2543,9 +2547,8 @@ read_sub(Subscriber, Node, NodeID, SubID, Lang) -> {result, #pubsub_subscription{options = Options}} -> {result, XdataEl} = pubsub_subscription:get_options_xform(Lang, Options), OptionsEl = #xmlel{ns = ?NS_PUBSUB, name = 'options', - attrs = [?XMLATTR('node', node_to_string(Node)), - ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), - ?XMLATTR('Subid', SubID)], + attrs = [ ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), + ?XMLATTR('Subid', SubID) | nodeAttr(Node)], children = [XdataEl]}, PubsubEl = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [OptionsEl]}, {result, PubsubEl} @@ -2636,7 +2639,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> []; ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription}) -> case Node of - [] -> + <<>> -> [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = [?XMLATTR('node', node_to_string(SubsNode)), ?XMLATTR('subscription', subscription_to_string(Subscription))]}]; @@ -2650,7 +2653,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> []; ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubID, SubJID}) -> case Node of - [] -> + <<>> -> [#xmlel{ns = ?NS_PUBSUB, name='subscription', attrs = [?XMLATTR('jid', exmpp_jid:jid_to_binary(SubJID)), ?XMLATTR('subid', SubID), @@ -2665,7 +2668,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> end; ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubJID}) -> case Node of - [] -> + <<>> -> [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = [?XMLATTR('node', node_to_string(SubsNode)), ?XMLATTR('jid', exmpp_jid:to_binary(SubJID)), @@ -2857,14 +2860,8 @@ subscription_to_string(_) -> "none". %% Node = pubsubNode() %% NodeStr = string() %% @doc

    Convert a node type from pubsubNode to string.

    -node_to_string([]) -> "/"; -node_to_string(Node) -> - case Node of - [[_ | _] | _] -> string:strip(lists:flatten(["/", lists:map(fun(S) -> [S, "/"] end, Node)]), right, $/); - [Head | _] when is_integer(Head) -> Node - end. -string_to_node(SNode) -> - string:tokens(SNode, "/"). +node_to_string(Node) -> binary_to_list(Node). +string_to_node(SNode) -> list_to_binary(SNode). %% @spec (Host) -> jid() %% Host = host() @@ -3093,6 +3090,7 @@ get_options_for_subs(NodeID, Subs) -> end, [], Subs). % TODO: merge broadcast code that way +% TODO: pablo: Why is this commented? Seems to be present on trunk. %broadcast(Host, Node, NodeId, Type, NodeOptions, Feature, Force, ElName, SubEls) -> % case (get_option(NodeOptions, Feature) or Force) of % true -> @@ -3100,7 +3098,7 @@ get_options_for_subs(NodeID, Subs) -> % {result, []} -> % {result, false}; % {result, Subs} -> -% Stanza = event_stanza([{xmlelement, ElName, [{"node", node_to_string(Node)}], SubEls}]), +% Stanza = event_stanza([{xmlelement, ElName, nodeAttr(Node), SubEls}]), % broadcast_stanza(Host, Node, Type, NodeOptions, SubOpts, Stanza), % {result, true}; % _ -> @@ -3217,7 +3215,7 @@ is_caps_notify(Host, Node, LJID) -> false; Caps -> case catch mod_caps:get_features(Host, Caps) of - Features when is_list(Features) -> lists:member(Node ++ "+notify", Features); + Features when is_list(Features) -> lists:member(node_to_string(Node) ++ "+notify", Features); _ -> false end end. @@ -3748,6 +3746,8 @@ uniqid() -> lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])). % node attributes +nodeAttr(Node) when is_list(Node) -> + [?XMLATTR('node', Node)]; nodeAttr(Node) -> [?XMLATTR('node', node_to_string(Node))]. diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index 93e07c172..92e7275ea 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -275,11 +275,11 @@ terminate_plugins(Host, ServerHost, Plugins, TreePlugin) -> ok. init_nodes(Host, ServerHost, _NodeTree, Plugins) -> - %% TODO, this call should be done PLugin side - case lists:member("hometree", Plugins) of + %% TODO, this call should be done plugin side + case lists:member("hometree_odbc", Plugins) of true -> - create_node(Host, ServerHost, ["home"], service_jid(Host), "hometree"), - create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), "hometree"); + create_node(Host, ServerHost, string_to_node("/home"), service_jid(Host), "hometree_odbc"), + create_node(Host, ServerHost, string_to_node("/home/" ++ ServerHost), service_jid(Host), "hometree_odbc"); false -> ok end. @@ -383,7 +383,7 @@ send_loop(State) -> on_sub_and_presence -> lists:foreach(fun({Resource, Caps}) -> CapsNotify = case catch mod_caps:get_features(ServerHost, Caps) of - Features when is_list(Features) -> lists:member(Node ++ "+notify", Features); + Features when is_list(Features) -> lists:member(node_to_string(Node) ++ "+notify", Features); _ -> false end, case CapsNotify of @@ -479,7 +479,7 @@ disco_sm_features(Acc, From, To, Node, _Lang) -> disco_sm_items(Acc, From, To, <<>>, _Lang) -> Host = exmpp_jid:prep_domain_as_list(To), - case tree_action(Host, get_subnodes, [Host, [], From]) of + case tree_action(Host, get_subnodes, [Host, <<>>, From]) of [] -> Acc; Nodes -> @@ -497,7 +497,7 @@ disco_sm_items(Acc, From, To, <<>>, _Lang) -> end; disco_sm_items(Acc, From, To, NodeB, _Lang) -> - Node = binary_to_list(NodeB), + Node = string_to_node(binary_to_list(NodeB)), %% TODO, use iq_disco_items(Host, Node, From) Host = exmpp_jid:prep_domain_as_list(To), LJID = jlib:short_prepd_bare_jid(To), @@ -513,8 +513,6 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) -> end, NodeItems = lists:map( fun(#pubsub_item{itemid = {Id, _}}) -> - %% "jid" is required by XEP-0030, and - %% "node" is forbidden by XEP-0060. {result, Name} = node_call(Type, get_item_name, [Host, Node, Id]), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', exmpp_jid:to_binary(LJID)), @@ -913,7 +911,7 @@ iq_disco_info(Host, SNode, From, Lang) -> end, Node = string_to_node(RealSNode), case Node of - [] -> + <<>> -> {result, [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [?XMLATTR('category', "pubsub"), @@ -933,24 +931,18 @@ iq_disco_info(Host, SNode, From, Lang) -> iq_disco_items(Host, [], From, _RSM) -> {result, lists:map( - fun(#pubsub_node{nodeid = {_, SubNode}}) -> - SN = node_to_string(SubNode), - RN = lists:last(SubNode), - %% remove name attribute + fun(#pubsub_node{nodeid = {_, SubNode}, type = Type}) -> + {result, Path} = node_call(Type, node_path, [SubNode]), + [Name | _] = lists:reverse(Path), #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), - ?XMLATTR('node', SN), - ?XMLATTR('name', RN)]} - end, tree_action(Host, get_subnodes, [Host, [], From]))}; + ?XMLATTR('name', Name) | nodeAttr(SubNode)]} + end, tree_action(Host, get_subnodes, [Host, <<>>, From]))}; iq_disco_items(Host, Item, From, RSM) -> case string:tokens(Item, "!") of [_SNode, _ItemID] -> {result, []}; [SNode] -> Node = string_to_node(SNode), - %% Note: Multiple Node Discovery not supported (mask on pubsub#type) - %% TODO this code is also back-compatible with pubsub v1.8 (for client issue) - %% TODO make it pubsub v1.12 compliant (breaks client compatibility ?) - %% TODO That is, remove name attribute (or node?, please check for 2.1) Action = fun(#pubsub_node{type = Type, id = NodeId}) -> %% TODO call get_items/6 instead for access control (EJAB-1033) @@ -960,17 +952,13 @@ iq_disco_items(Host, Item, From, RSM) -> end, Nodes = lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> - SN = node_to_string(SubNode), - RN = lists:last(SubNode), - #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), - ?XMLATTR('name', RN)]} + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host) | nodeAttr(SubNode)]} end, tree_call(Host, get_subnodes, [Host, Node, From])), Items = lists:map( fun(#pubsub_item{itemid = {RN, _}}) -> - SN = node_to_string(Node) ++ "!" ++ RN, - {result, Name} = node_call(Type, get_item_name, [NodeId, RN]), - #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), - ?XMLATTR('name', Name)]} + {result, Name} = node_call(Type, get_item_name, [Host, Node, RN]), + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), + ?XMLATTR('name', Name)]} end, NodeItems), {result, Nodes ++ Items ++ jlib:rsm_encode(RsmOut)} end, @@ -1028,10 +1016,7 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang) -> iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) -> case exmpp_xml:remove_cdata_from_list(SubEl#xmlel.children) of [#xmlel{name = Name, attrs = Attrs, children = Els} | Rest] -> - Node = case Host of - {_, _, _} -> exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false); - _ -> string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false)) - end, + Node = string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false)), case {IQType, Name} of {set, 'create'} -> Config = case Rest of @@ -1134,10 +1119,7 @@ iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> end, exmpp_xml:get_child_elements(SubEl)), case Action of [#xmlel{name = Name, attrs = Attrs, children = Els}] -> - Node = case Host of - {_, _, _} -> exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', ""); - _ -> string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', "")) - end, + Node = string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', "")), case {IQType, Name} of {get, 'configure'} -> get_configure(Host, ServerHost, Node, From, Lang); @@ -1379,8 +1361,7 @@ send_authorization_approval(Host, JID, SNode, Subscription) -> end, Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'subscription', attrs = - [?XMLATTR('node', SNode), - ?XMLATTR('jid', exmpp_jid:to_binary(JID))] ++ SubAttrs + [?XMLATTR('jid', exmpp_jid:to_binary(JID)) | nodeAttr(SNode)] ++ SubAttrs }]), ejabberd_router ! {route, service_jid(Host), JID, Stanza}. @@ -1390,11 +1371,8 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> lists:keysearch("pubsub#allow", 1, XFields)} of {{value, {_, [SNode]}}, {value, {_, [SSubscriber]}}, {value, {_, [SAllow]}}} -> - Node = case Host of - {_, _, _} -> [SNode]; - _ -> string:tokens(SNode, "/") - end, - Subscriber = exmpp_jid:parse(SSubscriber), + Node = string_to_node(SNode), + Subscriber = exmpp_jid:parse(SSubscriber), Allow = case SAllow of "1" -> true; "true" -> true; @@ -1528,21 +1506,18 @@ update_auth(Host, Node, Type, NodeId, Subscriber, %% create_node(Host, ServerHost, Node, Owner, Type) -> create_node(Host, ServerHost, Node, Owner, Type, all, []). -create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) -> +create_node(Host, ServerHost, <<>>, Owner, Type, Access, Configuration) -> case lists:member("instant-nodes", features(Type)) of true -> - {LOU, LOS, _} = jlib:short_prepd_jid(Owner), - HomeNode = ["home", LOS, LOU], - create_node(Host, ServerHost, - HomeNode, Owner, Type, Access, Configuration), - NewNode = HomeNode ++ [randoms:get_string()], + NewNode = string_to_node(randoms:get_string()), case create_node(Host, ServerHost, NewNode, Owner, Type, Access, Configuration) of {result, []} -> {result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(NewNode)}]}]}; - Error -> Error + Error -> + Error end; false -> %% Service does not support instant nodes @@ -1550,7 +1525,6 @@ create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) -> end; create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> Type = select_type(ServerHost, Host, Node, GivenType), - Parent = lists:sublist(Node, length(Node) - 1), %% TODO, check/set node_type = Type ParseOptions = case exmpp_xml:remove_cdata_from_list(Configuration) of [] -> @@ -1575,9 +1549,18 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> {result, NodeOptions} -> CreateNode = fun() -> + SNode = node_to_string(Node), + Parent = case node_call(Type, node_to_path, [Node]) of + {result, [SNode]} -> <<>>; + {result, Path} -> element(2, node_call(Type, path_to_node, [lists:sublist(Path, length(Path)-1)])) + end, + Parents = case Parent of + <<>> -> []; + _ -> [Parent] + end, case node_call(Type, create_node_permission, [Host, ServerHost, Node, Parent, Owner, Access]) of {result, true} -> - case tree_call(Host, create_node, [Host, Node, Type, Owner, NodeOptions]) of + case tree_call(Host, create_node, [Host, Node, Type, Owner, NodeOptions, Parents]) of {ok, NodeId} -> node_call(Type, create_node, [NodeId, Owner]); {error, {virtual, NodeId}} -> @@ -2374,9 +2357,8 @@ read_sub(Subscriber, Node, NodeID, SubID, Lang) -> {result, #pubsub_subscription{options = Options}} -> {result, XdataEl} = pubsub_subscription_odbc:get_options_xform(Lang, Options), OptionsEl = #xmlel{ns = ?NS_PUBSUB, name = 'options', - attrs = [?XMLATTR('node', node_to_string(Node)), - ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), - ?XMLATTR('Subid', SubID)], + attrs = [ ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), + ?XMLATTR('Subid', SubID) | nodeAttr(Node)], children = [XdataEl]}, PubsubEl = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [OptionsEl]}, {result, PubsubEl} @@ -2467,7 +2449,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> []; ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription}) -> case Node of - [] -> + <<>> -> [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = [?XMLATTR('node', node_to_string(SubsNode)), ?XMLATTR('subscription', subscription_to_string(Subscription))]}]; @@ -2481,7 +2463,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> []; ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubID, SubJID}) -> case Node of - [] -> + <<>> -> [#xmlel{ns = ?NS_PUBSUB, name='subscription', attrs = [?XMLATTR('jid', exmpp_jid:jid_to_binary(SubJID)), ?XMLATTR('subid', SubID), @@ -2496,7 +2478,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> end; ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubJID}) -> case Node of - [] -> + <<>> -> [#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs = [?XMLATTR('node', node_to_string(SubsNode)), ?XMLATTR('jid', exmpp_jid:to_binary(SubJID)), @@ -2688,14 +2670,8 @@ subscription_to_string(_) -> "none". %% Node = pubsubNode() %% NodeStr = string() %% @doc

    Convert a node type from pubsubNode to string.

    -node_to_string([]) -> "/"; -node_to_string(Node) -> - case Node of - [[_ | _] | _] -> string:strip(lists:flatten(["/", lists:map(fun(S) -> [S, "/"] end, Node)]), right, $/); - [Head | _] when is_integer(Head) -> Node - end. -string_to_node(SNode) -> - string:tokens(SNode, "/"). +node_to_string(Node) -> binary_to_list(Node). +string_to_node(SNode) -> list_to_binary(SNode). %% @spec (Host) -> jid() %% Host = host() @@ -2924,6 +2900,7 @@ get_options_for_subs(NodeID, Subs) -> end, [], Subs). % TODO: merge broadcast code that way +% TODO: pablo: why is this commented? %broadcast(Host, Node, NodeId, Type, NodeOptions, Feature, Force, ElName, SubEls) -> % case (get_option(NodeOptions, Feature) or Force) of % true -> @@ -2931,7 +2908,7 @@ get_options_for_subs(NodeID, Subs) -> % {result, []} -> % {result, false}; % {result, Subs} -> -% Stanza = event_stanza([{xmlelement, ElName, [{"node", node_to_string(Node)}], SubEls}]), +% Stanza = event_stanza([{xmlelement, ElName, nodeAttr(Node), SubEls}]), % broadcast_stanza(Host, Node, Type, NodeOptions, SubOpts, Stanza), % {result, true}; % _ -> @@ -3048,7 +3025,7 @@ is_caps_notify(Host, Node, LJID) -> false; Caps -> case catch mod_caps:get_features(Host, Caps) of - Features when is_list(Features) -> lists:member(Node ++ "+notify", Features); + Features when is_list(Features) -> lists:member(node_to_string(Node) ++ "+notify", Features); _ -> false end end. @@ -3635,6 +3612,8 @@ uniqid() -> lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])). % node attributes +nodeAttr(Node) when is_list(Node) -> + [?XMLATTR('node', Node)]; nodeAttr(Node) -> [?XMLATTR('node', node_to_string(Node))]. diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl index 0d672a748..4d0a75710 100644 --- a/src/mod_pubsub/node_buddy.erl +++ b/src/mod_pubsub/node_buddy.erl @@ -69,7 +69,9 @@ get_item/7, get_item/2, set_item/1, - get_item_name/3 + get_item_name/3, + node_to_path/1, + path_to_node/1 ]). @@ -195,3 +197,9 @@ set_item(Item) -> get_item_name(Host, Node, Id) -> node_hometree:get_item_name(Host, Node, Id). + +node_to_path(Node) -> + node_flat:node_to_path(Node). + +path_to_node(Path) -> + node_flat:path_to_node(Path). diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl index 3e27e2013..536c39d9f 100644 --- a/src/mod_pubsub/node_club.erl +++ b/src/mod_pubsub/node_club.erl @@ -68,7 +68,9 @@ get_item/7, get_item/2, set_item/1, - get_item_name/3 + get_item_name/3, + node_to_path/1, + path_to_node/1 ]). @@ -192,3 +194,9 @@ set_item(Item) -> get_item_name(Host, Node, Id) -> node_hometree:get_item_name(Host, Node, Id). + +node_to_path(Node) -> + node_flat:node_to_path(Node). + +path_to_node(Path) -> + node_flat:path_to_node(Path). diff --git a/src/mod_pubsub/node_dag.erl b/src/mod_pubsub/node_dag.erl index df654433e..439be2205 100644 --- a/src/mod_pubsub/node_dag.erl +++ b/src/mod_pubsub/node_dag.erl @@ -52,7 +52,9 @@ get_item/7, get_item/2, set_item/1, - get_item_name/3]). + get_item_name/3, + node_to_path/1, + path_to_node/1]). init(Host, ServerHost, Opts) -> @@ -173,3 +175,9 @@ set_item(Item) -> get_item_name(Host, Node, ID) -> node_hometree:get_item_name(Host, Node, ID). + +node_to_path(Node) -> + node_hometree:node_to_path(Node). + +path_to_node(Path) -> + node_hometree:path_to_node(Path). diff --git a/src/mod_pubsub/node_dispatch.erl b/src/mod_pubsub/node_dispatch.erl index 2dc1d3f30..05e7d8494 100644 --- a/src/mod_pubsub/node_dispatch.erl +++ b/src/mod_pubsub/node_dispatch.erl @@ -66,7 +66,9 @@ get_item/7, get_item/2, set_item/1, - get_item_name/3 + get_item_name/3, + node_to_path/1, + path_to_node/1 ]). @@ -197,3 +199,8 @@ set_item(Item) -> get_item_name(Host, Node, Id) -> node_hometree:get_item_name(Host, Node, Id). +node_to_path(Node) -> + node_flat:node_to_path(Node). + +path_to_node(Path) -> + node_flat:path_to_node(Path). diff --git a/src/mod_pubsub/node_flat.erl b/src/mod_pubsub/node_flat.erl index 6e5c2372a..3e3617f54 100644 --- a/src/mod_pubsub/node_flat.erl +++ b/src/mod_pubsub/node_flat.erl @@ -59,7 +59,9 @@ get_item/7, get_item/2, set_item/1, - get_item_name/3 + get_item_name/3, + node_to_path/1, + path_to_node/1 ]). @@ -180,3 +182,16 @@ set_item(Item) -> get_item_name(Host, Node, Id) -> node_hometree:get_item_name(Host, Node, Id). + +node_to_path(Node) -> + [binary_to_list(Node)]. + +path_to_node(Path) -> + case Path of + % default slot + [Node] -> list_to_binary(Node); + % handle old possible entries, used when migrating database content to new format + [Node|_] when is_list(Node) -> list_to_binary(string:join([""|Path], "/")); + % default case (used by PEP for example) + _ -> list_to_binary(Path) + end. diff --git a/src/mod_pubsub/node_flat_odbc.erl b/src/mod_pubsub/node_flat_odbc.erl index 08d818a41..973ee5018 100644 --- a/src/mod_pubsub/node_flat_odbc.erl +++ b/src/mod_pubsub/node_flat_odbc.erl @@ -60,7 +60,9 @@ get_item/2, set_item/1, get_item_name/3, - get_last_items/3 + get_last_items/3, + node_to_path/1, + path_to_node/1 ]). @@ -186,3 +188,16 @@ get_item_name(Host, Node, Id) -> get_last_items(NodeId, From, Count) -> node_hometree_odbc:get_last_items(NodeId, From, Count). + +node_to_path(Node) -> + [binary_to_list(Node)]. + +path_to_node(Path) -> + case Path of + % default slot + [Node] -> list_to_binary(Node); + % handle old possible entries, used when migrating database content to new format + [Node|_] when is_list(Node) -> list_to_binary(string:join([""|Path], "/")); + % default case (used by PEP for example) + _ -> list_to_binary(Path) + end. diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index c3fa6e293..c8bb61982 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -75,7 +75,9 @@ get_item/7, get_item/2, set_item/1, - get_item_name/3 + get_item_name/3, + node_to_path/1, + path_to_node/1 ]). %% ================ @@ -204,7 +206,7 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) -> {LU, LS, LR} = LOwner, case acl:match_rule(ServerHost, Access, exmpp_jid:make(LU, LS, LR)) of allow -> - case Node of + case node_to_path(Node) of ["home", Server, User | _] -> true; _ -> false end; @@ -981,6 +983,14 @@ del_items(NodeId, ItemIds) -> get_item_name(_Host, _Node, Id) -> Id. +node_to_path(Node) -> + string:tokens(binary_to_list(Node), "/"). + +path_to_node([]) -> + <<>>; +path_to_node(Path) -> + list_to_binary(string:join([""|Path], "/")). + %% @spec (Affiliation, Subscription) -> true | false %% Affiliation = owner | member | publisher | outcast | none %% Subscription = subscribed | none @@ -1006,3 +1016,4 @@ first_in_list(Pred, [H | T]) -> true -> {value, H}; _ -> first_in_list(Pred, T) end. + diff --git a/src/mod_pubsub/node_hometree_odbc.erl b/src/mod_pubsub/node_hometree_odbc.erl index 4bac466db..9e4414077 100644 --- a/src/mod_pubsub/node_hometree_odbc.erl +++ b/src/mod_pubsub/node_hometree_odbc.erl @@ -80,7 +80,9 @@ get_item/2, set_item/1, get_item_name/3, - get_last_items/3 + get_last_items/3, + path_to_node/1, + node_to_path/1 ]). -export([ @@ -209,7 +211,7 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) -> {LU, LS, LR} = LOwner, case acl:match_rule(ServerHost, Access, exmpp_jid:make(LU, LS, LR)) of allow -> - case Node of + case node_to_path(Node) of ["home", Server, User | _] -> true; _ -> false end; @@ -1372,3 +1374,11 @@ i2l(L, N) when is_list(L) -> C when C > N -> L; _ -> i2l([$0|L], N) end. + +node_to_path(Node) -> + string:tokens(binary_to_list(Node), "/"). + +path_to_node([]) -> + <<>>; +path_to_node(Path) -> + list_to_binary(string:join([""|Path], "/")). diff --git a/src/mod_pubsub/node_mb.erl b/src/mod_pubsub/node_mb.erl index 6fdebef43..9495a3bc5 100644 --- a/src/mod_pubsub/node_mb.erl +++ b/src/mod_pubsub/node_mb.erl @@ -72,7 +72,9 @@ get_item/7, get_item/2, set_item/1, - get_item_name/3 + get_item_name/3, + node_to_path/1, + path_to_node/1 ]). init(Host, ServerHost, Opts) -> @@ -202,3 +204,8 @@ set_item(Item) -> get_item_name(Host, Node, Id) -> node_pep:get_item_name(Host, Node, Id). +node_to_path(Node) -> + node_pep:node_to_path(Node). + +path_to_node(Path) -> + node_pep:path_to_node(Path). diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index 00d0c4095..ff397c8d2 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -65,7 +65,9 @@ get_item/7, get_item/2, set_item/1, - get_item_name/3 + get_item_name/3, + node_to_path/1, + path_to_node/1 ]). init(Host, ServerHost, Opts) -> @@ -270,6 +272,12 @@ set_item(Item) -> get_item_name(Host, Node, Id) -> node_hometree:get_item_name(Host, Node, Id). +node_to_path(Node) -> + node_flat:node_to_path(Node). + +path_to_node(Path) -> + node_flat:path_to_node(Path). + %%% %%% Internal diff --git a/src/mod_pubsub/node_pep_odbc.erl b/src/mod_pubsub/node_pep_odbc.erl index 0b16eaa60..a92e522aa 100644 --- a/src/mod_pubsub/node_pep_odbc.erl +++ b/src/mod_pubsub/node_pep_odbc.erl @@ -70,7 +70,9 @@ get_item/2, set_item/1, get_item_name/3, - get_last_items/3 + get_last_items/3, + node_to_path/1, + path_to_node/1 ]). init(Host, ServerHost, Opts) -> @@ -306,6 +308,11 @@ set_item(Item) -> get_item_name(Host, Node, Id) -> node_hometree_odbc:get_item_name(Host, Node, Id). +node_to_path(Node) -> + node_flat_odbc:node_to_path(Node). + +path_to_node(Path) -> + node_flat_odbc:path_to_node(Path). %%% %%% Internal diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl index 1cff4c11b..cdc50cd62 100644 --- a/src/mod_pubsub/node_private.erl +++ b/src/mod_pubsub/node_private.erl @@ -69,7 +69,9 @@ get_item/7, get_item/2, set_item/1, - get_item_name/3 + get_item_name/3, + node_to_path/1, + path_to_node/1 ]). @@ -197,3 +199,9 @@ set_item(Item) -> get_item_name(Host, Node, Id) -> node_hometree:get_item_name(Host, Node, Id). + +node_to_path(Node) -> + node_flat:node_to_path(Node). + +path_to_node(Path) -> + node_flat:path_to_node(Path). diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl index d227f6b89..7872bea02 100644 --- a/src/mod_pubsub/node_public.erl +++ b/src/mod_pubsub/node_public.erl @@ -69,7 +69,9 @@ get_item/7, get_item/2, set_item/1, - get_item_name/3 + get_item_name/3, + node_to_path/1, + path_to_node/1 ]). @@ -196,3 +198,9 @@ set_item(Item) -> %% node id.

    get_item_name(Host, Node, Id) -> node_hometree:get_item_name(Host, Node, Id). + +node_to_path(Node) -> + node_flat:node_to_path(Node). + +path_to_node(Path) -> + node_flat:path_to_node(Path). diff --git a/src/mod_pubsub/nodetree_dag.erl b/src/mod_pubsub/nodetree_dag.erl index 64b4adde1..0c749fb51 100644 --- a/src/mod_pubsub/nodetree_dag.erl +++ b/src/mod_pubsub/nodetree_dag.erl @@ -32,7 +32,7 @@ get_parentnodes_tree/3, get_subnodes/3, get_subnodes_tree/3, - create_node/5, + create_node/6, delete_node/2]). -include_lib("stdlib/include/qlc.hrl"). @@ -53,14 +53,12 @@ %% API %%==================================================================== init(Host, ServerHost, Opts) -> - nodetree_tree:init(Host, ServerHost, Opts), - mnesia:transaction(fun create_node/5, - [Host, [], "default", service_jid(ServerHost), []]). + nodetree_tree:init(Host, ServerHost, Opts). terminate(Host, ServerHost) -> nodetree_tree:terminate(Host, ServerHost). -create_node(Key, NodeID, Type, Owner, Options) -> +create_node(Key, NodeID, Type, Owner, Options, Parents) -> OwnerJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), case find_node(Key, NodeID) of false -> @@ -68,6 +66,7 @@ create_node(Key, NodeID, Type, Owner, Options) -> N = #pubsub_node{nodeid = oid(Key, NodeID), id = ID, type = Type, + parents = Parents, owners = [OwnerJID], options = Options}, case set_node(N) of diff --git a/src/mod_pubsub/nodetree_tree.erl b/src/mod_pubsub/nodetree_tree.erl index 9ea51658e..610a9851e 100644 --- a/src/mod_pubsub/nodetree_tree.erl +++ b/src/mod_pubsub/nodetree_tree.erl @@ -56,7 +56,7 @@ get_parentnodes_tree/3, get_subnodes/3, get_subnodes_tree/3, - create_node/5, + create_node/6, delete_node/2 ]). @@ -158,6 +158,12 @@ get_parentnodes_tree(Host, Node, From) -> %% From = mod_pubsub:jid() get_subnodes(Host, Node, _From) -> get_subnodes(Host, Node). +get_subnodes(Host, <<>>) -> + Q = qlc:q([N || #pubsub_node{nodeid = {NHost, _}, + parents = Parents} = N <- mnesia:table(pubsub_node), + Host == NHost, + Parents == []]), + qlc:e(Q); get_subnodes(Host, Node) -> Q = qlc:q([N || #pubsub_node{nodeid = {NHost, _}, parents = Parents} = N <- mnesia:table(pubsub_node), @@ -172,12 +178,21 @@ get_subnodes(Host, Node) -> get_subnodes_tree(Host, Node, _From) -> get_subnodes_tree(Host, Node). get_subnodes_tree(Host, Node) -> - mnesia:foldl(fun(#pubsub_node{nodeid = {H, N}} = R, Acc) -> - case lists:prefix(Node, N) and (H == Host) of - true -> [R | Acc]; - _ -> Acc - end - end, [], pubsub_node). + case get_node(Host, Node) of + {error, _} -> + []; + Rec -> + BasePlugin = list_to_atom("node_"++Rec#pubsub_node.type), + BasePath = BasePlugin:node_to_path(Node), + mnesia:foldl(fun(#pubsub_node{nodeid = {H, N}} = R, Acc) -> + Plugin = list_to_atom("node_"++R#pubsub_node.type), + Path = Plugin:node_to_path(N), + case lists:prefix(BasePath, Path) and (H == Host) of + true -> [R | Acc]; + false -> Acc + end + end, [], pubsub_node) + end. %% @spec (Host, Node, Type, Owner, Options) -> ok | {error, Reason} %% Host = mod_pubsub:host() | mod_pubsub:jid() @@ -185,26 +200,27 @@ get_subnodes_tree(Host, Node) -> %% NodeType = mod_pubsub:nodeType() %% Owner = mod_pubsub:jid() %% Options = list() -create_node(Host, Node, Type, Owner, Options) -> +create_node(Host, Node, Type, Owner, Options, Parents) -> BJID = jlib:short_prepd_bare_jid(Owner), case mnesia:read({pubsub_node, {Host, Node}}) of [] -> - {ParentNode, ParentExists} = + ParentExists = case Host of {_U, _S, _R} -> %% This is special case for PEP handling %% PEP does not uses hierarchy - {[], true}; + true; _ -> - Parent = lists:sublist(Node, length(Node) - 1), - case Parent of - [] -> - {[], true}; - _ -> + case Parents of + [] -> true; + [Parent | _] -> case mnesia:read({pubsub_node, {Host, Parent}}) of - [] -> {Parent, false}; - _ -> {Parent, lists:member(BJID, Parent#pubsub_node.owners)} - end + [#pubsub_node{owners = [{[], Host, []}]}] -> true; + [#pubsub_node{owners = Owners}] -> lists:member(BJID, Owners); + _ -> false + end; + _ -> + false end end, case ParentExists of @@ -212,7 +228,7 @@ create_node(Host, Node, Type, Owner, Options) -> NodeId = pubsub_index:new(node), mnesia:write(#pubsub_node{nodeid = {Host, Node}, id = NodeId, - parents = [ParentNode], + parents = Parents, type = Type, owners = [BJID], options = Options}), diff --git a/src/mod_pubsub/nodetree_tree_odbc.erl b/src/mod_pubsub/nodetree_tree_odbc.erl index 4d1995f1f..4853992d3 100644 --- a/src/mod_pubsub/nodetree_tree_odbc.erl +++ b/src/mod_pubsub/nodetree_tree_odbc.erl @@ -59,7 +59,7 @@ get_parentnodes_tree/3, get_subnodes/3, get_subnodes_tree/3, - create_node/5, + create_node/6, delete_node/2 ]). @@ -208,30 +208,37 @@ get_subnodes_tree(Host, Node) -> %% NodeType = mod_pubsub:nodeType() %% Owner = mod_pubsub:jid() %% Options = list() -create_node(Host, Node, Type, _Owner, Options) -> +create_node(Host, Node, Type, Owner, Options, Parents) -> + BJID = jlib:short_prepd_bare_jid(Owner), case nodeid(Host, Node) of {error, 'item_not_found'} -> - {ParentNode, ParentExists} = case Host of - {_U, _S, _R} -> + ParentExists = case Host of + {_, _, _} -> %% This is special case for PEP handling %% PEP does not uses hierarchy - {[], true}; + true; _ -> - case lists:sublist(Node, length(Node) - 1) of - [] -> - {[], true}; - Parent -> + case Parents of + [] -> true; + [Parent | _] -> case nodeid(Host, Parent) of - {result, _} -> {Parent, true}; - _ -> {Parent, false} - end + {result, PNodeId} -> + case nodeowners(PNodeId) of + [{[], Host, []}] -> true; + Owners -> lists:member(BJID, Owners) + end; + _ -> + false + end; + _ -> + false end end, case ParentExists of true -> case set_node(#pubsub_node{ nodeid={Host, Node}, - parents=[ParentNode], + parents=Parents, type=Type, options=Options}) of {result, NodeId} -> {ok, NodeId}; @@ -286,8 +293,8 @@ raw_to_node(Host, {Node, Parent, Type, NodeId}) -> [] end, #pubsub_node{ - nodeid = {Host, string_to_node(Host, Node)}, - parents = [string_to_node(Host, Parent)], + nodeid = {Host, ?PUBSUB:string_to_node(Node)}, + parents = [?PUBSUB:string_to_node(Parent)], id = NodeId, type = Type, options = Options}. @@ -296,7 +303,10 @@ raw_to_node(Host, {Node, Parent, Type, NodeId}) -> %% Record = mod_pubsub:pubsub_node() set_node(Record) -> {Host, Node} = Record#pubsub_node.nodeid, - [Parent] = Record#pubsub_node.parents, + Parent = case Record#pubsub_node.parents of + [] -> <<>>; + [First | _] -> First + end, Type = Record#pubsub_node.type, H = ?PUBSUB:escape(Host), N = ?PUBSUB:escape(?PUBSUB:node_to_string(Node)), @@ -353,5 +363,8 @@ nodeid(Host, Node) -> {error, 'item_not_found'} end. -string_to_node({_, _, _}, Node) -> Node; -string_to_node(_, Node) -> ?PUBSUB:string_to_node(Node). +nodeowners(NodeId) -> + {result, Res} = node_hometree_odbc:get_node_affiliations(NodeId), + lists:foldl(fun({LJID, owner}, Acc) -> [LJID|Acc]; + (_, Acc) -> Acc + end, [], Res). diff --git a/src/mod_pubsub/nodetree_virtual.erl b/src/mod_pubsub/nodetree_virtual.erl index 6285d724c..5dddd4aab 100644 --- a/src/mod_pubsub/nodetree_virtual.erl +++ b/src/mod_pubsub/nodetree_virtual.erl @@ -50,7 +50,7 @@ get_nodes/1, get_subnodes/3, get_subnodes_tree/3, - create_node/5, + create_node/6, delete_node/2 ]). @@ -133,7 +133,7 @@ get_subnodes_tree(_Host, _Node) -> %% @doc

    No node record is stored on database. Any valid node %% is considered as already created.

    %%

    default allowed nodes: /home/host/user/any/node/name

    -create_node(Host, Node, _Type, Owner, _Options) -> +create_node(Host, Node, _Type, Owner, _Options, _Parents) -> UserName = exmpp_jid:prep_node_as_list(Owner), UserHost = exmpp_jid:prep_domain_as_list(Owner), case Node of From cd09381efdc8e240a08b23d0c0eba8abb00f59a0 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Wed, 21 Oct 2009 08:31:51 +0000 Subject: [PATCH 582/582] update pubsub patch SVN Revision: 2691 --- src/mod_pubsub/pubsub_odbc.patch | 189 ++++++++++++++++++++++--------- 1 file changed, 137 insertions(+), 52 deletions(-) diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index cb16e8f75..0580f7592 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,5 +1,5 @@ ---- mod_pubsub.erl 2009-10-13 18:39:11.000000000 +0200 -+++ mod_pubsub_odbc.erl 2009-10-13 18:40:32.000000000 +0200 +--- mod_pubsub.erl 2009-10-21 10:28:28.000000000 +0200 ++++ mod_pubsub_odbc.erl 2009-10-21 10:28:28.000000000 +0200 @@ -42,7 +42,7 @@ %%% 6.2.3.1, 6.2.3.5, and 6.3. For information on subscription leases see %%% XEP-0060 section 12.18. @@ -49,7 +49,18 @@ init_nodes(Host, ServerHost, NodeTree, Plugins), State = #state{host = Host, server_host = ServerHost, -@@ -286,177 +284,7 @@ +@@ -278,206 +276,15 @@ + + init_nodes(Host, ServerHost, _NodeTree, Plugins) -> + %% TODO, this call should be done plugin side +- case lists:member("hometree", Plugins) of ++ case lists:member("hometree_odbc", Plugins) of + true -> +- create_node(Host, ServerHost, string_to_node("/home"), service_jid(Host), "hometree"), +- create_node(Host, ServerHost, string_to_node("/home" ++ ServerHost), service_jid(Host), "hometree"); ++ create_node(Host, ServerHost, string_to_node("/home"), service_jid(Host), "hometree_odbc"), ++ create_node(Host, ServerHost, string_to_node("/home/" ++ ServerHost), service_jid(Host), "hometree_odbc"); + false -> ok end. @@ -179,8 +190,29 @@ - rename_default_nodeplugin(); - _ -> - ok -- end. - +- end, +- mnesia:transaction(fun() -> +- case catch mnesia:first(pubsub_node) of +- {_, L} when is_list(L) -> +- lists:foreach( +- fun({H, N}) when is_list(N) -> +- [Node] = mnesia:read({pubsub_node, {H, N}}), +- Type = Node#pubsub_node.type, +- BN = element(2, node_call(Type, path_to_node, [N])), +- BP = case [element(2, node_call(Type, path_to_node, [P])) || P <- Node#pubsub_node.parents] of +- [<<>>] -> []; +- Parents -> Parents +- end, +- mnesia:write(Node#pubsub_node{nodeid={H, BN}, parents=BP}), +- mnesia:delete({pubsub_node, {H, N}}); +- (_) -> +- ok +- end, mnesia:all_keys(pubsub_node)); +- _ -> +- ok +- end +- end). +- -rename_default_nodeplugin() -> - lists:foreach(fun(Node) -> - mnesia:dirty_write(Node#pubsub_node{type = "hometree"}) @@ -224,10 +256,11 @@ - _ -> - ok - end. ++ send_queue(State, Msg) -> Pid = State#state.send_loop, -@@ -480,17 +308,15 @@ +@@ -501,17 +308,15 @@ %% for each node From is subscribed to %% and if the node is so configured, send the last published item to From lists:foreach(fun(PType) -> @@ -251,7 +284,17 @@ true -> % resource not concerned about that subscription ok -@@ -821,10 +647,10 @@ +@@ -692,8 +497,7 @@ + end; + + disco_sm_items(Acc, From, To, NodeB, _Lang) -> +- SNode = binary_to_list(NodeB), +- Node = string_to_node(SNode), ++ Node = string_to_node(binary_to_list(NodeB)), + %% TODO, use iq_disco_items(Host, Node, From) + Host = exmpp_jid:prep_domain_as_list(To), + LJID = jlib:short_prepd_bare_jid(To), +@@ -841,10 +645,10 @@ {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), lists:foreach(fun ({Node, subscribed, _, JID}) -> @@ -264,7 +307,7 @@ true -> node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); false -> -@@ -943,11 +769,12 @@ +@@ -963,11 +767,12 @@ end, ejabberd_router:route(To, From, Res); #iq{type = get, ns = ?NS_DISCO_ITEMS, @@ -279,7 +322,7 @@ {result, IQRes} -> Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query', attrs = QAttrs, -@@ -1050,7 +877,7 @@ +@@ -1070,7 +875,7 @@ [] -> ["leaf"]; %% No sub-nodes: it's a leaf node _ -> @@ -288,7 +331,7 @@ {result, []} -> ["collection"]; {result, _} -> ["leaf", "collection"]; _ -> [] -@@ -1066,8 +893,9 @@ +@@ -1086,8 +891,9 @@ []; true -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]} | @@ -300,7 +343,7 @@ end, features(Type))] end, %% TODO: add meta-data info (spec section 5.4) -@@ -1095,14 +923,15 @@ +@@ -1115,22 +921,23 @@ #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_DISCO_ITEMS_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s)]}, #xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_VCARD_s)]}] ++ @@ -317,19 +360,23 @@ -iq_disco_items(Host, [], From) -> +iq_disco_items(Host, [], From, _RSM) -> {result, lists:map( - fun(#pubsub_node{nodeid = {_, SubNode}}) -> - SN = node_to_string(SubNode), -@@ -1112,7 +941,7 @@ - ?XMLATTR('node', SN), - ?XMLATTR('name', RN)]} - end, tree_action(Host, get_subnodes, [Host, [], From]))}; + fun(#pubsub_node{nodeid = {_, SubNode}, type = Type}) -> +- {result, Path} = node_call(Type, node_to_path, [SubNode]), +- [Name | _] = lists:reverse(Path), ++ {result, Path} = node_call(Type, node_path, [SubNode]), ++ [Name | _] = lists:reverse(Path), + #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), +- ?XMLATTR('name', Name) | nodeAttr(SubNode)]} +- end, tree_action(Host, get_subnodes, [Host, [], From]))}; -iq_disco_items(Host, Item, From) -> ++ ?XMLATTR('name', Name) | nodeAttr(SubNode)]} ++ end, tree_action(Host, get_subnodes, [Host, <<>>, From]))}; +iq_disco_items(Host, Item, From, RSM) -> case string:tokens(Item, "!") of [_SNode, _ItemID] -> {result, []}; -@@ -1124,10 +953,10 @@ - %% TODO That is, remove name attribute (or node?, please check for 2.1) +@@ -1138,10 +945,10 @@ + Node = string_to_node(SNode), Action = fun(#pubsub_node{type = Type, id = NodeId}) -> - % TODO call get_items/6 instead for access control (EJAB-1033) @@ -342,16 +389,29 @@ end, Nodes = lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> -@@ -1143,7 +972,7 @@ - #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN), - ?XMLATTR('name', Name)]} +@@ -1150,9 +957,10 @@ + Items = lists:map( + fun(#pubsub_item{itemid = {RN, _}}) -> + {result, Name} = node_call(Type, get_item_name, [Host, Node, RN]), +- #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('name', Name)]} ++ #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ++ ?XMLATTR('name', Name)]} end, NodeItems), - {result, Nodes ++ Items} + {result, Nodes ++ Items ++ jlib:rsm_encode(RsmOut)} end, case transaction(Host, Node, Action, sync_dirty) of {result, {_, Result}} -> {result, Result}; -@@ -1277,7 +1106,8 @@ +@@ -1208,7 +1016,7 @@ + iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) -> + case exmpp_xml:remove_cdata_from_list(SubEl#xmlel.children) of + [#xmlel{name = Name, attrs = Attrs, children = Els} | Rest] -> +- Node = string_to_node(exmpp_xml:get_attribute_from_list_as_list(attrs, 'node', false)), ++ Node = string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false)), + case {IQType, Name} of + {set, 'create'} -> + Config = case Rest of +@@ -1283,7 +1091,8 @@ (_, Acc) -> Acc end, [], exmpp_xml:remove_cdata_from_list(Els)), @@ -361,7 +421,7 @@ {get, 'subscriptions'} -> get_subscriptions(Host, Node, From, Plugins); {get, 'affiliations'} -> -@@ -1299,8 +1129,9 @@ +@@ -1305,8 +1114,9 @@ end. iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> @@ -372,8 +432,8 @@ + end, exmpp_xml:get_child_elements(SubEl)), case Action of [#xmlel{name = Name, attrs = Attrs, children = Els}] -> - Node = case Host of -@@ -1430,7 +1261,8 @@ + Node = string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', "")), +@@ -1433,7 +1243,8 @@ _ -> [] end end, @@ -383,7 +443,7 @@ sync_dirty) of {result, Res} -> Res; Err -> Err -@@ -1475,7 +1307,7 @@ +@@ -1478,7 +1289,7 @@ %%% authorization handling @@ -392,7 +452,7 @@ Lang = "en", %% TODO fix {U, S, R} = Subscriber, Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children = -@@ -1505,7 +1337,7 @@ +@@ -1508,7 +1319,7 @@ lists:foreach(fun(Owner) -> {U, S, R} = Owner, ejabberd_router ! {route, service_jid(Host), exmpp_jid:make(U, S, R), Stanza} @@ -401,7 +461,23 @@ find_authorization_response(Packet) -> Els = Packet#xmlel.children, -@@ -1568,8 +1400,8 @@ +@@ -1550,7 +1361,7 @@ + end, + Stanza = event_stanza( + [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'subscription', attrs = +- [ ?XMLATTR('jid', exmpp_jid:to_binary(JID)) | nodeAttr(SNode)] ++ SubAttrs ++ [?XMLATTR('jid', exmpp_jid:to_binary(JID)) | nodeAttr(SNode)] ++ SubAttrs + }]), + ejabberd_router ! {route, service_jid(Host), JID, Stanza}. + +@@ -1561,14 +1372,14 @@ + {{value, {_, [SNode]}}, {value, {_, [SSubscriber]}}, + {value, {_, [SAllow]}}} -> + Node = string_to_node(SNode), +- Subscriber = exmpp_jid:parse(SSubscriber), ++ Subscriber = exmpp_jid:parse(SSubscriber), + Allow = case SAllow of + "1" -> true; "true" -> true; _ -> false end, @@ -412,7 +488,7 @@ {result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]), if not IsApprover -> -@@ -1759,7 +1591,7 @@ +@@ -1763,7 +1574,7 @@ end, Reply = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(Node)}]}, @@ -421,7 +497,7 @@ {result, {Result, broadcast}} -> %%Lang = "en", %% TODO: fix %%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), -@@ -1868,7 +1700,7 @@ +@@ -1872,7 +1683,7 @@ %%
  • The node does not exist.
  • %% subscribe_node(Host, Node, From, JID, Configuration) -> @@ -430,7 +506,7 @@ {result, GoodSubOpts} -> GoodSubOpts; _ -> invalid end, -@@ -1879,7 +1711,7 @@ +@@ -1883,7 +1694,7 @@ {undefined, undefined, undefined} end, SubId = uniqid(), @@ -439,7 +515,7 @@ Features = features(Type), SubscribeFeature = lists:member("subscribe", Features), OptionsFeature = lists:member("subscription-options", Features), -@@ -1898,9 +1730,13 @@ +@@ -1902,9 +1713,13 @@ {"", "", ""} -> {false, false}; _ -> @@ -456,7 +532,7 @@ end end, if -@@ -2233,7 +2069,7 @@ +@@ -2237,7 +2052,7 @@ %%

    The permission are not checked in this function.

    %% @todo We probably need to check that the user doing the query has the right %% to read the items. @@ -465,7 +541,7 @@ MaxItems = if SMaxItems == "" -> get_max_items_node(Host); -@@ -2272,11 +2108,11 @@ +@@ -2276,11 +2091,11 @@ node_call(Type, get_items, [NodeId, From, AccessModel, PresenceSubscription, RosterGroup, @@ -479,7 +555,7 @@ SendItems = case ItemIDs of [] -> Items; -@@ -2289,7 +2125,7 @@ +@@ -2293,7 +2108,7 @@ %% number of items sent to MaxItems: {result, #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = nodeAttr(Node), children = @@ -488,7 +564,7 @@ Error -> Error end -@@ -2321,17 +2157,29 @@ +@@ -2325,17 +2140,29 @@ %% @doc

    Resend the items of a node to the user.

    %% @todo use cache-last-item feature send_items(Host, Node, NodeId, Type, LJID, last) -> @@ -525,7 +601,7 @@ send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) -> ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of {result, []} -> -@@ -2460,29 +2308,12 @@ +@@ -2464,29 +2291,12 @@ error -> {error, 'bad-request'}; _ -> @@ -558,7 +634,7 @@ end, Entities), {result, []}; _ -> -@@ -2537,11 +2368,11 @@ +@@ -2541,11 +2351,11 @@ end. read_sub(Subscriber, Node, NodeID, SubID, Lang) -> @@ -570,9 +646,9 @@ - {result, XdataEl} = pubsub_subscription:get_options_xform(Lang, Options), + {result, XdataEl} = pubsub_subscription_odbc:get_options_xform(Lang, Options), OptionsEl = #xmlel{ns = ?NS_PUBSUB, name = 'options', - attrs = [?XMLATTR('node', node_to_string(Node)), - ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), -@@ -2569,7 +2400,7 @@ + attrs = [ ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)), + ?XMLATTR('Subid', SubID) | nodeAttr(Node)], +@@ -2572,7 +2382,7 @@ end. set_options_helper(Configuration, JID, NodeID, SubID, Type) -> @@ -581,7 +657,7 @@ {result, GoodSubOpts} -> GoodSubOpts; _ -> invalid end, -@@ -2599,7 +2430,7 @@ +@@ -2602,7 +2412,7 @@ write_sub(_Subscriber, _NodeID, _SubID, invalid) -> {error, extended_error('bad-request', "invalid-options")}; write_sub(Subscriber, NodeID, SubID, Options) -> @@ -590,7 +666,7 @@ {error, notfound} -> {error, extended_error('not-acceptable', "invalid-subid")}; {result, _} -> -@@ -2772,8 +2603,8 @@ +@@ -2775,8 +2585,8 @@ ?XMLATTR('subsription', subscription_to_string(Sub)) | nodeAttr(Node)]}]}]}, ejabberd_router ! {route, service_jid(Host), JID, Stanza} end, @@ -601,7 +677,7 @@ true -> Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> -@@ -3069,7 +2900,7 @@ +@@ -3066,7 +2876,7 @@ {Depth, [{N, get_node_subs(N)} || N <- Nodes]} end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))} end, @@ -610,7 +686,7 @@ {result, CollSubs} -> CollSubs; _ -> [] end. -@@ -3083,9 +2914,9 @@ +@@ -3080,9 +2890,9 @@ get_options_for_subs(NodeID, Subs) -> lists:foldl(fun({JID, subscribed, SubID}, Acc) -> @@ -622,7 +698,16 @@ _ -> Acc end; (_, Acc) -> -@@ -3284,6 +3115,30 @@ +@@ -3090,7 +2900,7 @@ + end, [], Subs). + + % TODO: merge broadcast code that way +-% TODO: pablo: Why is this commented? Seems to be present on trunk. ++% TODO: pablo: why is this commented? + %broadcast(Host, Node, NodeId, Type, NodeOptions, Feature, Force, ElName, SubEls) -> + % case (get_option(NodeOptions, Feature) or Force) of + % true -> +@@ -3282,6 +3092,30 @@ Result end. @@ -653,7 +738,7 @@ %% @spec (Host, Options) -> MaxItems %% Host = host() %% Options = [Option] -@@ -3673,7 +3528,13 @@ +@@ -3671,7 +3505,13 @@ tree_action(Host, Function, Args) -> ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), Fun = fun() -> tree_call(Host, Function, Args) end, @@ -668,7 +753,7 @@ %% @doc

    node plugin call.

    node_call(Type, Function, Args) -> -@@ -3693,13 +3554,13 @@ +@@ -3691,13 +3531,13 @@ node_action(Host, Type, Function, Args) -> ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), @@ -684,7 +769,7 @@ case tree_call(Host, get_node, [Host, Node]) of N when is_record(N, pubsub_node) -> case Action(N) of -@@ -3712,8 +3573,15 @@ +@@ -3710,8 +3550,15 @@ end end, Trans). @@ -702,7 +787,7 @@ {result, Result} -> {result, Result}; {error, Error} -> {error, Error}; {atomic, {result, Result}} -> {result, Result}; -@@ -3721,6 +3589,15 @@ +@@ -3719,6 +3566,15 @@ {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), {error, 'internal-server-error'}; @@ -718,7 +803,7 @@ {'EXIT', Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), {error, 'internal-server-error'}; -@@ -3729,6 +3606,16 @@ +@@ -3727,6 +3583,16 @@ {error, 'internal-server-error'} end.